commit 1b583810b6039c5a9efe079587542a271c427ff9
parent 2ebba9f79d835b76b288a76058e823af23cd00f8
Author: NunoSempere <nuno.sempere@protonmail.com>
Date: Sat, 16 Apr 2022 12:55:44 -0400
fix: Document before committing
Diffstat:
| A | README.md | | | 108 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | cli.js | | | 34 | ---------------------------------- |
| A | imgs/simple-rick.jpg | | | 0 | |
| A | imgs/simple-squiggle.png | | | 0 | |
| D | index.js | | | 237 | ------------------------------------------------------------------------------- |
| M | package.json | | | 3 | ++- |
| A | src/cli.js | | | 34 | ++++++++++++++++++++++++++++++++++ |
| A | src/index.js | | | 237 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/tests.js | | | 76 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | tests.js | | | 74 | -------------------------------------------------------------------------- |
10 files changed, 457 insertions(+), 346 deletions(-)
diff --git a/README.md b/README.md
@@ -0,0 +1,108 @@
+# Simple Squiggle
+
+## About
+
+
+
+"Simple Squiggle" is a simple parser that manipulates multiplications and divisions between numbers and lognormal. It uses a very restricted subset of Squiggle's syntax, and unlike it, it is not easily extensible. It may be useful for testing correctness of limited features of the full Squiggle.
+
+
+
+## Built with
+
+- [Node.js](https://nodejs.org/en/)
+- [Math.js](https://mathjs.org/)
+- [Best Readme template](https://github.com/othneildrew/Best-README-Template/blob/master/README.md)
+
+## Getting started
+
+### Prerequisites
+
+- npm
+- nodejs
+
+### Installation
+
+```
+git clone https://github.com/quantified-uncertainty/simple-squiggle.git
+cd simple-squiggle
+## npm install
+```
+
+The last line is not necessary, since I'm saving node_packages in the repository.
+
+## Usage
+
+Consider a squiggle model which only uses lognormals:
+
+```
+initialPrisonPopulation = 1.8M to 2.5M # Data for 2022 prison population has not yet been published, though this estimate is perhaps too wide.
+reductionInPrisonPopulation = 0.25 to 0.75
+badnessOfPrisonInQALYs = 0.2 to 5 # 80% as good as being alive to 5 times worse than living is good
+accelerationInYears = 5 to 50
+probabilityOfSuccess = 0.01 to 0.1 # 1% to 10%.
+estimateQALYs = leftTruncate(
+ initialPrisonPopulation *
+ reductionInPrisonPopulation *
+ badnessOfPrisonInQALYs *
+ accelerationInYears *
+ probabilityOfSuccess
+ , 0)
+cost = 2B to 20B
+costEffectivenessPerQALY = leftTruncate(cost / estimateQALYs, 0)
+costEffectivenessPerQALY
+```
+
+It can be simplified to the following simple squiggle model:
+
+```
+( 2000000000 to 20000000000 ) / ( (1800000 to 2500000) * (0.25 to 0.75) * (0.2 to 5) * (5 to 50) * (0.01 to 0.1) )
+```
+
+I provide both an exportable library and a command line interface (cli). The cli can be run with `npm run cli`, which produces a prompt:
+
+```
+> npm run cli
+
+Model:
+```
+
+After filling in the prompt
+
+```
+> npm run cli
+
+Model: ( 2000000000 to 20000000000 ) / ( (1800000 to 2500000) * (0.25 to 0.75) * (0.2 to 5) * (5 to 50) * (0.01 to 0.1) )
+```
+
+the output looks as follows:
+
+```
+> npm run cli
+
+Model: ( 2000000000 to 20000000000 ) / ( (1800000 to 2500000) * (0.25 to 0.75) * (0.2 to 5) * (5 to 50) * (0.01 to 0.1) )
+
+ = (lognormal(22.57, 0.70)) / ((lognormal(14.57, 0.10)) * (lognormal(-0.84, 0.33)) * (lognormal(0.00, 0.98)) * (lognormal(2.76, 0.70)) * (lognormal(-3.45, 0.70)))
+ -> lognormal(22.57, 0.70) / (lognormal(14.57, 0.10) * lognormal(-0.84, 0.33) * lognormal(0.00, 0.98) * lognormal(2.76, 0.70) * lognormal(-3.45, 0.70))
+ -> lognormal(22.57, 0.70) / (lognormal(13.73, 0.35) * lognormal(0.00, 0.98) * lognormal(2.76, 0.70) * lognormal(-3.45, 0.70))
+ -> lognormal(22.57, 0.70) / (lognormal(13.73, 1.04) * lognormal(2.76, 0.70) * lognormal(-3.45, 0.70))
+ -> lognormal(22.57, 0.70) / (lognormal(16.49, 1.25) * lognormal(-3.45, 0.70))
+ -> lognormal(22.57, 0.70) / (lognormal(13.04, 1.43))
+ -> lognormal(22.57, 0.70) / lognormal(13.04, 1.43)
+ -> lognormal(9.53, 1.60)
+
+=> lognormal(9.530291704996749, 1.596443005980748)
+----------------------------------------------------
+```
+
+For ease of representation, the intermediary outputs are printed only to two decimal points. But this is just a display decision; the innards of the program work with the full set of decimals.
+
+You can also run tests with `npm run test`
+
+## Roadmap
+
+I consider this repository to be feature complete. As such, I may tinker with the wrapper to make it a bit less hacky, but I don't really intend to add further functionality.
+
+## License
+
+Distributed under the MIT License
diff --git a/cli.js b/cli.js
@@ -1,34 +0,0 @@
-import readline from "readline";
-import { transformer } from "./index.js";
-
-let VERBOSE = true;
-let print = (x) => {
- if (VERBOSE) {
- console.log(x);
- }
-};
-
-let runTransformer = (string) => {
- console.log(`Received: ${string}`);
- console.group();
- print("");
- let result = transformer(string, print);
- print("");
- console.groupEnd();
- console.log(`=> ${result}`);
- print("-".repeat(52));
- console.log("");
-};
-
-let cliWrapper = async (message, callback) => {
- const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout,
- });
- rl.question(message, async (answer) => {
- rl.close();
- await callback(answer);
- });
-};
-
-cliWrapper("Model: ", runTransformer);
diff --git a/imgs/simple-rick.jpg b/imgs/simple-rick.jpg
Binary files differ.
diff --git a/imgs/simple-squiggle.png b/imgs/simple-squiggle.png
Binary files differ.
diff --git a/index.js b/index.js
@@ -1,237 +0,0 @@
-import { create, all } from "mathjs";
-const math = create(all);
-
-// Helper functions
-let VERBOSE = true;
-let print = (x) => {
- if (VERBOSE) {
- console.log(x);
- }
-};
-let printNode = (x) => print(JSON.stringify(x, null, 4));
-
-let isNumber = (x) => typeof x === "number" && isFinite(x);
-
-let isConstantNode = (arg) => {
- return isNumber(arg.value);
-};
-
-let isNegativeNumberNode = (arg) => {
- return (
- arg.op == "-" && arg.fn == "unaryMinus" && arg.args && arg.args.length == 1
- );
-};
-let isArgLognormal = (arg) => {
- let isFn = typeof arg.fn != "undefined";
- let andNameIsLognormal = isFn && arg.fn.name == "lognormal";
- let andHasArgs = andNameIsLognormal && !!arg.args;
- let andHasTwoArgs = andHasArgs && arg.args.length == 2;
- let andTwoArgsAreCorrectType =
- andHasTwoArgs &&
- arg.args
- .map(
- (innerArg) => {
- let isConstant = isConstantNode(innerArg);
- let isNegative = isNegativeNumberNode(innerArg);
- return isConstant || isNegative;
- }
- // innerArg
- )
- .reduce((a, b) => a && b, true);
- return andTwoArgsAreCorrectType;
-};
-
-let getFactors = (node) => {
- return node.args.map((arg) => {
- if (isConstantNode(arg)) {
- return arg.value;
- } else if (isNegativeNumberNode(arg)) {
- return -arg.args[0].value;
- }
- });
-};
-
-let createLogarithmNode = (mu, sigma) => {
- let node1 = new math.ConstantNode(mu);
- let node2 = new math.ConstantNode(sigma);
- let node3 = new math.FunctionNode("lognormal", [node1, node2]);
- return node3;
-};
-
-// Main function
-let transformerInner = (string) => {
- let nodes = math.parse(string);
- let transformed = nodes.transform(function (node, path, parent) {
- // Multiplication
- if (node.type == "OperatorNode" && node.op == "*") {
- let hasTwoArgs = node.args && node.args.length == 2;
- if (hasTwoArgs) {
- // Multiplication of two lognormals
- let areArgsLognormal = node.args
- .map((arg) => isArgLognormal(arg))
- .reduce((a, b) => a && b, true);
-
- let isFirstArgLognormal = isArgLognormal(node.args[0]);
- let isSecondArgNumber = isConstantNode(node.args[1]);
- let isLognormalTimesNumber = isFirstArgLognormal * isSecondArgNumber;
-
- let isFirstArgNumber = isConstantNode(node.args[0]);
- let isSecondArgLognormal = isArgLognormal(node.args[1]);
- let isNumberTimesLognormal = isFirstArgNumber * isSecondArgLognormal;
-
- if (areArgsLognormal) {
- // lognormal times lognormal
- let factors = node.args.map((arg) => getFactors(arg));
- let mean1 = factors[0][0];
- let std1 = factors[0][1];
- let mean2 = factors[1][0];
- let std2 = factors[1][1];
-
- let newMean = mean1 + mean2;
- let newStd = Math.sqrt(std1 ** 2 + std2 ** 2);
- return createLogarithmNode(newMean, newStd);
- } else if (isLognormalTimesNumber) {
- // lognormal times number
- let lognormalFactors = getFactors(node.args[0]);
- let mean = lognormalFactors[0];
- let std = lognormalFactors[1];
- let multiplier = node.args[1].value;
- let logMultiplier = Math.log(multiplier);
- let newMean = mean + logMultiplier;
- return createLogarithmNode(newMean, std);
- } else if (isNumberTimesLognormal) {
- // number times lognormal
- let lognormalFactors = getFactors(node.args[1]);
- let mean = lognormalFactors[0];
- let std = lognormalFactors[1];
- let multiplier = node.args[0].value;
- let logMultiplier = Math.log(multiplier);
- let newMean = mean + logMultiplier;
- return createLogarithmNode(newMean, std);
- }
- }
- } else if (node.type == "OperatorNode" && node.op == "/") {
- let hasTwoArgs = node.args && node.args.length == 2;
- if (hasTwoArgs) {
- let areArgsLognormal = node.args
- .map((arg) => isArgLognormal(arg))
- .reduce((a, b) => a && b, true);
-
- let isFirstArgLognormal = isArgLognormal(node.args[0]);
- let isSecondArgNumber = isConstantNode(node.args[1]);
- let isLognormalDividedByNumber =
- isFirstArgLognormal * isSecondArgNumber;
-
- let isFirstArgNumber = isConstantNode(node.args[0]);
- let isSecondArgLognormal = isArgLognormal(node.args[1]);
- let isNumberDividedByLognormal =
- isFirstArgNumber * isSecondArgLognormal;
-
- if (areArgsLognormal) {
- let factors = node.args.map((arg) => getFactors(arg));
- let mean1 = factors[0][0];
- let std1 = factors[0][1];
- let mean2 = factors[1][0];
- let std2 = factors[1][1];
-
- let newMean = mean1 - mean2;
- let newStd = Math.sqrt(std1 ** 2 + std2 ** 2);
- return createLogarithmNode(newMean, newStd);
- return new math.SymbolNode("xx");
- } else if (isLognormalDividedByNumber) {
- let lognormalFactors = getFactors(node.args[0]);
- let mean = lognormalFactors[0];
- let std = lognormalFactors[1];
- let multiplier = node.args[1].value;
- let logMultiplier = Math.log(multiplier);
- let newMean = mean - logMultiplier;
- return createLogarithmNode(newMean, std);
- } else if (isNumberDividedByLognormal) {
- let lognormalFactors = getFactors(node.args[1]);
- let mean = lognormalFactors[0];
- let std = lognormalFactors[1];
- let multiplier = node.args[0].value;
- let logMultiplier = Math.log(multiplier);
- let newMean = -mean + logMultiplier;
- return createLogarithmNode(newMean, std);
- }
- }
- }
- if (node.type == "ParenthesisNode") {
- if (
- !!node.content &&
- !!node.content.fn &&
- node.content.fn.name == "lognormal"
- ) {
- return node.content;
- }
- }
- return node;
- });
-
- return transformed;
-};
-
-let from90PercentCI = (low, high) => {
- let normal95confidencePoint = 1.6448536269514722;
- let logLow = Math.log(low);
- let logHigh = Math.log(high);
- let mu = (logLow + logHigh) / 2;
- let sigma = (logHigh - logLow) / (2.0 * normal95confidencePoint);
- return [mu, sigma];
-};
-
-let simplePreprocessor = (string) => {
- // left for documentation purposes only
- function replacer(match, p1, p2) {
- print(match);
- // p1 is nondigits, p2 digits, and p3 non-alphanumericsa
- print([p1, p2]);
- let result = from90PercentCI(p1, p2);
- return `lognormal(${result[0]}, ${result[1]})`;
- }
- let newString = string.replace(/(\d+) to (\d+)/g, replacer);
- print(newString);
- return newString; // abc - 12345 - #$*%
-};
-
-// simplePreprocessor("1 to 10 + 1 to 20");
-
-let customToStringHandler = (node, options) => {
- if (node.type == "ConstantNode") {
- return node.value.toFixed(2);
- }
-};
-
-let preprocessor = (string, print = console.log) => {
- // work in progress, currently not working
- let regex = /([\d]+\.?[\d]*|\.[\d]+) to ([\d]+\.?[\d]*|\.[\d]+)/g;
- function replacer(match, p1, p2) {
- let result = from90PercentCI(p1, p2);
- return `lognormal(${result[0]}, ${result[1]})`;
- }
- let newString = string.replace(regex, replacer);
- if (newString != string)
- print(
- `\t= ${math
- .parse(newString)
- .toString({ handler: customToStringHandler })}`
- );
- return newString; // abc - 12345 - #$*%
-};
-// preprocessor("1.2 to 10.5 * 1.1 to 20 * 1 to 2.5 * 1 to 5");
-
-export function transformer(string, print = console.log) {
- string = preprocessor(string, print);
- let transformerOutput = transformerInner(string);
- let stringNew = transformerOutput.toString();
- while (stringNew != string) {
- print(
- `\t->: ${transformerOutput.toString({ handler: customToStringHandler })}`
- );
- string = stringNew;
- transformerOutput = transformerInner(string);
- stringNew = transformerOutput.toString();
- }
- return stringNew;
-}
diff --git a/package.json b/package.json
@@ -5,7 +5,8 @@
"main": "index.js",
"type": "module",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "node src/tests.js",
+ "cli": "node src/cli.js"
},
"author": "",
"license": "ISC",
diff --git a/src/cli.js b/src/cli.js
@@ -0,0 +1,34 @@
+import readline from "readline";
+import { transformer } from "./index.js";
+
+let VERBOSE = true;
+let print = (x) => {
+ if (VERBOSE) {
+ console.log(x);
+ }
+};
+
+let runTransformer = (string) => {
+ // console.log(`Received: ${string}`);
+ console.group();
+ print("");
+ let result = transformer(string, print);
+ print("");
+ console.groupEnd();
+ console.log(`=> ${result}`);
+ print("-".repeat(52));
+ console.log("");
+};
+
+let cliWrapper = async (message, callback) => {
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+ rl.question(message, async (answer) => {
+ rl.close();
+ await callback(answer);
+ });
+};
+
+cliWrapper("Model: ", runTransformer);
diff --git a/src/index.js b/src/index.js
@@ -0,0 +1,237 @@
+import { create, all } from "mathjs";
+const math = create(all);
+
+// Helper functions
+let VERBOSE = true;
+let print = (x) => {
+ if (VERBOSE) {
+ console.log(x);
+ }
+};
+let printNode = (x) => print(JSON.stringify(x, null, 4));
+
+let isNumber = (x) => typeof x === "number" && isFinite(x);
+
+let isConstantNode = (arg) => {
+ return isNumber(arg.value);
+};
+
+let isNegativeNumberNode = (arg) => {
+ return (
+ arg.op == "-" && arg.fn == "unaryMinus" && arg.args && arg.args.length == 1
+ );
+};
+let isArgLognormal = (arg) => {
+ let isFn = typeof arg.fn != "undefined";
+ let andNameIsLognormal = isFn && arg.fn.name == "lognormal";
+ let andHasArgs = andNameIsLognormal && !!arg.args;
+ let andHasTwoArgs = andHasArgs && arg.args.length == 2;
+ let andTwoArgsAreCorrectType =
+ andHasTwoArgs &&
+ arg.args
+ .map(
+ (innerArg) => {
+ let isConstant = isConstantNode(innerArg);
+ let isNegative = isNegativeNumberNode(innerArg);
+ return isConstant || isNegative;
+ }
+ // innerArg
+ )
+ .reduce((a, b) => a && b, true);
+ return andTwoArgsAreCorrectType;
+};
+
+let getFactors = (node) => {
+ return node.args.map((arg) => {
+ if (isConstantNode(arg)) {
+ return arg.value;
+ } else if (isNegativeNumberNode(arg)) {
+ return -arg.args[0].value;
+ }
+ });
+};
+
+let createLogarithmNode = (mu, sigma) => {
+ let node1 = new math.ConstantNode(mu);
+ let node2 = new math.ConstantNode(sigma);
+ let node3 = new math.FunctionNode("lognormal", [node1, node2]);
+ return node3;
+};
+
+// Main function
+let transformerInner = (string) => {
+ let nodes = math.parse(string);
+ let transformed = nodes.transform(function (node, path, parent) {
+ // Multiplication
+ if (node.type == "OperatorNode" && node.op == "*") {
+ let hasTwoArgs = node.args && node.args.length == 2;
+ if (hasTwoArgs) {
+ // Multiplication of two lognormals
+ let areArgsLognormal = node.args
+ .map((arg) => isArgLognormal(arg))
+ .reduce((a, b) => a && b, true);
+
+ let isFirstArgLognormal = isArgLognormal(node.args[0]);
+ let isSecondArgNumber = isConstantNode(node.args[1]);
+ let isLognormalTimesNumber = isFirstArgLognormal * isSecondArgNumber;
+
+ let isFirstArgNumber = isConstantNode(node.args[0]);
+ let isSecondArgLognormal = isArgLognormal(node.args[1]);
+ let isNumberTimesLognormal = isFirstArgNumber * isSecondArgLognormal;
+
+ if (areArgsLognormal) {
+ // lognormal times lognormal
+ let factors = node.args.map((arg) => getFactors(arg));
+ let mean1 = factors[0][0];
+ let std1 = factors[0][1];
+ let mean2 = factors[1][0];
+ let std2 = factors[1][1];
+
+ let newMean = mean1 + mean2;
+ let newStd = Math.sqrt(std1 ** 2 + std2 ** 2);
+ return createLogarithmNode(newMean, newStd);
+ } else if (isLognormalTimesNumber) {
+ // lognormal times number
+ let lognormalFactors = getFactors(node.args[0]);
+ let mean = lognormalFactors[0];
+ let std = lognormalFactors[1];
+ let multiplier = node.args[1].value;
+ let logMultiplier = Math.log(multiplier);
+ let newMean = mean + logMultiplier;
+ return createLogarithmNode(newMean, std);
+ } else if (isNumberTimesLognormal) {
+ // number times lognormal
+ let lognormalFactors = getFactors(node.args[1]);
+ let mean = lognormalFactors[0];
+ let std = lognormalFactors[1];
+ let multiplier = node.args[0].value;
+ let logMultiplier = Math.log(multiplier);
+ let newMean = mean + logMultiplier;
+ return createLogarithmNode(newMean, std);
+ }
+ }
+ } else if (node.type == "OperatorNode" && node.op == "/") {
+ let hasTwoArgs = node.args && node.args.length == 2;
+ if (hasTwoArgs) {
+ let areArgsLognormal = node.args
+ .map((arg) => isArgLognormal(arg))
+ .reduce((a, b) => a && b, true);
+
+ let isFirstArgLognormal = isArgLognormal(node.args[0]);
+ let isSecondArgNumber = isConstantNode(node.args[1]);
+ let isLognormalDividedByNumber =
+ isFirstArgLognormal * isSecondArgNumber;
+
+ let isFirstArgNumber = isConstantNode(node.args[0]);
+ let isSecondArgLognormal = isArgLognormal(node.args[1]);
+ let isNumberDividedByLognormal =
+ isFirstArgNumber * isSecondArgLognormal;
+
+ if (areArgsLognormal) {
+ let factors = node.args.map((arg) => getFactors(arg));
+ let mean1 = factors[0][0];
+ let std1 = factors[0][1];
+ let mean2 = factors[1][0];
+ let std2 = factors[1][1];
+
+ let newMean = mean1 - mean2;
+ let newStd = Math.sqrt(std1 ** 2 + std2 ** 2);
+ return createLogarithmNode(newMean, newStd);
+ return new math.SymbolNode("xx");
+ } else if (isLognormalDividedByNumber) {
+ let lognormalFactors = getFactors(node.args[0]);
+ let mean = lognormalFactors[0];
+ let std = lognormalFactors[1];
+ let multiplier = node.args[1].value;
+ let logMultiplier = Math.log(multiplier);
+ let newMean = mean - logMultiplier;
+ return createLogarithmNode(newMean, std);
+ } else if (isNumberDividedByLognormal) {
+ let lognormalFactors = getFactors(node.args[1]);
+ let mean = lognormalFactors[0];
+ let std = lognormalFactors[1];
+ let multiplier = node.args[0].value;
+ let logMultiplier = Math.log(multiplier);
+ let newMean = -mean + logMultiplier;
+ return createLogarithmNode(newMean, std);
+ }
+ }
+ }
+ if (node.type == "ParenthesisNode") {
+ if (
+ !!node.content &&
+ !!node.content.fn &&
+ node.content.fn.name == "lognormal"
+ ) {
+ return node.content;
+ }
+ }
+ return node;
+ });
+
+ return transformed;
+};
+
+let from90PercentCI = (low, high) => {
+ let normal95confidencePoint = 1.6448536269514722;
+ let logLow = Math.log(low);
+ let logHigh = Math.log(high);
+ let mu = (logLow + logHigh) / 2;
+ let sigma = (logHigh - logLow) / (2.0 * normal95confidencePoint);
+ return [mu, sigma];
+};
+
+let simplePreprocessor = (string) => {
+ // left for documentation purposes only
+ function replacer(match, p1, p2) {
+ print(match);
+ // p1 is nondigits, p2 digits, and p3 non-alphanumericsa
+ print([p1, p2]);
+ let result = from90PercentCI(p1, p2);
+ return `lognormal(${result[0]}, ${result[1]})`;
+ }
+ let newString = string.replace(/(\d+) to (\d+)/g, replacer);
+ print(newString);
+ return newString; // abc - 12345 - #$*%
+};
+
+// simplePreprocessor("1 to 10 + 1 to 20");
+
+let customToStringHandler = (node, options) => {
+ if (node.type == "ConstantNode") {
+ return node.value.toFixed(2);
+ }
+};
+
+let preprocessor = (string, print = console.log) => {
+ // work in progress, currently not working
+ let regex = /([\d]+\.?[\d]*|\.[\d]+) to ([\d]+\.?[\d]*|\.[\d]+)/g;
+ function replacer(match, p1, p2) {
+ let result = from90PercentCI(p1, p2);
+ return `lognormal(${result[0]}, ${result[1]})`;
+ }
+ let newString = string.replace(regex, replacer);
+ if (newString != string)
+ print(
+ `\t= ${math
+ .parse(newString)
+ .toString({ handler: customToStringHandler })}`
+ );
+ return newString; // abc - 12345 - #$*%
+};
+// preprocessor("1.2 to 10.5 * 1.1 to 20 * 1 to 2.5 * 1 to 5");
+
+export function transformer(string, print = console.log) {
+ string = preprocessor(string, print);
+ let transformerOutput = transformerInner(string);
+ let stringNew = transformerOutput.toString();
+ while (stringNew != string) {
+ print(
+ `\t-> ${transformerOutput.toString({ handler: customToStringHandler })}`
+ );
+ string = stringNew;
+ transformerOutput = transformerInner(string);
+ stringNew = transformerOutput.toString();
+ }
+ return stringNew;
+}
diff --git a/src/tests.js b/src/tests.js
@@ -0,0 +1,76 @@
+import { transformer } from "./index.js";
+
+let VERBOSE = true;
+let print = (x) => {
+ if (VERBOSE) {
+ console.log(x);
+ }
+};
+
+let testTransformer = (string) => {
+ console.log(string);
+ console.group();
+ print("");
+ let result = transformer(string, print);
+ print("");
+ console.groupEnd();
+ console.log(`=> ${result}`);
+ print("-".repeat(52));
+ console.log("");
+};
+
+// Define tests
+let tests1 = [
+ `lognormal(1,10) * lognormal(1,10) + lognormal(1,10)`,
+ `lognormal(1,10) * lognormal(1,10) * lognormal(1,10)`,
+ `1 to 10 * lognormal(1, 10)`,
+ `lognormal(1, 10) * 1 to 20`,
+ `1 to 20 * 100 to 1000`,
+ `(lognormal(1,10) / lognormal(1,10)) + lognormal(1,10)`,
+ `lognormal(1,10) * lognormal(1,10) / lognormal(1,10)`,
+ `1 to 10 * lognormal(1, 10) / 1 to 10`,
+ `lognormal(1, 10) * 1 to 20 / 1 to 20`,
+ `1 to 20 * 100 to 1000 / 1 to 100`,
+];
+
+let tests2 = [
+ `3 * lognormal(1,10)`,
+ `lognormal(1,10) * 4`,
+ `lognormal(1, 10) / 3`,
+ `3 / lognormal(1, 10)`,
+ `lognormal(1,10) * lognormal(1/10) / 3`,
+ `lognormal(1, 10) / (1 to 3)`,
+];
+
+let tests3 = [
+ `(lognormal(1,10))`,
+ `lognormal(1,10) * (lognormal(1, 10) * 3) / (4 * lognormal(1,10))`,
+];
+
+let tests4 = [
+ `(1 to 2) * 3 * lognormal(1,10) * (1/lognormal(1,10)) / (1 to 10)`,
+ `lognormal(2.4451858789480823, 10.002219515733781) * lognormal(-1, 10) `,
+];
+
+// Run tests
+console.log("\n".repeat(10));
+console.clear();
+let runTests1 = true;
+if (runTests1) {
+ tests1.forEach((test) => testTransformer(test));
+}
+
+let runTests2 = true;
+if (runTests2) {
+ tests2.forEach((test) => testTransformer(test));
+}
+
+let runTests3 = true;
+if (runTests3) {
+ tests3.forEach((test) => testTransformer(test));
+}
+
+let runTests4 = true;
+if (runTests4) {
+ tests4.forEach((test) => testTransformer(test));
+}
diff --git a/tests.js b/tests.js
@@ -1,74 +0,0 @@
-import { transformer } from "./index.js";
-
-let VERBOSE = false;
-let print = (x) => {
- if (VERBOSE) {
- console.log(x);
- }
-};
-
-let testTransformer = (string) => {
- console.log(string);
- console.group();
- print("");
- let result = transformer(string, print);
- print("");
- console.groupEnd();
- console.log(`=> ${result}`);
- print("-".repeat(52));
- console.log("");
-};
-
-// Defs
-let tests1 = [
- `lognormal(1,10) * lognormal(1,10) + lognormal(1,10)`,
- `lognormal(1,10) * lognormal(1,10) * lognormal(1,10)`,
- `1 to 10 * lognormal(1, 10)`,
- `lognormal(1, 10) * 1 to 20`,
- `1 to 20 * 100 to 1000`,
- `(lognormal(1,10) / lognormal(1,10)) + lognormal(1,10)`,
- `lognormal(1,10) * lognormal(1,10) / lognormal(1,10)`,
- `1 to 10 * lognormal(1, 10) / 1 to 10`,
- `lognormal(1, 10) * 1 to 20 / 1 to 20`,
- `1 to 20 * 100 to 1000 / 1 to 100`,
-];
-let runTests1 = false;
-if (runTests1) {
- console.clear();
- tests.forEach((test) => testTransformer(test));
-}
-
-let tests2 = [
- `3 * lognormal(1,10)`,
- `lognormal(1,10) * 4`,
- `lognormal(1, 10) / 3`,
- `3 / lognormal(1, 10)`,
- `lognormal(1,10) * lognormal(1/10) / 3`,
- `lognormal(1, 10) / (1 to 3)`,
-];
-
-let runTests2 = false;
-if (runTests2) {
- console.clear();
- tests2.forEach((test) => testTransformer(test));
-}
-
-let tests3 = [
- `(lognormal(1,10))`,
- `lognormal(1,10) * (lognormal(1, 10) * 3) / (4 * lognormal(1,10))`,
-];
-let runTests3 = false;
-if (runTests3) {
- console.clear();
- tests3.forEach((test) => testTransformer(test));
-}
-
-let tests4 = [
- `(1 to 2) * 3 * lognormal(1,10) * (1/lognormal(1,10)) / (1 to 10)`,
- `lognormal(2.4451858789480823, 10.002219515733781) * lognormal(-1, 10) `,
-];
-let runTests4 = true;
-if (runTests4) {
- console.clear();
- tests4.forEach((test) => testTransformer(test));
-}