From 67ee34d8211beb56eed04c8bb2d51ef487865452 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 25 Feb 2020 12:28:26 +0000 Subject: [PATCH 1/5] Actually use cache when needed --- showcase/entries/Continuous.re | 10 +++- src/components/charts/DistPlusPlot.re | 1 - src/distributions/DistPlusIngredients.re | 8 ++- src/distributions/Distributions.re | 70 ++++++++++++------------ src/models/GlobalCatastrophe.re | 2 +- src/utility/Guesstimator.re | 20 +++++-- src/utility/GuesstimatorLibrary.js | 2 +- 7 files changed, 66 insertions(+), 47 deletions(-) diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re index 0406f5b8..4dba4e73 100644 --- a/showcase/entries/Continuous.re +++ b/showcase/entries/Continuous.re @@ -3,7 +3,7 @@ let timeDist = DistPlusIngredients.make( - ~guesstimatorString="mm(floor(10 to 15), 10 to 11, [.9,.1])", + ~guesstimatorString="(floor(10 to 15))", ~domain=Complete, ~unit= DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}), @@ -12,7 +12,11 @@ let timeDist = let setup = dist => dist - |> DistPlusIngredients.toDistPlus(~sampleCount=5000, ~outputXYPoints=1000); + |> DistPlusIngredients.toDistPlus( + ~sampleCount=10000, + ~outputXYPoints=2000, + ~truncateTo=Some(1000), + ); let distributions = () =>
@@ -20,7 +24,7 @@ let distributions = () =>

{"Single-Discrete" |> ReasonReact.string}

