Simple refactoring too add functionality in Shape.re

This commit is contained in:
Ozzie Gooen 2020-02-16 11:45:19 +00:00
parent 5de75a402b
commit 61645243f9
12 changed files with 193 additions and 281 deletions

View File

@ -0,0 +1,33 @@
// type t = {
// distribution: Types.ContinuousDistribution.t,
// domainMaxX: float,
// };
// let make = (~distribution, ~domainMaxX): t => {distribution, domainMaxX};
// let fromCdf =
// (
// cdf: Types.ContinuousDistribution.t,
// domainMaxX: float,
// probabilityAtMaxX: float,
// ) => {
// let distribution: Types.ContinuousDistribution.t = {
// xs: cdf.xs,
// ys: cdf.ys |> E.A.fmap(r => r *. probabilityAtMaxX),
// };
// {distribution, domainMaxX};
// };
// let _lastElement = (a: array('a)) =>
// switch (Belt.Array.size(a)) {
// | 0 => None
// | n => Belt.Array.get(a, n)
// };
// let probabilityBeforeDomainMax = (t: t) => _lastElement(t.distribution.ys);
// let domainMaxX = (t: t) => t.domainMaxX /* CdfLibrary.Distribution.findX(yPoint, t.distribution)*/;
// let probabilityDistribution = (t: t) =>
// t.distribution |> CdfLibrary.Distribution.toPdf;
// 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 cumulativeProbability = (t: t, xPoint: float) =>
// CdfLibrary.Distribution.findY(xPoint, t.distribution);
/* let cumulativeProbabilityInverse = (t: t, yPoint: float) =*/

View File

@ -0,0 +1,38 @@
// open TimeTypes;
// type t = {
// timeVector,
// limitedDomainCdf: LimitedDomainCdf.t,
// };
// let make =
// (
// ~timeVector: timeVector,
// ~distribution: Types.ContinuousDistribution.t,
// ~probabilityAtMaxX: float,
// ~maxX: [ | `time(MomentRe.Moment.t) | `x(float)],
// )
// : t => {
// let domainMaxX =
// switch (maxX) {
// | `time(m) => TimePoint.fromMoment(timeVector, m)
// | `x(r) => r
// };
// let limitedDomainCdf =
// LimitedDomainCdf.fromCdf(distribution, domainMaxX, probabilityAtMaxX);
// {timeVector, limitedDomainCdf};
// };
// let probabilityBeforeDomainMax = (t: t) =>
// LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf);
// let domainMaxX = (t: t) =>
// 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 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 cumulativeProbabilityInverse = (t: t, y: float) =>
/* LimitedDomainCdf.cumulativeProbabilityInverse(t.limitedDomainCdf, y*/

View File

