Improved mixed CDF function
This commit is contained in:
parent
d7f95df430
commit
3182067a48
|
@ -79,7 +79,10 @@ describe("Shape", () => {
|
||||||
make({xs: [|1., 4., 8.|], ys: [|0.1, 5., 1.0|]}, `Stepwise);
|
make({xs: [|1., 4., 8.|], ys: [|0.1, 5., 1.0|]}, `Stepwise);
|
||||||
continuous |> toLinear |> getShape;
|
continuous |> toLinear |> getShape;
|
||||||
},
|
},
|
||||||
{xs: [|1.0, 4.0, 4.0, 8.0, 8.0|], ys: [|0.1, 0.1, 5.0, 5.0, 1.0|]},
|
{
|
||||||
|
xs: [|1.00007, 4.0, 4.00007, 8.0, 8.00007|],
|
||||||
|
ys: [|0.1, 0.1, 5.0, 5.0, 1.0|],
|
||||||
|
},
|
||||||
);
|
);
|
||||||
makeTest(
|
makeTest(
|
||||||
"integralXToY",
|
"integralXToY",
|
||||||
|
@ -251,13 +254,20 @@ describe("Shape", () => {
|
||||||
T.Integral.get(~cache=None, mixed),
|
T.Integral.get(~cache=None, mixed),
|
||||||
Distributions.Continuous.make(
|
Distributions.Continuous.make(
|
||||||
{
|
{
|
||||||
xs: [|1., 3., 4., 4., 7., 8., 8., 14.|],
|
xs: [|1.00007, 3., 4., 4.00007, 7., 8., 8.00007, 14.|],
|
||||||
ys: [|0.15, 0.0, 0.15, 0.4, 0.13986013986013987, 0.4, 0.5, 0.5|],
|
ys: [|
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.18496503496503497,
|
||||||
|
0.4349674825174825,
|
||||||
|
0.5398601398601399,
|
||||||
|
0.5913086913086913,
|
||||||
|
0.6913122927072927,
|
||||||
|
1.0,
|
||||||
|
|],
|
||||||
},
|
},
|
||||||
`Linear,
|
`Linear,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// makeTest("integralXToY", T.Integral.xToY(~cache=None, 6.0, mixed), 0.9);
|
|
||||||
// makeTest("integralSum", T.Integral.sum(~cache=None, mixed), 1.0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -12,7 +12,11 @@ let distributions = () =>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<h2> {"Basic Mixed Distribution" |> ReasonReact.string} </h2>
|
<h2> {"Basic Mixed Distribution" |> ReasonReact.string} </h2>
|
||||||
{timeDist |> E.O.React.fmapOrNull(distPlus => <DistPlusPlot distPlus />)}
|
{timeDist
|
||||||
|
|> E.O.fmap(
|
||||||
|
Distributions.DistPlus.T.scaleToIntegralSum(~intendedSum=1.0),
|
||||||
|
)
|
||||||
|
|> E.O.React.fmapOrNull(distPlus => <DistPlusPlot distPlus />)}
|
||||||
<h2> {"Simple Continuous" |> ReasonReact.string} </h2>
|
<h2> {"Simple Continuous" |> ReasonReact.string} </h2>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -60,12 +60,6 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
||||||
() => {<IntegralChart distPlus onHover={r => {setX(_ => r)}} />},
|
() => {<IntegralChart distPlus onHover={r => {setX(_ => r)}} />},
|
||||||
[|distPlus|],
|
[|distPlus|],
|
||||||
);
|
);
|
||||||
Js.log4(
|
|
||||||
"distPlus",
|
|
||||||
x,
|
|
||||||
distPlus,
|
|
||||||
distPlus |> Distributions.DistPlus.T.xToY(x),
|
|
||||||
);
|
|
||||||
<div>
|
<div>
|
||||||
chart
|
chart
|
||||||
chart2
|
chart2
|
||||||
|
@ -93,14 +87,14 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
||||||
{distPlus
|
{distPlus
|
||||||
|> Distributions.DistPlus.T.xToY(x)
|
|> Distributions.DistPlus.T.xToY(x)
|
||||||
|> DistTypes.MixedPoint.toDiscreteValue
|
|> DistTypes.MixedPoint.toDiscreteValue
|
||||||
|> E.Float.with2DigitsPrecision
|
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|
||||||
|> ReasonReact.string}
|
|> ReasonReact.string}
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-2 border ">
|
<th className="px-4 py-2 border ">
|
||||||
{distPlus
|
{distPlus
|
||||||
|> Distributions.DistPlus.T.xToY(x)
|
|> Distributions.DistPlus.T.xToY(x)
|
||||||
|> DistTypes.MixedPoint.toContinuousValue
|
|> DistTypes.MixedPoint.toContinuousValue
|
||||||
|> E.Float.with2DigitsPrecision
|
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|
||||||
|> ReasonReact.string}
|
|> ReasonReact.string}
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-2 border ">
|
<th className="px-4 py-2 border ">
|
||||||
|
|
|
@ -101,7 +101,7 @@ module Continuous = {
|
||||||
switch (interpolation) {
|
switch (interpolation) {
|
||||||
| `Stepwise =>
|
| `Stepwise =>
|
||||||
xyShape
|
xyShape
|
||||||
|> XYShape.XtoY.stepwise(f)
|
|> XYShape.XtoY.stepwiseIncremental(f)
|
||||||
|> E.O.default(0.0)
|
|> E.O.default(0.0)
|
||||||
|> DistTypes.MixedPoint.makeContinuous
|
|> DistTypes.MixedPoint.makeContinuous
|
||||||
| `Linear =>
|
| `Linear =>
|
||||||
|
@ -109,6 +109,14 @@ module Continuous = {
|
||||||
|> XYShape.XtoY.linear(f)
|
|> XYShape.XtoY.linear(f)
|
||||||
|> DistTypes.MixedPoint.makeContinuous
|
|> DistTypes.MixedPoint.makeContinuous
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
let integral = (~cache, t) =>
|
let integral = (~cache, t) =>
|
||||||
cache
|
cache
|
||||||
|> E.O.default(
|
|> E.O.default(
|
||||||
|
@ -148,7 +156,7 @@ module Discrete = {
|
||||||
let toScaledDiscrete = t => Some(t);
|
let toScaledDiscrete = t => Some(t);
|
||||||
|
|
||||||
let xToY = (f, t) => {
|
let xToY = (f, t) => {
|
||||||
XYShape.XtoY.ifAtX(f, t)
|
XYShape.XtoY.stepwiseIfAtX(f, t)
|
||||||
|> E.O.default(0.0)
|
|> E.O.default(0.0)
|
||||||
|> DistTypes.MixedPoint.makeDiscrete;
|
|> DistTypes.MixedPoint.makeDiscrete;
|
||||||
};
|
};
|
||||||
|
@ -254,9 +262,11 @@ module Mixed = {
|
||||||
~scale=discreteProbabilityMassFraction,
|
~scale=discreteProbabilityMassFraction,
|
||||||
);
|
);
|
||||||
Continuous.make(
|
Continuous.make(
|
||||||
XYShape.combine(
|
XYShape.Combine.combineLinear(
|
||||||
Continuous.getShape(cont),
|
Continuous.getShape(cont),
|
||||||
Continuous.getShape(dist),
|
Continuous.getShape(dist),
|
||||||
|
(a, b) =>
|
||||||
|
a +. b
|
||||||
),
|
),
|
||||||
`Linear,
|
`Linear,
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,15 +5,21 @@ type t = xyShape;
|
||||||
let toJs = (t: t) => {
|
let toJs = (t: t) => {
|
||||||
{"xs": t.xs, "ys": t.ys};
|
{"xs": t.xs, "ys": t.ys};
|
||||||
};
|
};
|
||||||
let minX = (t: t) => t.xs |> E.A.first;
|
let xs = (t: t) => t.xs;
|
||||||
let maxX = (t: t) => t.xs |> E.A.last;
|
let minX = (t: t) => t |> xs |> E.A.first;
|
||||||
let first = (t: t) =>
|
let maxX = (t: t) => t |> xs |> E.A.last;
|
||||||
switch (t.xs |> E.A.first, t.ys |> E.A.first) {
|
let xTotalRange = (t: t) =>
|
||||||
|
switch (minX(t), maxX(t)) {
|
||||||
|
| (Some(min), Some(max)) => Some(max -. min)
|
||||||
|
| _ => None
|
||||||
|
};
|
||||||
|
let first = ({xs, ys}: t) =>
|
||||||
|
switch (xs |> E.A.first, ys |> E.A.first) {
|
||||||
| (Some(x), Some(y)) => Some((x, y))
|
| (Some(x), Some(y)) => Some((x, y))
|
||||||
| _ => None
|
| _ => None
|
||||||
};
|
};
|
||||||
let last = (t: t) =>
|
let last = ({xs, ys}: t) =>
|
||||||
switch (t.xs |> E.A.last, t.ys |> E.A.last) {
|
switch (xs |> E.A.last, ys |> E.A.last) {
|
||||||
| (Some(x), Some(y)) => Some((x, y))
|
| (Some(x), Some(y)) => Some((x, y))
|
||||||
| _ => None
|
| _ => None
|
||||||
};
|
};
|
||||||
|
@ -21,7 +27,7 @@ let last = (t: t) =>
|
||||||
let unsafeFirst = (t: t) => first(t) |> E.O.toExn("Unsafe operation");
|
let unsafeFirst = (t: t) => first(t) |> E.O.toExn("Unsafe operation");
|
||||||
let unsafeLast = (t: t) => last(t) |> E.O.toExn("Unsafe operation");
|
let unsafeLast = (t: t) => last(t) |> E.O.toExn("Unsafe operation");
|
||||||
|
|
||||||
let zip = t => Belt.Array.zip(t.xs, t.ys);
|
let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys);
|
||||||
let getBy = (t: t, fn) => t |> zip |> Belt.Array.getBy(_, fn);
|
let getBy = (t: t, fn) => t |> zip |> Belt.Array.getBy(_, fn);
|
||||||
|
|
||||||
let firstPairAtOrBeforeValue = (xValue, t: t) => {
|
let firstPairAtOrBeforeValue = (xValue, t: t) => {
|
||||||
|
@ -38,20 +44,64 @@ let firstPairAtOrBeforeValue = (xValue, t: t) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
module XtoY = {
|
module XtoY = {
|
||||||
let ifAtX = (f, t: t) =>
|
let stepwiseIncremental = (f, t: t) =>
|
||||||
getBy(t, ((x, _)) => x == f) |> E.O.fmap(((_, y)) => y);
|
|
||||||
|
|
||||||
let stepwise = (f, t: t) =>
|
|
||||||
firstPairAtOrBeforeValue(f, t) |> E.O.fmap(((_, y)) => y);
|
firstPairAtOrBeforeValue(f, t) |> E.O.fmap(((_, y)) => y);
|
||||||
|
|
||||||
|
let stepwiseIfAtX = (f, t: t) =>
|
||||||
|
getBy(t, ((x, _)) => x == f) |> E.O.fmap(((_, y)) => y);
|
||||||
|
|
||||||
// TODO: When Roman's PR comes in, fix this bit. This depends on interpolation, obviously.
|
// TODO: When Roman's PR comes in, fix this bit. This depends on interpolation, obviously.
|
||||||
let linear = (f, t: t) => t |> CdfLibrary.Distribution.findY(f);
|
let linear = (f, t: t) => t |> CdfLibrary.Distribution.findY(f);
|
||||||
};
|
};
|
||||||
|
|
||||||
let pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)};
|
let pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)};
|
||||||
|
let xMap = (fn, t: t): t => {xs: E.A.fmap(fn, t.xs), ys: t.ys};
|
||||||
let fromArray = ((xs, ys)): t => {xs, ys};
|
let fromArray = ((xs, ys)): t => {xs, ys};
|
||||||
let fromArrays = (xs, ys): t => {xs, ys};
|
let fromArrays = (xs, ys): t => {xs, ys};
|
||||||
|
|
||||||
|
module Combine = {
|
||||||
|
let combineLinear = (t1: t, t2: t, fn: (float, float) => float) => {
|
||||||
|
let allXs = Belt.Array.concat(xs(t1), xs(t2));
|
||||||
|
allXs |> Array.sort(compare);
|
||||||
|
let allYs =
|
||||||
|
allXs
|
||||||
|
|> E.A.fmap(x => {
|
||||||
|
let y1 = XtoY.linear(x, t1);
|
||||||
|
let y2 = XtoY.linear(x, t2);
|
||||||
|
fn(y1, y2);
|
||||||
|
});
|
||||||
|
fromArrays(allXs, allYs);
|
||||||
|
};
|
||||||
|
|
||||||
|
let combineStepwise =
|
||||||
|
(t1: t, t2: t, fn: (option(float), option(float)) => float) => {
|
||||||
|
let allXs = Belt.Array.concat(xs(t1), xs(t2));
|
||||||
|
allXs |> Array.sort(compare);
|
||||||
|
let allYs =
|
||||||
|
allXs
|
||||||
|
|> E.A.fmap(x => {
|
||||||
|
let y1 = XtoY.stepwiseIncremental(x, t1);
|
||||||
|
let y2 = XtoY.stepwiseIncremental(x, t2);
|
||||||
|
fn(y1, y2);
|
||||||
|
});
|
||||||
|
fromArrays(allXs, allYs);
|
||||||
|
};
|
||||||
|
|
||||||
|
let combineIfAtX =
|
||||||
|
(t1: t, t2: t, fn: (option(float), option(float)) => float) => {
|
||||||
|
let allXs = Belt.Array.concat(xs(t1), xs(t2));
|
||||||
|
allXs |> Array.sort(compare);
|
||||||
|
let allYs =
|
||||||
|
allXs
|
||||||
|
|> E.A.fmap(x => {
|
||||||
|
let y1 = XtoY.stepwiseIfAtX(x, t1);
|
||||||
|
let y2 = XtoY.stepwiseIfAtX(x, t2);
|
||||||
|
fn(y1, y2);
|
||||||
|
});
|
||||||
|
fromArrays(allXs, allYs);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// todo: maybe not needed?
|
// todo: maybe not needed?
|
||||||
// let comparePoint = (a: float, b: float) => a > b ? 1 : (-1);
|
// let comparePoint = (a: float, b: float) => a > b ? 1 : (-1);
|
||||||
|
|
||||||
|
@ -155,12 +205,19 @@ module Range = {
|
||||||
|
|
||||||
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x);
|
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x);
|
||||||
|
|
||||||
let stepsToContinuous = t =>
|
// TODO: It would be nicer if this the diff didn't change the first element, and also maybe if there were a more elegant way of doing this.
|
||||||
Belt.Array.zip(t.xs, t.ys)
|
let stepsToContinuous = t => {
|
||||||
|> E.A.toRanges
|
let diff = xTotalRange(t) |> E.O.fmap(r => r *. 0.00001);
|
||||||
|> E.R.toOption
|
switch (diff, E.A.toRanges(Belt.Array.zip(t.xs, t.ys))) {
|
||||||
|> E.O.fmap(r => r |> Belt.Array.map(_, rangePointAssumingSteps))
|
| (Some(diff), Ok(items)) =>
|
||||||
|> E.O.fmap(Belt.Array.unzip)
|
Some(
|
||||||
|> E.O.fmap(fromArray)
|
items
|
||||||
|> E.O.fmap(intersperce(t));
|
|> Belt.Array.map(_, rangePointAssumingSteps)
|
||||||
|
|> Belt.Array.unzip
|
||||||
|
|> fromArray
|
||||||
|
|> intersperce(t |> xMap(e => e +. diff)),
|
||||||
|
)
|
||||||
|
| _ => None
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user