feat: further progress, deal with parentheses

This commit is contained in:
NunoSempere 2022-04-15 11:06:56 -04:00
parent e5d19aa6ef
commit 4b9b223aeb

129
index.js
View File

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