Merge pull request #25 from foretold-app/Interface-refactor
Renderer-Refactor
This commit is contained in:
commit
e336aee9e9
|
@ -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>;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) {
|
|
@ -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) {
|
||||||
| {
|
| {
|
36
src/distPlus/renderers/DistPlusRenderer.re
Normal file
36
src/distPlus/renderers/DistPlusRenderer.re
Normal 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);
|
||||||
|
};
|
127
src/distPlus/renderers/RenderTypes.re
Normal file
127
src/distPlus/renderers/RenderTypes.re
Normal 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};
|
||||||
|
}
|
||||||
|
};
|
24
src/distPlus/renderers/ShapeRenderer.re
Normal file
24
src/distPlus/renderers/ShapeRenderer.re
Normal 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};
|
||||||
|
};
|
|
@ -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, ()));
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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("")
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)]);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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}),
|
||||||
|
|
|
@ -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}),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user