First full-through with symbolic parsing
This commit is contained in:
parent
0e0f0221e9
commit
f662ccd6c6
11
__tests__/Jstat__test.re
Normal file
11
__tests__/Jstat__test.re
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
open Jest;
|
||||||
|
open Expect;
|
||||||
|
|
||||||
|
describe("Shape", () => {
|
||||||
|
describe("Continuous", () => {
|
||||||
|
test("", () => {
|
||||||
|
Js.log(Jstat.Jstat.normal);
|
||||||
|
expect(Jstat.Jstat.normal##pdf(3.0, 3.0, 3.0)) |> toEqual(1.0);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
22
__tests__/Parser__test.re
Normal file
22
__tests__/Parser__test.re
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
open Jest;
|
||||||
|
open Expect;
|
||||||
|
|
||||||
|
let json = Mathjs.parseMath("mm(normal(5,2), normal(10))");
|
||||||
|
|
||||||
|
describe("Shape", () => {
|
||||||
|
describe("Parser", () => {
|
||||||
|
test("", () => {
|
||||||
|
let parsed1 = MathJsParser.parseMathjs(json);
|
||||||
|
let parsed2 =
|
||||||
|
(
|
||||||
|
switch (parsed1 |> E.O.fmap(MathJsParser.toValue)) {
|
||||||
|
| Some(Ok(r)) => Some(r)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> E.O.fmap(Jstat.toString);
|
||||||
|
Js.log2("YOYOYYO", parsed2);
|
||||||
|
expect(1.0) |> toEqual(1.0);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
5
__tests__/math__test.js
Normal file
5
__tests__/math__test.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const foo = require('./mathtest')
|
||||||
|
|
||||||
|
test('sdf', () => {
|
||||||
|
expect(1).toBe(2)
|
||||||
|
})
|
64
__tests__/mathtest.js
Normal file
64
__tests__/mathtest.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// This example demonstrates importing a custom data type,
|
||||||
|
// and extending an existing function (add) with support for this data type.
|
||||||
|
|
||||||
|
const { create, factory, all } = require('mathjs');
|
||||||
|
const math = create(all)
|
||||||
|
|
||||||
|
// factory function which defines a new data type FunctionalDistribution
|
||||||
|
const createFunctionalDistribution = factory('FunctionalDistribution', ['typed'], ({ typed }) => {
|
||||||
|
// create a new data type
|
||||||
|
function FunctionalDistribution (value) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
FunctionalDistribution.prototype.isFunctionalDistribution = true
|
||||||
|
FunctionalDistribution.prototype.toString = function () {
|
||||||
|
return 'FunctionalDistribution:' + this.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// define a new data type with typed-function
|
||||||
|
typed.addType({
|
||||||
|
name: 'FunctionalDistribution',
|
||||||
|
test: function (x) {
|
||||||
|
// test whether x is of type FunctionalDistribution
|
||||||
|
return x && x.isFunctionalDistribution === true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return FunctionalDistribution
|
||||||
|
})
|
||||||
|
|
||||||
|
// function add which can add the FunctionalDistribution data type
|
||||||
|
// When imported in math.js, the existing function `add` with support for
|
||||||
|
// FunctionalDistribution, because both implementations are typed-functions and do not
|
||||||
|
// have conflicting signatures.
|
||||||
|
const createAddFunctionalDistribution = factory('add', ['typed', 'FunctionalDistribution'], ({ typed, FunctionalDistribution }) => {
|
||||||
|
return typed('add', {
|
||||||
|
'FunctionalDistribution, FunctionalDistribution': function (a, b) {
|
||||||
|
return new FunctionalDistribution(a.value + b.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const createSubtractFunctionalDistribution = factory('subtract', ['typed', 'FunctionalDistribution'], ({ typed, FunctionalDistribution }) => {
|
||||||
|
return typed('subtract', {
|
||||||
|
'FunctionalDistribution, FunctionalDistribution': function (a, b) {
|
||||||
|
return new FunctionalDistribution(a.value - b.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// import the new data type and function
|
||||||
|
math.import([
|
||||||
|
createFunctionalDistribution,
|
||||||
|
createAddFunctionalDistribution,
|
||||||
|
createSubtractFunctionalDistribution
|
||||||
|
])
|
||||||
|
|
||||||
|
// use the new type
|
||||||
|
const ans = math.chain(new math.FunctionalDistribution(2)).subtract(new math.FunctionalDistribution(3))
|
||||||
|
// ans = FunctionalDistribution(5)
|
||||||
|
|
||||||
|
console.log(ans.toString())
|
||||||
|
// outputs 'FunctionalDistribution:5'
|
||||||
|
|
||||||
|
module.exports = ans
|
|
@ -3,7 +3,8 @@
|
||||||
"reason": {
|
"reason": {
|
||||||
"react-jsx": 3
|
"react-jsx": 3
|
||||||
},
|
},
|
||||||
"sources": [{
|
"sources": [
|
||||||
|
{
|
||||||
"dir": "src",
|
"dir": "src",
|
||||||
"subdirs": true
|
"subdirs": true
|
||||||
},
|
},
|
||||||
|
@ -19,14 +20,17 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"bsc-flags": ["-bs-super-errors", "-bs-no-version-header"],
|
"bsc-flags": ["-bs-super-errors", "-bs-no-version-header"],
|
||||||
"package-specs": [{
|
"package-specs": [
|
||||||
"module": "commonjs",
|
{
|
||||||
"in-source": true
|
"module": "commonjs",
|
||||||
}],
|
"in-source": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"suffix": ".bs.js",
|
"suffix": ".bs.js",
|
||||||
"namespace": true,
|
"namespace": true,
|
||||||
"bs-dependencies": [
|
"bs-dependencies": [
|
||||||
"@glennsl/bs-jest",
|
"@glennsl/bs-jest",
|
||||||
|
"@glennsl/bs-json",
|
||||||
"@foretold/components",
|
"@foretold/components",
|
||||||
"bs-ant-design-alt",
|
"bs-ant-design-alt",
|
||||||
"reason-react",
|
"reason-react",
|
||||||
|
@ -37,7 +41,5 @@
|
||||||
"reschema"
|
"reschema"
|
||||||
],
|
],
|
||||||
"refmt": 3,
|
"refmt": 3,
|
||||||
"ppx-flags": [
|
"ppx-flags": ["lenses-ppx/ppx"]
|
||||||
"lenses-ppx/ppx"
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"@foretold/components": "0.0.3",
|
"@foretold/components": "0.0.3",
|
||||||
"@foretold/guesstimator": "1.0.10",
|
"@foretold/guesstimator": "1.0.10",
|
||||||
"@glennsl/bs-jest": "^0.5.0",
|
"@glennsl/bs-jest": "^0.5.0",
|
||||||
|
"@glennsl/bs-json": "^5.0.2",
|
||||||
"antd": "3.17.0",
|
"antd": "3.17.0",
|
||||||
"autoprefixer": "9.7.4",
|
"autoprefixer": "9.7.4",
|
||||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||||
|
@ -65,4 +66,4 @@
|
||||||
"react": "./node_modules/react",
|
"react": "./node_modules/react",
|
||||||
"react-dom": "./node_modules/react-dom"
|
"react-dom": "./node_modules/react-dom"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ class BaseDistributionBinned {
|
||||||
this.max_bin_size = 0.005;
|
this.max_bin_size = 0.005;
|
||||||
this.min_bin_size = 0;
|
this.min_bin_size = 0;
|
||||||
this.increment = 0.0001;
|
this.increment = 0.0001;
|
||||||
this.desired_delta = 0.0001;
|
this.desired_delta = 0.001;
|
||||||
this.start_bin_size = 0.0001;
|
this.start_bin_size = 0.0001;
|
||||||
|
|
||||||
[this.params, this.pdf_func, this.sample] = this.get_params_and_pdf_func(
|
[this.params, this.pdf_func, this.sample] = this.get_params_and_pdf_func(
|
||||||
|
@ -44,6 +44,8 @@ class BaseDistributionBinned {
|
||||||
throw new Error("NotImplementedError");
|
throw new Error("NotImplementedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Adaptive binning. Specify a desired change in density to get adjusted bin sizes.
|
||||||
/**
|
/**
|
||||||
* @returns {(number[]|[*])[]}
|
* @returns {(number[]|[*])[]}
|
||||||
* @private
|
* @private
|
||||||
|
|
|
@ -8,6 +8,7 @@ const math = _math.create(_math.all);
|
||||||
const NUM_MC_SAMPLES = 3000;
|
const NUM_MC_SAMPLES = 3000;
|
||||||
const OUTPUT_GRID_NUMEL = 3000;
|
const OUTPUT_GRID_NUMEL = 3000;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main algorithmic work is done by functions in this module.
|
* The main algorithmic work is done by functions in this module.
|
||||||
* It also contains the main function, taking the user's string
|
* It also contains the main function, taking the user's string
|
||||||
|
@ -290,6 +291,7 @@ function pluck_from_array(array, idx) {
|
||||||
* If distr_string requires MC, try all possible
|
* If distr_string requires MC, try all possible
|
||||||
* choices for the deterministic distribution,
|
* choices for the deterministic distribution,
|
||||||
* and pick the one with the least variance.
|
* and pick the one with the least variance.
|
||||||
|
* It's much better to sample from a normal than a lognormal.
|
||||||
*
|
*
|
||||||
* @param distr_string
|
* @param distr_string
|
||||||
* @returns {(*|*[])[]|*[]}
|
* @returns {(*|*[])[]|*[]}
|
||||||
|
|
|
@ -200,13 +200,6 @@ module T = {
|
||||||
| (true, true) => (-1)
|
| (true, true) => (-1)
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: This is broken :(
|
|
||||||
let combine = (t1: t, t2: t) => {
|
|
||||||
let array = Belt.Array.concat(zip(t1), zip(t2));
|
|
||||||
Array.fast_sort(comparePoints, array);
|
|
||||||
array |> Belt.Array.unzip |> fromArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: I'd bet this is pretty slow
|
// TODO: I'd bet this is pretty slow
|
||||||
let intersperce = (t1: t, t2: t) => {
|
let intersperce = (t1: t, t2: t) => {
|
||||||
let items: ref(array((float, float))) = ref([||]);
|
let items: ref(array((float, float))) = ref([||]);
|
||||||
|
|
183
src/symbolic/Jstat.re
Normal file
183
src/symbolic/Jstat.re
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
// Todo: Another way of doing this is with [@bs.scope "normal"], which may be more elegant
|
||||||
|
module Jstat = {
|
||||||
|
type normal = {
|
||||||
|
.
|
||||||
|
[@bs.meth] "pdf": (float, float, float) => float,
|
||||||
|
[@bs.meth] "cdf": (float, float, float) => float,
|
||||||
|
[@bs.meth] "inv": (float, float, float) => float,
|
||||||
|
[@bs.meth] "sample": (float, float) => float,
|
||||||
|
};
|
||||||
|
type lognormal = {
|
||||||
|
.
|
||||||
|
[@bs.meth] "pdf": (float, float, float) => float,
|
||||||
|
[@bs.meth] "cdf": (float, float, float) => float,
|
||||||
|
[@bs.meth] "inv": (float, float, float) => float,
|
||||||
|
[@bs.meth] "sample": (float, float) => float,
|
||||||
|
};
|
||||||
|
type uniform = {
|
||||||
|
.
|
||||||
|
[@bs.meth] "pdf": (float, float, float) => float,
|
||||||
|
[@bs.meth] "cdf": (float, float, float) => float,
|
||||||
|
[@bs.meth] "inv": (float, float, float) => float,
|
||||||
|
[@bs.meth] "sample": (float, float) => float,
|
||||||
|
};
|
||||||
|
[@bs.module "jStat"] external normal: normal = "normal";
|
||||||
|
[@bs.module "jStat"] external lognormal: lognormal = "lognormal";
|
||||||
|
[@bs.module "jStat"] external uniform: uniform = "uniform";
|
||||||
|
};
|
||||||
|
|
||||||
|
type normal = {
|
||||||
|
mean: float,
|
||||||
|
stdev: float,
|
||||||
|
};
|
||||||
|
|
||||||
|
type lognormal = {
|
||||||
|
mu: float,
|
||||||
|
sigma: float,
|
||||||
|
};
|
||||||
|
|
||||||
|
type uniform = {
|
||||||
|
low: float,
|
||||||
|
high: float,
|
||||||
|
};
|
||||||
|
|
||||||
|
module Normal = {
|
||||||
|
type t = normal;
|
||||||
|
let pdf = (x, t: t) => Jstat.normal##pdf(x, t.mean, t.stdev);
|
||||||
|
let inv = (p, t: t) => Jstat.normal##inv(p, t.mean, t.stdev);
|
||||||
|
let sample = (t: t) => Jstat.normal##sample(t.mean, t.stdev);
|
||||||
|
let toString = ({mean, stdev}: t) => {j|Normal($mean,$stdev)|j};
|
||||||
|
};
|
||||||
|
|
||||||
|
module Lognormal = {
|
||||||
|
type t = lognormal;
|
||||||
|
let pdf = (x, t: t) => Jstat.lognormal##pdf(x, t.mu, t.sigma);
|
||||||
|
let inv = (p, t: t) => Jstat.lognormal##inv(p, t.mu, t.sigma);
|
||||||
|
let sample = (t: t) => Jstat.lognormal##sample(t.mu, t.sigma);
|
||||||
|
let toString = ({mu, sigma}: t) => {j|Lognormal($mu,$sigma)|j};
|
||||||
|
};
|
||||||
|
|
||||||
|
module Uniform = {
|
||||||
|
type t = uniform;
|
||||||
|
let pdf = (x, t: t) => Jstat.uniform##pdf(x, t.low, t.high);
|
||||||
|
let inv = (p, t: t) => Jstat.uniform##inv(p, t.low, t.high);
|
||||||
|
let sample = (t: t) => Jstat.uniform##sample(t.low, t.high);
|
||||||
|
let toString = ({low, high}: t) => {j|Uniform($low,$high)|j};
|
||||||
|
};
|
||||||
|
|
||||||
|
type dist = [
|
||||||
|
| `Normal(normal)
|
||||||
|
| `Lognormal(lognormal)
|
||||||
|
| `Uniform(uniform)
|
||||||
|
];
|
||||||
|
|
||||||
|
module Mixed = {
|
||||||
|
let pdf = (x, dist) =>
|
||||||
|
switch (dist) {
|
||||||
|
| `Normal(n) => Normal.pdf(x, n)
|
||||||
|
| `Lognormal(n) => Lognormal.pdf(x, n)
|
||||||
|
| `Uniform(n) => Uniform.pdf(x, n)
|
||||||
|
};
|
||||||
|
|
||||||
|
let inv = (x, dist) =>
|
||||||
|
switch (dist) {
|
||||||
|
| `Normal(n) => Normal.inv(x, n)
|
||||||
|
| `Lognormal(n) => Lognormal.inv(x, n)
|
||||||
|
| `Uniform(n) => Uniform.inv(x, n)
|
||||||
|
};
|
||||||
|
|
||||||
|
let sample = dist =>
|
||||||
|
switch (dist) {
|
||||||
|
| `Normal(n) => Normal.sample(n)
|
||||||
|
| `Lognormal(n) => Lognormal.sample(n)
|
||||||
|
| `Uniform(n) => Uniform.sample(n)
|
||||||
|
};
|
||||||
|
|
||||||
|
let toString = dist =>
|
||||||
|
switch (dist) {
|
||||||
|
| `Normal(n) => Normal.toString(n)
|
||||||
|
| `Lognormal(n) => Lognormal.toString(n)
|
||||||
|
| `Uniform(n) => Uniform.toString(n)
|
||||||
|
};
|
||||||
|
|
||||||
|
let min = dist =>
|
||||||
|
switch (dist) {
|
||||||
|
| `Normal(n) => Normal.inv(0.01, n)
|
||||||
|
| `Lognormal(n) => Lognormal.inv(0.01, n)
|
||||||
|
| `Uniform({low}) => low
|
||||||
|
};
|
||||||
|
|
||||||
|
let max = dist =>
|
||||||
|
switch (dist) {
|
||||||
|
| `Normal(n) => Normal.inv(0.99, n)
|
||||||
|
| `Lognormal(n) => Lognormal.inv(0.99, n)
|
||||||
|
| `Uniform({high}) => high
|
||||||
|
};
|
||||||
|
|
||||||
|
// will space linear
|
||||||
|
let toShape =
|
||||||
|
(~xSelection: [ | `Linear | `ByWeight]=`Linear, dist: dist, sampleCount) => {
|
||||||
|
let xs =
|
||||||
|
switch (xSelection) {
|
||||||
|
| `Linear => Functions.range(min(dist), max(dist), sampleCount)
|
||||||
|
| `ByWeight =>
|
||||||
|
Functions.range(0.001, 0.999, sampleCount)
|
||||||
|
|> E.A.fmap(x => inv(x, dist))
|
||||||
|
};
|
||||||
|
let ys = xs |> E.A.fmap(r => pdf(r, dist));
|
||||||
|
XYShape.T.fromArrays(xs, ys);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// module PointwiseCombination = {
|
||||||
|
// type math = Multiply | Add | Exponent | Power;
|
||||||
|
// let fn = fun
|
||||||
|
// | Multiply => 3.0
|
||||||
|
// | Add => 4.0
|
||||||
|
// }
|
||||||
|
|
||||||
|
module PointwiseAddDistributionsWeighted = {
|
||||||
|
type t = array((dist, float));
|
||||||
|
|
||||||
|
let normalizeWeights = (dists: t) => {
|
||||||
|
let total = dists |> E.A.fmap(snd) |> Functions.sum;
|
||||||
|
dists |> E.A.fmap(((a, b)) => (a, b /. total));
|
||||||
|
};
|
||||||
|
|
||||||
|
let pdf = (dists: t, x: float) =>
|
||||||
|
dists |> E.A.fmap(((e, w)) => Mixed.pdf(x, e) *. w) |> Functions.sum;
|
||||||
|
|
||||||
|
let min = (dists: t) =>
|
||||||
|
dists |> E.A.fmap(d => d |> fst |> Mixed.min) |> Functions.min;
|
||||||
|
|
||||||
|
let max = (dists: t) =>
|
||||||
|
dists |> E.A.fmap(d => d |> fst |> Mixed.min) |> Functions.min;
|
||||||
|
|
||||||
|
let toShape = (dists: t, sampleCount: int) => {
|
||||||
|
let xs = Functions.range(min(dists), max(dists), sampleCount);
|
||||||
|
let ys = xs |> E.A.fmap(pdf(dists));
|
||||||
|
XYShape.T.fromArrays(xs, ys);
|
||||||
|
};
|
||||||
|
|
||||||
|
let toString = (dists: t) => {
|
||||||
|
let distString =
|
||||||
|
dists
|
||||||
|
|> E.A.fmap(d => Mixed.toString(fst(d)))
|
||||||
|
|> Js.Array.joinWith(",");
|
||||||
|
{j|pointwideAdded($distString)|j};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type bigDist = [
|
||||||
|
| `Dist(dist)
|
||||||
|
| `PointwiseCombination(PointwiseAddDistributionsWeighted.t)
|
||||||
|
];
|
||||||
|
|
||||||
|
let toString = (r: bigDist) =>
|
||||||
|
r
|
||||||
|
|> (
|
||||||
|
fun
|
||||||
|
| `Dist(d) => Mixed.toString(d)
|
||||||
|
| `PointwiseCombination(d) =>
|
||||||
|
PointwiseAddDistributionsWeighted.toString(d)
|
||||||
|
);
|
58
src/symbolic/MathJsParser.re
Normal file
58
src/symbolic/MathJsParser.re
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
open Jstat;
|
||||||
|
|
||||||
|
type arg =
|
||||||
|
| Value(float)
|
||||||
|
| Fn(fn)
|
||||||
|
and fn = {
|
||||||
|
name: string,
|
||||||
|
args: array(arg),
|
||||||
|
};
|
||||||
|
|
||||||
|
let rec parseMathjs = (j: Js.Json.t) => {
|
||||||
|
Json.Decode.(
|
||||||
|
switch (field("mathjs", string, j)) {
|
||||||
|
| "FunctionNode" =>
|
||||||
|
let args = j |> field("args", array(parseMathjs));
|
||||||
|
Some(
|
||||||
|
Fn({
|
||||||
|
name: j |> field("fn", field("name", string)),
|
||||||
|
args: args |> E.A.O.concatSomes,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
| "ConstantNode" => Some(Value(field("value", float, j)))
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let normal = (r): result(bigDist, string) =>
|
||||||
|
r
|
||||||
|
|> (
|
||||||
|
fun
|
||||||
|
| [|Value(mean), Value(stdev)|] => Ok(`Dist(`Normal({mean, stdev})))
|
||||||
|
| _ => Error("Wrong number of variables in normal distribution")
|
||||||
|
);
|
||||||
|
|
||||||
|
let rec toValue = (r): result(bigDist, string) =>
|
||||||
|
r
|
||||||
|
|> (
|
||||||
|
fun
|
||||||
|
| Value(_) => Error("Top level can't be value")
|
||||||
|
| Fn({name: "normal", args}) => normal(args)
|
||||||
|
| Fn({name: "mm", args}) => {
|
||||||
|
let dists: array(dist) =
|
||||||
|
args
|
||||||
|
|> E.A.fmap(toValue)
|
||||||
|
|> E.A.fmap(
|
||||||
|
fun
|
||||||
|
| Ok(`Dist(`Normal({mean, stdev}))) =>
|
||||||
|
Some(`Normal({mean, stdev}))
|
||||||
|
| _ => None,
|
||||||
|
)
|
||||||
|
|> E.A.O.concatSomes;
|
||||||
|
|
||||||
|
let inputs = dists |> E.A.fmap(r => (r, 1.0));
|
||||||
|
Ok(`PointwiseCombination(inputs));
|
||||||
|
}
|
||||||
|
| Fn({name}) => Error(name ++ ": name not found")
|
||||||
|
);
|
2
src/symbolic/Mathjs.re
Normal file
2
src/symbolic/Mathjs.re
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[@bs.module "./MathjsWrapper.js"]
|
||||||
|
external parseMath: string => Js.Json.t = "parseMath";
|
8
src/symbolic/MathjsWrapper.js
Normal file
8
src/symbolic/MathjsWrapper.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
const math = require("mathjs");
|
||||||
|
|
||||||
|
function parseMath(f){ return JSON.parse(JSON.stringify(math.parse(f))) };
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
parseMath,
|
||||||
|
};
|
14
yarn.lock
14
yarn.lock
|
@ -1017,15 +1017,6 @@
|
||||||
lodash "4.17.15"
|
lodash "4.17.15"
|
||||||
pdfast "0.2.0"
|
pdfast "0.2.0"
|
||||||
|
|
||||||
"@foretold/cdf@1.0.15":
|
|
||||||
version "1.0.15"
|
|
||||||
resolved "https://registry.yarnpkg.com/@foretold/cdf/-/cdf-1.0.15.tgz#69ce4755158693e3d325e7be10d0aa9cdb465730"
|
|
||||||
integrity sha512-I7GhFQd4HaFd+tGD1IJ0W8xvFp2YiJdcFiXSCq9vYQZWWy+Npi4QOYsMoDJyoUTvOlVba4ARa/pDKPD2hn+uuQ==
|
|
||||||
dependencies:
|
|
||||||
lodash "4.17.15"
|
|
||||||
parcel "1.12.3"
|
|
||||||
pdfast "0.2.0"
|
|
||||||
|
|
||||||
"@foretold/components@0.0.3":
|
"@foretold/components@0.0.3":
|
||||||
version "0.0.3"
|
version "0.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@foretold/components/-/components-0.0.3.tgz#a195912647499735f64cb2b74f722eee4b2da13f"
|
resolved "https://registry.yarnpkg.com/@foretold/components/-/components-0.0.3.tgz#a195912647499735f64cb2b74f722eee4b2da13f"
|
||||||
|
@ -1081,6 +1072,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
jest "^25.1.0"
|
jest "^25.1.0"
|
||||||
|
|
||||||
|
"@glennsl/bs-json@^5.0.2":
|
||||||
|
version "5.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@glennsl/bs-json/-/bs-json-5.0.2.tgz#cfb85d94d370ec6dc17849e0ddb1a51eee08cfcc"
|
||||||
|
integrity sha512-vVlHJNrhmwvhyea14YiV4L5pDLjqw1edE3GzvMxlbPPQZVhzgO3sTWrUxCpQd2gV+CkMfk4FHBYunx9nWtBoDg==
|
||||||
|
|
||||||
"@iarna/toml@^2.2.0":
|
"@iarna/toml@^2.2.0":
|
||||||
version "2.2.3"
|
version "2.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.3.tgz#f060bf6eaafae4d56a7dac618980838b0696e2ab"
|
resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.3.tgz#f060bf6eaafae4d56a7dac618980838b0696e2ab"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user