Making model accessible with GenericDistribution

This commit is contained in:
Ozzie Gooen 2020-02-15 23:01:59 +00:00
parent 626b4f65c3
commit beda0b61ed
10 changed files with 248 additions and 189 deletions

View File

@ -26,19 +26,18 @@ let _lastElement = (a: array('a)) =>
let probabilityBeforeDomainMax = (t: t) => _lastElement(t.distribution.ys); let probabilityBeforeDomainMax = (t: t) => _lastElement(t.distribution.ys);
let domainMaxX = (t: t) => t.domainMaxX; let domainMaxX = (t: t) => t.domainMaxX /* CdfLibrary.Distribution.findX(yPoint, t.distribution)*/;
let probabilityDistribution = (t: t) => // let probabilityDistribution = (t: t) =>
t.distribution |> CdfLibrary.Distribution.toPdf; // t.distribution |> CdfLibrary.Distribution.toPdf;
let probability = (t: t, xPoint: float) => // let probability = (t: t, xPoint: float) =>
CdfLibrary.Distribution.findY(xPoint, probabilityDistribution(t)); // CdfLibrary.Distribution.findY(xPoint, probabilityDistribution(t));
let probabilityInverse = (t: t, yPoint: float) => // let probabilityInverse = (t: t, yPoint: float) =>
CdfLibrary.Distribution.findX(yPoint, probabilityDistribution(t)); // CdfLibrary.Distribution.findX(yPoint, probabilityDistribution(t));
let cumulativeProbability = (t: t, xPoint: float) => // let cumulativeProbability = (t: t, xPoint: float) =>
CdfLibrary.Distribution.findY(xPoint, t.distribution); // CdfLibrary.Distribution.findY(xPoint, t.distribution);
let cumulativeProbabilityInverse = (t: t, yPoint: float) => // let cumulativeProbabilityInverse = (t: t, yPoint: float) =>
CdfLibrary.Distribution.findX(yPoint, t.distribution);

View File

@ -27,21 +27,20 @@ let probabilityBeforeDomainMax = (t: t) =>
LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf); LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf);
let domainMaxX = (t: t) => let domainMaxX = (t: t) =>
LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf); LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf) /* |> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)))*/;
let probability = (t: t, m: MomentRe.Moment.t) => { // let probability = (t: t, m: MomentRe.Moment.t) => {
RelativeTimePoint.toXValue(t.timeVector, Time(m)) // RelativeTimePoint.toXValue(t.timeVector, Time(m))
|> LimitedDomainCdf.probability(t.limitedDomainCdf); // |> LimitedDomainCdf.probability(t.limitedDomainCdf);
}; // };
let probabilityInverse = (t: t, y: float) => // let probabilityInverse = (t: t, y: float) =>
LimitedDomainCdf.probabilityInverse(t.limitedDomainCdf, y) // LimitedDomainCdf.probabilityInverse(t.limitedDomainCdf, y)
|> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r))); // |> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)));
let cumulativeProbability = (t: t, m: MomentRe.Moment.t) => // let cumulativeProbability = (t: t, m: MomentRe.Moment.t) =>
RelativeTimePoint.toXValue(t.timeVector, Time(m)) // RelativeTimePoint.toXValue(t.timeVector, Time(m))
|> LimitedDomainCdf.cumulativeProbability(t.limitedDomainCdf); // |> LimitedDomainCdf.cumulativeProbability(t.limitedDomainCdf);
let cumulativeProbabilityInverse = (t: t, y: float) => // let cumulativeProbabilityInverse = (t: t, y: float) =>
LimitedDomainCdf.cumulativeProbabilityInverse(t.limitedDomainCdf, y) // LimitedDomainCdf.cumulativeProbabilityInverse(t.limitedDomainCdf, y)
|> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)));

View File

@ -48,89 +48,4 @@ type genericDistribution = {
probabilityType, probabilityType,
domain, domain,
unit: distributionUnit, unit: distributionUnit,
};
module Shape = {
module Continuous = {
let fromArrays = (xs, ys): continuousShape => {xs, ys};
};
module Discrete = {
let fromArrays = (xs, ys): continuousShape => {xs, ys};
};
module Mixed = {
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
continuous,
discrete,
discreteProbabilityMassFraction,
};
module Builder = {
type assumption =
| ADDS_TO_1
| ADDS_TO_CORRECT_PROBABILITY;
type assumptions = {
continuous: assumption,
discrete: assumption,
discreteProbabilityMass: option(float),
};
let build = (~continuous, ~discrete, ~assumptions) =>
switch (assumptions) {
| {
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: Some(r),
} =>
// TODO: Fix this, it's wrong :(
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: Some(r),
} =>
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: None,
} =>
None
| {
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_1,
discreteProbabilityMass: None,
} =>
None
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: None,
} =>
None
| _ => None
};
};
};
};
module GenericDistribution = {
let make =
(
~generationSource,
~probabilityType=Pdf,
~domain=Complete,
~unit=Unspecified,
(),
)
: genericDistribution => {
generationSource,
probabilityType,
domain,
unit,
};
}; };

