First attempt at adding dist functionality

This commit is contained in:
Ozzie Gooen 2020-02-13 11:29:06 +00:00
parent 71f3c6290d
commit 5046a04c40
9 changed files with 815 additions and 63 deletions

View File

@ -22,6 +22,8 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@foretold/cdf": "^1.0.14",
"@foretold/guesstimator": "^1.0.10",
"antd": "3.17.0", "antd": "3.17.0",
"autoprefixer": "^9.7.4", "autoprefixer": "^9.7.4",
"bs-ant-design-alt": "2.0.0-alpha.31", "bs-ant-design-alt": "2.0.0-alpha.31",

View File

@ -120,7 +120,7 @@ module TypeWithMetadata = {
let currentYear = let currentYear =
make( make(
~id="currentYear", ~id="currentYear",
~name="Current Year", ~name="Current Day",
~description=None, ~description=None,
~type_= ~type_=
DateTime({ DateTime({

4
src/lib/Types.re Normal file
View File

@ -0,0 +1,4 @@
type distribution = {
xs: array(float),
ys: array(float),
};

View File

@ -166,8 +166,8 @@ module Interface = {
let model: Prop.Model.t = let model: Prop.Model.t =
Prop.{ Prop.{
name: "EA Funds: Donations & Payouts", name: "CEA Funds: Donations & Payouts",
description: "Calculate the payments and payouts of EA Funds based on existing data.", description: "Calculate the payments and payouts of CEA Funds based on existing data.",
version: "1.0.0", version: "1.0.0",
author: "Ozzie Gooen", author: "Ozzie Gooen",
inputTypes: [| inputTypes: [|

160
src/utility/CdfLibrary.js Normal file
View File

@ -0,0 +1,160 @@
const {
Cdf,
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 };
}
/**
*
* @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 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,
mean,
scoreNonMarketCdfCdf,
differentialEntropy,
integral,
};

56
src/utility/CdfLibrary.re Normal file
View File

@ -0,0 +1,56 @@
module JS = {
[@bs.deriving abstract]
type distJs = {
xs: array(float),
ys: array(float),
};
let distToJs = (d: Types.distribution) => distJs(~xs=d.xs, ~ys=d.ys);
let jsToDist = (d: distJs): Types.distribution => {
xs: xsGet(d),
ys: ysGet(d),
};
let doAsDist = (f, d: Types.distribution) => d |> distToJs |> f |> jsToDist;
[@bs.module "./CdfLibraryImporter.js"]
external cdfToPdf: distJs => distJs = "cdfToPdf";
[@bs.module "./CdfLibraryImporter.js"]
external pdfToCdf: distJs => distJs = "pdfToCdf";
[@bs.module "./CdfLibraryImporter.js"]
external findY: (float, distJs) => float = "findY";
[@bs.module "./CdfLibraryImporter.js"]
external findX: (float, distJs) => float = "findX";
[@bs.module "./CdfLibraryImporter.js"]
external integral: distJs => float = "integral";
[@bs.module "./CdfLibraryImporter.js"]
external differentialEntropy: (int, distJs) => distJs =
"differentialEntropy";
[@bs.module "./CdfLibraryImporter.js"]
external scoreNonMarketCdfCdf: (int, distJs, distJs, float) => distJs =
"scoreNonMarketCdfCdf";
[@bs.module "./GuesstimatorLibrary.js"]
external toGuesstimator: (string, int) => distJs = "run";
};
module Distribution = {
let toPdf = dist => dist |> JS.doAsDist(JS.cdfToPdf);
let toCdf = dist => dist |> JS.doAsDist(JS.cdfToPdf);
let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y);
let findY = (x, dist) => dist |> JS.distToJs |> JS.findY(x);
let fromString = (str: string, sampleCount: int) =>
JS.toGuesstimator(str, sampleCount) |> JS.jsToDist;
let integral = dist => dist |> JS.distToJs |> JS.integral;
let differentialEntropy = (maxCalculationLength, dist) =>
dist
|> JS.doAsDist(JS.differentialEntropy(maxCalculationLength))
|> integral;
};

View File

@ -0,0 +1,46 @@
import { Guesstimator } from '@foretold/guesstimator';
import { Samples } from '@foretold/cdf';
const toPdf = (values, min, max) => {
const samples = new Samples(values);
const ratioSize$ = ratioSize(samples);
const width = ratioSize$ === 'SMALL' ? 20 : 1;
const pdf = samples.toPdf({ size: 1000, width, min, max });
return {ys:pdf.ys, xs:pdf.xs};
};
let run = (text, sampleCount, inputs=[], min=false, max=false) => {
let [_error, item] = Guesstimator.parse({ text });
const { parsedInput } = item;
const { guesstimateType } = parsedInput;
const guesstimator = new Guesstimator({ parsedInput });
const value = guesstimator.sample(
sampleCount,
inputs,
);
const samplerType = guesstimator.samplerType();
const values = _.filter(value.values, _.isFinite);
this.setState({
value: event.target.value,
items: values,
});
let update;
if (values.length === 0) {
update = {xs: [], ys: []};
} else if (values.length === 1) {
update = {xs: [], ys: []};
} else {
update = toPdf(values, min, max);
}
return update;
}
module.exports = {
run,
};

View File

@ -0,0 +1,2 @@
// [@bs.module "./GuesstimatorLibrary.js"]
/* external toGuesstimator: (string, int) => CdfLibrary.JS.distJs = "run"*/

600
yarn.lock

File diff suppressed because it is too large Load Diff