@ -1,43 +0,0 @@
type t = {
distribution: Types.ContinuousDistribution.t,
domainMaxX: float,
};
let make = (~distribution, ~domainMaxX): t => {distribution, domainMaxX};
let fromCdf =
(
cdf: Types.ContinuousDistribution.t,
domainMaxX: float,
probabilityAtMaxX: float,
) => {
let distribution: Types.ContinuousDistribution.t = {
xs: cdf.xs,
ys: cdf.ys |> E.A.fmap(r => r *. probabilityAtMaxX),
};
{distribution, domainMaxX};
};
let _lastElement = (a: array('a)) =>
switch (Belt.Array.size(a)) {
| 0 => None
| n => Belt.Array.get(a, n)
};
let probabilityBeforeDomainMax = (t: t) => _lastElement(t.distribution.ys);
let domainMaxX = (t: t) => t.domainMaxX /* CdfLibrary.Distribution.findX(yPoint, t.distribution)*/;
// let probabilityDistribution = (t: t) =>
// t.distribution |> CdfLibrary.Distribution.toPdf;
// 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 cumulativeProbability = (t: t, xPoint: float) =>
// CdfLibrary.Distribution.findY(xPoint, t.distribution);
// let cumulativeProbabilityInverse = (t: t, yPoint: float) =>

View File

@ -1,46 +0,0 @@
open TimeTypes;
type t = {
timeVector,
limitedDomainCdf: LimitedDomainCdf.t,
};
let make =
(
~timeVector: timeVector,
~distribution: Types.ContinuousDistribution.t,
~probabilityAtMaxX: float,
~maxX: [ | `time(MomentRe.Moment.t) | `x(float)],
)
: t => {
let domainMaxX =
switch (maxX) {
| `time(m) => TimePoint.fromMoment(timeVector, m)
| `x(r) => r
};
let limitedDomainCdf =
LimitedDomainCdf.fromCdf(distribution, domainMaxX, probabilityAtMaxX);
{timeVector, limitedDomainCdf};
};
let probabilityBeforeDomainMax = (t: t) =>
LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf);
let domainMaxX = (t: t) =>
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 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 cumulativeProbabilityInverse = (t: t, y: float) =>
// LimitedDomainCdf.cumulativeProbabilityInverse(t.limitedDomainCdf, y)

View File

@ -9,15 +9,13 @@ type domain =
| RightLimited(domainLimit) | RightLimited(domainLimit)
| LeftAndRightLimited(domainLimit, domainLimit); | LeftAndRightLimited(domainLimit, domainLimit);
type continuousShape = { type xyShape = {
xs: array(float), xs: array(float),
ys: array(float), ys: array(float),
}; };
type continuousShape = xyShape;
type discreteShape = { type discreteShape = xyShape;
xs: array(float),
ys: array(float),
};
type mixedShape = { type mixedShape = {
continuous: continuousShape, continuous: continuousShape,

View File

@ -0,0 +1,63 @@
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(
Shape.Mixed.make(
~continuous,
~discrete,
~discreteProbabilityMassFraction=r,
),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: Some(r),
} =>
Some(
Shape.Mixed.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,
} =>
let discreteProbabilityMassFraction = Shape.Discrete.ySum(discrete);
let discrete = Shape.Discrete.scaleYToTotal(1.0, discrete);
Some(
Shape.Mixed.make(
~continuous,
~discrete,
~discreteProbabilityMassFraction,
),
);
| _ => None
};

View File

@ -16,10 +16,6 @@ module Value = {
| Probability(float) | Probability(float)
| Conditional(conditional) | Conditional(conditional)
| GenericDistribution(DistributionTypes.genericDistribution) | GenericDistribution(DistributionTypes.genericDistribution)
| TimeLimitedDomainCdf(TimeLimitedDomainCdf.t)
| TimeLimitedDomainCdfLazy(
(string => Types.ContinuousDistribution.t) => TimeLimitedDomainCdf.t,
)
| ConditionalArray(array(conditional)) | ConditionalArray(array(conditional))
| FloatCdf(string); | FloatCdf(string);
@ -33,8 +29,6 @@ module Value = {
| SelectSingle(r) => r | SelectSingle(r) => r
| FloatCdf(r) => r | FloatCdf(r) => r
| GenericDistribution(_) => "" | GenericDistribution(_) => ""
| TimeLimitedDomainCdf(_) => ""
| TimeLimitedDomainCdfLazy(_) => ""
| Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%" | Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%"
| DateTime(r) => r |> MomentRe.Moment.defaultFormat | DateTime(r) => r |> MomentRe.Moment.defaultFormat
| FloatPoint(r) => r |> Js.Float.toFixed | FloatPoint(r) => r |> Js.Float.toFixed
@ -78,13 +72,6 @@ module Value = {
| None => "Something went wrong" |> ReasonReact.string | None => "Something went wrong" |> ReasonReact.string
| _ => <div /> | _ => <div />
}; };
| TimeLimitedDomainCdfLazy(_) => <div />
| TimeLimitedDomainCdf(r) =>
let cdf: Types.ContinuousDistribution.t =
r.limitedDomainCdf.distribution;
<>
<Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
</>;
| FloatCdf(_) => <div /> | FloatCdf(_) => <div />
| Probability(r) => | Probability(r) =>
(r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string (r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string

View File

@ -1,10 +1,46 @@
open DistributionTypes; open DistributionTypes;
module Continuous = { let _lastElement = (a: array('a)) =>
let fromArrays = (xs, ys): continuousShape => {xs, ys}; switch (Belt.Array.size(a)) {
let toJs = (t: continuousShape) => { | 0 => None
| n => Belt.Array.get(a, n)
};
module XYShape = {
type t = xyShape;
let toJs = (t: t) => {
{"xs": t.xs, "ys": t.ys}; {"xs": t.xs, "ys": t.ys};
}; };
let fmap = (t: t, y): t => {xs: t.xs, ys: t.ys |> E.A.fmap(y)};
let yFold = (fn, t: t) => {
E.A.fold_left(fn, 0., t.ys);
};
let ySum = yFold((a, b) => a +. b);
let fromArrays = (xs, ys): t => {xs, ys};
let transverse = (fn, p: t) => {
let (xs, ys) =
Belt.Array.zip(p.xs, p.ys)
->Belt.Array.reduce([||], (items, (x, y)) =>
switch (_lastElement(items)) {
| Some((_, yLast)) => [|(x, fn(y, yLast))|]
| None => [|(x, y)|]
}
)
|> Belt.Array.unzip;
fromArrays(xs, ys);
};
let derivative = transverse((aCurrent, aLast) => aCurrent -. aLast);
let integral = transverse((aCurrent, aLast) => aCurrent +. aLast);
};
module Continuous = {
let fromArrays = XYShape.fromArrays;
let toJs = XYShape.toJs;
let toPdf = CdfLibrary.Distribution.toPdf; let toPdf = CdfLibrary.Distribution.toPdf;
let toCdf = CdfLibrary.Distribution.toCdf; let toCdf = CdfLibrary.Distribution.toCdf;
let findX = CdfLibrary.Distribution.findX; let findX = CdfLibrary.Distribution.findX;
@ -13,47 +49,14 @@ module Continuous = {
module Discrete = { module Discrete = {
type t = discreteShape; type t = discreteShape;
let fromArrays = (xs, ys): discreteShape => {xs, ys}; let fromArrays = XYShape.fromArrays;
let _lastElement = (a: array('a)) => let toJs = XYShape.toJs;
switch (Belt.Array.size(a)) { let ySum = XYShape.ySum;
| 0 => None let zip = t => Belt.Array.zip(t.xs, t.ys);
| 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)) => E.A.append(items, [|(x, y +. yLast)|])
| None => [|(x, y)|]
}
)
|> Belt.Array.unzip;
fromArrays(xs, ys);
};
let ySum = (t: t) => {
E.A.fold_left((a, b) => a +. b, 0., t.ys);
};
let scaleYToTotal = (totalDesired, t: t): t => { let scaleYToTotal = (totalDesired, t: t): t => {
let currentSum = ySum(t); let difference = totalDesired /. ySum(t);
let difference = totalDesired /. currentSum; XYShape.fmap(t, y => y *. difference);
{xs: t.xs, ys: t.ys |> E.A.fmap(y => y *. difference)};
}; };
let render = (t: t) => let render = (t: t) =>
@ -67,6 +70,12 @@ module Discrete = {
</div> </div>
) )
|> ReasonReact.array; |> ReasonReact.array;
let findY = (x: float, t: t) =>
switch (E.A.getBy(zip(t), ((ix, _)) => ix == x)) {
| Some((_, y)) => y
| None => 0.
};
}; };
module Mixed = { module Mixed = {
@ -75,56 +84,4 @@ module Mixed = {
discrete, discrete,
discreteProbabilityMassFraction, 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,
} =>
let discreteProbabilityMassFraction = Discrete.ySum(discrete);
let discrete = Discrete.scaleYToTotal(1.0, discrete);
Some(make(~continuous, ~discrete, ~discreteProbabilityMassFraction));
| _ => None
};
};
}; };

View File

@ -1,66 +0,0 @@
module ContinuousDistribution = {
type t = {
xs: array(float),
ys: array(float),
};
let toJs = (t: t) => {
{"xs": t.xs, "ys": t.ys};
};
let toComponentsDist = (d: t): ForetoldComponents.Types.Dist.t => {
xs: d.xs,
ys: d.ys,
};
type pdf = t;
type cdf = t;
};
module DiscreteDistribution = {
type t = {
xs: array(float),
ys: array(float),
};
let fromArray = (xs, ys) => {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;
fromArray(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;
fromArray(xs, ys);
};
};
module MixedDistribution = {
type t = {
discrete: DiscreteDistribution.t,
continuous: ContinuousDistribution.t,
};
};

View File

@ -129,15 +129,7 @@ module Model = {
(), (),
); );
Prop.Value.GenericDistribution(genericDistribution); Prop.Value.GenericDistribution(genericDistribution);
| CHANCE_OF_EXISTENCE => | CHANCE_OF_EXISTENCE => Prop.Value.Probability(0.3)
let lazyDistribution = r =>
TimeLimitedDomainCdf.make(
~timeVector={zero: currentDateTime, unit: `years},
~distribution=r(FloatCdf.logNormal(10., 2.)),
~probabilityAtMaxX=0.7,
~maxX=`x(200.),
);
Prop.Value.TimeLimitedDomainCdfLazy(lazyDistribution);
}; };
}; };
}; };

