commit
3f901a1102
179
__tests__/CDF__Test.re
Normal file
179
__tests__/CDF__Test.re
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
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.)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
92
__tests__/Functions__Test.re
Normal file
92
__tests__/Functions__Test.re
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
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.)|])
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,11 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require("react");
|
|
||||||
var ReactDOMRe = require("reason-react/src/ReactDOMRe.js");
|
|
||||||
var App$ProbExample = require("./App.bs.js");
|
|
||||||
|
|
||||||
((import('./styles/index.css')));
|
|
||||||
|
|
||||||
ReactDOMRe.renderToElementWithId(React.createElement(App$ProbExample.make, { }), "app");
|
|
||||||
|
|
||||||
/* Not a pure module */
|
|
|
@ -130,14 +130,11 @@ const {
|
||||||
function integral({ xs, ys }) {
|
function integral({ xs, ys }) {
|
||||||
if (_.includes(ys, NaN)) {
|
if (_.includes(ys, NaN)) {
|
||||||
return NaN;
|
return NaN;
|
||||||
}
|
} else if (_.includes(ys, Infinity) && _.includes(ys, -Infinity)) {
|
||||||
else if (_.includes(ys, Infinity) && _.includes(ys, -Infinity)){
|
|
||||||
return NaN;
|
return NaN;
|
||||||
}
|
} else if (_.includes(ys, Infinity)) {
|
||||||
else if (_.includes(ys, Infinity)){
|
|
||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
} else if (_.includes(ys, -Infinity)) {
|
||||||
else if (_.includes(ys, -Infinity)){
|
|
||||||
return -Infinity;
|
return -Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,4 +168,3 @@ const {
|
||||||
differentialEntropy,
|
differentialEntropy,
|
||||||
integral,
|
integral,
|
||||||
};
|
};
|
||||||
|
|
107
src/utility/lib/CDF.re
Normal file
107
src/utility/lib/CDF.re
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
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 = Belt.Array.getIndexBy(xs, e => e >= x);
|
||||||
|
switch (firstHigherIndex) {
|
||||||
|
| None => maxY()
|
||||||
|
| Some(0) => minY()
|
||||||
|
| Some(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 = Belt.Array.getIndexBy(ys, e => e >= y);
|
||||||
|
switch (firstHigherIndex) {
|
||||||
|
| None => maxX()
|
||||||
|
| Some(0) => minX()
|
||||||
|
| Some(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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
36
src/utility/lib/Functions.re
Normal file
36
src/utility/lib/Functions.re
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
exception RangeWrong(string);
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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