diff --git a/__tests__/Foo/Foo__Test.re b/__tests__/Foo/Foo__Test.re
index b35d7d1c..c613d9db 100644
--- a/__tests__/Foo/Foo__Test.re
+++ b/__tests__/Foo/Foo__Test.re
@@ -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);
});
});
\ No newline at end of file
diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re
index 7357d5b6..585d258c 100644
--- a/showcase/entries/Continuous.re
+++ b/showcase/entries/Continuous.re
@@ -12,7 +12,11 @@ let distributions = () =>
{"Basic Mixed Distribution" |> ReasonReact.string}
- {timeDist |> E.O.React.fmapOrNull(distPlus => )}
+ {timeDist
+ |> E.O.fmap(
+ Distributions.DistPlus.T.scaleToIntegralSum(~intendedSum=1.0),
+ )
+ |> E.O.React.fmapOrNull(distPlus => )}
{"Simple Continuous" |> ReasonReact.string}
;
diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re
index ce5dbd48..d6f9d820 100644
--- a/src/components/charts/DistPlusPlot.re
+++ b/src/components/charts/DistPlusPlot.re
@@ -60,12 +60,6 @@ let make = (~distPlus: DistTypes.distPlus) => {
() => { {setX(_ => r)}} />},
[|distPlus|],
);
- Js.log4(
- "distPlus",
- x,
- distPlus,
- distPlus |> Distributions.DistPlus.T.xToY(x),
- );
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}
{distPlus
|> Distributions.DistPlus.T.xToY(x)
|> DistTypes.MixedPoint.toContinuousValue
- |> E.Float.with2DigitsPrecision
+ |> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|> ReasonReact.string}
|
diff --git a/src/distributions/Distributions.re b/src/distributions/Distributions.re
index 1a5a0fb0..ab9d6c6e 100644
--- a/src/distributions/Distributions.re
+++ b/src/distributions/Distributions.re
@@ -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,
);
diff --git a/src/distributions/XYShape.re b/src/distributions/XYShape.re
index 26fd0f05..0eb6fcfa 100644
--- a/src/distributions/XYShape.re
+++ b/src/distributions/XYShape.re
@@ -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
+ };
+ };
};
\ No newline at end of file
|