Adding render options and params
This commit is contained in:
parent
db78bc07f3
commit
e84cfd4c92
|
@ -15,12 +15,8 @@ let timeDist =
|
|||
);
|
||||
|
||||
let setup = dist =>
|
||||
dist
|
||||
|> DistPlusIngredients.toDistPlus(
|
||||
~sampleCount=2000,
|
||||
~outputXYPoints=1000,
|
||||
~truncateTo=Some(1000),
|
||||
)
|
||||
RenderTypes.DistPlus.make(~distPlusIngredients=dist,())
|
||||
|> DistPlusIngredients.toDistPlus
|
||||
|> E.O.React.fmapOrNull(distPlus => <DistPlusPlot distPlus />);
|
||||
|
||||
let simpleExample = (name, guesstimatorString) =>
|
||||
|
|
|
@ -22,6 +22,7 @@ module KDE = {
|
|||
|> 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
|
||||
|
@ -88,33 +89,94 @@ module T = {
|
|||
(continuous, discrete);
|
||||
};
|
||||
|
||||
let kde = (~samples, ~outputXYPoints) => {
|
||||
let width = Bandwidth.nrd0(samples);
|
||||
let xWidthToUnitWidth = (samples, outputXYPoints, xWidth) => {
|
||||
let xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0);
|
||||
let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints);
|
||||
let kernelWidth = int_of_float(Jstat.max([|(width /. xyPointWidth), 1.0 |]));
|
||||
KDE.normalSampling(samples, outputXYPoints, kernelWidth);
|
||||
xWidth /. xyPointWidth;
|
||||
};
|
||||
|
||||
let formatUnitWidth = w => Jstat.max([|w, 1.0|]) |> int_of_float;
|
||||
|
||||
let suggestedUnitWidth = (samples, outputXYPoints) => {
|
||||
let suggestedXWidth = Bandwidth.nrd0(samples);
|
||||
xWidthToUnitWidth(samples, outputXYPoints, suggestedXWidth);
|
||||
};
|
||||
|
||||
let kde = (~samples, ~outputXYPoints, width) => {
|
||||
KDE.normalSampling(samples, outputXYPoints, width);
|
||||
};
|
||||
|
||||
// todo: Figure out some way of doing this without having to integrate so many times.
|
||||
let toShape = (~samples: t, ~outputXYPoints=3000, ~kernelWidth=10, ()) => {
|
||||
let toShape =
|
||||
(~samples: t, ~samplingInputs: RenderTypes.Sampling.Inputs.fInputs, ()) => {
|
||||
Array.fast_sort(compare, samples);
|
||||
let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples);
|
||||
let length = samples |> E.A.length;
|
||||
let lengthFloat = float_of_int(length);
|
||||
let length = samples |> E.A.length |> float_of_int;
|
||||
let discrete: DistTypes.xyShape =
|
||||
discretePart
|
||||
|> E.FloatFloatMap.fmap(r => r /. lengthFloat)
|
||||
|> E.FloatFloatMap.fmap(r => r /. length)
|
||||
|> E.FloatFloatMap.toArray
|
||||
|> XYShape.T.fromZippedArray;
|
||||
let pdf: DistTypes.xyShape =
|
||||
|
||||
let pdf =
|
||||
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.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: [||]};
|
||||
let continuous = pdf |> Distributions.Continuous.make(`Linear);
|
||||
let shape = MixedShapeBuilder.buildSimple(~continuous, ~discrete);
|
||||
shape;
|
||||
: None;
|
||||
let shape =
|
||||
MixedShapeBuilder.buildSimple(
|
||||
~continuous=pdf |> E.O.fmap(fst),
|
||||
~discrete,
|
||||
);
|
||||
let samplesParse: RenderTypes.Sampling.outputs = {
|
||||
continuousParseParams: pdf |> E.O.fmap(snd),
|
||||
shape,
|
||||
};
|
||||
samplesParse;
|
||||
};
|
||||
|
||||
let fromGuesstimatorString =
|
||||
(
|
||||
~guesstimatorString,
|
||||
~samplingInputs=RenderTypes.Sampling.Inputs.empty,
|
||||
(),
|
||||
) => {
|
||||
let hasValidSamples =
|
||||
Guesstimator.stringToSamples(guesstimatorString, 10) |> E.A.length > 0;
|
||||
let samplingInputs = RenderTypes.Sampling.Inputs.toF(samplingInputs);
|
||||
switch (hasValidSamples) {
|
||||
| false => None
|
||||
| true =>
|
||||
let samples =
|
||||
Guesstimator.stringToSamples(guesstimatorString, samplingInputs.sampleCount);
|
||||
Some(toShape(~samples, ~samplingInputs, ()));
|
||||
};
|
||||
};
|
||||
};
|
|
@ -26,7 +26,7 @@ type options = {
|
|||
sampleCount: int,
|
||||
outputXYPoints: int,
|
||||
truncateTo: option(int),
|
||||
kernelWidth: int,
|
||||
kernelWidth: option(float),
|
||||
};
|
||||
|
||||
module Form = ReForm.Make(FormConfig);
|
||||
|
@ -111,6 +111,13 @@ module Styles = {
|
|||
]);
|
||||
};
|
||||
|
||||
type inputs = {
|
||||
samplingInputs: RenderTypes.Sampling.inputs,
|
||||
guesstimatorString: string,
|
||||
length: int,
|
||||
shouldTruncateSampledDistribution: int,
|
||||
};
|
||||
|
||||
module DemoDist = {
|
||||
[@react.component]
|
||||
let make = (~guesstimatorString, ~domain, ~unit, ~options) => {
|
||||
|
@ -119,14 +126,24 @@ module DemoDist = {
|
|||
<div>
|
||||
{switch (domain, unit, options) {
|
||||
| (Some(domain), Some(unit), Some(options)) =>
|
||||
let distPlus =
|
||||
DistPlusIngredients.make(~guesstimatorString, ~domain, ~unit, ())
|
||||
|> DistPlusIngredients.toDistPlus(
|
||||
~sampleCount=options.sampleCount,
|
||||
~outputXYPoints=options.outputXYPoints,
|
||||
~truncateTo=options.truncateTo,
|
||||
~kernelWidth=options.kernelWidth,
|
||||
);
|
||||
let distPlusIngredients =
|
||||
DistPlusIngredients.make(
|
||||
~guesstimatorString,
|
||||
~domain,
|
||||
~unit,
|
||||
(),
|
||||
);
|
||||
let inputs =
|
||||
RenderTypes.DistPlus.make(
|
||||
~samplingInputs={
|
||||
sampleCount: Some(options.sampleCount),
|
||||
outputXYPoints: Some(options.outputXYPoints),
|
||||
kernelWidth: options.kernelWidth,
|
||||
},
|
||||
~distPlusIngredients,
|
||||
(),
|
||||
);
|
||||
let distPlus = DistPlusIngredients.toDistPlus(inputs);
|
||||
switch (distPlus) {
|
||||
| Some(distPlus) => <DistPlusPlot distPlus />
|
||||
| _ =>
|
||||
|
@ -160,9 +177,9 @@ let make = () => {
|
|||
unitType: "UnspecifiedDistribution",
|
||||
zero: MomentRe.momentNow(),
|
||||
unit: "days",
|
||||
sampleCount: "10000",
|
||||
outputXYPoints: "500",
|
||||
truncateTo: "100",
|
||||
sampleCount: "30000",
|
||||
outputXYPoints: "10000",
|
||||
truncateTo: "1000",
|
||||
kernelWidth: "5",
|
||||
},
|
||||
(),
|
||||
|
@ -246,7 +263,7 @@ let make = () => {
|
|||
truncateTo:
|
||||
int_of_float(truncateTo) > 0
|
||||
? Some(int_of_float(truncateTo)) : None,
|
||||
kernelWidth: kernelWidth |> int_of_float,
|
||||
kernelWidth: kernelWidth == 0.0 ? None : Some(kernelWidth),
|
||||
})
|
||||
| _ => None
|
||||
};
|
||||
|
|
|
@ -15,41 +15,34 @@ let applyTruncation = (truncateTo, distPlus) =>
|
|||
| _ => None
|
||||
};
|
||||
|
||||
// ~samplingInputs=RenderTypes.Sampling.Inputs.empty,
|
||||
// ~truncateTo: option(int),
|
||||
// t: distPlusIngredients,
|
||||
//Make truncation optional
|
||||
let toDistPlus =
|
||||
(
|
||||
~sampleCount=2000,
|
||||
~outputXYPoints=1500,
|
||||
~truncateTo=Some(300),
|
||||
~kernelWidth=5,
|
||||
t: distPlusIngredients,
|
||||
inputs:RenderTypes.DistPlus.inputs
|
||||
)
|
||||
: option(distPlus) => {
|
||||
let toDist = shape =>
|
||||
Distributions.DistPlus.make(
|
||||
~shape,
|
||||
~domain=t.domain,
|
||||
~unit=t.unit,
|
||||
~guesstimatorString=Some(t.guesstimatorString),
|
||||
~domain=inputs.distPlusIngredients.domain,
|
||||
~unit=inputs.distPlusIngredients.unit,
|
||||
~guesstimatorString=Some(inputs.distPlusIngredients.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;
|
||||
GuesstimatorToShape.run(
|
||||
~renderingInputs={
|
||||
guesstimatorString: inputs.distPlusIngredients.guesstimatorString,
|
||||
shapeLength: inputs.recommendedLength,
|
||||
},
|
||||
~samplingInputs=inputs.samplingInputs,
|
||||
)
|
||||
|> GuesstimatorToShape.getShape;
|
||||
//TODO: Apply truncation
|
||||
let foo = shape |> E.O.fmap(toDist);
|
||||
foo;
|
||||
};
|
32
src/distribution/GuesstimatorToShape.re
Normal file
32
src/distribution/GuesstimatorToShape.re
Normal file
|
@ -0,0 +1,32 @@
|
|||
let runSymbolic =
|
||||
(renderingInputs: RenderTypes.primaryInputs) =>{
|
||||
let graph = MathJsParser.fromString(renderingInputs.guesstimatorString);
|
||||
graph |> E.R.fmap(g => RenderTypes.Symbolic.make(g, SymbolicDist.toShape(renderingInputs.shapeLength,g)))
|
||||
}
|
||||
|
||||
let getShape = (r: RenderTypes.Combined.outputs) =>
|
||||
switch (r.symbolic, r.sampling) {
|
||||
| (Some(Ok({shape})), _) => Some(shape)
|
||||
| (_, Some({shape})) => shape
|
||||
| _ => None
|
||||
};
|
||||
|
||||
let run =
|
||||
(
|
||||
~renderingInputs: RenderTypes.primaryInputs,
|
||||
~samplingInputs: RenderTypes.Sampling.inputs,
|
||||
)
|
||||
: RenderTypes.Combined.outputs => {
|
||||
let symbolic = runSymbolic(renderingInputs);
|
||||
let sampling =
|
||||
switch (symbolic) {
|
||||
| Ok(r) => None
|
||||
| Error(r) =>
|
||||
Samples.T.fromGuesstimatorString(
|
||||
~guesstimatorString=renderingInputs.guesstimatorString,
|
||||
~samplingInputs,
|
||||
(),
|
||||
)
|
||||
};
|
||||
{symbolic: Some(symbolic), sampling};
|
||||
};
|
|
@ -8,7 +8,8 @@ type assumptions = {
|
|||
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 =
|
||||
continuous
|
||||
|> Distributions.Continuous.getShape
|
||||
|
|
86
src/distribution/RenderTypes.re
Normal file
86
src/distribution/RenderTypes.re
Normal file
|
@ -0,0 +1,86 @@
|
|||
type primaryInputs = {
|
||||
guesstimatorString: string,
|
||||
shapeLength: int,
|
||||
};
|
||||
|
||||
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(ProbExample.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: ProbExample.SymbolicDist.bigDist,
|
||||
shape: ProbExample.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),
|
||||
};
|
||||
};
|
||||
|
||||
module DistPlus = {
|
||||
let defaultRecommendedLength = 10000;
|
||||
let defaultShouldTruncate = true;
|
||||
type inputs = {
|
||||
distPlusIngredients: DistTypes.distPlusIngredients,
|
||||
samplingInputs: Sampling.inputs,
|
||||
recommendedLength: int,
|
||||
shouldTruncate: bool,
|
||||
};
|
||||
let make =
|
||||
(
|
||||
~samplingInputs=Sampling.Inputs.empty,
|
||||
~recommendedLength=defaultRecommendedLength,
|
||||
~shouldTruncate=defaultShouldTruncate,
|
||||
~distPlusIngredients,
|
||||
()
|
||||
)
|
||||
: inputs => {
|
||||
distPlusIngredients,
|
||||
samplingInputs,
|
||||
recommendedLength,
|
||||
shouldTruncate,
|
||||
};
|
||||
};
|
|
@ -19,12 +19,8 @@ let propValue = (t: Prop.Value.t) => {
|
|||
| ConditionalArray(r) => "Array" |> ReasonReact.string
|
||||
| DistPlusIngredients((r: DistTypes.distPlusIngredients)) =>
|
||||
let newDistribution =
|
||||
DistPlusIngredients.toDistPlus(
|
||||
~sampleCount=1000,
|
||||
~outputXYPoints=2000,
|
||||
~truncateTo=Some(500),
|
||||
r,
|
||||
);
|
||||
RenderTypes.DistPlus.make(~distPlusIngredients=r, ~recommendedLength=1000, ~shouldTruncate=true,())
|
||||
|> DistPlusIngredients.toDistPlus
|
||||
switch (newDistribution) {
|
||||
| Some(distribution) =>
|
||||
<div> <DistPlusPlot distPlus=distribution /> </div>
|
||||
|
|
|
@ -110,6 +110,7 @@ module Model = {
|
|||
// TODO: Fixe number that integral is calculated for
|
||||
let getGlobalCatastropheChance = dateTime => {
|
||||
GlobalCatastrophe.makeI(MomentRe.momentNow())
|
||||
|> RenderTypes.DistPlus.make(~distPlusIngredients=_, ())
|
||||
|> DistPlusIngredients.toDistPlus
|
||||
|> E.O.bind(_, Distributions.DistPlusTime.Integral.xToY(Time(dateTime)));
|
||||
};
|
||||
|
|
|
@ -245,6 +245,5 @@ let fromString = str => {
|
|||
}
|
||||
);
|
||||
let value = E.R.bind(mathJsParse, MathAdtToDistDst.run);
|
||||
Js.log4("fromString", mathJsToJson, mathJsParse, value);
|
||||
value;
|
||||
};
|
|
@ -296,7 +296,7 @@ module PointwiseAddDistributionsWeighted = {
|
|||
let normalized = normalizeWeights(dists);
|
||||
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 shape = MixedShapeBuilder.buildSimple(~continuous, ~discrete);
|
||||
let shape = MixedShapeBuilder.buildSimple(~continuous=Some(continuous), ~discrete);
|
||||
shape |> E.O.toExt("")
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user