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 */
|
|
@ -1,174 +1,170 @@
|
|||
const {
|
||||
Cdf,
|
||||
Pdf,
|
||||
ContinuousDistribution,
|
||||
ContinuousDistributionCombination,
|
||||
scoringFunctions,
|
||||
} = require("@foretold/cdf/lib");
|
||||
const _ = require("lodash");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {{ys: *, xs: *}}
|
||||
*/
|
||||
function cdfToPdf({ xs, ys }) {
|
||||
let cdf = new Cdf(xs, ys);
|
||||
let pdf = cdf.toPdf();
|
||||
return { xs: pdf.xs, ys: pdf.ys };
|
||||
}
|
||||
Cdf,
|
||||
Pdf,
|
||||
ContinuousDistribution,
|
||||
ContinuousDistributionCombination,
|
||||
scoringFunctions,
|
||||
} = require("@foretold/cdf/lib");
|
||||
const _ = require("lodash");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {{ys: *, xs: *}}
|
||||
*/
|
||||
function pdfToCdf({ xs, ys }) {
|
||||
let cdf = new Pdf(xs, ys);
|
||||
let pdf = cdf.toCdf();
|
||||
return { xs: pdf.xs, ys: pdf.ys };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sampleCount
|
||||
* @param vars
|
||||
* @returns {{ys: *, xs: *}}
|
||||
*/
|
||||
function mean(sampleCount, vars) {
|
||||
let cdfs = vars.map(r => new Cdf(r.xs, r.ys));
|
||||
let comb = new ContinuousDistributionCombination(cdfs);
|
||||
let newCdf = comb.combineYsWithMean(sampleCount);
|
||||
|
||||
return { xs: newCdf.xs, ys: newCdf.ys };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sampleCount
|
||||
* @param predictionCdf
|
||||
* @param resolutionCdf
|
||||
*/
|
||||
function scoreNonMarketCdfCdf(sampleCount, predictionCdf, resolutionCdf, resolutionUniformAdditionWeight=0) {
|
||||
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
||||
let prediction = toCdf(predictionCdf);
|
||||
if (_.isFinite(resolutionUniformAdditionWeight)){
|
||||
prediction = prediction.combineWithUniformOfCdf(
|
||||
{
|
||||
cdf: toCdf(resolutionCdf),
|
||||
uniformWeight: resolutionUniformAdditionWeight,
|
||||
sampleCount
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return scoringFunctions.distributionInputDistributionOutputMarketless({
|
||||
predictionCdf: prediction,
|
||||
resultCdf: toCdf(resolutionCdf),
|
||||
sampleCount,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sampleCount
|
||||
* @param cdf
|
||||
*/
|
||||
function differentialEntropy(sampleCount, cdf) {
|
||||
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
||||
|
||||
return scoringFunctions.differentialEntropy({
|
||||
cdf: toCdf(cdf),
|
||||
sampleCount: sampleCount
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number}
|
||||
*/
|
||||
function findY(x, { xs, ys }) {
|
||||
let cdf = new Cdf(xs, ys);
|
||||
return cdf.findY(x);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {{ys: *, xs: *}}
|
||||
*/
|
||||
function cdfToPdf({ xs, ys }) {
|
||||
let cdf = new Cdf(xs, ys);
|
||||
let pdf = cdf.toPdf();
|
||||
return { xs: pdf.xs, ys: pdf.ys };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number[]}
|
||||
*/
|
||||
function convertToNewLength(n, { xs, ys }) {
|
||||
let dist = new ContinuousDistribution(xs, ys);
|
||||
return dist.convertToNewLength(n);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param y
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number}
|
||||
*/
|
||||
function findX(y, { xs, ys }) {
|
||||
let cdf = new Cdf(xs, ys);
|
||||
return cdf.findX(y);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number[]}
|
||||
*/
|
||||
function integral({ xs, ys }) {
|
||||
if (_.includes(ys, NaN)){
|
||||
return NaN;
|
||||
}
|
||||
else if (_.includes(ys, Infinity) && _.includes(ys, -Infinity)){
|
||||
return NaN;
|
||||
}
|
||||
else if (_.includes(ys, Infinity)){
|
||||
return Infinity;
|
||||
}
|
||||
else if (_.includes(ys, -Infinity)){
|
||||
return -Infinity;
|
||||
}
|
||||
|
||||
let integral = 0;
|
||||
for (let i = 1; i < ys.length; i++) {
|
||||
let thisY = ys[i];
|
||||
let lastY = ys[i - 1];
|
||||
let thisX = xs[i];
|
||||
let lastX = xs[i - 1];
|
||||
|
||||
if (
|
||||
_.isFinite(thisY) && _.isFinite(lastY) &&
|
||||
_.isFinite(thisX) && _.isFinite(lastX)
|
||||
) {
|
||||
let sectionInterval = ((thisY + lastY) / 2) * (thisX - lastX);
|
||||
integral = integral + sectionInterval;
|
||||
/**
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {{ys: *, xs: *}}
|
||||
*/
|
||||
function pdfToCdf({ xs, ys }) {
|
||||
let cdf = new Pdf(xs, ys);
|
||||
let pdf = cdf.toCdf();
|
||||
return { xs: pdf.xs, ys: pdf.ys };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sampleCount
|
||||
* @param vars
|
||||
* @returns {{ys: *, xs: *}}
|
||||
*/
|
||||
function mean(sampleCount, vars) {
|
||||
let cdfs = vars.map(r => new Cdf(r.xs, r.ys));
|
||||
let comb = new ContinuousDistributionCombination(cdfs);
|
||||
let newCdf = comb.combineYsWithMean(sampleCount);
|
||||
|
||||
return { xs: newCdf.xs, ys: newCdf.ys };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sampleCount
|
||||
* @param predictionCdf
|
||||
* @param resolutionCdf
|
||||
*/
|
||||
function scoreNonMarketCdfCdf(sampleCount, predictionCdf, resolutionCdf, resolutionUniformAdditionWeight = 0) {
|
||||
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
||||
let prediction = toCdf(predictionCdf);
|
||||
if (_.isFinite(resolutionUniformAdditionWeight)) {
|
||||
prediction = prediction.combineWithUniformOfCdf(
|
||||
{
|
||||
cdf: toCdf(resolutionCdf),
|
||||
uniformWeight: resolutionUniformAdditionWeight,
|
||||
sampleCount
|
||||
}
|
||||
|
||||
}
|
||||
return integral;
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cdfToPdf,
|
||||
pdfToCdf,
|
||||
findY,
|
||||
findX,
|
||||
convertToNewLength,
|
||||
mean,
|
||||
scoreNonMarketCdfCdf,
|
||||
differentialEntropy,
|
||||
integral,
|
||||
};
|
||||
|
||||
|
||||
return scoringFunctions.distributionInputDistributionOutputMarketless({
|
||||
predictionCdf: prediction,
|
||||
resultCdf: toCdf(resolutionCdf),
|
||||
sampleCount,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sampleCount
|
||||
* @param cdf
|
||||
*/
|
||||
function differentialEntropy(sampleCount, cdf) {
|
||||
let toCdf = (r) => (new Cdf(r.xs, r.ys));
|
||||
|
||||
return scoringFunctions.differentialEntropy({
|
||||
cdf: toCdf(cdf),
|
||||
sampleCount: sampleCount
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number}
|
||||
*/
|
||||
function findY(x, { xs, ys }) {
|
||||
let cdf = new Cdf(xs, ys);
|
||||
return cdf.findY(x);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number[]}
|
||||
*/
|
||||
function convertToNewLength(n, { xs, ys }) {
|
||||
let dist = new ContinuousDistribution(xs, ys);
|
||||
return dist.convertToNewLength(n);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param y
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number}
|
||||
*/
|
||||
function findX(y, { xs, ys }) {
|
||||
let cdf = new Cdf(xs, ys);
|
||||
return cdf.findX(y);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @returns {number[]}
|
||||
*/
|
||||
function integral({ xs, ys }) {
|
||||
if (_.includes(ys, NaN)) {
|
||||
return NaN;
|
||||
} else if (_.includes(ys, Infinity) && _.includes(ys, -Infinity)) {
|
||||
return NaN;
|
||||
} else if (_.includes(ys, Infinity)) {
|
||||
return Infinity;
|
||||
} else if (_.includes(ys, -Infinity)) {
|
||||
return -Infinity;
|
||||
}
|
||||
|
||||
let integral = 0;
|
||||
for (let i = 1; i < ys.length; i++) {
|
||||
let thisY = ys[i];
|
||||
let lastY = ys[i - 1];
|
||||
let thisX = xs[i];
|
||||
let lastX = xs[i - 1];
|
||||
|
||||
if (
|
||||
_.isFinite(thisY) && _.isFinite(lastY) &&
|
||||
_.isFinite(thisX) && _.isFinite(lastX)
|
||||
) {
|
||||
let sectionInterval = ((thisY + lastY) / 2) * (thisX - lastX);
|
||||
integral = integral + sectionInterval;
|
||||
}
|
||||
|
||||
}
|
||||
return integral;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cdfToPdf,
|
||||
pdfToCdf,
|
||||
findY,
|
||||
findX,
|
||||
convertToNewLength,
|
||||
mean,
|
||||
scoreNonMarketCdfCdf,
|
||||
differentialEntropy,
|
||||
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