The slow replacement of Shape.re begins

This commit is contained in:
Ozzie Gooen 2020-02-22 19:21:04 +00:00
parent 0d2c53eca4
commit cd1b114295
5 changed files with 175 additions and 204 deletions

View File

@ -45,7 +45,7 @@ let make =
?minX ?minX
?scale ?scale
?timeScale ?timeScale
discrete={discrete |> E.O.fmap(Shape.Discrete.toJs)} discrete={discrete |> E.O.fmap(XYShape.toJs)}
height height
marginBottom=50 marginBottom=50
marginTop=0 marginTop=0

View File

@ -49,6 +49,12 @@ module Dist = (T: dist) => {
let xToY = T.integralXtoY; let xToY = T.integralXtoY;
let sum = T.integralSum; let sum = T.integralSum;
}; };
// This is suboptimal because it could get the cache but doesn't here.
let scaleToIntegralSum = (~intendedSum=1.0, t: t) => {
let scale = intendedSum /. Integral.sum(~cache=None, t);
scaleBy(~scale, t);
};
}; };
module Continuous = { module Continuous = {
@ -123,6 +129,31 @@ module Discrete = {
}; };
module Mixed = { module Mixed = {
let make =
(~continuous, ~discrete, ~discreteProbabilityMassFraction)
: DistributionTypes.mixedShape => {
continuous,
discrete,
discreteProbabilityMassFraction,
};
let clean =
(t: DistributionTypes.mixedShape): option(DistributionTypes.shape) => {
switch (t) {
| {
continuous: {xyShape: {xs: [||], ys: [||]}},
discrete: {xs: [||], ys: [||]},
} =>
None
| {discrete: {xs: [|_|], ys: [|_|]}} => None
| {continuous, discrete: {xs: [||], ys: [||]}} =>
Some(Continuous(continuous))
| {continuous: {xyShape: {xs: [||], ys: [||]}}, discrete} =>
Some(Discrete(discrete))
| shape => Some(Mixed(shape))
};
};
module T = module T =
Dist({ Dist({
type t = DistributionTypes.mixedShape; type t = DistributionTypes.mixedShape;
@ -312,24 +343,24 @@ module WithMetadata = {
type t = DistributionTypes.complexPower; type t = DistributionTypes.complexPower;
type integral = DistributionTypes.complexPower; type integral = DistributionTypes.complexPower;
let toShape = ({shape, _}: t) => shape; let toShape = ({shape, _}: t) => shape;
let toContinuous = (t: t) => t |> toShape |> Shape.T.toContinuous; let shapeFn = (fn, t: t) => t |> toShape |> fn;
let toDiscrete = (t: t) => t |> toShape |> Shape.T.toDiscrete; let toContinuous = shapeFn(Shape.T.toContinuous);
let toDiscrete = shapeFn(Shape.T.toDiscrete);
// todo: adjust for limit, and the fact that total mass is lower. // todo: adjust for limit, and the fact that total mass is lower.
let xToY = (f, t: t) => t |> toShape |> Shape.T.xToY(f); let xToY = f => shapeFn(Shape.T.xToY(f));
let minX = (t: t) => t |> toShape |> Shape.T.minX; let minX = shapeFn(Shape.T.minX);
let maxX = (t: t) => t |> toShape |> Shape.T.maxX; let maxX = shapeFn(Shape.T.maxX);
let fromShape = (shape, t): t => DistributionTypes.update(~shape, t); let fromShape = (shape, t): t => DistributionTypes.update(~shape, t);
// todo: adjust for limit // todo: adjust for limit
let pointwiseFmap = (fn, {shape, _} as t: t): t => let pointwiseFmap = (fn, {shape, _} as t: t): t =>
fromShape(Shape.T.pointwiseFmap(fn, shape), t); fromShape(Shape.T.pointwiseFmap(fn, shape), t);
let integral = (~cache as _, t: t) => let integral = (~cache as _, t: t) =>
fromShape(Continuous(t.integralCache), t); fromShape(Continuous(t.integralCache), t);
let integralSum = (~cache as _, t: t) => let integralSum = (~cache as _, t: t) =>
t |> toShape |> Shape.T.Integral.sum(~cache=Some(t.integralCache)); Shape.T.Integral.sum(~cache=Some(t.integralCache), toShape(t));
// TODO: Fix this below, obviously. Adjust for limit. // TODO: Fix this below, obviously. Adjust for limit.
let integralXtoY = (~cache as _, f, t) => { let integralXtoY = (~cache as _, f, t: t) => {
1337.0; Shape.T.Integral.xToY(~cache=Some(t.integralCache), f, toShape(t));
}; };
}); });
}; };

View File

@ -49,7 +49,7 @@ let renderIfNeeded =
switch (t.generationSource) { switch (t.generationSource) {
| GuesstimatorString(s) => | GuesstimatorString(s) =>
Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ()) Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ())
|> E.O.bind(_, Shape.Mixed.clean) |> E.O.bind(_, DistFunctor.Mixed.clean)
|> E.O.fmap((shape: DistributionTypes.shape) => |> E.O.fmap((shape: DistributionTypes.shape) =>
make( make(
~generationSource=Shape(shape), ~generationSource=Shape(shape),
@ -71,13 +71,9 @@ let normalize = (t: genericDistribution): option(genericDistribution) => {
}; };
let yIntegral = (t: DistributionTypes.genericDistribution, x) => { let yIntegral = (t: DistributionTypes.genericDistribution, x) => {
let addInitialMass = n => n +. Domain.initialProbabilityMass(t.domain);
let normalize = n => n *. Domain.normalizeProbabilityMass(t.domain);
switch (t) { switch (t) {
| {generationSource: Shape(shape)} => | {generationSource: Shape(shape)} =>
Shape.T.yIntegral(shape, x) Some(DistFunctor.Shape.T.Integral.xToY(~cache=None, x, shape))
|> E.O.fmap(addInitialMass)
|> E.O.fmap(normalize)
| _ => None | _ => None
}; };
}; };

View File

@ -17,7 +17,7 @@ let build = (~continuous, ~discrete, ~assumptions) =>
} => } =>
// TODO: Fix this, it's wrong :( // TODO: Fix this, it's wrong :(
Some( Some(
Shape.Mixed.make( DistFunctor.Mixed.make(
~continuous, ~continuous,
~discrete, ~discrete,
~discreteProbabilityMassFraction=r, ~discreteProbabilityMassFraction=r,
@ -30,7 +30,7 @@ let build = (~continuous, ~discrete, ~assumptions) =>
discreteProbabilityMass: Some(r), discreteProbabilityMass: Some(r),
} => } =>
Some( Some(
Shape.Mixed.make( DistFunctor.Mixed.make(
~continuous, ~continuous,
~discrete, ~discrete,
~discreteProbabilityMassFraction=r, ~discreteProbabilityMassFraction=r,
@ -56,10 +56,12 @@ let build = (~continuous, ~discrete, ~assumptions) =>
discrete: ADDS_TO_CORRECT_PROBABILITY, discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: None, discreteProbabilityMass: None,
} => } =>
let discreteProbabilityMassFraction = Shape.Discrete.ySum(discrete); let discreteProbabilityMassFraction =
let discrete = Shape.Discrete.scaleYToTotal(1.0, discrete); DistFunctor.Discrete.T.Integral.sum(~cache=None, discrete);
let discrete =
DistFunctor.Discrete.T.scaleToIntegralSum(~intendedSum=1.0, discrete);
Some( Some(
Shape.Mixed.make( DistFunctor.Mixed.make(
~continuous, ~continuous,
~discrete, ~discrete,
~discreteProbabilityMassFraction, ~discreteProbabilityMassFraction,

View File

@ -115,11 +115,11 @@ let max = (f1: option(float), f2: option(float)) =>
}; };
module Mixed = { module Mixed = {
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => { // let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
continuous, // continuous,
discrete, // discrete,
discreteProbabilityMassFraction, // discreteProbabilityMassFraction,
}; // };
let minX = (t: DistributionTypes.mixedShape) => let minX = (t: DistributionTypes.mixedShape) =>
min(t.continuous |> Continuous.minX, t.discrete |> Discrete.minX); min(t.continuous |> Continuous.minX, t.discrete |> Discrete.minX);
@ -163,193 +163,135 @@ module Mixed = {
| _ => None | _ => None
}; };
}; };
} /* }*/;
let clean = (t: DistributionTypes.mixedShape) => // module T = {
switch (t) { // type t = DistributionTypes.shape;
| {
continuous: {xyShape: {xs: [||], ys: [||]}},
discrete: {xs: [||], ys: [||]},
} =>
None
| {discrete: {xs: [|_|], ys: [|_|]}} => None
| {continuous, discrete: {xs: [||], ys: [||]}} =>
Some(Continuous(continuous))
| {continuous: {xyShape: {xs: [||], ys: [||]}}, discrete} =>
Some(Discrete(discrete))
| shape => Some(Mixed(shape))
};
};
module T = { // let y = (t: t, x: float) =>
type t = DistributionTypes.shape; // switch (t) {
// | Mixed(m) => `mixed(Mixed.findY(m, x))
// | Discrete(discreteShape) => `discrete(Discrete.findY(x, discreteShape))
// | Continuous(continuousShape) =>
// `continuous(Continuous.findY(x, continuousShape))
// };
let y = (t: t, x: float) => // let yIntegral = (t: t, x: float) =>
switch (t) { // switch (t) {
| Mixed(m) => `mixed(Mixed.findY(m, x)) // | Mixed(m) => Mixed.findYIntegral(x, m)
| Discrete(discreteShape) => `discrete(Discrete.findY(x, discreteShape)) // | Discrete(discreteShape) =>
| Continuous(continuousShape) => // Discrete.findIntegralY(x, discreteShape) |> E.O.some
`continuous(Continuous.findY(x, continuousShape)) // | Continuous(continuousShape) =>
}; // Continuous.findIntegralY(x, continuousShape)
// };
let yIntegral = (t: t, x: float) => // let minX = (t: t) =>
switch (t) { // switch (t) {
| Mixed(m) => Mixed.findYIntegral(x, m) // | Mixed(m) => Mixed.minX(m)
| Discrete(discreteShape) => // | Discrete(discreteShape) => Discrete.minX(discreteShape)
Discrete.findIntegralY(x, discreteShape) |> E.O.some // | Continuous(continuousShape) => Continuous.minX(continuousShape)
| Continuous(continuousShape) => // };
Continuous.findIntegralY(x, continuousShape)
};
let minX = (t: t) => // let maxX = (t: t) =>
switch (t) { // switch (t) {
| Mixed(m) => Mixed.minX(m) // | Mixed(m) => Mixed.maxX(m)
| Discrete(discreteShape) => Discrete.minX(discreteShape) // | Discrete(discreteShape) => Discrete.maxX(discreteShape)
| Continuous(continuousShape) => Continuous.minX(continuousShape) // | Continuous(continuousShape) => Continuous.maxX(continuousShape)
}; // };
let maxX = (t: t) => // let discreteComponent = (t: t) =>
switch (t) { // switch (t) {
| Mixed(m) => Mixed.maxX(m) // | Mixed({discrete}) => Some(discrete)
| Discrete(discreteShape) => Discrete.maxX(discreteShape) // | Discrete(d) => Some(d)
| Continuous(continuousShape) => Continuous.maxX(continuousShape) // | Continuous(_) => None
}; // };
let discreteComponent = (t: t) => // let continuousComponent = (t: t) =>
switch (t) { // switch (t) {
| Mixed({discrete}) => Some(discrete) // | Mixed({continuous}) => Some(continuous)
| Discrete(d) => Some(d) // | Continuous(c) => Some(c)
| Continuous(_) => None // | Discrete(_) => None
}; // };
// // let scaledContinuousComponent = (t: t): option(continuousShape) => {
// // switch (t) {
// // | Mixed({continuous, discreteProbabilityMassFraction}) =>
// // Continuous.scalePdf(
// // ~scaleTo=1.0 -. discreteProbabilityMassFraction,
// // continuous,
// // )
// // | Discrete(_) => None
// // | Continuous(c) => Some(c)
// // };
// // };
// // let scaledDiscreteComponent = (t: t): option(discreteShape) => {
// // switch (t) {
// // | Mixed({discrete, discreteProbabilityMassFraction}) =>
// // Some(Discrete.scaleYToTotal(discreteProbabilityMassFraction, discrete))
// // | Discrete(d) => Some(d)
// // | Continuous(_) => None
// // };
// // };
// // let pointwiseFmap = (fn, t: t): shape =>
// // switch (t) {
// // | Mixed({discrete, continuous, discreteProbabilityMassFraction}) =>
// // Mixed({
// // continuous: XYShape.pointwiseMap(fn, continuous),
// // discrete: XYShape.pointwiseMap(fn, discrete),
// // discreteProbabilityMassFraction,
// // })
// // | Discrete(x) => Discrete(XYShape.pointwiseMap(fn, x))
// // | Continuous(x) => Continuous(XYShape.pointwiseMap(fn, x))
// // };
// // module Cdf = {
// // let normalizeCdf = (t: DistributionTypes.shape) => {
// // switch (t) {
// // | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
// // Mixed({
// // continuous: continuous |> Continuous.normalizeCdf,
// // discrete: discrete |> Discrete.scaleYToTotal(1.0),
// // discreteProbabilityMassFraction,
// // })
// // | Discrete(d) => Discrete(d |> Discrete.scaleYToTotal(1.0))
// // | Continuous(continuousShape) =>
// // Continuous(Continuous.normalizeCdf(continuousShape))
// // };
// // };
// // };
// };
let continuousComponent = (t: t) => // module PdfCdfShape = {
switch (t) { // type t = pdfCdfCombo;
| Mixed({continuous}) => Some(continuous) // let pdf = (t: t) =>
| Continuous(c) => Some(c) // switch (t.pdf) {
| Discrete(_) => None // | Mixed(pdf) => Mixed(pdf)
}; // | Discrete(pdf) => Discrete(pdf)
// | Continuous(pdf) => Continuous(pdf)
// };
// let cdf = (t: t) => t.cdf;
// };
// let scaledContinuousComponent = (t: t): option(continuousShape) => { // type distributionUnit =
// switch (t) { // | UnspecifiedDistribution
// | Mixed({continuous, discreteProbabilityMassFraction}) => // | TimeDistribution(TimeTypes.timeVector);
// Continuous.scalePdf(
// ~scaleTo=1.0 -. discreteProbabilityMassFraction,
// continuous,
// )
// | Discrete(_) => None
// | Continuous(c) => Some(c)
// };
// };
// let scaledDiscreteComponent = (t: t): option(discreteShape) => { // type withLimitedDomain = {
// switch (t) { // domain,
// | Mixed({discrete, discreteProbabilityMassFraction}) => // dist: pdfCdfCombo,
// Some(Discrete.scaleYToTotal(discreteProbabilityMassFraction, discrete)) // };
// | Discrete(d) => Some(d)
// | Continuous(_) => None
// };
// };
// let pointwiseFmap = (fn, t: t): shape => // module WithLimitedDomain = {
// switch (t) { // type t = withLimitedDomain;
// | Mixed({discrete, continuous, discreteProbabilityMassFraction}) => // let dist = (t: t) => t.dist;
// Mixed({ // let pdf = (t: t) => PdfCdfShape.pdf(t.dist);
// continuous: XYShape.pointwiseMap(fn, continuous), // let cdf = (t: t) => PdfCdfShape.cdf(t.dist);
// discrete: XYShape.pointwiseMap(fn, discrete), // // TODO: This is bad, obviously needs to be fixed.
// discreteProbabilityMassFraction, // let distScaleFactor = (t: t) => 3.0;
// }) // // let scaledPdfShape = (scaleFactor, t: t) =>
// | Discrete(x) => Discrete(XYShape.pointwiseMap(fn, x)) // // t |> pdf |> T.pointwiseFmap(r => r *. scaleFactor);
// | Continuous(x) => Continuous(XYShape.pointwiseMap(fn, x)) // // let scaledCdfShape = (scaleFactor, t: t) =>
// }; // // t |> cdf |> XYShape.pointwiseMap(r => r *. scaleFactor);
// };
// module Cdf = { // type withTimeVector = {
// let normalizeCdf = (t: DistributionTypes.shape) => { // timeVector: TimeTypes.timeVector,
// switch (t) { // dist: withLimitedDomain,
// | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
// Mixed({
// continuous: continuous |> Continuous.normalizeCdf,
// discrete: discrete |> Discrete.scaleYToTotal(1.0),
// discreteProbabilityMassFraction,
// })
// | Discrete(d) => Discrete(d |> Discrete.scaleYToTotal(1.0))
// | Continuous(continuousShape) =>
// Continuous(Continuous.normalizeCdf(continuousShape))
// };
// };
// };
module Pdf = {
// TODO: This is wrong. The discrete component should be made continuous when integrating.
// let toCdf = (t: t) =>
// switch (t) {
// | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
// Some(
// Mixed({
// continuous: Continuous.toCdf(continuous) |> E.O.toExt(""),
// discrete: discrete |> Discrete.integrate,
// discreteProbabilityMassFraction,
// }),
// )
// | Discrete(discrete) =>
// Some(Continuous(discrete |> Discrete.integrate))
// | Continuous(continuous) =>
// Continuous.toCdf(continuous) |> E.O.fmap(e => Continuous(e))
// };
// let normalize = (t: DistributionTypes.shape): option(shape) => {
// switch (t) {
// | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
// continuous
// |> Continuous.scalePdf(~scaleTo=1.0)
// |> E.O.fmap(r =>
// Mixed({
// continuous: r,
// discrete: discrete |> Discrete.scaleYToTotal(1.0),
// discreteProbabilityMassFraction,
// })
// )
// | Discrete(d) => Some(Discrete(d |> Discrete.scaleYToTotal(1.0)))
// | Continuous(continuousShape) =>
// continuousShape
// |> Continuous.scalePdf(~scaleTo=1.0)
// |> E.O.fmap(r => Continuous(r))
// };
// };
};
};
module PdfCdfShape = {
type t = pdfCdfCombo;
let pdf = (t: t) =>
switch (t.pdf) {
| Mixed(pdf) => Mixed(pdf)
| Discrete(pdf) => Discrete(pdf)
| Continuous(pdf) => Continuous(pdf)
};
let cdf = (t: t) => t.cdf;
};
type distributionUnit =
| UnspecifiedDistribution
| TimeDistribution(TimeTypes.timeVector);
type withLimitedDomain = {
domain,
dist: pdfCdfCombo,
};
module WithLimitedDomain = {
type t = withLimitedDomain;
let dist = (t: t) => t.dist;
let pdf = (t: t) => PdfCdfShape.pdf(t.dist);
let cdf = (t: t) => PdfCdfShape.cdf(t.dist);
// TODO: This is bad, obviously needs to be fixed.
let distScaleFactor = (t: t) => 3.0;
// let scaledPdfShape = (scaleFactor, t: t) =>
// t |> pdf |> T.pointwiseFmap(r => r *. scaleFactor);
// let scaledCdfShape = (scaleFactor, t: t) =>
// t |> cdf |> XYShape.pointwiseMap(r => r *. scaleFactor);
};
type withTimeVector = {
timeVector: TimeTypes.timeVector,
dist: withLimitedDomain,
};