Ozzie's suggestions
This commit is contained in:
parent
9cdcc85d6c
commit
f3922761f4
|
@ -17,25 +17,25 @@ let toDiscretePointMassesFromTriangulars =
|
||||||
let n = s |> XYShape.T.length;
|
let n = s |> XYShape.T.length;
|
||||||
// first, double up the leftmost and rightmost points:
|
// first, double up the leftmost and rightmost points:
|
||||||
let {xs, ys}: XYShape.T.t = s;
|
let {xs, ys}: XYShape.T.t = s;
|
||||||
let _ = Js.Array.unshift(xs[0], xs);
|
Js.Array.unshift(xs[0], xs) |> ignore;
|
||||||
let _ = Js.Array.unshift(ys[0], ys);
|
Js.Array.unshift(ys[0], ys) |> ignore;
|
||||||
let _ = Js.Array.push(xs[n - 1], xs);
|
Js.Array.push(xs[n - 1], xs) |> ignore;
|
||||||
let _ = Js.Array.push(ys[n - 1], ys);
|
Js.Array.push(ys[n - 1], ys) |> ignore;
|
||||||
let n = E.A.length(xs);
|
let n = E.A.length(xs);
|
||||||
// squares and neighbourly products of the xs
|
// squares and neighbourly products of the xs
|
||||||
let xsSq: array(float) = Belt.Array.makeUninitializedUnsafe(n);
|
let xsSq: array(float) = Belt.Array.makeUninitializedUnsafe(n);
|
||||||
let xsProdN1: array(float) = Belt.Array.makeUninitializedUnsafe(n - 1);
|
let xsProdN1: array(float) = Belt.Array.makeUninitializedUnsafe(n - 1);
|
||||||
let xsProdN2: array(float) = Belt.Array.makeUninitializedUnsafe(n - 2);
|
let xsProdN2: array(float) = Belt.Array.makeUninitializedUnsafe(n - 2);
|
||||||
for (i in 0 to n - 1) {
|
for (i in 0 to n - 1) {
|
||||||
let _ = Belt.Array.set(xsSq, i, xs[i] *. xs[i]);
|
Belt.Array.set(xsSq, i, xs[i] *. xs[i]) |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
for (i in 0 to n - 2) {
|
for (i in 0 to n - 2) {
|
||||||
let _ = Belt.Array.set(xsProdN1, i, xs[i] *. xs[i + 1]);
|
Belt.Array.set(xsProdN1, i, xs[i] *. xs[i + 1]) |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
for (i in 0 to n - 3) {
|
for (i in 0 to n - 3) {
|
||||||
let _ = Belt.Array.set(xsProdN2, i, xs[i] *. xs[i + 2]);
|
Belt.Array.set(xsProdN2, i, xs[i] *. xs[i + 2]) |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
// means and variances
|
// means and variances
|
||||||
|
@ -45,12 +45,11 @@ let toDiscretePointMassesFromTriangulars =
|
||||||
|
|
||||||
if (inverse) {
|
if (inverse) {
|
||||||
for (i in 1 to n - 2) {
|
for (i in 1 to n - 2) {
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
masses,
|
||||||
masses,
|
i - 1,
|
||||||
i - 1,
|
(xs[i + 1] -. xs[i - 1]) *. ys[i] /. 2.,
|
||||||
(xs[i + 1] -. xs[i - 1]) *. ys[i] /. 2.,
|
) |> ignore;
|
||||||
);
|
|
||||||
|
|
||||||
// this only works when the whole triange is either on the left or on the right of zero
|
// this only works when the whole triange is either on the left or on the right of zero
|
||||||
let a = xs[i - 1];
|
let a = xs[i - 1];
|
||||||
|
@ -71,43 +70,39 @@ let toDiscretePointMassesFromTriangulars =
|
||||||
-. inverseMean
|
-. inverseMean
|
||||||
** 2.;
|
** 2.;
|
||||||
|
|
||||||
let _ = Belt.Array.set(means, i - 1, inverseMean);
|
Belt.Array.set(means, i - 1, inverseMean) |> ignore;
|
||||||
|
|
||||||
let _ = Belt.Array.set(variances, i - 1, inverseVar);
|
Belt.Array.set(variances, i - 1, inverseVar) |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
|
|
||||||
{n: n - 2, masses, means, variances};
|
{n: n - 2, masses, means, variances};
|
||||||
} else {
|
} else {
|
||||||
for (i in 1 to n - 2) {
|
for (i in 1 to n - 2) {
|
||||||
|
|
||||||
// area of triangle = width * height / 2
|
// area of triangle = width * height / 2
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
masses,
|
||||||
masses,
|
i - 1,
|
||||||
i - 1,
|
(xs[i + 1] -. xs[i - 1]) *. ys[i] /. 2.,
|
||||||
(xs[i + 1] -. xs[i - 1]) *. ys[i] /. 2.,
|
) |> ignore;
|
||||||
);
|
|
||||||
|
|
||||||
// means of triangle = (a + b + c) / 3
|
// means of triangle = (a + b + c) / 3
|
||||||
let _ =
|
Belt.Array.set(means, i - 1, (xs[i - 1] +. xs[i] +. xs[i + 1]) /. 3.) |> ignore;
|
||||||
Belt.Array.set(means, i - 1, (xs[i - 1] +. xs[i] +. xs[i + 1]) /. 3.);
|
|
||||||
|
|
||||||
// variance of triangle = (a^2 + b^2 + c^2 - ab - ac - bc) / 18
|
// variance of triangle = (a^2 + b^2 + c^2 - ab - ac - bc) / 18
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
variances,
|
||||||
variances,
|
i - 1,
|
||||||
i - 1,
|
(
|
||||||
(
|
xsSq[i - 1]
|
||||||
xsSq[i - 1]
|
+. xsSq[i]
|
||||||
+. xsSq[i]
|
+. xsSq[i + 1]
|
||||||
+. xsSq[i + 1]
|
-. xsProdN1[i - 1]
|
||||||
-. xsProdN1[i - 1]
|
-. xsProdN1[i]
|
||||||
-. xsProdN1[i]
|
-. xsProdN2[i - 1]
|
||||||
-. xsProdN2[i - 1]
|
)
|
||||||
)
|
/. 18.,
|
||||||
/. 18.,
|
) |> ignore;
|
||||||
);
|
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
{n: n - 2, masses, means, variances};
|
{n: n - 2, masses, means, variances};
|
||||||
|
@ -163,7 +158,7 @@ let combineShapesContinuousContinuous =
|
||||||
for (i in 0 to t1m.n - 1) {
|
for (i in 0 to t1m.n - 1) {
|
||||||
for (j in 0 to t2m.n - 1) {
|
for (j in 0 to t2m.n - 1) {
|
||||||
let k = i * t2m.n + j;
|
let k = i * t2m.n + j;
|
||||||
let _ = Belt.Array.set(masses, k, t1m.masses[i] *. t2m.masses[j]);
|
Belt.Array.set(masses, k, t1m.masses[i] *. t2m.masses[j]) |> ignore;
|
||||||
|
|
||||||
let mean = combineMeansFn(t1m.means[i], t2m.means[j]);
|
let mean = combineMeansFn(t1m.means[i], t2m.means[j]);
|
||||||
let variance =
|
let variance =
|
||||||
|
@ -173,8 +168,8 @@ let combineShapesContinuousContinuous =
|
||||||
t1m.means[i],
|
t1m.means[i],
|
||||||
t2m.means[j],
|
t2m.means[j],
|
||||||
);
|
);
|
||||||
let _ = Belt.Array.set(means, k, mean);
|
Belt.Array.set(means, k, mean) |> ignore;
|
||||||
let _ = Belt.Array.set(variances, k, variance);
|
Belt.Array.set(variances, k, variance) |> ignore;
|
||||||
// update bounds
|
// update bounds
|
||||||
let minX = mean -. 2. *. sqrt(variance) *. 1.644854;
|
let minX = mean -. 2. *. sqrt(variance) *. 1.644854;
|
||||||
let maxX = mean +. 2. *. sqrt(variance) *. 1.644854;
|
let maxX = mean +. 2. *. sqrt(variance) *. 1.644854;
|
||||||
|
@ -194,15 +189,15 @@ let combineShapesContinuousContinuous =
|
||||||
let outputYs: array(float) = Belt.Array.make(nOut, 0.0);
|
let outputYs: array(float) = Belt.Array.make(nOut, 0.0);
|
||||||
// now, for each of the outputYs, accumulate from a Gaussian kernel over each input point.
|
// now, for each of the outputYs, accumulate from a Gaussian kernel over each input point.
|
||||||
for (j in 0 to E.A.length(masses) - 1) { // go through all of the result points
|
for (j in 0 to E.A.length(masses) - 1) { // go through all of the result points
|
||||||
let _ = if (variances[j] > 0. && masses[j] > 0.) {
|
if (variances[j] > 0. && masses[j] > 0.) {
|
||||||
for (i in 0 to E.A.length(outputXs) - 1) { // go through all of the target points
|
for (i in 0 to E.A.length(outputXs) - 1) { // go through all of the target points
|
||||||
let dx = outputXs[i] -. means[j];
|
let dx = outputXs[i] -. means[j];
|
||||||
let contribution = masses[j] *. exp(-. (dx ** 2.) /. (2. *. variances[j])) /. (sqrt(2. *. 3.14159276 *. variances[j]));
|
let contribution = masses[j] *. exp(-. (dx ** 2.) /. (2. *. variances[j])) /. (sqrt(2. *. 3.14159276 *. variances[j]));
|
||||||
let _ = Belt.Array.set(outputYs, i, outputYs[i] +. contribution);
|
Belt.Array.set(outputYs, i, outputYs[i] +. contribution) |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
();
|
();
|
||||||
};
|
} |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -219,26 +214,23 @@ let toDiscretePointMassesFromDiscrete = (s: DistTypes.xyShape): pointMassesWithM
|
||||||
let variances: array(float) = Belt.Array.makeUninitializedUnsafe(n);
|
let variances: array(float) = Belt.Array.makeUninitializedUnsafe(n);
|
||||||
|
|
||||||
for (i in 0 to n - 1) {
|
for (i in 0 to n - 1) {
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
masses,
|
||||||
masses,
|
i,
|
||||||
i,
|
ys[i]
|
||||||
ys[i]
|
) |> ignore;
|
||||||
);
|
|
||||||
|
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
means,
|
||||||
means,
|
i,
|
||||||
i,
|
xs[i]
|
||||||
xs[i]
|
) |> ignore;
|
||||||
);
|
|
||||||
|
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
variances,
|
||||||
variances,
|
i,
|
||||||
i,
|
0.0
|
||||||
0.0
|
) |> ignore;
|
||||||
);
|
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -246,11 +238,11 @@ let toDiscretePointMassesFromDiscrete = (s: DistTypes.xyShape): pointMassesWithM
|
||||||
};
|
};
|
||||||
|
|
||||||
let combineShapesContinuousDiscrete =
|
let combineShapesContinuousDiscrete =
|
||||||
(op: ExpressionTypes.algebraicOperation, s1: DistTypes.xyShape, s2: DistTypes.xyShape)
|
(op: ExpressionTypes.algebraicOperation, continuousShape: DistTypes.xyShape, discreteShape: DistTypes.xyShape)
|
||||||
: array(DistTypes.xyShape) => {
|
: DistTypes.xyShape => {
|
||||||
|
|
||||||
let t1n = s1 |> XYShape.T.length;
|
let t1n = continuousShape |> XYShape.T.length;
|
||||||
let t2n = s2 |> XYShape.T.length;
|
let t2n = discreteShape |> XYShape.T.length;
|
||||||
|
|
||||||
// each x pair is added/subtracted
|
// each x pair is added/subtracted
|
||||||
let fn = Operation.Algebraic.toFn(op);
|
let fn = Operation.Algebraic.toFn(op);
|
||||||
|
@ -262,46 +254,45 @@ let combineShapesContinuousDiscrete =
|
||||||
| `Add
|
| `Add
|
||||||
| `Subtract => {
|
| `Subtract => {
|
||||||
for (j in 0 to t2n - 1) {
|
for (j in 0 to t2n - 1) {
|
||||||
// for each one of the discrete points
|
// creates a new continuous shape for each one of the discrete points, and collects them in outXYShapes.
|
||||||
// create a new distribution, as long as the original continuous one
|
|
||||||
let dxyShape: array((float, float)) =
|
let dxyShape: array((float, float)) =
|
||||||
Belt.Array.makeUninitializedUnsafe(t1n);
|
Belt.Array.makeUninitializedUnsafe(t1n);
|
||||||
|
|
||||||
for (i in 0 to t1n - 1) {
|
for (i in 0 to t1n - 1) {
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
dxyShape,
|
||||||
dxyShape,
|
i,
|
||||||
i,
|
(fn(continuousShape.xs[i], discreteShape.xs[j]), continuousShape.ys[i] *. discreteShape.ys[j]),
|
||||||
(fn(s1.xs[i], s2.xs[j]), s1.ys[i] *. s2.ys[j]),
|
) |> ignore;
|
||||||
);
|
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
let _ = Belt.Array.set(outXYShapes, j, dxyShape);
|
Belt.Array.set(outXYShapes, j, dxyShape) |> ignore;
|
||||||
();
|
();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| `Multiply
|
| `Multiply
|
||||||
| `Divide => {
|
| `Divide => {
|
||||||
for (j in 0 to t2n - 1) {
|
for (j in 0 to t2n - 1) {
|
||||||
// for each one of the discrete points
|
// creates a new continuous shape for each one of the discrete points, and collects them in outXYShapes.
|
||||||
// create a new distribution, as long as the original continuous one
|
|
||||||
let dxyShape: array((float, float)) =
|
let dxyShape: array((float, float)) =
|
||||||
Belt.Array.makeUninitializedUnsafe(t1n);
|
Belt.Array.makeUninitializedUnsafe(t1n);
|
||||||
for (i in 0 to t1n - 1) {
|
for (i in 0 to t1n - 1) {
|
||||||
let _ =
|
Belt.Array.set(
|
||||||
Belt.Array.set(
|
dxyShape,
|
||||||
dxyShape,
|
i,
|
||||||
i,
|
(fn(continuousShape.xs[i], discreteShape.xs[j]), continuousShape.ys[i] *. discreteShape.ys[j] /. discreteShape.xs[j]),
|
||||||
(fn(s1.xs[i], s2.xs[j]), s1.ys[i] *. s2.ys[j] /. s2.xs[j]),
|
) |> ignore;
|
||||||
);
|
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
let _ = Belt.Array.set(outXYShapes, j, dxyShape);
|
Belt.Array.set(outXYShapes, j, dxyShape) |> ignore;
|
||||||
();
|
();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
outXYShapes
|
outXYShapes
|
||||||
|> E.A.fmap(XYShape.T.fromZippedArray);
|
|> E.A.fmap(XYShape.T.fromZippedArray)
|
||||||
|
|> E.A.fold_left(
|
||||||
|
XYShape.PointwiseCombination.combine((+.),
|
||||||
|
XYShape.XtoY.continuousInterpolator(`Linear, `UseZero)),
|
||||||
|
XYShape.T.empty);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ open Distributions;
|
||||||
type t = DistTypes.continuousShape;
|
type t = DistTypes.continuousShape;
|
||||||
let getShape = (t: t) => t.xyShape;
|
let getShape = (t: t) => t.xyShape;
|
||||||
let interpolation = (t: t) => t.interpolation;
|
let interpolation = (t: t) => t.interpolation;
|
||||||
let make = (interpolation, xyShape, integralSumCache, integralCache): t => {
|
let make = (~interpolation=`Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => {
|
||||||
xyShape,
|
xyShape,
|
||||||
interpolation,
|
interpolation,
|
||||||
integralSumCache,
|
integralSumCache,
|
||||||
|
@ -19,7 +19,7 @@ let lastY = (t: t) => t |> getShape |> XYShape.T.lastY;
|
||||||
let oShapeMap =
|
let oShapeMap =
|
||||||
(fn, {xyShape, interpolation, integralSumCache, integralCache}: t)
|
(fn, {xyShape, interpolation, integralSumCache, integralCache}: t)
|
||||||
: option(DistTypes.continuousShape) =>
|
: option(DistTypes.continuousShape) =>
|
||||||
fn(xyShape) |> E.O.fmap(make(interpolation, _, integralSumCache, integralCache));
|
fn(xyShape) |> E.O.fmap(make(~interpolation, ~integralSumCache, ~integralCache));
|
||||||
|
|
||||||
let emptyIntegral: DistTypes.continuousShape = {
|
let emptyIntegral: DistTypes.continuousShape = {
|
||||||
xyShape: {xs: [|neg_infinity|], ys: [|0.0|]},
|
xyShape: {xs: [|neg_infinity|], ys: [|0.0|]},
|
||||||
|
@ -35,7 +35,7 @@ let empty: DistTypes.continuousShape = {
|
||||||
};
|
};
|
||||||
|
|
||||||
let stepwiseToLinear = (t: t): t =>
|
let stepwiseToLinear = (t: t): t =>
|
||||||
make(`Linear, XYShape.Range.stepwiseToLinear(t.xyShape), t.integralSumCache, t.integralCache);
|
make(~integralSumCache=t.integralSumCache, ~integralCache=t.integralCache, XYShape.Range.stepwiseToLinear(t.xyShape));
|
||||||
|
|
||||||
let combinePointwise =
|
let combinePointwise =
|
||||||
(
|
(
|
||||||
|
@ -71,16 +71,13 @@ let combinePointwise =
|
||||||
let interpolator = XYShape.XtoY.continuousInterpolator(t1.interpolation, extrapolation);
|
let interpolator = XYShape.XtoY.continuousInterpolator(t1.interpolation, extrapolation);
|
||||||
|
|
||||||
make(
|
make(
|
||||||
`Linear,
|
~integralSumCache=combinedIntegralSum,
|
||||||
XYShape.PointwiseCombination.combine(
|
XYShape.PointwiseCombination.combine(
|
||||||
(+.),
|
(+.),
|
||||||
interpolator,
|
interpolator,
|
||||||
interpolator,
|
|
||||||
t1.xyShape,
|
t1.xyShape,
|
||||||
t2.xyShape,
|
t2.xyShape,
|
||||||
),
|
),
|
||||||
combinedIntegralSum,
|
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +86,7 @@ let toLinear = (t: t): option(t) => {
|
||||||
| {interpolation: `Stepwise, xyShape, integralSumCache, integralCache} =>
|
| {interpolation: `Stepwise, xyShape, integralSumCache, integralCache} =>
|
||||||
xyShape
|
xyShape
|
||||||
|> XYShape.Range.stepsToContinuous
|
|> XYShape.Range.stepsToContinuous
|
||||||
|> E.O.fmap(make(`Linear, _, integralSumCache, integralCache))
|
|> E.O.fmap(make(~integralSumCache, ~integralCache))
|
||||||
| {interpolation: `Linear} => Some(t)
|
| {interpolation: `Linear} => Some(t)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -117,13 +114,13 @@ let reduce =
|
||||||
|
|
||||||
let mapY = (~integralSumCacheFn=_ => None,
|
let mapY = (~integralSumCacheFn=_ => None,
|
||||||
~integralCacheFn=_ => None,
|
~integralCacheFn=_ => None,
|
||||||
fn, t: t) => {
|
~fn, t: t) => {
|
||||||
let yMapFn = shapeMap(XYShape.T.mapY(fn));
|
make(
|
||||||
|
~interpolation=t.interpolation,
|
||||||
t
|
~integralSumCache=t.integralSumCache |> E.O.bind(_, integralSumCacheFn),
|
||||||
|> yMapFn
|
~integralCache=t.integralCache |> E.O.bind(_, integralCacheFn),
|
||||||
|> updateIntegralSumCache(E.O.bind(t.integralSumCache, integralSumCacheFn))
|
t |> getShape |> XYShape.T.mapY(fn),
|
||||||
|> updateIntegralCache(E.O.bind(t.integralCache, integralCacheFn));
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let rec scaleBy = (~scale=1.0, t: t): t => {
|
let rec scaleBy = (~scale=1.0, t: t): t => {
|
||||||
|
@ -131,7 +128,7 @@ let rec scaleBy = (~scale=1.0, t: t): t => {
|
||||||
let scaledIntegralCache = E.O.bind(t.integralCache, v => Some(scaleBy(~scale, v)));
|
let scaledIntegralCache = E.O.bind(t.integralCache, v => Some(scaleBy(~scale, v)));
|
||||||
|
|
||||||
t
|
t
|
||||||
|> mapY((r: float) => r *. scale)
|
|> mapY(~fn=(r: float) => r *. scale)
|
||||||
|> updateIntegralSumCache(scaledIntegralSumCache)
|
|> updateIntegralSumCache(scaledIntegralSumCache)
|
||||||
|> updateIntegralCache(scaledIntegralCache)
|
|> updateIntegralCache(scaledIntegralCache)
|
||||||
};
|
};
|
||||||
|
@ -177,24 +174,20 @@ module T =
|
||||||
let truncatedShape =
|
let truncatedShape =
|
||||||
XYShape.T.fromZippedArray(truncatedZippedPairsWithNewPoints);
|
XYShape.T.fromZippedArray(truncatedZippedPairsWithNewPoints);
|
||||||
|
|
||||||
make(`Linear, truncatedShape, None, None);
|
make(truncatedShape)
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: This should work with stepwise plots.
|
// TODO: This should work with stepwise plots.
|
||||||
let integral = (t) => {
|
let integral = (t) =>
|
||||||
if (t |> getShape |> XYShape.T.isEmpty) {
|
switch (getShape(t) |> XYShape.T.isEmpty, t.integralCache) {
|
||||||
make(`Linear, {xs: [|neg_infinity|], ys: [|0.0|]}, None, None);
|
| (true, _) => emptyIntegral
|
||||||
} else {
|
| (false, Some(cache)) => cache
|
||||||
switch (t.integralCache) {
|
| (false, None) =>
|
||||||
| Some(cache) => cache
|
t
|
||||||
| None =>
|
|> getShape
|
||||||
t
|
|> XYShape.Range.integrateWithTriangles
|
||||||
|> getShape
|
|> E.O.toExt("This should not have happened")
|
||||||
|> XYShape.Range.integrateWithTriangles
|
|> make
|
||||||
|> E.O.toExt("This should not have happened")
|
|
||||||
|> make(`Linear, _, None, None)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let downsample = (length, t): t =>
|
let downsample = (length, t): t =>
|
||||||
|
@ -249,23 +242,17 @@ let combineAlgebraicallyWithDiscrete =
|
||||||
t2: DistTypes.discreteShape,
|
t2: DistTypes.discreteShape,
|
||||||
) => {
|
) => {
|
||||||
let t1s = t1 |> getShape;
|
let t1s = t1 |> getShape;
|
||||||
let t2s = t2.xyShape; // would like to use Discrete.getShape here, but current file structure doesn't allow for that
|
let t2s = t2.xyShape; // TODO would like to use Discrete.getShape here, but current file structure doesn't allow for that
|
||||||
|
|
||||||
if (XYShape.T.isEmpty(t1s) || XYShape.T.isEmpty(t2s)) {
|
if (XYShape.T.isEmpty(t1s) || XYShape.T.isEmpty(t2s)) {
|
||||||
empty;
|
empty;
|
||||||
} else {
|
} else {
|
||||||
let shapeArray = AlgebraicShapeCombination.combineShapesContinuousDiscrete(op, t1s, t2s);
|
let continuousAsLinear = switch (t1.interpolation) {
|
||||||
|
| `Linear => t1;
|
||||||
|
| `Stepwise => stepwiseToLinear(t1)
|
||||||
|
};
|
||||||
|
|
||||||
let t1Interpolator = XYShape.XtoY.continuousInterpolator(t1.interpolation, `UseZero);
|
let combinedShape = AlgebraicShapeCombination.combineShapesContinuousDiscrete(op, continuousAsLinear |> getShape, t2s);
|
||||||
let t2Interpolator = XYShape.XtoY.discreteInterpolator;
|
|
||||||
|
|
||||||
let combinedShape =
|
|
||||||
shapeArray
|
|
||||||
|> E.A.fold_left(
|
|
||||||
XYShape.PointwiseCombination.combine((+.),
|
|
||||||
t1Interpolator,
|
|
||||||
t2Interpolator),
|
|
||||||
XYShape.T.empty);
|
|
||||||
|
|
||||||
let combinedIntegralSum =
|
let combinedIntegralSum =
|
||||||
Common.combineIntegralSums(
|
Common.combineIntegralSums(
|
||||||
|
@ -275,7 +262,7 @@ let combineAlgebraicallyWithDiscrete =
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: It could make sense to automatically transform the integrals here (shift or scale)
|
// TODO: It could make sense to automatically transform the integrals here (shift or scale)
|
||||||
make(t1.interpolation, combinedShape, combinedIntegralSum, None)
|
make(~interpolation=t1.interpolation, ~integralSumCache=combinedIntegralSum, combinedShape)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -297,6 +284,6 @@ let combineAlgebraically =
|
||||||
t2.integralSumCache,
|
t2.integralSumCache,
|
||||||
);
|
);
|
||||||
// return a new Continuous distribution
|
// return a new Continuous distribution
|
||||||
make(`Linear, combinedShape, combinedIntegralSum, None);
|
make(~integralSumCache=combinedIntegralSum, combinedShape);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ open Distributions;
|
||||||
|
|
||||||
type t = DistTypes.discreteShape;
|
type t = DistTypes.discreteShape;
|
||||||
|
|
||||||
let make = (xyShape, integralSumCache, integralCache): t => {xyShape, integralSumCache, integralCache};
|
let make = (~integralSumCache=None, ~integralCache=None, xyShape): t => {xyShape, integralSumCache, integralCache};
|
||||||
let shapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): t => {
|
let shapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): t => {
|
||||||
xyShape: fn(xyShape),
|
xyShape: fn(xyShape),
|
||||||
integralSumCache,
|
integralSumCache,
|
||||||
|
@ -10,9 +10,21 @@ let shapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): t => {
|
||||||
};
|
};
|
||||||
let getShape = (t: t) => t.xyShape;
|
let getShape = (t: t) => t.xyShape;
|
||||||
let oShapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): option(t) =>
|
let oShapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): option(t) =>
|
||||||
fn(xyShape) |> E.O.fmap(make(_, integralSumCache, integralCache));
|
fn(xyShape) |> E.O.fmap(make(~integralSumCache, ~integralCache));
|
||||||
|
|
||||||
|
let emptyIntegral: DistTypes.continuousShape = {
|
||||||
|
xyShape: {xs: [|neg_infinity|], ys: [|0.0|]},
|
||||||
|
interpolation: `Stepwise,
|
||||||
|
integralSumCache: Some(0.0),
|
||||||
|
integralCache: None,
|
||||||
|
};
|
||||||
|
let empty: DistTypes.discreteShape = {
|
||||||
|
xyShape: XYShape.T.empty,
|
||||||
|
integralSumCache: Some(0.0),
|
||||||
|
integralCache: Some(emptyIntegral),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
let empty: t = {xyShape: XYShape.T.empty, integralSumCache: Some(0.0), integralCache: None};
|
|
||||||
let shapeFn = (fn, t: t) => t |> getShape |> fn;
|
let shapeFn = (fn, t: t) => t |> getShape |> fn;
|
||||||
|
|
||||||
let lastY = (t: t) => t |> getShape |> XYShape.T.lastY;
|
let lastY = (t: t) => t |> getShape |> XYShape.T.lastY;
|
||||||
|
@ -37,15 +49,13 @@ let combinePointwise =
|
||||||
// It could be done for pointwise additions, but is that ever needed?
|
// It could be done for pointwise additions, but is that ever needed?
|
||||||
|
|
||||||
make(
|
make(
|
||||||
|
~integralSumCache=combinedIntegralSum,
|
||||||
XYShape.PointwiseCombination.combine(
|
XYShape.PointwiseCombination.combine(
|
||||||
(+.),
|
(+.),
|
||||||
XYShape.XtoY.discreteInterpolator,
|
XYShape.XtoY.discreteInterpolator,
|
||||||
XYShape.XtoY.discreteInterpolator,
|
|
||||||
t1.xyShape,
|
t1.xyShape,
|
||||||
t2.xyShape,
|
t2.xyShape,
|
||||||
),
|
),
|
||||||
combinedIntegralSum,
|
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,27 +110,26 @@ let combineAlgebraically =
|
||||||
|
|
||||||
let combinedShape = XYShape.T.fromZippedArray(rxys);
|
let combinedShape = XYShape.T.fromZippedArray(rxys);
|
||||||
|
|
||||||
make(combinedShape, combinedIntegralSum, None);
|
make(~integralSumCache=combinedIntegralSum, combinedShape);
|
||||||
};
|
};
|
||||||
|
|
||||||
let mapY = (~integralSumCacheFn=_ => None,
|
let mapY = (~integralSumCacheFn=_ => None,
|
||||||
~integralCacheFn=_ => None,
|
~integralCacheFn=_ => None,
|
||||||
fn, t: t) => {
|
~fn, t: t) => {
|
||||||
let yMapFn = shapeMap(XYShape.T.mapY(fn));
|
make(
|
||||||
|
~integralSumCache=t.integralSumCache |> E.O.bind(_, integralSumCacheFn),
|
||||||
t
|
~integralCache=t.integralCache |> E.O.bind(_, integralCacheFn),
|
||||||
|> yMapFn
|
t |> getShape |> XYShape.T.mapY(fn),
|
||||||
|> updateIntegralSumCache(E.O.bind(t.integralSumCache, integralSumCacheFn))
|
);
|
||||||
|> updateIntegralCache(E.O.bind(t.integralCache, integralCacheFn));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let scaleBy = (~scale=1.0, t: t): t => {
|
let scaleBy = (~scale=1.0, t: t): t => {
|
||||||
let scaledIntegralSumCache = E.O.bind(t.integralSumCache, v => Some(scale *. v));
|
let scaledIntegralSumCache = t.integralSumCache |> E.O.fmap((*.)(scale));
|
||||||
let scaledIntegralCache = E.O.bind(t.integralCache, v => Some(Continuous.scaleBy(~scale, v)));
|
let scaledIntegralCache = t.integralCache |> E.O.fmap(Continuous.scaleBy(~scale));
|
||||||
|
|
||||||
t
|
t
|
||||||
|> mapY((r: float) => r *. scale)
|
|> mapY(~fn=(r: float) => r *. scale)
|
||||||
|> updateIntegralSumCache(scaledIntegralSumCache)
|
|> updateIntegralSumCache(scaledIntegralSumCache)
|
||||||
|> updateIntegralCache(scaledIntegralCache)
|
|> updateIntegralCache(scaledIntegralCache)
|
||||||
};
|
};
|
||||||
|
@ -130,29 +139,21 @@ module T =
|
||||||
type t = DistTypes.discreteShape;
|
type t = DistTypes.discreteShape;
|
||||||
type integral = DistTypes.continuousShape;
|
type integral = DistTypes.continuousShape;
|
||||||
let integral = (t) =>
|
let integral = (t) =>
|
||||||
if (t |> getShape |> XYShape.T.isEmpty) {
|
switch (getShape(t) |> XYShape.T.isEmpty, t.integralCache) {
|
||||||
Continuous.make(
|
| (true, _) => emptyIntegral
|
||||||
`Stepwise,
|
| (false, Some(c)) => c
|
||||||
{xs: [|neg_infinity|], ys: [|0.0|]},
|
| (false, None) => {
|
||||||
None,
|
let ts = getShape(t);
|
||||||
None,
|
// The first xy of this integral should always be the zero, to ensure nice plotting
|
||||||
);
|
let firstX = ts |> XYShape.T.minX;
|
||||||
} else {
|
let prependedZeroPoint: XYShape.T.t = {xs: [|firstX -. epsilon_float|], ys: [|0.|]};
|
||||||
switch (t.integralCache) {
|
let integralShape =
|
||||||
| Some(c) => c
|
ts
|
||||||
| None => {
|
|> XYShape.T.concat(prependedZeroPoint)
|
||||||
let ts = getShape(t);
|
|> XYShape.T.accumulateYs((+.));
|
||||||
// The first xy of this integral should always be the zero, to ensure nice plotting
|
|
||||||
let firstX = ts |> XYShape.T.minX;
|
|
||||||
let prependedZeroPoint: XYShape.T.t = {xs: [|firstX -. epsilon_float|], ys: [|0.|]};
|
|
||||||
let integralShape =
|
|
||||||
ts
|
|
||||||
|> XYShape.T.concat(prependedZeroPoint)
|
|
||||||
|> XYShape.T.accumulateYs((+.));
|
|
||||||
|
|
||||||
Continuous.make(`Stepwise, integralShape, None, None);
|
Continuous.make(~interpolation=`Stepwise, integralShape);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let integralEndY = (t: t) =>
|
let integralEndY = (t: t) =>
|
||||||
|
@ -179,17 +180,15 @@ module T =
|
||||||
let currentLength = t |> getShape |> XYShape.T.length;
|
let currentLength = t |> getShape |> XYShape.T.length;
|
||||||
|
|
||||||
if (i < currentLength && i >= 1 && currentLength > 1) {
|
if (i < currentLength && i >= 1 && currentLength > 1) {
|
||||||
let clippedShape =
|
t
|
||||||
t
|
|> getShape
|
||||||
|> getShape
|
|> XYShape.T.zip
|
||||||
|> XYShape.T.zip
|
|> XYShape.Zipped.sortByY
|
||||||
|> XYShape.Zipped.sortByY
|
|> Belt.Array.reverse
|
||||||
|> Belt.Array.reverse
|
|> Belt.Array.slice(_, ~offset=0, ~len=i)
|
||||||
|> Belt.Array.slice(_, ~offset=0, ~len=i)
|
|> XYShape.Zipped.sortByX
|
||||||
|> XYShape.Zipped.sortByX
|
|> XYShape.T.fromZippedArray
|
||||||
|> XYShape.T.fromZippedArray;
|
|> make;
|
||||||
|
|
||||||
make(clippedShape, None, None); // if someone needs the sum, they'll have to recompute it
|
|
||||||
} else {
|
} else {
|
||||||
t;
|
t;
|
||||||
};
|
};
|
||||||
|
@ -197,17 +196,15 @@ module T =
|
||||||
|
|
||||||
let truncate =
|
let truncate =
|
||||||
(leftCutoff: option(float), rightCutoff: option(float), t: t): t => {
|
(leftCutoff: option(float), rightCutoff: option(float), t: t): t => {
|
||||||
let truncatedShape =
|
t
|
||||||
t
|
|> getShape
|
||||||
|> getShape
|
|> XYShape.T.zip
|
||||||
|> XYShape.T.zip
|
|> XYShape.Zipped.filterByX(x =>
|
||||||
|> XYShape.Zipped.filterByX(x =>
|
x >= E.O.default(neg_infinity, leftCutoff)
|
||||||
x >= E.O.default(neg_infinity, leftCutoff)
|
&& x <= E.O.default(infinity, rightCutoff)
|
||||||
&& x <= E.O.default(infinity, rightCutoff)
|
)
|
||||||
)
|
|> XYShape.T.fromZippedArray
|
||||||
|> XYShape.T.fromZippedArray;
|
|> make;
|
||||||
|
|
||||||
make(truncatedShape, None, None);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let xToY = (f, t) =>
|
let xToY = (f, t) =>
|
||||||
|
|
|
@ -94,11 +94,11 @@ module T =
|
||||||
(
|
(
|
||||||
~integralSumCacheFn=previousIntegralSum => None,
|
~integralSumCacheFn=previousIntegralSum => None,
|
||||||
~integralCacheFn=previousIntegralCache => None,
|
~integralCacheFn=previousIntegralCache => None,
|
||||||
fn,
|
~fn,
|
||||||
{shape, _} as t: t,
|
{shape, _} as t: t,
|
||||||
)
|
)
|
||||||
: t =>
|
: t =>
|
||||||
Shape.T.mapY(~integralSumCacheFn, fn, shape)
|
Shape.T.mapY(~integralSumCacheFn, ~fn, shape)
|
||||||
|> updateShape(_, t);
|
|> updateShape(_, t);
|
||||||
|
|
||||||
// get the total of everything
|
// get the total of everything
|
||||||
|
|
|
@ -14,11 +14,11 @@ type xyShape = {
|
||||||
ys: array(float),
|
ys: array(float),
|
||||||
};
|
};
|
||||||
|
|
||||||
type interpolation = [
|
type interpolationStrategy = [
|
||||||
| `Stepwise
|
| `Stepwise
|
||||||
| `Linear
|
| `Linear
|
||||||
];
|
];
|
||||||
type extrapolation = [
|
type extrapolationStrategy = [
|
||||||
| `UseZero
|
| `UseZero
|
||||||
| `UseOutermostPoints
|
| `UseOutermostPoints
|
||||||
];
|
];
|
||||||
|
@ -27,14 +27,13 @@ type interpolator = (xyShape, int, float) => float;
|
||||||
|
|
||||||
type continuousShape = {
|
type continuousShape = {
|
||||||
xyShape,
|
xyShape,
|
||||||
interpolation: interpolation,
|
interpolation: interpolationStrategy,
|
||||||
integralSumCache: option(float),
|
integralSumCache: option(float),
|
||||||
integralCache: option(continuousShape),
|
integralCache: option(continuousShape),
|
||||||
};
|
};
|
||||||
|
|
||||||
type discreteShape = {
|
type discreteShape = {
|
||||||
xyShape,
|
xyShape,
|
||||||
/* interpolation is always `Discrete */
|
|
||||||
integralSumCache: option(float),
|
integralSumCache: option(float),
|
||||||
integralCache: option(continuousShape),
|
integralCache: option(continuousShape),
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ module type dist = {
|
||||||
let minX: t => float;
|
let minX: t => float;
|
||||||
let maxX: t => float;
|
let maxX: t => float;
|
||||||
let mapY:
|
let mapY:
|
||||||
(~integralSumCacheFn: float => option(float)=?, ~integralCacheFn: DistTypes.continuousShape => option(DistTypes.continuousShape)=?, float => float, t) => t;
|
(~integralSumCacheFn: float => option(float)=?, ~integralCacheFn: DistTypes.continuousShape => option(DistTypes.continuousShape)=?, ~fn: float => float, t) => t;
|
||||||
let xToY: (float, t) => DistTypes.mixedPoint;
|
let xToY: (float, t) => DistTypes.mixedPoint;
|
||||||
let toShape: t => DistTypes.shape;
|
let toShape: t => DistTypes.shape;
|
||||||
let toContinuous: t => option(DistTypes.continuousShape);
|
let toContinuous: t => option(DistTypes.continuousShape);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
open Distributions;
|
open Distributions;
|
||||||
|
|
||||||
type t = DistTypes.mixedShape;
|
type t = DistTypes.mixedShape;
|
||||||
let make = (~continuous, ~discrete, integralSumCache, integralCache): t => {continuous, discrete, integralSumCache, integralCache};
|
let make = (~integralSumCache=None, ~integralCache=None, ~continuous, ~discrete): t => {continuous, discrete, integralSumCache, integralCache};
|
||||||
|
|
||||||
let totalLength = (t: t): int => {
|
let totalLength = (t: t): int => {
|
||||||
let continuousLength =
|
let continuousLength =
|
||||||
|
@ -16,7 +16,7 @@ let scaleBy = (~scale=1.0, t: t): t => {
|
||||||
let scaledContinuous = Continuous.scaleBy(~scale, t.continuous);
|
let scaledContinuous = Continuous.scaleBy(~scale, t.continuous);
|
||||||
let scaledIntegralCache = E.O.bind(t.integralCache, v => Some(Continuous.scaleBy(~scale, v)));
|
let scaledIntegralCache = E.O.bind(t.integralCache, v => Some(Continuous.scaleBy(~scale, v)));
|
||||||
let scaledIntegralSumCache = E.O.bind(t.integralSumCache, s => Some(s *. scale));
|
let scaledIntegralSumCache = E.O.bind(t.integralSumCache, s => Some(s *. scale));
|
||||||
make(~discrete=scaledDiscrete, ~continuous=scaledContinuous, scaledIntegralSumCache, scaledIntegralCache);
|
make(~discrete=scaledDiscrete, ~continuous=scaledContinuous, ~integralSumCache=scaledIntegralSumCache, ~integralCache=scaledIntegralCache);
|
||||||
};
|
};
|
||||||
|
|
||||||
let toContinuous = ({continuous}: t) => Some(continuous);
|
let toContinuous = ({continuous}: t) => Some(continuous);
|
||||||
|
@ -54,7 +54,7 @@ module T =
|
||||||
let truncatedDiscrete =
|
let truncatedDiscrete =
|
||||||
Discrete.T.truncate(leftCutoff, rightCutoff, discrete);
|
Discrete.T.truncate(leftCutoff, rightCutoff, discrete);
|
||||||
|
|
||||||
make(~discrete=truncatedDiscrete, ~continuous=truncatedContinuous, None, None);
|
make(~integralSumCache=None, ~integralCache=None, ~discrete=truncatedDiscrete, ~continuous=truncatedContinuous);
|
||||||
};
|
};
|
||||||
|
|
||||||
let normalize = (t: t): t => {
|
let normalize = (t: t): t => {
|
||||||
|
@ -82,7 +82,7 @@ module T =
|
||||||
|> Discrete.scaleBy(~scale=newDiscreteSum /. discreteIntegralSum)
|
|> Discrete.scaleBy(~scale=newDiscreteSum /. discreteIntegralSum)
|
||||||
|> Discrete.updateIntegralSumCache(Some(newDiscreteSum));
|
|> Discrete.updateIntegralSumCache(Some(newDiscreteSum));
|
||||||
|
|
||||||
make(~continuous=normalizedContinuous, ~discrete=normalizedDiscrete, Some(1.0), None);
|
make(~integralSumCache=Some(1.0), ~integralCache=None, ~continuous=normalizedContinuous, ~discrete=normalizedDiscrete);
|
||||||
};
|
};
|
||||||
|
|
||||||
let xToY = (x, t: t) => {
|
let xToY = (x, t: t) => {
|
||||||
|
@ -144,16 +144,12 @@ module T =
|
||||||
let discreteIntegral = Continuous.stepwiseToLinear(Discrete.T.Integral.get(t.discrete));
|
let discreteIntegral = Continuous.stepwiseToLinear(Discrete.T.Integral.get(t.discrete));
|
||||||
|
|
||||||
Continuous.make(
|
Continuous.make(
|
||||||
`Linear,
|
|
||||||
XYShape.PointwiseCombination.combine(
|
XYShape.PointwiseCombination.combine(
|
||||||
(+.),
|
(+.),
|
||||||
XYShape.XtoY.continuousInterpolator(`Linear, `UseOutermostPoints),
|
XYShape.XtoY.continuousInterpolator(`Linear, `UseOutermostPoints),
|
||||||
XYShape.XtoY.continuousInterpolator(`Linear, `UseOutermostPoints),
|
|
||||||
Continuous.getShape(continuousIntegral),
|
Continuous.getShape(continuousIntegral),
|
||||||
Continuous.getShape(discreteIntegral),
|
Continuous.getShape(discreteIntegral),
|
||||||
),
|
),
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -177,19 +173,19 @@ module T =
|
||||||
(
|
(
|
||||||
~integralSumCacheFn=previousIntegralSum => None,
|
~integralSumCacheFn=previousIntegralSum => None,
|
||||||
~integralCacheFn=previousIntegral => None,
|
~integralCacheFn=previousIntegral => None,
|
||||||
fn,
|
~fn,
|
||||||
t: t,
|
t: t,
|
||||||
)
|
)
|
||||||
: t => {
|
: t => {
|
||||||
let yMappedDiscrete: DistTypes.discreteShape =
|
let yMappedDiscrete: DistTypes.discreteShape =
|
||||||
t.discrete
|
t.discrete
|
||||||
|> Discrete.T.mapY(fn)
|
|> Discrete.T.mapY(~fn)
|
||||||
|> Discrete.updateIntegralSumCache(E.O.bind(t.discrete.integralSumCache, integralSumCacheFn))
|
|> Discrete.updateIntegralSumCache(E.O.bind(t.discrete.integralSumCache, integralSumCacheFn))
|
||||||
|> Discrete.updateIntegralCache(E.O.bind(t.discrete.integralCache, integralCacheFn));
|
|> Discrete.updateIntegralCache(E.O.bind(t.discrete.integralCache, integralCacheFn));
|
||||||
|
|
||||||
let yMappedContinuous: DistTypes.continuousShape =
|
let yMappedContinuous: DistTypes.continuousShape =
|
||||||
t.continuous
|
t.continuous
|
||||||
|> Continuous.T.mapY(fn)
|
|> Continuous.T.mapY(~fn)
|
||||||
|> Continuous.updateIntegralSumCache(E.O.bind(t.continuous.integralSumCache, integralSumCacheFn))
|
|> Continuous.updateIntegralSumCache(E.O.bind(t.continuous.integralSumCache, integralSumCacheFn))
|
||||||
|> Continuous.updateIntegralCache(E.O.bind(t.continuous.integralCache, integralCacheFn));
|
|> Continuous.updateIntegralCache(E.O.bind(t.continuous.integralCache, integralCacheFn));
|
||||||
|
|
||||||
|
@ -332,5 +328,5 @@ let combinePointwise = (~integralSumCachesFn = (_, _) => None, ~integralCachesFn
|
||||||
t2.integralCache,
|
t2.integralCache,
|
||||||
);
|
);
|
||||||
|
|
||||||
make(~discrete=reducedDiscrete, ~continuous=reducedContinuous, combinedIntegralSum, combinedIntegral);
|
make(~integralSumCache=combinedIntegralSum, ~integralCache=combinedIntegral, ~discrete=reducedDiscrete, ~continuous=reducedContinuous);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,8 +9,8 @@ type assumptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
let buildSimple = (~continuous: option(DistTypes.continuousShape), ~discrete: option(DistTypes.discreteShape)): option(DistTypes.shape) => {
|
let buildSimple = (~continuous: option(DistTypes.continuousShape), ~discrete: option(DistTypes.discreteShape)): option(DistTypes.shape) => {
|
||||||
let continuous = continuous |> E.O.default(Continuous.make(`Linear, {xs: [||], ys: [||]}, Some(0.0), None));
|
let continuous = continuous |> E.O.default(Continuous.make(~integralSumCache=Some(0.0), {xs: [||], ys: [||]}));
|
||||||
let discrete = discrete |> E.O.default(Discrete.make({xs: [||], ys: [||]}, Some(0.0), None));
|
let discrete = discrete |> E.O.default(Discrete.make(~integralSumCache=Some(0.0), {xs: [||], ys: [||]}));
|
||||||
let cLength =
|
let cLength =
|
||||||
continuous
|
continuous
|
||||||
|> Continuous.getShape
|
|> Continuous.getShape
|
||||||
|
@ -24,10 +24,10 @@ let buildSimple = (~continuous: option(DistTypes.continuousShape), ~discrete: op
|
||||||
| (_, _) =>
|
| (_, _) =>
|
||||||
let mixedDist =
|
let mixedDist =
|
||||||
Mixed.make(
|
Mixed.make(
|
||||||
|
~integralSumCache=None,
|
||||||
|
~integralCache=None,
|
||||||
~continuous,
|
~continuous,
|
||||||
~discrete,
|
~discrete,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
Some(Mixed(mixedDist));
|
Some(Mixed(mixedDist));
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,8 +19,8 @@ let fmap = ((fn1, fn2, fn3), t: t): t =>
|
||||||
let toMixed =
|
let toMixed =
|
||||||
mapToAll((
|
mapToAll((
|
||||||
m => m,
|
m => m,
|
||||||
d => Mixed.make(~discrete=d, ~continuous=Continuous.empty, d.integralSumCache, d.integralCache),
|
d => Mixed.make(~integralSumCache=d.integralSumCache, ~integralCache=d.integralCache, ~discrete=d, ~continuous=Continuous.empty),
|
||||||
c => Mixed.make(~discrete=Discrete.empty, ~continuous=c, c.integralSumCache, c.integralCache),
|
c => Mixed.make(~integralSumCache=c.integralSumCache, ~integralCache=c.integralCache, ~discrete=Discrete.empty, ~continuous=c),
|
||||||
));
|
));
|
||||||
|
|
||||||
let combineAlgebraically =
|
let combineAlgebraically =
|
||||||
|
@ -176,11 +176,11 @@ module T =
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let maxX = mapToAll((Mixed.T.maxX, Discrete.T.maxX, Continuous.T.maxX));
|
let maxX = mapToAll((Mixed.T.maxX, Discrete.T.maxX, Continuous.T.maxX));
|
||||||
let mapY = (~integralSumCacheFn=previousIntegralSum => None, ~integralCacheFn=previousIntegral=>None, fn) =>
|
let mapY = (~integralSumCacheFn=previousIntegralSum => None, ~integralCacheFn=previousIntegral=>None, ~fn) =>
|
||||||
fmap((
|
fmap((
|
||||||
Mixed.T.mapY(~integralSumCacheFn, ~integralCacheFn, fn),
|
Mixed.T.mapY(~integralSumCacheFn, ~integralCacheFn, ~fn),
|
||||||
Discrete.T.mapY(~integralSumCacheFn, ~integralCacheFn, fn),
|
Discrete.T.mapY(~integralSumCacheFn, ~integralCacheFn, ~fn),
|
||||||
Continuous.T.mapY(~integralSumCacheFn, ~integralCacheFn, fn),
|
Continuous.T.mapY(~integralSumCacheFn, ~integralCacheFn, ~fn),
|
||||||
));
|
));
|
||||||
|
|
||||||
let mean = (t: t): float =>
|
let mean = (t: t): float =>
|
||||||
|
|
|
@ -146,56 +146,52 @@ module XtoY = {
|
||||||
|
|
||||||
/* Returns a between-points-interpolating function that can be used with PointwiseCombination.combine.
|
/* Returns a between-points-interpolating function that can be used with PointwiseCombination.combine.
|
||||||
Interpolation can either be stepwise (using the value on the left) or linear. Extrapolation can be `UseZero or `UseOutermostPoints. */
|
Interpolation can either be stepwise (using the value on the left) or linear. Extrapolation can be `UseZero or `UseOutermostPoints. */
|
||||||
let continuousInterpolator = (interpolation: DistTypes.interpolation, extrapolation: DistTypes.extrapolation): interpolator => {
|
let continuousInterpolator = (interpolation: DistTypes.interpolationStrategy, extrapolation: DistTypes.extrapolationStrategy): interpolator => {
|
||||||
switch (interpolation) {
|
switch (interpolation, extrapolation) {
|
||||||
| `Linear => switch (extrapolation) {
|
| (`Linear, `UseZero) => (t: T.t, leftIndex: int, x: float) => {
|
||||||
| `UseZero => (t: T.t, leftIndex: int, x: float) => {
|
if (leftIndex < 0) {
|
||||||
if (leftIndex < 0) {
|
0.0
|
||||||
0.0
|
} else if (leftIndex >= T.length(t) - 1) {
|
||||||
} else if (leftIndex >= T.length(t) - 1) {
|
0.0
|
||||||
0.0
|
} else {
|
||||||
} else {
|
let x1 = t.xs[leftIndex];
|
||||||
let x1 = t.xs[leftIndex];
|
let x2 = t.xs[leftIndex + 1];
|
||||||
let x2 = t.xs[leftIndex + 1];
|
let y1 = t.ys[leftIndex];
|
||||||
let y1 = t.ys[leftIndex];
|
let y2 = t.ys[leftIndex + 1];
|
||||||
let y2 = t.ys[leftIndex + 1];
|
let fraction = (x -. x1) /. (x2 -. x1);
|
||||||
let fraction = (x -. x1) /. (x2 -. x1);
|
y1 *. (1. -. fraction) +. y2 *. fraction;
|
||||||
y1 *. (1. -. fraction) +. y2 *. fraction;
|
};
|
||||||
};
|
}
|
||||||
}
|
| (`Linear, `UseOutermostPoints) => (t: T.t, leftIndex: int, x: float) => {
|
||||||
| `UseOutermostPoints => (t: T.t, leftIndex: int, x: float) => {
|
if (leftIndex < 0) {
|
||||||
if (leftIndex < 0) {
|
t.ys[0];
|
||||||
t.ys[0];
|
} else if (leftIndex >= T.length(t) - 1) {
|
||||||
} else if (leftIndex >= T.length(t) - 1) {
|
t.ys[T.length(t) - 1]
|
||||||
T.lastY(t);
|
} else {
|
||||||
} else {
|
let x1 = t.xs[leftIndex];
|
||||||
let x1 = t.xs[leftIndex];
|
let x2 = t.xs[leftIndex + 1];
|
||||||
let x2 = t.xs[leftIndex + 1];
|
let y1 = t.ys[leftIndex];
|
||||||
let y1 = t.ys[leftIndex];
|
let y2 = t.ys[leftIndex + 1];
|
||||||
let y2 = t.ys[leftIndex + 1];
|
let fraction = (x -. x1) /. (x2 -. x1);
|
||||||
let fraction = (x -. x1) /. (x2 -. x1);
|
y1 *. (1. -. fraction) +. y2 *. fraction;
|
||||||
y1 *. (1. -. fraction) +. y2 *. fraction;
|
};
|
||||||
};
|
}
|
||||||
|
| (`Stepwise, `UseZero) => (t: T.t, leftIndex: int, x: float) => {
|
||||||
|
if (leftIndex < 0) {
|
||||||
|
0.0
|
||||||
|
} else if (leftIndex >= T.length(t) - 1) {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
t.ys[leftIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| `Stepwise => switch (extrapolation) {
|
| (`Stepwise, `UseOutermostPoints) => (t: T.t, leftIndex: int, x: float) => {
|
||||||
| `UseZero => (t: T.t, leftIndex: int, x: float) => {
|
if (leftIndex < 0) {
|
||||||
if (leftIndex < 0) {
|
t.ys[0];
|
||||||
0.0
|
} else if (leftIndex >= T.length(t) - 1) {
|
||||||
} else if (leftIndex >= T.length(t) - 1) {
|
t.ys[T.length(t) - 1]
|
||||||
0.0
|
} else {
|
||||||
} else {
|
t.ys[leftIndex];
|
||||||
t.ys[leftIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| `UseOutermostPoints => (t: T.t, leftIndex: int, x: float) => {
|
|
||||||
if (leftIndex < 0) {
|
|
||||||
t.ys[0];
|
|
||||||
} else if (leftIndex >= T.length(t) - 1) {
|
|
||||||
T.lastY(t);
|
|
||||||
} else {
|
|
||||||
t.ys[leftIndex];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +242,7 @@ module PointwiseCombination = {
|
||||||
// and interpolates the value on the other side, thus accumulating xs and ys.
|
// and interpolates the value on the other side, thus accumulating xs and ys.
|
||||||
// This is written in raw JS because this can still be a bottleneck, and using refs for the i and j indices is quite painful.
|
// This is written in raw JS because this can still be a bottleneck, and using refs for the i and j indices is quite painful.
|
||||||
|
|
||||||
function(fn, t1Interpolator, t2Interpolator, t1, t2) {
|
function(fn, interpolator, t1, t2) {
|
||||||
let t1n = t1.xs.length;
|
let t1n = t1.xs.length;
|
||||||
let t2n = t2.xs.length;
|
let t2n = t2.xs.length;
|
||||||
let outX = [];
|
let outX = [];
|
||||||
|
@ -263,7 +259,7 @@ module PointwiseCombination = {
|
||||||
x = t1.xs[i];
|
x = t1.xs[i];
|
||||||
ya = t1.ys[i];
|
ya = t1.ys[i];
|
||||||
|
|
||||||
yb = t2Interpolator(t2, j, x);
|
yb = interpolator(t2, j, x);
|
||||||
} else if (i == t1n - 1 && j < t2n - 1 ||
|
} else if (i == t1n - 1 && j < t2n - 1 ||
|
||||||
t1.xs[i+1] > t2.xs[j+1]) { // if b has to catch up to a, or if a is already done
|
t1.xs[i+1] > t2.xs[j+1]) { // if b has to catch up to a, or if a is already done
|
||||||
j++;
|
j++;
|
||||||
|
@ -271,7 +267,7 @@ module PointwiseCombination = {
|
||||||
x = t2.xs[j];
|
x = t2.xs[j];
|
||||||
yb = t2.ys[j];
|
yb = t2.ys[j];
|
||||||
|
|
||||||
ya = t1Interpolator(t1, i, x);
|
ya = interpolator(t1, i, x);
|
||||||
} else if (i < t1n - 1 && j < t2n && t1.xs[i+1] === t2.xs[j+1]) { // if they happen to be equal, move both ahead
|
} else if (i < t1n - 1 && j < t2n && t1.xs[i+1] === t2.xs[j+1]) { // if they happen to be equal, move both ahead
|
||||||
i++;
|
i++;
|
||||||
j++;
|
j++;
|
||||||
|
@ -384,16 +380,16 @@ module Range = {
|
||||||
let newXs: array(float) = Belt.Array.makeUninitializedUnsafe(2 * length);
|
let newXs: array(float) = Belt.Array.makeUninitializedUnsafe(2 * length);
|
||||||
let newYs: array(float) = Belt.Array.makeUninitializedUnsafe(2 * length);
|
let newYs: array(float) = Belt.Array.makeUninitializedUnsafe(2 * length);
|
||||||
|
|
||||||
let _ = Belt.Array.set(newXs, 0, xs[0] -. epsilon_float);
|
Belt.Array.set(newXs, 0, xs[0] -. epsilon_float) |> ignore;
|
||||||
let _ = Belt.Array.set(newYs, 0, 0.);
|
Belt.Array.set(newYs, 0, 0.) |> ignore;
|
||||||
let _ = Belt.Array.set(newXs, 1, xs[0]);
|
Belt.Array.set(newXs, 1, xs[0]) |> ignore;
|
||||||
let _ = Belt.Array.set(newYs, 1, ys[0]);
|
Belt.Array.set(newYs, 1, ys[0]) |> ignore;
|
||||||
|
|
||||||
for (i in 1 to E.A.length(xs) - 1) {
|
for (i in 1 to E.A.length(xs) - 1) {
|
||||||
let _ = Belt.Array.set(newXs, i * 2, xs[i] -. epsilon_float);
|
Belt.Array.set(newXs, i * 2, xs[i] -. epsilon_float) |> ignore;
|
||||||
let _ = Belt.Array.set(newYs, i * 2, ys[i-1]);
|
Belt.Array.set(newYs, i * 2, ys[i-1]) |> ignore;
|
||||||
let _ = Belt.Array.set(newXs, i * 2 + 1, xs[i]);
|
Belt.Array.set(newXs, i * 2 + 1, xs[i]) |> ignore;
|
||||||
let _ = Belt.Array.set(newYs, i * 2 + 1, ys[i]);
|
Belt.Array.set(newYs, i * 2 + 1, ys[i]) |> ignore;
|
||||||
();
|
();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ module VerticalScaling = {
|
||||||
Shape.T.mapY(
|
Shape.T.mapY(
|
||||||
~integralSumCacheFn=integralSumCacheFn(sm),
|
~integralSumCacheFn=integralSumCacheFn(sm),
|
||||||
~integralCacheFn=integralCacheFn(sm),
|
~integralCacheFn=integralCacheFn(sm),
|
||||||
fn(sm),
|
~fn=fn(sm),
|
||||||
rs,
|
rs,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -120,7 +120,7 @@ module T = {
|
||||||
|> E.FloatFloatMap.fmap(r => r /. length)
|
|> E.FloatFloatMap.fmap(r => r /. length)
|
||||||
|> E.FloatFloatMap.toArray
|
|> E.FloatFloatMap.toArray
|
||||||
|> XYShape.T.fromZippedArray
|
|> XYShape.T.fromZippedArray
|
||||||
|> Discrete.make(_, None, None);
|
|> Discrete.make;
|
||||||
|
|
||||||
let pdf =
|
let pdf =
|
||||||
continuousPart |> E.A.length > 5
|
continuousPart |> E.A.length > 5
|
||||||
|
@ -150,7 +150,7 @@ module T = {
|
||||||
~outputXYPoints=samplingInputs.outputXYPoints,
|
~outputXYPoints=samplingInputs.outputXYPoints,
|
||||||
formatUnitWidth(usedUnitWidth),
|
formatUnitWidth(usedUnitWidth),
|
||||||
)
|
)
|
||||||
|> Continuous.make(`Linear, _, None, None)
|
|> Continuous.make
|
||||||
|> (r => Some((r, foo)));
|
|> (r => Some((r, foo)));
|
||||||
}
|
}
|
||||||
: None;
|
: None;
|
||||||
|
|
|
@ -317,13 +317,13 @@ module T = {
|
||||||
switch (d) {
|
switch (d) {
|
||||||
| `Float(v) =>
|
| `Float(v) =>
|
||||||
Discrete(
|
Discrete(
|
||||||
Discrete.make({xs: [|v|], ys: [|1.0|]}, Some(1.0), None),
|
Discrete.make(~integralSumCache=Some(1.0), {xs: [|v|], ys: [|1.0|]}),
|
||||||
)
|
)
|
||||||
| _ =>
|
| _ =>
|
||||||
let xs = interpolateXs(~xSelection=`ByWeight, d, sampleCount);
|
let xs = interpolateXs(~xSelection=`ByWeight, d, sampleCount);
|
||||||
let ys = xs |> E.A.fmap(x => pdf(x, d));
|
let ys = xs |> E.A.fmap(x => pdf(x, d));
|
||||||
Continuous(
|
Continuous(
|
||||||
Continuous.make(`Linear, {xs, ys}, Some(1.0), None),
|
Continuous.make(~integralSumCache=Some(1.0), {xs, ys}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user