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:
| M | index.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));
+}