View File

@ -0,0 +1,34 @@
open DistributionTypes;
let make =
(
~generationSource,
~probabilityType=Pdf,
~domain=Complete,
~unit=Unspecified,
(),
)
: genericDistribution => {
generationSource,
probabilityType,
domain,
unit,
};
let renderIfNeeded =
(~sampleCount=1000, t: genericDistribution): option(genericDistribution) => {
switch (t.generationSource) {
| GuesstimatorString(s) =>
let shape = Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ());
shape
|> E.O.fmap((shape: DistributionTypes.mixedShape) =>
make(
~generationSource=Shape(Mixed(shape)),
~probabilityType=Cdf,
~domain=t.domain,
~unit=t.unit,
(),
)
);
| Shape(_) => Some(t)
};
};

View File

@ -15,6 +15,7 @@ module Value = {
| FloatPoint(float) | FloatPoint(float)
| Probability(float) | Probability(float)
| Conditional(conditional) | Conditional(conditional)
| GenericDistribution(DistributionTypes.genericDistribution)
| TimeLimitedDomainCdf(TimeLimitedDomainCdf.t) | TimeLimitedDomainCdf(TimeLimitedDomainCdf.t)
| TimeLimitedDomainCdfLazy( | TimeLimitedDomainCdfLazy(
(string => Types.ContinuousDistribution.t) => TimeLimitedDomainCdf.t, (string => Types.ContinuousDistribution.t) => TimeLimitedDomainCdf.t,
@ -31,6 +32,7 @@ module Value = {
} }
| SelectSingle(r) => r | SelectSingle(r) => r
| FloatCdf(r) => r | FloatCdf(r) => r
| GenericDistribution(_) => ""
| TimeLimitedDomainCdf(_) => "" | TimeLimitedDomainCdf(_) => ""
| TimeLimitedDomainCdfLazy(_) => "" | TimeLimitedDomainCdfLazy(_) => ""
| Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%" | Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%"
@ -55,41 +57,29 @@ module Value = {
| SelectSingle(r) => r |> ReasonReact.string | SelectSingle(r) => r |> ReasonReact.string
| ConditionalArray(r) => "Array" |> ReasonReact.string | ConditionalArray(r) => "Array" |> ReasonReact.string
| Conditional(r) => r.name |> ReasonReact.string | Conditional(r) => r.name |> ReasonReact.string
| TimeLimitedDomainCdfLazy(r) => <div /> | GenericDistribution(r) =>
// let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000)); let newDistribution =
// let cdf = timeLimited.limitedDomainCdf.distribution; GenericDistribution.renderIfNeeded(~sampleCount=1000, r);
// <> switch (newDistribution) {
// <Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} /> | Some({generationSource: Shape(Mixed({continuous: n}))}) =>
// <Chart <div>
// height=100 <Chart height=100 data={n |> Shape.Continuous.toJs} />
// data={ <Chart
// cdf height=100
// |> CdfLibrary.Distribution.toPdf data={n |> Shape.Continuous.toCdf |> Shape.Continuous.toJs}
// |> Types.ContinuousDistribution.toJs />
// } </div>
// /> | None => "Something went wrong" |> ReasonReact.string
// {FloatCdf.logNormal(50., 20.) |> ReasonReact.string} | _ => <div />
// </>; };
| TimeLimitedDomainCdfLazy(_) => <div />
| TimeLimitedDomainCdf(r) => | TimeLimitedDomainCdf(r) =>
let cdf: Types.ContinuousDistribution.t = let cdf: Types.ContinuousDistribution.t =
r.limitedDomainCdf.distribution; r.limitedDomainCdf.distribution;
<> <>
<Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} /> <Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
</>; </>;
| FloatCdf(r) => <div /> | FloatCdf(_) => <div />
// let cdf: Types.MixedDistribution.t =
// CdfLibrary.Distribution.fromString(r, 2000);
// <>
// <Chart
// height=100
// data={
// cdf
// |> CdfLibrary.Distribution.toPdf
// |> Types.ContinuousDistribution.toJs
// }
// />
// {r |> ReasonReact.string}
// </>;
| Probability(r) => | Probability(r) =>
(r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string (r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string
| DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string | DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string

108
src/lib/Shape.re Normal file
View File

@ -0,0 +1,108 @@
open DistributionTypes;
module Continuous = {
let fromArrays = (xs, ys): continuousShape => {xs, ys};
let toJs = (t: continuousShape) => {
{"xs": t.xs, "ys": t.ys};
};
let toPdf = CdfLibrary.Distribution.toPdf;
let toCdf = CdfLibrary.Distribution.toCdf;
let findX = CdfLibrary.Distribution.findX;
let findY = CdfLibrary.Distribution.findY;
};
module Discrete = {
type t = discreteShape;
let fromArrays = (xs, ys): discreteShape => {xs, ys};
let _lastElement = (a: array('a)) =>
switch (Belt.Array.size(a)) {
| 0 => None
| n => Belt.Array.get(a, n)
};
let derivative = (p: t) => {
let (xs, ys) =
Belt.Array.zip(p.xs, p.ys)
->Belt.Array.reduce([||], (items, (x, y)) =>
switch (_lastElement(items)) {
| Some((_, yLast)) => [|(x, y -. yLast)|]
| None => [|(x, y)|]
}
)
|> Belt.Array.unzip;
fromArrays(xs, ys);
};
let integral = (p: t) => {
let (xs, ys) =
Belt.Array.zip(p.xs, p.ys)
->Belt.Array.reduce([||], (items, (x, y)) =>
switch (_lastElement(items)) {
| Some((_, yLast)) => [|(x, y +. yLast)|]
| None => [|(x, y)|]
}
)
|> Belt.Array.unzip;
fromArrays(xs, ys);
};
};
module Mixed = {
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
continuous,
discrete,
discreteProbabilityMassFraction,
};
module Builder = {
type assumption =
| ADDS_TO_1
| ADDS_TO_CORRECT_PROBABILITY;
type assumptions = {
continuous: assumption,
discrete: assumption,
discreteProbabilityMass: option(float),
};
let build = (~continuous, ~discrete, ~assumptions) =>
switch (assumptions) {
| {
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: Some(r),
} =>
// TODO: Fix this, it's wrong :(
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: Some(r),
} =>
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: None,
} =>
None
| {
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_1,
discreteProbabilityMass: None,
} =>
None
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: Some(r),
} =>
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| _ => None
};
};
};

View File

@ -113,14 +113,22 @@ module Model = {
switch (output) { switch (output) {
| DONATIONS | DONATIONS
| PAYOUTS => | PAYOUTS =>
Prop.Value.FloatCdf( let difference =
calculateDifference( calculateDifference(
currentValue(group, output), currentValue(group, output),
dateTime, dateTime,
currentDateTime, currentDateTime,
yearlyMeanGrowthRateIfNotClosed(group), yearlyMeanGrowthRateIfNotClosed(group),
), );
) let genericDistribution =
GenericDistribution.make(
~generationSource=GuesstimatorString(difference),
~probabilityType=Cdf,
~domain=Complete,
~unit=Unspecified,
(),
);
Prop.Value.GenericDistribution(genericDistribution);
| CHANCE_OF_EXISTENCE => | CHANCE_OF_EXISTENCE =>
let lazyDistribution = r => let lazyDistribution = r =>
TimeLimitedDomainCdf.make( TimeLimitedDomainCdf.make(

View File

@ -1,13 +1,14 @@
module Model = { module Model = {
let make = (currentDateTime: MomentRe.Moment.t) => { let make = (currentDateTime: MomentRe.Moment.t) => {
let lazyDistribution = r => let genericDistribution =
TimeLimitedDomainCdf.make( GenericDistribution.make(
~timeVector={zero: currentDateTime, unit: `years}, ~generationSource=GuesstimatorString(FloatCdf.logNormal(20., 3.)),
~distribution=r(FloatCdf.logNormal(20., 3.)), ~probabilityType=Cdf,
~probabilityAtMaxX=0.7, ~domain=RightLimited({xPoint: 200., excludingProbabilityMass: 0.3}),
~maxX=`x(200.), ~unit=Time({zero: currentDateTime, unit: `years}),
(),
); );
Prop.Value.TimeLimitedDomainCdfLazy(lazyDistribution); Prop.Value.GenericDistribution(genericDistribution);
}; };
}; };

View File

@ -5,15 +5,15 @@ module JS = {
ys: array(float), ys: array(float),
}; };
let distToJs = (d: Types.ContinuousDistribution.t) => let distToJs = (d: DistributionTypes.continuousShape) =>
distJs(~xs=d.xs, ~ys=d.ys); distJs(~xs=d.xs, ~ys=d.ys);
let jsToDist = (d: distJs): Types.ContinuousDistribution.t => { let jsToDist = (d: distJs): DistributionTypes.continuousShape => {
xs: xsGet(d), xs: xsGet(d),
ys: ysGet(d), ys: ysGet(d),
}; };
let doAsDist = (f, d: Types.ContinuousDistribution.t) => let doAsDist = (f, d: DistributionTypes.continuousShape) =>
d |> distToJs |> f |> jsToDist; d |> distToJs |> f |> jsToDist;
[@bs.module "./CdfLibrary.js"] [@bs.module "./CdfLibrary.js"]
@ -34,40 +34,6 @@ module JS = {
[@bs.module "./CdfLibrary.js"] [@bs.module "./CdfLibrary.js"]
external differentialEntropy: (int, distJs) => distJs = external differentialEntropy: (int, distJs) => distJs =
"differentialEntropy"; "differentialEntropy";
[@bs.module "./CdfLibrary.js"]
external scoreNonMarketCdfCdf: (int, distJs, distJs, float) => distJs =
"scoreNonMarketCdfCdf";
module Guesstimator = {
[@bs.deriving abstract]
type discrete = {
xs: array(float),
ys: array(float),
};
let jsToDistDiscrete = (d: discrete): Types.DiscreteDistribution.t => {
xs: xsGet(d),
ys: ysGet(d),
};
[@bs.deriving abstract]
type combined = {
continuous: distJs,
discrete,
};
let toContinous = (r: combined) => continuousGet(r) |> jsToDist;
let toDiscrete = (r: combined): Types.DiscreteDistribution.t =>
discreteGet(r) |> jsToDistDiscrete;
let toMixed = (r: combined): Types.MixedDistribution.t => {
discrete: toDiscrete(r),
continuous: toContinous(r),
};
[@bs.module "./GuesstimatorLibrary.js"]
external toGuesstimator: (string, int) => combined = "run";
};
}; };
module Distribution = { module Distribution = {
@ -75,9 +41,6 @@ module Distribution = {
let toCdf = dist => dist |> JS.doAsDist(JS.cdfToPdf); let toCdf = dist => dist |> JS.doAsDist(JS.cdfToPdf);
let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y); let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y);
let findY = (x, dist) => dist |> JS.distToJs |> JS.findY(x); let findY = (x, dist) => dist |> JS.distToJs |> JS.findY(x);
let fromString = (str: string, sampleCount: int) =>
JS.Guesstimator.toGuesstimator(str, sampleCount)
|> JS.Guesstimator.toMixed;
let integral = dist => dist |> JS.distToJs |> JS.integral; let integral = dist => dist |> JS.distToJs |> JS.integral;
let differentialEntropy = (maxCalculationLength, dist) => let differentialEntropy = (maxCalculationLength, dist) =>
dist dist

View File

@ -0,0 +1,42 @@
module Internals = {
[@bs.deriving abstract]
type discrete = {
xs: array(float),
ys: array(float),
};
let jsToDistDiscrete = (d: discrete): DistributionTypes.discreteShape => {
xs: xsGet(d),
ys: ysGet(d),
};
[@bs.deriving abstract]
type combined = {
continuous: CdfLibrary.JS.distJs,
discrete,
};
let toContinous = (r: combined): DistributionTypes.continuousShape =>
continuousGet(r) |> CdfLibrary.JS.jsToDist;
let toDiscrete = (r: combined): DistributionTypes.discreteShape =>
discreteGet(r) |> jsToDistDiscrete;
[@bs.module "./GuesstimatorLibrary.js"]
external toCombinedFormat: (string, int) => combined = "run";
let toMixedShape = (r: combined): option(DistributionTypes.mixedShape) => {
let assumptions: Shape.Mixed.Builder.assumptions = {
continuous: ADDS_TO_1,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: Some(0.3),
};
Shape.Mixed.Builder.build(
~continuous=toContinous(r),
~discrete=toDiscrete(r),
~assumptions,
);
};
};
let stringToMixedShape = (~string, ~sampleCount=1000, ()) =>
Internals.toCombinedFormat(string, sampleCount) |> Internals.toMixedShape;