squiggle/src/utility/GuesstimatorLibrary.js

88 lines
2.3 KiB
JavaScript
Raw Normal View History

import { Guesstimator } from '@foretold/guesstimator';
import { Samples } from '@foretold/cdf';
import _ from 'lodash';
/**
*
* @param {number} minValue
* @param {number} maxValue
* @returns {string}
*/
const minMaxRatio = (minValue, maxValue) => {
if (minValue === 0 || maxValue === 0) {
return 'SMALL';
}
const ratio = maxValue / minValue;
if (ratio < 100000) {
return 'SMALL';
} else if (ratio < 10000000) {
return 'MEDIUM';
} else {
return 'LARGE';
}
};
/**
* @param samples
* @return {string}
*/
const ratioSize = samples => {
samples.sort();
const minValue = samples.getPercentile(2);
const maxValue = samples.getPercentile(98);
return minMaxRatio(minValue, maxValue);
};
2020-02-15 19:44:18 +00:00
const toPdf = (values, sampleCount, min, max) => {
2020-02-15 19:44:18 +00:00
let duplicateSamples = _(values).groupBy().pickBy(x => x.length > 1).keys().value();
let totalLength = _.size(values);
let frequencies = duplicateSamples.map(s => ({value: parseFloat(s), percentage: _(values).filter(x => x ==s).size()/totalLength}));
2020-02-15 19:44:18 +00:00
let continuousSamples = _.difference(values, frequencies.map(f => f.value));
let discrete = {xs: frequencies.map(f => f.value), ys: frequencies.map(f => f.percentage)};
let continuous = {ys: [], xs: []};
if (continuousSamples.length > 1){
const samples = new Samples(continuousSamples);
const ratioSize$ = ratioSize(samples);
const width = ratioSize$ === 'SMALL' ? 20 : 1;
const cdf = samples.toCdf({ size: sampleCount, width, min, max });
continuous = cdf;
}
return {continuous, discrete};
};
let run = (text, sampleCount, inputs=[], min=false, max=false) => {
let [_error, item] = Guesstimator.parse({ text: "=" + 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);
let update;
let blankResponse = {
continuous: {ys: [], xs: []},
discrete: {ys: [], xs: []}
};
if (values.length === 0) {
update = blankResponse;
} else if (values.length === 1) {
update = blankResponse;
} else {
update = toPdf(values, sampleCount, min, max);
}
return update;
}
module.exports = {
run,
};