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 domainMaxX = (t: t) => t.domainMaxX;
let domainMaxX = (t: t) => t.domainMaxX /* CdfLibrary.Distribution.findX(yPoint, t.distribution)*/;
let probabilityDistribution = (t: t) =>
t.distribution |> CdfLibrary.Distribution.toPdf;
// let probabilityDistribution = (t: t) =>
// t.distribution |> CdfLibrary.Distribution.toPdf;
let probability = (t: t, xPoint: float) =>
CdfLibrary.Distribution.findY(xPoint, probabilityDistribution(t));
// let probability = (t: t, xPoint: float) =>
// CdfLibrary.Distribution.findY(xPoint, probabilityDistribution(t));
let probabilityInverse = (t: t, yPoint: float) =>
CdfLibrary.Distribution.findX(yPoint, probabilityDistribution(t));
// let probabilityInverse = (t: t, yPoint: float) =>
// CdfLibrary.Distribution.findX(yPoint, probabilityDistribution(t));
let cumulativeProbability = (t: t, xPoint: float) =>
CdfLibrary.Distribution.findY(xPoint, t.distribution);
// let cumulativeProbability = (t: t, xPoint: float) =>
// CdfLibrary.Distribution.findY(xPoint, t.distribution);
let cumulativeProbabilityInverse = (t: t, yPoint: float) =>
CdfLibrary.Distribution.findX(yPoint, t.distribution);
// let cumulativeProbabilityInverse = (t: t, yPoint: float) =>

View File

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

View File

@ -48,89 +48,4 @@ type genericDistribution = {
probabilityType,
domain,
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)
| Probability(float)
| Conditional(conditional)
| GenericDistribution(DistributionTypes.genericDistribution)
| TimeLimitedDomainCdf(TimeLimitedDomainCdf.t)
| TimeLimitedDomainCdfLazy(
(string => Types.ContinuousDistribution.t) => TimeLimitedDomainCdf.t,
@ -31,6 +32,7 @@ module Value = {
}
| SelectSingle(r) => r
| FloatCdf(r) => r
| GenericDistribution(_) => ""
| TimeLimitedDomainCdf(_) => ""
| TimeLimitedDomainCdfLazy(_) => ""
| Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%"
@ -55,41 +57,29 @@ module Value = {
| SelectSingle(r) => r |> ReasonReact.string
| ConditionalArray(r) => "Array" |> ReasonReact.string
| Conditional(r) => r.name |> ReasonReact.string
| TimeLimitedDomainCdfLazy(r) => <div />
// let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000));
// let cdf = timeLimited.limitedDomainCdf.distribution;
// <>
// <Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
// <Chart
// height=100
// data={
// cdf
// |> CdfLibrary.Distribution.toPdf
// |> Types.ContinuousDistribution.toJs
// }
// />
// {FloatCdf.logNormal(50., 20.) |> ReasonReact.string}
// </>;
| GenericDistribution(r) =>
let newDistribution =
GenericDistribution.renderIfNeeded(~sampleCount=1000, r);
switch (newDistribution) {
| Some({generationSource: Shape(Mixed({continuous: n}))}) =>
<div>
<Chart height=100 data={n |> Shape.Continuous.toJs} />
<Chart
height=100
data={n |> Shape.Continuous.toCdf |> Shape.Continuous.toJs}
/>
</div>
| None => "Something went wrong" |> ReasonReact.string
| _ => <div />
};
| TimeLimitedDomainCdfLazy(_) => <div />
| TimeLimitedDomainCdf(r) =>
let cdf: Types.ContinuousDistribution.t =
r.limitedDomainCdf.distribution;
<>
<Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
</>;
| FloatCdf(r) => <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}
// </>;
| FloatCdf(_) => <div />
| Probability(r) =>
(r *. 100. |> Js.Float.toFixed) ++ "%" |> 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) {
| DONATIONS
| PAYOUTS =>
Prop.Value.FloatCdf(
let difference =
calculateDifference(
currentValue(group, output),
dateTime,
currentDateTime,
yearlyMeanGrowthRateIfNotClosed(group),
),
)
);
let genericDistribution =
GenericDistribution.make(
~generationSource=GuesstimatorString(difference),
~probabilityType=Cdf,
~domain=Complete,
~unit=Unspecified,
(),
);
Prop.Value.GenericDistribution(genericDistribution);
| CHANCE_OF_EXISTENCE =>
let lazyDistribution = r =>
TimeLimitedDomainCdf.make(

View File

@ -1,13 +1,14 @@
module Model = {
let make = (currentDateTime: MomentRe.Moment.t) => {
let lazyDistribution = r =>
TimeLimitedDomainCdf.make(
~timeVector={zero: currentDateTime, unit: `years},
~distribution=r(FloatCdf.logNormal(20., 3.)),
~probabilityAtMaxX=0.7,
~maxX=`x(200.),
let genericDistribution =
GenericDistribution.make(
~generationSource=GuesstimatorString(FloatCdf.logNormal(20., 3.)),
~probabilityType=Cdf,
~domain=RightLimited({xPoint: 200., excludingProbabilityMass: 0.3}),
~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),
};
let distToJs = (d: Types.ContinuousDistribution.t) =>
let distToJs = (d: DistributionTypes.continuousShape) =>
distJs(~xs=d.xs, ~ys=d.ys);
let jsToDist = (d: distJs): Types.ContinuousDistribution.t => {
let jsToDist = (d: distJs): DistributionTypes.continuousShape => {
xs: xsGet(d),
ys: ysGet(d),
};
let doAsDist = (f, d: Types.ContinuousDistribution.t) =>
let doAsDist = (f, d: DistributionTypes.continuousShape) =>
d |> distToJs |> f |> jsToDist;
[@bs.module "./CdfLibrary.js"]
@ -34,40 +34,6 @@ module JS = {
[@bs.module "./CdfLibrary.js"]
external differentialEntropy: (int, distJs) => distJs =
"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 = {
@ -75,9 +41,6 @@ module Distribution = {
let toCdf = dist => dist |> JS.doAsDist(JS.cdfToPdf);
let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y);
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 differentialEntropy = (maxCalculationLength, 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;