View File

@ -1,10 +1,9 @@
// ~generationSource=GuesstimatorString(FloatCdf.logNormal(20., 3.)), // ~generationSource=GuesstimatorString(,
module Model = { module Model = {
let make = (currentDateTime: MomentRe.Moment.t) => { let make = (currentDateTime: MomentRe.Moment.t) => {
let genericDistribution = let genericDistribution =
GenericDistribution.make( GenericDistribution.make(
~generationSource= ~generationSource=GuesstimatorString(FloatCdf.logNormal(20., 3.)),
GuesstimatorString("mm(floor(10 to 15), 20 to 30, [.5,.5])"),
~probabilityType=Cdf, ~probabilityType=Cdf,
~domain=RightLimited({xPoint: 200., excludingProbabilityMass: 0.3}), ~domain=RightLimited({xPoint: 200., excludingProbabilityMass: 0.3}),
~unit=Time({zero: currentDateTime, unit: `years}), ~unit=Time({zero: currentDateTime, unit: `years}),

View File

@ -25,12 +25,12 @@ module Internals = {
external toCombinedFormat: (string, int) => combined = "run"; external toCombinedFormat: (string, int) => combined = "run";
let toMixedShape = (r: combined): option(DistributionTypes.mixedShape) => { let toMixedShape = (r: combined): option(DistributionTypes.mixedShape) => {
let assumptions: Shape.Mixed.Builder.assumptions = { let assumptions: MixedShapeBuilder.assumptions = {
continuous: ADDS_TO_1, continuous: ADDS_TO_1,
discrete: ADDS_TO_CORRECT_PROBABILITY, discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: None, discreteProbabilityMass: None,
}; };
Shape.Mixed.Builder.build( MixedShapeBuilder.build(
~continuous=toContinous(r), ~continuous=toContinous(r),
~discrete=toDiscrete(r), ~discrete=toDiscrete(r),
~assumptions, ~assumptions,