diff --git a/README.md b/README.md new file mode 100644 index 0000000..ab3c69e --- /dev/null +++ b/README.md @@ -0,0 +1,108 @@ +# Simple Squiggle + +## About + +![](imgs/simple-rick.jpg) + +"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. + +![](imgs/simple-squiggle.png) + +## 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/imgs/simple-rick.jpg b/imgs/simple-rick.jpg new file mode 100644 index 0000000..41ba52b Binary files /dev/null and b/imgs/simple-rick.jpg differ diff --git a/imgs/simple-squiggle.png b/imgs/simple-squiggle.png new file mode 100644 index 0000000..7ce92bb Binary files /dev/null and b/imgs/simple-squiggle.png differ diff --git a/package.json b/package.json index 22cc05c..97835cd 100644 --- 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/cli.js b/src/cli.js similarity index 94% rename from cli.js rename to src/cli.js index a0018a9..b8d4a0e 100644 --- a/cli.js +++ b/src/cli.js @@ -9,7 +9,7 @@ let print = (x) => { }; let runTransformer = (string) => { - console.log(`Received: ${string}`); + // console.log(`Received: ${string}`); console.group(); print(""); let result = transformer(string, print); diff --git a/index.js b/src/index.js similarity index 98% rename from index.js rename to src/index.js index 226fd8e..fe093d6 100644 --- a/index.js +++ b/src/index.js @@ -227,7 +227,7 @@ export function transformer(string, print = console.log) { let stringNew = transformerOutput.toString(); while (stringNew != string) { print( - `\t->: ${transformerOutput.toString({ handler: customToStringHandler })}` + `\t-> ${transformerOutput.toString({ handler: customToStringHandler })}` ); string = stringNew; transformerOutput = transformerInner(string); diff --git a/tests.js b/src/tests.js similarity index 87% rename from tests.js rename to src/tests.js index 6845e5a..c22303f 100644 --- a/tests.js +++ b/src/tests.js @@ -1,6 +1,6 @@ import { transformer } from "./index.js"; -let VERBOSE = false; +let VERBOSE = true; let print = (x) => { if (VERBOSE) { console.log(x); @@ -19,7 +19,7 @@ let testTransformer = (string) => { console.log(""); }; -// Defs +// Define tests let tests1 = [ `lognormal(1,10) * lognormal(1,10) + lognormal(1,10)`, `lognormal(1,10) * lognormal(1,10) * lognormal(1,10)`, @@ -32,11 +32,6 @@ let tests1 = [ `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)`, @@ -47,28 +42,35 @@ let tests2 = [ `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) `, ]; + +// 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) { - console.clear(); tests4.forEach((test) => testTransformer(test)); }