Continuous integration should include first item
This commit is contained in:
parent
8d7a6f7f6c
commit
24dc4e657e
|
@ -11,7 +11,7 @@ let makeTest = (str, item1, item2) =>
|
||||||
describe("Shape", () => {
|
describe("Shape", () => {
|
||||||
describe("Continuous", () => {
|
describe("Continuous", () => {
|
||||||
open Distributions.Continuous;
|
open Distributions.Continuous;
|
||||||
let continuous = make(shape, `Stepwise);
|
let continuous = make(shape, `Linear);
|
||||||
makeTest("minX", T.minX(continuous), Some(1.0));
|
makeTest("minX", T.minX(continuous), Some(1.0));
|
||||||
makeTest("maxX", T.maxX(continuous), Some(8.0));
|
makeTest("maxX", T.maxX(continuous), Some(8.0));
|
||||||
makeTest(
|
makeTest(
|
||||||
|
@ -19,32 +19,75 @@ describe("Shape", () => {
|
||||||
T.pointwiseFmap(r => r *. 2.0, continuous) |> getShape |> (r => r.ys),
|
T.pointwiseFmap(r => r *. 2.0, continuous) |> getShape |> (r => r.ys),
|
||||||
[|16., 18.0, 4.0|],
|
[|16., 18.0, 4.0|],
|
||||||
);
|
);
|
||||||
makeTest(
|
describe("xToY", () => {
|
||||||
"xToY at 4.0",
|
describe("when Linear", () => {
|
||||||
T.xToY(4., continuous),
|
makeTest(
|
||||||
{continuous: 9.0, discrete: 0.0},
|
"at 4.0",
|
||||||
);
|
T.xToY(4., continuous),
|
||||||
makeTest(
|
{continuous: 9.0, discrete: 0.0},
|
||||||
"xToY at 0.0",
|
);
|
||||||
T.xToY(0., continuous),
|
// Note: This below is weird to me, I'm not sure if it's what we want really.
|
||||||
{continuous: 8.0, discrete: 0.0},
|
makeTest(
|
||||||
);
|
"at 0.0",
|
||||||
makeTest(
|
T.xToY(0., continuous),
|
||||||
"xToY at 5.0",
|
{continuous: 8.0, discrete: 0.0},
|
||||||
T.xToY(5., continuous),
|
);
|
||||||
{continuous: 7.25, discrete: 0.0},
|
makeTest(
|
||||||
);
|
"at 5.0",
|
||||||
|
T.xToY(5., continuous),
|
||||||
|
{continuous: 7.25, discrete: 0.0},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"at 10.0",
|
||||||
|
T.xToY(10., continuous),
|
||||||
|
{continuous: 2.0, discrete: 0.0},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
describe("when Stepwise", () => {
|
||||||
|
let continuous = make(shape, `Stepwise);
|
||||||
|
makeTest(
|
||||||
|
"at 4.0",
|
||||||
|
T.xToY(4., continuous),
|
||||||
|
{continuous: 9.0, discrete: 0.0},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"at 0.0",
|
||||||
|
T.xToY(0., continuous),
|
||||||
|
{continuous: 0.0, discrete: 0.0},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"at 5.0",
|
||||||
|
T.xToY(5., continuous),
|
||||||
|
{continuous: 9.0, discrete: 0.0},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"at 10.0",
|
||||||
|
T.xToY(10., continuous),
|
||||||
|
{continuous: 2.0, discrete: 0.0},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
makeTest(
|
makeTest(
|
||||||
"integral",
|
"integral",
|
||||||
T.Integral.get(~cache=None, continuous) |> getShape,
|
T.Integral.get(~cache=None, continuous) |> getShape,
|
||||||
{xs: [|4.0, 8.0|], ys: [|25.5, 47.5|]},
|
{xs: [|1.0, 4.0, 8.0|], ys: [|0.0, 25.5, 47.5|]},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"integralXToY",
|
||||||
|
T.Integral.xToY(~cache=None, 0.0, continuous),
|
||||||
|
0.0,
|
||||||
);
|
);
|
||||||
makeTest(
|
makeTest(
|
||||||
"integralXToY",
|
"integralXToY",
|
||||||
T.Integral.xToY(~cache=None, 2.0, continuous),
|
T.Integral.xToY(~cache=None, 2.0, continuous),
|
||||||
25.5,
|
8.5,
|
||||||
);
|
);
|
||||||
makeTest("integralSum", T.Integral.sum(~cache=None, continuous), 73.0);
|
makeTest(
|
||||||
|
"integralXToY",
|
||||||
|
T.Integral.xToY(~cache=None, 100.0, continuous),
|
||||||
|
47.5,
|
||||||
|
);
|
||||||
|
makeTest("integralSum", T.Integral.sum(~cache=None, continuous), 47.5);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Discrete", () => {
|
describe("Discrete", () => {
|
||||||
|
@ -76,6 +119,23 @@ describe("Shape", () => {
|
||||||
T.xToY(5., discrete),
|
T.xToY(5., discrete),
|
||||||
{discrete: 0.0, continuous: 0.0},
|
{discrete: 0.0, continuous: 0.0},
|
||||||
);
|
);
|
||||||
|
makeTest(
|
||||||
|
"scaleBy",
|
||||||
|
T.scaleBy(~scale=4.0, discrete),
|
||||||
|
{xs: [|1., 4., 8.|], ys: [|1.2, 2.0, 0.8|]},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"scaleToIntegralSum",
|
||||||
|
T.scaleToIntegralSum(~intendedSum=4.0, discrete),
|
||||||
|
{xs: [|1., 4., 8.|], ys: [|1.2, 2.0, 0.8|]},
|
||||||
|
);
|
||||||
|
makeTest(
|
||||||
|
"scaleToIntegralSum: back and forth",
|
||||||
|
discrete
|
||||||
|
|> T.scaleToIntegralSum(~intendedSum=4.0)
|
||||||
|
|> T.scaleToIntegralSum(~intendedSum=1.0),
|
||||||
|
discrete,
|
||||||
|
);
|
||||||
makeTest(
|
makeTest(
|
||||||
"integral",
|
"integral",
|
||||||
T.Integral.get(~cache=None, discrete),
|
T.Integral.get(~cache=None, discrete),
|
||||||
|
@ -84,6 +144,11 @@ describe("Shape", () => {
|
||||||
`Stepwise,
|
`Stepwise,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
makeTest(
|
||||||
|
"integral with 1 element",
|
||||||
|
T.Integral.get(~cache=None, {xs: [|0.0|], ys: [|1.0|]}),
|
||||||
|
Distributions.Continuous.make({xs: [|0.0|], ys: [|1.0|]}, `Stepwise),
|
||||||
|
);
|
||||||
makeTest(
|
makeTest(
|
||||||
"integralXToY",
|
"integralXToY",
|
||||||
T.Integral.xToY(~cache=None, 6.0, discrete),
|
T.Integral.xToY(~cache=None, 6.0, discrete),
|
||||||
|
|
|
@ -60,6 +60,12 @@ 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
|
||||||
|
@ -67,6 +73,12 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-4 py-2"> {"X Point" |> ReasonReact.string} </th>
|
<th className="px-4 py-2"> {"X Point" |> ReasonReact.string} </th>
|
||||||
|
<th className="px-4 py-2">
|
||||||
|
{"Discrete Value" |> ReasonReact.string}
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2">
|
||||||
|
{"Continuous Value" |> ReasonReact.string}
|
||||||
|
</th>
|
||||||
<th className="px-4 py-2">
|
<th className="px-4 py-2">
|
||||||
{"Y Integral to Point" |> ReasonReact.string}
|
{"Y Integral to Point" |> ReasonReact.string}
|
||||||
</th>
|
</th>
|
||||||
|
@ -77,6 +89,20 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
||||||
<th className="px-4 py-2 border ">
|
<th className="px-4 py-2 border ">
|
||||||
{x |> E.Float.toString |> ReasonReact.string}
|
{x |> E.Float.toString |> ReasonReact.string}
|
||||||
</th>
|
</th>
|
||||||
|
<th className="px-4 py-2 border ">
|
||||||
|
{distPlus
|
||||||
|
|> Distributions.DistPlus.T.xToY(x)
|
||||||
|
|> DistTypes.MixedPoint.toDiscreteValue
|
||||||
|
|> E.Float.with2DigitsPrecision
|
||||||
|
|> ReasonReact.string}
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 border ">
|
||||||
|
{distPlus
|
||||||
|
|> Distributions.DistPlus.T.xToY(x)
|
||||||
|
|> DistTypes.MixedPoint.toContinuousValue
|
||||||
|
|> E.Float.with2DigitsPrecision
|
||||||
|
|> ReasonReact.string}
|
||||||
|
</th>
|
||||||
<th className="px-4 py-2 border ">
|
<th className="px-4 py-2 border ">
|
||||||
{distPlus
|
{distPlus
|
||||||
|> Distributions.DistPlus.T.Integral.xToY(~cache=None, x)
|
|> Distributions.DistPlus.T.Integral.xToY(~cache=None, x)
|
||||||
|
|
|
@ -54,7 +54,7 @@ module Dist = (T: dist) => {
|
||||||
let sum = T.integralSum;
|
let sum = T.integralSum;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is suboptimal because it could get the cache but doesn't here.
|
// This is suboptimal because it could get the cache but doesn't here.
|
||||||
let scaleToIntegralSum = (~intendedSum=1.0, t: t) => {
|
let scaleToIntegralSum = (~intendedSum=1.0, t: t) => {
|
||||||
let scale = intendedSum /. Integral.sum(~cache=None, t);
|
let scale = intendedSum /. Integral.sum(~cache=None, t);
|
||||||
scaleBy(~scale, t);
|
scaleBy(~scale, t);
|
||||||
|
@ -90,8 +90,9 @@ module Continuous = {
|
||||||
type t = DistTypes.continuousShape;
|
type t = DistTypes.continuousShape;
|
||||||
type integral = DistTypes.continuousShape;
|
type integral = DistTypes.continuousShape;
|
||||||
let shapeFn = (fn, t: t) => t |> xyShape |> fn;
|
let shapeFn = (fn, t: t) => t |> xyShape |> fn;
|
||||||
// TODO: Obviously fix this, it's terrible. Use interpolation method here.
|
// TODO: Obviously fix this, it's terrible. Use interpolation param to do appropriate interpolation.
|
||||||
// TODO: Steps could be 1 value, interpolation needs at least 2.
|
// TODO: Steps could be 1 value, interpolation needs at least 2.
|
||||||
|
// TODO: integrateWithTriangles should return (x0, 0.0) as the first item.
|
||||||
let integral = (~cache, t) =>
|
let integral = (~cache, t) =>
|
||||||
cache
|
cache
|
||||||
|> E.O.default(
|
|> E.O.default(
|
||||||
|
@ -103,16 +104,28 @@ module Continuous = {
|
||||||
);
|
);
|
||||||
// This seems wrong, we really want the ending bit, I'd assume
|
// This seems wrong, we really want the ending bit, I'd assume
|
||||||
let integralSum = (~cache, t) =>
|
let integralSum = (~cache, t) =>
|
||||||
t |> integral(~cache) |> xyShape |> XYShape.ySum;
|
t
|
||||||
|
|> integral(~cache)
|
||||||
|
|> xyShape
|
||||||
|
|> XYShape.unsafeLast
|
||||||
|
|> (((_, y)) => y);
|
||||||
let minX = shapeFn(XYShape.minX);
|
let minX = shapeFn(XYShape.minX);
|
||||||
let maxX = shapeFn(XYShape.maxX);
|
let maxX = shapeFn(XYShape.maxX);
|
||||||
let pointwiseFmap = (fn, t: t) =>
|
let pointwiseFmap = (fn, t: t) =>
|
||||||
t |> xyShape |> XYShape.pointwiseMap(fn) |> fromShape;
|
t |> xyShape |> XYShape.pointwiseMap(fn) |> fromShape;
|
||||||
let toShape = (t: t): DistTypes.shape => Continuous(t);
|
let toShape = (t: t): DistTypes.shape => Continuous(t);
|
||||||
// TODO: When Roman's PR comes in, fix this bit. This depends on interpolation, obviously.
|
let xToY = (f, {interpolation, xyShape}: t) =>
|
||||||
let xToY = (f, t) =>
|
switch (interpolation) {
|
||||||
shapeFn(CdfLibrary.Distribution.findY(f), t)
|
| `Stepwise =>
|
||||||
|> DistTypes.MixedPoint.makeContinuous;
|
xyShape
|
||||||
|
|> XYShape.XtoY.stepwise(f)
|
||||||
|
|> E.O.default(0.0)
|
||||||
|
|> DistTypes.MixedPoint.makeContinuous
|
||||||
|
| `Linear =>
|
||||||
|
xyShape
|
||||||
|
|> XYShape.XtoY.linear(f)
|
||||||
|
|> DistTypes.MixedPoint.makeContinuous
|
||||||
|
};
|
||||||
let integralXtoY = (~cache, f, t) =>
|
let integralXtoY = (~cache, f, t) =>
|
||||||
t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f));
|
t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f));
|
||||||
let toContinuous = t => Some(t);
|
let toContinuous = t => Some(t);
|
||||||
|
@ -138,7 +151,6 @@ module Discrete = {
|
||||||
Continuous.make(XYShape.accumulateYs(t), `Stepwise);
|
Continuous.make(XYShape.accumulateYs(t), `Stepwise);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// todo: Fix this with last element
|
|
||||||
let integralSum = (~cache, t) => t |> XYShape.ySum;
|
let integralSum = (~cache, t) => t |> XYShape.ySum;
|
||||||
let minX = XYShape.minX;
|
let minX = XYShape.minX;
|
||||||
let maxX = XYShape.maxX;
|
let maxX = XYShape.maxX;
|
||||||
|
@ -150,8 +162,7 @@ module Discrete = {
|
||||||
let toScaledDiscrete = t => Some(t);
|
let toScaledDiscrete = t => Some(t);
|
||||||
|
|
||||||
let xToY = (f, t) => {
|
let xToY = (f, t) => {
|
||||||
XYShape.getBy(t, ((x, _)) => x == f)
|
XYShape.XtoY.ifAtX(f, t)
|
||||||
|> E.O.fmap(((_, y)) => y)
|
|
||||||
|> E.O.default(0.0)
|
|> E.O.default(0.0)
|
||||||
|> DistTypes.MixedPoint.makeDiscrete;
|
|> DistTypes.MixedPoint.makeDiscrete;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,8 +18,36 @@ let last = (t: t) =>
|
||||||
| _ => None
|
| _ => None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 = t => Belt.Array.zip(t.xs, t.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 zipped = zip(t);
|
||||||
|
let firstIndex =
|
||||||
|
zipped |> Belt.Array.getIndexBy(_, ((x, y)) => x > xValue);
|
||||||
|
let previousIndex =
|
||||||
|
switch (firstIndex) {
|
||||||
|
| None => Some(Array.length(zipped) - 1)
|
||||||
|
| Some(0) => None
|
||||||
|
| Some(n) => Some(n - 1)
|
||||||
|
};
|
||||||
|
previousIndex |> Belt.Option.flatMap(_, Belt.Array.get(zipped));
|
||||||
|
};
|
||||||
|
|
||||||
|
module XtoY = {
|
||||||
|
let ifAtX = (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);
|
||||||
|
|
||||||
|
// 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 pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)};
|
||||||
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};
|
||||||
|
@ -109,21 +137,24 @@ module Range = {
|
||||||
(((lastX, lastY), (nextX, nextY)): zippedRange) =>
|
(((lastX, lastY), (nextX, nextY)): zippedRange) =>
|
||||||
(nextY -. lastY) /. (nextX -. lastX);
|
(nextY -. lastY) /. (nextX -. lastX);
|
||||||
|
|
||||||
let inRanges = (mapper, reducer, t: t) => {
|
let mapYsBasedOnRanges = (fn, t) =>
|
||||||
Belt.Array.zip(t.xs, t.ys)
|
Belt.Array.zip(t.xs, t.ys)
|
||||||
|> E.A.toRanges
|
|> E.A.toRanges
|
||||||
|> E.R.toOption
|
|> E.R.toOption
|
||||||
|> E.O.fmap(r => r |> Belt.Array.map(_, mapper) |> reducer);
|
|> E.O.fmap(r => r |> Belt.Array.map(_, r => (nextX(r), fn(r))));
|
||||||
};
|
|
||||||
|
|
||||||
let mapYsBasedOnRanges = fn => inRanges(r => (nextX(r), fn(r)), toT);
|
let integrateWithTriangles = z => {
|
||||||
|
let rangeItems = mapYsBasedOnRanges(rangeAreaAssumingTriangles, z);
|
||||||
let integrateWithSteps = z =>
|
(
|
||||||
mapYsBasedOnRanges(rangeAreaAssumingSteps, z) |> E.O.fmap(accumulateYs);
|
switch (rangeItems, z |> first) {
|
||||||
|
| (Some(r), Some((firstX, _))) =>
|
||||||
let integrateWithTriangles = z =>
|
Some(Belt.Array.concat([|(firstX, 0.0)|], r))
|
||||||
mapYsBasedOnRanges(rangeAreaAssumingTriangles, z)
|
| _ => None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> E.O.fmap(toT)
|
||||||
|> E.O.fmap(accumulateYs);
|
|> E.O.fmap(accumulateYs);
|
||||||
|
};
|
||||||
|
|
||||||
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x);
|
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user