Merge branch 'master' of github.com:foretold-app/estiband
* 'master' of github.com:foretold-app/estiband: (32 commits) Fixes CdfLibrary.js Fixes CdfLibrary.js Adds integral function Adds integral function Adds tests Adds tests FindX tests FindY tests (2) FindY tests Renames CDFunctor Findx FindY FindY Adds tests (5) Adds tests (4) Adds tests (3) Adds tests (2) Adds tests Adds a "range" function Fixes file link ...
This commit is contained in:
commit
eece6cf95e
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 */
|
|
|
@ -4,57 +4,57 @@ const {
|
||||||
ContinuousDistribution,
|
ContinuousDistribution,
|
||||||
ContinuousDistributionCombination,
|
ContinuousDistributionCombination,
|
||||||
scoringFunctions,
|
scoringFunctions,
|
||||||
} = require("@foretold/cdf/lib");
|
} = require("@foretold/cdf/lib");
|
||||||
const _ = require("lodash");
|
const _ = require("lodash");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param xs
|
* @param xs
|
||||||
* @param ys
|
* @param ys
|
||||||
* @returns {{ys: *, xs: *}}
|
* @returns {{ys: *, xs: *}}
|
||||||
*/
|
*/
|
||||||
function cdfToPdf({ xs, ys }) {
|
function cdfToPdf({ xs, ys }) {
|
||||||
let cdf = new Cdf(xs, ys);
|
let cdf = new Cdf(xs, ys);
|
||||||
let pdf = cdf.toPdf();
|
let pdf = cdf.toPdf();
|
||||||
return { xs: pdf.xs, ys: pdf.ys };
|
return { xs: pdf.xs, ys: pdf.ys };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param xs
|
* @param xs
|
||||||
* @param ys
|
* @param ys
|
||||||
* @returns {{ys: *, xs: *}}
|
* @returns {{ys: *, xs: *}}
|
||||||
*/
|
*/
|
||||||
function pdfToCdf({ xs, ys }) {
|
function pdfToCdf({ xs, ys }) {
|
||||||
let cdf = new Pdf(xs, ys);
|
let cdf = new Pdf(xs, ys);
|
||||||
let pdf = cdf.toCdf();
|
let pdf = cdf.toCdf();
|
||||||
return { xs: pdf.xs, ys: pdf.ys };
|
return { xs: pdf.xs, ys: pdf.ys };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param sampleCount
|
* @param sampleCount
|
||||||
* @param vars
|
* @param vars
|
||||||
* @returns {{ys: *, xs: *}}
|
* @returns {{ys: *, xs: *}}
|
||||||
*/
|
*/
|
||||||
function mean(sampleCount, vars) {
|
function mean(sampleCount, vars) {
|
||||||
let cdfs = vars.map(r => new Cdf(r.xs, r.ys));
|
let cdfs = vars.map(r => new Cdf(r.xs, r.ys));
|
||||||
let comb = new ContinuousDistributionCombination(cdfs);
|
let comb = new ContinuousDistributionCombination(cdfs);
|
||||||
let newCdf = comb.combineYsWithMean(sampleCount);
|
let newCdf = comb.combineYsWithMean(sampleCount);
|
||||||
|
|
||||||
return { xs: newCdf.xs, ys: newCdf.ys };
|
return { xs: newCdf.xs, ys: newCdf.ys };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param sampleCount
|
* @param sampleCount
|
||||||
* @param predictionCdf
|
* @param predictionCdf
|
||||||
* @param resolutionCdf
|
* @param resolutionCdf
|
||||||
*/
|
*/
|
||||||
function scoreNonMarketCdfCdf(sampleCount, predictionCdf, resolutionCdf, resolutionUniformAdditionWeight=0) {
|
function scoreNonMarketCdfCdf(sampleCount, predictionCdf, resolutionCdf, resolutionUniformAdditionWeight = 0) {
|
||||||
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
||||||
let prediction = toCdf(predictionCdf);
|
let prediction = toCdf(predictionCdf);
|
||||||
if (_.isFinite(resolutionUniformAdditionWeight)){
|
if (_.isFinite(resolutionUniformAdditionWeight)) {
|
||||||
prediction = prediction.combineWithUniformOfCdf(
|
prediction = prediction.combineWithUniformOfCdf(
|
||||||
{
|
{
|
||||||
cdf: toCdf(resolutionCdf),
|
cdf: toCdf(resolutionCdf),
|
||||||
|
@ -69,75 +69,72 @@ const {
|
||||||
resultCdf: toCdf(resolutionCdf),
|
resultCdf: toCdf(resolutionCdf),
|
||||||
sampleCount,
|
sampleCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param sampleCount
|
* @param sampleCount
|
||||||
* @param cdf
|
* @param cdf
|
||||||
*/
|
*/
|
||||||
function differentialEntropy(sampleCount, cdf) {
|
function differentialEntropy(sampleCount, cdf) {
|
||||||
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
||||||
|
|
||||||
return scoringFunctions.differentialEntropy({
|
return scoringFunctions.differentialEntropy({
|
||||||
cdf: toCdf(cdf),
|
cdf: toCdf(cdf),
|
||||||
sampleCount: sampleCount
|
sampleCount: sampleCount
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param x
|
* @param x
|
||||||
* @param xs
|
* @param xs
|
||||||
* @param ys
|
* @param ys
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
function findY(x, { xs, ys }) {
|
function findY(x, { xs, ys }) {
|
||||||
let cdf = new Cdf(xs, ys);
|
let cdf = new Cdf(xs, ys);
|
||||||
return cdf.findY(x);
|
return cdf.findY(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param x
|
* @param x
|
||||||
* @param xs
|
* @param xs
|
||||||
* @param ys
|
* @param ys
|
||||||
* @returns {number[]}
|
* @returns {number[]}
|
||||||
*/
|
*/
|
||||||
function convertToNewLength(n, { xs, ys }) {
|
function convertToNewLength(n, { xs, ys }) {
|
||||||
let dist = new ContinuousDistribution(xs, ys);
|
let dist = new ContinuousDistribution(xs, ys);
|
||||||
return dist.convertToNewLength(n);
|
return dist.convertToNewLength(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param y
|
* @param y
|
||||||
* @param xs
|
* @param xs
|
||||||
* @param ys
|
* @param ys
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
function findX(y, { xs, ys }) {
|
function findX(y, { xs, ys }) {
|
||||||
let cdf = new Cdf(xs, ys);
|
let cdf = new Cdf(xs, ys);
|
||||||
return cdf.findX(y);
|
return cdf.findX(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param xs
|
* @param xs
|
||||||
* @param ys
|
* @param ys
|
||||||
* @returns {number[]}
|
* @returns {number[]}
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,9 +155,9 @@ const {
|
||||||
|
|
||||||
}
|
}
|
||||||
return integral;
|
return integral;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
cdfToPdf,
|
cdfToPdf,
|
||||||
pdfToCdf,
|
pdfToCdf,
|
||||||
findY,
|
findY,
|
||||||
|
@ -170,5 +167,4 @@ const {
|
||||||
scoreNonMarketCdfCdf,
|
scoreNonMarketCdfCdf,
|
||||||
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