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)
| LeftAndRightLimited(domainLimit, domainLimit);
type continuousShape = {
type xyShape = {
xs: array(float),
ys: array(float),
};
type continuousShape = xyShape;
type discreteShape = {
xs: array(float),
ys: array(float),
};
type discreteShape = xyShape;
type mixedShape = {
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)
| Conditional(conditional)
| GenericDistribution(DistributionTypes.genericDistribution)
| TimeLimitedDomainCdf(TimeLimitedDomainCdf.t)
| TimeLimitedDomainCdfLazy(
(string => Types.ContinuousDistribution.t) => TimeLimitedDomainCdf.t,
)
| ConditionalArray(array(conditional))
| FloatCdf(string);
@ -33,8 +29,6 @@ module Value = {
| SelectSingle(r) => r
| FloatCdf(r) => r
| GenericDistribution(_) => ""
| TimeLimitedDomainCdf(_) => ""
| TimeLimitedDomainCdfLazy(_) => ""
| Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%"
| DateTime(r) => r |> MomentRe.Moment.defaultFormat
| FloatPoint(r) => r |> Js.Float.toFixed
@ -78,13 +72,6 @@ module Value = {
| 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(_) => <div />
| Probability(r) =>
(r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string

View File

@ -1,10 +1,46 @@
open DistributionTypes;
module Continuous = {
let fromArrays = (xs, ys): continuousShape => {xs, ys};
let toJs = (t: continuousShape) => {
let _lastElement = (a: array('a)) =>
switch (Belt.Array.size(a)) {
| 0 => None
| n => Belt.Array.get(a, n)
};
module XYShape = {
type t = xyShape;
let toJs = (t: t) => {
{"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 toCdf = CdfLibrary.Distribution.toCdf;
let findX = CdfLibrary.Distribution.findX;
@ -13,47 +49,14 @@ module Continuous = {
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)) => 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 fromArrays = XYShape.fromArrays;
let toJs = XYShape.toJs;
let ySum = XYShape.ySum;
let zip = t => Belt.Array.zip(t.xs, t.ys);
let scaleYToTotal = (totalDesired, t: t): t => {
let currentSum = ySum(t);
let difference = totalDesired /. currentSum;
{xs: t.xs, ys: t.ys |> E.A.fmap(y => y *. difference)};
let difference = totalDesired /. ySum(t);
XYShape.fmap(t, y => y *. difference);
};
let render = (t: t) =>
@ -67,6 +70,12 @@ module Discrete = {
</div>
)
|> ReasonReact.array;
let findY = (x: float, t: t) =>
switch (E.A.getBy(zip(t), ((ix, _)) => ix == x)) {
| Some((_, y)) => y
| None => 0.
};
};
module Mixed = {
@ -75,56 +84,4 @@ module Mixed = {
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,
} =>
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);
| CHANCE_OF_EXISTENCE =>
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);
| CHANCE_OF_EXISTENCE => Prop.Value.Probability(0.3)
};
};
};

View File

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

View File

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