First refactor to XYShape
This commit is contained in:
parent
f061e9fa01
commit
6f8d06a6d6
|
@ -1,179 +0,0 @@
|
|||
open Jest;
|
||||
open Expect;
|
||||
|
||||
exception ShapeWrong(string);
|
||||
describe("CDF", () => {
|
||||
test("raise - w/o order", () => {
|
||||
expect(() => {
|
||||
module Cdf =
|
||||
CDF.Make({
|
||||
let shape: DistTypes.xyShape = {
|
||||
xs: [|10., 4., 8.|],
|
||||
ys: [|8., 9., 2.|],
|
||||
};
|
||||
});
|
||||
();
|
||||
})
|
||||
|> toThrow
|
||||
});
|
||||
test("raise - with order", () => {
|
||||
expect(() => {
|
||||
module Cdf =
|
||||
CDF.Make({
|
||||
let shape: DistTypes.xyShape = {
|
||||
xs: [|1., 4., 8.|],
|
||||
ys: [|8., 9., 2.|],
|
||||
};
|
||||
});
|
||||
();
|
||||
})
|
||||
|> not_
|
||||
|> toThrow
|
||||
});
|
||||
test("order#1", () => {
|
||||
let a = CDF.order({xs: [|1., 4., 8.|], ys: [|8., 9., 2.|]});
|
||||
let b: DistTypes.xyShape = {xs: [|1., 4., 8.|], ys: [|8., 9., 2.|]};
|
||||
expect(a) |> toEqual(b);
|
||||
});
|
||||
test("order#2", () => {
|
||||
let a = CDF.order({xs: [|10., 5., 12.|], ys: [|8., 9., 2.|]});
|
||||
let b: DistTypes.xyShape = {xs: [|5., 10., 12.|], ys: [|9., 8., 2.|]};
|
||||
expect(a) |> toEqual(b);
|
||||
});
|
||||
|
||||
describe("minX - maxX", () => {
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape = CDF.order({xs: [|20., 4., 8.|], ys: [|8., 9., 2.|]});
|
||||
});
|
||||
test("minX", () => {
|
||||
expect(Dist.minX()) |> toEqual(4.)
|
||||
});
|
||||
test("maxX", () => {
|
||||
expect(Dist.maxX()) |> toEqual(20.)
|
||||
});
|
||||
});
|
||||
|
||||
describe("findY", () => {
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape = CDF.order({xs: [|1., 2., 3.|], ys: [|5., 6., 7.|]});
|
||||
});
|
||||
test("#1", () => {
|
||||
expect(Dist.findY(1.)) |> toEqual(5.)
|
||||
});
|
||||
test("#2", () => {
|
||||
expect(Dist.findY(1.5)) |> toEqual(5.5)
|
||||
});
|
||||
test("#3", () => {
|
||||
expect(Dist.findY(3.)) |> toEqual(7.)
|
||||
});
|
||||
test("#4", () => {
|
||||
expect(Dist.findY(4.)) |> toEqual(7.)
|
||||
});
|
||||
test("#5", () => {
|
||||
expect(Dist.findY(15.)) |> toEqual(7.)
|
||||
});
|
||||
test("#6", () => {
|
||||
expect(Dist.findY(-1.)) |> toEqual(5.)
|
||||
});
|
||||
});
|
||||
|
||||
describe("findX", () => {
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape = CDF.order({xs: [|1., 2., 3.|], ys: [|5., 6., 7.|]});
|
||||
});
|
||||
test("#1", () => {
|
||||
expect(Dist.findX(5.)) |> toEqual(1.)
|
||||
});
|
||||
test("#2", () => {
|
||||
expect(Dist.findX(7.)) |> toEqual(3.)
|
||||
});
|
||||
test("#3", () => {
|
||||
expect(Dist.findX(5.5)) |> toEqual(1.5)
|
||||
});
|
||||
test("#4", () => {
|
||||
expect(Dist.findX(8.)) |> toEqual(3.)
|
||||
});
|
||||
test("#5", () => {
|
||||
expect(Dist.findX(4.)) |> toEqual(1.)
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertWithAlternativeXs", () => {
|
||||
open Functions;
|
||||
let xs = up(1, 9);
|
||||
let ys = up(20, 28);
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape = CDF.order({xs, ys});
|
||||
});
|
||||
|
||||
let xs2 = up(3, 7);
|
||||
module Dist2 =
|
||||
CDF.Make({
|
||||
let shape = Dist.convertWithAlternativeXs(xs2);
|
||||
});
|
||||
|
||||
test("#1", () => {
|
||||
expect(Dist2.xs) |> toEqual([|3., 4., 5., 6., 7.|])
|
||||
});
|
||||
test("#2", () => {
|
||||
expect(Dist2.ys) |> toEqual([|22., 23., 24., 25., 26.|])
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertToNewLength", () => {
|
||||
open Functions;
|
||||
let xs = up(1, 9);
|
||||
let ys = up(50, 58);
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape = CDF.order({xs, ys});
|
||||
});
|
||||
module Dist2 =
|
||||
CDF.Make({
|
||||
let shape = Dist.convertToNewLength(3);
|
||||
});
|
||||
test("#1", () => {
|
||||
expect(Dist2.xs) |> toEqual([|1., 5., 9.|])
|
||||
});
|
||||
test("#2", () => {
|
||||
expect(Dist2.ys) |> toEqual([|50., 54., 58.|])
|
||||
});
|
||||
});
|
||||
|
||||
// @todo: Should each test expect 70.?
|
||||
describe("sample", () => {
|
||||
open Functions;
|
||||
let xs = up(1, 9);
|
||||
let ys = up(70, 78);
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape = CDF.order({xs, ys});
|
||||
});
|
||||
|
||||
let xs2 = Dist.sample(3);
|
||||
test("#1", () => {
|
||||
expect(xs2[0]) |> toBe(70.)
|
||||
});
|
||||
test("#2", () => {
|
||||
expect(xs2[1]) |> toBe(70.)
|
||||
});
|
||||
test("#3", () => {
|
||||
expect(xs2[2]) |> toBe(70.)
|
||||
});
|
||||
});
|
||||
|
||||
describe("integral", () => {
|
||||
module Dist =
|
||||
CDF.Make({
|
||||
let shape =
|
||||
CDF.order({xs: [|0., 1., 2., 4.|], ys: [|0.0, 1.0, 2.0, 2.0|]});
|
||||
});
|
||||
test("with regular inputs", () => {
|
||||
expect(Dist.integral()) |> toBe(6.)
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,92 +0,0 @@
|
|||
open Jest;
|
||||
open Expect;
|
||||
|
||||
exception ShapeWrong(string);
|
||||
describe("Functions", () => {
|
||||
test("interpolate", () => {
|
||||
let a = Functions.interpolate(10., 20., 1., 2., 15.);
|
||||
let b = 1.5;
|
||||
expect(a) |> toEqual(b);
|
||||
});
|
||||
test("range#1", () => {
|
||||
expect(Functions.range(1., 5., 3)) |> toEqual([|1., 3., 5.|])
|
||||
});
|
||||
test("range#2", () => {
|
||||
expect(Functions.range(1., 5., 5)) |> toEqual([|1., 2., 3., 4., 5.|])
|
||||
});
|
||||
test("range#3", () => {
|
||||
expect(Functions.range(-10., 15., 2)) |> toEqual([|(-10.), 15.|])
|
||||
});
|
||||
test("range#4", () => {
|
||||
expect(Functions.range(-10., 15., 3)) |> toEqual([|(-10.), 2.5, 15.|])
|
||||
});
|
||||
test("range#5", () => {
|
||||
expect(Functions.range(-10.3, 17., 3))
|
||||
|> toEqual([|(-10.3), 3.3499999999999996, 17.|])
|
||||
});
|
||||
test("range#6", () => {
|
||||
expect(Functions.range(-10.3, 17., 5))
|
||||
|> toEqual([|
|
||||
(-10.3),
|
||||
(-3.4750000000000005),
|
||||
3.3499999999999996,
|
||||
10.175,
|
||||
17.0,
|
||||
|])
|
||||
});
|
||||
test("range#7", () => {
|
||||
expect(Functions.range(-10.3, 17.31, 3))
|
||||
|> toEqual([|(-10.3), 3.504999999999999, 17.31|])
|
||||
});
|
||||
test("range#8", () => {
|
||||
expect(Functions.range(1., 1., 3)) |> toEqual([|1., 1., 1.|])
|
||||
});
|
||||
test("mean#1", () => {
|
||||
expect(Functions.mean([|1., 2., 3.|])) |> toEqual(2.)
|
||||
});
|
||||
test("mean#2", () => {
|
||||
expect(Functions.mean([|1., 2., 3., (-2.)|])) |> toEqual(1.)
|
||||
});
|
||||
test("mean#3", () => {
|
||||
expect(Functions.mean([|1., 2., 3., (-2.), (-10.)|])) |> toEqual(-1.2)
|
||||
});
|
||||
test("min#1", () => {
|
||||
expect(Functions.min([|1., 2., 3.|])) |> toEqual(1.)
|
||||
});
|
||||
test("min#2", () => {
|
||||
expect(Functions.min([|(-1.), (-2.), 0., 20.|])) |> toEqual(-2.)
|
||||
});
|
||||
test("min#3", () => {
|
||||
expect(Functions.min([|(-1.), (-2.), 0., 20., (-2.2)|]))
|
||||
|> toEqual(-2.2)
|
||||
});
|
||||
test("max#1", () => {
|
||||
expect(Functions.max([|1., 2., 3.|])) |> toEqual(3.)
|
||||
});
|
||||
test("max#2", () => {
|
||||
expect(Functions.max([|(-1.), (-2.), 0., 20.|])) |> toEqual(20.)
|
||||
});
|
||||
test("max#3", () => {
|
||||
expect(Functions.max([|(-1.), (-2.), 0., (-2.2)|])) |> toEqual(0.)
|
||||
});
|
||||
test("random#1", () => {
|
||||
expect(Functions.random(1, 5)) |> toBeLessThanOrEqual(5)
|
||||
});
|
||||
test("random#2", () => {
|
||||
expect(Functions.random(1, 5)) |> toBeGreaterThanOrEqual(1)
|
||||
});
|
||||
test("up#1", () => {
|
||||
expect(Functions.up(1, 5)) |> toEqual([|1., 2., 3., 4., 5.|])
|
||||
});
|
||||
test("up#2", () => {
|
||||
expect(Functions.up(-1, 5))
|
||||
|> toEqual([|(-1.), 0., 1., 2., 3., 4., 5.|])
|
||||
});
|
||||
test("down#1", () => {
|
||||
expect(Functions.down(5, 1)) |> toEqual([|5., 4., 3., 2., 1.|])
|
||||
});
|
||||
test("down#2", () => {
|
||||
expect(Functions.down(5, -1))
|
||||
|> toEqual([|5., 4., 3., 2., 1., 0., (-1.)|])
|
||||
});
|
||||
});
|
|
@ -43,7 +43,7 @@ describe("XYShapes", () => {
|
|||
describe("transverse", () => {
|
||||
makeTest(
|
||||
"When very different",
|
||||
XYShape.T._transverse2(
|
||||
XYShape.T.Transversal._transverse(
|
||||
(aCurrent, aLast) => aCurrent +. aLast,
|
||||
[|1.0, 2.0, 3.0, 4.0|],
|
||||
),
|
||||
|
|
|
@ -91,7 +91,7 @@ module T = {
|
|||
// todo: Figure out some way of doing this without having to integrate so many times.
|
||||
let toShape = (~samples: t, ~outputXYPoints=3000, ~kernelWidth=10, ()) => {
|
||||
Array.fast_sort(compare, samples);
|
||||
let (continuousPart, discretePart) = E.A.Floats.split(samples);
|
||||
let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples);
|
||||
let length = samples |> E.A.length;
|
||||
let lengthFloat = float_of_int(length);
|
||||
let discrete: DistTypes.xyShape =
|
||||
|
|
|
@ -87,7 +87,7 @@ module Continuous = {
|
|||
interpolation,
|
||||
};
|
||||
let lastY = (t: t) =>
|
||||
t |> xyShape |> XYShape.T.unsafeLast |> (((_, y)) => y);
|
||||
t |> xyShape |> XYShape.T.Pairs.unsafeLast |> (((_, y)) => y);
|
||||
let oShapeMap =
|
||||
(fn, {xyShape, interpolation}: t): option(DistTypes.continuousShape) =>
|
||||
fn(xyShape) |> E.O.fmap(make(_, interpolation));
|
||||
|
@ -146,16 +146,16 @@ module Continuous = {
|
|||
let truncate = (~cache=None, i, t) =>
|
||||
t
|
||||
|> shapeMap(
|
||||
XYShape.T.convertToNewLengthByProbabilityMass(
|
||||
XYShape.T.XsConversion.proportionByProbabilityMass(
|
||||
i,
|
||||
integral(~cache, t).xyShape,
|
||||
),
|
||||
);
|
||||
let integralEndY = (~cache, t) => t |> integral(~cache) |> lastY;
|
||||
let integralXtoY = (~cache, f, t) =>
|
||||
t |> integral(~cache) |> shapeFn(XYShape.T.findY(f));
|
||||
t |> integral(~cache) |> shapeFn(XYShape.T.XtoY.linear(f));
|
||||
let integralYtoX = (~cache, f, t) =>
|
||||
t |> integral(~cache) |> shapeFn(XYShape.T.findX(f));
|
||||
t |> integral(~cache) |> shapeFn(XYShape.T.YtoX.linear(f));
|
||||
let toContinuous = t => Some(t);
|
||||
let toDiscrete = _ => None;
|
||||
let toScaledContinuous = t => Some(t);
|
||||
|
@ -208,10 +208,16 @@ module Discrete = {
|
|||
};
|
||||
|
||||
let integralXtoY = (~cache, f, t) =>
|
||||
t |> integral(~cache) |> Continuous.getShape |> XYShape.T.findY(f);
|
||||
t
|
||||
|> integral(~cache)
|
||||
|> Continuous.getShape
|
||||
|> XYShape.T.XtoY.linear(f);
|
||||
|
||||
let integralYtoX = (~cache, f, t) =>
|
||||
t |> integral(~cache) |> Continuous.getShape |> XYShape.T.findX(f);
|
||||
t
|
||||
|> integral(~cache)
|
||||
|> Continuous.getShape
|
||||
|> XYShape.T.YtoX.linear(f);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -357,11 +363,17 @@ module Mixed = {
|
|||
};
|
||||
|
||||
let integralXtoY = (~cache, f, t) => {
|
||||
t |> integral(~cache) |> Continuous.getShape |> XYShape.T.findY(f);
|
||||
t
|
||||
|> integral(~cache)
|
||||
|> Continuous.getShape
|
||||
|> XYShape.T.XtoY.linear(f);
|
||||
};
|
||||
|
||||
let integralYtoX = (~cache, f, t) => {
|
||||
t |> integral(~cache) |> Continuous.getShape |> XYShape.T.findX(f);
|
||||
t
|
||||
|> integral(~cache)
|
||||
|> Continuous.getShape
|
||||
|> XYShape.T.YtoX.linear(f);
|
||||
};
|
||||
|
||||
// TODO: This functionality is kinda weird, because it seems to assume the cdf adds to 1.0 elsewhere, which wouldn't happen here.
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
open DistTypes;
|
||||
|
||||
let interpolate =
|
||||
(xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float)
|
||||
: float => {
|
||||
let minProportion = (xMax -. xIntended) /. (xMax -. xMin);
|
||||
let maxProportion = (xIntended -. xMin) /. (xMax -. xMin);
|
||||
yMin *. minProportion +. yMax *. maxProportion;
|
||||
};
|
||||
|
||||
module T = {
|
||||
type t = xyShape;
|
||||
type ts = array(xyShape);
|
||||
|
@ -9,36 +17,65 @@ module T = {
|
|||
};
|
||||
let xs = (t: t) => t.xs;
|
||||
let ys = (t: t) => t.ys;
|
||||
let minX = (t: t) => t |> xs |> E.A.first;
|
||||
let maxX = (t: t) => t |> xs |> E.A.last;
|
||||
let minY = (t: t) => t |> ys |> E.A.first;
|
||||
let maxY = (t: t) => t |> ys |> 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 = ({xs, ys}: t) =>
|
||||
switch (xs |> E.A.last, ys |> E.A.last) {
|
||||
| (Some(x), Some(y)) => Some((x, y))
|
||||
| _ => None
|
||||
let minX = (t: t) => t |> xs |> E.A.Sorted.min;
|
||||
let maxX = (t: t) => t |> xs |> E.A.Sorted.max;
|
||||
let minY = (t: t) => t |> ys |> E.A.Sorted.min;
|
||||
let maxY = (t: t) => t |> ys |> E.A.Sorted.max;
|
||||
let xTotalRange = (t: t) => t |> xs |> E.A.Sorted.range;
|
||||
let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys);
|
||||
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};
|
||||
let fromZippedArray = (is: array((float, float))): t =>
|
||||
is |> Belt.Array.unzip |> fromArray;
|
||||
let equallyDividedXs = (t: t, newLength) => {
|
||||
E.A.Floats.range(
|
||||
minX(t) |> E.O.toExt("Unsafe"),
|
||||
maxX(t) |> E.O.toExt("Unsafe"),
|
||||
newLength,
|
||||
);
|
||||
};
|
||||
|
||||
module Ts = {
|
||||
type t = ts;
|
||||
let minX = (t: t) =>
|
||||
t
|
||||
|> E.A.fmap(minX)
|
||||
|> E.A.O.concatSomes
|
||||
|> E.A.min
|
||||
|> E.O.toExt("Unsafe");
|
||||
let maxX = (t: t) =>
|
||||
t
|
||||
|> E.A.fmap(maxX)
|
||||
|> E.A.O.concatSomes
|
||||
|> E.A.max
|
||||
|> E.O.toExt("Unsafe");
|
||||
let equallyDividedXs = (t: t, newLength) => {
|
||||
E.A.Floats.range(minX(t), maxX(t), newLength);
|
||||
};
|
||||
};
|
||||
|
||||
module Pairs = {
|
||||
let first = (t: t) =>
|
||||
switch (minX(t), minY(t)) {
|
||||
| (Some(x), Some(y)) => Some((x, y))
|
||||
| _ => None
|
||||
};
|
||||
let last = (t: t) =>
|
||||
switch (maxX(t), maxY(t)) {
|
||||
| (Some(x), Some(y)) => Some((x, y))
|
||||
| _ => 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 = ({xs, ys}: t) => Belt.Array.zip(xs, ys);
|
||||
let getBy = (t: t, fn) => t |> zip |> Belt.Array.getBy(_, fn);
|
||||
|
||||
let firstPairAtOrBeforeValue = (xValue, t: t) => {
|
||||
let firstAtOrBeforeXValue = (xValue, t: t) => {
|
||||
let zipped = zip(t);
|
||||
let firstIndex =
|
||||
zipped |> Belt.Array.getIndexBy(_, ((x, y)) => x > xValue);
|
||||
zipped |> Belt.Array.getIndexBy(_, ((x, _)) => x > xValue);
|
||||
let previousIndex =
|
||||
switch (firstIndex) {
|
||||
| None => Some(Array.length(zipped) - 1)
|
||||
|
@ -47,34 +84,10 @@ module T = {
|
|||
};
|
||||
previousIndex |> Belt.Option.flatMap(_, Belt.Array.get(zipped));
|
||||
};
|
||||
|
||||
let findY = (x: float, t: t): float => {
|
||||
let firstHigherIndex =
|
||||
E.A.Sorted.binarySearchFirstElementGreaterIndex(xs(t), x);
|
||||
let n =
|
||||
switch (firstHigherIndex) {
|
||||
| `overMax => maxY(t) |> E.O.default(0.0)
|
||||
| `underMin => minY(t) |> E.O.default(0.0)
|
||||
| `firstHigher(firstHigherIndex) =>
|
||||
let lowerOrEqualIndex =
|
||||
firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1;
|
||||
let needsInterpolation = xs(t)[lowerOrEqualIndex] != x;
|
||||
if (needsInterpolation) {
|
||||
Functions.interpolate(
|
||||
xs(t)[lowerOrEqualIndex],
|
||||
xs(t)[firstHigherIndex],
|
||||
ys(t)[lowerOrEqualIndex],
|
||||
ys(t)[firstHigherIndex],
|
||||
x,
|
||||
);
|
||||
} else {
|
||||
ys(t)[lowerOrEqualIndex];
|
||||
};
|
||||
};
|
||||
n;
|
||||
};
|
||||
|
||||
let findX = (y: float, t: t): float => {
|
||||
module YtoX = {
|
||||
let linear = (y: float, t: t): float => {
|
||||
let firstHigherIndex =
|
||||
E.A.Sorted.binarySearchFirstElementGreaterIndex(ys(t), y);
|
||||
let foundX =
|
||||
|
@ -84,59 +97,77 @@ module T = {
|
|||
| `firstHigher(firstHigherIndex) =>
|
||||
let lowerOrEqualIndex =
|
||||
firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1;
|
||||
let needsInterpolation = ys(t)[lowerOrEqualIndex] != y;
|
||||
let (_xs, _ys) = (xs(t), ys(t));
|
||||
let needsInterpolation = _ys[lowerOrEqualIndex] != y;
|
||||
if (needsInterpolation) {
|
||||
Functions.interpolate(
|
||||
ys(t)[lowerOrEqualIndex],
|
||||
ys(t)[firstHigherIndex],
|
||||
xs(t)[lowerOrEqualIndex],
|
||||
xs(t)[firstHigherIndex],
|
||||
interpolate(
|
||||
_ys[lowerOrEqualIndex],
|
||||
_ys[firstHigherIndex],
|
||||
_xs[lowerOrEqualIndex],
|
||||
_xs[firstHigherIndex],
|
||||
y,
|
||||
);
|
||||
} else {
|
||||
xs(t)[lowerOrEqualIndex];
|
||||
_xs[lowerOrEqualIndex];
|
||||
};
|
||||
};
|
||||
foundX;
|
||||
};
|
||||
|
||||
let convertWithAlternativeXs = (newXs: array(float), t: t): t => {
|
||||
let newYs = Belt.Array.map(newXs, f => findY(f, t));
|
||||
{xs: newXs, ys: newYs};
|
||||
};
|
||||
|
||||
let convertToNewLength = (newLength: int, t: t): DistTypes.xyShape => {
|
||||
Functions.(
|
||||
range(min(xs(t)), max(xs(t)), newLength)
|
||||
|> convertWithAlternativeXs(_, t)
|
||||
);
|
||||
};
|
||||
|
||||
let convertToNewLengthByProbabilityMass =
|
||||
(newLength: int, integral: t, t: t): DistTypes.xyShape => {
|
||||
Functions.range(0.0, 1.0, newLength)
|
||||
|> E.A.fmap(findX(_, integral))
|
||||
|> convertWithAlternativeXs(_, t);
|
||||
};
|
||||
|
||||
module XtoY = {
|
||||
let stepwiseIncremental = (f, t: t) =>
|
||||
firstPairAtOrBeforeValue(f, t) |> E.O.fmap(((_, y)) => y);
|
||||
Pairs.firstAtOrBeforeXValue(f, t) |> E.O.fmap(((_, y)) => y);
|
||||
|
||||
let stepwiseIfAtX = (f: float, t: t) => {
|
||||
getBy(t, ((x: float, _)) => {x == f}) |> E.O.fmap(((_, y)) => y);
|
||||
Pairs.getBy(t, ((x: float, _)) => {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 |> findY(f);
|
||||
let linear = (x: float, t: t): float => {
|
||||
let firstHigherIndex =
|
||||
E.A.Sorted.binarySearchFirstElementGreaterIndex(xs(t), x);
|
||||
let n =
|
||||
switch (firstHigherIndex) {
|
||||
| `overMax => maxY(t) |> E.O.default(0.0)
|
||||
| `underMin => minY(t) |> E.O.default(0.0)
|
||||
| `firstHigher(firstHigherIndex) =>
|
||||
let lowerOrEqualIndex =
|
||||
firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1;
|
||||
let (_xs, _ys) = (xs(t), ys(t));
|
||||
let needsInterpolation = _xs[lowerOrEqualIndex] != x;
|
||||
if (needsInterpolation) {
|
||||
interpolate(
|
||||
_xs[lowerOrEqualIndex],
|
||||
_xs[firstHigherIndex],
|
||||
_ys[lowerOrEqualIndex],
|
||||
_ys[firstHigherIndex],
|
||||
x,
|
||||
);
|
||||
} else {
|
||||
_ys[lowerOrEqualIndex];
|
||||
};
|
||||
};
|
||||
n;
|
||||
};
|
||||
};
|
||||
|
||||
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};
|
||||
let fromZippedArray = (is: array((float, float))): t =>
|
||||
is |> Belt.Array.unzip |> fromArray;
|
||||
module XsConversion = {
|
||||
let replaceWithXs = (newXs: array(float), t: t): t => {
|
||||
let newYs = Belt.Array.map(newXs, f => XtoY.linear(f, t));
|
||||
{xs: newXs, ys: newYs};
|
||||
};
|
||||
|
||||
let proportionEquallyOverX = (newLength: int, t: t): t => {
|
||||
equallyDividedXs(t, newLength) |> replaceWithXs(_, t);
|
||||
};
|
||||
|
||||
let proportionByProbabilityMass = (newLength: int, integral: t, t: t): t => {
|
||||
E.A.Floats.range(0.0, 1.0, newLength)
|
||||
|> E.A.fmap(YtoX.linear(_, integral))
|
||||
|> replaceWithXs(_, t);
|
||||
};
|
||||
};
|
||||
|
||||
module Zipped = {
|
||||
type zipped = array((float, float));
|
||||
|
@ -146,90 +177,33 @@ module T = {
|
|||
t |> E.A.stableSortBy(_, ((x1, _), (x2, _)) => x1 > x2 ? 1 : 0);
|
||||
};
|
||||
|
||||
// TODO: Use faster sort at least, geese.
|
||||
module Combine = {
|
||||
let combineLinear = (t1: t, t2: t, fn: (float, float) => float) => {
|
||||
let allXs = Belt.Array.concat(xs(t1), xs(t2));
|
||||
allXs |> Array.fast_sort(compare);
|
||||
let _allXs = (t1: t, t2: t) => E.A.Sorted.concat(xs(t1), xs(t2));
|
||||
|
||||
let _combineAbstract = (comboAlg, t1: t, t2: t, fn) => {
|
||||
let allXs = _allXs(t1, t2);
|
||||
let allYs =
|
||||
allXs
|
||||
|> E.A.fmap(x => {
|
||||
let y1 = XtoY.linear(x, t1);
|
||||
let y2 = XtoY.linear(x, t2);
|
||||
let y1 = comboAlg(x, t1);
|
||||
let y2 = comboAlg(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.fast_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.fast_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);
|
||||
|
||||
let comparePoints = ((x1: float, y1: float), (x2: float, y2: float)) =>
|
||||
switch (x1 == x2, y1 == y2) {
|
||||
| (false, _) => compare(x1, x2)
|
||||
| (true, false) => compare(y1, y2)
|
||||
| (true, true) => (-1)
|
||||
};
|
||||
let combineLinear = _combineAbstract(XtoY.linear);
|
||||
let combineStepwise = _combineAbstract(XtoY.stepwiseIncremental);
|
||||
let combineIfAtX = _combineAbstract(XtoY.stepwiseIfAtX);
|
||||
|
||||
// TODO: I'd bet this is pretty slow
|
||||
let intersperce = (t1: t, t2: t) => {
|
||||
let items: ref(array((float, float))) = ref([||]);
|
||||
let t1 = zip(t1);
|
||||
let t2 = zip(t2);
|
||||
|
||||
Belt.Array.forEachWithIndex(t1, (i, item) => {
|
||||
switch (Belt.Array.get(t2, i)) {
|
||||
| Some(r) => items := E.A.append(items^, [|item, r|])
|
||||
| None => items := E.A.append(items^, [|item|])
|
||||
}
|
||||
});
|
||||
items^ |> Belt.Array.unzip |> fromArray;
|
||||
let intersperse = (t1: t, t2: t) => {
|
||||
E.A.intersperse(zip(t1), zip(t2)) |> fromZippedArray;
|
||||
};
|
||||
};
|
||||
|
||||
let yFold = (fn, t: t) => {
|
||||
E.A.fold_left(fn, 0., t.ys);
|
||||
};
|
||||
|
||||
let ySum = yFold((a, b) => a +. b);
|
||||
|
||||
let _transverseSimple = fn =>
|
||||
Belt.Array.reduce(_, [||], (items, y) =>
|
||||
switch (E.A.last(items)) {
|
||||
| Some(yLast) => Belt.Array.concat(items, [|fn(y, yLast)|])
|
||||
| None => [|y|]
|
||||
}
|
||||
);
|
||||
|
||||
let _transverse2 = (fn, items) => {
|
||||
module Transversal = {
|
||||
let _transverse = (fn, items) => {
|
||||
let length = items |> E.A.length;
|
||||
let empty = Belt.Array.make(length, items |> E.A.unsafe_get(_, 0));
|
||||
Belt.Array.forEachWithIndex(
|
||||
|
@ -247,37 +221,13 @@ module T = {
|
|||
empty;
|
||||
};
|
||||
|
||||
let _transverseB = (fn, items) => {
|
||||
let (xs, ys) = items |> Belt.Array.unzip;
|
||||
let newYs = _transverse2(fn, ys);
|
||||
Belt.Array.zip(xs, newYs);
|
||||
};
|
||||
|
||||
let _transverse = fn =>
|
||||
Belt.Array.reduce(_, [||], (items, (x, y)) =>
|
||||
switch (E.A.last(items)) {
|
||||
| Some((_, yLast)) =>
|
||||
Belt.Array.concat(items, [|(x, fn(y, yLast))|])
|
||||
| None => [|(x, y)|]
|
||||
}
|
||||
);
|
||||
|
||||
let _transverseShape2 = (fn, p: t) => {
|
||||
Belt.Array.zip(p.xs, p.ys)
|
||||
|> _transverseB(fn)
|
||||
|> Belt.Array.unzip
|
||||
|> fromArray;
|
||||
};
|
||||
|
||||
let _transverseShape = (fn, p: t) => {
|
||||
fromArray((p.xs, _transverse2(fn, p.ys)));
|
||||
fromArray((p.xs, _transverse(fn, p.ys)));
|
||||
};
|
||||
};
|
||||
|
||||
let filter = (fn, t: t) =>
|
||||
t |> zip |> E.A.filter(fn) |> Belt.Array.unzip |> fromArray;
|
||||
|
||||
let accumulateYs = _transverseShape((aCurrent, aLast) => aCurrent +. aLast);
|
||||
let subtractYs = _transverseShape((aCurrent, aLast) => aCurrent -. aLast);
|
||||
let accumulateYs =
|
||||
Transversal._transverseShape((aCurrent, aLast) => aCurrent +. aLast);
|
||||
};
|
||||
|
||||
// I'm really not sure this part is actually what we want at this point.
|
||||
|
@ -286,7 +236,7 @@ module Range = {
|
|||
type zippedRange = ((float, float), (float, float));
|
||||
|
||||
let floatSum = Belt.Array.reduce(_, 0., (a, b) => a +. b);
|
||||
let toT = r => r |> Belt.Array.unzip |> T.fromArray;
|
||||
let toT = T.fromZippedArray;
|
||||
let nextX = ((_, (nextX, _)): zippedRange) => nextX;
|
||||
|
||||
let rangePointAssumingSteps =
|
||||
|
@ -320,6 +270,7 @@ module Range = {
|
|||
let integrateWithTriangles = ({xs, ys}) => {
|
||||
let length = E.A.length(xs);
|
||||
let cumulativeY = Belt.Array.make(length, 0.0);
|
||||
//TODO: I don't think this next line is needed, but definitely check.
|
||||
let _ = Belt.Array.set(cumulativeY, 0, 0.0);
|
||||
for (x in 0 to E.A.length(xs) - 2) {
|
||||
Belt.Array.set(
|
||||
|
@ -343,41 +294,24 @@ module Range = {
|
|||
Some(
|
||||
items
|
||||
|> Belt.Array.map(_, rangePointAssumingSteps)
|
||||
|> Belt.Array.unzip
|
||||
|> T.fromArray
|
||||
|> T.intersperce(t |> T.xMap(e => e +. diff)),
|
||||
|> T.fromZippedArray
|
||||
|> T.Combine.intersperse(t |> T.xMap(e => e +. diff)),
|
||||
)
|
||||
| _ => Some(t)
|
||||
};
|
||||
let bar = items |> E.O.fmap(T.zip) |> E.O.bind(_, E.A.get(_, 0));
|
||||
let items =
|
||||
switch (items, bar) {
|
||||
let first = items |> E.O.fmap(T.zip) |> E.O.bind(_, E.A.get(_, 0));
|
||||
switch (items, first) {
|
||||
| (Some(items), Some((0.0, _))) => Some(items)
|
||||
| (Some(items), Some((firstX, _))) =>
|
||||
let all = E.A.append([|(firstX, 0.0)|], items |> T.zip);
|
||||
let foo = all |> Belt.Array.unzip |> T.fromArray;
|
||||
Some(foo);
|
||||
all |> T.fromZippedArray |> E.O.some;
|
||||
| _ => None
|
||||
};
|
||||
items;
|
||||
};
|
||||
};
|
||||
|
||||
module Ts = {
|
||||
type t = T.ts;
|
||||
let minX = (t: t) =>
|
||||
t |> E.A.fmap(T.minX) |> E.A.O.concatSomes |> Functions.min;
|
||||
let maxX = (t: t) =>
|
||||
t |> E.A.fmap(T.maxX) |> E.A.O.concatSomes |> Functions.max;
|
||||
|
||||
// TODO/Warning: This will break if the shapes are empty.
|
||||
let equallyDividedXs = (t: t, newLength) => {
|
||||
Functions.range(minX(t), maxX(t), newLength);
|
||||
};
|
||||
};
|
||||
|
||||
let combinePointwise = (fn, sampleCount, t1: xyShape, t2: xyShape) => {
|
||||
let xs = Ts.equallyDividedXs([|t1, t2|], sampleCount);
|
||||
let xs = T.Ts.equallyDividedXs([|t1, t2|], sampleCount);
|
||||
let ys =
|
||||
xs |> E.A.fmap(x => fn(T.XtoY.linear(x, t1), T.XtoY.linear(x, t2)));
|
||||
T.fromArrays(xs, ys);
|
||||
|
@ -396,5 +330,5 @@ let logScorePoint = (sampleCount, t1, t2) =>
|
|||
logScoreDist(sampleCount, t1, t2)
|
||||
|> Range.integrateWithTriangles
|
||||
|> E.O.fmap(T.accumulateYs)
|
||||
|> E.O.bind(_, T.last)
|
||||
|> E.O.bind(_, T.Pairs.last)
|
||||
|> E.O.fmap(((_, y)) => y);
|
|
@ -94,7 +94,7 @@ module Lognormal = {
|
|||
let from90PercentCI = (low, high) => {
|
||||
let logLow = Js.Math.log(low);
|
||||
let logHigh = Js.Math.log(high);
|
||||
let mu = Functions.mean([|logLow, logHigh|]);
|
||||
let mu = E.A.Floats.mean([|logLow, logHigh|]);
|
||||
let sigma = (logHigh -. logLow) /. (2.0 *. 1.645);
|
||||
`Lognormal({mu, sigma});
|
||||
};
|
||||
|
@ -189,9 +189,9 @@ module GenericSimple = {
|
|||
let interpolateXs =
|
||||
(~xSelection: [ | `Linear | `ByWeight]=`Linear, dist: dist, sampleCount) => {
|
||||
switch (xSelection) {
|
||||
| `Linear => Functions.range(min(dist), max(dist), sampleCount)
|
||||
| `Linear => E.A.Floats.range(min(dist), max(dist), sampleCount)
|
||||
| `ByWeight =>
|
||||
Functions.range(minCdfValue, maxCdfValue, sampleCount)
|
||||
E.A.Floats.range(minCdfValue, maxCdfValue, sampleCount)
|
||||
|> E.A.fmap(x => inv(x, dist))
|
||||
};
|
||||
};
|
||||
|
@ -208,20 +208,20 @@ module PointwiseAddDistributionsWeighted = {
|
|||
type t = pointwiseAdd;
|
||||
|
||||
let normalizeWeights = (dists: t) => {
|
||||
let total = dists |> E.A.fmap(snd) |> Functions.sum;
|
||||
let total = dists |> E.A.fmap(snd) |> E.A.Floats.sum;
|
||||
dists |> E.A.fmap(((a, b)) => (a, b /. total));
|
||||
};
|
||||
|
||||
let pdf = (dists: t, x: float) =>
|
||||
dists
|
||||
|> E.A.fmap(((e, w)) => GenericSimple.pdf(x, e) *. w)
|
||||
|> Functions.sum;
|
||||
|> E.A.Floats.sum;
|
||||
|
||||
let min = (dists: t) =>
|
||||
dists |> E.A.fmap(d => d |> fst |> GenericSimple.min) |> Functions.min;
|
||||
dists |> E.A.fmap(d => d |> fst |> GenericSimple.min) |> E.A.min;
|
||||
|
||||
let max = (dists: t) =>
|
||||
dists |> E.A.fmap(d => d |> fst |> GenericSimple.max) |> Functions.max;
|
||||
dists |> E.A.fmap(d => d |> fst |> GenericSimple.max) |> E.A.max;
|
||||
|
||||
let toShape = (dists: t, sampleCount: int) => {
|
||||
let xs =
|
||||
|
|
|
@ -249,6 +249,12 @@ module A = {
|
|||
let fold_right = Array.fold_right;
|
||||
let concatMany = Belt.Array.concatMany;
|
||||
let keepMap = Belt.Array.keepMap;
|
||||
let min = a =>
|
||||
get(a, 0)
|
||||
|> O.fmap(first => Belt.Array.reduce(a, first, (i, j) => i < j ? i : j));
|
||||
let max = a =>
|
||||
get(a, 0)
|
||||
|> O.fmap(first => Belt.Array.reduce(a, first, (i, j) => i > j ? i : j));
|
||||
let stableSortBy = Belt.SortArray.stableSortBy;
|
||||
let toRanges = (a: array('a)) =>
|
||||
switch (a |> Belt.Array.length) {
|
||||
|
@ -270,6 +276,19 @@ module A = {
|
|||
/* TODO: Is there a better way of doing this? */
|
||||
let uniq = r => asList(L.uniq, r);
|
||||
|
||||
//intersperse([1,2,3], [10,11,12]) => [1,10,2,11,3,12]
|
||||
let intersperse = (a: array('a), b: array('a)) => {
|
||||
let items: ref(array('a)) = ref([||]);
|
||||
|
||||
Belt.Array.forEachWithIndex(a, (i, item) => {
|
||||
switch (Belt.Array.get(b, i)) {
|
||||
| Some(r) => items := append(items^, [|item, r|])
|
||||
| None => items := append(items^, [|item|])
|
||||
}
|
||||
});
|
||||
items^;
|
||||
};
|
||||
|
||||
// @todo: Is -1 still the indicator that this is false (as is true with
|
||||
// @todo: js findIndex)? Wasn't sure.
|
||||
let findIndex = (e, i) =>
|
||||
|
@ -314,6 +333,13 @@ module A = {
|
|||
};
|
||||
|
||||
module Sorted = {
|
||||
let min = first;
|
||||
let max = last;
|
||||
let range = (~min=min, ~max=max, a) =>
|
||||
switch (min(a), max(a)) {
|
||||
| (Some(min), Some(max)) => Some(max -. min)
|
||||
| _ => None
|
||||
};
|
||||
let binarySearchFirstElementGreaterIndex = (ar: array('a), el: 'a) => {
|
||||
let el = Belt.SortArray.binarySearchBy(ar, el, compare);
|
||||
let el = el < 0 ? el * (-1) - 1 : el;
|
||||
|
@ -323,9 +349,24 @@ module A = {
|
|||
| e => `firstHigher(e)
|
||||
};
|
||||
};
|
||||
|
||||
let concat = (t1: array('a), t2: array('a)) => {
|
||||
let ts = Belt.Array.concat(t1, t2);
|
||||
ts |> Array.fast_sort(compare);
|
||||
ts;
|
||||
};
|
||||
|
||||
module Floats = {
|
||||
let makeIncrementalUp = (a, b) =>
|
||||
Array.make(b - a + 1, a)
|
||||
|> Array.mapi((i, c) => c + i)
|
||||
|> Belt.Array.map(_, float_of_int);
|
||||
|
||||
let makeIncrementalDown = (a, b) =>
|
||||
Array.make(a - b + 1, a)
|
||||
|> Array.mapi((i, c) => c - i)
|
||||
|> Belt.Array.map(_, float_of_int);
|
||||
|
||||
let split = (sortedArray: array(float)) => {
|
||||
let continuous = [||];
|
||||
let discrete = FloatFloatMap.empty();
|
||||
|
@ -357,6 +398,29 @@ module A = {
|
|||
(continuous, discrete);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
module Floats = {
|
||||
let sum = Belt.Array.reduce(_, 0., (i, j) => i +. j);
|
||||
let mean = a => sum(a) /. (Array.length(a) |> float_of_int);
|
||||
let random = Js.Math.random_int;
|
||||
|
||||
exception RangeError(string);
|
||||
let range = (min: float, max: float, n: int): array(float) => {
|
||||
switch (n) {
|
||||
| 0 => [||]
|
||||
| 1 => [|min|]
|
||||
| 2 => [|min, max|]
|
||||
| _ when min == max => Belt.Array.make(n, min)
|
||||
| _ when n < 0 => raise(RangeError("n must be greater than 0"))
|
||||
| _ when min > max =>
|
||||
raise(RangeError("Min value is less then max value"))
|
||||
| _ =>
|
||||
let diff = (max -. min) /. Belt.Float.fromInt(n - 1);
|
||||
Belt.Array.makeBy(n, i => {min +. Belt.Float.fromInt(i) *. diff});
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
module JsArray = {
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
module type Config = {let shape: DistTypes.xyShape;};
|
||||
|
||||
exception ShapeWrong(string);
|
||||
|
||||
let order = (shape: DistTypes.xyShape): DistTypes.xyShape => {
|
||||
let xy =
|
||||
shape.xs
|
||||
|> Array.mapi((i, x) => [x, shape.ys |> Array.get(_, i)])
|
||||
|> Belt.SortArray.stableSortBy(_, ([a, _], [b, _]) => a > b ? 1 : (-1));
|
||||
{
|
||||
xs: xy |> Array.map(([x, _]) => x),
|
||||
ys: xy |> Array.map(([_, y]) => y),
|
||||
};
|
||||
};
|
||||
|
||||
module Make = (Config: Config) => {
|
||||
let xs = Config.shape.xs;
|
||||
let ys = Config.shape.ys;
|
||||
let get = Array.get;
|
||||
let len = Array.length;
|
||||
|
||||
let validateHasLength = (): bool => len(xs) > 0;
|
||||
let validateSize = (): bool => len(xs) == len(ys);
|
||||
if (!validateHasLength()) {
|
||||
raise(ShapeWrong("You need at least one element."));
|
||||
};
|
||||
if (!validateSize()) {
|
||||
raise(ShapeWrong("Arrays of \"xs\" and \"ys\" have different sizes."));
|
||||
};
|
||||
if (!Belt.SortArray.isSorted(xs, (a, b) => a > b ? 1 : (-1))) {
|
||||
raise(ShapeWrong("Arrays of \"xs\" and \"ys\" have different sizes."));
|
||||
};
|
||||
let minX = () => get(xs, 0);
|
||||
let maxX = () => get(xs, len(xs) - 1);
|
||||
let minY = () => get(ys, 0);
|
||||
let maxY = () => get(ys, len(ys) - 1);
|
||||
let findY = (x: float): float => {
|
||||
let firstHigherIndex =
|
||||
E.A.Sorted.binarySearchFirstElementGreaterIndex(xs, x);
|
||||
switch (firstHigherIndex) {
|
||||
| `overMax => maxY()
|
||||
| `underMin => minY()
|
||||
| `firstHigher(firstHigherIndex) =>
|
||||
let lowerOrEqualIndex =
|
||||
firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1;
|
||||
let needsInterpolation = get(xs, lowerOrEqualIndex) != x;
|
||||
if (needsInterpolation) {
|
||||
Functions.interpolate(
|
||||
get(xs, lowerOrEqualIndex),
|
||||
get(xs, firstHigherIndex),
|
||||
get(ys, lowerOrEqualIndex),
|
||||
get(ys, firstHigherIndex),
|
||||
x,
|
||||
);
|
||||
} else {
|
||||
ys[lowerOrEqualIndex];
|
||||
};
|
||||
};
|
||||
};
|
||||
let findX = (y: float): float => {
|
||||
let firstHigherIndex =
|
||||
E.A.Sorted.binarySearchFirstElementGreaterIndex(ys, y);
|
||||
switch (firstHigherIndex) {
|
||||
| `overMax => maxX()
|
||||
| `underMin => minX()
|
||||
| `firstHigher(firstHigherIndex) =>
|
||||
let lowerOrEqualIndex =
|
||||
firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1;
|
||||
let needsInterpolation = get(ys, lowerOrEqualIndex) != y;
|
||||
if (needsInterpolation) {
|
||||
Functions.interpolate(
|
||||
get(ys, lowerOrEqualIndex),
|
||||
get(ys, firstHigherIndex),
|
||||
get(xs, lowerOrEqualIndex),
|
||||
get(xs, firstHigherIndex),
|
||||
y,
|
||||
);
|
||||
} else {
|
||||
xs[lowerOrEqualIndex];
|
||||
};
|
||||
};
|
||||
};
|
||||
let convertWithAlternativeXs = (newXs: array(float)): DistTypes.xyShape => {
|
||||
let newYs = Belt.Array.map(newXs, findY);
|
||||
{xs: newXs, ys: newYs};
|
||||
};
|
||||
let convertToNewLength = (newLength: int): DistTypes.xyShape => {
|
||||
Functions.(
|
||||
range(min(xs), max(xs), newLength) |> convertWithAlternativeXs
|
||||
);
|
||||
};
|
||||
let sampleSingle = (): float => Js.Math.random() |> findY;
|
||||
let sample = (size: int): array(float) =>
|
||||
Belt.Array.makeBy(size, i => sampleSingle());
|
||||
let integral = () => {
|
||||
Belt.Array.reduceWithIndex(ys, 0., (integral, y, i) => {
|
||||
switch (i) {
|
||||
| 0 => integral
|
||||
| _ =>
|
||||
let thisY = y;
|
||||
let lastY = get(ys, i - 1);
|
||||
let thisX = get(xs, i);
|
||||
let lastX = get(xs, i - 1);
|
||||
let sectionInterval = (thisY +. lastY) /. 2. *. (thisX -. lastX);
|
||||
integral +. sectionInterval;
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
|
@ -1,5 +1,3 @@
|
|||
exception RangeWrong(string);
|
||||
|
||||
let interpolate =
|
||||
(xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float)
|
||||
: float => {
|
||||
|
@ -7,30 +5,3 @@ let interpolate =
|
|||
let maxProportion = (xIntended -. xMin) /. (xMax -. xMin);
|
||||
yMin *. minProportion +. yMax *. maxProportion;
|
||||
};
|
||||
|
||||
let sum = Belt.Array.reduce(_, 0., (i, j) => i +. j);
|
||||
let mean = a => sum(a) /. (Array.length(a) |> float_of_int);
|
||||
let min = a => Belt.Array.reduce(a, a[0], (i, j) => i < j ? i : j);
|
||||
let max = a => Belt.Array.reduce(a, a[0], (i, j) => i > j ? i : j);
|
||||
let up = (a, b) =>
|
||||
Array.make(b - a + 1, a)
|
||||
|> Array.mapi((i, c) => c + i)
|
||||
|> Belt.Array.map(_, float_of_int);
|
||||
let down = (a, b) =>
|
||||
Array.make(a - b + 1, a)
|
||||
|> Array.mapi((i, c) => c - i)
|
||||
|> Belt.Array.map(_, float_of_int);
|
||||
let range = (min: float, max: float, n: int): array(float) => {
|
||||
switch (n) {
|
||||
| 0 => [||]
|
||||
| 1 => [|min|]
|
||||
| 2 => [|min, max|]
|
||||
| _ when min == max => Belt.Array.make(n, min)
|
||||
| _ when n < 0 => raise(RangeWrong("n is less then zero"))
|
||||
| _ when min > max => raise(RangeWrong("Min values is less then max"))
|
||||
| _ =>
|
||||
let diff = (max -. min) /. Belt.Float.fromInt(n - 1);
|
||||
Belt.Array.makeBy(n, i => {min +. Belt.Float.fromInt(i) *. diff});
|
||||
};
|
||||
};
|
||||
let random = Js.Math.random_int;
|
||||
|
|
Loading…
Reference in New Issue
Block a user