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);
|
||||
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(
|
||||
"integralXToY",
|
||||
|
@ -251,13 +254,20 @@ describe("Shape", () => {
|
|||
T.Integral.get(~cache=None, mixed),
|
||||
Distributions.Continuous.make(
|
||||
{
|
||||
xs: [|1., 3., 4., 4., 7., 8., 8., 14.|],
|
||||
ys: [|0.15, 0.0, 0.15, 0.4, 0.13986013986013987, 0.4, 0.5, 0.5|],
|
||||
xs: [|1.00007, 3., 4., 4.00007, 7., 8., 8.00007, 14.|],
|
||||
ys: [|
|
||||
0.15,
|
||||
0.15,
|
||||
0.18496503496503497,
|
||||
0.4349674825174825,
|
||||
0.5398601398601399,
|
||||
0.5913086913086913,
|
||||
0.6913122927072927,
|
||||
1.0,
|
||||
|],
|
||||
},
|
||||
`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>
|
||||
<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>
|
||||
</div>
|
||||
</div>;
|
||||
|
|
|
@ -60,12 +60,6 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
|||
() => {<IntegralChart distPlus onHover={r => {setX(_ => r)}} />},
|
||||
[|distPlus|],
|
||||
);
|
||||
Js.log4(
|
||||
"distPlus",
|
||||
x,
|
||||
distPlus,
|
||||
distPlus |> Distributions.DistPlus.T.xToY(x),
|
||||
);
|
||||
<div>
|
||||
chart
|
||||
chart2
|
||||
|
@ -93,14 +87,14 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
|||
{distPlus
|
||||
|> Distributions.DistPlus.T.xToY(x)
|
||||
|> DistTypes.MixedPoint.toDiscreteValue
|
||||
|> E.Float.with2DigitsPrecision
|
||||
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|
||||
|> ReasonReact.string}
|
||||
</th>
|
||||
<th className="px-4 py-2 border ">
|
||||
{distPlus
|
||||
|> Distributions.DistPlus.T.xToY(x)
|
||||
|> DistTypes.MixedPoint.toContinuousValue
|
||||
|> E.Float.with2DigitsPrecision
|
||||
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|
||||
|> ReasonReact.string}
|
||||
</th>
|
||||
<th className="px-4 py-2 border ">
|
||||
|
|
|
@ -101,7 +101,7 @@ module Continuous = {
|
|||
switch (interpolation) {
|
||||
| `Stepwise =>
|
||||
xyShape
|
||||
|> XYShape.XtoY.stepwise(f)
|
||||
|> XYShape.XtoY.stepwiseIncremental(f)
|
||||
|> E.O.default(0.0)
|
||||
|> DistTypes.MixedPoint.makeContinuous
|
||||
| `Linear =>
|
||||
|
@ -109,6 +109,14 @@ module Continuous = {
|
|||
|> XYShape.XtoY.linear(f)
|
||||
|> 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) =>
|
||||
cache
|
||||
|> E.O.default(
|
||||
|
@ -148,7 +156,7 @@ module Discrete = {
|
|||
let toScaledDiscrete = t => Some(t);
|
||||
|
||||
let xToY = (f, t) => {
|
||||
XYShape.XtoY.ifAtX(f, t)
|
||||
XYShape.XtoY.stepwiseIfAtX(f, t)
|
||||
|> E.O.default(0.0)
|
||||
|> DistTypes.MixedPoint.makeDiscrete;
|
||||
};
|
||||
|
@ -254,9 +262,11 @@ module Mixed = {
|
|||
~scale=discreteProbabilityMassFraction,
|
||||
);
|
||||
Continuous.make(
|
||||
XYShape.combine(
|
||||
XYShape.Combine.combineLinear(
|
||||
Continuous.getShape(cont),
|
||||
Continuous.getShape(dist),
|
||||
(a, b) =>
|
||||
a +. b
|
||||
),
|
||||
`Linear,
|
||||
);
|
||||
|
|
|
@ -5,15 +5,21 @@ type t = xyShape;
|
|||
let toJs = (t: t) => {
|
||||
{"xs": t.xs, "ys": t.ys};
|
||||
};
|
||||
let minX = (t: t) => t.xs |> E.A.first;
|
||||
let maxX = (t: t) => t.xs |> E.A.last;
|
||||
let first = (t: t) =>
|
||||
switch (t.xs |> E.A.first, t.ys |> E.A.first) {
|
||||
let xs = (t: t) => t.xs;
|
||||
let minX = (t: t) => t |> xs |> E.A.first;
|
||||
let maxX = (t: t) => t |> xs |> E.A.last;
|
||||
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))
|
||||
| _ => None
|
||||
};
|
||||
let last = (t: t) =>
|
||||
switch (t.xs |> E.A.last, t.ys |> E.A.last) {
|
||||
let last = ({xs, ys}: t) =>
|
||||
switch (xs |> E.A.last, ys |> E.A.last) {
|
||||
| (Some(x), Some(y)) => Some((x, y))
|
||||
| _ => None
|
||||
};
|
||||
|
@ -21,7 +27,7 @@ let last = (t: t) =>
|
|||
let unsafeFirst = (t: t) => first(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 firstPairAtOrBeforeValue = (xValue, t: t) => {
|
||||
|
@ -38,20 +44,64 @@ let firstPairAtOrBeforeValue = (xValue, t: t) => {
|
|||
};
|
||||
|
||||
module XtoY = {
|
||||
let ifAtX = (f, t: t) =>
|
||||
getBy(t, ((x, _)) => x == f) |> E.O.fmap(((_, y)) => y);
|
||||
|
||||
let stepwise = (f, t: t) =>
|
||||
let stepwiseIncremental = (f, t: t) =>
|
||||
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.
|
||||
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 xMap = (fn, t: t): t => {xs: E.A.fmap(fn, t.xs), ys: t.ys};
|
||||
let fromArray = ((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?
|
||||
// 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 stepsToContinuous = t =>
|
||||
Belt.Array.zip(t.xs, t.ys)
|
||||
|> E.A.toRanges
|
||||
|> E.R.toOption
|
||||
|> E.O.fmap(r => r |> Belt.Array.map(_, rangePointAssumingSteps))
|
||||
|> E.O.fmap(Belt.Array.unzip)
|
||||
|> E.O.fmap(fromArray)
|
||||
|> E.O.fmap(intersperce(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.
|
||||
let stepsToContinuous = t => {
|
||||
let diff = xTotalRange(t) |> E.O.fmap(r => r *. 0.00001);
|
||||
switch (diff, E.A.toRanges(Belt.Array.zip(t.xs, t.ys))) {
|
||||
| (Some(diff), Ok(items)) =>
|
||||
Some(
|
||||
items
|
||||
|> Belt.Array.map(_, rangePointAssumingSteps)
|
||||
|> Belt.Array.unzip
|
||||
|> fromArray
|
||||
|> intersperce(t |> xMap(e => e +. diff)),
|
||||
)
|
||||
| _ => None
|
||||
};
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user