diff --git a/showcase/entries/Continuous2.re b/showcase/entries/Continuous2.re
index 86823fc0..f6cb9a53 100644
--- a/showcase/entries/Continuous2.re
+++ b/showcase/entries/Continuous2.re
@@ -19,8 +19,9 @@ let timeDist ={
let setup = dist =>
RenderTypes.DistPlusRenderer.make(~distPlusIngredients=dist,())
|> DistPlusRenderer.run
- |> RenderTypes.DistPlusRenderer.Outputs.distplus
- |> R.O.fmapOrNull(distPlus => );
+ |> E.R.fmap(distPlus => )
+ |> E.R.toOption
+ |> E.O.toExn("")
let simpleExample = (name, guesstimatorString) =>
<>
diff --git a/showcase/entries/ExpressionTreeExamples.re b/showcase/entries/ExpressionTreeExamples.re
index ef29cdaf..2ca91990 100644
--- a/showcase/entries/ExpressionTreeExamples.re
+++ b/showcase/entries/ExpressionTreeExamples.re
@@ -1,8 +1,9 @@
let setup = dist =>
RenderTypes.DistPlusRenderer.make(~distPlusIngredients=dist, ())
|> DistPlusRenderer.run
- |> RenderTypes.DistPlusRenderer.Outputs.distplus
- |> R.O.fmapOrNull(distPlus => );
+ |> E.R.fmap(distPlus => )
+ |> E.R.toOption
+ |> E.O.toExn("")
let simpleExample = (guesstimatorString, ~problem="", ()) =>
<>
diff --git a/src/components/DistBuilder.re b/src/components/DistBuilder.re
index 87746905..ae00fbb6 100644
--- a/src/components/DistBuilder.re
+++ b/src/components/DistBuilder.re
@@ -146,14 +146,11 @@ module DemoDist = {
(),
);
let response = DistPlusRenderer.run(inputs);
- switch (RenderTypes.DistPlusRenderer.Outputs.distplus(response)) {
- | Some(distPlus) => {
+ switch (response) {
+ | Ok(distPlus) =>
let normalizedDistPlus = DistPlus.T.normalize(distPlus);
- ;
- }
- | _ =>
- "Correct Guesstimator string input to show a distribution."
- |> R.ste
+ ;
+ | Error(r) => r |> R.ste
};
| _ =>
"Nothing to show. Try to change the distribution description."
@@ -484,7 +481,10 @@ let make = () => {
/>
-
+
diff --git a/src/distPlus/expressionTree/ExpressionTreeEvaluator.re b/src/distPlus/expressionTree/ExpressionTreeEvaluator.re
index 134fbdbe..e93176b2 100644
--- a/src/distPlus/expressionTree/ExpressionTreeEvaluator.re
+++ b/src/distPlus/expressionTree/ExpressionTreeEvaluator.re
@@ -32,6 +32,50 @@ module AlgebraicCombination = {
);
};
+ let choose = (t1: node, t2: node) => {
+ let dLength = (r: DistTypes.discreteShape) =>
+ r.xyShape |> XYShape.T.length;
+ switch (t1, t2) {
+ | (`RenderedDist(Continuous(_)), `RenderedDist(Continuous(_))) => `Sampling
+ | (`RenderedDist(Discrete(m1)), `RenderedDist(Discrete(m2)))
+ when dLength(m1) * dLength(m2) > 1000 => `Analytical
+ | (`RenderedDist(Discrete(_)), `RenderedDist(Discrete(_))) => `Sampling
+ | (`RenderedDist(Discrete(d)), `SymbolicDist(_))
+ | (`SymbolicDist(_), `RenderedDist(Discrete(d)))
+ | (`RenderedDist(Discrete(d)), `RenderedDist(Continuous(_)))
+ | (`RenderedDist(Continuous(_)), `RenderedDist(Discrete(d))) =>
+ dLength(d) > 10 ? `Sampling : `Analytical
+ | _ => `Sampling
+ };
+ };
+ let foo =
+ (evaluationParams, algebraicOp, t1: node, t2: node)
+ : result(node, string) => {
+ E.R.merge(
+ SamplingDistribution.renderIfIsNotSamplingDistribution(
+ evaluationParams,
+ t1,
+ ),
+ SamplingDistribution.renderIfIsNotSamplingDistribution(
+ evaluationParams,
+ t2,
+ ),
+ )
+ |> E.R.bind(_, ((a, b)) =>
+ switch (choose(a, b)) {
+ | `Sampling =>
+ SamplingDistribution.combineShapesUsingSampling(
+ evaluationParams,
+ algebraicOp,
+ a,
+ b,
+ )
+ | `Analytical =>
+ combinationByRendering(evaluationParams, algebraicOp, a, b)
+ }
+ );
+ };
+
let operationToLeaf =
(
evaluationParams: evaluationParams,
@@ -45,8 +89,8 @@ module AlgebraicCombination = {
|> E.R.bind(
_,
fun
- | `SymbolicDist(d) as t => Ok(t)
- | _ => combinationByRendering(evaluationParams, algebraicOp, t1, t2),
+ | `SymbolicDist(_) as t => Ok(t)
+ | _ => foo(evaluationParams, algebraicOp, t1, t2),
);
};
diff --git a/src/distPlus/expressionTree/SamplingDistribution.re b/src/distPlus/expressionTree/SamplingDistribution.re
index 60886b40..2f95be1e 100644
--- a/src/distPlus/expressionTree/SamplingDistribution.re
+++ b/src/distPlus/expressionTree/SamplingDistribution.re
@@ -6,7 +6,7 @@ let isSamplingDistribution: node => bool =
| `RenderedDist(_) => true
| _ => false;
-let renderIfIsNotSamplingDistribution = (params, t) =>
+let renderIfIsNotSamplingDistribution = (params, t): result(node, string) =>
!isSamplingDistribution(t)
? switch (Render.render(params, t)) {
| Ok(r) => Ok(r)
@@ -70,9 +70,7 @@ let combineShapesUsingSampling =
},
),
)
- |> E.O.bind(_, (r: RenderTypes.ShapeRenderer.Sampling.outputs) =>
- r.shape
- )
+ |> E.O.bind(_, (r) => r.shape)
|> E.O.toResult("No response");
shape |> E.R.fmap(r => `Normalize(`RenderedDist(r)));
},
diff --git a/src/distPlus/renderers/DistPlusRenderer.re b/src/distPlus/renderers/DistPlusRenderer.re
index 521b244d..1d06eb4a 100644
--- a/src/distPlus/renderers/DistPlusRenderer.re
+++ b/src/distPlus/renderers/DistPlusRenderer.re
@@ -1,18 +1,4 @@
-let downsampleIfShould =
- (
- {recommendedLength, shouldDownsample}: RenderTypes.DistPlusRenderer.inputs,
- outputs: RenderTypes.ShapeRenderer.Combined.outputs,
- dist,
- ) => {
- let willDownsample =
- shouldDownsample
- && RenderTypes.ShapeRenderer.Combined.methodUsed(outputs) == `Sampling;
- willDownsample ? dist |> DistPlus.T.downsample(recommendedLength) : dist;
-};
-
-let run =
- (inputs: RenderTypes.DistPlusRenderer.inputs)
- : RenderTypes.DistPlusRenderer.outputs => {
+let run = (inputs: RenderTypes.DistPlusRenderer.inputs) => {
let toDist = shape =>
DistPlus.make(
~shape,
@@ -22,7 +8,7 @@ let run =
(),
)
|> DistPlus.T.normalize;
- let outputs =
+ let output =
ShapeRenderer.run({
samplingInputs: inputs.samplingInputs,
guesstimatorString: inputs.distPlusIngredients.guesstimatorString,
@@ -30,8 +16,8 @@ let run =
length: inputs.recommendedLength,
},
});
- let shape = outputs |> RenderTypes.ShapeRenderer.Combined.getShape;
- let dist =
- shape |> E.O.fmap(toDist) |> E.O.fmap(downsampleIfShould(inputs, outputs));
- RenderTypes.DistPlusRenderer.Outputs.make(outputs, dist);
+ output
+ |> E.R.fmap((o: RenderTypes.ShapeRenderer.Symbolic.outputs) =>
+ toDist(o.shape)
+ );
};
diff --git a/src/distPlus/renderers/ShapeRenderer.re b/src/distPlus/renderers/ShapeRenderer.re
index a54c8c34..bc6bf411 100644
--- a/src/distPlus/renderers/ShapeRenderer.re
+++ b/src/distPlus/renderers/ShapeRenderer.re
@@ -36,9 +36,6 @@ let runSymbolic = (inputs: RenderTypes.ShapeRenderer.Combined.inputs) => {
);
};
-let run =
- (inputs: RenderTypes.ShapeRenderer.Combined.inputs)
- : RenderTypes.ShapeRenderer.Combined.outputs => {
- let symbolic = runSymbolic(inputs);
- {symbolic: Some(symbolic), sampling: None};
+let run = (inputs: RenderTypes.ShapeRenderer.Combined.inputs) => {
+ runSymbolic(inputs);
};
diff --git a/src/distPlus/renderers/samplesRenderer/Samples.re b/src/distPlus/renderers/samplesRenderer/Samples.re
index ff8f6f46..7f9b10aa 100644
--- a/src/distPlus/renderers/samplesRenderer/Samples.re
+++ b/src/distPlus/renderers/samplesRenderer/Samples.re
@@ -1,3 +1,42 @@
+module Types = {
+ let defaultSampleCount = 5000;
+ let defaultOutputXYPoints = 10000;
+
+ type inputs = {
+ sampleCount: option(int),
+ outputXYPoints: option(int),
+ kernelWidth: option(float),
+ };
+
+ type samplingStats = {
+ sampleCount: int,
+ outputXYPoints: int,
+ bandwidthXSuggested: float,
+ bandwidthUnitSuggested: float,
+ bandwidthXImplemented: float,
+ bandwidthUnitImplemented: float,
+ };
+
+ type outputs = {
+ continuousParseParams: option(samplingStats),
+ shape: option(DistTypes.shape),
+ };
+
+ let empty = {sampleCount: None, outputXYPoints: None, kernelWidth: None};
+
+ type fInputs = {
+ sampleCount: int,
+ outputXYPoints: int,
+ kernelWidth: option(float),
+ };
+
+ let toF = (i: inputs): fInputs => {
+ sampleCount: i.sampleCount |> E.O.default(defaultSampleCount),
+ outputXYPoints: i.outputXYPoints |> E.O.default(defaultOutputXYPoints),
+ kernelWidth: i.kernelWidth,
+ };
+};
+
module JS = {
[@bs.deriving abstract]
type distJs = {
@@ -21,39 +60,6 @@ module KDE = {
|> JS.samplesToContinuousPdf(_, outputXYPoints, kernelWidth)
|> JS.jsToDist;
};
-
- // Note: This was an experiment, but it didn't actually work that well.
- let inGroups = (samples, outputXYPoints, kernelWidth, ~cuttoff=0.9, ()) => {
- let partitionAt =
- samples
- |> E.A.length
- |> float_of_int
- |> (e => e *. cuttoff)
- |> int_of_float;
- let part1XYPoints =
- outputXYPoints |> float_of_int |> (e => e *. cuttoff) |> int_of_float;
- let part2XYPoints = outputXYPoints - part1XYPoints |> Js.Math.max_int(30);
- let part1Data =
- samples |> Belt.Array.slice(_, ~offset=0, ~len=partitionAt);
- let part2DataLength = (samples |> E.A.length) - partitionAt;
- let part2Data =
- samples
- |> Belt.Array.slice(
- _,
- ~offset=(-1) * part2DataLength,
- ~len=part2DataLength,
- );
- let part1 =
- part1Data
- |> JS.samplesToContinuousPdf(_, part1XYPoints, kernelWidth)
- |> JS.jsToDist;
- let part2 =
- part2Data
- |> JS.samplesToContinuousPdf(_, part2XYPoints, 3)
- |> JS.jsToDist;
- let opp = 1.0 -. cuttoff;
- part1;
- };
};
module T = {
@@ -109,7 +115,7 @@ module T = {
let toShape =
(
~samples: t,
- ~samplingInputs: RenderTypes.ShapeRenderer.Sampling.Inputs.fInputs,
+ ~samplingInputs: Types.fInputs,
(),
) => {
Array.fast_sort(compare, samples);
@@ -126,6 +132,7 @@ module T = {
continuousPart |> E.A.length > 5
? {
let _suggestedXWidth = Bandwidth.nrd0(continuousPart);
+ // todo: This does some recalculating from the last step.
let _suggestedUnitWidth =
suggestedUnitWidth(continuousPart, samplingInputs.outputXYPoints);
let usedWidth =
@@ -136,7 +143,7 @@ module T = {
samplingInputs.outputXYPoints,
usedWidth,
);
- let foo: RenderTypes.ShapeRenderer.Sampling.samplingStats = {
+ let foo: Types.samplingStats = {
sampleCount: samplingInputs.sampleCount,
outputXYPoints: samplingInputs.outputXYPoints,
bandwidthXSuggested: _suggestedXWidth,
@@ -159,7 +166,7 @@ module T = {
~continuous=pdf |> E.O.fmap(fst),
~discrete=Some(discrete),
);
- let samplesParse: RenderTypes.ShapeRenderer.Sampling.outputs = {
+ let samplesParse: Types.outputs = {
continuousParseParams: pdf |> E.O.fmap(snd),
shape,
};
@@ -168,11 +175,11 @@ module T = {
let fromSamples =
(
- ~samplingInputs=RenderTypes.ShapeRenderer.Sampling.Inputs.empty,
+ ~samplingInputs=Types.empty,
samples,
) => {
let samplingInputs =
- RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs);
+ Types.toF(samplingInputs);
toShape(~samples, ~samplingInputs, ());
};
};
diff --git a/src/interface/FormBuilder.re b/src/interface/FormBuilder.re
index 7556a82f..ea06e318 100644
--- a/src/interface/FormBuilder.re
+++ b/src/interface/FormBuilder.re
@@ -25,11 +25,9 @@ let propValue = (t: Prop.Value.t) => {
~shouldDownsample=true,
(),
)
- |> DistPlusRenderer.run
- |> RenderTypes.DistPlusRenderer.Outputs.distplus;
+ |> DistPlusRenderer.run;
switch (newDistribution) {
- | Some(distribution) =>
-
+ | Ok(distribution) =>
// {
// className="w-1/3 border w-1/2 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline bg-white">
// {"30 to infinity, 80% mass" |> ReasonReact.string}
//
- | None => "Something went wrong" |> ReasonReact.string
+ | Error(e) => e |> ReasonReact.string
};
| FloatCdf(_) =>
| Probability(r) =>
diff --git a/src/models/EAFunds.re b/src/models/EAFunds.re
index 65f26ef9..215bfe2a 100644
--- a/src/models/EAFunds.re
+++ b/src/models/EAFunds.re
@@ -112,8 +112,12 @@ module Model = {
GlobalCatastrophe.makeI(MomentRe.momentNow())
|> RenderTypes.DistPlusRenderer.make(~distPlusIngredients=_, ())
|> DistPlusRenderer.run
- |> RenderTypes.DistPlusRenderer.Outputs.distplus
- |> E.O.bind(_, DistPlusTime.Integral.xToY(Time(dateTime)));
+ |> E.R.bind(_, r =>
+ r
+ |> DistPlusTime.Integral.xToY(Time(dateTime))
+ |> E.O.toResult("error")
+ )
+ |> E.R.toOption;
};
let make =
@@ -299,4 +303,4 @@ module Interface = {
outputTypes: [||],
run,
};
-};
\ No newline at end of file
+};