simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

commit 4b9b223aeb58659de4cba8eaf50b535313b40382
parent e5d19aa6ef9857d1315171a91f4ef4e8251c8d4f
Author: NunoSempere <nuno.sempere@protonmail.com>
Date:   Fri, 15 Apr 2022 11:06:56 -0400

feat: further progress, deal with parentheses

Diffstat:
Mindex.js | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 125 insertions(+), 18 deletions(-)

diff --git a/index.js b/index.js @@ -14,12 +14,14 @@ let isArgLognormal = (arg) => { let andNameIsLognormal = isFn && arg.fn.name == "lognormal"; let andHasArgs = andNameIsLognormal && !!arg.args; let andHasTwoArgs = andHasArgs && arg.args.length == 2; - let andTwoArgsAreConstant = arg.args - .map( - (innerArg) => isConstantNode(innerArg) - // innerArg - ) - .reduce((a, b) => a && b, true); + let andTwoArgsAreConstant = + andHasTwoArgs && + arg.args + .map( + (innerArg) => isConstantNode(innerArg) + // innerArg + ) + .reduce((a, b) => a && b, true); return andTwoArgsAreConstant; }; @@ -38,13 +40,26 @@ let createLogarithmNode = (mu, sigma) => { let transformerInner = (string) => { let nodes = math.parse(string); let transformed = nodes.transform(function (node, path, parent) { + // Multiplication if (node.type == "OperatorNode" && node.op == "*") { - let hasArgs = node.args && node.args.length == 2; - if (hasArgs) { + let hasTwoArgs = node.args && node.args.length == 2; + if (hasTwoArgs) { + console.log(JSON.stringify(node.args, null, 4)); + // 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]; @@ -54,19 +69,43 @@ let transformerInner = (string) => { let newMean = mean1 + mean2; let newStd = Math.sqrt(std1 ** 2 + std2 ** 2); return createLogarithmNode(newMean, newStd); - return new math.SymbolNode("xx"); - } else { - return node; + } 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 { - return node; } } else if (node.type == "OperatorNode" && node.op == "/") { - let hasArgs = node.args && node.args.length == 2; - if (hasArgs) { + 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]; @@ -78,9 +117,34 @@ let transformerInner = (string) => { 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; }); @@ -146,12 +210,55 @@ let testTransformer = (string) => { }; // Defs -let 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 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) `, ]; -console.clear(); -tests.forEach((test) => testTransformer(test)); +let runTests4 = true; +if (runTests4) { + console.clear(); + tests4.forEach((test) => testTransformer(test)); +}