From 5d01cc9d36ccd35d3219757d8f6258612c623570 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Tue, 2 Jun 2020 11:13:09 -0700 Subject: [PATCH 1/8] clone node to avoid double negative being added --- lib/util/flattenOperands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/flattenOperands.js b/lib/util/flattenOperands.js index 8e5c0343..5cda0a4e 100644 --- a/lib/util/flattenOperands.js +++ b/lib/util/flattenOperands.js @@ -86,7 +86,7 @@ function flattenOperands(node) { return node; } else if (Node.Type.isUnaryMinus(node)) { - const arg = flattenOperands(node.args[0]); + const arg = flattenOperands(node.args[0].cloneDeep()); const flattenedNode = Negative.negate(arg, true); if (node.changeGroup) { flattenedNode.changeGroup = node.changeGroup; From 3aa6b47ccfb31539d4670267a18aaae8d9ca8d36 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Tue, 2 Jun 2020 11:14:25 -0700 Subject: [PATCH 2/8] add comment --- lib/util/flattenOperands.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/util/flattenOperands.js b/lib/util/flattenOperands.js index 5cda0a4e..8aa63d1a 100644 --- a/lib/util/flattenOperands.js +++ b/lib/util/flattenOperands.js @@ -86,6 +86,8 @@ function flattenOperands(node) { return node; } else if (Node.Type.isUnaryMinus(node)) { + // since arg is changed when it is negated, clone it before negation to avoid + // modifiying original reference const arg = flattenOperands(node.args[0].cloneDeep()); const flattenedNode = Negative.negate(arg, true); if (node.changeGroup) { From 626d787172f4da231ac9baf6cf3b5306617148a7 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Tue, 2 Jun 2020 12:49:53 -0700 Subject: [PATCH 3/8] better handling of unaryMinus with parenthesis --- lib/node/Type.js | 3 +++ lib/solveEquation/stepThrough.js | 6 ++++-- lib/util/removeUnnecessaryParens.js | 7 ++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/node/Type.js b/lib/node/Type.js index c1d6bd96..818c9625 100644 --- a/lib/node/Type.js +++ b/lib/node/Type.js @@ -63,6 +63,9 @@ NodeType.isConstantFraction = function(node, allowUnaryMinus=false) { if (NodeType.isOperator(node, '/')) { return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + return NodeType.isConstantFraction(node.args[0]) + } else { return false; } diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js index 40c1474c..6e9dc635 100644 --- a/lib/solveEquation/stepThrough.js +++ b/lib/solveEquation/stepThrough.js @@ -260,8 +260,10 @@ function solveConstantEquation(equation, debug, steps=[]) { equation.leftNode = removeUnnecessaryParens(equation.leftNode); equation.rightNode = removeUnnecessaryParens(equation.rightNode); - if (!Node.Type.isConstantOrConstantFraction(equation.leftNode, true) || - !Node.Type.isConstantOrConstantFraction(equation.rightNode, true)) { + let rNodeIsConstant = Node.Type.isConstantOrConstantFraction(equation.rightNode, true) + let lNodeIsConstant = Node.Type.isConstantOrConstantFraction(equation.leftNode, true) + + if (!lNodeIsConstant || !rNodeIsConstant) { throw Error('Expected both nodes to be constants, instead got: ' + equation.ascii()); } diff --git a/lib/util/removeUnnecessaryParens.js b/lib/util/removeUnnecessaryParens.js index 3bbf796d..f13545f8 100644 --- a/lib/util/removeUnnecessaryParens.js +++ b/lib/util/removeUnnecessaryParens.js @@ -37,7 +37,12 @@ function removeUnnecessaryParensSearch(node) { return node; } else if (Node.Type.isUnaryMinus(node)) { - const content = node.args[0]; + let content = node.args[0]; + + if (Node.Type.isParenthesis(content)) { + content = removeUnnecessaryParensInParenthesisNode(content) + } + node.args[0] = removeUnnecessaryParensSearch(content); return node; } From 110675ab5f197c51153d261cc9773da175875ee8 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Thu, 4 Jun 2020 17:29:49 -0700 Subject: [PATCH 4/8] add in better check for isOverallConstant --- lib/node/Type.js | 13 ++++++++++--- lib/solveEquation/stepThrough.js | 8 ++++---- lib/util/removeUnnecessaryParens.js | 8 +------- test/util/removeUnnecessaryParens.test.js | 1 + 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/node/Type.js b/lib/node/Type.js index 818c9625..b48484c8 100644 --- a/lib/node/Type.js +++ b/lib/node/Type.js @@ -63,9 +63,6 @@ NodeType.isConstantFraction = function(node, allowUnaryMinus=false) { if (NodeType.isOperator(node, '/')) { return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - return NodeType.isConstantFraction(node.args[0]) - } else { return false; } @@ -81,6 +78,16 @@ NodeType.isConstantOrConstantFraction = function(node, allowUnaryMinus=false) { } }; +NodeType.isOverallConstant = function (node) { + if (NodeType.isConstantOrConstantFraction(node)) { + return true + } else if (NodeType.isUnaryMinus(node)) { + return NodeType.isOverallConstant(node.args[0]) + } else if (NodeType.isParenthesis(node)) { + return NodeType.isOverallConstant(node.content) + } +} + NodeType.isIntegerFraction = function(node, allowUnaryMinus=false) { if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { return false; diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js index 6e9dc635..b8cb5c10 100644 --- a/lib/solveEquation/stepThrough.js +++ b/lib/solveEquation/stepThrough.js @@ -257,11 +257,11 @@ function solveConstantEquation(equation, debug, steps=[]) { // If the left or right side didn't have any steps, unnecessary parens // might not have been removed, so do that now. - equation.leftNode = removeUnnecessaryParens(equation.leftNode); - equation.rightNode = removeUnnecessaryParens(equation.rightNode); + equation.leftNode = removeUnnecessaryParens(equation.leftNode, true); + equation.rightNode = removeUnnecessaryParens(equation.rightNode, true); - let rNodeIsConstant = Node.Type.isConstantOrConstantFraction(equation.rightNode, true) - let lNodeIsConstant = Node.Type.isConstantOrConstantFraction(equation.leftNode, true) + let rNodeIsConstant = Node.Type.isOverallConstant(equation.rightNode) + let lNodeIsConstant = Node.Type.isOverallConstant(equation.leftNode) if (!lNodeIsConstant || !rNodeIsConstant) { throw Error('Expected both nodes to be constants, instead got: ' + diff --git a/lib/util/removeUnnecessaryParens.js b/lib/util/removeUnnecessaryParens.js index f13545f8..3d3c1447 100644 --- a/lib/util/removeUnnecessaryParens.js +++ b/lib/util/removeUnnecessaryParens.js @@ -37,13 +37,7 @@ function removeUnnecessaryParensSearch(node) { return node; } else if (Node.Type.isUnaryMinus(node)) { - let content = node.args[0]; - - if (Node.Type.isParenthesis(content)) { - content = removeUnnecessaryParensInParenthesisNode(content) - } - - node.args[0] = removeUnnecessaryParensSearch(content); + node.args[0] = removeUnnecessaryParensSearch(node.args[0]) return node; } else { diff --git a/test/util/removeUnnecessaryParens.test.js b/test/util/removeUnnecessaryParens.test.js index 9d7520ab..72f772a1 100644 --- a/test/util/removeUnnecessaryParens.test.js +++ b/test/util/removeUnnecessaryParens.test.js @@ -17,6 +17,7 @@ describe('removeUnnecessaryParens', function () { ['x + (12)', 'x + 12'], ['x + (y)', 'x + y'], ['x + -(y)', 'x - y'], + ['((((1))))', '1'], ['((3 - 5)) * x', '(3 - 5) * x'], ['((3 - 5)) * x', '(3 - 5) * x'], ['(((-5)))', '-5'], From 92728b37f5e28db06e59ccdf311336ec99e41e03 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Thu, 4 Jun 2020 17:42:46 -0700 Subject: [PATCH 5/8] add allow unary --- lib/node/Type.js | 2 +- lib/solveEquation/stepThrough.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/node/Type.js b/lib/node/Type.js index b48484c8..c3cdeaa1 100644 --- a/lib/node/Type.js +++ b/lib/node/Type.js @@ -79,7 +79,7 @@ NodeType.isConstantOrConstantFraction = function(node, allowUnaryMinus=false) { }; NodeType.isOverallConstant = function (node) { - if (NodeType.isConstantOrConstantFraction(node)) { + if (NodeType.isConstantOrConstantFraction(node, true)) { return true } else if (NodeType.isUnaryMinus(node)) { return NodeType.isOverallConstant(node.args[0]) diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js index b8cb5c10..59e49cd5 100644 --- a/lib/solveEquation/stepThrough.js +++ b/lib/solveEquation/stepThrough.js @@ -262,7 +262,12 @@ function solveConstantEquation(equation, debug, steps=[]) { let rNodeIsConstant = Node.Type.isOverallConstant(equation.rightNode) let lNodeIsConstant = Node.Type.isOverallConstant(equation.leftNode) - + if (!lNodeIsConstant) { + console.log("left node xxx ", equation.leftNode.toString()) + } + if (!rNodeIsConstant) { + console.log("right node xxx ", equation.rightNode.toString()) + } if (!lNodeIsConstant || !rNodeIsConstant) { throw Error('Expected both nodes to be constants, instead got: ' + equation.ascii()); From 6a1924c335a6218f3d84558038ea8735768786b0 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Fri, 5 Jun 2020 07:26:24 -0700 Subject: [PATCH 6/8] cleanup debuggers --- lib/solveEquation/stepThrough.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js index 59e49cd5..744db20e 100644 --- a/lib/solveEquation/stepThrough.js +++ b/lib/solveEquation/stepThrough.js @@ -260,15 +260,7 @@ function solveConstantEquation(equation, debug, steps=[]) { equation.leftNode = removeUnnecessaryParens(equation.leftNode, true); equation.rightNode = removeUnnecessaryParens(equation.rightNode, true); - let rNodeIsConstant = Node.Type.isOverallConstant(equation.rightNode) - let lNodeIsConstant = Node.Type.isOverallConstant(equation.leftNode) - if (!lNodeIsConstant) { - console.log("left node xxx ", equation.leftNode.toString()) - } - if (!rNodeIsConstant) { - console.log("right node xxx ", equation.rightNode.toString()) - } - if (!lNodeIsConstant || !rNodeIsConstant) { + if (!Node.Type.isOverallConstant(equation.leftNode) || !Node.Type.isOverallConstant(equation.rightNode)) { throw Error('Expected both nodes to be constants, instead got: ' + equation.ascii()); } From f21dc6c851697c0cff35800f038efbef063ee2b1 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Fri, 5 Jun 2020 07:37:25 -0700 Subject: [PATCH 7/8] spec examples --- test/solveEquation/solveEquation.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/solveEquation/solveEquation.test.js b/test/solveEquation/solveEquation.test.js index 251179fe..2d0eb4c0 100644 --- a/test/solveEquation/solveEquation.test.js +++ b/test/solveEquation/solveEquation.test.js @@ -99,7 +99,9 @@ describe('solveEquation for =', function () { ['((x)/(4))=4', 'x = 16'], ['(2x-12)=(x+4)', 'x = 16'], ['x+y=x+y', '0 = 0'], - ['y + 2x = 14 + y', 'x = 7'] + ['y + 2x = 14 + y', 'x = 7'], + ['-(x/2) = 4', 'x = -8'], + ['-((1)/(3)) = ((-1)/(3))', '-(1/3) = -1/3'] // TODO: fix these cases, fail because lack of factoring support, for complex #s, // for taking the sqrt of both sides, etc // ['(x + y) (y + 2) = 0', 'y = -y'], From b774b61c4cf5bc5a0a01039621e94835a69418b2 Mon Sep 17 00:00:00 2001 From: Gabe Mahan Date: Fri, 5 Jun 2020 07:57:26 -0700 Subject: [PATCH 8/8] add in negCoeff check --- lib/node/Term.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/Term.js b/lib/node/Term.js index 34bb04ae..21f5694b 100644 --- a/lib/node/Term.js +++ b/lib/node/Term.js @@ -114,7 +114,7 @@ Term.parseNode = function(node, baseNodeFunc, onlyImplicitMultiplication) { throw Error('Expected two arguments to *'); } const coeffNode = node.args[0]; - if (!NodeType.isConstantOrConstantFraction(coeffNode)) { + if (!NodeType.isConstantOrConstantFraction(coeffNode, true)) { throw Error('Expected coefficient to be constant or fraction of ' + 'constants term, got ' + coeffNode); }