Merge pull request #15 from foretold-app/improvements/1102
Improvements/1102
This commit is contained in:
commit
7398877e55
|
@ -45,18 +45,20 @@ module FieldString = {
|
||||||
|
|
||||||
module FieldNumber = {
|
module FieldNumber = {
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~field, ~label) => {
|
let make = (~field, ~label, ~min=0) => {
|
||||||
<Form.Field
|
<Form.Field
|
||||||
field
|
field
|
||||||
render={({handleChange, error, value, validate}) =>
|
render={({handleChange, error, value, validate}) =>
|
||||||
<Antd.Form.Item label={label |> E.ste}>
|
<Antd.Form.Item label={label |> E.ste}>
|
||||||
<Antd.InputNumber
|
<Antd.InputNumber
|
||||||
value
|
value
|
||||||
onChange={e => {
|
onChange=handleChange
|
||||||
e |> handleChange;
|
min
|
||||||
();
|
|
||||||
}}
|
|
||||||
onBlur={_ => validate()}
|
onBlur={_ => validate()}
|
||||||
|
parser={str => {
|
||||||
|
let a = str |> Js.Float.fromString |> int_of_float;
|
||||||
|
a < min ? min : a;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Antd.Form.Item>
|
</Antd.Form.Item>
|
||||||
}
|
}
|
||||||
|
@ -66,19 +68,22 @@ module FieldNumber = {
|
||||||
|
|
||||||
module FieldFloat = {
|
module FieldFloat = {
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~field, ~label, ~className=Css.style([])) => {
|
let make =
|
||||||
|
(~field, ~label, ~className=Css.style([]), ~min=0., ~precision=2) => {
|
||||||
<Form.Field
|
<Form.Field
|
||||||
field
|
field
|
||||||
render={({handleChange, error, value, validate}) =>
|
render={({handleChange, error, value, validate}) =>
|
||||||
<Antd.Form.Item label={label |> E.ste}>
|
<Antd.Form.Item label={label |> E.ste}>
|
||||||
<Antd.InputFloat
|
<Antd.InputFloat
|
||||||
value
|
value
|
||||||
onChange={e => {
|
precision
|
||||||
e |> handleChange;
|
onChange=handleChange
|
||||||
();
|
|
||||||
}}
|
|
||||||
onBlur={_ => validate()}
|
onBlur={_ => validate()}
|
||||||
className
|
className
|
||||||
|
parser={str => {
|
||||||
|
let a = str |> Js.Float.fromString;
|
||||||
|
Js.Float.isNaN(a) ? min : a;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Antd.Form.Item>
|
</Antd.Form.Item>
|
||||||
}
|
}
|
||||||
|
@ -440,16 +445,25 @@ let make = () => {
|
||||||
</Row>
|
</Row>
|
||||||
<Row _type=`flex className=Styles.rows>
|
<Row _type=`flex className=Styles.rows>
|
||||||
<Col span=4>
|
<Col span=4>
|
||||||
<FieldNumber field=FormConfig.SampleCount label="Sample Count" />
|
<FieldNumber
|
||||||
|
field=FormConfig.SampleCount
|
||||||
|
label="Sample Count"
|
||||||
|
min=100
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span=4>
|
<Col span=4>
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
field=FormConfig.OutputXYPoints
|
field=FormConfig.OutputXYPoints
|
||||||
label="Output XY-points"
|
label="Output XY-points"
|
||||||
|
min=100
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span=4>
|
<Col span=4>
|
||||||
<FieldNumber field=FormConfig.TruncateTo label="Truncate To" />
|
<FieldNumber
|
||||||
|
field=FormConfig.TruncateTo
|
||||||
|
label="Truncate To"
|
||||||
|
min=10
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Antd.Button
|
<Antd.Button
|
||||||
|
|
|
@ -34,11 +34,15 @@ module Styles = {
|
||||||
module DemoDist = {
|
module DemoDist = {
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~guesstimatorString: string) => {
|
let make = (~guesstimatorString: string) => {
|
||||||
let (ys, xs) = DistEditor.getPdfFromUserInput(guesstimatorString);
|
let (ys, xs, isEmpty) =
|
||||||
|
DistEditor.getPdfFromUserInput(guesstimatorString);
|
||||||
let continuous: DistTypes.xyShape = {xs, ys};
|
let continuous: DistTypes.xyShape = {xs, ys};
|
||||||
<Antd.Card title={"Distribution" |> E.ste}>
|
<Antd.Card title={"Distribution" |> E.ste}>
|
||||||
<div className=Styles.spacer />
|
<div className=Styles.spacer />
|
||||||
<DistributionPlot continuous />
|
{isEmpty
|
||||||
|
? "Nothing to show. Try to change the distribution description."
|
||||||
|
|> E.ste
|
||||||
|
: <DistributionPlot continuous />}
|
||||||
</Antd.Card>;
|
</Antd.Card>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,14 +68,18 @@ export class CdfChartD3 {
|
||||||
* @returns {CdfChartD3}
|
* @returns {CdfChartD3}
|
||||||
*/
|
*/
|
||||||
data(data) {
|
data(data) {
|
||||||
|
const continuousXs = _.get(data, 'continuous.xs', []);
|
||||||
|
const continuousYs = _.get(data, 'continuous.ys', []);
|
||||||
|
const discreteXs = _.get(data, 'discrete.xs', []);
|
||||||
|
const discreteYs = _.get(data, 'discrete.ys', []);
|
||||||
this.attrs.data = data;
|
this.attrs.data = data;
|
||||||
this.attrs.data.continuous = data.continuous || {
|
this.attrs.data.continuous = {
|
||||||
xs: [],
|
xs: continuousXs,
|
||||||
ys: [],
|
ys: continuousYs,
|
||||||
};
|
};
|
||||||
this.attrs.data.discrete = data.discrete || {
|
this.attrs.data.discrete = {
|
||||||
xs: [],
|
xs: discreteXs,
|
||||||
ys: [],
|
ys: discreteYs,
|
||||||
};
|
};
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[@bs.module "./main.js"]
|
[@bs.module "./main.js"]
|
||||||
external getPdfFromUserInput: string => (array(float), array(float)) =
|
external getPdfFromUserInput: string => (array(float), array(float), bool) =
|
||||||
"get_pdf_from_user_input";
|
"get_pdf_from_user_input";
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
// This module defines an abstract BinnedDistribution class, which
|
|
||||||
// should be implemented for each distribution. You need to decide
|
|
||||||
// how to bin the distribution (use _adabin unless there's a nicer
|
|
||||||
// way for your distr) and how to choose the distribution's support.
|
|
||||||
const _math = require("mathjs");
|
const _math = require("mathjs");
|
||||||
const math = _math.create(_math.all);
|
const math = _math.create(_math.all);
|
||||||
const jStat = require("jstat");
|
const jStat = require("jstat");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This module defines an abstract BinnedDistribution class, which
|
||||||
|
* should be implemented for each distribution. You need to decide
|
||||||
|
* how to bin the distribution (use _adabin unless there's a nicer
|
||||||
|
* way for your distr) and how to choose the distribution's support.
|
||||||
|
*/
|
||||||
|
|
||||||
math.import({
|
math.import({
|
||||||
normal: jStat.normal,
|
normal: jStat.normal,
|
||||||
beta: jStat.beta,
|
beta: jStat.beta,
|
||||||
|
@ -14,6 +17,9 @@ math.import({
|
||||||
});
|
});
|
||||||
|
|
||||||
class BaseDistributionBinned {
|
class BaseDistributionBinned {
|
||||||
|
/**
|
||||||
|
* @param args
|
||||||
|
*/
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
this._set_props();
|
this._set_props();
|
||||||
this.max_bin_size = 0.5;
|
this.max_bin_size = 0.5;
|
||||||
|
@ -30,11 +36,18 @@ class BaseDistributionBinned {
|
||||||
[this.pdf_vals, this.divider_pts] = this.bin();
|
[this.pdf_vals, this.divider_pts] = this.bin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is hacky but class properties aren't always supported
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_set_props() {
|
_set_props() {
|
||||||
// this is hacky but class properties aren't always supported
|
|
||||||
throw new Error("NotImplementedError");
|
throw new Error("NotImplementedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {(number[]|[*])[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_adabin() {
|
_adabin() {
|
||||||
let point = this.start_point;
|
let point = this.start_point;
|
||||||
let vals = [this.pdf_func(point)];
|
let vals = [this.pdf_func(point)];
|
||||||
|
@ -78,6 +91,10 @@ class BaseDistributionBinned {
|
||||||
throw new Error("NotImplementedError");
|
throw new Error("NotImplementedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param args
|
||||||
|
* @returns {(any|(function(*=): *))[]}
|
||||||
|
*/
|
||||||
get_params_and_pdf_func(args) {
|
get_params_and_pdf_func(args) {
|
||||||
let args_str = args.toString() + ")";
|
let args_str = args.toString() + ")";
|
||||||
let substr = this.name + ".pdf(x, " + args_str;
|
let substr = this.name + ".pdf(x, " + args_str;
|
||||||
|
@ -95,11 +112,17 @@ class BaseDistributionBinned {
|
||||||
}
|
}
|
||||||
|
|
||||||
class NormalDistributionBinned extends BaseDistributionBinned {
|
class NormalDistributionBinned extends BaseDistributionBinned {
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_set_props() {
|
_set_props() {
|
||||||
this.name = "normal";
|
this.name = "normal";
|
||||||
this.param_names = ["mean", "std"];
|
this.param_names = ["mean", "std"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {(number|*)[]}
|
||||||
|
*/
|
||||||
get_bounds() {
|
get_bounds() {
|
||||||
return [
|
return [
|
||||||
this.params.mean - 4 * this.params.std,
|
this.params.mean - 4 * this.params.std,
|
||||||
|
@ -107,22 +130,34 @@ class NormalDistributionBinned extends BaseDistributionBinned {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {[[*], [*]]}
|
||||||
|
*/
|
||||||
bin() {
|
bin() {
|
||||||
return this._adabin(this.params.std);
|
return this._adabin(this.params.std);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UniformDistributionBinned extends BaseDistributionBinned {
|
class UniformDistributionBinned extends BaseDistributionBinned {
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_set_props() {
|
_set_props() {
|
||||||
this.name = "uniform";
|
this.name = "uniform";
|
||||||
this.param_names = ["start_point", "end_point"];
|
this.param_names = ["start_point", "end_point"];
|
||||||
this.num_bins = 200;
|
this.num_bins = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
get_bounds() {
|
get_bounds() {
|
||||||
return [this.params.start_point, this.params.end_point];
|
return [this.params.start_point, this.params.end_point];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {(*[])[]}
|
||||||
|
*/
|
||||||
bin() {
|
bin() {
|
||||||
let divider_pts = evenly_spaced_grid(
|
let divider_pts = evenly_spaced_grid(
|
||||||
this.params.start_point,
|
this.params.start_point,
|
||||||
|
@ -138,6 +173,9 @@ class UniformDistributionBinned extends BaseDistributionBinned {
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogNormalDistributionBinned extends BaseDistributionBinned {
|
class LogNormalDistributionBinned extends BaseDistributionBinned {
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_set_props() {
|
_set_props() {
|
||||||
this.name = "lognormal";
|
this.name = "lognormal";
|
||||||
this.param_names = ["normal_mean", "normal_std"];
|
this.param_names = ["normal_mean", "normal_std"];
|
||||||
|
@ -145,6 +183,12 @@ class LogNormalDistributionBinned extends BaseDistributionBinned {
|
||||||
this.n_largest_bound_sample = 10;
|
this.n_largest_bound_sample = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param samples
|
||||||
|
* @param n
|
||||||
|
* @returns {any}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_nth_largest(samples, n) {
|
_nth_largest(samples, n) {
|
||||||
var largest_buffer = Array(n).fill(-Infinity);
|
var largest_buffer = Array(n).fill(-Infinity);
|
||||||
for (const sample of samples) {
|
for (const sample of samples) {
|
||||||
|
@ -159,6 +203,9 @@ class LogNormalDistributionBinned extends BaseDistributionBinned {
|
||||||
return largest_buffer[n - 1];
|
return largest_buffer[n - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {(*|any)[]}
|
||||||
|
*/
|
||||||
get_bounds() {
|
get_bounds() {
|
||||||
let samples = Array(this.n_bounds_samples)
|
let samples = Array(this.n_bounds_samples)
|
||||||
.fill(0)
|
.fill(0)
|
||||||
|
@ -169,11 +216,20 @@ class LogNormalDistributionBinned extends BaseDistributionBinned {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {[[*], [*]]}
|
||||||
|
*/
|
||||||
bin() {
|
bin() {
|
||||||
return this._adabin();
|
return this._adabin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param start
|
||||||
|
* @param stop
|
||||||
|
* @param numel
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
function evenly_spaced_grid(start, stop, numel) {
|
function evenly_spaced_grid(start, stop, numel) {
|
||||||
return Array(numel)
|
return Array(numel)
|
||||||
.fill(0)
|
.fill(0)
|
||||||
|
|
|
@ -1,30 +1,57 @@
|
||||||
// The main algorithmic work is done by functions in this module.
|
const _math = require("mathjs");
|
||||||
// It also contains the main function, taking the user's string
|
const bst = require("binary-search-tree");
|
||||||
// and returning pdf values and x's.
|
|
||||||
|
|
||||||
const distrs = require("./distribution.js").distrs;
|
const distrs = require("./distribution.js").distrs;
|
||||||
const parse = require("./parse.js");
|
const parse = require("./parse.js");
|
||||||
const _math = require("mathjs");
|
|
||||||
const math = _math.create(_math.all);
|
const math = _math.create(_math.all);
|
||||||
const bst = require("binary-search-tree");
|
|
||||||
|
|
||||||
const NUM_MC_SAMPLES = 300;
|
const NUM_MC_SAMPLES = 300;
|
||||||
const OUTPUT_GRID_NUMEL = 300;
|
const OUTPUT_GRID_NUMEL = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main algorithmic work is done by functions in this module.
|
||||||
|
* It also contains the main function, taking the user's string
|
||||||
|
* and returning pdf values and x's.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param start
|
||||||
|
* @param stop
|
||||||
|
* @param numel
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
function evenly_spaced_grid(start, stop, numel) {
|
function evenly_spaced_grid(start, stop, numel) {
|
||||||
return Array(numel)
|
return Array(numel)
|
||||||
.fill(0)
|
.fill(0)
|
||||||
.map((_, idx) => start + (idx / numel) * (stop - start));
|
.map((_, idx) => start + (idx / numel) * (stop - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an array of strings like "normal(0, 1)" and
|
||||||
|
* returns the corresponding distribution objects
|
||||||
|
* @param substrings
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
function get_distributions(substrings) {
|
function get_distributions(substrings) {
|
||||||
// Takes an array of strings like "normal(0, 1)" and
|
|
||||||
// returns the corresponding distribution objects
|
|
||||||
let names_and_args = substrings.map(parse.get_distr_name_and_args);
|
let names_and_args = substrings.map(parse.get_distr_name_and_args);
|
||||||
let pdfs = names_and_args.map(x => new distrs[x[0]](x[1]));
|
let pdfs = names_and_args.map(x => new distrs[x[0]](x[1]));
|
||||||
return pdfs;
|
return pdfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update the binary search tree with bin points of
|
||||||
|
* deterministic_pdf transformed by tansform func
|
||||||
|
* (transfrom func can be a stocahstic func with parameters
|
||||||
|
* sampled from mc_distrs)
|
||||||
|
*
|
||||||
|
* @param transform_func
|
||||||
|
* @param deterministic_pdf
|
||||||
|
* @param mc_distrs
|
||||||
|
* @param track_idx
|
||||||
|
* @param num_mc_samples
|
||||||
|
* @param bst_pts_and_idxs
|
||||||
|
* @returns {(number)[]}
|
||||||
|
*/
|
||||||
function update_transformed_divider_points_bst(
|
function update_transformed_divider_points_bst(
|
||||||
transform_func,
|
transform_func,
|
||||||
deterministic_pdf,
|
deterministic_pdf,
|
||||||
|
@ -33,10 +60,6 @@ function update_transformed_divider_points_bst(
|
||||||
num_mc_samples,
|
num_mc_samples,
|
||||||
bst_pts_and_idxs
|
bst_pts_and_idxs
|
||||||
) {
|
) {
|
||||||
// update the binary search tree with bin points of
|
|
||||||
// deterministic_pdf transformed by tansform func
|
|
||||||
// (transfrom func can be a stocahstic func with parameters
|
|
||||||
// sampled from mc_distrs)
|
|
||||||
var transformed_pts = [];
|
var transformed_pts = [];
|
||||||
var pdf_inner_idxs = [];
|
var pdf_inner_idxs = [];
|
||||||
var factors = [];
|
var factors = [];
|
||||||
|
@ -97,10 +120,17 @@ function update_transformed_divider_points_bst(
|
||||||
return [start_pt, end_pt];
|
return [start_pt, end_pt];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the binary search tree with transformed bin points,
|
||||||
|
* and an array of pdf values associated with the bins,
|
||||||
|
* and return a pdf over an evenly spaced grid
|
||||||
|
*
|
||||||
|
* @param pdf_vals
|
||||||
|
* @param bst_pts_and_idxs
|
||||||
|
* @param output_grid
|
||||||
|
* @returns {[]}
|
||||||
|
*/
|
||||||
function get_final_pdf(pdf_vals, bst_pts_and_idxs, output_grid) {
|
function get_final_pdf(pdf_vals, bst_pts_and_idxs, output_grid) {
|
||||||
// Take the binary search tree with transformed bin points,
|
|
||||||
// and an array of pdf values associated with the bins,
|
|
||||||
// and return a pdf over an evenly spaced grid
|
|
||||||
var offset = output_grid[1] / 2 - output_grid[0] / 2;
|
var offset = output_grid[1] / 2 - output_grid[0] / 2;
|
||||||
var active_intervals = new Map();
|
var active_intervals = new Map();
|
||||||
var active_endpoints = new bst.AVLTree();
|
var active_endpoints = new bst.AVLTree();
|
||||||
|
@ -152,47 +182,66 @@ function get_final_pdf(pdf_vals, bst_pts_and_idxs, output_grid) {
|
||||||
return final_pdf_vals;
|
return final_pdf_vals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entrypoint. Pass user input strings to this function,
|
||||||
|
* get the corresponding pdf values and input points back.
|
||||||
|
* If the pdf requires monte carlo (it contains a between-distr function)
|
||||||
|
* we first determing which distr to have deterministic
|
||||||
|
* and which to sample from. This is decided based on which
|
||||||
|
* choice gives the least variance.
|
||||||
|
*
|
||||||
|
* @param user_input_string
|
||||||
|
* @returns {([]|*[])[]}
|
||||||
|
*/
|
||||||
function get_pdf_from_user_input(user_input_string) {
|
function get_pdf_from_user_input(user_input_string) {
|
||||||
// Entrypoint. Pass user input strings to this function,
|
try{
|
||||||
// get the corresponding pdf values and input points back.
|
let parsed = parse.parse_initial_string(user_input_string);
|
||||||
// If the pdf requires monte carlo (it contains a between-distr function)
|
let mm_args = parse.separate_mm_args(parsed.mm_args_string);
|
||||||
// we first determing which distr to have deterministic
|
|
||||||
// and whih to sample from. This is decided based on which
|
const is_mm = mm_args.distrs.length > 0;
|
||||||
// choice gives the least variance.
|
if (!parsed.outer_string) return [[], [], true];
|
||||||
let parsed = parse.parse_initial_string(user_input_string);
|
|
||||||
let mm_args = parse.separate_mm_args(parsed.mm_args_string);
|
let tree = new bst.AVLTree();
|
||||||
const is_mm = mm_args.distrs.length > 0;
|
let possible_start_pts = [];
|
||||||
let tree = new bst.AVLTree();
|
let possible_end_pts = [];
|
||||||
let possible_start_pts = [];
|
let all_vals = [];
|
||||||
let possible_end_pts = [];
|
let weights = is_mm ? math.compile(mm_args.weights).evaluate()._data : [1];
|
||||||
let all_vals = [];
|
let weights_sum = weights.reduce((a, b) => a + b);
|
||||||
let weights = is_mm ? math.compile(mm_args.weights).evaluate()._data : [1];
|
weights = weights.map(x => x / weights_sum);
|
||||||
let weights_sum = weights.reduce((a, b) => a + b);
|
let n_iters = is_mm ? mm_args.distrs.length : 1;
|
||||||
weights = weights.map(x => x / weights_sum);
|
|
||||||
let n_iters = is_mm ? mm_args.distrs.length : 1;
|
for (let i = 0; i < n_iters; ++i) {
|
||||||
for (let i = 0; i < n_iters; ++i) {
|
let distr_string = is_mm ? mm_args.distrs[i] : parsed.outer_string;
|
||||||
let distr_string = is_mm ? mm_args.distrs[i] : parsed.outer_string;
|
var [deterministic_pdf, mc_distrs] = choose_pdf_func(distr_string);
|
||||||
var [deterministic_pdf, mc_distrs] = choose_pdf_func(distr_string);
|
var grid_transform = get_grid_transform(distr_string);
|
||||||
var grid_transform = get_grid_transform(distr_string);
|
var [start_pt, end_pt] = update_transformed_divider_points_bst(
|
||||||
var [start_pt, end_pt] = update_transformed_divider_points_bst(
|
grid_transform,
|
||||||
grid_transform,
|
deterministic_pdf,
|
||||||
deterministic_pdf,
|
mc_distrs,
|
||||||
mc_distrs,
|
i,
|
||||||
i,
|
NUM_MC_SAMPLES,
|
||||||
NUM_MC_SAMPLES,
|
tree
|
||||||
tree
|
);
|
||||||
);
|
possible_start_pts.push(start_pt);
|
||||||
possible_start_pts.push(start_pt);
|
possible_end_pts.push(end_pt);
|
||||||
possible_end_pts.push(end_pt);
|
all_vals.push(deterministic_pdf.pdf_vals.map(x => x * weights[i]));
|
||||||
all_vals.push(deterministic_pdf.pdf_vals.map(x => x * weights[i]));
|
}
|
||||||
|
|
||||||
|
start_pt = Math.min(...possible_start_pts);
|
||||||
|
end_pt = Math.max(...possible_end_pts);
|
||||||
|
|
||||||
|
let output_grid = evenly_spaced_grid(start_pt, end_pt, OUTPUT_GRID_NUMEL);
|
||||||
|
let final_pdf_vals = get_final_pdf(all_vals, tree, output_grid);
|
||||||
|
return [final_pdf_vals, output_grid, false];
|
||||||
|
} catch (e) {
|
||||||
|
return [[], [], true];
|
||||||
}
|
}
|
||||||
start_pt = Math.min(...possible_start_pts);
|
|
||||||
end_pt = Math.max(...possible_end_pts);
|
|
||||||
let output_grid = evenly_spaced_grid(start_pt, end_pt, OUTPUT_GRID_NUMEL);
|
|
||||||
let final_pdf_vals = get_final_pdf(all_vals, tree, output_grid);
|
|
||||||
return [final_pdf_vals, output_grid];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param vals
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
function variance(vals) {
|
function variance(vals) {
|
||||||
var vari = 0;
|
var vari = 0;
|
||||||
for (let i = 0; i < vals[0].length; ++i) {
|
for (let i = 0; i < vals[0].length; ++i) {
|
||||||
|
@ -209,14 +258,24 @@ function variance(vals) {
|
||||||
return vari;
|
return vari;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array
|
||||||
|
* @param idx
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
function pluck_from_array(array, idx) {
|
function pluck_from_array(array, idx) {
|
||||||
return [array[idx], array.slice(0, idx).concat(array.slice(idx + 1))];
|
return [array[idx], array.slice(0, idx).concat(array.slice(idx + 1))];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If distr_string requires MC, try all possible
|
||||||
|
* choices for the deterministic distribution,
|
||||||
|
* and pick the one with the least variance.
|
||||||
|
*
|
||||||
|
* @param distr_string
|
||||||
|
* @returns {(*|*[])[]|*[]}
|
||||||
|
*/
|
||||||
function choose_pdf_func(distr_string) {
|
function choose_pdf_func(distr_string) {
|
||||||
// If distr_string requires MC, try all possible
|
|
||||||
// choices for the deterministic distribution,
|
|
||||||
// and pick the one with the least variance.
|
|
||||||
var variances = [];
|
var variances = [];
|
||||||
let transform_func = get_grid_transform(distr_string);
|
let transform_func = get_grid_transform(distr_string);
|
||||||
let substrings = parse.get_distr_substrings(distr_string);
|
let substrings = parse.get_distr_substrings(distr_string);
|
||||||
|
@ -259,6 +318,10 @@ function choose_pdf_func(distr_string) {
|
||||||
return [pdfs[best_idx], mc_distrs];
|
return [pdfs[best_idx], mc_distrs];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param distr_string
|
||||||
|
* @returns {function(*): *}
|
||||||
|
*/
|
||||||
function get_grid_transform(distr_string) {
|
function get_grid_transform(distr_string) {
|
||||||
let substrings = parse.get_distr_substrings(distr_string);
|
let substrings = parse.get_distr_substrings(distr_string);
|
||||||
let arg_strings = [];
|
let arg_strings = [];
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
// Functions for parsing/processing user input strings are here
|
|
||||||
const _math = require("mathjs");
|
const _math = require("mathjs");
|
||||||
const math = _math.create(_math.all);
|
const math = _math.create(_math.all);
|
||||||
|
|
||||||
|
// Functions for parsing/processing user input strings are here
|
||||||
|
|
||||||
const DISTR_REGEXS = [
|
const DISTR_REGEXS = [
|
||||||
/beta\(/g,
|
/beta\(/g,
|
||||||
/(log)?normal\(/g,
|
/(log)?normal\(/g,
|
||||||
|
@ -10,6 +11,11 @@ const DISTR_REGEXS = [
|
||||||
/uniform\(/g
|
/uniform\(/g
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user_input_string
|
||||||
|
* @returns {{mm_args_string: string, outer_string: string}}
|
||||||
|
*/
|
||||||
function parse_initial_string(user_input_string) {
|
function parse_initial_string(user_input_string) {
|
||||||
let outer_output_string = "";
|
let outer_output_string = "";
|
||||||
let mm_args_string = "";
|
let mm_args_string = "";
|
||||||
|
@ -42,6 +48,10 @@ function parse_initial_string(user_input_string) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mm_args_string
|
||||||
|
* @returns {{distrs: [], weights: string}}
|
||||||
|
*/
|
||||||
function separate_mm_args(mm_args_string) {
|
function separate_mm_args(mm_args_string) {
|
||||||
if (mm_args_string.endsWith(",")) {
|
if (mm_args_string.endsWith(",")) {
|
||||||
mm_args_string = mm_args_string.slice(0, -1);
|
mm_args_string = mm_args_string.slice(0, -1);
|
||||||
|
@ -68,6 +78,10 @@ function separate_mm_args(mm_args_string) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param distr_string
|
||||||
|
* @returns {[]}
|
||||||
|
*/
|
||||||
function get_distr_substrings(distr_string) {
|
function get_distr_substrings(distr_string) {
|
||||||
let substrings = [];
|
let substrings = [];
|
||||||
for (let regex of DISTR_REGEXS) {
|
for (let regex of DISTR_REGEXS) {
|
||||||
|
@ -92,6 +106,10 @@ function get_distr_substrings(distr_string) {
|
||||||
return substrings;
|
return substrings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param substr
|
||||||
|
* @returns {(string|*)[]}
|
||||||
|
*/
|
||||||
function get_distr_name_and_args(substr) {
|
function get_distr_name_and_args(substr) {
|
||||||
let distr_name = "";
|
let distr_name = "";
|
||||||
let args_str = "";
|
let args_str = "";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user