2020-02-21 23:42:15 +00:00
|
|
|
module type dist = {
|
|
|
|
type t;
|
2020-03-18 20:50:01 +00:00
|
|
|
type integral;
|
2020-03-28 21:29:02 +00:00
|
|
|
let minX: t => float;
|
|
|
|
let maxX: t => float;
|
2020-03-28 14:17:47 +00:00
|
|
|
let mapY: (float => float, t) => t;
|
2020-02-23 13:27:52 +00:00
|
|
|
let xToY: (float, t) => DistTypes.mixedPoint;
|
|
|
|
let toShape: t => DistTypes.shape;
|
|
|
|
let toContinuous: t => option(DistTypes.continuousShape);
|
|
|
|
let toDiscrete: t => option(DistTypes.discreteShape);
|
|
|
|
let toScaledContinuous: t => option(DistTypes.continuousShape);
|
|
|
|
let toScaledDiscrete: t => option(DistTypes.discreteShape);
|
2020-02-26 10:08:37 +00:00
|
|
|
let toDiscreteProbabilityMass: t => float;
|
2020-03-18 20:50:01 +00:00
|
|
|
let truncate: (~cache: option(integral)=?, int, t) => t;
|
2020-02-22 10:17:51 +00:00
|
|
|
|
2020-02-22 10:10:10 +00:00
|
|
|
let integral: (~cache: option(integral), t) => integral;
|
2020-02-24 21:01:29 +00:00
|
|
|
let integralEndY: (~cache: option(integral), t) => float;
|
2020-02-22 10:17:51 +00:00
|
|
|
let integralXtoY: (~cache: option(integral), float, t) => float;
|
2020-03-14 18:33:39 +00:00
|
|
|
let integralYtoX: (~cache: option(integral), float, t) => float;
|
2020-02-21 23:42:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
module Dist = (T: dist) => {
|
|
|
|
type t = T.t;
|
|
|
|
type integral = T.integral;
|
|
|
|
let minX = T.minX;
|
|
|
|
let maxX = T.maxX;
|
2020-03-28 21:29:02 +00:00
|
|
|
let xTotalRange = (t: t) => maxX(t) -. minX(t);
|
2020-03-28 14:17:47 +00:00
|
|
|
let mapY = T.mapY;
|
2020-02-21 23:42:15 +00:00
|
|
|
let xToY = T.xToY;
|
2020-03-15 00:30:18 +00:00
|
|
|
let truncate = T.truncate;
|
2020-02-22 16:24:54 +00:00
|
|
|
let toShape = T.toShape;
|
2020-02-26 10:08:37 +00:00
|
|
|
let toDiscreteProbabilityMass = T.toDiscreteProbabilityMass;
|
2020-02-22 16:24:54 +00:00
|
|
|
let toContinuous = T.toContinuous;
|
|
|
|
let toDiscrete = T.toDiscrete;
|
2020-02-22 21:46:49 +00:00
|
|
|
let toScaledContinuous = T.toScaledContinuous;
|
|
|
|
let toScaledDiscrete = T.toScaledDiscrete;
|
2020-03-18 21:46:43 +00:00
|
|
|
|
|
|
|
// TODO: Move this to each class, have use integral to produce integral in DistPlus class.
|
2020-03-28 14:17:47 +00:00
|
|
|
let scaleBy = (~scale=1.0, t: t) => t |> mapY((r: float) => r *. scale);
|
2020-02-22 10:17:51 +00:00
|
|
|
|
|
|
|
module Integral = {
|
|
|
|
type t = T.integral;
|
|
|
|
let get = T.integral;
|
|
|
|
let xToY = T.integralXtoY;
|
2020-03-14 18:33:39 +00:00
|
|
|
let yToX = T.integralYtoX;
|
2020-02-24 21:01:29 +00:00
|
|
|
let sum = T.integralEndY;
|
2020-02-22 10:17:51 +00:00
|
|
|
};
|
2020-02-22 19:21:04 +00:00
|
|
|
|
2020-02-23 20:50:27 +00:00
|
|
|
// This is suboptimal because it could get the cache but doesn't here.
|
2020-03-18 21:46:43 +00:00
|
|
|
let scaleToIntegralSum =
|
|
|
|
(~cache: option(integral)=None, ~intendedSum=1.0, t: t) => {
|
|
|
|
let scale = intendedSum /. Integral.sum(~cache, t);
|
2020-02-22 19:21:04 +00:00
|
|
|
scaleBy(~scale, t);
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
};
|
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module Continuous = {
|
2020-02-23 13:27:52 +00:00
|
|
|
type t = DistTypes.continuousShape;
|
2020-02-22 16:24:54 +00:00
|
|
|
let getShape = (t: t) => t.xyShape;
|
|
|
|
let interpolation = (t: t) => t.interpolation;
|
2020-03-28 21:46:17 +00:00
|
|
|
let make = (interpolation, xyShape): t => {xyShape, interpolation};
|
2020-02-22 16:24:54 +00:00
|
|
|
let shapeMap = (fn, {xyShape, interpolation}: t): t => {
|
|
|
|
xyShape: fn(xyShape),
|
|
|
|
interpolation,
|
|
|
|
};
|
2020-03-28 21:29:02 +00:00
|
|
|
let lastY = (t: t) => t |> getShape |> XYShape.T.lastY;
|
2020-02-22 16:24:54 +00:00
|
|
|
let oShapeMap =
|
2020-02-23 13:27:52 +00:00
|
|
|
(fn, {xyShape, interpolation}: t): option(DistTypes.continuousShape) =>
|
2020-03-28 21:46:17 +00:00
|
|
|
fn(xyShape) |> E.O.fmap(make(interpolation));
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-24 21:01:29 +00:00
|
|
|
let toLinear = (t: t): option(t) => {
|
2020-02-22 23:55:43 +00:00
|
|
|
switch (t) {
|
2020-02-24 21:01:29 +00:00
|
|
|
| {interpolation: `Stepwise, xyShape} =>
|
2020-03-28 21:46:17 +00:00
|
|
|
xyShape |> XYShape.Range.stepsToContinuous |> E.O.fmap(make(`Linear))
|
2020-02-24 21:01:29 +00:00
|
|
|
| {interpolation: `Linear, _} => Some(t)
|
2020-02-22 23:55:43 +00:00
|
|
|
};
|
2020-02-24 21:01:29 +00:00
|
|
|
};
|
2020-03-28 21:29:02 +00:00
|
|
|
let shapeFn = (fn, t: t) => t |> getShape |> fn;
|
2020-02-24 21:01:29 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module T =
|
|
|
|
Dist({
|
2020-02-23 13:27:52 +00:00
|
|
|
type t = DistTypes.continuousShape;
|
|
|
|
type integral = DistTypes.continuousShape;
|
2020-03-28 21:46:17 +00:00
|
|
|
let minX = shapeFn(XYShape.T.minX);
|
|
|
|
let maxX = shapeFn(XYShape.T.maxX);
|
2020-03-14 18:33:39 +00:00
|
|
|
let toDiscreteProbabilityMass = _ => 0.0;
|
2020-03-28 21:46:17 +00:00
|
|
|
let mapY = fn => shapeMap(XYShape.T.mapY(fn));
|
2020-02-23 13:27:52 +00:00
|
|
|
let toShape = (t: t): DistTypes.shape => Continuous(t);
|
2020-03-28 21:46:17 +00:00
|
|
|
let xToY = (f, {interpolation, xyShape}: t) => {
|
|
|
|
(
|
|
|
|
switch (interpolation) {
|
|
|
|
| `Stepwise =>
|
|
|
|
xyShape
|
|
|
|
|> XYShape.XtoY.stepwiseIncremental(f)
|
|
|
|
|> E.O.default(0.0)
|
|
|
|
| `Linear => xyShape |> XYShape.XtoY.linear(f)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|> DistTypes.MixedPoint.makeContinuous;
|
|
|
|
};
|
2020-02-24 16:39:55 +00:00
|
|
|
|
|
|
|
// let combineWithFn = (t1: t, t2: t, fn: (float, float) => float) => {
|
|
|
|
// switch(t1, t2){
|
|
|
|
// | ({interpolation: `Stepwise}, {interpolation: `Stepwise}) => 3.0
|
|
|
|
// | ({interpolation: `Linear}, {interpolation: `Linear}) => 3.0
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
|
2020-03-28 21:46:17 +00:00
|
|
|
// TODO: This should work with stepwise plots.
|
2020-02-24 11:11:03 +00:00
|
|
|
let integral = (~cache, t) =>
|
2020-02-25 12:28:26 +00:00
|
|
|
switch (cache) {
|
|
|
|
| Some(cache) => cache
|
|
|
|
| None =>
|
|
|
|
t
|
2020-03-28 21:29:02 +00:00
|
|
|
|> getShape
|
2020-02-25 12:28:26 +00:00
|
|
|
|> XYShape.Range.integrateWithTriangles
|
|
|
|
|> E.O.toExt("This should not have happened")
|
2020-03-28 21:46:17 +00:00
|
|
|
|> make(`Linear)
|
2020-02-25 12:28:26 +00:00
|
|
|
};
|
2020-03-28 21:46:17 +00:00
|
|
|
let truncate = (~cache=None, length, t) =>
|
2020-03-18 20:50:01 +00:00
|
|
|
t
|
|
|
|
|> shapeMap(
|
2020-03-28 14:17:47 +00:00
|
|
|
XYShape.XsConversion.proportionByProbabilityMass(
|
2020-03-28 21:46:17 +00:00
|
|
|
length,
|
2020-03-18 20:50:01 +00:00
|
|
|
integral(~cache, t).xyShape,
|
|
|
|
),
|
|
|
|
);
|
2020-02-24 21:01:29 +00:00
|
|
|
let integralEndY = (~cache, t) => t |> integral(~cache) |> lastY;
|
2020-02-22 16:24:54 +00:00
|
|
|
let integralXtoY = (~cache, f, t) =>
|
2020-03-28 14:17:47 +00:00
|
|
|
t |> integral(~cache) |> shapeFn(XYShape.XtoY.linear(f));
|
2020-03-14 18:33:39 +00:00
|
|
|
let integralYtoX = (~cache, f, t) =>
|
2020-03-28 14:17:47 +00:00
|
|
|
t |> integral(~cache) |> shapeFn(XYShape.YtoX.linear(f));
|
2020-02-22 16:24:54 +00:00
|
|
|
let toContinuous = t => Some(t);
|
|
|
|
let toDiscrete = _ => None;
|
2020-02-22 21:46:49 +00:00
|
|
|
let toScaledContinuous = t => Some(t);
|
|
|
|
let toScaledDiscrete = _ => None;
|
2020-02-22 16:24:54 +00:00
|
|
|
});
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module Discrete = {
|
2020-03-15 00:30:18 +00:00
|
|
|
let sortedByY = (t: DistTypes.discreteShape) =>
|
|
|
|
t
|
|
|
|
|> XYShape.T.zip
|
|
|
|
|> E.A.stableSortBy(_, ((_, y1), (_, y2)) => y1 > y2 ? 1 : 0);
|
|
|
|
let sortedByX = (t: DistTypes.discreteShape) =>
|
|
|
|
t
|
|
|
|
|> XYShape.T.zip
|
|
|
|
|> E.A.stableSortBy(_, ((x1, _), (x2, _)) => x1 > x2 ? 1 : 0);
|
2020-02-22 16:24:54 +00:00
|
|
|
module T =
|
|
|
|
Dist({
|
2020-02-23 13:27:52 +00:00
|
|
|
type t = DistTypes.discreteShape;
|
|
|
|
type integral = DistTypes.continuousShape;
|
2020-02-22 16:24:54 +00:00
|
|
|
let integral = (~cache, t) =>
|
2020-02-25 12:28:26 +00:00
|
|
|
switch (cache) {
|
|
|
|
| Some(c) => c
|
2020-03-28 21:46:17 +00:00
|
|
|
| None => Continuous.make(`Stepwise, XYShape.T.accumulateYs((+.), t))
|
2020-02-25 12:28:26 +00:00
|
|
|
};
|
2020-02-24 21:01:29 +00:00
|
|
|
let integralEndY = (~cache, t) =>
|
2020-02-24 11:11:03 +00:00
|
|
|
t |> integral(~cache) |> Continuous.lastY;
|
2020-03-14 21:18:34 +00:00
|
|
|
let minX = XYShape.T.minX;
|
|
|
|
let maxX = XYShape.T.maxX;
|
2020-02-26 10:08:37 +00:00
|
|
|
let toDiscreteProbabilityMass = t => 1.0;
|
2020-03-28 14:17:47 +00:00
|
|
|
let mapY = XYShape.T.mapY;
|
2020-02-23 13:27:52 +00:00
|
|
|
let toShape = (t: t): DistTypes.shape => Discrete(t);
|
2020-02-22 16:24:54 +00:00
|
|
|
let toContinuous = _ => None;
|
|
|
|
let toDiscrete = t => Some(t);
|
2020-02-23 18:34:34 +00:00
|
|
|
let toScaledContinuous = _ => None;
|
2020-02-22 21:46:49 +00:00
|
|
|
let toScaledDiscrete = t => Some(t);
|
2020-03-18 20:50:01 +00:00
|
|
|
let truncate = (~cache=None, i, t: t): DistTypes.discreteShape =>
|
2020-03-15 00:30:18 +00:00
|
|
|
t
|
|
|
|
|> XYShape.T.zip
|
2020-03-28 14:17:47 +00:00
|
|
|
|> XYShape.Zipped.sortByY
|
2020-03-18 19:13:12 +00:00
|
|
|
|> Belt.Array.reverse
|
2020-03-15 00:30:18 +00:00
|
|
|
|> Belt.Array.slice(_, ~offset=0, ~len=i)
|
2020-03-28 14:17:47 +00:00
|
|
|
|> XYShape.Zipped.sortByX
|
2020-03-15 00:30:18 +00:00
|
|
|
|> XYShape.T.fromZippedArray;
|
2020-02-23 19:40:38 +00:00
|
|
|
|
|
|
|
let xToY = (f, t) => {
|
2020-03-28 14:17:47 +00:00
|
|
|
XYShape.XtoY.stepwiseIfAtX(f, t)
|
2020-02-23 19:40:38 +00:00
|
|
|
|> E.O.default(0.0)
|
2020-02-23 13:27:52 +00:00
|
|
|
|> DistTypes.MixedPoint.makeDiscrete;
|
2020-02-23 19:40:38 +00:00
|
|
|
};
|
2020-03-14 18:33:39 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
let integralXtoY = (~cache, f, t) =>
|
2020-03-26 23:18:19 +00:00
|
|
|
t
|
|
|
|
|> integral(~cache)
|
|
|
|
|> Continuous.getShape
|
2020-03-28 14:17:47 +00:00
|
|
|
|> XYShape.XtoY.linear(f);
|
2020-03-14 18:33:39 +00:00
|
|
|
|
|
|
|
let integralYtoX = (~cache, f, t) =>
|
2020-03-26 23:18:19 +00:00
|
|
|
t
|
|
|
|
|> integral(~cache)
|
|
|
|
|> Continuous.getShape
|
2020-03-28 14:17:47 +00:00
|
|
|
|> XYShape.YtoX.linear(f);
|
2020-02-22 16:24:54 +00:00
|
|
|
});
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module Mixed = {
|
2020-02-23 18:34:34 +00:00
|
|
|
type t = DistTypes.mixedShape;
|
2020-02-22 19:21:04 +00:00
|
|
|
let make =
|
|
|
|
(~continuous, ~discrete, ~discreteProbabilityMassFraction)
|
2020-02-23 13:27:52 +00:00
|
|
|
: DistTypes.mixedShape => {
|
2020-02-22 19:21:04 +00:00
|
|
|
continuous,
|
|
|
|
discrete,
|
|
|
|
discreteProbabilityMassFraction,
|
|
|
|
};
|
|
|
|
|
2020-02-23 18:34:34 +00:00
|
|
|
// todo: Put into scaling module
|
2020-02-23 12:40:18 +00:00
|
|
|
let scaleDiscreteFn =
|
2020-02-23 13:27:52 +00:00
|
|
|
({discreteProbabilityMassFraction}: DistTypes.mixedShape, f) =>
|
2020-02-22 21:46:49 +00:00
|
|
|
f *. discreteProbabilityMassFraction;
|
|
|
|
|
2020-03-18 21:46:43 +00:00
|
|
|
//TODO: Warning: This currently computes the integral, which is expensive.
|
2020-02-23 12:40:18 +00:00
|
|
|
let scaleContinuousFn =
|
2020-02-23 13:27:52 +00:00
|
|
|
({discreteProbabilityMassFraction}: DistTypes.mixedShape, f) =>
|
2020-02-22 21:46:49 +00:00
|
|
|
f *. (1.0 -. discreteProbabilityMassFraction);
|
|
|
|
|
2020-03-18 21:46:43 +00:00
|
|
|
//TODO: Warning: This currently computes the integral, which is expensive.
|
2020-02-23 18:34:34 +00:00
|
|
|
let scaleContinuous = ({discreteProbabilityMassFraction}: t, continuous) =>
|
|
|
|
continuous
|
2020-02-25 19:27:30 +00:00
|
|
|
|> Continuous.T.scaleToIntegralSum(
|
|
|
|
~intendedSum=1.0 -. discreteProbabilityMassFraction,
|
|
|
|
);
|
2020-02-23 18:34:34 +00:00
|
|
|
|
|
|
|
let scaleDiscrete = ({discreteProbabilityMassFraction}: t, disrete) =>
|
2020-02-25 19:27:30 +00:00
|
|
|
disrete
|
|
|
|
|> Discrete.T.scaleToIntegralSum(
|
|
|
|
~intendedSum=discreteProbabilityMassFraction,
|
|
|
|
);
|
2020-02-23 18:34:34 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module T =
|
|
|
|
Dist({
|
2020-02-23 13:27:52 +00:00
|
|
|
type t = DistTypes.mixedShape;
|
|
|
|
type integral = DistTypes.continuousShape;
|
2020-02-25 19:55:01 +00:00
|
|
|
let minX = ({continuous, discrete}: t) => {
|
2020-02-22 16:24:54 +00:00
|
|
|
min(Continuous.T.minX(continuous), Discrete.T.minX(discrete));
|
2020-02-25 19:55:01 +00:00
|
|
|
};
|
2020-02-22 16:24:54 +00:00
|
|
|
let maxX = ({continuous, discrete}: t) =>
|
|
|
|
max(Continuous.T.maxX(continuous), Discrete.T.maxX(discrete));
|
2020-02-23 13:27:52 +00:00
|
|
|
let toShape = (t: t): DistTypes.shape => Mixed(t);
|
2020-02-22 16:24:54 +00:00
|
|
|
let toContinuous = ({continuous}: t) => Some(continuous);
|
|
|
|
let toDiscrete = ({discrete}: t) => Some(discrete);
|
2020-02-26 10:08:37 +00:00
|
|
|
let toDiscreteProbabilityMass = ({discreteProbabilityMassFraction}: t) => discreteProbabilityMassFraction;
|
2020-02-23 12:40:18 +00:00
|
|
|
let xToY = (f, {discrete, continuous} as t: t) => {
|
2020-02-22 16:24:54 +00:00
|
|
|
let c =
|
|
|
|
continuous
|
|
|
|
|> Continuous.T.xToY(f)
|
2020-02-23 13:27:52 +00:00
|
|
|
|> DistTypes.MixedPoint.fmap(scaleContinuousFn(t));
|
2020-02-22 16:24:54 +00:00
|
|
|
let d =
|
|
|
|
discrete
|
|
|
|
|> Discrete.T.xToY(f)
|
2020-02-23 13:27:52 +00:00
|
|
|
|> DistTypes.MixedPoint.fmap(scaleDiscreteFn(t));
|
|
|
|
DistTypes.MixedPoint.add(c, d);
|
2020-02-22 16:24:54 +00:00
|
|
|
};
|
|
|
|
|
2020-03-15 00:30:18 +00:00
|
|
|
let truncate =
|
|
|
|
(
|
2020-03-18 20:50:01 +00:00
|
|
|
~cache=None,
|
2020-03-15 00:30:18 +00:00
|
|
|
count,
|
|
|
|
{discrete, continuous, discreteProbabilityMassFraction} as t: t,
|
|
|
|
)
|
|
|
|
: t => {
|
|
|
|
{
|
|
|
|
discrete:
|
|
|
|
Discrete.T.truncate(
|
|
|
|
int_of_float(
|
|
|
|
float_of_int(count) *. discreteProbabilityMassFraction,
|
|
|
|
),
|
|
|
|
discrete,
|
|
|
|
),
|
|
|
|
continuous:
|
|
|
|
Continuous.T.truncate(
|
|
|
|
int_of_float(
|
|
|
|
float_of_int(count)
|
|
|
|
*. (1.0 -. discreteProbabilityMassFraction),
|
|
|
|
),
|
|
|
|
continuous,
|
|
|
|
),
|
|
|
|
discreteProbabilityMassFraction,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-02-22 23:55:43 +00:00
|
|
|
let toScaledContinuous = ({continuous} as t: t) =>
|
|
|
|
Some(scaleContinuous(t, continuous));
|
|
|
|
|
|
|
|
let toScaledDiscrete = ({discrete} as t: t) =>
|
|
|
|
Some(scaleDiscrete(t, discrete));
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-22 23:55:43 +00:00
|
|
|
let integral =
|
|
|
|
(
|
|
|
|
~cache,
|
2020-02-25 19:27:30 +00:00
|
|
|
{continuous, discrete, discreteProbabilityMassFraction}: t,
|
2020-02-22 23:55:43 +00:00
|
|
|
) => {
|
2020-02-25 12:28:26 +00:00
|
|
|
switch (cache) {
|
|
|
|
| Some(cache) => cache
|
|
|
|
| None =>
|
2020-02-25 19:27:30 +00:00
|
|
|
let scaleContinuousBy =
|
|
|
|
(1.0 -. discreteProbabilityMassFraction)
|
|
|
|
/. (continuous |> Continuous.T.Integral.sum(~cache=None));
|
|
|
|
|
|
|
|
let scaleDiscreteBy =
|
|
|
|
discreteProbabilityMassFraction
|
|
|
|
/. (
|
|
|
|
discrete
|
|
|
|
|> Discrete.T.Integral.get(~cache=None)
|
|
|
|
|> Continuous.toLinear
|
|
|
|
|> E.O.fmap(Continuous.lastY)
|
|
|
|
|> E.O.toExn("")
|
|
|
|
);
|
|
|
|
|
2020-02-25 12:28:26 +00:00
|
|
|
let cont =
|
|
|
|
continuous
|
|
|
|
|> Continuous.T.Integral.get(~cache=None)
|
2020-02-25 19:27:30 +00:00
|
|
|
|> Continuous.T.scaleBy(~scale=scaleContinuousBy);
|
|
|
|
|
2020-02-25 12:28:26 +00:00
|
|
|
let dist =
|
|
|
|
discrete
|
|
|
|
|> Discrete.T.Integral.get(~cache=None)
|
|
|
|
|> Continuous.toLinear
|
|
|
|
|> E.O.toExn("")
|
2020-02-25 19:27:30 +00:00
|
|
|
|> Continuous.T.scaleBy(~scale=scaleDiscreteBy);
|
|
|
|
|
|
|
|
let result =
|
|
|
|
Continuous.make(
|
2020-03-28 21:46:17 +00:00
|
|
|
`Linear,
|
2020-03-28 14:17:47 +00:00
|
|
|
XYShape.Combine.combineLinear(
|
|
|
|
~fn=(a, b) => a +. b,
|
|
|
|
Continuous.getShape(cont),
|
|
|
|
Continuous.getShape(dist),
|
2020-02-25 19:27:30 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
result;
|
2020-02-25 12:28:26 +00:00
|
|
|
};
|
2020-02-22 10:10:10 +00:00
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-24 21:01:29 +00:00
|
|
|
let integralEndY = (~cache, t: t) => {
|
|
|
|
integral(~cache, t) |> Continuous.lastY;
|
2020-02-22 10:10:10 +00:00
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-03-14 18:33:39 +00:00
|
|
|
let integralXtoY = (~cache, f, t) => {
|
2020-03-26 23:18:19 +00:00
|
|
|
t
|
|
|
|
|> integral(~cache)
|
|
|
|
|> Continuous.getShape
|
2020-03-28 14:17:47 +00:00
|
|
|
|> XYShape.XtoY.linear(f);
|
2020-03-14 18:33:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let integralYtoX = (~cache, f, t) => {
|
2020-03-26 23:18:19 +00:00
|
|
|
t
|
|
|
|
|> integral(~cache)
|
|
|
|
|> Continuous.getShape
|
2020-03-28 14:17:47 +00:00
|
|
|
|> XYShape.YtoX.linear(f);
|
2020-02-22 16:24:54 +00:00
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-23 18:34:34 +00:00
|
|
|
// TODO: This functionality is kinda weird, because it seems to assume the cdf adds to 1.0 elsewhere, which wouldn't happen here.
|
2020-03-28 14:17:47 +00:00
|
|
|
let mapY =
|
2020-02-22 16:24:54 +00:00
|
|
|
(fn, {discrete, continuous, discreteProbabilityMassFraction}: t): t => {
|
|
|
|
{
|
2020-03-28 14:17:47 +00:00
|
|
|
discrete: Discrete.T.mapY(fn, discrete),
|
|
|
|
continuous: Continuous.T.mapY(fn, continuous),
|
2020-02-22 16:24:54 +00:00
|
|
|
discreteProbabilityMassFraction,
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
};
|
2020-02-22 16:24:54 +00:00
|
|
|
});
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module Shape = {
|
|
|
|
module T =
|
|
|
|
Dist({
|
2020-02-23 13:27:52 +00:00
|
|
|
type t = DistTypes.shape;
|
|
|
|
type integral = DistTypes.continuousShape;
|
2020-02-22 12:51:25 +00:00
|
|
|
|
2020-02-23 18:34:34 +00:00
|
|
|
// todo: change order of arguments so t goes last.
|
|
|
|
// todo: Think of other name here?
|
2020-02-22 16:24:54 +00:00
|
|
|
let mapToAll = (t: t, (fn1, fn2, fn3)) =>
|
|
|
|
switch (t) {
|
|
|
|
| Mixed(m) => fn1(m)
|
|
|
|
| Discrete(m) => fn2(m)
|
|
|
|
| Continuous(m) => fn3(m)
|
|
|
|
};
|
2020-02-22 12:51:25 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
let fmap = (t: t, (fn1, fn2, fn3)): t =>
|
|
|
|
switch (t) {
|
|
|
|
| Mixed(m) => Mixed(fn1(m))
|
|
|
|
| Discrete(m) => Discrete(fn2(m))
|
|
|
|
| Continuous(m) => Continuous(fn3(m))
|
|
|
|
};
|
2020-02-22 12:51:25 +00:00
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
let xToY = (f, t) =>
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(Mixed.T.xToY(f), Discrete.T.xToY(f), Continuous.T.xToY(f)),
|
|
|
|
);
|
|
|
|
let toShape = (t: t) => t;
|
|
|
|
let toContinuous = (t: t) =>
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.toContinuous,
|
|
|
|
Discrete.T.toContinuous,
|
|
|
|
Continuous.T.toContinuous,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
let toDiscrete = (t: t) =>
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.toDiscrete,
|
|
|
|
Discrete.T.toDiscrete,
|
|
|
|
Continuous.T.toDiscrete,
|
|
|
|
),
|
|
|
|
);
|
2020-02-26 10:08:37 +00:00
|
|
|
|
2020-03-18 20:50:01 +00:00
|
|
|
let truncate = (~cache=None, i, t: t) =>
|
2020-03-15 00:30:18 +00:00
|
|
|
fmap(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.truncate(i),
|
|
|
|
Discrete.T.truncate(i),
|
|
|
|
Continuous.T.truncate(i),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2020-02-26 10:08:37 +00:00
|
|
|
let toDiscreteProbabilityMass = (t: t) =>
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.toDiscreteProbabilityMass,
|
|
|
|
Discrete.T.toDiscreteProbabilityMass,
|
|
|
|
Continuous.T.toDiscreteProbabilityMass,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2020-02-22 21:46:49 +00:00
|
|
|
let toScaledDiscrete = (t: t) =>
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.toScaledDiscrete,
|
|
|
|
Discrete.T.toScaledDiscrete,
|
|
|
|
Continuous.T.toScaledDiscrete,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
let toScaledContinuous = (t: t) =>
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.toScaledContinuous,
|
|
|
|
Discrete.T.toScaledContinuous,
|
|
|
|
Continuous.T.toScaledContinuous,
|
|
|
|
),
|
|
|
|
);
|
2020-02-22 16:24:54 +00:00
|
|
|
let minX = (t: t) =>
|
|
|
|
mapToAll(t, (Mixed.T.minX, Discrete.T.minX, Continuous.T.minX));
|
2020-02-22 23:55:43 +00:00
|
|
|
let integral = (~cache, t: t) => {
|
2020-02-22 16:24:54 +00:00
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.Integral.get(~cache),
|
|
|
|
Discrete.T.Integral.get(~cache),
|
|
|
|
Continuous.T.Integral.get(~cache),
|
|
|
|
),
|
|
|
|
);
|
2020-02-22 23:55:43 +00:00
|
|
|
};
|
2020-02-24 21:01:29 +00:00
|
|
|
let integralEndY = (~cache, t: t) =>
|
2020-02-22 16:24:54 +00:00
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.Integral.sum(~cache),
|
|
|
|
Discrete.T.Integral.sum(~cache),
|
|
|
|
Continuous.T.Integral.sum(~cache),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
let integralXtoY = (~cache, f, t) => {
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.Integral.xToY(~cache, f),
|
|
|
|
Discrete.T.Integral.xToY(~cache, f),
|
|
|
|
Continuous.T.Integral.xToY(~cache, f),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
};
|
2020-03-14 18:33:39 +00:00
|
|
|
let integralYtoX = (~cache, f, t) => {
|
|
|
|
mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.T.Integral.yToX(~cache, f),
|
|
|
|
Discrete.T.Integral.yToX(~cache, f),
|
|
|
|
Continuous.T.Integral.yToX(~cache, f),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
};
|
2020-02-22 16:24:54 +00:00
|
|
|
let maxX = (t: t) =>
|
2020-02-22 20:36:22 +00:00
|
|
|
mapToAll(t, (Mixed.T.maxX, Discrete.T.maxX, Continuous.T.maxX));
|
2020-03-28 14:17:47 +00:00
|
|
|
let mapY = (fn, t: t) =>
|
2020-02-22 16:24:54 +00:00
|
|
|
fmap(
|
|
|
|
t,
|
2020-03-28 14:17:47 +00:00
|
|
|
(Mixed.T.mapY(fn), Discrete.T.mapY(fn), Continuous.T.mapY(fn)),
|
2020-02-22 16:24:54 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
|
2020-02-23 12:49:33 +00:00
|
|
|
module DistPlus = {
|
2020-02-23 13:27:52 +00:00
|
|
|
open DistTypes;
|
2020-02-23 18:34:34 +00:00
|
|
|
|
|
|
|
type t = DistTypes.distPlus;
|
|
|
|
|
2020-02-24 21:01:29 +00:00
|
|
|
let shapeIntegral = shape => Shape.T.Integral.get(~cache=None, shape);
|
2020-02-22 20:36:22 +00:00
|
|
|
let make =
|
|
|
|
(
|
|
|
|
~shape,
|
|
|
|
~guesstimatorString,
|
|
|
|
~domain=Complete,
|
|
|
|
~unit=UnspecifiedDistribution,
|
|
|
|
(),
|
|
|
|
)
|
2020-02-23 18:34:34 +00:00
|
|
|
: t => {
|
2020-02-24 21:01:29 +00:00
|
|
|
let integral = shapeIntegral(shape);
|
2020-02-22 20:36:22 +00:00
|
|
|
{shape, domain, integralCache: integral, unit, guesstimatorString};
|
|
|
|
};
|
2020-02-23 18:34:34 +00:00
|
|
|
|
2020-02-22 20:36:22 +00:00
|
|
|
let update =
|
|
|
|
(
|
|
|
|
~shape=?,
|
|
|
|
~integralCache=?,
|
|
|
|
~domain=?,
|
|
|
|
~unit=?,
|
|
|
|
~guesstimatorString=?,
|
2020-02-23 18:34:34 +00:00
|
|
|
t: t,
|
2020-02-22 20:36:22 +00:00
|
|
|
) => {
|
|
|
|
shape: E.O.default(t.shape, shape),
|
|
|
|
integralCache: E.O.default(t.integralCache, integralCache),
|
|
|
|
domain: E.O.default(t.domain, domain),
|
|
|
|
unit: E.O.default(t.unit, unit),
|
|
|
|
guesstimatorString: E.O.default(t.guesstimatorString, guesstimatorString),
|
|
|
|
};
|
|
|
|
|
2020-02-24 21:01:29 +00:00
|
|
|
let updateShape = (shape, t) => {
|
|
|
|
let integralCache = shapeIntegral(shape);
|
|
|
|
update(~shape, ~integralCache, t);
|
|
|
|
};
|
|
|
|
|
2020-02-23 18:34:34 +00:00
|
|
|
let domainIncludedProbabilityMass = (t: t) =>
|
|
|
|
Domain.includedProbabilityMass(t.domain);
|
|
|
|
|
|
|
|
let domainIncludedProbabilityMassAdjustment = (t: t, f) =>
|
|
|
|
f *. Domain.includedProbabilityMass(t.domain);
|
|
|
|
|
|
|
|
let toShape = ({shape, _}: t) => shape;
|
|
|
|
|
|
|
|
let shapeFn = (fn, {shape}: t) => fn(shape);
|
|
|
|
|
2020-02-22 16:24:54 +00:00
|
|
|
module T =
|
|
|
|
Dist({
|
2020-02-23 13:27:52 +00:00
|
|
|
type t = DistTypes.distPlus;
|
|
|
|
type integral = DistTypes.distPlus;
|
2020-02-23 18:34:34 +00:00
|
|
|
let toShape = toShape;
|
2020-02-22 19:21:04 +00:00
|
|
|
let toContinuous = shapeFn(Shape.T.toContinuous);
|
|
|
|
let toDiscrete = shapeFn(Shape.T.toDiscrete);
|
2020-02-22 21:46:49 +00:00
|
|
|
// todo: Adjust for total mass.
|
2020-02-23 12:40:18 +00:00
|
|
|
|
|
|
|
let toScaledContinuous = (t: t) => {
|
|
|
|
t
|
|
|
|
|> toShape
|
|
|
|
|> Shape.T.toScaledContinuous
|
|
|
|
|> E.O.fmap(
|
2020-03-28 14:17:47 +00:00
|
|
|
Continuous.T.mapY(domainIncludedProbabilityMassAdjustment(t)),
|
2020-02-23 12:40:18 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
let toScaledDiscrete = (t: t) => {
|
|
|
|
t
|
|
|
|
|> toShape
|
|
|
|
|> Shape.T.toScaledDiscrete
|
|
|
|
|> E.O.fmap(
|
2020-03-28 14:17:47 +00:00
|
|
|
Discrete.T.mapY(domainIncludedProbabilityMassAdjustment(t)),
|
2020-02-23 12:40:18 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
let xToY = (f, t: t) =>
|
|
|
|
t
|
|
|
|
|> toShape
|
|
|
|
|> Shape.T.xToY(f)
|
|
|
|
|> MixedPoint.fmap(domainIncludedProbabilityMassAdjustment(t));
|
|
|
|
|
2020-02-22 19:21:04 +00:00
|
|
|
let minX = shapeFn(Shape.T.minX);
|
|
|
|
let maxX = shapeFn(Shape.T.maxX);
|
2020-02-26 10:08:37 +00:00
|
|
|
let toDiscreteProbabilityMass =
|
|
|
|
shapeFn(Shape.T.toDiscreteProbabilityMass);
|
2020-02-23 12:40:18 +00:00
|
|
|
|
2020-03-18 21:46:43 +00:00
|
|
|
// This bit is kind of awkward, could probably use rethinking.
|
2020-02-24 22:04:39 +00:00
|
|
|
let integral = (~cache, t: t) =>
|
2020-02-24 21:01:29 +00:00
|
|
|
updateShape(Continuous(t.integralCache), t);
|
|
|
|
|
2020-03-18 20:50:01 +00:00
|
|
|
let truncate = (~cache=None, i, t) =>
|
2020-03-15 00:30:18 +00:00
|
|
|
updateShape(t |> toShape |> Shape.T.truncate(i), t);
|
2020-02-24 21:01:29 +00:00
|
|
|
// todo: adjust for limit, maybe?
|
2020-03-28 14:17:47 +00:00
|
|
|
let mapY = (fn, {shape, _} as t: t): t =>
|
|
|
|
Shape.T.mapY(fn, shape) |> updateShape(_, t);
|
2020-02-23 12:40:18 +00:00
|
|
|
|
2020-02-24 21:01:29 +00:00
|
|
|
let integralEndY = (~cache as _, t: t) =>
|
2020-02-22 19:21:04 +00:00
|
|
|
Shape.T.Integral.sum(~cache=Some(t.integralCache), toShape(t));
|
2020-02-23 12:40:18 +00:00
|
|
|
|
2020-02-23 18:34:34 +00:00
|
|
|
// TODO: Fix this below, obviously. Adjust for limits
|
2020-02-22 19:21:04 +00:00
|
|
|
let integralXtoY = (~cache as _, f, t: t) => {
|
2020-02-25 19:27:30 +00:00
|
|
|
Shape.T.Integral.xToY(~cache=Some(t.integralCache), f, toShape(t))
|
|
|
|
|> domainIncludedProbabilityMassAdjustment(t);
|
2020-02-22 16:24:54 +00:00
|
|
|
};
|
2020-03-14 18:33:39 +00:00
|
|
|
|
|
|
|
// TODO: This part is broken when there is a limit, if this is supposed to be taken into account.
|
|
|
|
let integralYtoX = (~cache as _, f, t: t) => {
|
|
|
|
Shape.T.Integral.yToX(~cache=Some(t.integralCache), f, toShape(t));
|
|
|
|
};
|
2020-02-22 16:24:54 +00:00
|
|
|
});
|
2020-02-23 18:34:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
module DistPlusTime = {
|
|
|
|
open DistTypes;
|
|
|
|
|
|
|
|
type t = DistTypes.distPlus;
|
|
|
|
|
|
|
|
let unitToJson = ({unit}: t) => unit |> DistTypes.DistributionUnit.toJson;
|
|
|
|
|
|
|
|
let timeVector = ({unit}: t) =>
|
|
|
|
switch (unit) {
|
|
|
|
| TimeDistribution(timeVector) => Some(timeVector)
|
|
|
|
| UnspecifiedDistribution => None
|
|
|
|
};
|
|
|
|
|
|
|
|
let timeInVectorToX = (f: TimeTypes.timeInVector, t: t) => {
|
|
|
|
let timeVector = t |> timeVector;
|
|
|
|
timeVector |> E.O.fmap(TimeTypes.RelativeTimePoint.toXValue(_, f));
|
|
|
|
};
|
|
|
|
|
|
|
|
let xToY = (f: TimeTypes.timeInVector, t: t) => {
|
|
|
|
timeInVectorToX(f, t) |> E.O.fmap(DistPlus.T.xToY(_, t));
|
|
|
|
};
|
|
|
|
|
|
|
|
module Integral = {
|
|
|
|
include DistPlus.T.Integral;
|
2020-02-25 19:27:30 +00:00
|
|
|
let xToY = (f: TimeTypes.timeInVector, t: t) => {
|
2020-02-23 18:34:34 +00:00
|
|
|
timeInVectorToX(f, t)
|
|
|
|
|> E.O.fmap(x => DistPlus.T.Integral.xToY(~cache=None, x, t));
|
|
|
|
};
|
|
|
|
};
|
2020-02-22 16:24:54 +00:00
|
|
|
};
|