Removed a bunch of now-unused files

This commit is contained in:
Ozzie Gooen 2020-07-13 00:05:21 +01:00
parent 2da6f00211
commit cecbe4fcc3
12 changed files with 1 additions and 1078 deletions

View File

@ -27,7 +27,6 @@
"license": "MIT",
"dependencies": {
"@foretold/components": "0.0.6",
"@foretold/guesstimator": "1.0.11",
"@glennsl/bs-json": "^5.0.2",
"antd": "3.17.0",
"autoprefixer": "9.7.4",

View File

@ -1,8 +1,6 @@
type route =
| Model(string)
| DistBuilder
| DistBuilder2
| DistBuilder3
| Drawer
| Home
| NotFound;
@ -11,8 +9,6 @@ let routeToPath = route =>
switch (route) {
| Model(modelId) => "/m/" ++ modelId
| DistBuilder => "/dist-builder"
| DistBuilder2 => "/dist-builder2"
| DistBuilder3 => "/dist-builder3"
| Drawer => "/drawer"
| Home => "/"
| _ => "/"
@ -75,12 +71,6 @@ module Menu = {
<Item href={routeToPath(DistBuilder)} key="dist-builder">
{"Dist Builder" |> R.ste}
</Item>
<Item href={routeToPath(DistBuilder2)} key="dist-builder-2">
{"Dist Builder 2" |> R.ste}
</Item>
<Item href={routeToPath(DistBuilder3)} key="dist-builder-3">
{"Dist Builder 3" |> R.ste}
</Item>
<Item href={routeToPath(Drawer)} key="drawer">
{"Drawer" |> R.ste}
</Item>
@ -97,8 +87,6 @@ let make = () => {
switch (url.path) {
| ["m", modelId] => Model(modelId)
| ["dist-builder"] => DistBuilder
| ["dist-builder2"] => DistBuilder2
| ["dist-builder3"] => DistBuilder3
| ["drawer"] => Drawer
| [] => Home
| _ => NotFound
@ -113,8 +101,6 @@ let make = () => {
| None => <div> {"Page is not found" |> R.ste} </div>
}
| DistBuilder => <DistBuilder />
| DistBuilder2 => <DistBuilder2 />
| DistBuilder3 => <DistBuilder3 />
| Drawer => <Drawer />
| Home => <Home />
| _ => <div> {"Page is not found" |> R.ste} </div>

View File

@ -1,105 +0,0 @@
open BsReform;
open Antd.Grid;
module FormConfig = [%lenses type state = {guesstimatorString: string}];
module Form = ReForm.Make(FormConfig);
let schema = Form.Validation.Schema([||]);
module FieldString = {
[@react.component]
let make = (~field, ~label) => {
<Form.Field
field
render={({handleChange, error, value, validate}) =>
<Antd.Form.Item label={label |> R.ste}>
<Antd.Input
value
onChange={BsReform.Helpers.handleChange(handleChange)}
onBlur={_ => validate()}
/>
</Antd.Form.Item>
}
/>;
};
};
module Styles = {
open Css;
let dist = style([padding(em(1.))]);
let spacer = style([marginTop(em(1.))]);
};
module DemoDist = {
[@react.component]
let make = (~guesstimatorString: string) => {
let (ys, xs, isEmpty) =
DistEditor.getPdfFromUserInput(guesstimatorString);
let inside =
isEmpty
? "Nothing to show" |> R.ste
: {
let distPlus =
DistPlus.make(
~shape=
Continuous(
Continuous.make(`Linear, {xs, ys}, None),
),
~domain=Complete,
~unit=UnspecifiedDistribution,
~guesstimatorString=None,
(),
)
|> DistPlus.T.normalize;
<DistPlusPlot distPlus />;
};
<Antd.Card title={"Distribution" |> R.ste}>
<div className=Styles.spacer />
inside
</Antd.Card>;
};
};
[@react.component]
let make = () => {
let reform =
Form.use(
~validationStrategy=OnDemand,
~schema,
~onSubmit=({state}) => {None},
~initialState={guesstimatorString: "lognormal(6.1, 1)"},
(),
);
let demoDist =
React.useMemo1(
() => {
<DemoDist
guesstimatorString={reform.state.values.guesstimatorString}
/>
},
[|reform.state.values.guesstimatorString|],
);
<div>
<div className=Styles.spacer />
demoDist
<div className=Styles.spacer />
<Antd.Card title={"Distribution Form" |> R.ste}>
<Form.Provider value=reform>
<Antd.Form>
<Row _type=`flex>
<Col span=12>
<FieldString
field=FormConfig.GuesstimatorString
label="Guesstimator String"
/>
</Col>
</Row>
</Antd.Form>
</Form.Provider>
</Antd.Card>
<div className=Styles.spacer />
</div>;
};

View File

@ -1,121 +0,0 @@
open BsReform;
open Antd.Grid;
module FormConfig = [%lenses type state = {guesstimatorString: string}];
module Form = ReForm.Make(FormConfig);
let schema = Form.Validation.Schema([||]);
module FieldString = {
[@react.component]
let make = (~field, ~label) => {
<Form.Field
field
render={({handleChange, error, value, validate}) =>
<Antd.Form.Item label={label |> R.ste}>
<Antd.Input
value
onChange={BsReform.Helpers.handleChange(handleChange)}
onBlur={_ => validate()}
/>
</Antd.Form.Item>
}
/>;
};
};
module Styles = {
open Css;
let dist = style([padding(em(1.))]);
let spacer = style([marginTop(em(1.))]);
};
module DemoDist = {
[@react.component]
let make = (~guesstimatorString: string) => {
let parsed1 = MathJsParser.fromString(guesstimatorString);
let shape =
switch (parsed1) {
| Ok(r) =>
Some(
ExpressionTree.toShape(
10000,
{sampleCount: 10000, outputXYPoints: 10000, kernelWidth: None},
r,
),
)
| _ => None
};
let str =
switch (parsed1) {
| Ok(r) => ExpressionTree.toString(r)
| Error(e) => e
};
let inside =
shape
|> E.O.fmap(shape => {
let distPlus =
DistPlus.make(
~shape,
~domain=Complete,
~unit=UnspecifiedDistribution,
~guesstimatorString=None,
(),
)
|> DistPlus.T.normalize;
<DistPlusPlot distPlus />;
})
|> E.O.default(ReasonReact.null);
<Antd.Card title={"Distribution" |> R.ste}>
<div className=Styles.spacer />
inside
{str |> ReasonReact.string}
</Antd.Card>;
};
};
[@react.component]
let make = () => {
let reform =
Form.use(
~validationStrategy=OnDemand,
~schema,
~onSubmit=({state}) => {None},
~initialState={guesstimatorString: "mm(1 to 100, 50 to 200, [.5,.5])"},
(),
);
let demoDist =
React.useMemo1(
() => {
<DemoDist
guesstimatorString={reform.state.values.guesstimatorString}
/>
},
[|reform.state.values.guesstimatorString|],
);
<div>
<div className=Styles.spacer />
demoDist
<div className=Styles.spacer />
<Antd.Card title={"Distribution Form" |> R.ste}>
<Form.Provider value=reform>
<Antd.Form>
<Row _type=`flex>
<Col span=12>
<FieldString
field=FormConfig.GuesstimatorString
label="Guesstimator String"
/>
</Col>
</Row>
</Antd.Form>
</Form.Provider>
</Antd.Card>
<div className=Styles.spacer />
</div>;
};

View File

@ -1,3 +0,0 @@
[@bs.module "./main.js"]
external getPdfFromUserInput: string => (array(float), array(float), bool) =
"get_pdf_from_user_input";

View File

@ -1,247 +0,0 @@
const _math = require("mathjs");
const math = _math.create(_math.all);
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({
normal: jStat.normal,
beta: jStat.beta,
lognormal: jStat.lognormal,
uniform: jStat.uniform
});
class BaseDistributionBinned {
/**
* @param args
*/
constructor(args) {
this._set_props();
this.max_bin_size = 0.005;
this.min_bin_size = 0;
this.increment = 0.0001;
this.desired_delta = 0.001;
this.start_bin_size = 0.0001;
[this.params, this.pdf_func, this.sample] = this.get_params_and_pdf_func(
args
);
[this.start_point, this.end_point] = this.get_bounds();
[this.pdf_vals, this.divider_pts] = this.bin();
}
/**
* this is hacky but class properties aren't always supported
* @private
*/
_set_props() {
throw new Error("NotImplementedError");
}
//Adaptive binning. Specify a desired change in density to get adjusted bin sizes.
/**
* @returns {(number[]|[*])[]}
* @private
*/
_adabin() {
let point = this.start_point;
let vals = [this.pdf_func(point)];
let divider_pts = [point];
let support = this.end_point - this.start_point;
let bin_size = this.start_bin_size * support;
while (point < this.end_point) {
let val = this.pdf_func(point + bin_size);
if (Math.abs(val - vals[vals.length - 1]) > this.desired_delta) {
while (
(Math.abs(val - vals[vals.length - 1]) > this.desired_delta) &
(bin_size - this.increment * support > this.min_bin_size)
) {
bin_size -= this.increment;
val = this.pdf_func(point + bin_size);
}
} else if (Math.abs(val - vals[vals.length - 1]) < this.desired_delta) {
while (
(Math.abs(val - vals[vals.length - 1]) < this.desired_delta) &
(bin_size < this.max_bin_size)
) {
bin_size += this.increment;
val = this.pdf_func(point + bin_size);
}
}
point += bin_size;
vals.push(val);
divider_pts.push(point);
}
vals = vals.map((_, idx) => vals[idx] / 2 + vals[idx + 1] / 2);
vals = vals.slice(0, -1);
return [vals, divider_pts];
}
bin() {
throw new Error("NotImplementedError");
}
get_bounds() {
throw new Error("NotImplementedError");
}
/**
* @param args
* @returns {(any|(function(*=): *))[]}
*/
get_params_and_pdf_func(args) {
let args_str = args.toString() + ")";
let substr = this.name + ".pdf(x, " + args_str;
let compiled = math.compile(substr);
function pdf_func(x) {
return compiled.evaluate({ x: x });
}
let mc_compiled = math.compile(this.name + ".sample(" + args_str);
let kv_pairs = this.param_names.map((val, idx) => [val, args[idx]]);
let params = Object.fromEntries(new Map(kv_pairs));
return [params, pdf_func, mc_compiled.evaluate];
}
}
class NormalDistributionBinned extends BaseDistributionBinned {
/**
* @private
*/
_set_props() {
this.name = "normal";
this.param_names = ["mean", "std"];
}
/**
* @returns {(number|*)[]}
*/
get_bounds() {
return [
this.params.mean - 4 * this.params.std,
this.params.mean + 4 * this.params.std
];
}
/**
* @returns {[[*], [*]]}
*/
bin() {
return this._adabin(this.params.std);
}
}
class UniformDistributionBinned extends BaseDistributionBinned {
/**
* @private
*/
_set_props() {
this.name = "uniform";
this.param_names = ["start_point", "end_point"];
this.num_bins = 200;
}
/**
* @returns {*[]}
*/
get_bounds() {
return [this.params.start_point, this.params.end_point];
}
/**
* @returns {(*[])[]}
*/
bin() {
let divider_pts = evenly_spaced_grid(
this.params.start_point,
this.params.end_point,
this.num_bins
);
let vals = divider_pts.map(x =>
this.pdf_func(this.params.start_point / 2 + this.params.end_point / 2)
);
vals = vals.slice(0, -1);
return [vals, divider_pts];
}
}
class LogNormalDistributionBinned extends BaseDistributionBinned {
/**
* @private
*/
_set_props() {
this.name = "lognormal";
this.param_names = ["normal_mean", "normal_std"];
this.n_bounds_samples = 10000;
this.n_largest_bound_sample = 10;
}
/**
* @param samples
* @param n
* @returns {any}
* @private
*/
_nth_largest(samples, n) {
var largest_buffer = Array(n).fill(-Infinity);
for (const sample of samples) {
if (sample > largest_buffer[n - 1]) {
var i = n;
while ((i > 0) & (sample > largest_buffer[i - 1])) {
i -= 1;
}
largest_buffer[i] = sample;
}
}
return largest_buffer[n - 1];
}
/**
* @returns {(*|any)[]}
*/
get_bounds() {
let samples = Array(this.n_bounds_samples)
.fill(0)
.map(() => this.sample());
return [
math.min(samples),
this._nth_largest(samples, this.n_largest_bound_sample)
];
}
/**
* @returns {[[*], [*]]}
*/
bin() {
return this._adabin();
}
}
/**
* @param start
* @param stop
* @param numel
* @returns {*[]}
*/
function evenly_spaced_grid(start, stop, numel) {
return Array(numel)
.fill(0)
.map((_, idx) => start + (idx / numel) * (stop - start));
}
const distrs = {
normal: NormalDistributionBinned,
lognormal: LogNormalDistributionBinned,
uniform: UniformDistributionBinned
};
exports.distrs = distrs;

View File

@ -1,364 +0,0 @@
const _math = require("mathjs");
const bst = require("binary-search-tree");
const distrs = require("./distribution.js").distrs;
const parse = require("./parse.js");
const math = _math.create(_math.all);
const NUM_MC_SAMPLES = 3000;
const OUTPUT_GRID_NUMEL = 3000;
/**
* 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) {
return Array(numel)
.fill(0)
.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) {
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]));
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(
transform_func,
deterministic_pdf,
mc_distrs,
track_idx,
num_mc_samples,
bst_pts_and_idxs
) {
var transformed_pts = [];
var pdf_inner_idxs = [];
var factors = [];
var start_pt = Infinity;
var end_pt = -Infinity;
let use_mc = mc_distrs.length > 0;
var num_outer_iters = use_mc ? num_mc_samples : 1;
for (let sample_idx = 0; sample_idx < num_outer_iters; ++sample_idx) {
var this_transformed_pts = deterministic_pdf.divider_pts;
if (use_mc) {
let samples = mc_distrs.map(x => x.sample());
this_transformed_pts = this_transformed_pts.map(x =>
transform_func([x].concat(samples))
);
} else {
this_transformed_pts = this_transformed_pts.map(x => transform_func([x]));
}
var this_transformed_pts_paired = [];
for (let tp_idx = 0; tp_idx < this_transformed_pts.length - 1; tp_idx++) {
let sorted = [
this_transformed_pts[tp_idx],
this_transformed_pts[tp_idx + 1]
].sort((a, b) => a - b);
if (sorted[0] < start_pt) {
start_pt = sorted[0];
}
if (sorted[1] > end_pt) {
end_pt = sorted[1];
}
this_transformed_pts_paired.push(sorted);
}
transformed_pts = transformed_pts.concat(this_transformed_pts_paired);
pdf_inner_idxs = pdf_inner_idxs.concat([
...Array(this_transformed_pts_paired.length).keys()
]);
var this_factors = [];
for (let idx = 0; idx < this_transformed_pts_paired.length; idx++) {
this_factors.push(
(deterministic_pdf.divider_pts[idx + 1] -
deterministic_pdf.divider_pts[idx]) /
(this_transformed_pts_paired[idx][1] -
this_transformed_pts_paired[idx][0])
);
}
factors = factors.concat(this_factors);
}
for (let i = 0; i < transformed_pts.length; ++i) {
bst_pts_and_idxs.insert(transformed_pts[i][0], {
start: transformed_pts[i][0],
end: transformed_pts[i][1],
idx: [track_idx, pdf_inner_idxs[i]],
factor: factors[i] / num_outer_iters
});
}
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) {
var offset = output_grid[1] / 2 - output_grid[0] / 2;
var active_intervals = new Map();
var active_endpoints = new bst.AVLTree();
var final_pdf_vals = [];
for (
let out_grid_idx = 0;
out_grid_idx < output_grid.length;
++out_grid_idx
) {
let startpoints_within_bin = bst_pts_and_idxs.betweenBounds({
$gte: output_grid[out_grid_idx] - offset,
$lt: output_grid[out_grid_idx] + offset
});
for (let interval of startpoints_within_bin) {
active_intervals.set(interval.idx, [
interval.start,
interval.end,
interval.factor
]);
active_endpoints.insert(interval.end, interval.idx);
}
var contrib = 0;
for (let [pdf_idx, bounds_and_ratio] of active_intervals.entries()) {
let overlap_start = Math.max(
output_grid[out_grid_idx] - offset,
bounds_and_ratio[0]
);
let overlap_end = Math.min(
output_grid[out_grid_idx] + offset,
bounds_and_ratio[1]
);
let interval_size = bounds_and_ratio[1] - bounds_and_ratio[0];
let contrib_frac =
interval_size === 0
? 0
: (overlap_end - overlap_start) * bounds_and_ratio[2];
let t = contrib_frac * pdf_vals[pdf_idx[0]][pdf_idx[1]];
contrib += t;
}
final_pdf_vals.push(contrib);
let endpoints_within_bin = active_endpoints.betweenBounds({
$gte: output_grid[out_grid_idx] - offset,
$lt: output_grid[out_grid_idx] + offset
});
for (let interval_idx of endpoints_within_bin) {
active_intervals.delete(interval_idx);
}
}
return final_pdf_vals;
}
/**
* @param {string} str
* @param {string} char
* @returns {number}
*/
function get_count_of_chars(str, char) {
return str.split(char).length - 1;
}
/**
* 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) {
try {
const count_opened_bracket = get_count_of_chars(user_input_string, '(');
const count_closed_bracket = get_count_of_chars(user_input_string, ')');
if (count_opened_bracket !== count_closed_bracket) {
throw new Error('Count of brackets are not equal.');
}
let parsed = parse.parse_initial_string(user_input_string);
let mm_args = parse.separate_mm_args(parsed.mm_args_string);
const is_mm = mm_args.distrs.length > 0;
if (!parsed.outer_string) {
throw new Error('Parse string is empty.');
}
let tree = new bst.AVLTree();
let possible_start_pts = [];
let possible_end_pts = [];
let all_vals = [];
let weights = is_mm ? math.compile(mm_args.weights).evaluate()._data : [1];
let weights_sum = weights.reduce((a, b) => a + b);
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) {
let distr_string = is_mm ? mm_args.distrs[i] : parsed.outer_string;
var [deterministic_pdf, mc_distrs] = choose_pdf_func(distr_string);
var grid_transform = get_grid_transform(distr_string);
var [start_pt, end_pt] = update_transformed_divider_points_bst(
grid_transform,
deterministic_pdf,
mc_distrs,
i,
NUM_MC_SAMPLES,
tree
);
possible_start_pts.push(start_pt);
possible_end_pts.push(end_pt);
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];
}
}
/**
* @param vals
* @returns {number}
*/
function variance(vals) {
var vari = 0;
for (let i = 0; i < vals[0].length; ++i) {
let mean = 0;
let this_vari = 0;
for (let val of vals) {
mean += val[i] / vals.length;
}
for (let val of vals) {
this_vari += (val[i] - mean) ** 2;
}
vari += this_vari;
}
return vari;
}
/**
* @param array
* @param idx
* @returns {*[]}
*/
function pluck_from_array(array, idx) {
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.
* It's much better to sample from a normal than a lognormal.
*
* @param distr_string
* @returns {(*|*[])[]|*[]}
*/
function choose_pdf_func(distr_string) {
var variances = [];
let transform_func = get_grid_transform(distr_string);
let substrings = parse.get_distr_substrings(distr_string);
var pdfs = get_distributions(substrings);
if (pdfs.length === 1) {
return [pdfs[0], []];
}
var start_pt = 0;
var end_pt = 0;
for (let i = 0; i < pdfs.length; ++i) {
var outputs = [];
for (let j = 0; j < 20; ++j) {
let tree = new bst.AVLTree();
let [deterministic_pdf, mc_distrs] = pluck_from_array(pdfs, i);
let [this_start_pt, this_end_pt] = update_transformed_divider_points_bst(
transform_func,
deterministic_pdf,
mc_distrs,
0,
10,
tree
);
[start_pt, end_pt] =
j === 0 ? [this_start_pt, this_end_pt] : [start_pt, end_pt];
var output_grid = evenly_spaced_grid(start_pt, end_pt, 100);
let final_pdf_vals = get_final_pdf(
[deterministic_pdf.pdf_vals],
tree,
output_grid
);
outputs.push(final_pdf_vals);
}
variances.push(variance(outputs));
}
let best_variance = Math.min(...variances);
let best_idx = variances
.map((val, idx) => [val, idx])
.filter(x => x[0] === best_variance)[0][1];
let mc_distrs = pdfs.slice(0, best_idx).concat(pdfs.slice(best_idx + 1));
return [pdfs[best_idx], mc_distrs];
}
/**
* @param distr_string
* @returns {function(*): *}
*/
function get_grid_transform(distr_string) {
let substrings = parse.get_distr_substrings(distr_string);
let arg_strings = [];
for (let i = 0; i < substrings.length; ++i) {
distr_string = distr_string.replace(substrings[i], "x_" + i.toString());
arg_strings.push("x_" + i.toString());
}
let compiled = math.compile(distr_string);
function grid_transform(x) {
let kv_pairs = arg_strings.map((val, idx) => [val, x[idx]]);
let args_obj = Object.fromEntries(new Map(kv_pairs));
return compiled.evaluate(args_obj);
}
return grid_transform;
}
exports.get_pdf_from_user_input = get_pdf_from_user_input;

View File

@ -1,139 +0,0 @@
const _math = require("mathjs");
const math = _math.create(_math.all);
// Functions for parsing/processing user input strings are here
// @todo: Do not use objects.
const DISTR_REGEXS = [
/beta\(/g,
/(log)?normal\(/g,
/multimodal\(/g,
/mm\(/g,
/uniform\(/g
];
/**
* @param user_input_string
* @returns {{mm_args_string: string, outer_string: string}}
*/
function parse_initial_string(user_input_string) {
let outer_output_string = "";
let mm_args_string = "";
let idx = 0;
while (idx < user_input_string.length) {
if (
user_input_string.substring(idx - 11, idx) === "multimodal(" ||
user_input_string.substring(idx - 3, idx) === "mm("
) {
let num_open_brackets = 1;
while (num_open_brackets > 0 && idx < user_input_string.length) {
mm_args_string += user_input_string[idx];
idx += 1;
if (user_input_string[idx] === ")") {
num_open_brackets -= 1;
} else if (user_input_string[idx] === "(") {
num_open_brackets += 1;
}
}
outer_output_string += ")";
idx += 1;
} else {
outer_output_string += user_input_string[idx];
idx += 1;
}
}
return {
outer_string: outer_output_string,
mm_args_string: mm_args_string
};
}
/**
* @param mm_args_string
* @returns {{distrs: [], weights: string}}
*/
function separate_mm_args(mm_args_string) {
if (mm_args_string.endsWith(",")) {
mm_args_string = mm_args_string.slice(0, -1);
}
let args_array = [];
let num_open_brackets = 0;
let arg_substring = "";
for (let char of mm_args_string) {
if (num_open_brackets === 0 && char === ",") {
args_array.push(arg_substring.trim());
arg_substring = "";
} else {
if (char === ")" || char === "]") {
num_open_brackets -= 1;
} else if (char === "(" || char === "[") {
num_open_brackets += 1;
}
arg_substring += char;
}
}
return {
distrs: args_array,
weights: arg_substring.trim()
};
}
/**
* @param distr_string
* @returns {[]}
*/
function get_distr_substrings(distr_string) {
let substrings = [];
for (let regex of DISTR_REGEXS) {
let matches = distr_string.matchAll(regex);
for (let match of matches) {
let idx = match.index + match[0].length;
let num_open_brackets = 1;
let distr_substring = "";
while (num_open_brackets !== 0 && idx < distr_string.length) {
distr_substring += distr_string[idx];
if (distr_string[idx] === "(") {
num_open_brackets += 1;
} else if (distr_string[idx] === ")") {
num_open_brackets -= 1;
}
idx += 1;
}
substrings.push((match[0] + distr_substring).trim());
}
}
return substrings;
}
/**
* @param substr
* @returns {(string|*)[]}
*/
function get_distr_name_and_args(substr) {
let distr_name = "";
let args_str = "";
let args_flag = false;
for (let char of substr) {
if (!args_flag && char !== "(") {
distr_name += char;
}
if (args_flag && char !== ")") {
args_str += char;
}
if (char === "(") {
args_str += "[";
args_flag = true;
}
}
args_str += "]";
let args = math.compile(args_str).evaluate()._data;
return [distr_name, args];
}
exports.get_distr_name_and_args = get_distr_name_and_args;
exports.get_distr_substrings = get_distr_substrings;
exports.separate_mm_args = separate_mm_args;
exports.parse_initial_string = parse_initial_string;

View File

@ -40,16 +40,5 @@ let run =
(inputs: RenderTypes.ShapeRenderer.Combined.inputs)
: RenderTypes.ShapeRenderer.Combined.outputs => {
let symbolic = runSymbolic(inputs);
let sampling =
switch (symbolic) {
| Ok(_) => None
| Error(_) =>
Samples.T.fromGuesstimatorString(
~guesstimatorString=inputs.guesstimatorString,
~samplingInputs=inputs.samplingInputs,
(),
)
};
Js.log3("IS SOME?", symbolic |> E.R.toOption |> E.O.isSome, symbolic);
{symbolic: Some(symbolic), sampling};
{symbolic: Some(symbolic), sampling: None};
};

View File

@ -1,13 +0,0 @@
[@bs.deriving abstract]
type discrete = {
xs: array(float),
ys: array(float),
};
let jsToDistDiscrete = (d: discrete): DistTypes.discreteShape => {xyShape: {
xs: xsGet(d),
ys: ysGet(d),
}, knownIntegralSum: None};
[@bs.module "./GuesstimatorLibrary.js"]
external stringToSamples: (string, int) => array(float) = "stringToSamples";

View File

@ -1,37 +0,0 @@
const _ = require("lodash");
const {
Guesstimator
} = require('@foretold/guesstimator/src');
const stringToSamples = (
text,
sampleCount,
inputs = [],
) => {
const [_error, {
parsedInput,
parsedError
}] = Guesstimator.parse({
text: "=" + text
});
const guesstimator = new Guesstimator({
parsedInput
});
const {
values,
errors
} = guesstimator.sample(
sampleCount,
inputs,
);
if (errors.length > 0) {
return []
} else {
return _.filter(values, _.isFinite)
}
};
module.exports = {
stringToSamples,
};

View File

@ -175,26 +175,4 @@ module T = {
RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs);
toShape(~samples, ~samplingInputs, ());
};
let fromGuesstimatorString =
(
~guesstimatorString,
~samplingInputs=RenderTypes.ShapeRenderer.Sampling.Inputs.empty,
(),
) => {
let hasValidSamples =
Guesstimator.stringToSamples(guesstimatorString, 10) |> E.A.length > 0;
let _samplingInputs =
RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs);
switch (hasValidSamples) {
| false => None
| true =>
let samples =
Guesstimator.stringToSamples(
guesstimatorString,
_samplingInputs.sampleCount,
);
Some(fromSamples(~samplingInputs, samples));
};
};
};