diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re
index 0406f5b8..a86d6004 100644
--- a/showcase/entries/Continuous.re
+++ b/showcase/entries/Continuous.re
@@ -1,10 +1,11 @@
// "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="mm(floor(10 to 15), 10 to 11, [.9,.1])",
- ~domain=Complete,
+ ~guesstimatorString="(floor(10 to 15))",
+ ~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}),
~unit=
DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
(),
@@ -12,7 +13,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,8 +25,10 @@ let distributions = () =>
{"Single-Discrete" |> ReasonReact.string}
{setup(
DistPlusIngredients.make(
- ~guesstimatorString="8 to 12, [.5,.5])",
- ~domain=Complete,
+ ~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 1d8027f3..3a132689 100644
--- a/src/components/charts/DistPlusPlot.re
+++ b/src/components/charts/DistPlusPlot.re
@@ -2,13 +2,18 @@ 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 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;
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;
- Js.log3("HIHI", continuous, distPlus);
{
{"Y Integral to Point" |> ReasonReact.string}
|
+
+ {"Y Integral Total" |> ReasonReact.string}
+ |
@@ -114,6 +127,64 @@ let make = (~distPlus: DistTypes.distPlus) => {
+
+
+
+
+ {"Continuous Total" |> ReasonReact.string}
+ |
+
+ {"Scaled Continuous Total" |> ReasonReact.string}
+ |
+
+ {"Discrete Total" |> ReasonReact.string}
+ |
+
+ {"Scaled Discrete Total" |> 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}
+ |
+
+
+
;
// chart
diff --git a/src/components/charts/DistributionPlot/distPlotReact.js b/src/components/charts/DistributionPlot/distPlotReact.js
index fff61201..3fe3ee09 100644
--- a/src/components/charts/DistributionPlot/distPlotReact.js
+++ b/src/components/charts/DistributionPlot/distPlotReact.js
@@ -40,8 +40,8 @@ function CdfChartReact(props) {
.minX(props.minX)
.onHover(props.onHover)
.marginBottom(props.marginBottom || 15)
- .marginLeft(5)
- .marginRight(5)
+ .marginLeft(30)
+ .marginRight(30)
.marginTop(5)
.showDistributionLines(props.showDistributionLines)
.showDistributionYAxis(props.showDistributionYAxis)
diff --git a/src/distributions/DistPlusIngredients.re b/src/distributions/DistPlusIngredients.re
index b1174737..9882b917 100644
--- a/src/distributions/DistPlusIngredients.re
+++ b/src/distributions/DistPlusIngredients.re
@@ -9,13 +9,19 @@ let make =
};
let toDistPlus =
- (~sampleCount=1000, ~outputXYPoints=1000, t: distPlusIngredients)
+ (
+ ~sampleCount=2000,
+ ~outputXYPoints=1500,
+ ~truncateTo=Some(300),
+ t: distPlusIngredients,
+ )
: option(distPlus) => {
let shape =
Guesstimator.stringToMixedShape(
~string=t.guesstimatorString,
~sampleCount,
~outputXYPoints,
+ ~truncateTo,
(),
);
let 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 7773d453..111b6ef0 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;
@@ -188,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) =>
@@ -214,17 +202,23 @@ 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({
type t = DistTypes.mixedShape;
type integral = DistTypes.continuousShape;
- let minX = ({continuous, discrete}: t) =>
+ 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);
@@ -251,34 +245,47 @@ module Mixed = {
let integral =
(
~cache,
- {continuous, discrete, discreteProbabilityMassFraction} as t: t,
+ {continuous, discrete, discreteProbabilityMassFraction}: 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 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)
+ |> Continuous.T.scaleBy(~scale=scaleContinuousBy);
+
+ let dist =
+ discrete
+ |> Discrete.T.Integral.get(~cache=None)
+ |> Continuous.toLinear
+ |> E.O.toExn("")
+ |> Continuous.T.scaleBy(~scale=scaleDiscreteBy);
+
+ let result =
+ Continuous.make(
+ XYShape.Combine.combineLinear(
+ Continuous.getShape(cont), Continuous.getShape(dist), (a, b) =>
+ a +. b
+ ),
+ `Linear,
+ );
+ result;
+ };
};
let integralEndY = (~cache, t: t) => {
@@ -501,7 +508,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) =>
@@ -516,14 +522,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;
@@ -546,7 +552,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/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) {
| {
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/EAFunds.re b/src/models/EAFunds.re
index 1dd3a3df..a8c30de2 100644
--- a/src/models/EAFunds.re
+++ b/src/models/EAFunds.re
@@ -70,14 +70,14 @@ module Model = {
};
let yearlyMeanGrowthRateIfNotClosed = (group: group): yearlyNumericDiff => {
- {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,
@@ -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"
@@ -175,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/models/GlobalCatastrophe.re b/src/models/GlobalCatastrophe.re
index 82cbfc56..239a8829 100644
--- a/src/models/GlobalCatastrophe.re
+++ b/src/models/GlobalCatastrophe.re
@@ -1,21 +1,16 @@
-let guesstimatorString = "floor(10 to 20)";
+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 9fe403bc..1e4bf9f4 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=3000,
+ ~outputXYPoints=3000,
+ ~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..bbe6a493 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';
@@ -42,11 +42,11 @@ 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);
- const width = ratioSize$ === 'SMALL' ? 100 : 1;
+ const width = ratioSize$ === 'SMALL' ? 60 : 1;
const pdf = samples.toPdf({ size: outputResolutionCount, width, min, max });
continuous = pdf;