diff --git a/src/components/charts/GenericDistributionChart.re b/src/components/charts/GenericDistributionChart.re
index 42bf3200..3141cff9 100644
--- a/src/components/charts/GenericDistributionChart.re
+++ b/src/components/charts/GenericDistributionChart.re
@@ -1,12 +1,12 @@
module Shapee = {
[@react.component]
- let make = (~shape: DistributionTypes.pointsType, ~timeScale, ~onHover) => {
- let discrete = Shape.PointsType.scaledDiscreteComponent(shape);
- let continuous = Shape.PointsType.scaledContinuousComponent(shape);
+ let make = (~shape: DistributionTypes.shape, ~timeScale, ~onHover) => {
+ let discrete = Shape.T.scaledDiscreteComponent(shape);
+ let continuous = Shape.T.scaledContinuousComponent(shape);
{
genericDistribution
- |> DistributionTypes.shape
+ |> DistributionTypes.shapee
|> E.O.React.fmapOrNull(shape => {
setX(_ => r)} />
})
diff --git a/src/core/DistFunctor.re b/src/core/DistFunctor.re
new file mode 100644
index 00000000..6db55b90
--- /dev/null
+++ b/src/core/DistFunctor.re
@@ -0,0 +1,218 @@
+let min = (f1: option(float), f2: option(float)) =>
+ switch (f1, f2) {
+ | (Some(f1), Some(f2)) => Some(f1 < f2 ? f1 : f2)
+ | (Some(f1), None) => Some(f1)
+ | (None, Some(f2)) => Some(f2)
+ | (None, None) => None
+ };
+
+let max = (f1: option(float), f2: option(float)) =>
+ switch (f1, f2) {
+ | (Some(f1), Some(f2)) => Some(f1 > f2 ? f1 : f2)
+ | (Some(f1), None) => Some(f1)
+ | (None, Some(f2)) => Some(f2)
+ | (None, None) => None
+ };
+
+type yPoint =
+ | Mixed({
+ continuous: float,
+ discrete: float,
+ })
+ | Continuous(float)
+ | Discrete(float);
+
+module type dist = {
+ type t;
+ type integral;
+ let minX: t => option(float);
+ let maxX: t => option(float);
+ let pointwiseFmap: (float => float, t) => t;
+ let xToY: (float, t) => yPoint;
+ let xToIntegralY: (float, t) => float;
+ let shape: t => DistributionTypes.shape;
+ let integral: t => integral;
+ let integralSum: t => float;
+};
+
+module Dist = (T: dist) => {
+ type t = T.t;
+ type integral = T.integral;
+ let minX = T.minX;
+ let maxX = T.maxX;
+ let pointwiseFmap = T.pointwiseFmap;
+ let xToIntegralY = T.xToIntegralY;
+ let xToY = T.xToY;
+ let shape = T.shape;
+ let integral = T.integral;
+ let integralSum = T.integralSum;
+};
+
+module Continuous =
+ Dist({
+ type t = DistributionTypes.continuousShape;
+ type integral = DistributionTypes.continuousShape;
+ let integral = t =>
+ t |> Shape.XYShape.Range.integrateWithTriangles |> E.O.toExt("");
+ let integralSum = t => t |> integral |> Shape.XYShape.ySum;
+ let minX = Shape.XYShape.minX;
+ let maxX = Shape.XYShape.maxX;
+ let pointwiseFmap = Shape.XYShape.pointwiseMap;
+ let shape = (t: t): DistributionTypes.shape => Continuous(t);
+ let xToY = (f, t) =>
+ CdfLibrary.Distribution.findY(f, t) |> (e => Continuous(e));
+ let xToIntegralY = (f, t) =>
+ t |> integral |> CdfLibrary.Distribution.findY(f);
+ });
+
+module Discrete =
+ Dist({
+ type t = DistributionTypes.discreteShape;
+ type integral = DistributionTypes.continuousShape;
+ let integral = t => t |> Shape.Discrete.integrate;
+ let integralSum = t => t |> Shape.XYShape.ySum;
+ let minX = Shape.XYShape.minX;
+ let maxX = Shape.XYShape.maxX;
+ let pointwiseFmap = Shape.XYShape.pointwiseMap;
+ let shape = (t: t): DistributionTypes.shape => Discrete(t);
+ let xToY = (f, t) =>
+ CdfLibrary.Distribution.findY(f, t) |> (e => Discrete(e));
+ let xToIntegralY = (f, t) =>
+ t |> Shape.XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
+ });
+
+module Mixed =
+ Dist({
+ type t = DistributionTypes.mixedShape;
+ type integral = DistributionTypes.continuousShape;
+ let minX = ({continuous, discrete}: t) =>
+ min(Continuous.minX(continuous), Discrete.minX(discrete));
+ let maxX = ({continuous, discrete}: t) =>
+ max(Continuous.maxX(continuous), Discrete.maxX(discrete));
+ let shape = (t: t): DistributionTypes.shape => Mixed(t);
+ let xToY =
+ (f, {discrete, continuous, discreteProbabilityMassFraction}: t) =>
+ Mixed({
+ continuous:
+ CdfLibrary.Distribution.findY(f, continuous)
+ |> (e => e *. (1. -. discreteProbabilityMassFraction)),
+ discrete:
+ Shape.Discrete.findY(f, discrete)
+ |> (e => e *. discreteProbabilityMassFraction),
+ });
+
+ let scaledContinuousComponent =
+ ({continuous, discreteProbabilityMassFraction}: t)
+ : option(DistributionTypes.continuousShape) => {
+ Shape.Continuous.scalePdf(
+ ~scaleTo=1.0 -. discreteProbabilityMassFraction,
+ continuous,
+ );
+ };
+
+ let scaledDiscreteComponent =
+ ({discrete, discreteProbabilityMassFraction}: t)
+ : DistributionTypes.continuousShape =>
+ Discrete.pointwiseFmap(
+ f => f *. discreteProbabilityMassFraction,
+ discrete,
+ );
+
+ // TODO: Add these two directly, once interpolation is added.
+ let integral = t => {
+ // let cont = scaledContinuousComponent(t);
+ // let discrete = scaledDiscreteComponent(t);
+ scaledContinuousComponent(t) |> E.O.toExt("");
+ };
+
+ let integralSum =
+ ({discrete, continuous, discreteProbabilityMassFraction}: t) => {
+ Discrete.integralSum(discrete)
+ *. discreteProbabilityMassFraction
+ +. Continuous.integralSum(continuous)
+ *. (1.0 -. discreteProbabilityMassFraction);
+ };
+
+ let xToIntegralY =
+ (f, {discrete, continuous, discreteProbabilityMassFraction}: t) => {
+ let cont = Continuous.xToIntegralY(f, continuous);
+ let discrete = Discrete.xToIntegralY(f, discrete);
+ discrete
+ *. discreteProbabilityMassFraction
+ +. cont
+ *. (1.0 -. discreteProbabilityMassFraction);
+ };
+
+ let pointwiseFmap =
+ (fn, {discrete, continuous, discreteProbabilityMassFraction}: t): t => {
+ {
+ discrete: Shape.XYShape.pointwiseMap(fn, discrete),
+ continuous: Shape.XYShape.pointwiseMap(fn, continuous),
+ discreteProbabilityMassFraction,
+ };
+ };
+ });
+
+module Shape =
+ Dist({
+ type t = DistributionTypes.shape;
+ type integral = DistributionTypes.continuousShape;
+ let xToY = (f, t) =>
+ Shape.T.mapToAll(
+ t,
+ (Mixed.xToY(f), Discrete.xToY(f), Continuous.xToY(f)),
+ );
+ let shape = (t: t) => t;
+ let minX = (t: t) =>
+ Shape.T.mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX));
+ let integral = (t: t) =>
+ Shape.T.mapToAll(
+ t,
+ (Mixed.integral, Discrete.integral, Continuous.integral),
+ );
+ let integralSum = (t: t) =>
+ Shape.T.mapToAll(
+ t,
+ (Mixed.integralSum, Discrete.integralSum, Continuous.integralSum),
+ );
+ let xToIntegralY = (f, t) => {
+ Shape.T.mapToAll(
+ t,
+ (
+ Mixed.xToIntegralY(f),
+ Discrete.xToIntegralY(f),
+ Continuous.xToIntegralY(f),
+ ),
+ );
+ };
+ let maxX = (t: t) =>
+ Shape.T.mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX));
+ let pointwiseFmap = (fn, t: t) =>
+ Shape.T.fmap(
+ t,
+ (
+ Mixed.pointwiseFmap(fn),
+ Discrete.pointwiseFmap(fn),
+ Continuous.pointwiseFmap(fn),
+ ),
+ );
+ });
+
+module WithMetadata =
+ Dist({
+ type t = DistributionTypes.complexPower;
+ type integral = DistributionTypes.complexPower;
+ let shape = ({shape, _}: t) => shape;
+ let xToY = (f, t: t) => t |> shape |> Shape.xToY(f);
+ let minX = (t: t) => t |> shape |> Shape.minX;
+ let maxX = (t: t) => t |> shape |> Shape.maxX;
+ let fromShape = (shape, t): t => DistributionTypes.update(~shape, t);
+ let pointwiseFmap = (fn, {shape, _} as t: t): t =>
+ fromShape(Shape.pointwiseFmap(fn, shape), t);
+
+ let integral = (t: t) => fromShape(Continuous(t.integralCache), t);
+ let integralSum = (t: t) => t |> shape |> Shape.integralSum;
+ let xToIntegralY = (f, t) => {
+ 3.0;
+ };
+ });
\ No newline at end of file
diff --git a/src/core/DistributionTypes.re b/src/core/DistributionTypes.re
index 677ec416..069a063f 100644
--- a/src/core/DistributionTypes.re
+++ b/src/core/DistributionTypes.re
@@ -23,14 +23,26 @@ type mixedShape = {
discreteProbabilityMassFraction: float,
};
-type pointsType =
- | Mixed(mixedShape)
- | Discrete(discreteShape)
- | Continuous(continuousShape);
+type shapeMonad('a, 'b, 'c) =
+ | Mixed('a)
+ | Discrete('b)
+ | Continuous('c);
+
+type shape = shapeMonad(mixedShape, discreteShape, continuousShape);
+
+module ShapeMonad = {
+ let fmap =
+ (t: shapeMonad('a, 'b, 'c), (fn1, fn2, fn3)): shapeMonad('d, 'e, 'f) =>
+ switch (t) {
+ | Mixed(m) => Mixed(fn1(m))
+ | Discrete(m) => Discrete(fn2(m))
+ | Continuous(m) => Continuous(fn3(m))
+ };
+};
type generationSource =
| GuesstimatorString(string)
- | Shape(pointsType);
+ | Shape(shape);
type distributionUnit =
| UnspecifiedDistribution
@@ -48,12 +60,31 @@ type genericDistribution = {
unit: distributionUnit,
};
-let shape = ({generationSource}: genericDistribution) =>
+let shapee = ({generationSource}: genericDistribution) =>
switch (generationSource) {
| GuesstimatorString(_) => None
| Shape(pointsType) => Some(pointsType)
};
+type pdfCdfCombo = {
+ pdf: shape,
+ cdf: continuousShape,
+};
+
+type complexPower = {
+ shape,
+ integralCache: continuousShape,
+ domain: domainLimit,
+ unit: distributionUnit,
+};
+
+let update = (~shape=?, ~integralCache=?, ~domain=?, ~unit=?, t: complexPower) => {
+ shape: E.O.default(t.shape, shape),
+ integralCache: E.O.default(t.integralCache, integralCache),
+ domain: E.O.default(t.domain, domain),
+ unit: E.O.default(t.unit, unit),
+};
+
module DistributionUnit = {
let toJson = (distributionUnit: distributionUnit) =>
switch (distributionUnit) {
diff --git a/src/core/GenericDistribution.re b/src/core/GenericDistribution.re
index f9a147fd..cc5aa2a9 100644
--- a/src/core/GenericDistribution.re
+++ b/src/core/GenericDistribution.re
@@ -43,36 +43,22 @@ let make =
unit,
};
+//TODO: The fact that it is a CDF is really something you find later, this can't be chosen until GuesstimatorToString happens.
let renderIfNeeded =
(~sampleCount=1000, t: genericDistribution): option(genericDistribution) => {
switch (t.generationSource) {
| GuesstimatorString(s) =>
- let shape = Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ());
- let newShape =
- switch (shape) {
- | Some({
- continuous: {xs: [||], ys: [||]},
- discrete: {xs: [||], ys: [||]},
- }) =>
- None
- | Some({continuous, discrete: {xs: [||], ys: [||]}}) =>
- Some(Continuous(continuous))
- | Some({continuous: {xs: [||], ys: [||]}, discrete}) =>
- Some(Discrete(discrete))
- | Some(shape) => Some(Mixed(shape))
- | _ => None
- };
-
- newShape
- |> E.O.fmap((shape: DistributionTypes.pointsType) =>
+ Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ())
+ |> E.O.bind(_, Shape.Mixed.clean)
+ |> E.O.fmap((shape: DistributionTypes.shape) =>
make(
~generationSource=Shape(shape),
- ~probabilityType=Cdf,
+ ~probabilityType=Pdf,
~domain=t.domain,
~unit=t.unit,
(),
)
- );
+ )
| Shape(_) => Some(t)
};
};
@@ -80,7 +66,7 @@ let renderIfNeeded =
let normalize = (t: genericDistribution): option(genericDistribution) => {
switch (t.generationSource) {
| Shape(shape) =>
- Shape.PointsType.normalizePdf(shape)
+ Shape.T.Pdf.normalize(shape)
|> E.O.fmap(shape => {...t, generationSource: Shape(shape)})
| GuesstimatorString(_) => Some(t)
};
@@ -91,7 +77,7 @@ let yIntegral = (t: DistributionTypes.genericDistribution, x) => {
let normalize = n => n *. Domain.normalizeProbabilityMass(t.domain);
switch (t) {
| {generationSource: Shape(shape)} =>
- Shape.PointsType.yIntegral(shape, x)
+ Shape.T.yIntegral(shape, x)
|> E.O.fmap(addInitialMass)
|> E.O.fmap(normalize)
| _ => None
diff --git a/src/core/Shape.re b/src/core/Shape.re
index f54ade9e..c4c9c738 100644
--- a/src/core/Shape.re
+++ b/src/core/Shape.re
@@ -25,6 +25,8 @@ module XYShape = {
let fmap = (t: t, y): t => {xs: t.xs, ys: t.ys |> E.A.fmap(y)};
+ let pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)};
+
let scaleCdfTo = (~scaleTo=1., t: t) =>
switch (_lastElement(t.ys)) {
| Some(n) =>
@@ -135,6 +137,10 @@ module Discrete = {
let toJs = XYShape.toJs;
let ySum = XYShape.ySum;
let zip = t => Belt.Array.zip(t.xs, t.ys);
+ let pointwiseMap = (t: discreteShape, fn): discreteShape => {
+ xs: t.xs,
+ ys: t.ys |> E.A.fmap(fn),
+ };
let scaleYToTotal = (totalDesired, t: t): t => {
let difference = totalDesired /. ySum(t);
@@ -214,13 +220,17 @@ module Mixed = {
type yPdfPoint = {
continuous: option(float),
discrete: option(float),
- discreteProbabilityMassFraction: float,
};
let findY = (t: DistributionTypes.mixedShape, x: float): yPdfPoint => {
- continuous: Continuous.findY(x, t.continuous) |> E.O.some,
- discrete: Discrete.findY(x, t.discrete) |> E.O.some,
- discreteProbabilityMassFraction: t.discreteProbabilityMassFraction,
+ continuous:
+ Continuous.findY(x, t.continuous)
+ |> (e => e *. (1. -. t.discreteProbabilityMassFraction))
+ |> E.O.some,
+ discrete:
+ Discrete.findY(x, t.discrete)
+ |> (e => e *. t.discreteProbabilityMassFraction)
+ |> E.O.some,
};
let findYIntegral =
@@ -232,10 +242,36 @@ module Mixed = {
| _ => None
};
};
+
+ let clean = (t: DistributionTypes.mixedShape) =>
+ switch (t) {
+ | {continuous: {xs: [||], ys: [||]}, discrete: {xs: [||], ys: [||]}} =>
+ None
+ | {discrete: {xs: [|_|], ys: [|_|]}} => None
+ | {continuous, discrete: {xs: [||], ys: [||]}} =>
+ Some(Continuous(continuous))
+ | {continuous: {xs: [||], ys: [||]}, discrete} =>
+ Some(Discrete(discrete))
+ | shape => Some(Mixed(shape))
+ };
};
-module PointsType = {
- type t = DistributionTypes.pointsType;
+module T = {
+ type t = DistributionTypes.shape;
+
+ let mapToAll = (t: t, (fn1, fn2, fn3)) =>
+ switch (t) {
+ | Mixed(m) => fn1(m)
+ | Discrete(m) => fn2(m)
+ | Continuous(m) => fn3(m)
+ };
+
+ let fmap = (t: t, (fn1, fn2, fn3)) =>
+ switch (t) {
+ | Mixed(m) => Mixed(fn1(m))
+ | Discrete(m) => Discrete(fn2(m))
+ | Continuous(m) => Continuous(fn3(m))
+ };
let y = (t: t, x: float) =>
switch (t) {
@@ -268,22 +304,6 @@ module PointsType = {
| Continuous(continuousShape) => Continuous.maxX(continuousShape)
};
- // TODO: This is wrong. The discrete component should be made continuous when integrating.
- let pdfToCdf = (t: t) =>
- switch (t) {
- | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
- Some(
- Mixed({
- continuous: Continuous.toCdf(continuous) |> E.O.toExt(""),
- discrete: discrete |> Discrete.integrate,
- discreteProbabilityMassFraction,
- }),
- )
- | Discrete(discrete) => Some(Continuous(discrete |> Discrete.integrate))
- | Continuous(continuous) =>
- Continuous.toCdf(continuous) |> E.O.fmap(e => Continuous(e))
- };
-
let discreteComponent = (t: t) =>
switch (t) {
| Mixed({discrete}) => Some(discrete)
@@ -319,37 +339,123 @@ module PointsType = {
};
};
- let normalizeCdf = (t: DistributionTypes.pointsType) => {
+ let pointwiseFmap = (fn, t: t): shape =>
switch (t) {
- | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
+ | Mixed({discrete, continuous, discreteProbabilityMassFraction}) =>
Mixed({
- continuous: continuous |> Continuous.normalizeCdf,
- discrete: discrete |> Discrete.scaleYToTotal(1.0),
+ continuous: XYShape.pointwiseMap(fn, continuous),
+ discrete: XYShape.pointwiseMap(fn, discrete),
discreteProbabilityMassFraction,
})
- | Discrete(d) => Discrete(d |> Discrete.scaleYToTotal(1.0))
- | Continuous(continuousShape) =>
- Continuous(Continuous.normalizeCdf(continuousShape))
+ | Discrete(x) => Discrete(XYShape.pointwiseMap(fn, x))
+ | Continuous(x) => Continuous(XYShape.pointwiseMap(fn, x))
+ };
+
+ module Cdf = {
+ let normalizeCdf = (t: DistributionTypes.shape) => {
+ switch (t) {
+ | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
+ Mixed({
+ continuous: continuous |> Continuous.normalizeCdf,
+ discrete: discrete |> Discrete.scaleYToTotal(1.0),
+ discreteProbabilityMassFraction,
+ })
+ | Discrete(d) => Discrete(d |> Discrete.scaleYToTotal(1.0))
+ | Continuous(continuousShape) =>
+ Continuous(Continuous.normalizeCdf(continuousShape))
+ };
};
};
- let normalizePdf = (t: DistributionTypes.pointsType) => {
- switch (t) {
- | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
- continuous
- |> Continuous.scalePdf(~scaleTo=1.0)
- |> E.O.fmap(r =>
- Mixed({
- continuous: r,
- discrete: discrete |> Discrete.scaleYToTotal(1.0),
- discreteProbabilityMassFraction,
- })
- )
- | Discrete(d) => Some(Discrete(d |> Discrete.scaleYToTotal(1.0)))
- | Continuous(continuousShape) =>
- continuousShape
- |> Continuous.scalePdf(~scaleTo=1.0)
- |> E.O.fmap(r => Continuous(r))
+ module Pdf = {
+ // TODO: This is wrong. The discrete component should be made continuous when integrating.
+ let toCdf = (t: t) =>
+ switch (t) {
+ | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
+ Some(
+ Mixed({
+ continuous: Continuous.toCdf(continuous) |> E.O.toExt(""),
+ discrete: discrete |> Discrete.integrate,
+ discreteProbabilityMassFraction,
+ }),
+ )
+ | Discrete(discrete) =>
+ Some(Continuous(discrete |> Discrete.integrate))
+ | Continuous(continuous) =>
+ Continuous.toCdf(continuous) |> E.O.fmap(e => Continuous(e))
+ };
+
+ let normalize = (t: DistributionTypes.shape): option(shape) => {
+ switch (t) {
+ | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
+ continuous
+ |> Continuous.scalePdf(~scaleTo=1.0)
+ |> E.O.fmap(r =>
+ Mixed({
+ continuous: r,
+ discrete: discrete |> Discrete.scaleYToTotal(1.0),
+ discreteProbabilityMassFraction,
+ })
+ )
+ | Discrete(d) => Some(Discrete(d |> Discrete.scaleYToTotal(1.0)))
+ | Continuous(continuousShape) =>
+ continuousShape
+ |> Continuous.scalePdf(~scaleTo=1.0)
+ |> E.O.fmap(r => Continuous(r))
+ };
};
};
+
+ let toPdfCdfCombo = (t: t): option(pdfCdfCombo) =>
+ switch (t) {
+ | Mixed({continuous, discrete, discreteProbabilityMassFraction} as tt) =>
+ Some({
+ cdf: continuous |> Continuous.toCdf |> E.O.toExt(""),
+ pdf: Mixed(tt),
+ })
+ | Discrete(d) => Some({cdf: d |> Discrete.integrate, pdf: Discrete(d)})
+ | Continuous(c) =>
+ Some({
+ cdf: c |> Continuous.toCdf |> E.O.toExt(""),
+ pdf: Continuous(c),
+ })
+ };
+};
+
+module PdfCdfShape = {
+ type t = pdfCdfCombo;
+ let pdf = (t: t) =>
+ switch (t.pdf) {
+ | Mixed(pdf) => Mixed(pdf)
+ | Discrete(pdf) => Discrete(pdf)
+ | Continuous(pdf) => Continuous(pdf)
+ };
+ let cdf = (t: t) => t.cdf;
+};
+
+type distributionUnit =
+ | UnspecifiedDistribution
+ | TimeDistribution(TimeTypes.timeVector);
+
+type withLimitedDomain = {
+ domain,
+ dist: pdfCdfCombo,
+};
+
+module WithLimitedDomain = {
+ type t = withLimitedDomain;
+ let dist = (t: t) => t.dist;
+ let pdf = (t: t) => PdfCdfShape.pdf(t.dist);
+ let cdf = (t: t) => PdfCdfShape.cdf(t.dist);
+ // TODO: This is bad, obviously needs to be fixed.
+ let distScaleFactor = (t: t) => 3.0;
+ let scaledPdfShape = (scaleFactor, t: t) =>
+ t |> pdf |> T.pointwiseFmap(r => r *. scaleFactor);
+ let scaledCdfShape = (scaleFactor, t: t) =>
+ t |> cdf |> XYShape.pointwiseMap(r => r *. scaleFactor);
+};
+
+type withTimeVector = {
+ timeVector: TimeTypes.timeVector,
+ dist: withLimitedDomain,
};
\ No newline at end of file
diff --git a/src/core/Try24.re b/src/core/Try24.re
new file mode 100644
index 00000000..4f2da095
--- /dev/null
+++ b/src/core/Try24.re
@@ -0,0 +1,5 @@
+open DistributionTypes;
+
+module Shappe = {
+ type t = shape;
+};
\ No newline at end of file
diff --git a/src/utility/Guesstimator.re b/src/utility/Guesstimator.re
index ae99c34e..7407c36f 100644
--- a/src/utility/Guesstimator.re
+++ b/src/utility/Guesstimator.re
@@ -25,6 +25,7 @@ module Internals = {
[@bs.module "./GuesstimatorLibrary.js"]
external toCombinedFormat: (string, int) => combined = "run";
+ // todo: Format to correct mass, also normalize the pdf.
let toMixedShape = (r: combined): option(DistributionTypes.mixedShape) => {
let assumptions: MixedShapeBuilder.assumptions = {
continuous: ADDS_TO_1,