{setup( DistPlusIngredients.make( - ~guesstimatorString="8 to 12, [.5,.5])", + ~guesstimatorString="mm(5 to 20, floor(normal(20,2)), [.5, .05])", ~domain=Complete, (), ), diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index 1d8027f3..4a37c99b 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -37,7 +37,6 @@ module IntegralChart = { let minX = integral |> Distributions.Continuous.T.minX; let maxX = integral |> Distributions.Continuous.T.maxX; let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson; - Js.log3("HIHI", continuous, distPlus); { let shape = Guesstimator.stringToMixedShape( ~string=t.guesstimatorString, ~sampleCount, ~outputXYPoints, + ~truncateTo, (), ); let distPlus = diff --git a/src/distributions/Distributions.re b/src/distributions/Distributions.re index 7773d453..aa9851ab 100644 --- a/src/distributions/Distributions.re +++ b/src/distributions/Distributions.re @@ -127,14 +127,15 @@ module Continuous = { // }; let integral = (~cache, t) => - cache - |> E.O.default( - t - |> xyShape - |> XYShape.Range.integrateWithTriangles - |> E.O.toExt("This should not have happened") - |> fromShape, - ); + switch (cache) { + | Some(cache) => cache + | None => + t + |> xyShape + |> XYShape.Range.integrateWithTriangles + |> E.O.toExt("This should not have happened") + |> fromShape + }; let integralEndY = (~cache, t) => t |> integral(~cache) |> lastY; let integralXtoY = (~cache, f, t) => t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f)); @@ -151,8 +152,10 @@ module Discrete = { type t = DistTypes.discreteShape; type integral = DistTypes.continuousShape; let integral = (~cache, t) => - cache - |> E.O.default(Continuous.make(XYShape.accumulateYs(t), `Stepwise)); + switch (cache) { + | Some(c) => c + | None => Continuous.make(XYShape.accumulateYs(t), `Stepwise) + }; let integralEndY = (~cache, t) => t |> integral(~cache) |> Continuous.lastY; let minX = XYShape.minX; @@ -253,32 +256,27 @@ module Mixed = { ~cache, {continuous, discrete, discreteProbabilityMassFraction} as t: t, ) => { - cache - |> E.O.default( - { - let cont = - continuous - |> Continuous.T.Integral.get(~cache=None) - |> scaleContinuous(t); - let dist = - discrete - |> Discrete.T.Integral.get(~cache=None) - |> Continuous.toLinear - |> E.O.toExn("") - |> Continuous.T.scaleBy( - ~scale=discreteProbabilityMassFraction, - ); - Continuous.make( - XYShape.Combine.combineLinear( - Continuous.getShape(cont), - Continuous.getShape(dist), - (a, b) => - a +. b - ), - `Linear, - ); - }, - ); + switch (cache) { + | Some(cache) => cache + | None => + let cont = + continuous + |> Continuous.T.Integral.get(~cache=None) + |> scaleContinuous(t); + let dist = + discrete + |> Discrete.T.Integral.get(~cache=None) + |> Continuous.toLinear + |> E.O.toExn("") + |> Continuous.T.scaleBy(~scale=discreteProbabilityMassFraction); + Continuous.make( + XYShape.Combine.combineLinear( + Continuous.getShape(cont), Continuous.getShape(dist), (a, b) => + a +. b + ), + `Linear, + ); + }; }; let integralEndY = (~cache, t: t) => { diff --git a/src/models/GlobalCatastrophe.re b/src/models/GlobalCatastrophe.re index 82cbfc56..ad633077 100644 --- a/src/models/GlobalCatastrophe.re +++ b/src/models/GlobalCatastrophe.re @@ -1,4 +1,4 @@ -let guesstimatorString = "floor(10 to 20)"; +let guesstimatorString = "normal(40,10)"; let makeI = (currentDateTime: MomentRe.Moment.t) => { DistPlusIngredients.make( diff --git a/src/utility/Guesstimator.re b/src/utility/Guesstimator.re index 9fe403bc..51ee992a 100644 --- a/src/utility/Guesstimator.re +++ b/src/utility/Guesstimator.re @@ -29,9 +29,15 @@ module Internals = { external toCombinedFormat: (string, int, int) => combined = "run"; // todo: Format to correct mass, also normalize the pdf. - let toMixedShape = (r: combined): option(DistTypes.shape) => { + let toMixedShape = + (~truncateTo=Some(500), r: combined): option(DistTypes.shape) => { + let continuous = toContinous(r); let continuous = - toContinous(r) |> Distributions.Continuous.convertToNewLength(100); + switch (truncateTo) { + | Some(t) => + continuous |> Distributions.Continuous.convertToNewLength(t) + | None => continuous + }; let discrete = toDiscrete(r); // let continuousProb = // cont |> Distributions.Continuous.T.Integral.sum(~cache=None); @@ -44,6 +50,12 @@ module Internals = { }; let stringToMixedShape = - (~string, ~sampleCount=1000, ~outputXYPoints=1000, ()) => + ( + ~string, + ~sampleCount=1000, + ~outputXYPoints=1000, + ~truncateTo=Some(500), + (), + ) => Internals.toCombinedFormat(string, sampleCount, outputXYPoints) - |> Internals.toMixedShape; \ No newline at end of file + |> Internals.toMixedShape(~truncateTo); \ No newline at end of file diff --git a/src/utility/GuesstimatorLibrary.js b/src/utility/GuesstimatorLibrary.js index 8b4deef9..06c2513c 100644 --- a/src/utility/GuesstimatorLibrary.js +++ b/src/utility/GuesstimatorLibrary.js @@ -42,7 +42,7 @@ const toPdf = (values, outputResolutionCount, min, max) => { let discrete = {xs: frequencies.map(f => f.value), ys: frequencies.map(f => f.percentage)}; let continuous = {ys: [], xs: []}; - if (continuousSamples.length > 1){ + if (continuousSamples.length > 20){ const samples = new Samples(continuousSamples); const ratioSize$ = ratioSize(samples); From a940fa30b78efbcb24a2b61ae79aa6bb36c55759 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 25 Feb 2020 12:54:52 +0000 Subject: [PATCH 2/5] Fixed mass-ratio of continuous vs. discrete --- showcase/entries/Continuous.re | 2 +- src/components/charts/DistPlusPlot.re | 64 ++++++++++++++++++++++++++ src/distributions/Distributions.re | 15 ------ src/distributions/MixedShapeBuilder.re | 13 ++++-- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re index 4dba4e73..1d4baeb5 100644 --- a/showcase/entries/Continuous.re +++ b/showcase/entries/Continuous.re @@ -24,7 +24,7 @@ let distributions = () =>

{"Single-Discrete" |> ReasonReact.string}

{setup( DistPlusIngredients.make( - ~guesstimatorString="mm(5 to 20, floor(normal(20,2)), [.5, .05])", + ~guesstimatorString="mm(5 to 20, floor(normal(20,2)), [.5, .5])", ~domain=Complete, (), ), diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index 4a37c99b..c7975bca 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -77,6 +77,9 @@ let make = (~distPlus: DistTypes.distPlus) => { {"Y Integral to Point" |> ReasonReact.string} + + {"Y Integral Total" |> ReasonReact.string} + @@ -104,12 +107,73 @@ let make = (~distPlus: DistTypes.distPlus) => { |> E.Float.with2DigitsPrecision |> ReasonReact.string} + + + + + + + + + + + + + + + + + + +
+ {"Y Integral Total" |> ReasonReact.string} + + {"Continuous Total" |> ReasonReact.string} + + {"Scaled Continuous Total" |> ReasonReact.string} + + {"Discrete Total" |> ReasonReact.string} + + {"Scaled Discrete Total" |> ReasonReact.string} +
{distPlus |> Distributions.DistPlus.T.Integral.sum(~cache=None) |> E.Float.with2DigitsPrecision |> ReasonReact.string} + {distPlus + |> Distributions.DistPlus.T.toContinuous + |> E.O.fmap( + Distributions.Continuous.T.Integral.sum(~cache=None), + ) + |> E.O.fmap(E.Float.with2DigitsPrecision) + |> E.O.default("") + |> ReasonReact.string} + + {distPlus + |> Distributions.DistPlus.T.toScaledContinuous + |> E.O.fmap( + Distributions.Continuous.T.Integral.sum(~cache=None), + ) + |> E.O.fmap(E.Float.with2DigitsPrecision) + |> E.O.default("") + |> ReasonReact.string} + + {distPlus + |> Distributions.DistPlus.T.toDiscrete + |> E.O.fmap(Distributions.Discrete.T.Integral.sum(~cache=None)) + |> E.O.fmap(E.Float.with2DigitsPrecision) + |> E.O.default("") + |> ReasonReact.string} + + {distPlus + |> Distributions.DistPlus.T.toScaledDiscrete + |> E.O.fmap(Distributions.Discrete.T.Integral.sum(~cache=None)) + |> E.O.fmap(E.Float.with2DigitsPrecision) + |> E.O.default("") + |> ReasonReact.string} +
diff --git a/src/distributions/Distributions.re b/src/distributions/Distributions.re index aa9851ab..61aa25fe 100644 --- a/src/distributions/Distributions.re +++ b/src/distributions/Distributions.re @@ -191,21 +191,6 @@ module Mixed = { discreteProbabilityMassFraction, }; - let clean = (t: DistTypes.mixedShape): option(DistTypes.shape) => { - switch (t) { - | { - continuous: {xyShape: {xs: [||], ys: [||]}}, - discrete: {xs: [||], ys: [||]}, - } => - None - | {continuous, discrete: {xs: [||], ys: [||]}} => - Some(Continuous(continuous)) - | {continuous: {xyShape: {xs: [||], ys: [||]}}, discrete} => - Some(Discrete(discrete)) - | shape => Some(Mixed(shape)) - }; - }; - // todo: Put into scaling module let scaleDiscreteFn = ({discreteProbabilityMassFraction}: DistTypes.mixedShape, f) => diff --git a/src/distributions/MixedShapeBuilder.re b/src/distributions/MixedShapeBuilder.re index cd4e4ca3..feab0ad6 100644 --- a/src/distributions/MixedShapeBuilder.re +++ b/src/distributions/MixedShapeBuilder.re @@ -21,16 +21,21 @@ let buildSimple = (~continuous, ~discrete): option(DistTypes.shape) => { Distributions.Discrete.T.Integral.sum(~cache=None, discrete); let discrete = Distributions.Discrete.T.scaleToIntegralSum(~intendedSum=1.0, discrete); - let foobar = + let continuous = + Distributions.Continuous.T.scaleToIntegralSum( + ~intendedSum=1.0, + continuous, + ); + let mixedDist = Distributions.Mixed.make( ~continuous, ~discrete, ~discreteProbabilityMassFraction, - ) - |> Distributions.Mixed.clean; - foobar; + ); + Some(Mixed(mixedDist)); }; }; + let build = (~continuous, ~discrete, ~assumptions) => switch (assumptions) { | { From c30fab22c74f88a1f45e1bd4ad4c084d1c6cc8f3 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 25 Feb 2020 19:27:30 +0000 Subject: [PATCH 3/5] Fixed math around fixed integral calculations --- showcase/entries/Continuous.re | 5 ++- src/components/charts/DistPlusPlot.re | 21 ++++----- src/distributions/DistPlusIngredients.re | 4 +- src/distributions/DistTypes.re | 2 +- src/distributions/Distributions.re | 54 +++++++++++++++++------- src/models/EAFunds.re | 18 ++------ 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re index 1d4baeb5..f0a9b7d8 100644 --- a/showcase/entries/Continuous.re +++ b/showcase/entries/Continuous.re @@ -4,7 +4,7 @@ let timeDist = DistPlusIngredients.make( ~guesstimatorString="(floor(10 to 15))", - ~domain=Complete, + ~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}), ~unit= DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}), (), @@ -25,7 +25,8 @@ let distributions = () => {setup( DistPlusIngredients.make( ~guesstimatorString="mm(5 to 20, floor(normal(20,2)), [.5, .5])", - ~domain=Complete, + ~domain= + RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}), (), ), ) diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index c7975bca..e60062e3 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -2,11 +2,10 @@ module DistPlusChart = { [@react.component] let make = (~distPlus: DistTypes.distPlus, ~onHover) => { open Distributions.DistPlus; - // todo: Change to scaledContinuous and scaledDiscrete - let discrete = distPlus |> T.toDiscrete; + let discrete = distPlus |> T.toScaledDiscrete; let continuous = distPlus - |> T.toContinuous + |> T.toScaledContinuous |> E.O.fmap(Distributions.Continuous.getShape); let minX = T.minX(distPlus); let maxX = T.maxX(distPlus); @@ -40,6 +39,7 @@ module IntegralChart = { { |> E.Float.with2DigitsPrecision |> ReasonReact.string} + + {distPlus + |> Distributions.DistPlus.T.Integral.sum(~cache=None) + |> E.Float.with2DigitsPrecision + |> ReasonReact.string} + - @@ -132,12 +135,6 @@ let make = (~distPlus: DistTypes.distPlus) => { -
- {"Y Integral Total" |> ReasonReact.string} - {"Continuous Total" |> ReasonReact.string}
- {distPlus - |> Distributions.DistPlus.T.Integral.sum(~cache=None) - |> E.Float.with2DigitsPrecision - |> ReasonReact.string} - {distPlus |> Distributions.DistPlus.T.toContinuous diff --git a/src/distributions/DistPlusIngredients.re b/src/distributions/DistPlusIngredients.re index 6431059c..9882b917 100644 --- a/src/distributions/DistPlusIngredients.re +++ b/src/distributions/DistPlusIngredients.re @@ -11,8 +11,8 @@ let make = let toDistPlus = ( ~sampleCount=2000, - ~outputXYPoints=2000, - ~truncateTo=Some(100), + ~outputXYPoints=1500, + ~truncateTo=Some(300), t: distPlusIngredients, ) : option(distPlus) => { diff --git a/src/distributions/DistTypes.re b/src/distributions/DistTypes.re index d970a824..3ce13e1d 100644 --- a/src/distributions/DistTypes.re +++ b/src/distributions/DistTypes.re @@ -120,7 +120,7 @@ module MixedPoint = { let makeContinuous = (continuous: float): t => {continuous, discrete: 0.0}; let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete}; - let fmap = (fn, t: t) => { + let fmap = (fn: float => float, t: t) => { continuous: fn(t.continuous), discrete: fn(t.discrete), }; diff --git a/src/distributions/Distributions.re b/src/distributions/Distributions.re index 61aa25fe..6afd2e06 100644 --- a/src/distributions/Distributions.re +++ b/src/distributions/Distributions.re @@ -202,10 +202,15 @@ module Mixed = { let scaleContinuous = ({discreteProbabilityMassFraction}: t, continuous) => continuous - |> Continuous.T.scaleBy(~scale=1.0 -. discreteProbabilityMassFraction); + |> Continuous.T.scaleToIntegralSum( + ~intendedSum=1.0 -. discreteProbabilityMassFraction, + ); let scaleDiscrete = ({discreteProbabilityMassFraction}: t, disrete) => - disrete |> Discrete.T.scaleBy(~scale=discreteProbabilityMassFraction); + disrete + |> Discrete.T.scaleToIntegralSum( + ~intendedSum=discreteProbabilityMassFraction, + ); module T = Dist({ @@ -239,28 +244,46 @@ module Mixed = { let integral = ( ~cache, - {continuous, discrete, discreteProbabilityMassFraction} as t: t, + {continuous, discrete, discreteProbabilityMassFraction}: t, ) => { switch (cache) { | Some(cache) => cache | None => + let scaleContinuousBy = + (1.0 -. discreteProbabilityMassFraction) + /. (continuous |> Continuous.T.Integral.sum(~cache=None)); + + let scaleDiscreteBy = + discreteProbabilityMassFraction + /. ( + discrete + |> Discrete.T.Integral.get(~cache=None) + |> Continuous.toLinear + |> E.O.fmap(Continuous.lastY) + |> E.O.toExn("") + ); + let cont = continuous |> Continuous.T.Integral.get(~cache=None) - |> scaleContinuous(t); + |> Continuous.T.scaleBy(~scale=scaleContinuousBy); + let dist = discrete |> Discrete.T.Integral.get(~cache=None) |> Continuous.toLinear |> E.O.toExn("") - |> Continuous.T.scaleBy(~scale=discreteProbabilityMassFraction); - Continuous.make( - XYShape.Combine.combineLinear( - Continuous.getShape(cont), Continuous.getShape(dist), (a, b) => - a +. b - ), - `Linear, - ); + |> Continuous.T.scaleBy(~scale=scaleDiscreteBy); + + let result = + Continuous.make( + XYShape.Combine.combineLinear( + Continuous.getShape(cont), Continuous.getShape(dist), (a, b) => + a +. b + ), + `Linear, + ); + result; }; }; @@ -484,7 +507,6 @@ module DistPlus = { let minX = shapeFn(Shape.T.minX); let maxX = shapeFn(Shape.T.maxX); - let fromShape = (t, shape): t => update(~shape, t); // This bit is kind of akward, could probably use rethinking. let integral = (~cache, t: t) => @@ -499,14 +521,14 @@ module DistPlus = { // TODO: Fix this below, obviously. Adjust for limits let integralXtoY = (~cache as _, f, t: t) => { - Shape.T.Integral.xToY(~cache=Some(t.integralCache), f, toShape(t)); + Shape.T.Integral.xToY(~cache=Some(t.integralCache), f, toShape(t)) + |> domainIncludedProbabilityMassAdjustment(t); }; }); }; module DistPlusTime = { open DistTypes; - open DistPlus; type t = DistTypes.distPlus; @@ -529,7 +551,7 @@ module DistPlusTime = { module Integral = { include DistPlus.T.Integral; - let xToY = (~cache as _, f: TimeTypes.timeInVector, t: t) => { + let xToY = (f: TimeTypes.timeInVector, t: t) => { timeInVectorToX(f, t) |> E.O.fmap(x => DistPlus.T.Integral.xToY(~cache=None, x, t)); }; diff --git a/src/models/EAFunds.re b/src/models/EAFunds.re index 1dd3a3df..c15f4726 100644 --- a/src/models/EAFunds.re +++ b/src/models/EAFunds.re @@ -110,19 +110,8 @@ module Model = { // TODO: Fixe number that integral is calculated for let getGlobalCatastropheChance = dateTime => { GlobalCatastrophe.makeI(MomentRe.momentNow()) - |> DistPlusIngredients.toDistPlus(~sampleCount=1000) - |> E.O.bind( - _, - t => { - let foo = - Distributions.DistPlusTime.Integral.xToY( - ~cache=None, - Time(dateTime), - t, - ); - Some(0.5); - }, - ); + |> DistPlusIngredients.toDistPlus + |> E.O.bind(_, Distributions.DistPlusTime.Integral.xToY(Time(dateTime))); }; let make = @@ -151,8 +140,7 @@ module Model = { | Some({truthValue: false}) => difference | None => let foo = - // getGlobalCatastropheChance(dateTime) - Some(0.5) + getGlobalCatastropheChance(dateTime) |> E.O.fmap(E.Float.with2DigitsPrecision) |> E.O.fmap((r: string) => "uniform(0,1) > " ++ r ++ " ? " ++ difference ++ ": 0" From ddd0bc082001f7e4495659673227b7e90900650a Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 25 Feb 2020 19:55:01 +0000 Subject: [PATCH 4/5] Make sure that chart minimum is shown --- showcase/entries/Continuous.re | 4 +++- src/components/charts/DistPlusPlot.re | 8 +++++++- .../charts/DistributionPlot/distPlotReact.js | 4 ++-- src/distributions/Distributions.re | 3 ++- src/distributions/TimeTypes.re | 5 +++-- src/interface/FormBuilder.re | 14 +++++++++++--- src/models/GlobalCatastrophe.re | 11 +++-------- src/utility/Guesstimator.re | 4 ++-- src/utility/GuesstimatorLibrary.js | 6 +++--- 9 files changed, 36 insertions(+), 23 deletions(-) diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re index f0a9b7d8..a86d6004 100644 --- a/showcase/entries/Continuous.re +++ b/showcase/entries/Continuous.re @@ -1,6 +1,7 @@ // "mm(floor(uniform(30,35)), normal(50,20), [.25,.5])", // "mm(floor(normal(28,4)), normal(32,2), uniform(20,24), [.5,.2,.1])", +// "mm(5 to 20, floor(normal(20,2)), [.5, .5])", let timeDist = DistPlusIngredients.make( ~guesstimatorString="(floor(10 to 15))", @@ -24,7 +25,8 @@ let distributions = () =>

{"Single-Discrete" |> ReasonReact.string}

{setup( DistPlusIngredients.make( - ~guesstimatorString="mm(5 to 20, floor(normal(20,2)), [.5, .5])", + ~guesstimatorString= + "uniform(0,1) > 0.036 ? lognormal(6.652, -0.41): 0", ~domain= RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}), (), diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index e60062e3..4fadde2d 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -7,7 +7,13 @@ module DistPlusChart = { distPlus |> T.toScaledContinuous |> E.O.fmap(Distributions.Continuous.getShape); - let minX = T.minX(distPlus); + let range = T.xTotalRange(distPlus); + let minX = + switch (T.minX(distPlus), range) { + | (Some(min), Some(range)) => Some(min -. range *. 0.001) + | _ => None + }; + let maxX = T.maxX(distPlus); let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson; + let minX = ({continuous, discrete}: t) => { min(Continuous.T.minX(continuous), Discrete.T.minX(discrete)); + }; let maxX = ({continuous, discrete}: t) => max(Continuous.T.maxX(continuous), Discrete.T.maxX(discrete)); let toShape = (t: t): DistTypes.shape => Mixed(t); diff --git a/src/distributions/TimeTypes.re b/src/distributions/TimeTypes.re index 355e8ba5..7a8368e0 100644 --- a/src/distributions/TimeTypes.re +++ b/src/distributions/TimeTypes.re @@ -63,8 +63,9 @@ module RelativeTimePoint = { |> MomentRe.Moment.add(~duration=MomentRe.duration(r, timeVector.unit)) }; - let _timeToX = (time, timeStart, timeUnit) => - MomentRe.diff(timeStart, time, timeUnit); + let _timeToX = (time, timeStart, timeUnit) => { + MomentRe.diff(time, timeStart, timeUnit); + }; let toXValue = (timeVector: timeVector, timeInVector: timeInVector) => switch (timeInVector) { diff --git a/src/interface/FormBuilder.re b/src/interface/FormBuilder.re index 55f1bf23..6a66e981 100644 --- a/src/interface/FormBuilder.re +++ b/src/interface/FormBuilder.re @@ -17,12 +17,20 @@ let propValue = (t: Prop.Value.t) => { switch (t) { | SelectSingle(r) => r |> ReasonReact.string | ConditionalArray(r) => "Array" |> ReasonReact.string - | DistPlusIngredients(r) => + | DistPlusIngredients((r: DistTypes.distPlusIngredients)) => let newDistribution = - DistPlusIngredients.toDistPlus(~sampleCount=1000, r); + DistPlusIngredients.toDistPlus( + ~sampleCount=2000, + ~outputXYPoints=2000, + ~truncateTo=Some(100), + r, + ); switch (newDistribution) { | Some(distribution) => -
+
+ + {r.guesstimatorString |> ReasonReact.string} +
| None => "Something went wrong" |> ReasonReact.string }; | FloatCdf(_) =>
diff --git a/src/models/GlobalCatastrophe.re b/src/models/GlobalCatastrophe.re index ad633077..239a8829 100644 --- a/src/models/GlobalCatastrophe.re +++ b/src/models/GlobalCatastrophe.re @@ -1,21 +1,16 @@ -let guesstimatorString = "normal(40,10)"; +let guesstimatorString = "uniform(1, 100)"; let makeI = (currentDateTime: MomentRe.Moment.t) => { DistPlusIngredients.make( ~guesstimatorString, ~unit=TimeDistribution({zero: currentDateTime, unit: `years}), + ~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}), (), ); }; module Model = { let make = (currentDateTime: MomentRe.Moment.t) => { - let distPlusIngredients = - DistPlusIngredients.make( - ~guesstimatorString, - ~unit=TimeDistribution({zero: currentDateTime, unit: `years}), - (), - ); - Prop.Value.DistPlusIngredients(distPlusIngredients); + Prop.Value.DistPlusIngredients(makeI(currentDateTime)); }; }; diff --git a/src/utility/Guesstimator.re b/src/utility/Guesstimator.re index 51ee992a..1e4bf9f4 100644 --- a/src/utility/Guesstimator.re +++ b/src/utility/Guesstimator.re @@ -52,8 +52,8 @@ module Internals = { let stringToMixedShape = ( ~string, - ~sampleCount=1000, - ~outputXYPoints=1000, + ~sampleCount=3000, + ~outputXYPoints=3000, ~truncateTo=Some(500), (), ) => diff --git a/src/utility/GuesstimatorLibrary.js b/src/utility/GuesstimatorLibrary.js index 06c2513c..cef3a65b 100644 --- a/src/utility/GuesstimatorLibrary.js +++ b/src/utility/GuesstimatorLibrary.js @@ -13,9 +13,9 @@ const minMaxRatio = (minValue, maxValue) => { return 'SMALL'; } const ratio = maxValue / minValue; - if (ratio < 100000) { + if (ratio < 10000) { return 'SMALL'; - } else if (ratio < 10000000) { + } else if (ratio < 1000000) { return 'MEDIUM'; } else { return 'LARGE'; @@ -46,7 +46,7 @@ const toPdf = (values, outputResolutionCount, min, max) => { const samples = new Samples(continuousSamples); const ratioSize$ = ratioSize(samples); - const width = ratioSize$ === 'SMALL' ? 100 : 1; + const width = ratioSize$ === 'SMALL' ? 40 : 1; const pdf = samples.toPdf({ size: outputResolutionCount, width, min, max }); continuous = pdf; From f2d52e61809e700e993f63abdac001159bb21f2b Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 25 Feb 2020 20:08:53 +0000 Subject: [PATCH 5/5] Minor touches to models --- src/components/charts/DistPlusPlot.re | 7 ++++++- src/models/EAFunds.re | 7 ++++--- src/utility/GuesstimatorLibrary.js | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index 4fadde2d..3a132689 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -39,7 +39,12 @@ module IntegralChart = { integral |> Distributions.Continuous.toLinear |> E.O.fmap(Distributions.Continuous.getShape); - let minX = integral |> Distributions.Continuous.T.minX; + let range = T.xTotalRange(distPlus); + let minX = + switch (T.minX(distPlus), range) { + | (Some(min), Some(range)) => Some(min -. range *. 0.001) + | _ => None + }; let maxX = integral |> Distributions.Continuous.T.maxX; let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson; { - {meanDiff: 1.1, stdDiff: 1.1}; + {meanDiff: 1.1, stdDiff: 1.08}; }; let calculateDifference = (currentValue, dateTime, currentDateTime, y: yearlyNumericDiff) => { let yearDiff = MomentRe.diff(dateTime, currentDateTime, `days) /. 365.; let meanDiff = Js.Math.pow_float(~base=y.meanDiff, ~exp=yearDiff); - let stdDevDiff = Js.Math.pow_float(~base=y.meanDiff, ~exp=yearDiff); + let stdDevDiff = Js.Math.pow_float(~base=y.stdDiff, ~exp=yearDiff); GuesstimatorDist.logNormal( currentValue *. meanDiff, firstYearStdDev *. stdDevDiff, @@ -163,8 +163,9 @@ module Model = { ~guesstimatorString= GuesstimatorDist.min( GlobalCatastrophe.guesstimatorString, - GuesstimatorDist.logNormal(40., 4.), + GuesstimatorDist.logNormal(20., 2.), ), + ~unit=TimeDistribution({zero: currentDateTime, unit: `years}), ~domain=RightLimited({xPoint: 100., excludingProbabilityMass: 0.3}), (), ), diff --git a/src/utility/GuesstimatorLibrary.js b/src/utility/GuesstimatorLibrary.js index cef3a65b..bbe6a493 100644 --- a/src/utility/GuesstimatorLibrary.js +++ b/src/utility/GuesstimatorLibrary.js @@ -46,7 +46,7 @@ const toPdf = (values, outputResolutionCount, min, max) => { const samples = new Samples(continuousSamples); const ratioSize$ = ratioSize(samples); - const width = ratioSize$ === 'SMALL' ? 40 : 1; + const width = ratioSize$ === 'SMALL' ? 60 : 1; const pdf = samples.toPdf({ size: outputResolutionCount, width, min, max }); continuous = pdf;