Merge pull request #25 from foretold-app/Interface-refactor

Renderer-Refactor
This commit is contained in:
Ozzie Gooen 2020-04-05 12:17:18 +01:00 committed by GitHub
commit e336aee9e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 364 additions and 151 deletions

View File

@ -5,22 +5,21 @@
// floor(3 to 4) // floor(3 to 4)
// uniform(0,1) > 0.3 ? lognormal(6.652, -0.41): 0 // uniform(0,1) > 0.3 ? lognormal(6.652, -0.41): 0
let timeDist = let timeDist ={
DistPlusIngredients.make( let ingredients = RenderTypes.DistPlusRenderer.Ingredients.make(
~guesstimatorString="(floor(10 to 15))", ~guesstimatorString="(floor(10 to 15))",
~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}), ~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}),
~unit= ~unit=
DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}), DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
(), ());
); let inputs = RenderTypes.DistPlusRenderer.make(~distPlusIngredients=ingredients,())
inputs |> DistPlusRenderer.run
}
let setup = dist => let setup = dist =>
dist RenderTypes.DistPlusRenderer.make(~distPlusIngredients=dist,())
|> DistPlusIngredients.toDistPlus( |> DistPlusRenderer.run
~sampleCount=2000, |> RenderTypes.DistPlusRenderer.Outputs.distplus
~outputXYPoints=1000,
~truncateTo=Some(1000),
)
|> E.O.React.fmapOrNull(distPlus => <DistPlusPlot distPlus />); |> E.O.React.fmapOrNull(distPlus => <DistPlusPlot distPlus />);
let simpleExample = (name, guesstimatorString) => let simpleExample = (name, guesstimatorString) =>
@ -28,7 +27,7 @@ let simpleExample = (name, guesstimatorString) =>
<h3 className="text-gray-600 text-lg font-bold"> <h3 className="text-gray-600 text-lg font-bold">
{name |> ReasonReact.string} {name |> ReasonReact.string}
</h3> </h3>
{setup(DistPlusIngredients.make(~guesstimatorString, ()))} {setup(RenderTypes.DistPlusRenderer.Ingredients.make(~guesstimatorString, ()))}
</>; </>;
let timeExample = (name, guesstimatorString) => let timeExample = (name, guesstimatorString) =>
@ -37,7 +36,7 @@ let timeExample = (name, guesstimatorString) =>
{name |> ReasonReact.string} {name |> ReasonReact.string}
</h3> </h3>
{setup( {setup(
DistPlusIngredients.make( RenderTypes.DistPlusRenderer.Ingredients.make(
~guesstimatorString, ~guesstimatorString,
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}), ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
(), (),
@ -51,37 +50,37 @@ let distributions = () =>
<h2 className="text-gray-800 text-xl font-bold"> <h2 className="text-gray-800 text-xl font-bold">
{"Initial Section" |> ReasonReact.string} {"Initial Section" |> ReasonReact.string}
</h2> </h2>
{simpleExample("Continuous", "5 to 20")} {simpleExample("Continuous", "5 to 20")}
{simpleExample("Continuous, wide range", "1 to 1000000")} {simpleExample("Continuous, wide range", "1 to 1000000")}
{simpleExample("Continuous, tiny values", "0.000000001 to 0.00000001")} {simpleExample("Continuous, tiny values", "0.000000001 to 0.00000001")}
{simpleExample( {simpleExample(
"Continuous large values", "Continuous large values",
"50000000000000 to 200000000000000000", "50000000000000 to 200000000000000000",
)} )}
{simpleExample("Discrete", "floor(10 to 20)")} {simpleExample("Discrete", "floor(10 to 20)")}
{simpleExample( {simpleExample(
"Discrete and below 0, normal(10,30)", "Discrete and below 0, normal(10,30)",
"floor(normal(10,30))", "floor(normal(10,30))",
)} )}
{simpleExample("Discrete, wide range", "floor(10 to 200000)")} {simpleExample("Discrete, wide range", "floor(10 to 200000)")}
{simpleExample("Mixed", "mm(5 to 20, floor(20 to 30), [.5,.5])")} {simpleExample("Mixed", "mm(5 to 20, floor(20 to 30), [.5,.5])")}
{simpleExample("Mixed, Early-Discrete Point", "mm(1, 5 to 20, [.5,.5])")} {simpleExample("Mixed, Early-Discrete Point", "mm(1, 5 to 20, [.5,.5])")}
{simpleExample( {simpleExample(
"Mixed, Two-Discrete Points", "Mixed, Two-Discrete Points",
"mm(0,10, 5 to 20, [.5,.5,.5])", "mm(0,10, 5 to 20, [.5,.5,.5])",
)} )}
<h2 className="text-gray-800 text-xl font-bold"> <h2 className="text-gray-800 text-xl font-bold">
{"Over Time" |> ReasonReact.string} {"Over Time" |> ReasonReact.string}
</h2> </h2>
{timeExample("Continuous", "5 to 20")} {timeExample("Continuous", "5 to 20")}
{timeExample("Continuous Over Long Period", "500 to 200000")} {timeExample("Continuous Over Long Period", "500 to 200000")}
{timeExample("Continuous Over Short Period", "0.0001 to 0.001")} {timeExample("Continuous Over Short Period", "0.0001 to 0.001")}
{timeExample( {timeExample(
"Continuous Over Very Long Period", "Continuous Over Very Long Period",
"500 to 20000000000000", "500 to 20000000000000",
)} )}
{timeExample("Discrete", "floor(5 to 20)")} {timeExample("Discrete", "floor(5 to 20)")}
{timeExample("Mixed", "mm(5 to 20, floor(5 to 20), [.5,.5])")} {timeExample("Mixed", "mm(5 to 20, floor(5 to 20), [.5,.5])")}
</div> </div>
</div>; </div>;

View File

@ -26,7 +26,7 @@ type options = {
sampleCount: int, sampleCount: int,
outputXYPoints: int, outputXYPoints: int,
truncateTo: option(int), truncateTo: option(int),
kernelWidth: int, kernelWidth: option(float),
}; };
module Form = ReForm.Make(FormConfig); module Form = ReForm.Make(FormConfig);
@ -111,6 +111,13 @@ module Styles = {
]); ]);
}; };
type inputs = {
samplingInputs: RenderTypes.ShapeRenderer.Sampling.inputs,
guesstimatorString: string,
length: int,
shouldTruncateSampledDistribution: int,
};
module DemoDist = { module DemoDist = {
[@react.component] [@react.component]
let make = (~guesstimatorString, ~domain, ~unit, ~options) => { let make = (~guesstimatorString, ~domain, ~unit, ~options) => {
@ -119,15 +126,27 @@ module DemoDist = {
<div> <div>
{switch (domain, unit, options) { {switch (domain, unit, options) {
| (Some(domain), Some(unit), Some(options)) => | (Some(domain), Some(unit), Some(options)) =>
let distPlus = let distPlusIngredients =
DistPlusIngredients.make(~guesstimatorString, ~domain, ~unit, ()) RenderTypes.DistPlusRenderer.Ingredients.make(
|> DistPlusIngredients.toDistPlus( ~guesstimatorString,
~sampleCount=options.sampleCount, ~domain,
~outputXYPoints=options.outputXYPoints, ~unit,
~truncateTo=options.truncateTo, (),
~kernelWidth=options.kernelWidth, );
); let inputs =
switch (distPlus) { RenderTypes.DistPlusRenderer.make(
~samplingInputs={
sampleCount: Some(options.sampleCount),
outputXYPoints: Some(options.outputXYPoints),
kernelWidth: options.kernelWidth,
},
~distPlusIngredients,
~shouldTruncate=options.truncateTo |> E.O.isSome,
~recommendedLength=options.truncateTo |> E.O.default(10000),
(),
);
let response = DistPlusRenderer.run(inputs);
switch (RenderTypes.DistPlusRenderer.Outputs.distplus(response)) {
| Some(distPlus) => <DistPlusPlot distPlus /> | Some(distPlus) => <DistPlusPlot distPlus />
| _ => | _ =>
"Correct Guesstimator string input to show a distribution." "Correct Guesstimator string input to show a distribution."
@ -160,9 +179,9 @@ let make = () => {
unitType: "UnspecifiedDistribution", unitType: "UnspecifiedDistribution",
zero: MomentRe.momentNow(), zero: MomentRe.momentNow(),
unit: "days", unit: "days",
sampleCount: "10000", sampleCount: "30000",
outputXYPoints: "500", outputXYPoints: "10000",
truncateTo: "100", truncateTo: "1000",
kernelWidth: "5", kernelWidth: "5",
}, },
(), (),
@ -246,7 +265,7 @@ let make = () => {
truncateTo: truncateTo:
int_of_float(truncateTo) > 0 int_of_float(truncateTo) > 0
? Some(int_of_float(truncateTo)) : None, ? Some(int_of_float(truncateTo)) : None,
kernelWidth: kernelWidth |> int_of_float, kernelWidth: kernelWidth == 0.0 ? None : Some(kernelWidth),
}) })
| _ => None | _ => None
}; };

View File

@ -60,12 +60,6 @@ type distPlus = {
guesstimatorString: option(string), guesstimatorString: option(string),
}; };
type distPlusIngredients = {
guesstimatorString: string,
domain,
unit: distributionUnit,
};
module DistributionUnit = { module DistributionUnit = {
let toJson = (distributionUnit: distributionUnit) => let toJson = (distributionUnit: distributionUnit) =>
switch (distributionUnit) { switch (distributionUnit) {

View File

@ -8,7 +8,8 @@ type assumptions = {
discreteProbabilityMass: option(float), discreteProbabilityMass: option(float),
}; };
let buildSimple = (~continuous, ~discrete): option(DistTypes.shape) => { let buildSimple = (~continuous: option(DistTypes.continuousShape), ~discrete): option(DistTypes.shape) => {
let continuous = continuous |> E.O.default(Distributions.Continuous.make(`Linear, {xs: [||], ys: [||]}))
let cLength = let cLength =
continuous continuous
|> Distributions.Continuous.getShape |> Distributions.Continuous.getShape
@ -39,6 +40,8 @@ let buildSimple = (~continuous, ~discrete): option(DistTypes.shape) => {
}; };
}; };
// TODO: Delete, only being used in tests
let build = (~continuous, ~discrete, ~assumptions) => let build = (~continuous, ~discrete, ~assumptions) =>
switch (assumptions) { switch (assumptions) {
| { | {

View File

@ -0,0 +1,36 @@
let truncateIfShould =
(
{recommendedLength, shouldTruncate}: RenderTypes.DistPlusRenderer.inputs,
outputs: RenderTypes.ShapeRenderer.Combined.outputs,
dist,
) => {
shouldTruncate
&& RenderTypes.ShapeRenderer.Combined.methodUsed(outputs) == `Sampling
? dist |> Distributions.DistPlus.T.truncate(recommendedLength) : dist;
};
let run =
(inputs: RenderTypes.DistPlusRenderer.inputs)
: RenderTypes.DistPlusRenderer.outputs => {
let toDist = shape =>
Distributions.DistPlus.make(
~shape,
~domain=inputs.distPlusIngredients.domain,
~unit=inputs.distPlusIngredients.unit,
~guesstimatorString=Some(inputs.distPlusIngredients.guesstimatorString),
(),
)
|> Distributions.DistPlus.T.scaleToIntegralSum(~intendedSum=1.0);
let outputs =
ShapeRenderer.run({
samplingInputs: inputs.samplingInputs,
guesstimatorString: inputs.distPlusIngredients.guesstimatorString,
symbolicInputs: {
length: inputs.recommendedLength,
},
});
let shape = outputs |> RenderTypes.ShapeRenderer.Combined.getShape;
let dist =
shape |> E.O.fmap(toDist) |> E.O.fmap(truncateIfShould(inputs, outputs));
RenderTypes.DistPlusRenderer.Outputs.make(outputs, dist);
};

View File

@ -0,0 +1,127 @@
module ShapeRenderer = {
module Sampling = {
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),
};
module Inputs = {
let defaultSampleCount = 5000;
let defaultOutputXYPoints = 10000;
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 Symbolic = {
type inputs = {length: int};
type outputs = {
graph: SymbolicDist.bigDist,
shape: DistTypes.shape,
};
let make = (graph, shape) => {graph, shape};
};
module Combined = {
type inputs = {
samplingInputs: Sampling.inputs,
symbolicInputs: Symbolic.inputs,
guesstimatorString: string,
};
type outputs = {
symbolic: option(Belt.Result.t(Symbolic.outputs, string)),
sampling: option(Sampling.outputs),
};
let methodUsed = ({symbolic, sampling}:outputs) => switch(symbolic, sampling){
| (Some(Ok(_)), _) => `Symbolic
| (None, Some({shape: Some(_)})) => `Sampling
| _ => `None
}
let getShape = (r: outputs) =>
switch (r.symbolic, r.sampling) {
| (Some(Ok({shape})), _) => Some(shape)
| (_, Some({shape})) => shape
| _ => None
};
};
};
module DistPlusRenderer = {
let defaultRecommendedLength = 10000;
let defaultShouldTruncate = true;
type ingredients = {
guesstimatorString: string,
domain: DistTypes.domain,
unit: DistTypes.distributionUnit,
};
type inputs = {
distPlusIngredients: ingredients,
samplingInputs: ShapeRenderer.Sampling.inputs,
recommendedLength: int,
shouldTruncate: bool,
};
module Ingredients = {
let make =
(
~guesstimatorString,
~domain=DistTypes.Complete,
~unit=DistTypes.UnspecifiedDistribution,
(),
)
: ingredients => {
guesstimatorString,
domain,
unit,
};
};
let make =
(
~samplingInputs=ShapeRenderer.Sampling.Inputs.empty,
~recommendedLength=defaultRecommendedLength,
~shouldTruncate=defaultShouldTruncate,
~distPlusIngredients,
(),
)
: inputs => {
distPlusIngredients,
samplingInputs,
recommendedLength,
shouldTruncate,
};
type outputs = {
shapeRenderOutputs: ShapeRenderer.Combined.outputs,
distPlus: option(DistTypes.distPlus)
}
module Outputs = {
let distplus = (t:outputs) => t.distPlus
let shapeRenderOutputs = (t:outputs) => t.shapeRenderOutputs
let make = (shapeRenderOutputs, distPlus) => {shapeRenderOutputs, distPlus};
}
};

View File

@ -0,0 +1,24 @@
let runSymbolic =
(guesstimatorString, length) =>{
let graph = MathJsParser.fromString(guesstimatorString);
graph |> E.R.fmap(g => RenderTypes.ShapeRenderer.Symbolic.make(g, SymbolicDist.toShape(length,g)))
}
let run =
(
inputs: RenderTypes.ShapeRenderer.Combined.inputs
)
: RenderTypes.ShapeRenderer.Combined.outputs => {
let symbolic = runSymbolic(inputs.guesstimatorString, inputs.symbolicInputs.length);
let sampling =
switch (symbolic) {
| Ok(_) => None
| Error(_) =>
Samples.T.fromGuesstimatorString(
~guesstimatorString=inputs.guesstimatorString,
~samplingInputs=inputs.samplingInputs,
(),
)
};
{symbolic: Some(symbolic), sampling};
};

View File

@ -10,7 +10,7 @@ module JS = {
ys: ysGet(d), ys: ysGet(d),
}; };
[@bs.module "./utility/KdeLibrary.js"] [@bs.module "./KdeLibrary.js"]
external samplesToContinuousPdf: (array(float), int, int) => distJs = external samplesToContinuousPdf: (array(float), int, int) => distJs =
"samplesToContinuousPdf"; "samplesToContinuousPdf";
}; };
@ -22,6 +22,7 @@ module KDE = {
|> JS.jsToDist; |> JS.jsToDist;
}; };
// Note: This was an experiment, but it didn't actually work that well.
let inGroups = (samples, outputXYPoints, kernelWidth, ~cuttoff=0.9, ()) => { let inGroups = (samples, outputXYPoints, kernelWidth, ~cuttoff=0.9, ()) => {
let partitionAt = let partitionAt =
samples samples
@ -88,33 +89,93 @@ module T = {
(continuous, discrete); (continuous, discrete);
}; };
let kde = (~samples, ~outputXYPoints) => { let xWidthToUnitWidth = (samples, outputXYPoints, xWidth) => {
let width = Bandwidth.nrd0(samples);
let xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0); let xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0);
let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints); let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints);
let kernelWidth = int_of_float(Jstat.max([|(width /. xyPointWidth), 1.0 |])); xWidth /. xyPointWidth;
KDE.normalSampling(samples, outputXYPoints, kernelWidth);
}; };
// todo: Figure out some way of doing this without having to integrate so many times. let formatUnitWidth = w => Jstat.max([|w, 1.0|]) |> int_of_float;
let toShape = (~samples: t, ~outputXYPoints=3000, ~kernelWidth=10, ()) => {
let suggestedUnitWidth = (samples, outputXYPoints) => {
let suggestedXWidth = Bandwidth.nrd0(samples);
xWidthToUnitWidth(samples, outputXYPoints, suggestedXWidth);
};
let kde = (~samples, ~outputXYPoints, width) => {
KDE.normalSampling(samples, outputXYPoints, width);
};
let toShape =
(~samples: t, ~samplingInputs: RenderTypes.ShapeRenderer.Sampling.Inputs.fInputs, ()) => {
Array.fast_sort(compare, samples); Array.fast_sort(compare, samples);
let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples); let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples);
let length = samples |> E.A.length; let length = samples |> E.A.length |> float_of_int;
let lengthFloat = float_of_int(length);
let discrete: DistTypes.xyShape = let discrete: DistTypes.xyShape =
discretePart discretePart
|> E.FloatFloatMap.fmap(r => r /. lengthFloat) |> E.FloatFloatMap.fmap(r => r /. length)
|> E.FloatFloatMap.toArray |> E.FloatFloatMap.toArray
|> XYShape.T.fromZippedArray; |> XYShape.T.fromZippedArray;
let pdf: DistTypes.xyShape =
let pdf =
continuousPart |> E.A.length > 5 continuousPart |> E.A.length > 5
? { ? {
continuousPart |> kde(~samples=_, ~outputXYPoints) let _suggestedXWidth = Bandwidth.nrd0(continuousPart);
let _suggestedUnitWidth =
suggestedUnitWidth(continuousPart, samplingInputs.outputXYPoints);
let usedWidth =
samplingInputs.kernelWidth |> E.O.default(_suggestedXWidth);
let usedUnitWidth =
xWidthToUnitWidth(
samples,
samplingInputs.outputXYPoints,
usedWidth,
);
let foo: RenderTypes.ShapeRenderer.Sampling.samplingStats = {
sampleCount: samplingInputs.sampleCount,
outputXYPoints: samplingInputs.outputXYPoints,
bandwidthXSuggested: _suggestedXWidth,
bandwidthUnitSuggested: _suggestedUnitWidth,
bandwidthXImplemented: usedWidth,
bandwidthUnitImplemented: usedUnitWidth,
};
continuousPart
|> kde(
~samples=_,
~outputXYPoints=samplingInputs.outputXYPoints,
formatUnitWidth(usedUnitWidth),
)
|> Distributions.Continuous.make(`Linear)
|> (r => Some((r, foo)));
} }
: {xs: [||], ys: [||]}; : None;
let continuous = pdf |> Distributions.Continuous.make(`Linear); let shape =
let shape = MixedShapeBuilder.buildSimple(~continuous, ~discrete); MixedShapeBuilder.buildSimple(
shape; ~continuous=pdf |> E.O.fmap(fst),
~discrete,
);
let samplesParse: RenderTypes.ShapeRenderer.Sampling.outputs = {
continuousParseParams: pdf |> E.O.fmap(snd),
shape,
};
samplesParse;
};
let fromGuesstimatorString =
(
~guesstimatorString,
~samplingInputs=RenderTypes.ShapeRenderer.Sampling.Inputs.empty,
(),
) => {
let hasValidSamples =
Guesstimator.stringToSamples(guesstimatorString, 10) |> E.A.length > 0;
let samplingInputs = RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs);
switch (hasValidSamples) {
| false => None
| true =>
let samples =
Guesstimator.stringToSamples(guesstimatorString, samplingInputs.sampleCount);
Some(toShape(~samples, ~samplingInputs, ()));
};
}; };
}; };

View File

@ -1,3 +1,5 @@
// todo: rename to SymbolicParser
module MathJsonToMathJsAdt = { module MathJsonToMathJsAdt = {
type arg = type arg =
| Symbol(string) | Symbol(string)
@ -245,6 +247,5 @@ let fromString = str => {
} }
); );
let value = E.R.bind(mathJsParse, MathAdtToDistDst.run); let value = E.R.bind(mathJsParse, MathAdtToDistDst.run);
Js.log4("fromString", mathJsToJson, mathJsParse, value);
value; value;
}; };

View File

@ -296,7 +296,7 @@ module PointwiseAddDistributionsWeighted = {
let normalized = normalizeWeights(dists); let normalized = normalizeWeights(dists);
let continuous = normalized |> E.A.filter(((r,_)) => GenericSimple.contType(r) == `Continuous) |> continuousShape(_, sampleCount); let continuous = normalized |> E.A.filter(((r,_)) => GenericSimple.contType(r) == `Continuous) |> continuousShape(_, sampleCount);
let discrete = normalized |> E.A.filter(((r,_)) => GenericSimple.contType(r) == `Discrete) |> discreteShape(_, sampleCount); let discrete = normalized |> E.A.filter(((r,_)) => GenericSimple.contType(r) == `Discrete) |> discreteShape(_, sampleCount);
let shape = MixedShapeBuilder.buildSimple(~continuous, ~discrete); let shape = MixedShapeBuilder.buildSimple(~continuous=Some(continuous), ~discrete);
shape |> E.O.toExt("") shape |> E.O.toExt("")
}; };

View File

@ -1,55 +0,0 @@
open DistTypes;
let make =
(~guesstimatorString, ~domain=Complete, ~unit=UnspecifiedDistribution, ())
: distPlusIngredients => {
guesstimatorString,
domain,
unit,
};
let applyTruncation = (truncateTo, distPlus) =>
switch (truncateTo, distPlus) {
| (Some(t), Some(d)) => Some(d |> Distributions.DistPlus.T.truncate(t))
| (None, Some(d)) => Some(d)
| _ => None
};
let toDistPlus =
(
~sampleCount=2000,
~outputXYPoints=1500,
~truncateTo=Some(300),
~kernelWidth=5,
t: distPlusIngredients,
)
: option(distPlus) => {
let toDist = shape =>
Distributions.DistPlus.make(
~shape,
~domain=t.domain,
~unit=t.unit,
~guesstimatorString=Some(t.guesstimatorString),
(),
)
|> Distributions.DistPlus.T.scaleToIntegralSum(~intendedSum=1.0);
let parsed1 = MathJsParser.fromString(t.guesstimatorString);
let shape =
switch (parsed1) {
| Ok(r) =>
let shape = SymbolicDist.toShape(truncateTo |> E.O.default(10000), r);
Some(shape |> toDist);
| _ =>
let fewSamples = Guesstimator.stringToSamples(t.guesstimatorString, 10);
if (fewSamples |> E.A.length > 0) {
let samples =
Guesstimator.stringToSamples(t.guesstimatorString, sampleCount);
let shape =
Samples.T.toShape(~samples, ~outputXYPoints, ~kernelWidth, ());
shape |> E.O.fmap(toDist) |> applyTruncation(truncateTo);
} else {
None;
};
};
shape;
};

View File

@ -17,14 +17,16 @@ let propValue = (t: Prop.Value.t) => {
switch (t) { switch (t) {
| SelectSingle(r) => r |> ReasonReact.string | SelectSingle(r) => r |> ReasonReact.string
| ConditionalArray(r) => "Array" |> ReasonReact.string | ConditionalArray(r) => "Array" |> ReasonReact.string
| DistPlusIngredients((r: DistTypes.distPlusIngredients)) => | DistPlusIngredients((r: RenderTypes.DistPlusRenderer.ingredients)) =>
let newDistribution = let newDistribution =
DistPlusIngredients.toDistPlus( RenderTypes.DistPlusRenderer.make(
~sampleCount=1000, ~distPlusIngredients=r,
~outputXYPoints=2000, ~recommendedLength=10000,
~truncateTo=Some(500), ~shouldTruncate=true,
r, (),
); )
|> DistPlusRenderer.run
|> RenderTypes.DistPlusRenderer.Outputs.distplus;
switch (newDistribution) { switch (newDistribution) {
| Some(distribution) => | Some(distribution) =>
<div> <DistPlusPlot distPlus=distribution /> </div> <div> <DistPlusPlot distPlus=distribution /> </div>

View File

@ -9,7 +9,7 @@ module Value = {
| DateTime(MomentRe.Moment.t) | DateTime(MomentRe.Moment.t)
| FloatPoint(float) | FloatPoint(float)
| Probability(float) | Probability(float)
| DistPlusIngredients(DistTypes.distPlusIngredients) | DistPlusIngredients(RenderTypes.DistPlusRenderer.ingredients)
| ConditionalArray(array(conditional)) | ConditionalArray(array(conditional))
| FloatCdf(string); | FloatCdf(string);
@ -85,7 +85,7 @@ module ValueCluster = {
[ | `combination(range(MomentRe.Moment.t)) | `item(string)], [ | `combination(range(MomentRe.Moment.t)) | `item(string)],
) )
| Probability([ | `item(string)]) | Probability([ | `item(string)])
| DistPlusIngredients([ | `item(DistTypes.distPlusIngredients)]) | DistPlusIngredients([ | `item(RenderTypes.DistPlusRenderer.ingredients)])
| ConditionalArray([ | `item(array(conditional))]) | ConditionalArray([ | `item(array(conditional))])
| FloatCdf([ | `item(string)]); | FloatCdf([ | `item(string)]);
}; };

View File

@ -110,7 +110,9 @@ module Model = {
// TODO: Fixe number that integral is calculated for // TODO: Fixe number that integral is calculated for
let getGlobalCatastropheChance = dateTime => { let getGlobalCatastropheChance = dateTime => {
GlobalCatastrophe.makeI(MomentRe.momentNow()) GlobalCatastrophe.makeI(MomentRe.momentNow())
|> DistPlusIngredients.toDistPlus |> RenderTypes.DistPlusRenderer.make(~distPlusIngredients=_, ())
|> DistPlusRenderer.run
|> RenderTypes.DistPlusRenderer.Outputs.distplus
|> E.O.bind(_, Distributions.DistPlusTime.Integral.xToY(Time(dateTime))); |> E.O.bind(_, Distributions.DistPlusTime.Integral.xToY(Time(dateTime)));
}; };
@ -151,7 +153,7 @@ module Model = {
}; };
let distPlusIngredients = let distPlusIngredients =
DistPlusIngredients.make( RenderTypes.DistPlusRenderer.Ingredients.make(
~guesstimatorString=str, ~guesstimatorString=str,
~domain=Complete, ~domain=Complete,
~unit=UnspecifiedDistribution, ~unit=UnspecifiedDistribution,
@ -161,7 +163,7 @@ module Model = {
| CHANCE_OF_EXISTENCE => | CHANCE_OF_EXISTENCE =>
Prop.Value.DistPlusIngredients( Prop.Value.DistPlusIngredients(
DistPlusIngredients.make( RenderTypes.DistPlusRenderer.Ingredients.make(
~guesstimatorString= ~guesstimatorString=
GuesstimatorDist.min( GuesstimatorDist.min(
GlobalCatastrophe.guesstimatorString, GlobalCatastrophe.guesstimatorString,

View File

@ -1,7 +1,7 @@
let guesstimatorString = "uniform(1, 100)"; let guesstimatorString = "uniform(1, 100)";
let makeI = (currentDateTime: MomentRe.Moment.t) => { let makeI = (currentDateTime: MomentRe.Moment.t) => {
DistPlusIngredients.make( RenderTypes.DistPlusRenderer.Ingredients.make(
~guesstimatorString, ~guesstimatorString,
~unit=TimeDistribution({zero: currentDateTime, unit: `years}), ~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}), ~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}),

View File

@ -2,7 +2,7 @@ let guesstimatorString = age =>
GuesstimatorDist.normal(72.0 -. age, 5.0 -. age *. 0.01); GuesstimatorDist.normal(72.0 -. age, 5.0 -. age *. 0.01);
let makeI = (age: float) => { let makeI = (age: float) => {
DistPlusIngredients.make( RenderTypes.DistPlusRenderer.Ingredients.make(
~guesstimatorString=guesstimatorString(age), ~guesstimatorString=guesstimatorString(age),
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}), ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}), ~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}),