2020-02-21 23:42:15 +00:00
|
|
|
let min = (f1: option(float), f2: option(float)) =>
|
|
|
|
switch (f1, f2) {
|
|
|
|
| (Some(f1), Some(f2)) => Some(f1 < f2 ? f1 : f2)
|
|
|
|
| (Some(f1), None) => Some(f1)
|
|
|
|
| (None, Some(f2)) => Some(f2)
|
|
|
|
| (None, None) => None
|
|
|
|
};
|
|
|
|
|
|
|
|
let max = (f1: option(float), f2: option(float)) =>
|
|
|
|
switch (f1, f2) {
|
|
|
|
| (Some(f1), Some(f2)) => Some(f1 > f2 ? f1 : f2)
|
|
|
|
| (Some(f1), None) => Some(f1)
|
|
|
|
| (None, Some(f2)) => Some(f2)
|
|
|
|
| (None, None) => None
|
|
|
|
};
|
|
|
|
|
|
|
|
type yPoint =
|
|
|
|
| Mixed({
|
|
|
|
continuous: float,
|
|
|
|
discrete: float,
|
|
|
|
})
|
|
|
|
| Continuous(float)
|
|
|
|
| Discrete(float);
|
|
|
|
|
2020-02-22 11:07:17 +00:00
|
|
|
module YPoint = {
|
|
|
|
type t = yPoint;
|
|
|
|
let toContinuousValue = (t: t) =>
|
|
|
|
switch (t) {
|
|
|
|
| Continuous(f) => f
|
|
|
|
| Mixed({continuous}) => continuous
|
|
|
|
| _ => 0.0
|
|
|
|
};
|
|
|
|
let makeContinuous = (f: float): t => Continuous(f);
|
|
|
|
let makeDiscrete = (f: float): t => Discrete(f);
|
|
|
|
let makeMixed = (c: float, d: float): t =>
|
|
|
|
Mixed({continuous: c, discrete: d});
|
|
|
|
};
|
2020-02-22 10:10:10 +00:00
|
|
|
|
2020-02-21 23:42:15 +00:00
|
|
|
module type dist = {
|
|
|
|
type t;
|
|
|
|
let minX: t => option(float);
|
|
|
|
let maxX: t => option(float);
|
|
|
|
let pointwiseFmap: (float => float, t) => t;
|
|
|
|
let xToY: (float, t) => yPoint;
|
|
|
|
let shape: t => DistributionTypes.shape;
|
2020-02-22 10:17:51 +00:00
|
|
|
|
|
|
|
type integral;
|
2020-02-22 10:10:10 +00:00
|
|
|
let integral: (~cache: option(integral), t) => integral;
|
|
|
|
let integralSum: (~cache: option(integral), t) => float;
|
2020-02-22 10:17:51 +00:00
|
|
|
let integralXtoY: (~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;
|
|
|
|
let pointwiseFmap = T.pointwiseFmap;
|
|
|
|
let xToY = T.xToY;
|
|
|
|
let shape = T.shape;
|
2020-02-22 10:17:51 +00:00
|
|
|
|
|
|
|
module Integral = {
|
|
|
|
type t = T.integral;
|
|
|
|
let get = T.integral;
|
|
|
|
let xToY = T.integralXtoY;
|
|
|
|
let sum = T.integralSum;
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
module Continuous =
|
|
|
|
Dist({
|
|
|
|
type t = DistributionTypes.continuousShape;
|
|
|
|
type integral = DistributionTypes.continuousShape;
|
2020-02-22 11:07:17 +00:00
|
|
|
let shape = (t: t) => t.shape;
|
2020-02-22 10:10:10 +00:00
|
|
|
let integral = (~cache, t) =>
|
2020-02-22 11:07:17 +00:00
|
|
|
cache
|
|
|
|
|> E.O.default(
|
|
|
|
t
|
|
|
|
|> shape
|
|
|
|
|> Shape.XYShape.Range.integrateWithTriangles
|
|
|
|
|> E.O.toExt("")
|
|
|
|
|> Shape.Continuous.fromShape,
|
|
|
|
);
|
2020-02-22 10:10:10 +00:00
|
|
|
// This seems wrong, we really want the ending bit, I'd assume
|
|
|
|
let integralSum = (~cache, t) =>
|
2020-02-22 11:07:17 +00:00
|
|
|
t |> integral(~cache) |> shape |> Shape.XYShape.ySum;
|
|
|
|
let minX = (t: t) => t |> shape |> Shape.XYShape.minX;
|
|
|
|
let maxX = (t: t) => t |> shape |> Shape.XYShape.maxX;
|
|
|
|
let pointwiseFmap = (fn, t: t) =>
|
|
|
|
t
|
|
|
|
|> shape
|
|
|
|
|> Shape.XYShape.pointwiseMap(fn)
|
|
|
|
|> Shape.Continuous.fromShape;
|
2020-02-21 23:42:15 +00:00
|
|
|
let shape = (t: t): DistributionTypes.shape => Continuous(t);
|
|
|
|
let xToY = (f, t) =>
|
2020-02-22 11:07:17 +00:00
|
|
|
Shape.Continuous.findY(f, t) |> YPoint.makeContinuous;
|
2020-02-22 10:17:51 +00:00
|
|
|
let integralXtoY = (~cache, f, t) =>
|
2020-02-22 11:07:17 +00:00
|
|
|
t |> integral(~cache) |> Shape.Continuous.findY(f);
|
2020-02-21 23:42:15 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
module Discrete =
|
|
|
|
Dist({
|
|
|
|
type t = DistributionTypes.discreteShape;
|
|
|
|
type integral = DistributionTypes.continuousShape;
|
2020-02-22 10:17:51 +00:00
|
|
|
let integral = (~cache, t) =>
|
|
|
|
cache |> E.O.default(t |> Shape.Discrete.integrate);
|
2020-02-22 10:10:10 +00:00
|
|
|
let integralSum = (~cache, t) => t |> Shape.XYShape.ySum;
|
2020-02-21 23:42:15 +00:00
|
|
|
let minX = Shape.XYShape.minX;
|
|
|
|
let maxX = Shape.XYShape.maxX;
|
|
|
|
let pointwiseFmap = Shape.XYShape.pointwiseMap;
|
|
|
|
let shape = (t: t): DistributionTypes.shape => Discrete(t);
|
|
|
|
let xToY = (f, t) =>
|
|
|
|
CdfLibrary.Distribution.findY(f, t) |> (e => Discrete(e));
|
2020-02-22 10:17:51 +00:00
|
|
|
let integralXtoY = (~cache, f, t) =>
|
2020-02-21 23:42:15 +00:00
|
|
|
t |> Shape.XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
|
|
|
|
});
|
|
|
|
|
|
|
|
module Mixed =
|
|
|
|
Dist({
|
|
|
|
type t = DistributionTypes.mixedShape;
|
|
|
|
type integral = DistributionTypes.continuousShape;
|
|
|
|
let minX = ({continuous, discrete}: t) =>
|
|
|
|
min(Continuous.minX(continuous), Discrete.minX(discrete));
|
|
|
|
let maxX = ({continuous, discrete}: t) =>
|
|
|
|
max(Continuous.maxX(continuous), Discrete.maxX(discrete));
|
|
|
|
let shape = (t: t): DistributionTypes.shape => Mixed(t);
|
|
|
|
let xToY =
|
|
|
|
(f, {discrete, continuous, discreteProbabilityMassFraction}: t) =>
|
|
|
|
Mixed({
|
|
|
|
continuous:
|
2020-02-22 11:07:17 +00:00
|
|
|
Continuous.xToY(f, continuous)
|
|
|
|
|> YPoint.toContinuousValue
|
2020-02-21 23:42:15 +00:00
|
|
|
|> (e => e *. (1. -. discreteProbabilityMassFraction)),
|
|
|
|
discrete:
|
|
|
|
Shape.Discrete.findY(f, discrete)
|
|
|
|
|> (e => e *. discreteProbabilityMassFraction),
|
|
|
|
});
|
|
|
|
|
|
|
|
let scaledContinuousComponent =
|
|
|
|
({continuous, discreteProbabilityMassFraction}: t)
|
|
|
|
: option(DistributionTypes.continuousShape) => {
|
|
|
|
Shape.Continuous.scalePdf(
|
|
|
|
~scaleTo=1.0 -. discreteProbabilityMassFraction,
|
|
|
|
continuous,
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
let scaledDiscreteComponent =
|
|
|
|
({discrete, discreteProbabilityMassFraction}: t)
|
|
|
|
: DistributionTypes.continuousShape =>
|
2020-02-22 11:07:17 +00:00
|
|
|
Shape.Continuous.make(
|
|
|
|
Discrete.pointwiseFmap(
|
|
|
|
f => f *. discreteProbabilityMassFraction,
|
|
|
|
discrete,
|
|
|
|
),
|
|
|
|
`Stepwise,
|
2020-02-21 23:42:15 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
// TODO: Add these two directly, once interpolation is added.
|
2020-02-22 10:10:10 +00:00
|
|
|
let integral = (~cache, t) => {
|
2020-02-21 23:42:15 +00:00
|
|
|
// let cont = scaledContinuousComponent(t);
|
|
|
|
// let discrete = scaledDiscreteComponent(t);
|
2020-02-22 10:10:10 +00:00
|
|
|
switch (cache) {
|
|
|
|
| Some(cache) => cache
|
|
|
|
| None => scaledContinuousComponent(t) |> E.O.toExt("")
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let integralSum =
|
2020-02-22 10:10:10 +00:00
|
|
|
(~cache, {discrete, continuous, discreteProbabilityMassFraction}: t) => {
|
|
|
|
switch (cache) {
|
|
|
|
| Some(cache) => 3.0
|
|
|
|
| None =>
|
2020-02-22 10:17:51 +00:00
|
|
|
Discrete.Integral.sum(~cache=None, discrete)
|
2020-02-22 10:10:10 +00:00
|
|
|
*. discreteProbabilityMassFraction
|
2020-02-22 10:17:51 +00:00
|
|
|
+. Continuous.Integral.sum(~cache=None, continuous)
|
2020-02-22 10:10:10 +00:00
|
|
|
*. (1.0 -. discreteProbabilityMassFraction)
|
|
|
|
};
|
2020-02-21 23:42:15 +00:00
|
|
|
};
|
|
|
|
|
2020-02-22 10:17:51 +00:00
|
|
|
let integralXtoY =
|
2020-02-22 10:10:10 +00:00
|
|
|
(
|
|
|
|
~cache,
|
|
|
|
f,
|
|
|
|
{discrete, continuous, discreteProbabilityMassFraction}: t,
|
|
|
|
) => {
|
2020-02-22 10:17:51 +00:00
|
|
|
let cont = Continuous.Integral.xToY(~cache, f, continuous);
|
|
|
|
let discrete = Discrete.Integral.xToY(~cache, f, discrete);
|
2020-02-21 23:42:15 +00:00
|
|
|
discrete
|
|
|
|
*. discreteProbabilityMassFraction
|
|
|
|
+. cont
|
|
|
|
*. (1.0 -. discreteProbabilityMassFraction);
|
|
|
|
};
|
|
|
|
|
|
|
|
let pointwiseFmap =
|
|
|
|
(fn, {discrete, continuous, discreteProbabilityMassFraction}: t): t => {
|
|
|
|
{
|
|
|
|
discrete: Shape.XYShape.pointwiseMap(fn, discrete),
|
2020-02-22 11:07:17 +00:00
|
|
|
continuous:
|
|
|
|
continuous
|
|
|
|
|> Shape.Continuous.shapeMap(Shape.XYShape.pointwiseMap(fn)),
|
2020-02-21 23:42:15 +00:00
|
|
|
discreteProbabilityMassFraction,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
module Shape =
|
|
|
|
Dist({
|
|
|
|
type t = DistributionTypes.shape;
|
|
|
|
type integral = DistributionTypes.continuousShape;
|
|
|
|
let xToY = (f, t) =>
|
|
|
|
Shape.T.mapToAll(
|
|
|
|
t,
|
|
|
|
(Mixed.xToY(f), Discrete.xToY(f), Continuous.xToY(f)),
|
|
|
|
);
|
|
|
|
let shape = (t: t) => t;
|
|
|
|
let minX = (t: t) =>
|
|
|
|
Shape.T.mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX));
|
2020-02-22 10:10:10 +00:00
|
|
|
let integral = (~cache, t: t) =>
|
2020-02-21 23:42:15 +00:00
|
|
|
Shape.T.mapToAll(
|
|
|
|
t,
|
2020-02-22 10:10:10 +00:00
|
|
|
(
|
2020-02-22 10:17:51 +00:00
|
|
|
Mixed.Integral.get(~cache),
|
|
|
|
Discrete.Integral.get(~cache),
|
|
|
|
Continuous.Integral.get(~cache),
|
2020-02-22 10:10:10 +00:00
|
|
|
),
|
2020-02-21 23:42:15 +00:00
|
|
|
);
|
2020-02-22 10:10:10 +00:00
|
|
|
let integralSum = (~cache, t: t) =>
|
2020-02-21 23:42:15 +00:00
|
|
|
Shape.T.mapToAll(
|
|
|
|
t,
|
2020-02-22 10:10:10 +00:00
|
|
|
(
|
2020-02-22 10:17:51 +00:00
|
|
|
Mixed.Integral.sum(~cache),
|
|
|
|
Discrete.Integral.sum(~cache),
|
|
|
|
Continuous.Integral.sum(~cache),
|
2020-02-22 10:10:10 +00:00
|
|
|
),
|
2020-02-21 23:42:15 +00:00
|
|
|
);
|
2020-02-22 10:17:51 +00:00
|
|
|
let integralXtoY = (~cache, f, t) => {
|
2020-02-21 23:42:15 +00:00
|
|
|
Shape.T.mapToAll(
|
|
|
|
t,
|
|
|
|
(
|
2020-02-22 10:17:51 +00:00
|
|
|
Mixed.Integral.xToY(~cache, f),
|
|
|
|
Discrete.Integral.xToY(~cache, f),
|
|
|
|
Continuous.Integral.xToY(~cache, f),
|
2020-02-21 23:42:15 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
let maxX = (t: t) =>
|
|
|
|
Shape.T.mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX));
|
|
|
|
let pointwiseFmap = (fn, t: t) =>
|
|
|
|
Shape.T.fmap(
|
|
|
|
t,
|
|
|
|
(
|
|
|
|
Mixed.pointwiseFmap(fn),
|
|
|
|
Discrete.pointwiseFmap(fn),
|
|
|
|
Continuous.pointwiseFmap(fn),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
module WithMetadata =
|
|
|
|
Dist({
|
|
|
|
type t = DistributionTypes.complexPower;
|
|
|
|
type integral = DistributionTypes.complexPower;
|
|
|
|
let shape = ({shape, _}: t) => shape;
|
|
|
|
let xToY = (f, t: t) => t |> shape |> Shape.xToY(f);
|
|
|
|
let minX = (t: t) => t |> shape |> Shape.minX;
|
|
|
|
let maxX = (t: t) => t |> shape |> Shape.maxX;
|
|
|
|
let fromShape = (shape, t): t => DistributionTypes.update(~shape, t);
|
|
|
|
let pointwiseFmap = (fn, {shape, _} as t: t): t =>
|
|
|
|
fromShape(Shape.pointwiseFmap(fn, shape), t);
|
|
|
|
|
2020-02-22 11:07:17 +00:00
|
|
|
let integral = (~cache as _, t: t) =>
|
2020-02-22 10:10:10 +00:00
|
|
|
fromShape(Continuous(t.integralCache), t);
|
2020-02-22 11:07:17 +00:00
|
|
|
let integralSum = (~cache as _, t: t) =>
|
2020-02-22 10:17:51 +00:00
|
|
|
t |> shape |> Shape.Integral.sum(~cache=Some(t.integralCache));
|
2020-02-22 11:07:17 +00:00
|
|
|
let integralXtoY = (~cache as _, f, t) => {
|
2020-02-21 23:42:15 +00:00
|
|
|
3.0;
|
|
|
|
};
|
|
|
|
});
|