From 43779299f917b0abc6757f8f4ddc69ebef03c5e2 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 7 Apr 2017 19:32:27 -0700 Subject: [PATCH 01/12] Initial port. Lost of compile errors, and lots of un-ported features/classes. Shoutouts to Resharper magic --- .gitignore | 1 + MathSteps-Ts.njsproj | 226 ++++++++++++ MathSteps-Ts.sln | 22 ++ index.js | 9 - index.ts | 10 + lib/ChangeTypes.js | 339 ++++++++---------- lib/ChangeTypes.js.map | 1 + lib/ChangeTypes.ts | 186 ++++++++++ lib/Negative.js | 94 ----- lib/Negative.ts | 87 +++++ lib/Symbols.js | 75 ---- lib/Symbols.ts | 75 ++++ lib/TreeSearch.js | 70 ---- lib/TreeSearch.ts | 57 +++ ...es.js => canAddLikeTermPolynomialNodes.ts} | 11 +- ... => canMultiplyLikeTermPolynomialNodes.ts} | 11 +- ...fficient.js => canRearrangeCoefficient.ts} | 11 +- lib/checks/canSimplifyPolynomialTerms.js | 13 - lib/checks/canSimplifyPolynomialTerms.ts | 14 + ...pportedNodes.js => hasUnsupportedNodes.ts} | 19 +- lib/checks/index.js | 17 - lib/checks/index.ts | 18 + lib/checks/{isQuadratic.js => isQuadratic.ts} | 26 +- ...vesToConstant.js => resolvesToConstant.ts} | 15 +- lib/equation/{Equation.js => Equation.ts} | 30 +- lib/equation/Status.js | 73 ---- lib/equation/Status.ts | 70 ++++ lib/equation/index.js | 15 +- lib/equation/index.js.map | 1 + lib/equation/index.ts | 8 + lib/factor/ConstantFactors.js | 107 +++--- lib/factor/ConstantFactors.js.map | 1 + lib/factor/ConstantFactors.ts | 59 +++ ...{factorQuadratic.js => factorQuadratic.ts} | 36 +- lib/{node/Creator.js => mathNode/Creator.ts} | 8 +- .../PolynomialTerm.ts} | 61 ++-- lib/mathNode/Status.ts | 124 +++++++ lib/mathNode/Type.ts | 90 +++++ lib/mathNode/index.js | 14 + lib/mathNode/index.js.map | 1 + lib/mathNode/index.ts | 12 + lib/node/Status.js | 126 ------- lib/node/Type.js | 100 ------ lib/node/index.js | 11 - .../arithmeticSearch/{index.js => index.ts} | 38 +- .../basicsSearch/{index.js => index.ts} | 35 +- .../basicsSearch/rearrangeCoefficient.js | 27 -- .../basicsSearch/rearrangeCoefficient.ts | 27 ++ .../basicsSearch/reduceExponentByZero.js | 21 -- .../basicsSearch/reduceExponentByZero.ts | 22 ++ .../reduceMultiplicationByZero.js | 31 -- .../reduceMultiplicationByZero.ts | 32 ++ .../reduceZeroDividedByAnything.js | 20 -- .../reduceZeroDividedByAnything.ts | 21 ++ ...itionOfZero.js => removeAdditionOfZero.ts} | 20 +- ...ivisionByOne.js => removeDivisionByOne.ts} | 30 +- .../basicsSearch/removeExponentBaseOne.js | 21 -- .../basicsSearch/removeExponentBaseOne.ts | 21 ++ .../basicsSearch/removeExponentByOne.js | 19 - .../basicsSearch/removeExponentByOne.ts | 19 + ...s => removeMultiplicationByNegativeOne.ts} | 26 +- ...nByOne.js => removeMultiplicationByOne.ts} | 20 +- .../basicsSearch/simplifyDoubleUnaryMinus.js | 38 -- .../basicsSearch/simplifyDoubleUnaryMinus.ts | 38 ++ .../{index.js => index.ts} | 31 +- ...eTermCollector.js => LikeTermCollector.ts} | 234 ++++++------ .../{addLikeTerms.js => addLikeTerms.ts} | 74 ++-- ...eConstantSum.js => evaluateConstantSum.ts} | 63 ++-- .../{index.js => index.ts} | 37 +- ...tiplyLikeTerms.js => multiplyLikeTerms.ts} | 60 ++-- .../distributeSearch/{index.js => index.ts} | 123 ++++--- .../divisionSearch/{index.js => index.ts} | 44 +-- ...dFraction.js => addConstantAndFraction.ts} | 52 +-- ...ntFractions.js => addConstantFractions.ts} | 88 ++--- ...{cancelLikeTerms.js => cancelLikeTerms.ts} | 94 ++--- .../{divideByGCD.js => divideByGCD.ts} | 32 +- .../fractionsSearch/{index.js => index.ts} | 26 +- ...ctionSigns.js => simplifyFractionSigns.ts} | 24 +- ...ction.js => simplifyPolynomialFraction.ts} | 27 +- .../functionsSearch/absoluteValue.js | 38 -- .../functionsSearch/absoluteValue.ts | 38 ++ .../functionsSearch/index.js | 32 -- .../functionsSearch/index.ts | 31 ++ .../{nthRoot.js => nthRoot.ts} | 188 +++++----- lib/simplifyExpression/{index.js => index.ts} | 6 +- .../{index.js => index.ts} | 35 +- lib/simplifyExpression/simplify.js | 56 ++- lib/simplifyExpression/simplify.js.map | 1 + lib/simplifyExpression/simplify.ts | 36 ++ .../{stepThrough.js => stepThrough.ts} | 41 +-- lib/solveEquation/EquationOperations.js | 232 ------------ lib/solveEquation/EquationOperations.ts | 230 ++++++++++++ lib/solveEquation/{index.js => index.ts} | 7 +- .../{stepThrough.js => stepThrough.ts} | 42 +-- lib/util/Util.js | 32 +- lib/util/Util.js.map | 1 + lib/util/Util.ts | 18 + lib/util/clone.js | 28 +- lib/util/clone.js.map | 1 + lib/util/clone.ts | 19 + lib/util/evaluate.js | 8 +- lib/util/evaluate.js.map | 1 + lib/util/evaluate.ts | 11 + ...{flattenOperands.js => flattenOperands.ts} | 17 +- lib/util/{print.js => print.ts} | 9 +- ...ryParens.js => removeUnnecessaryParens.ts} | 13 +- test/Negative.test.js | 28 -- test/Negative.test.ts | 26 ++ test/Node/PolynomialTerm.test.js | 24 -- test/Node/PolynomialTerm.test.ts | 24 ++ test/Node/Type.test.js | 110 ------ test/Node/Type.test.ts | 109 ++++++ test/TestUtil.js | 56 --- test/TestUtil.ts | 52 +++ ... => canAddLikeTermPolynomialNodes.test.ts} | 6 +- ...anMultiplyLikeTermPolynomialNodes.test.ts} | 6 +- ...est.js => canRearrangeCoefficient.test.ts} | 6 +- test/checks/checks.test.js | 31 -- test/checks/checks.test.ts | 31 ++ test/checks/hasUnsupportedNodes.test.js | 30 -- test/checks/hasUnsupportedNodes.test.ts | 28 ++ test/checks/isQuadratic.test.js | 28 -- test/checks/isQuadratic.test.ts | 29 ++ test/checks/resolvesToConstant.test.js | 18 - test/checks/resolvesToConstant.test.ts | 18 + test/{equation.test.js => equation.test.ts} | 7 +- test/factor/ConstantFactors.test.js | 44 --- test/factor/ConstantFactors.test.ts | 45 +++ test/factor/factorQuadratic.test.js | 34 -- test/factor/factorQuadratic.test.ts | 35 ++ .../arithmeticSearch/arithmeticSearch.test.js | 16 - .../arithmeticSearch/arithmeticSearch.test.ts | 16 + .../basicsSearch/rearrangeCoefficient.test.js | 11 - .../basicsSearch/rearrangeCoefficient.test.ts | 9 + .../basicsSearch/reduceExponentByZero.test.js | 7 - .../basicsSearch/reduceExponentByZero.test.ts | 5 + .../reduceMutliplicationByZero.test.js | 11 - .../reduceMutliplicationByZero.test.ts | 9 + .../reduceZeroDividedByAnything.test.js | 11 - .../reduceZeroDividedByAnything.test.ts | 9 + .../basicsSearch/removeAdditionOfZero.test.js | 12 - .../basicsSearch/removeAdditionOfZero.test.ts | 10 + .../basicsSearch/removeDivisionByOne.test.js | 7 - .../basicsSearch/removeDivisionByOne.test.ts | 5 + .../removeExponentBaseOne.test.js | 12 - .../removeExponentBaseOne.test.ts | 10 + .../basicsSearch/removeExponentByOne.test.js | 7 - .../basicsSearch/removeExponentByOne.test.ts | 5 + .../removeMultiplicationByNegativeOne.test.js | 12 - .../removeMultiplicationByNegativeOne.test.ts | 10 + .../removeMultiplicationByOne.test.js | 13 - .../removeMultiplicationByOne.test.ts | 11 + .../simplifyDoubleUnaryMinus.test.js | 12 - .../simplifyDoubleUnaryMinus.test.ts | 9 + .../basicsSearch/testSimplify.js | 18 - .../basicsSearch/testSimplify.ts | 17 + .../breakUpNumeratorSearch.test.js | 16 - .../breakUpNumeratorSearch.test.ts | 16 + .../LikeTermCollector.test.js | 97 ----- .../LikeTermCollector.test.ts | 96 +++++ .../collectAndCombineSearch.test.js | 62 ---- .../collectAndCombineSearch.test.ts | 63 ++++ .../evaluateConstantSum.test.js | 33 -- .../evaluateConstantSum.test.ts | 33 ++ .../distributeSearch/distributeSearch.test.js | 89 ----- .../distributeSearch/distributeSearch.test.ts | 90 +++++ .../divisionSearch/divisionSearch.test.js | 21 -- .../divisionSearch/divisionSearch.test.ts | 21 ++ .../addConstantAndFraction.test.js | 32 -- .../addConstantAndFraction.test.ts | 32 ++ .../addConstantFractions.test.js | 38 -- .../addConstantFractions.test.ts | 38 ++ .../fractionsSearch/cancelLikeTerms.test.js | 33 -- .../fractionsSearch/cancelLikeTerms.test.ts | 33 ++ .../fractionsSearch/divideByGCD.test.js | 19 - .../fractionsSearch/divideByGCD.test.ts | 19 + .../simplifyFractionSigns.test.js | 15 - .../simplifyFractionSigns.test.ts | 15 + .../simplifyPolynomialFraction.test.js | 20 -- .../simplifyPolynomialFraction.test.ts | 20 ++ .../functionsSearch/absoluteValue.test.js | 15 - .../functionsSearch/absoluteValue.test.ts | 15 + .../functionsSearch/nthRoot.test.js | 72 ---- .../functionsSearch/nthRoot.test.ts | 73 ++++ .../multiplyFractionsSearch.test.js | 16 - .../multiplyFractionsSearch.test.ts | 16 + test/simplifyExpression/oneStep.test.js | 96 ----- test/simplifyExpression/oneStep.test.ts | 94 +++++ test/simplifyExpression/simplify.test.js | 168 --------- test/simplifyExpression/simplify.test.ts | 166 +++++++++ test/solveEquation/solveEquation.test.js | 130 ------- test/solveEquation/solveEquation.test.ts | 128 +++++++ test/util/Util.test.js | 22 -- test/util/Util.test.ts | 20 ++ test/util/flattenOperands.test.js | 103 ------ test/util/flattenOperands.test.ts | 102 ++++++ test/util/print.test.js | 48 --- test/util/print.test.ts | 48 +++ test/util/removeUnnecessaryParens.test.js | 30 -- test/util/removeUnnecessaryParens.test.ts | 29 ++ 200 files changed, 4543 insertions(+), 3958 deletions(-) create mode 100644 MathSteps-Ts.njsproj create mode 100644 MathSteps-Ts.sln delete mode 100644 index.js create mode 100644 index.ts create mode 100644 lib/ChangeTypes.js.map create mode 100644 lib/ChangeTypes.ts delete mode 100644 lib/Negative.js create mode 100644 lib/Negative.ts delete mode 100644 lib/Symbols.js create mode 100644 lib/Symbols.ts delete mode 100644 lib/TreeSearch.js create mode 100644 lib/TreeSearch.ts rename lib/checks/{canAddLikeTermPolynomialNodes.js => canAddLikeTermPolynomialNodes.ts} (70%) rename lib/checks/{canMultiplyLikeTermPolynomialNodes.js => canMultiplyLikeTermPolynomialNodes.ts} (63%) rename lib/checks/{canRearrangeCoefficient.js => canRearrangeCoefficient.ts} (59%) delete mode 100644 lib/checks/canSimplifyPolynomialTerms.js create mode 100644 lib/checks/canSimplifyPolynomialTerms.ts rename lib/checks/{hasUnsupportedNodes.js => hasUnsupportedNodes.ts} (50%) delete mode 100644 lib/checks/index.js create mode 100644 lib/checks/index.ts rename lib/checks/{isQuadratic.js => isQuadratic.ts} (66%) rename lib/checks/{resolvesToConstant.js => resolvesToConstant.ts} (56%) rename lib/equation/{Equation.js => Equation.ts} (63%) delete mode 100644 lib/equation/Status.js create mode 100644 lib/equation/Status.ts create mode 100644 lib/equation/index.js.map create mode 100644 lib/equation/index.ts create mode 100644 lib/factor/ConstantFactors.js.map create mode 100644 lib/factor/ConstantFactors.ts rename lib/factor/{factorQuadratic.js => factorQuadratic.ts} (85%) rename lib/{node/Creator.js => mathNode/Creator.ts} (95%) rename lib/{node/PolynomialTerm.js => mathNode/PolynomialTerm.ts} (83%) create mode 100644 lib/mathNode/Status.ts create mode 100644 lib/mathNode/Type.ts create mode 100644 lib/mathNode/index.js create mode 100644 lib/mathNode/index.js.map create mode 100644 lib/mathNode/index.ts delete mode 100644 lib/node/Status.js delete mode 100644 lib/node/Type.js delete mode 100644 lib/node/index.js rename lib/simplifyExpression/arithmeticSearch/{index.js => index.ts} (54%) rename lib/simplifyExpression/basicsSearch/{index.js => index.ts} (56%) delete mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js create mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts delete mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.js create mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts delete mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js create mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts delete mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js create mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts rename lib/simplifyExpression/basicsSearch/{removeAdditionOfZero.js => removeAdditionOfZero.ts} (54%) rename lib/simplifyExpression/basicsSearch/{removeDivisionByOne.js => removeDivisionByOne.ts} (52%) delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.ts rename lib/simplifyExpression/basicsSearch/{removeMultiplicationByNegativeOne.js => removeMultiplicationByNegativeOne.ts} (69%) rename lib/simplifyExpression/basicsSearch/{removeMultiplicationByOne.js => removeMultiplicationByOne.ts} (54%) delete mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js create mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts rename lib/simplifyExpression/breakUpNumeratorSearch/{index.js => index.ts} (57%) rename lib/simplifyExpression/collectAndCombineSearch/{LikeTermCollector.js => LikeTermCollector.ts} (50%) rename lib/simplifyExpression/collectAndCombineSearch/{addLikeTerms.js => addLikeTerms.ts} (69%) rename lib/simplifyExpression/collectAndCombineSearch/{evaluateConstantSum.js => evaluateConstantSum.ts} (62%) rename lib/simplifyExpression/collectAndCombineSearch/{index.js => index.ts} (73%) rename lib/simplifyExpression/collectAndCombineSearch/{multiplyLikeTerms.js => multiplyLikeTerms.ts} (68%) rename lib/simplifyExpression/distributeSearch/{index.js => index.ts} (68%) rename lib/simplifyExpression/divisionSearch/{index.js => index.ts} (65%) rename lib/simplifyExpression/fractionsSearch/{addConstantAndFraction.js => addConstantAndFraction.ts} (63%) rename lib/simplifyExpression/fractionsSearch/{addConstantFractions.js => addConstantFractions.ts} (60%) rename lib/simplifyExpression/fractionsSearch/{cancelLikeTerms.js => cancelLikeTerms.ts} (78%) rename lib/simplifyExpression/fractionsSearch/{divideByGCD.js => divideByGCD.ts} (64%) rename lib/simplifyExpression/fractionsSearch/{index.js => index.ts} (63%) rename lib/simplifyExpression/fractionsSearch/{simplifyFractionSigns.js => simplifyFractionSigns.ts} (54%) rename lib/simplifyExpression/fractionsSearch/{simplifyPolynomialFraction.js => simplifyPolynomialFraction.ts} (55%) delete mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.js create mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.ts delete mode 100644 lib/simplifyExpression/functionsSearch/index.js create mode 100644 lib/simplifyExpression/functionsSearch/index.ts rename lib/simplifyExpression/functionsSearch/{nthRoot.js => nthRoot.ts} (66%) rename lib/simplifyExpression/{index.js => index.ts} (67%) rename lib/simplifyExpression/multiplyFractionsSearch/{index.js => index.ts} (59%) create mode 100644 lib/simplifyExpression/simplify.js.map create mode 100644 lib/simplifyExpression/simplify.ts rename lib/simplifyExpression/{stepThrough.js => stepThrough.ts} (76%) delete mode 100644 lib/solveEquation/EquationOperations.js create mode 100644 lib/solveEquation/EquationOperations.ts rename lib/solveEquation/{index.js => index.ts} (86%) rename lib/solveEquation/{stepThrough.js => stepThrough.ts} (87%) create mode 100644 lib/util/Util.js.map create mode 100644 lib/util/Util.ts create mode 100644 lib/util/clone.js.map create mode 100644 lib/util/clone.ts create mode 100644 lib/util/evaluate.js.map create mode 100644 lib/util/evaluate.ts rename lib/util/{flattenOperands.js => flattenOperands.ts} (95%) rename lib/util/{print.js => print.ts} (94%) rename lib/util/{removeUnnecessaryParens.js => removeUnnecessaryParens.ts} (92%) delete mode 100644 test/Negative.test.js create mode 100644 test/Negative.test.ts delete mode 100644 test/Node/PolynomialTerm.test.js create mode 100644 test/Node/PolynomialTerm.test.ts delete mode 100644 test/Node/Type.test.js create mode 100644 test/Node/Type.test.ts delete mode 100644 test/TestUtil.js create mode 100644 test/TestUtil.ts rename test/{canAddLikeTermPolynomialNodes.test.js => canAddLikeTermPolynomialNodes.test.ts} (63%) rename test/{canMultiplyLikeTermPolynomialNodes.test.js => canMultiplyLikeTermPolynomialNodes.test.ts} (63%) rename test/{canRearrangeCoefficient.test.js => canRearrangeCoefficient.test.ts} (62%) delete mode 100644 test/checks/checks.test.js create mode 100644 test/checks/checks.test.ts delete mode 100644 test/checks/hasUnsupportedNodes.test.js create mode 100644 test/checks/hasUnsupportedNodes.test.ts delete mode 100644 test/checks/isQuadratic.test.js create mode 100644 test/checks/isQuadratic.test.ts delete mode 100644 test/checks/resolvesToConstant.test.js create mode 100644 test/checks/resolvesToConstant.test.ts rename test/{equation.test.js => equation.test.ts} (74%) delete mode 100644 test/factor/ConstantFactors.test.js create mode 100644 test/factor/ConstantFactors.test.ts delete mode 100644 test/factor/factorQuadratic.test.js create mode 100644 test/factor/factorQuadratic.test.ts delete mode 100644 test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js create mode 100644 test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js create mode 100644 test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js create mode 100644 test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js create mode 100644 test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js create mode 100644 test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeExponentByOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js create mode 100644 test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/testSimplify.js create mode 100644 test/simplifyExpression/basicsSearch/testSimplify.ts delete mode 100644 test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js create mode 100644 test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts delete mode 100644 test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js create mode 100644 test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts delete mode 100644 test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js create mode 100644 test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts delete mode 100644 test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js create mode 100644 test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts delete mode 100644 test/simplifyExpression/distributeSearch/distributeSearch.test.js create mode 100644 test/simplifyExpression/distributeSearch/distributeSearch.test.ts delete mode 100644 test/simplifyExpression/divisionSearch/divisionSearch.test.js create mode 100644 test/simplifyExpression/divisionSearch/divisionSearch.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js create mode 100644 test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/addConstantFractions.test.js create mode 100644 test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js create mode 100644 test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/divideByGCD.test.js create mode 100644 test/simplifyExpression/fractionsSearch/divideByGCD.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js create mode 100644 test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js create mode 100644 test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts delete mode 100644 test/simplifyExpression/functionsSearch/absoluteValue.test.js create mode 100644 test/simplifyExpression/functionsSearch/absoluteValue.test.ts delete mode 100644 test/simplifyExpression/functionsSearch/nthRoot.test.js create mode 100644 test/simplifyExpression/functionsSearch/nthRoot.test.ts delete mode 100644 test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js create mode 100644 test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts delete mode 100644 test/simplifyExpression/oneStep.test.js create mode 100644 test/simplifyExpression/oneStep.test.ts delete mode 100644 test/simplifyExpression/simplify.test.js create mode 100644 test/simplifyExpression/simplify.test.ts delete mode 100644 test/solveEquation/solveEquation.test.js create mode 100644 test/solveEquation/solveEquation.test.ts delete mode 100644 test/util/Util.test.js create mode 100644 test/util/Util.test.ts delete mode 100644 test/util/flattenOperands.test.js create mode 100644 test/util/flattenOperands.test.ts delete mode 100644 test/util/print.test.js create mode 100644 test/util/print.test.ts delete mode 100644 test/util/removeUnnecessaryParens.test.js create mode 100644 test/util/removeUnnecessaryParens.test.ts diff --git a/.gitignore b/.gitignore index f58d10d0..caea85c4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules *.log .DS_Store +/.vs/MathSteps-Ts/v15 diff --git a/MathSteps-Ts.njsproj b/MathSteps-Ts.njsproj new file mode 100644 index 00000000..c5f36ccf --- /dev/null +++ b/MathSteps-Ts.njsproj @@ -0,0 +1,226 @@ + + + + Debug + 2.0 + {d741bb67-79e4-48ae-91fe-723afef84328} + + ShowAllFiles + index.ts + . + . + {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD} + true + CommonJS + true + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 0 + / + http://localhost:48022/ + False + True + http://localhost:1337 + False + + + + + + + CurrentPage + True + False + False + False + + + + + + + + + False + False + + + + + \ No newline at end of file diff --git a/MathSteps-Ts.sln b/MathSteps-Ts.sln new file mode 100644 index 00000000..6f69851b --- /dev/null +++ b/MathSteps-Ts.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "MathSteps-Ts", "MathSteps-Ts.njsproj", "{D741BB67-79E4-48AE-91FE-723AFEF84328}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D741BB67-79E4-48AE-91FE-723AFEF84328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D741BB67-79E4-48AE-91FE-723AFEF84328}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D741BB67-79E4-48AE-91FE-723AFEF84328}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D741BB67-79E4-48AE-91FE-723AFEF84328}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/index.js b/index.js deleted file mode 100644 index b96ce3ec..00000000 --- a/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const ChangeTypes = require('./lib/ChangeTypes'); -const simplifyExpression = require('./lib/simplifyExpression'); -const solveEquation = require('./lib/solveEquation'); - -module.exports = { - simplifyExpression, - solveEquation, - ChangeTypes, -}; diff --git a/index.ts b/index.ts new file mode 100644 index 00000000..451a4634 --- /dev/null +++ b/index.ts @@ -0,0 +1,10 @@ +import ChangeTypes = require('./lib/ChangeTypes'); +import simplifyExpression = require('./lib/simplifyExpression'); +import solveEquation = require('./lib/solveEquation'); +var tmp; +tmp = { + simplifyExpression, + solveEquation, + ChangeTypes, +}; +export = tmp; diff --git a/lib/ChangeTypes.js b/lib/ChangeTypes.js index a02ccca1..862f06c7 100644 --- a/lib/ChangeTypes.js +++ b/lib/ChangeTypes.js @@ -1,184 +1,159 @@ // The text to identify rules for each possible step that can be taken - -module.exports = { - NO_CHANGE: 'NO_CHANGE', - - // ARITHMETIC - - // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 - SIMPLIFY_ARITHMETIC: 'SIMPLIFY_ARITHMETIC', - - // BASICS - - // e.g. 2/-1 -> -2 - DIVISION_BY_NEGATIVE_ONE: 'DIVISION_BY_NEGATIVE_ONE', - // e.g. 2/1 -> 2 - DIVISION_BY_ONE: 'DIVISION_BY_ONE', - // e.g. x * 0 -> 0 - MULTIPLY_BY_ZERO: 'MULTIPLY_BY_ZERO', - // e.g. x * 2 -> 2x - REARRANGE_COEFF: 'REARRANGE_COEFF', - // e.g. x ^ 0 -> 1 - REDUCE_EXPONENT_BY_ZERO: 'REDUCE_EXPONENT_BY_ZERO', - // e.g. 0/1 -> 0 - REDUCE_ZERO_NUMERATOR: 'REDUCE_ZERO_NUMERATOR', - // e.g. 2 + 0 -> 2 - REMOVE_ADDING_ZERO: 'REMOVE_ADDING_ZERO', - // e.g. x ^ 1 -> x - REMOVE_EXPONENT_BY_ONE: 'REMOVE_EXPONENT_BY_ONE', - // e.g. 1 ^ x -> 1 - REMOVE_EXPONENT_BASE_ONE: 'REMOVE_EXPONENT_BASE_ONE', - // e.g. x * -1 -> -x - REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: 'REMOVE_MULTIPLYING_BY_NEGATIVE_ONE', - // e.g. x * 1 -> x - REMOVE_MULTIPLYING_BY_ONE: 'REMOVE_MULTIPLYING_BY_ONE', - // e.g. 2 - - 3 -> 2 + 3 - RESOLVE_DOUBLE_MINUS: 'RESOLVE_DOUBLE_MINUS', - - // COLLECT AND COMBINE - - // e.g. 2 + x + 3 + x -> 5 + 2x - COLLECT_AND_COMBINE_LIKE_TERMS: 'COLLECT_AND_COMBINE_LIKE_TERMS', - // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) - COLLECT_LIKE_TERMS: 'COLLECT_LIKE_TERMS', - - // ADDING POLYNOMIALS - - // e.g. 2x + x -> 2x + 1x - ADD_COEFFICIENT_OF_ONE: 'ADD_COEFFICIENT_OF_ONE', - // e.g. x^2 + x^2 -> 2x^2 - ADD_POLYNOMIAL_TERMS: 'ADD_POLYNOMIAL_TERMS', - // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 - GROUP_COEFFICIENTS: 'GROUP_COEFFICIENTS', - // e.g. -x + 2x => -1*x + 2x - UNARY_MINUS_TO_NEGATIVE_ONE: 'UNARY_MINUS_TO_NEGATIVE_ONE', - - // MULTIPLYING POLYNOMIALS - - // e.g. x^2 * x -> x^2 * x^1 - ADD_EXPONENT_OF_ONE: 'ADD_EXPONENT_OF_ONE', - // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) - COLLECT_EXPONENTS: 'COLLECT_EXPONENTS', - // e.g. 2x * 3x -> (2 * 3)(x * x) - MULTIPLY_COEFFICIENTS: 'MULTIPLY_COEFFICIENTS', - // e.g. 2x * x -> 2x ^ 2 - MULTIPLY_POLYNOMIAL_TERMS: 'MULTIPLY_POLYNOMIAL_TERMS', - - // FRACTIONS - - // e.g. (x + 2)/2 -> x/2 + 2/2 - BREAK_UP_FRACTION: 'BREAK_UP_FRACTION', - // e.g. -2/-3 => 2/3 - CANCEL_MINUSES: 'CANCEL_MINUSES', - // e.g. 2x/2 -> x - CANCEL_TERMS: 'CANCEL_TERMS', - // e.g. 2/6 -> 1/3 - SIMPLIFY_FRACTION: 'SIMPLIFY_FRACTION', - // e.g. 2/-3 -> -2/3 - SIMPLIFY_SIGNS: 'SIMPLIFY_SIGNS', - - // ADDING FRACTIONS - - // e.g. 1/2 + 1/3 -> 5/6 - ADD_FRACTIONS: 'ADD_FRACTIONS', - // e.g. (1 + 2)/3 -> 3/3 - ADD_NUMERATORS: 'ADD_NUMERATORS', - // e.g. (2+1)/5 - COMBINE_NUMERATORS: 'COMBINE_NUMERATORS', - // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) - COMMON_DENOMINATOR: 'COMMON_DENOMINATOR', - // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) - CONVERT_INTEGER_TO_FRACTION: 'CONVERT_INTEGER_TO_FRACTION', - // e.g. 1.2 + 1/2 -> 1.2 + 0.5 - DIVIDE_FRACTION_FOR_ADDITION: 'DIVIDE_FRACTION_FOR_ADDITION', - // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 - MULTIPLY_DENOMINATORS: 'MULTIPLY_DENOMINATORS', - // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 - MULTIPLY_NUMERATORS: 'MULTIPLY_NUMERATORS', - - // MULTIPLYING FRACTIONS - - // e.g. 1/2 * 2/3 -> 2/6 - MULTIPLY_FRACTIONS: 'MULTIPLY_FRACTIONS', - - // DIVISION - - // e.g. 2/3/4 -> 2/(3*4) - SIMPLIFY_DIVISION: 'SIMPLIFY_DIVISION', - // e.g. x/(2/3) -> x * 3/2 - MULTIPLY_BY_INVERSE: 'MULTIPLY_BY_INVERSE', - - // DISTRIBUTION - - // e.g. 2(x + y) -> 2x + 2y - DISTRIBUTE: 'DISTRIBUTE', - // e.g. -(2 + x) -> -2 - x - DISTRIBUTE_NEGATIVE_ONE: 'DISTRIBUTE_NEGATIVE_ONE', - // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) - SIMPLIFY_TERMS: 'SIMPLIFY_TERMS', - - // ABSOLUTE - // e.g. |-3| -> 3 - ABSOLUTE_VALUE: 'ABSOLUTE_VALUE', - - // ROOTS - // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) - CANCEL_EXPONENT: 'CANCEL_EXPONENT', - // e.g. nthRoot(x ^ 2, 2) -> x - CANCEL_EXPONENT_AND_ROOT: 'CANCEL_EXPONENT_AND_ROOT', - // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 - CANCEL_ROOT: 'CANCEL_ROOT', - // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) - COMBINE_UNDER_ROOT: 'COMBINE_UNDER_ROOT', - // e.g. 2 * 2 * 2 -> 2 ^ 3 - CONVERT_MULTIPLICATION_TO_EXPONENT: 'CONVERT_MULTIPLICATION_TO_EXPONENT', - // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) - DISTRIBUTE_NTH_ROOT: 'DISTRIBUTE_NTH_ROOT', - // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x - EVALUATE_DISTRIBUTED_NTH_ROOT: 'EVALUATE_DISTRIBUTED_NTH_ROOT', - // e.g. 12 -> 2 * 2 * 3 - FACTOR_INTO_PRIMES: 'FACTOR_INTO_PRIMES', - // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) - GROUP_TERMS_BY_ROOT: 'GROUP_TERMS_BY_ROOT', - // e.g. nthRoot(4) -> 2 - NTH_ROOT_VALUE: 'NTH_ROOT_VALUE', - - // SOLVING FOR A VARIABLE - - // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 - ADD_TO_BOTH_SIDES: 'ADD_TO_BOTH_SIDES', - // e.g. 2x = 1 -> (2x)/2 = 1/2 - DIVIDE_FROM_BOTH_SIDES: 'DIVIDE_FROM_BOTH_SIDES', - // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) - MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: 'MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION', - // e.g. -x = 2 -> -1 * -x = -1 * 2 - MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: 'MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE', - // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 - MULTIPLY_TO_BOTH_SIDES: 'MULTIPLY_TO_BOTH_SIDES', - // e.g. x + 2 - 1 = 3 -> x + 1 = 3 - SIMPLIFY_LEFT_SIDE: 'SIMPLIFY_LEFT_SIDE', - // e.g. x = 3 - 1 -> x = 2 - SIMPLIFY_RIGHT_SIDE: 'SIMPLIFY_RIGHT_SIDE', - // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 - SUBTRACT_FROM_BOTH_SIDES: 'SUBTRACT_FROM_BOTH_SIDES', - // e.g. 2 = x -> x = 2 - SWAP_SIDES: 'SWAP_SIDES', - - // CONSTANT EQUATION - - // e.g. 2 = 2 - STATEMENT_IS_TRUE: 'STATEMENT_IS_TRUE', - // e.g. 2 = 3 - STATEMENT_IS_FALSE: 'STATEMENT_IS_FALSE', - - // FACTORING - - // e.g. x^2 - 4x -> x(x - 4) - FACTOR_SYMBOL: 'FACTOR_SYMBOL', - // e.g. x^2 - 4 -> (x - 2)(x + 2) - FACTOR_DIFFERENCE_OF_SQUARES: 'FACTOR_DIFFERENCE_OF_SQUARES', - // e.g. x^2 + 2x + 1 -> (x + 1)^2 - FACTOR_PERFECT_SQUARE: 'FACTOR_PERFECT_SQUARE', - // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) - FACTOR_SUM_PRODUCT_RULE: 'FACTOR_SUM_PRODUCT_RULE', +"use strict"; +var tmp; +tmp = { + NO_CHANGE: 'NO_CHANGE', + // ARITHMETIC + // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 + SIMPLIFY_ARITHMETIC: 'SIMPLIFY_ARITHMETIC', + // BASICS + // e.g. 2/-1 -> -2 + DIVISION_BY_NEGATIVE_ONE: 'DIVISION_BY_NEGATIVE_ONE', + // e.g. 2/1 -> 2 + DIVISION_BY_ONE: 'DIVISION_BY_ONE', + // e.g. x * 0 -> 0 + MULTIPLY_BY_ZERO: 'MULTIPLY_BY_ZERO', + // e.g. x * 2 -> 2x + REARRANGE_COEFF: 'REARRANGE_COEFF', + // e.g. x ^ 0 -> 1 + REDUCE_EXPONENT_BY_ZERO: 'REDUCE_EXPONENT_BY_ZERO', + // e.g. 0/1 -> 0 + REDUCE_ZERO_NUMERATOR: 'REDUCE_ZERO_NUMERATOR', + // e.g. 2 + 0 -> 2 + REMOVE_ADDING_ZERO: 'REMOVE_ADDING_ZERO', + // e.g. x ^ 1 -> x + REMOVE_EXPONENT_BY_ONE: 'REMOVE_EXPONENT_BY_ONE', + // e.g. 1 ^ x -> 1 + REMOVE_EXPONENT_BASE_ONE: 'REMOVE_EXPONENT_BASE_ONE', + // e.g. x * -1 -> -x + REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: 'REMOVE_MULTIPLYING_BY_NEGATIVE_ONE', + // e.g. x * 1 -> x + REMOVE_MULTIPLYING_BY_ONE: 'REMOVE_MULTIPLYING_BY_ONE', + // e.g. 2 - - 3 -> 2 + 3 + RESOLVE_DOUBLE_MINUS: 'RESOLVE_DOUBLE_MINUS', + // COLLECT AND COMBINE + // e.g. 2 + x + 3 + x -> 5 + 2x + COLLECT_AND_COMBINE_LIKE_TERMS: 'COLLECT_AND_COMBINE_LIKE_TERMS', + // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) + COLLECT_LIKE_TERMS: 'COLLECT_LIKE_TERMS', + // ADDING POLYNOMIALS + // e.g. 2x + x -> 2x + 1x + ADD_COEFFICIENT_OF_ONE: 'ADD_COEFFICIENT_OF_ONE', + // e.g. x^2 + x^2 -> 2x^2 + ADD_POLYNOMIAL_TERMS: 'ADD_POLYNOMIAL_TERMS', + // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 + GROUP_COEFFICIENTS: 'GROUP_COEFFICIENTS', + // e.g. -x + 2x => -1*x + 2x + UNARY_MINUS_TO_NEGATIVE_ONE: 'UNARY_MINUS_TO_NEGATIVE_ONE', + // MULTIPLYING POLYNOMIALS + // e.g. x^2 * x -> x^2 * x^1 + ADD_EXPONENT_OF_ONE: 'ADD_EXPONENT_OF_ONE', + // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) + COLLECT_EXPONENTS: 'COLLECT_EXPONENTS', + // e.g. 2x * 3x -> (2 * 3)(x * x) + MULTIPLY_COEFFICIENTS: 'MULTIPLY_COEFFICIENTS', + // e.g. 2x * x -> 2x ^ 2 + MULTIPLY_POLYNOMIAL_TERMS: 'MULTIPLY_POLYNOMIAL_TERMS', + // FRACTIONS + // e.g. (x + 2)/2 -> x/2 + 2/2 + BREAK_UP_FRACTION: 'BREAK_UP_FRACTION', + // e.g. -2/-3 => 2/3 + CANCEL_MINUSES: 'CANCEL_MINUSES', + // e.g. 2x/2 -> x + CANCEL_TERMS: 'CANCEL_TERMS', + // e.g. 2/6 -> 1/3 + SIMPLIFY_FRACTION: 'SIMPLIFY_FRACTION', + // e.g. 2/-3 -> -2/3 + SIMPLIFY_SIGNS: 'SIMPLIFY_SIGNS', + // ADDING FRACTIONS + // e.g. 1/2 + 1/3 -> 5/6 + ADD_FRACTIONS: 'ADD_FRACTIONS', + // e.g. (1 + 2)/3 -> 3/3 + ADD_NUMERATORS: 'ADD_NUMERATORS', + // e.g. (2+1)/5 + COMBINE_NUMERATORS: 'COMBINE_NUMERATORS', + // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) + COMMON_DENOMINATOR: 'COMMON_DENOMINATOR', + // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) + CONVERT_INTEGER_TO_FRACTION: 'CONVERT_INTEGER_TO_FRACTION', + // e.g. 1.2 + 1/2 -> 1.2 + 0.5 + DIVIDE_FRACTION_FOR_ADDITION: 'DIVIDE_FRACTION_FOR_ADDITION', + // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 + MULTIPLY_DENOMINATORS: 'MULTIPLY_DENOMINATORS', + // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 + MULTIPLY_NUMERATORS: 'MULTIPLY_NUMERATORS', + // MULTIPLYING FRACTIONS + // e.g. 1/2 * 2/3 -> 2/6 + MULTIPLY_FRACTIONS: 'MULTIPLY_FRACTIONS', + // DIVISION + // e.g. 2/3/4 -> 2/(3*4) + SIMPLIFY_DIVISION: 'SIMPLIFY_DIVISION', + // e.g. x/(2/3) -> x * 3/2 + MULTIPLY_BY_INVERSE: 'MULTIPLY_BY_INVERSE', + // DISTRIBUTION + // e.g. 2(x + y) -> 2x + 2y + DISTRIBUTE: 'DISTRIBUTE', + // e.g. -(2 + x) -> -2 - x + DISTRIBUTE_NEGATIVE_ONE: 'DISTRIBUTE_NEGATIVE_ONE', + // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) + SIMPLIFY_TERMS: 'SIMPLIFY_TERMS', + // ABSOLUTE + // e.g. |-3| -> 3 + ABSOLUTE_VALUE: 'ABSOLUTE_VALUE', + // ROOTS + // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) + CANCEL_EXPONENT: 'CANCEL_EXPONENT', + // e.g. nthRoot(x ^ 2, 2) -> x + CANCEL_EXPONENT_AND_ROOT: 'CANCEL_EXPONENT_AND_ROOT', + // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 + CANCEL_ROOT: 'CANCEL_ROOT', + // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) + COMBINE_UNDER_ROOT: 'COMBINE_UNDER_ROOT', + // e.g. 2 * 2 * 2 -> 2 ^ 3 + CONVERT_MULTIPLICATION_TO_EXPONENT: 'CONVERT_MULTIPLICATION_TO_EXPONENT', + // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) + DISTRIBUTE_NTH_ROOT: 'DISTRIBUTE_NTH_ROOT', + // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x + EVALUATE_DISTRIBUTED_NTH_ROOT: 'EVALUATE_DISTRIBUTED_NTH_ROOT', + // e.g. 12 -> 2 * 2 * 3 + FACTOR_INTO_PRIMES: 'FACTOR_INTO_PRIMES', + // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) + GROUP_TERMS_BY_ROOT: 'GROUP_TERMS_BY_ROOT', + // e.g. nthRoot(4) -> 2 + NTH_ROOT_VALUE: 'NTH_ROOT_VALUE', + // SOLVING FOR A VARIABLE + // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 + ADD_TO_BOTH_SIDES: 'ADD_TO_BOTH_SIDES', + // e.g. 2x = 1 -> (2x)/2 = 1/2 + DIVIDE_FROM_BOTH_SIDES: 'DIVIDE_FROM_BOTH_SIDES', + // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) + MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: 'MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION', + // e.g. -x = 2 -> -1 * -x = -1 * 2 + MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: 'MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE', + // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 + MULTIPLY_TO_BOTH_SIDES: 'MULTIPLY_TO_BOTH_SIDES', + // e.g. x + 2 - 1 = 3 -> x + 1 = 3 + SIMPLIFY_LEFT_SIDE: 'SIMPLIFY_LEFT_SIDE', + // e.g. x = 3 - 1 -> x = 2 + SIMPLIFY_RIGHT_SIDE: 'SIMPLIFY_RIGHT_SIDE', + // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 + SUBTRACT_FROM_BOTH_SIDES: 'SUBTRACT_FROM_BOTH_SIDES', + // e.g. 2 = x -> x = 2 + SWAP_SIDES: 'SWAP_SIDES', + // CONSTANT EQUATION + // e.g. 2 = 2 + STATEMENT_IS_TRUE: 'STATEMENT_IS_TRUE', + // e.g. 2 = 3 + STATEMENT_IS_FALSE: 'STATEMENT_IS_FALSE', + // FACTORING + // e.g. x^2 - 4x -> x(x - 4) + FACTOR_SYMBOL: 'FACTOR_SYMBOL', + // e.g. x^2 - 4 -> (x - 2)(x + 2) + FACTOR_DIFFERENCE_OF_SQUARES: 'FACTOR_DIFFERENCE_OF_SQUARES', + // e.g. x^2 + 2x + 1 -> (x + 1)^2 + FACTOR_PERFECT_SQUARE: 'FACTOR_PERFECT_SQUARE', + // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) + FACTOR_SUM_PRODUCT_RULE: 'FACTOR_SUM_PRODUCT_RULE', }; +module.exports = tmp; +//# sourceMappingURL=ChangeTypes.js.map \ No newline at end of file diff --git a/lib/ChangeTypes.js.map b/lib/ChangeTypes.js.map new file mode 100644 index 00000000..ed45886e --- /dev/null +++ b/lib/ChangeTypes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ChangeTypes.js","sourceRoot":"","sources":["ChangeTypes.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/ChangeTypes.ts b/lib/ChangeTypes.ts new file mode 100644 index 00000000..d713b5ba --- /dev/null +++ b/lib/ChangeTypes.ts @@ -0,0 +1,186 @@ +// The text to identify rules for each possible step that can be taken + +var tmp; +tmp = { + NO_CHANGE: 'NO_CHANGE', + + // ARITHMETIC + + // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 + SIMPLIFY_ARITHMETIC: 'SIMPLIFY_ARITHMETIC', + + // BASICS + + // e.g. 2/-1 -> -2 + DIVISION_BY_NEGATIVE_ONE: 'DIVISION_BY_NEGATIVE_ONE', + // e.g. 2/1 -> 2 + DIVISION_BY_ONE: 'DIVISION_BY_ONE', + // e.g. x * 0 -> 0 + MULTIPLY_BY_ZERO: 'MULTIPLY_BY_ZERO', + // e.g. x * 2 -> 2x + REARRANGE_COEFF: 'REARRANGE_COEFF', + // e.g. x ^ 0 -> 1 + REDUCE_EXPONENT_BY_ZERO: 'REDUCE_EXPONENT_BY_ZERO', + // e.g. 0/1 -> 0 + REDUCE_ZERO_NUMERATOR: 'REDUCE_ZERO_NUMERATOR', + // e.g. 2 + 0 -> 2 + REMOVE_ADDING_ZERO: 'REMOVE_ADDING_ZERO', + // e.g. x ^ 1 -> x + REMOVE_EXPONENT_BY_ONE: 'REMOVE_EXPONENT_BY_ONE', + // e.g. 1 ^ x -> 1 + REMOVE_EXPONENT_BASE_ONE: 'REMOVE_EXPONENT_BASE_ONE', + // e.g. x * -1 -> -x + REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: 'REMOVE_MULTIPLYING_BY_NEGATIVE_ONE', + // e.g. x * 1 -> x + REMOVE_MULTIPLYING_BY_ONE: 'REMOVE_MULTIPLYING_BY_ONE', + // e.g. 2 - - 3 -> 2 + 3 + RESOLVE_DOUBLE_MINUS: 'RESOLVE_DOUBLE_MINUS', + + // COLLECT AND COMBINE + + // e.g. 2 + x + 3 + x -> 5 + 2x + COLLECT_AND_COMBINE_LIKE_TERMS: 'COLLECT_AND_COMBINE_LIKE_TERMS', + // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) + COLLECT_LIKE_TERMS: 'COLLECT_LIKE_TERMS', + + // ADDING POLYNOMIALS + + // e.g. 2x + x -> 2x + 1x + ADD_COEFFICIENT_OF_ONE: 'ADD_COEFFICIENT_OF_ONE', + // e.g. x^2 + x^2 -> 2x^2 + ADD_POLYNOMIAL_TERMS: 'ADD_POLYNOMIAL_TERMS', + // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 + GROUP_COEFFICIENTS: 'GROUP_COEFFICIENTS', + // e.g. -x + 2x => -1*x + 2x + UNARY_MINUS_TO_NEGATIVE_ONE: 'UNARY_MINUS_TO_NEGATIVE_ONE', + + // MULTIPLYING POLYNOMIALS + + // e.g. x^2 * x -> x^2 * x^1 + ADD_EXPONENT_OF_ONE: 'ADD_EXPONENT_OF_ONE', + // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) + COLLECT_EXPONENTS: 'COLLECT_EXPONENTS', + // e.g. 2x * 3x -> (2 * 3)(x * x) + MULTIPLY_COEFFICIENTS: 'MULTIPLY_COEFFICIENTS', + // e.g. 2x * x -> 2x ^ 2 + MULTIPLY_POLYNOMIAL_TERMS: 'MULTIPLY_POLYNOMIAL_TERMS', + + // FRACTIONS + + // e.g. (x + 2)/2 -> x/2 + 2/2 + BREAK_UP_FRACTION: 'BREAK_UP_FRACTION', + // e.g. -2/-3 => 2/3 + CANCEL_MINUSES: 'CANCEL_MINUSES', + // e.g. 2x/2 -> x + CANCEL_TERMS: 'CANCEL_TERMS', + // e.g. 2/6 -> 1/3 + SIMPLIFY_FRACTION: 'SIMPLIFY_FRACTION', + // e.g. 2/-3 -> -2/3 + SIMPLIFY_SIGNS: 'SIMPLIFY_SIGNS', + + // ADDING FRACTIONS + + // e.g. 1/2 + 1/3 -> 5/6 + ADD_FRACTIONS: 'ADD_FRACTIONS', + // e.g. (1 + 2)/3 -> 3/3 + ADD_NUMERATORS: 'ADD_NUMERATORS', + // e.g. (2+1)/5 + COMBINE_NUMERATORS: 'COMBINE_NUMERATORS', + // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) + COMMON_DENOMINATOR: 'COMMON_DENOMINATOR', + // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) + CONVERT_INTEGER_TO_FRACTION: 'CONVERT_INTEGER_TO_FRACTION', + // e.g. 1.2 + 1/2 -> 1.2 + 0.5 + DIVIDE_FRACTION_FOR_ADDITION: 'DIVIDE_FRACTION_FOR_ADDITION', + // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 + MULTIPLY_DENOMINATORS: 'MULTIPLY_DENOMINATORS', + // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 + MULTIPLY_NUMERATORS: 'MULTIPLY_NUMERATORS', + + // MULTIPLYING FRACTIONS + + // e.g. 1/2 * 2/3 -> 2/6 + MULTIPLY_FRACTIONS: 'MULTIPLY_FRACTIONS', + + // DIVISION + + // e.g. 2/3/4 -> 2/(3*4) + SIMPLIFY_DIVISION: 'SIMPLIFY_DIVISION', + // e.g. x/(2/3) -> x * 3/2 + MULTIPLY_BY_INVERSE: 'MULTIPLY_BY_INVERSE', + + // DISTRIBUTION + + // e.g. 2(x + y) -> 2x + 2y + DISTRIBUTE: 'DISTRIBUTE', + // e.g. -(2 + x) -> -2 - x + DISTRIBUTE_NEGATIVE_ONE: 'DISTRIBUTE_NEGATIVE_ONE', + // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) + SIMPLIFY_TERMS: 'SIMPLIFY_TERMS', + + // ABSOLUTE + // e.g. |-3| -> 3 + ABSOLUTE_VALUE: 'ABSOLUTE_VALUE', + + // ROOTS + // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) + CANCEL_EXPONENT: 'CANCEL_EXPONENT', + // e.g. nthRoot(x ^ 2, 2) -> x + CANCEL_EXPONENT_AND_ROOT: 'CANCEL_EXPONENT_AND_ROOT', + // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 + CANCEL_ROOT: 'CANCEL_ROOT', + // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) + COMBINE_UNDER_ROOT: 'COMBINE_UNDER_ROOT', + // e.g. 2 * 2 * 2 -> 2 ^ 3 + CONVERT_MULTIPLICATION_TO_EXPONENT: 'CONVERT_MULTIPLICATION_TO_EXPONENT', + // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) + DISTRIBUTE_NTH_ROOT: 'DISTRIBUTE_NTH_ROOT', + // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x + EVALUATE_DISTRIBUTED_NTH_ROOT: 'EVALUATE_DISTRIBUTED_NTH_ROOT', + // e.g. 12 -> 2 * 2 * 3 + FACTOR_INTO_PRIMES: 'FACTOR_INTO_PRIMES', + // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) + GROUP_TERMS_BY_ROOT: 'GROUP_TERMS_BY_ROOT', + // e.g. nthRoot(4) -> 2 + NTH_ROOT_VALUE: 'NTH_ROOT_VALUE', + + // SOLVING FOR A VARIABLE + + // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 + ADD_TO_BOTH_SIDES: 'ADD_TO_BOTH_SIDES', + // e.g. 2x = 1 -> (2x)/2 = 1/2 + DIVIDE_FROM_BOTH_SIDES: 'DIVIDE_FROM_BOTH_SIDES', + // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) + MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: 'MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION', + // e.g. -x = 2 -> -1 * -x = -1 * 2 + MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: 'MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE', + // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 + MULTIPLY_TO_BOTH_SIDES: 'MULTIPLY_TO_BOTH_SIDES', + // e.g. x + 2 - 1 = 3 -> x + 1 = 3 + SIMPLIFY_LEFT_SIDE: 'SIMPLIFY_LEFT_SIDE', + // e.g. x = 3 - 1 -> x = 2 + SIMPLIFY_RIGHT_SIDE: 'SIMPLIFY_RIGHT_SIDE', + // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 + SUBTRACT_FROM_BOTH_SIDES: 'SUBTRACT_FROM_BOTH_SIDES', + // e.g. 2 = x -> x = 2 + SWAP_SIDES: 'SWAP_SIDES', + + // CONSTANT EQUATION + + // e.g. 2 = 2 + STATEMENT_IS_TRUE: 'STATEMENT_IS_TRUE', + // e.g. 2 = 3 + STATEMENT_IS_FALSE: 'STATEMENT_IS_FALSE', + + // FACTORING + + // e.g. x^2 - 4x -> x(x - 4) + FACTOR_SYMBOL: 'FACTOR_SYMBOL', + // e.g. x^2 - 4 -> (x - 2)(x + 2) + FACTOR_DIFFERENCE_OF_SQUARES: 'FACTOR_DIFFERENCE_OF_SQUARES', + // e.g. x^2 + 2x + 1 -> (x + 1)^2 + FACTOR_PERFECT_SQUARE: 'FACTOR_PERFECT_SQUARE', + // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) + FACTOR_SUM_PRODUCT_RULE: 'FACTOR_SUM_PRODUCT_RULE', +}; +export = tmp; diff --git a/lib/Negative.js b/lib/Negative.js deleted file mode 100644 index 6efb0afc..00000000 --- a/lib/Negative.js +++ /dev/null @@ -1,94 +0,0 @@ -const Node = require('./node'); - -const Negative = {}; - -// Returns if the given node is negative. Treats a unary minus as a negative, -// as well as a negative constant value or a constant fraction that would -// evaluate to a negative number -Negative.isNegative = function(node) { - if (Node.Type.isUnaryMinus(node)) { - return !Negative.isNegative(node.args[0]); - } - else if (Node.Type.isConstant(node)) { - return parseFloat(node.value) < 0; - } - else if (Node.Type.isConstantFraction(node)) { - const numeratorValue = parseFloat(node.args[0].value); - const denominatorValue = parseFloat(node.args[1].value); - if (numeratorValue < 0 || denominatorValue < 0) { - return !(numeratorValue < 0 && denominatorValue < 0); - } - } - else if (Node.PolynomialTerm.isPolynomialTerm(node)) { - const polyNode = new Node.PolynomialTerm(node); - return Negative.isNegative(polyNode.getCoeffNode(true)); - } - - return false; -}; - -// Given a node, returns the negated node -// If naive is true, then we just add an extra unary minus to the expression -// otherwise, we do the actual negation -// E.g. -// not naive: -3 -> 3, x -> -x -// naive: -3 -> --3, x -> -x -Negative.negate = function(node, naive=false) { - if (Node.Type.isConstantFraction(node)) { - node.args[0] = Negative.negate(node.args[0], naive); - return node; - } - else if (Node.PolynomialTerm.isPolynomialTerm(node)) { - return Negative.negatePolynomialTerm(node, naive); - } - else if (!naive) { - if (Node.Type.isUnaryMinus(node)) { - return node.args[0]; - } - else if (Node.Type.isConstant(node)) { - return Node.Creator.constant(0 - parseFloat(node.value)); - } - } - return Node.Creator.unaryMinus(node); -}; - -// Multiplies a polynomial term by -1 and returns the new node -// If naive is true, then we just add an extra unary minus to the expression -// otherwise, we do the actual negation -// E.g. -// not naive: -3x -> 3x, x -> -x -// naive: -3x -> --3x, x -> -x -Negative.negatePolynomialTerm = function(node, naive=false) { - if (!Node.PolynomialTerm.isPolynomialTerm(node)) { - throw Error('node is not a polynomial term'); - } - const polyNode = new Node.PolynomialTerm(node); - - let newCoeff; - if (!polyNode.hasCoeff()) { - newCoeff = Node.Creator.constant(-1); - } - else { - const oldCoeff = polyNode.getCoeffNode(); - if (oldCoeff.value === '-1') { - newCoeff = null; - } - else if (polyNode.hasFractionCoeff()) { - let numerator = oldCoeff.args[0]; - numerator = Negative.negate(numerator, naive); - - const denominator = oldCoeff.args[1]; - newCoeff = Node.Creator.operator('/', [numerator, denominator]); - } - else { - newCoeff = Negative.negate(oldCoeff, naive); - if (newCoeff.value === '1') { - newCoeff = null; - } - } - } - return Node.Creator.polynomialTerm( - polyNode.getSymbolNode(), polyNode.getExponentNode(), newCoeff); -}; - -module.exports = Negative; diff --git a/lib/Negative.ts b/lib/Negative.ts new file mode 100644 index 00000000..d6ced34b --- /dev/null +++ b/lib/Negative.ts @@ -0,0 +1,87 @@ +import mathNode = require('./mathNode'); + +class Negative { +// Returns if the given node is negative. Treats a unary minus as a negative, +// as well as a negative constant value or a constant fraction that would +// evaluate to a negative number + isNegative(node) { + if (mathNode.Type.isUnaryMinus(node)) { + return !Negative.isNegative(node.args[0]); + } else if (mathNode.Type.isConstant(node)) { + return parseFloat(node.value) < 0; + } else if (mathNode.Type.isConstantFraction(node)) { + const numeratorValue = parseFloat(node.args[0].value); + const denominatorValue = parseFloat(node.args[1].value); + if (numeratorValue < 0 || denominatorValue < 0) { + return !(numeratorValue < 0 && denominatorValue < 0); + } + } else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + const polyNode = new mathNode.PolynomialTerm(node); + return Negative.isNegative(polyNode.getCoeffNode(true)); + } + + return false; + } + +// Given a node, returns the negated node +// If naive is true, then we just add an extra unary minus to the expression +// otherwise, we do the actual negation +// E.g. +// not naive: -3 -> 3, x -> -x +// naive: -3 -> --3, x -> -x + negate(node, naive=false) { + if (mathNode.Type.isConstantFraction(node)) { + node.args[0] = Negative.negate(node.args[0], naive); + return node; + } else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + return Negative.negatePolynomialTerm(node, naive); + } else if (!naive) { + if (mathNode.Type.isUnaryMinus(node)) { + return node.args[0]; + } else if (mathNode.Type.isConstant(node)) { + return mathNode.Creator.constant(0 - parseFloat(node.value)); + } + } + return mathNode.Creator.unaryMinus(node); + } + +// Multiplies a polynomial term by -1 and returns the new node +// If naive is true, then we just add an extra unary minus to the expression +// otherwise, we do the actual negation +// E.g. +// not naive: -3x -> 3x, x -> -x +// naive: -3x -> --3x, x -> -x + negatePolynomialTerm(node, naive=false) { + if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { + throw Error('node is not a polynomial term'); + } + const polyNode = new mathNode.PolynomialTerm(node); + + let newCoeff; + if (!polyNode.hasCoeff()) { + newCoeff = mathNode.Creator.constant(-1); + } else { + const oldCoeff = polyNode.getCoeffNode(); + if (oldCoeff.value === '-1') { + newCoeff = null; + } else if (polyNode.hasFractionCoeff()) { + let numerator = oldCoeff.args[0]; + numerator = Negative.negate(numerator, naive); + + const denominator = oldCoeff.args[1]; + newCoeff = mathNode.Creator.operator('/', [numerator, denominator]); + } else { + newCoeff = Negative.negate(oldCoeff, naive); + if (newCoeff.value === '1') { + newCoeff = null; + } + } + } + return mathNode.Creator.polynomialTerm( + polyNode.getSymbolNode(), + polyNode.getExponentNode(), + newCoeff); + } +} + +export = Negative; diff --git a/lib/Symbols.js b/lib/Symbols.js deleted file mode 100644 index 6978a8f9..00000000 --- a/lib/Symbols.js +++ /dev/null @@ -1,75 +0,0 @@ -const Node = require('./node'); - -const Symbols = {}; - -// returns the set of all the symbols in an equation -Symbols.getSymbolsInEquation = function(equation) { - const leftSymbols = Symbols.getSymbolsInExpression(equation.leftNode); - const rightSymbols = Symbols.getSymbolsInExpression(equation.rightNode); - const symbols = new Set([...leftSymbols, ...rightSymbols]); - return symbols; -}; - -// return the set of symbols in the expression tree -Symbols.getSymbolsInExpression = function(expression) { - const symbolNodes = expression.filter(node => node.isSymbolNode); // all the symbol nodes - const symbols = symbolNodes.map(node => node.name); // all the symbol nodes' names - const symbolSet = new Set(symbols); // to get rid of duplicates - return symbolSet; -}; - -// Iterates through a node and returns the polynomial term with the symbol name -// Returns null if no terms with the symbol name are in the node. -// e.g. 4x^2 + 2x + y + 2 with `symbolName=x` would return 2x -Symbols.getLastSymbolTerm = function(node, symbolName) { - // First check if the node itself is a polyomial term with symbolName - if (isSymbolTerm(node, symbolName)) { - return node; - } - // Otherwise, it's a sum of terms. Look through the operands for a term - // with `symbolName` - else if (Node.Type.isOperator(node, '+')) { - for (let i = node.args.length - 1; i >= 0 ; i--) { - const child = node.args[i]; - if (isSymbolTerm(child, symbolName)) { - return child; - } - } - } - return null; -}; - -// Iterates through a node and returns the last term that does not have the -// symbolName including other polynomial terms, and constants or constant -// fractions -// e.g. 4x^2 with `symbolName=x` would return 4 -// e.g. 4x^2 + 2x + 2/4 with `symbolName=x` would return 2/4 -// e.g. 4x^2 + 2x + y with `symbolName=x` would return y -Symbols.getLastNonSymbolTerm = function(node, symbolName) { - if (isSymbolTerm(node, symbolName)) { - return new Node.PolynomialTerm(node).getCoeffNode(); - } - else if (Node.Type.isOperator(node)) { - for (let i = node.args.length - 1; i >= 0 ; i--) { - const child = node.args[i]; - if (!isSymbolTerm(child, symbolName)) { - return child; - } - } - } - - return null; -}; - -// Returns if `node` is a polynomial term with symbol `symbolName` -function isSymbolTerm(node, symbolName) { - if (Node.PolynomialTerm.isPolynomialTerm(node)) { - const polyTerm = new Node.PolynomialTerm(node); - if (polyTerm.getSymbolName() === symbolName) { - return true; - } - } - return false; -} - -module.exports = Symbols; diff --git a/lib/Symbols.ts b/lib/Symbols.ts new file mode 100644 index 00000000..da423bc5 --- /dev/null +++ b/lib/Symbols.ts @@ -0,0 +1,75 @@ +import mathNode = require('./mathNode'); + +class Symbols { + // returns the set of all the symbols in an equation + getSymbolsInEquation(equation) { + const leftSymbols = Symbols.getSymbolsInExpression(equation.leftNode); + const rightSymbols = Symbols.getSymbolsInExpression(equation.rightNode); + const symbols = new Set([...leftSymbols, ...rightSymbols]); + return symbols; + }; + + +// return the set of symbols in the expression tree + static getSymbolsInExpression = expression => { + const symbolNodes = expression.filter(node => node.isSymbolNode); // all the symbol nodes + const symbols = symbolNodes.map(node => node.name); // all the symbol nodes' names + const symbolSet = new Set(symbols); // to get rid of duplicates + return symbolSet; + }; + +// Iterates through a node and returns the polynomial term with the symbol name +// Returns null if no terms with the symbol name are in the node. +// e.g. 4x^2 + 2x + y + 2 with `symbolName=x` would return 2x + getLastSymbolTerm = (node, symbolName) => { + // First check if the node itself is a polyomial term with symbolName + if (this.isSymbolTerm(node, symbolName)) { + return node; + } + // Otherwise, it's a sum of terms. Look through the operands for a term + // with `symbolName` + else if (mathNode.Type.isOperator(node, '+')) { + for (let i = node.args.length - 1; i >= 0; i--) { + const child = node.args[i]; + if (this.isSymbolTerm(child, symbolName)) { + return child; + } + } + } + return null; + }; + +// Iterates through a node and returns the last term that does not have the +// symbolName including other polynomial terms, and constants or constant +// fractions +// e.g. 4x^2 with `symbolName=x` would return 4 +// e.g. 4x^2 + 2x + 2/4 with `symbolName=x` would return 2/4 +// e.g. 4x^2 + 2x + y with `symbolName=x` would return y + getLastNonSymbolTerm = (node, symbolName) => { + if (this.isSymbolTerm(node, symbolName)) { + return new mathNode.PolynomialTerm(node).getCoeffNode(); + } else if (mathNode.Type.isOperator(node)) { + for (let i = node.args.length - 1; i >= 0; i--) { + const child = node.args[i]; + if (!this.isSymbolTerm(child, symbolName)) { + return child; + } + } + } + + return null; + }; + +// Returns if `node` is a polynomial term with symbol `symbolName` + isSymbolTerm(node, symbolName) { + if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + const polyTerm = new mathNode.PolynomialTerm(node); + if (polyTerm.getSymbolName() === symbolName) { + return true; + } + } + return false; + } +} + +export = Symbols; diff --git a/lib/TreeSearch.js b/lib/TreeSearch.js deleted file mode 100644 index ea5c7b18..00000000 --- a/lib/TreeSearch.js +++ /dev/null @@ -1,70 +0,0 @@ -const Node = require('./node'); - -const TreeSearch = {}; - -// Returns a function that performs a preorder search on the tree for the given -// simplifcation function -TreeSearch.preOrder = function(simplificationFunction) { - return function (node) { - return search(simplificationFunction, node, true); - }; -}; - -// Returns a function that performs a postorder search on the tree for the given -// simplifcation function -TreeSearch.postOrder = function(simplificationFunction) { - return function (node) { - return search(simplificationFunction, node, false); - }; -}; - -// A helper function for performing a tree search with a function -function search(simplificationFunction, node, preOrder) { - let status; - - if (preOrder) { - status = simplificationFunction(node); - if (status.hasChanged()) { - return status; - } - } - - if (Node.Type.isConstant(node) || Node.Type.isSymbol(node)) { - return Node.Status.noChange(node); - } - else if (Node.Type.isUnaryMinus(node)) { - status = search(simplificationFunction, node.args[0], preOrder); - if (status.hasChanged()) { - return Node.Status.childChanged(node, status); - } - } - else if (Node.Type.isOperator(node) || Node.Type.isFunction(node)) { - for (let i = 0; i < node.args.length; i++) { - const child = node.args[i]; - const childNodeStatus = search(simplificationFunction, child, preOrder); - if (childNodeStatus.hasChanged()) { - return Node.Status.childChanged(node, childNodeStatus, i); - } - } - } - else if (Node.Type.isParenthesis(node)) { - status = search(simplificationFunction, node.content, preOrder); - if (status.hasChanged()) { - return Node.Status.childChanged(node, status); - } - } - else { - throw Error('Unsupported node type: ' + node); - } - - if (!preOrder) { - return simplificationFunction(node); - } - else { - return Node.Status.noChange(node); - } -} - - - -module.exports = TreeSearch; diff --git a/lib/TreeSearch.ts b/lib/TreeSearch.ts new file mode 100644 index 00000000..5f8f6ae8 --- /dev/null +++ b/lib/TreeSearch.ts @@ -0,0 +1,57 @@ +import mathNode = require('./mathNode'); + +class TreeSearch { + +// Returns a function that performs a preorder search on the tree for the given +// simplifcation function + preOrder = simplificationFunction => node => search(simplificationFunction, node, true); + +// Returns a function that performs a postorder search on the tree for the given +// simplifcation function + postOrder = simplificationFunction => node => search(simplificationFunction, node, false); + +// A helper function for performing a tree search with a function + + search(simplificationFunction, node, preOrder) { + let status; + + if (preOrder) { + status = simplificationFunction(node); + if (status.hasChanged()) { + return status; + } + } + + if (mathNode.Type.isConstant(node) || mathNode.Type.isSymbol(node)) { + return mathNode.Status.noChange(node); + } else if (mathNode.Type.isUnaryMinus(node)) { + status = this.search(simplificationFunction, node.args[0], preOrder); + if (status.hasChanged()) { + return mathNode.Status.childChanged(node, status); + } + } else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { + for (let i = 0; i < node.args.length; i++) { + const child = node.args[i]; + const childNodeStatus = search(simplificationFunction, child, preOrder); + if (childNodeStatus.hasChanged()) { + return mathNode.Status.childChanged(node, childNodeStatus, i); + } + } + } else if (mathNode.Type.isParenthesis(node)) { + status = search(simplificationFunction, node.content, preOrder); + if (status.hasChanged()) { + return mathNode.Status.childChanged(node, status); + } + } else { + throw Error('Unsupported node type: ' + node); + } + + if (!preOrder) { + return simplificationFunction(node); + } else { + return mathNode.Status.noChange(node); + } + } +} + +export = TreeSearch; diff --git a/lib/checks/canAddLikeTermPolynomialNodes.js b/lib/checks/canAddLikeTermPolynomialNodes.ts similarity index 70% rename from lib/checks/canAddLikeTermPolynomialNodes.js rename to lib/checks/canAddLikeTermPolynomialNodes.ts index 6c9ac1ca..8e1792e4 100644 --- a/lib/checks/canAddLikeTermPolynomialNodes.js +++ b/lib/checks/canAddLikeTermPolynomialNodes.ts @@ -1,19 +1,20 @@ -const Node = require('../node'); +const mathNode = require('../node'); // Returns true if the nodes are polynomial terms that can be added together. +function canAddLikeTermPolynomialNodes(node: any); function canAddLikeTermPolynomialNodes(node) { - if (!Node.Type.isOperator(node) || node.op !== '+') { + if (!mathNode.Type.isOperator(node) || node.op !== '+') { return false; } const args = node.args; - if (!args.every(n => Node.PolynomialTerm.isPolynomialTerm(n))) { + if (!args.every(n => mathNode.PolynomialTerm.isPolynomialTerm(n))) { return false; } if (args.length === 1) { return false; } - const polynomialTermList = args.map(n => new Node.PolynomialTerm(n)); + const polynomialTermList = args.map(n => new mathNode.PolynomialTerm(n)); // to add terms, they must have the same symbol name *and* exponent const firstTerm = polynomialTermList[0]; @@ -29,4 +30,4 @@ function canAddLikeTermPolynomialNodes(node) { }); } -module.exports = canAddLikeTermPolynomialNodes; +export = canAddLikeTermPolynomialNodes; diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.js b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts similarity index 63% rename from lib/checks/canMultiplyLikeTermPolynomialNodes.js rename to lib/checks/canMultiplyLikeTermPolynomialNodes.ts index 0654ae82..580ce8fc 100644 --- a/lib/checks/canMultiplyLikeTermPolynomialNodes.js +++ b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts @@ -1,20 +1,21 @@ -const Node = require('../node'); +const mathNode = require('../node'); // Returns true if the nodes are symbolic terms with the same symbol and no // coefficients. +function canMultiplyLikeTermPolynomialNodes(node: any); function canMultiplyLikeTermPolynomialNodes(node) { - if (!Node.Type.isOperator(node) || node.op !== '*') { + if (!mathNode.Type.isOperator(node) || node.op !== '*') { return false; } const args = node.args; - if (!args.every(n => Node.PolynomialTerm.isPolynomialTerm(n))) { + if (!args.every(n => mathNode.PolynomialTerm.isPolynomialTerm(n))) { return false; } if (args.length === 1) { return false; } - const polynomialTermList = node.args.map(n => new Node.PolynomialTerm(n)); + const polynomialTermList = node.args.map(n => new mathNode.PolynomialTerm(n)); if (!polynomialTermList.every(polyTerm => !polyTerm.hasCoeff())) { return false; } @@ -25,4 +26,4 @@ function canMultiplyLikeTermPolynomialNodes(node) { return restTerms.every(term => firstTerm.getSymbolName() === term.getSymbolName()); } -module.exports = canMultiplyLikeTermPolynomialNodes; +export = canMultiplyLikeTermPolynomialNodes; diff --git a/lib/checks/canRearrangeCoefficient.js b/lib/checks/canRearrangeCoefficient.ts similarity index 59% rename from lib/checks/canRearrangeCoefficient.js rename to lib/checks/canRearrangeCoefficient.ts index 36979a4f..fffc5303 100644 --- a/lib/checks/canRearrangeCoefficient.js +++ b/lib/checks/canRearrangeCoefficient.ts @@ -1,7 +1,8 @@ -const Node = require('../node'); +const mathNode = require('../node'); // Returns true if the expression is a multiplication between a constant // and polynomial without a coefficient. +function canRearrangeCoefficient(node: any); function canRearrangeCoefficient(node) { // implicit multiplication doesn't count as multiplication here, since it // represents a single term. @@ -11,15 +12,15 @@ function canRearrangeCoefficient(node) { if (node.args.length !== 2) { return false; } - if (!Node.Type.isConstantOrConstantFraction(node.args[1])) { + if (!mathNode.Type.isConstantOrConstantFraction(node.args[1])) { return false; } - if (!Node.PolynomialTerm.isPolynomialTerm(node.args[0])) { + if (!mathNode.PolynomialTerm.isPolynomialTerm(node.args[0])) { return false; } - const polyNode = new Node.PolynomialTerm(node.args[0]); + const polyNode = new mathNode.PolynomialTerm(node.args[0]); return !polyNode.hasCoeff(); } -module.exports = canRearrangeCoefficient; +export = canRearrangeCoefficient; diff --git a/lib/checks/canSimplifyPolynomialTerms.js b/lib/checks/canSimplifyPolynomialTerms.js deleted file mode 100644 index eed134d0..00000000 --- a/lib/checks/canSimplifyPolynomialTerms.js +++ /dev/null @@ -1,13 +0,0 @@ -const canAddLikeTermPolynomialNodes = require('./canAddLikeTermPolynomialNodes'); -const canMultiplyLikeTermPolynomialNodes = require('./canMultiplyLikeTermPolynomialNodes'); -const canRearrangeCoefficient = require('./canRearrangeCoefficient'); - -// Returns true if the node is an operation node with parameters that are -// polynomial terms that can be combined in some way. -function canSimplifyPolynomialTerms(node) { - return (canAddLikeTermPolynomialNodes(node) || - canMultiplyLikeTermPolynomialNodes(node) || - canRearrangeCoefficient(node)); -} - -module.exports = canSimplifyPolynomialTerms; diff --git a/lib/checks/canSimplifyPolynomialTerms.ts b/lib/checks/canSimplifyPolynomialTerms.ts new file mode 100644 index 00000000..9ccad33e --- /dev/null +++ b/lib/checks/canSimplifyPolynomialTerms.ts @@ -0,0 +1,14 @@ +import canAddLikeTermPolynomialNodes = require('./canAddLikeTermPolynomialNodes'); +import canMultiplyLikeTermPolynomialNodes = require('./canMultiplyLikeTermPolynomialNodes'); +import canRearrangeCoefficient = require('./canRearrangeCoefficient'); + +// Returns true if the node is an operation node with parameters that are +// polynomial terms that can be combined in some way. +function canSimplifyPolynomialTerms(node: any); +function canSimplifyPolynomialTerms(node) { + return (canAddLikeTermPolynomialNodes(node) || + canMultiplyLikeTermPolynomialNodes(node) || + canRearrangeCoefficient(node)); +} + +export = canSimplifyPolynomialTerms; diff --git a/lib/checks/hasUnsupportedNodes.js b/lib/checks/hasUnsupportedNodes.ts similarity index 50% rename from lib/checks/hasUnsupportedNodes.js rename to lib/checks/hasUnsupportedNodes.ts index fb229ab4..c646791c 100644 --- a/lib/checks/hasUnsupportedNodes.js +++ b/lib/checks/hasUnsupportedNodes.ts @@ -1,20 +1,21 @@ -const Node = require('../node'); -const resolvesToConstant = require('./resolvesToConstant'); +const mathNode = require('../node'); +import resolvesToConstant = require('./resolvesToConstant'); +function hasUnsupportedNodes(node: any); function hasUnsupportedNodes(node) { - if (Node.Type.isParenthesis(node)) { + if (mathNode.Type.isParenthesis(node)) { return hasUnsupportedNodes(node.content); } - else if (Node.Type.isUnaryMinus(node)) { + else if (mathNode.Type.isUnaryMinus(node)) { return hasUnsupportedNodes(node.args[0]); } - else if (Node.Type.isOperator(node)) { + else if (mathNode.Type.isOperator(node)) { return node.args.some(hasUnsupportedNodes); } - else if (Node.Type.isSymbol(node) || Node.Type.isConstant(node)) { + else if (mathNode.Type.isSymbol(node) || mathNode.Type.isConstant(node)) { return false; } - else if (Node.Type.isFunction(node, 'abs')) { + else if (mathNode.Type.isFunction(node, 'abs')) { if (node.args.length !== 1) { return true; } @@ -23,7 +24,7 @@ function hasUnsupportedNodes(node) { } return !resolvesToConstant(node.args[0]); } - else if (Node.Type.isFunction(node, 'nthRoot')) { + else if (mathNode.Type.isFunction(node, 'nthRoot')) { return node.args.some(hasUnsupportedNodes) || node.args.length < 1; } else { @@ -31,4 +32,4 @@ function hasUnsupportedNodes(node) { } } -module.exports = hasUnsupportedNodes; +export = hasUnsupportedNodes; diff --git a/lib/checks/index.js b/lib/checks/index.js deleted file mode 100644 index 5bb07252..00000000 --- a/lib/checks/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const canAddLikeTermPolynomialNodes = require('./canAddLikeTermPolynomialNodes'); -const canMultiplyLikeTermPolynomialNodes = require('./canMultiplyLikeTermPolynomialNodes'); -const canRearrangeCoefficient = require('./canRearrangeCoefficient'); -const canSimplifyPolynomialTerms = require('./canSimplifyPolynomialTerms'); -const hasUnsupportedNodes = require('./hasUnsupportedNodes'); -const isQuadratic = require('./isQuadratic'); -const resolvesToConstant = require('./resolvesToConstant'); - -module.exports = { - canAddLikeTermPolynomialNodes, - canMultiplyLikeTermPolynomialNodes, - canRearrangeCoefficient, - canSimplifyPolynomialTerms, - hasUnsupportedNodes, - isQuadratic, - resolvesToConstant, -}; diff --git a/lib/checks/index.ts b/lib/checks/index.ts new file mode 100644 index 00000000..eab47622 --- /dev/null +++ b/lib/checks/index.ts @@ -0,0 +1,18 @@ +import canAddLikeTermPolynomialNodes = require('./canAddLikeTermPolynomialNodes'); +import canMultiplyLikeTermPolynomialNodes = require('./canMultiplyLikeTermPolynomialNodes'); +import canRearrangeCoefficient = require('./canRearrangeCoefficient'); +import canSimplifyPolynomialTerms = require('./canSimplifyPolynomialTerms'); +import hasUnsupportedNodes = require('./hasUnsupportedNodes'); +import isQuadratic = require('./isQuadratic'); +import resolvesToConstant = require('./resolvesToConstant'); +var tmp; +tmp = { + canAddLikeTermPolynomialNodes, + canMultiplyLikeTermPolynomialNodes, + canRearrangeCoefficient, + canSimplifyPolynomialTerms, + hasUnsupportedNodes, + isQuadratic, + resolvesToConstant, +}; +export = tmp; diff --git a/lib/checks/isQuadratic.js b/lib/checks/isQuadratic.ts similarity index 66% rename from lib/checks/isQuadratic.js rename to lib/checks/isQuadratic.ts index f23ec7a7..06667853 100644 --- a/lib/checks/isQuadratic.js +++ b/lib/checks/isQuadratic.ts @@ -1,10 +1,11 @@ -const Node = require('../node'); -const Symbols = require('../Symbols'); +const mathNode = require('../node'); +import Symbols = require('../Symbols'); // Given a node, will determine if the expression is in the form of a quadratic // e.g. `x^2 + 2x + 1` OR `x^2 - 1` but not `x^3 + x^2 + x + 1` +function isQuadratic(node: any); function isQuadratic(node) { - if (!Node.Type.isOperator(node, '+')) { + if (!mathNode.Type.isOperator(node, '+')) { return false; } @@ -20,7 +21,7 @@ function isQuadratic(node) { const secondDegreeTerms = node.args.filter(isPolynomialTermOfDegree(2)); const firstDegreeTerms = node.args.filter(isPolynomialTermOfDegree(1)); - const constantTerms = node.args.filter(Node.Type.isConstant); + const constantTerms = node.args.filter(mathNode.Type.isConstant); // Check that there is one second degree term and at most one first degree // term and at most one constant term @@ -40,15 +41,16 @@ function isQuadratic(node) { // Given a degree, returns a function that checks if a node // is a polynomial term of the given degree. +function isPolynomialTermOfDegree(degree: any); function isPolynomialTermOfDegree(degree) { - return function(node) { - if (Node.PolynomialTerm.isPolynomialTerm(node)) { - const polyTerm = new Node.PolynomialTerm(node); - const exponent = polyTerm.getExponentNode(true); - return exponent && parseFloat(exponent.value) === degree; - } - return false; + return node => { + if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + const polyTerm = new mathNode.PolynomialTerm(node); + const exponent = polyTerm.getExponentNode(true); + return exponent && parseFloat(exponent.value) === degree; + } + return false; }; } -module.exports = isQuadratic; +export = isQuadratic; diff --git a/lib/checks/resolvesToConstant.js b/lib/checks/resolvesToConstant.ts similarity index 56% rename from lib/checks/resolvesToConstant.js rename to lib/checks/resolvesToConstant.ts index c70829c9..197dc6ba 100644 --- a/lib/checks/resolvesToConstant.js +++ b/lib/checks/resolvesToConstant.ts @@ -1,23 +1,24 @@ -const Node = require('../node'); +const mathNode = require('../node'); // Returns true if the node is a constant or can eventually be resolved to // a constant. // e.g. 2, 2+4, (2+4)^2 would all return true. x + 4 would return false +function resolvesToConstant(node: any); function resolvesToConstant(node) { - if (Node.Type.isOperator(node) || Node.Type.isFunction(node)) { + if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { return node.args.every( (child) => resolvesToConstant(child)); } - else if (Node.Type.isParenthesis(node)) { + else if (mathNode.Type.isParenthesis(node)) { return resolvesToConstant(node.content); } - else if (Node.Type.isConstant(node, true)) { + else if (mathNode.Type.isConstant(node, true)) { return true; } - else if (Node.Type.isSymbol(node)) { + else if (mathNode.Type.isSymbol(node)) { return false; } - else if (Node.Type.isUnaryMinus(node)) { + else if (mathNode.Type.isUnaryMinus(node)) { return resolvesToConstant(node.args[0]); } else { @@ -25,4 +26,4 @@ function resolvesToConstant(node) { } } -module.exports = resolvesToConstant; +export = resolvesToConstant; diff --git a/lib/equation/Equation.js b/lib/equation/Equation.ts similarity index 63% rename from lib/equation/Equation.js rename to lib/equation/Equation.ts index 26b2c1d9..60793454 100644 --- a/lib/equation/Equation.js +++ b/lib/equation/Equation.ts @@ -1,7 +1,6 @@ -const math = require('mathjs'); - -const clone = require('../util/clone'); -const printNode = require('../util/print'); +import math = require('mathjs'); +import clone = require('../util/clone'); +import printNode = require('../util/print'); // This represents an equation, made up of the leftNode (LHS), the // rightNode (RHS) and a comparator (=, <, >, <=, or >=) @@ -30,16 +29,15 @@ class Equation { // Splits a string on the given comparator and returns a new Equation object // from the left and right hand sides -Equation.createEquationFromString = function(str, comparator) { - const sides = str.split(comparator); - if (sides.length !== 2) { - throw Error('Expected two sides of an equation using comparator: ' + - comparator); - } - const leftNode = math.parse(sides[0]); - const rightNode = math.parse(sides[1]); - - return new Equation(leftNode, rightNode, comparator); +Equation.createEquationFromString = (str, comparator) => { + const sides = str.split(comparator); + if (sides.length !== 2) { + throw Error('Expected two sides of an equation using comparator: ' + + comparator); + } + const leftNode = math.parse(sides[0]); + const rightNode = math.parse(sides[1]); + + return new Equation(leftNode, rightNode, comparator); }; - -module.exports = Equation; +export = Equation; diff --git a/lib/equation/Status.js b/lib/equation/Status.js deleted file mode 100644 index a8754442..00000000 --- a/lib/equation/Status.js +++ /dev/null @@ -1,73 +0,0 @@ -const ChangeTypes = require('../ChangeTypes'); -const Equation = require('./Equation'); -const Node = require('../node'); - -// This represents the current equation we're solving. -// As we move step by step, an equation might be updated. Functions return this -// status object to pass on the updated equation and information on if/how it was -// changed. -class Status { - constructor(changeType, oldEquation, newEquation, substeps=[]) { - if (!newEquation) { - throw Error('new equation isn\'t defined'); - } - if (changeType === undefined || typeof(changeType) !== 'string') { - throw Error('changetype isn\'t valid'); - } - - this.changeType = changeType; - this.oldEquation = oldEquation; - this.newEquation = newEquation; - this.substeps = substeps; - } - - hasChanged() { - return this.changeType !== ChangeTypes.NO_CHANGE; - } -} - -// A wrapper around the Status constructor for the case where equation -// hasn't been changed. -Status.noChange = function(equation) { - return new Status(ChangeTypes.NO_CHANGE, null, equation); -}; - -Status.addLeftStep = function(equation, leftStep) { - const substeps = []; - leftStep.substeps.forEach(substep => { - substeps.push(Status.addLeftStep(equation, substep)); - }); - let oldEquation = null; - if (leftStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.leftNode = leftStep.oldNode; - } - const newEquation = equation.clone(); - newEquation.leftNode = leftStep.newNode; - return new Status( - leftStep.changeType, oldEquation, newEquation, substeps); -}; - -Status.addRightStep = function(equation, rightStep) { - const substeps = []; - rightStep.substeps.forEach(substep => { - substeps.push(Status.addRightStep(equation, substep)); - }); - let oldEquation = null; - if (rightStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.rightNode = rightStep.oldNode; - } - const newEquation = equation.clone(); - newEquation.rightNode = rightStep.newNode; - return new Status( - rightStep.changeType, oldEquation, newEquation, substeps); -}; - -Status.resetChangeGroups = function(equation) { - const leftNode = Node.Status.resetChangeGroups(equation.leftNode); - const rightNode = Node.Status.resetChangeGroups(equation.rightNode); - return new Equation(leftNode, rightNode, equation.comparator); -}; - -module.exports = Status; diff --git a/lib/equation/Status.ts b/lib/equation/Status.ts new file mode 100644 index 00000000..eb6174e7 --- /dev/null +++ b/lib/equation/Status.ts @@ -0,0 +1,70 @@ +import ChangeTypes = require('../ChangeTypes'); +import Equation = require('./Equation'); +const mathNode = require('../node'); + +// This represents the current equation we're solving. +// As we move step by step, an equation might be updated. Functions return this +// status object to pass on the updated equation and information on if/how it was +// changed. +class Status { + constructor(changeType, oldEquation, newEquation, substeps=[]) { + if (!newEquation) { + throw Error('new equation isn\'t defined'); + } + if (changeType === undefined || typeof(changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } + + this.changeType = changeType; + this.oldEquation = oldEquation; + this.newEquation = newEquation; + this.substeps = substeps; + } + + hasChanged() { + return this.changeType !== ChangeTypes.NO_CHANGE; + } +} + +// A wrapper around the Status constructor for the case where equation +// hasn't been changed. +Status.noChange = equation => new Status(ChangeTypes.NO_CHANGE, null, equation); + +Status.addLeftStep = (equation, leftStep) => { + const substeps = []; + leftStep.substeps.forEach(substep => { + substeps.push(Status.addLeftStep(equation, substep)); + }); + let oldEquation = null; + if (leftStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.leftNode = leftStep.oldNode; + } + const newEquation = equation.clone(); + newEquation.leftNode = leftStep.newNode; + return new Status( + leftStep.changeType, oldEquation, newEquation, substeps); +}; + +Status.addRightStep = (equation, rightStep) => { + const substeps = []; + rightStep.substeps.forEach(substep => { + substeps.push(Status.addRightStep(equation, substep)); + }); + let oldEquation = null; + if (rightStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.rightNode = rightStep.oldNode; + } + const newEquation = equation.clone(); + newEquation.rightNode = rightStep.newNode; + return new Status( + rightStep.changeType, oldEquation, newEquation, substeps); +}; + +Status.resetChangeGroups = equation => { + const leftNode = mathNode.Status.resetChangeGroups(equation.leftNode); + const rightNode = mathNode.Status.resetChangeGroups(equation.rightNode); + return new Equation(leftNode, rightNode, equation.comparator); +}; +export = Status; diff --git a/lib/equation/index.js b/lib/equation/index.js index 0f18d847..d6e213da 100644 --- a/lib/equation/index.js +++ b/lib/equation/index.js @@ -1,7 +1,10 @@ -const Equation = require('./Equation'); -const Status = require('./Status'); - -module.exports = { - Equation, - Status, +"use strict"; +var Equation = require("./Equation"); +var Status = require("./Status"); +var tmp; +tmp = { + Equation: Equation, + Status: Status, }; +module.exports = tmp; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/equation/index.js.map b/lib/equation/index.js.map new file mode 100644 index 00000000..42d9b0fb --- /dev/null +++ b/lib/equation/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,qCAAwC;AACxC,iCAAoC;AACpC,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,QAAQ,UAAA;IACR,MAAM,QAAA;CACT,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/equation/index.ts b/lib/equation/index.ts new file mode 100644 index 00000000..574fa000 --- /dev/null +++ b/lib/equation/index.ts @@ -0,0 +1,8 @@ +import Equation = require('./Equation'); +import Status = require('./Status'); +var tmp; +tmp = { + Equation, + Status, +}; +export = tmp; diff --git a/lib/factor/ConstantFactors.js b/lib/factor/ConstantFactors.js index ff72f287..8e1cf69b 100644 --- a/lib/factor/ConstantFactors.js +++ b/lib/factor/ConstantFactors.js @@ -1,58 +1,55 @@ // This module deals with getting constant factors, including prime factors // and factor pairs of a number - -const ConstantFactors = {}; - -// Given a number, will return all the prime factors of that number as a list -// sorted from smallest to largest -ConstantFactors.getPrimeFactors = function(number){ - let factors = []; - if (number < 0) { - factors = [-1]; - factors = factors.concat(ConstantFactors.getPrimeFactors(-1 * number)); - return factors; - } - - const root = Math.sqrt(number); - let candidate = 2; - if (number % 2) { - candidate = 3; // assign first odd - while (number % candidate && candidate <= root) { - candidate = candidate + 2; +"use strict"; +var constantFactors = (function () { + function constantFactors() { } - } - - // if no factor found then the number is prime - if (candidate > root) { - factors.push(number); - } - // if we find a factor, make a recursive call on the quotient of the number and - // our newly found prime factor in order to find more factors - else { - factors.push(candidate); - factors = factors.concat(ConstantFactors.getPrimeFactors(number/candidate)); - } - - return factors; -}; - -// Given a number, will return all the factor pairs for that number as a list -// of 2-item lists -ConstantFactors.getFactorPairs = function(number){ - const factors = []; - - const bound = Math.floor(Math.sqrt(Math.abs(number))); - for (var divisor = -bound; divisor <= bound; divisor++) { - if (divisor === 0) { - continue; - } - if (number % divisor === 0) { - const quotient = number / divisor; - factors.push([divisor, quotient]); - } - } - - return factors; -}; - -module.exports = ConstantFactors; + // Given a number, will return all the prime factors of that number as a list + // sorted from smallest to largest + constantFactors.prototype.getPrimeFactors = function (number) { + var factors = []; + if (number < 0) { + factors = [-1]; + factors = factors.concat(ConstantFactors.getPrimeFactors(-1 * number)); + return factors; + } + var root = Math.sqrt(number); + var candidate = 2; + if (number % 2) { + candidate = 3; // assign first odd + while (number % candidate && candidate <= root) { + candidate = candidate + 2; + } + } + // if no factor found then the number is prime + if (candidate > root) { + factors.push(number); + } + else { + factors.push(candidate); + factors = factors.concat(ConstantFactors.getPrimeFactors(number / candidate)); + } + return factors; + }; + ; + // Given a number, will return all the factor pairs for that number as a list + // of 2-item lists + constantFactors.prototype.getFactorPairs = function (number) { + var factors = []; + var bound = Math.floor(Math.sqrt(Math.abs(number))); + for (var divisor = -bound; divisor <= bound; divisor++) { + if (divisor === 0) { + continue; + } + if (number % divisor === 0) { + var quotient = number / divisor; + factors.push([divisor, quotient]); + } + } + return factors; + }; + ; + return constantFactors; +}()); +module.exports = constantFactors; +//# sourceMappingURL=ConstantFactors.js.map \ No newline at end of file diff --git a/lib/factor/ConstantFactors.js.map b/lib/factor/ConstantFactors.js.map new file mode 100644 index 00000000..d1edf44a --- /dev/null +++ b/lib/factor/ConstantFactors.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ConstantFactors.js","sourceRoot":"","sources":["ConstantFactors.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,+BAA+B;;AAE/B;IAAA;IAqDA,CAAC;IAnDD,6EAA6E;IAC7E,kCAAkC;IAC9B,yCAAe,GAAf,UAAgB,MAAa;QACzB,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACf,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;YACvE,MAAM,CAAC,OAAO,CAAC;QACnB,CAAC;QAED,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,SAAS,GAAG,CAAC,CAAC,CAAC,mBAAmB;YAClC,OAAO,MAAM,GAAG,SAAS,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC7C,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC;QAED,8CAA8C;QAC9C,EAAE,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAGD,IAAI,CAAC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IAEN,6EAA6E;IAC7E,kBAAkB;IACd,wCAAc,GAAd,UAAe,MAAa;QACxB,IAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,IAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YACrD,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBAChB,QAAQ,CAAC;YACb,CAAC;YACD,EAAE,CAAC,CAAC,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IACN,sBAAC;AAAD,CAAC,AArDD,IAqDC;AAED,iBAAS,eAAe,CAAC"} \ No newline at end of file diff --git a/lib/factor/ConstantFactors.ts b/lib/factor/ConstantFactors.ts new file mode 100644 index 00000000..89859223 --- /dev/null +++ b/lib/factor/ConstantFactors.ts @@ -0,0 +1,59 @@ +// This module deals with getting constant factors, including prime factors +// and factor pairs of a number + +class constantFactors { + +// Given a number, will return all the prime factors of that number as a list +// sorted from smallest to largest + getPrimeFactors(number:number) { + let factors = []; + if (number < 0) { + factors = [-1]; + factors = factors.concat(ConstantFactors.getPrimeFactors(-1 * number)); + return factors; + } + + const root = Math.sqrt(number); + let candidate = 2; + if (number % 2) { + candidate = 3; // assign first odd + while (number % candidate && candidate <= root) { + candidate = candidate + 2; + } + } + + // if no factor found then the number is prime + if (candidate > root) { + factors.push(number); + } + // if we find a factor, make a recursive call on the quotient of the number and + // our newly found prime factor in order to find more factors + else { + factors.push(candidate); + factors = factors.concat(ConstantFactors.getPrimeFactors(number / candidate)); + } + + return factors; + }; + +// Given a number, will return all the factor pairs for that number as a list +// of 2-item lists + getFactorPairs(number:number) { + const factors = []; + + const bound = Math.floor(Math.sqrt(Math.abs(number))); + for (var divisor = -bound; divisor <= bound; divisor++) { + if (divisor === 0) { + continue; + } + if (number % divisor === 0) { + const quotient = number / divisor; + factors.push([divisor, quotient]); + } + } + + return factors; + }; +} + +export = constantFactors; diff --git a/lib/factor/factorQuadratic.js b/lib/factor/factorQuadratic.ts similarity index 85% rename from lib/factor/factorQuadratic.js rename to lib/factor/factorQuadratic.ts index 0a4b60e8..f46ea762 100644 --- a/lib/factor/factorQuadratic.js +++ b/lib/factor/factorQuadratic.ts @@ -1,14 +1,11 @@ -const math = require('mathjs'); - -const ConstantFactors = require('./ConstantFactors'); - -const ChangeTypes = require('../ChangeTypes'); -const checks = require('../checks'); -const evaluate = require('../util/evaluate'); -const flatten = require('../util/flattenOperands'); -const Negative = require('../Negative'); -const Node = require('../node'); - +import math = require('mathjs'); +import ConstantFactors = require('./ConstantFactors'); +import ChangeTypes = require('../ChangeTypes'); +import checks = require('../checks'); +import evaluate = require('../util/evaluate'); +import flatten = require('../util/flattenOperands'); +import Negative = require('../Negative'); +import Node = require('../node'); const FACTOR_FUNCTIONS = [ // factor just the symbol e.g. x^2 + 2x -> x(x + 2) factorSymbol, @@ -30,6 +27,7 @@ const FACTOR_FUNCTIONS = [ // - TODO: quadratic formula // requires us simplify the following only within the parens: // a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a) +function factorQuadratic(node: any); function factorQuadratic(node) { node = flatten(node); if (!checks.isQuadratic(node)) { @@ -84,6 +82,7 @@ function factorQuadratic(node) { } // Will factor the node if it's in the form of ax^2 + bx +function factorSymbol(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { if (!bValue || cValue) { return Node.Status.noChange(node); @@ -110,7 +109,14 @@ function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { // Will factor the node if it's in the form of ax^2 - c, and the aValue // and cValue are perfect squares // e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) -function factorDifferenceOfSquares(node, symbol, aValue, bValue, cValue, negate) { +function factorDifferenceOfSquares(node: any, + symbol: any, + aValue: any, + bValue?: boolean, + cValue?: any, + negate?: any); +function factorDifferenceOfSquares(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); +function factorDifferenceOfSquares(node, symbol, aValue, bValue?, cValue?, negate?) { // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, // (iii) c is negative if (bValue || !cValue) { @@ -150,6 +156,7 @@ function factorDifferenceOfSquares(node, symbol, aValue, bValue, cValue, negate) // Will factor the node if it's in the form of ax^2 + bx + c, where a and c // are perfect squares and b = 2*sqrt(a)*sqrt(c) // e.g. x^2 + 2x + 1 -> (x + 1)^2 +function factorPerfectSquare(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) if (!bValue || !cValue) { @@ -195,6 +202,8 @@ function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { // Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by // applying the sum product rule: finding factors of c that add up to b. // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) +function factorSumProductRule(node: any, symbol: any, aValue: number, bValue: any, cValue: any, negate: any); +function factorSumProductRule(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorSumProductRule(node, symbol, aValue, bValue, cValue, negate) { if (aValue === 1 && bValue && cValue) { // try sum/product rule: find a factor pair of c that adds up to b @@ -221,5 +230,4 @@ function factorSumProductRule(node, symbol, aValue, bValue, cValue, negate) { return Node.Status.noChange(node); } - -module.exports = factorQuadratic; +export = factorQuadratic; diff --git a/lib/node/Creator.js b/lib/mathNode/Creator.ts similarity index 95% rename from lib/node/Creator.js rename to lib/mathNode/Creator.ts index 165a6863..e7d2ca06 100644 --- a/lib/node/Creator.js +++ b/lib/mathNode/Creator.ts @@ -4,9 +4,8 @@ information on nodes in mathJS */ -const math = require('mathjs'); -const NodeType = require('./Type'); - +import math = require('mathjs'); +import NodeType = require('./Type'); const NodeCreator = { operator (op, args, implicit=false) { switch (op) { @@ -73,5 +72,4 @@ const NodeCreator = { return new math.expression.node.FunctionNode(symbol, [radicandNode, rootNode]); } }; - -module.exports = NodeCreator; +export = NodeCreator; diff --git a/lib/node/PolynomialTerm.js b/lib/mathNode/PolynomialTerm.ts similarity index 83% rename from lib/node/PolynomialTerm.js rename to lib/mathNode/PolynomialTerm.ts index e5aa8919..dfd7c1d9 100644 --- a/lib/node/PolynomialTerm.js +++ b/lib/mathNode/PolynomialTerm.ts @@ -1,7 +1,6 @@ -const NodeCreator = require('./Creator'); -const NodeType = require('./Type'); - -const evaluate = require('../util/evaluate'); +import NodeCreator = require('./Creator'); +import NodeType = require('./Type'); +import evaluate = require('../util/evaluate'); // For storing polynomial terms. // Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. @@ -152,35 +151,37 @@ class PolynomialTerm { hasCoeff() { return !!this.coeff; } -} - -// Returns if the node represents an expression that can be considered a term. -// e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. -// See the tests for some more thorough examples of exactly what counts and -// what does not. -PolynomialTerm.isPolynomialTerm = function( - node, onlyImplicitMultiplication=false) { - try { - // will throw error if node isn't poly term - new PolynomialTerm(node, onlyImplicitMultiplication); - return true; - } - catch (err) { - return false; - } -}; + // Returns if the node represents an expression that can be considered a term. + // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. + // See the tests for some more thorough examples of exactly what counts and + // what does not. + isPolynomialTerm = (node, onlyImplicitMultiplication = false) => { + try { + // will throw error if node isn't poly term + new PolynomialTerm(node, onlyImplicitMultiplication); + return true; + } + catch (err) { + return false; + } + }; // Multiplies `node`, a constant or fraction of two constant nodes, by -1 // Returns a node function negativeCoefficient(node) { - if (NodeType.isConstant(node)) { - node = NodeCreator.constant(0 - parseFloat(node.value)); - } - else { - const numeratorValue = 0 - parseFloat(node.args[0].value); - node.args[0] = NodeCreator.constant(numeratorValue); - } - return node; + if (NodeType.isConstant(node)) { + node = NodeCreator.constant(0 - parseFloat(node.value)); + } + else { + const numeratorValue = 0 - parseFloat(node.args[0].value); + node.args[0] = NodeCreator.constant(numeratorValue); + } + return node; +} + exponent; + symbol; + coeff; } -module.exports = PolynomialTerm; + +export = PolynomialTerm; diff --git a/lib/mathNode/Status.ts b/lib/mathNode/Status.ts new file mode 100644 index 00000000..94ffec50 --- /dev/null +++ b/lib/mathNode/Status.ts @@ -0,0 +1,124 @@ +import clone = require('../util/clone'); +import ChangeTypes = require('../ChangeTypes'); +import Type = require('./Type'); + +// This represents the current (sub)expression we're simplifying. +// As we move step by step, a node might be updated. Functions return this +// status object to pass on the updated node and information on if/how it was +// changed. +// Status(node) creates a Status object that signals no change +class Status { + constructor(changeType, oldNode, newNode, substeps=[]) { + if (!newNode) { + throw Error('node is not defined'); + } + if (changeType === undefined || typeof(changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } + + this.changeType = changeType; + this.oldNode = oldNode; + this.newNode = newNode; + this.substeps = substeps; + } + + hasChanged() { + return this.changeType !== ChangeTypes.NO_CHANGE; + } + resetChangeGroups(node) { + node = clone(node); + node.filter(node => node.changeGroup).forEach(change => { + delete change.changeGroup; + }); + return node; + }; + // A wrapper around the Status constructor for the case where node hasn't + // been changed. + noChange(node) { + return new Status(ChangeTypes.NO_CHANGE, null, node); + }; + // A wrapper around the Status constructor for the case of a change + // that is happening at the level of oldNode + newNode + // e.g. 2 + 2 --> 4 (an addition node becomes a constant node) + Status.nodeChanged(changeType, oldNode, newNode, defaultChangeGroup = true, steps = []) { + if (defaultChangeGroup) { + oldNode.changeGroup = 1; + newNode.changeGroup = 1; + } + + return new Status(changeType, oldNode, newNode, steps); + }; + // A wrapper around the Status constructor for the case where there was + // a change that happened deeper `node`'s tree, and `node`'s children must be + // updated to have the newNode/oldNode metadata (changeGroups) + // e.g. (2 + 2) + x --> 4 + x has to update the left argument + childChanged(node, childStatus, childArgIndex = null) { + const oldNode = clone(node); + const newNode = clone(node); + let substeps = childStatus.substeps; + + if (!childStatus.oldNode) { + throw Error('Expected old node for changeType: ' + childStatus.changeType); + } + + function updateSubsteps(substeps: any, fn: any); + function updateSubsteps(substeps, fn) { + substeps.map((step) => { + step = fn(step); + step.substeps = updateSubsteps(step.substeps, fn); + }); + return substeps; + } + + if (Type.isParenthesis(node)) { + oldNode.content = childStatus.oldNode; + newNode.content = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.content = step.oldNode; + newNode.content = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else if ((Type.isOperator(node) || Type.isFunction(node) && + childArgIndex !== null)) { + oldNode.args[childArgIndex] = childStatus.oldNode; + newNode.args[childArgIndex] = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.args[childArgIndex] = step.oldNode; + newNode.args[childArgIndex] = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else if (Type.isUnaryMinus(node)) { + oldNode.args[0] = childStatus.oldNode; + newNode.args[0] = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.args[0] = step.oldNode; + newNode.args[0] = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else { + throw Error('Unexpected node type: ' + node.type); + } + + return new Status(childStatus.changeType, oldNode, newNode, substeps); + }; + changeType; + oldNode; + newNode; + substeps; +} +export = Status; diff --git a/lib/mathNode/Type.ts b/lib/mathNode/Type.ts new file mode 100644 index 00000000..0de6673e --- /dev/null +++ b/lib/mathNode/Type.ts @@ -0,0 +1,90 @@ +/* + For determining the type of a mathJS node. + */ + +class NodeType { + static isOperator (node, operator = null) { + return node.type === 'OperatorNode' && + node.fn !== 'unaryMinus' && + ('*+-/^'.lastIndexOf(node.op) !== -1) && + (operator ? node.op === operator : true); + }; + static isParenthesis(node) { + return node.type === 'ParenthesisNode'; + }; + static isUnaryMinus(node) { + return node.type === 'OperatorNode' && node.fn === 'unaryMinus'; + }; + static isFunction(node, functionName = null) { + if (node.type !== 'FunctionNode') { + return false; + } + if (functionName && node.fn.name !== functionName) { + return false; + } + return true; + }; + isSymbol(node, allowUnaryMinus = true) { + if (node.type === 'SymbolNode') { + return true; + } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + return NodeType.isSymbol(node.args[0], false); + } + else { + return false; + } + }; + static isConstant(node, allowUnaryMinus = false) { + if (node.type === 'ConstantNode') { + return true; + } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + if (NodeType.isConstant(node.args[0], false)) { + const value = parseFloat(node.args[0].value); + return value >= 0; + } + else { + return false; + } + } + else { + return false; + } + }; + static isConstantFraction(node, allowUnaryMinus = false) { + if (NodeType.isOperator(node, '/')) { + return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); + } + else { + return false; + } + }; + isConstantOrConstantFraction(node, allowUnaryMinus = false) { + if (NodeType.isConstant(node, allowUnaryMinus) || + NodeType.isConstantFraction(node, allowUnaryMinus)) { + return true; + } + else { + return false; + } + }; + isIntegerFraction(node, allowUnaryMinus = false) { + if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { + return false; + } + let [numerator, denominator] = node.args; + if (allowUnaryMinus) { + if (NodeType.isUnaryMinus(numerator)) { + numerator = numerator.args[0]; + } + if (NodeType.isUnaryMinus(denominator)) { + denominator = denominator.args[0]; + } + } + return ((parseFloat(numerator.value)% 1 ===0) && + (parseFloat(denominator.value)%1 === 0)); + }; +} + +export = NodeType; diff --git a/lib/mathNode/index.js b/lib/mathNode/index.js new file mode 100644 index 00000000..f37372df --- /dev/null +++ b/lib/mathNode/index.js @@ -0,0 +1,14 @@ +"use strict"; +var Creator = require("./Creator"); +var PolynomialTerm = require("./PolynomialTerm"); +var Status = require("./Status"); +var Type = require("./Type"); +var tmp; +tmp = { + Creator: Creator, + PolynomialTerm: PolynomialTerm, + Status: Status, + Type: Type +}; +module.exports = tmp; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/mathNode/index.js.map b/lib/mathNode/index.js.map new file mode 100644 index 00000000..dbeaf38c --- /dev/null +++ b/lib/mathNode/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,mCAAsC;AACtC,iDAAoD;AACpD,iCAAoC;AACpC,6BAAgC;AAChC,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,OAAO,SAAA;IACP,cAAc,gBAAA;IACd,MAAM,QAAA;IACN,IAAI,MAAA;CACP,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/mathNode/index.ts b/lib/mathNode/index.ts new file mode 100644 index 00000000..c0cc8281 --- /dev/null +++ b/lib/mathNode/index.ts @@ -0,0 +1,12 @@ +import Creator = require('./Creator'); +import PolynomialTerm = require('./PolynomialTerm'); +import Status = require('./Status'); +import Type = require('./Type'); +var tmp; +tmp = { + Creator, + PolynomialTerm, + Status, + Type +}; +export = tmp; diff --git a/lib/node/Status.js b/lib/node/Status.js deleted file mode 100644 index cc4440e5..00000000 --- a/lib/node/Status.js +++ /dev/null @@ -1,126 +0,0 @@ -const clone = require('../util/clone'); - -const ChangeTypes = require('../ChangeTypes'); -const Type = require('./Type'); - -// This represents the current (sub)expression we're simplifying. -// As we move step by step, a node might be updated. Functions return this -// status object to pass on the updated node and information on if/how it was -// changed. -// Status(node) creates a Status object that signals no change -class Status { - constructor(changeType, oldNode, newNode, substeps=[]) { - if (!newNode) { - throw Error('node is not defined'); - } - if (changeType === undefined || typeof(changeType) !== 'string') { - throw Error('changetype isn\'t valid'); - } - - this.changeType = changeType; - this.oldNode = oldNode; - this.newNode = newNode; - this.substeps = substeps; - } - - hasChanged() { - return this.changeType !== ChangeTypes.NO_CHANGE; - } -} - -Status.resetChangeGroups = function(node) { - node = clone(node); - node.filter(node => node.changeGroup).forEach(change => { - delete change.changeGroup; - }); - return node; -}; - -// A wrapper around the Status constructor for the case where node hasn't -// been changed. -Status.noChange = function(node) { - return new Status(ChangeTypes.NO_CHANGE, null, node); -}; - -// A wrapper around the Status constructor for the case of a change -// that is happening at the level of oldNode + newNode -// e.g. 2 + 2 --> 4 (an addition node becomes a constant node) -Status.nodeChanged = function( - changeType, oldNode, newNode, defaultChangeGroup=true, steps=[]) { - if (defaultChangeGroup) { - oldNode.changeGroup = 1; - newNode.changeGroup = 1; - } - - return new Status(changeType, oldNode, newNode, steps); -}; - -// A wrapper around the Status constructor for the case where there was -// a change that happened deeper `node`'s tree, and `node`'s children must be -// updated to have the newNode/oldNode metadata (changeGroups) -// e.g. (2 + 2) + x --> 4 + x has to update the left argument -Status.childChanged = function(node, childStatus, childArgIndex=null) { - const oldNode = clone(node); - const newNode = clone(node); - let substeps = childStatus.substeps; - - if (!childStatus.oldNode) { - throw Error ('Expected old node for changeType: ' + childStatus.changeType); - } - - function updateSubsteps(substeps, fn) { - substeps.map((step) => { - step = fn(step); - step.substeps = updateSubsteps(step.substeps, fn); - }); - return substeps; - } - - if (Type.isParenthesis(node)) { - oldNode.content = childStatus.oldNode; - newNode.content = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.content = step.oldNode; - newNode.content = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else if ((Type.isOperator(node) || Type.isFunction(node) && - childArgIndex !== null)) { - oldNode.args[childArgIndex] = childStatus.oldNode; - newNode.args[childArgIndex] = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.args[childArgIndex] = step.oldNode; - newNode.args[childArgIndex] = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else if (Type.isUnaryMinus(node)) { - oldNode.args[0] = childStatus.oldNode; - newNode.args[0] = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.args[0] = step.oldNode; - newNode.args[0] = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else { - throw Error('Unexpected node type: ' + node.type); - } - - return new Status(childStatus.changeType, oldNode, newNode, substeps); -}; - -module.exports = Status; diff --git a/lib/node/Type.js b/lib/node/Type.js deleted file mode 100644 index 97f7406e..00000000 --- a/lib/node/Type.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - For determining the type of a mathJS node. - */ - -const NodeType = {}; - -NodeType.isOperator = function(node, operator=null) { - return node.type === 'OperatorNode' && - node.fn !== 'unaryMinus' && - '*+-/^'.includes(node.op) && - (operator ? node.op === operator : true); -}; - -NodeType.isParenthesis = function(node) { - return node.type === 'ParenthesisNode'; -}; - -NodeType.isUnaryMinus = function(node) { - return node.type === 'OperatorNode' && node.fn === 'unaryMinus'; -}; - -NodeType.isFunction = function(node, functionName=null) { - if (node.type !== 'FunctionNode') { - return false; - } - if (functionName && node.fn.name !== functionName) { - return false; - } - return true; -}; - -NodeType.isSymbol = function(node, allowUnaryMinus=true) { - if (node.type === 'SymbolNode') { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - return NodeType.isSymbol(node.args[0], false); - } - else { - return false; - } -}; - -NodeType.isConstant = function(node, allowUnaryMinus=false) { - if (node.type === 'ConstantNode') { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - if (NodeType.isConstant(node.args[0], false)) { - const value = parseFloat(node.args[0].value); - return value >= 0; - } - else { - return false; - } - } - else { - return false; - } -}; - -NodeType.isConstantFraction = function(node, allowUnaryMinus=false) { - if (NodeType.isOperator(node, '/')) { - return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); - } - else { - return false; - } -}; - -NodeType.isConstantOrConstantFraction = function(node, allowUnaryMinus=false) { - if (NodeType.isConstant(node, allowUnaryMinus) || - NodeType.isConstantFraction(node, allowUnaryMinus)) { - return true; - } - else { - return false; - } -}; - -NodeType.isIntegerFraction = function(node, allowUnaryMinus=false) { - if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { - return false; - } - let numerator = node.args[0]; - let denominator = node.args[1]; - if (allowUnaryMinus) { - if (NodeType.isUnaryMinus(numerator)) { - numerator = numerator.args[0]; - } - if (NodeType.isUnaryMinus(denominator)) { - denominator = denominator.args[0]; - } - } - return (Number.isInteger(parseFloat(numerator.value)) && - Number.isInteger(parseFloat(denominator.value))); -}; - - -module.exports = NodeType; diff --git a/lib/node/index.js b/lib/node/index.js deleted file mode 100644 index c40c0797..00000000 --- a/lib/node/index.js +++ /dev/null @@ -1,11 +0,0 @@ -const Creator = require('./Creator'); -const PolynomialTerm = require('./PolynomialTerm'); -const Status = require('./Status'); -const Type = require('./Type'); - -module.exports = { - Creator, - PolynomialTerm, - Status, - Type, -}; diff --git a/lib/simplifyExpression/arithmeticSearch/index.js b/lib/simplifyExpression/arithmeticSearch/index.ts similarity index 54% rename from lib/simplifyExpression/arithmeticSearch/index.js rename to lib/simplifyExpression/arithmeticSearch/index.ts index b84c7f8f..d6ee12ee 100644 --- a/lib/simplifyExpression/arithmeticSearch/index.js +++ b/lib/simplifyExpression/arithmeticSearch/index.ts @@ -1,52 +1,54 @@ -const ChangeTypes = require('../../ChangeTypes'); -const evaluate = require('../../util/evaluate'); -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require('../../ChangeTypes'); +import evaluate = require('../../util/evaluate'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); // Searches through the tree, prioritizing deeper nodes, and evaluates // arithmetic (e.g. 2+2 or 3*5*2) on an operation node if possible. -// Returns a Node.Status object. +// Returns a mathNode.Status object. const search = TreeSearch.postOrder(arithmetic); // evaluates arithmetic (e.g. 2+2 or 3*5*2) on an operation node. -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function arithmetic(node: any); function arithmetic(node) { - if (!Node.Type.isOperator(node)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node)) { + return mathNode.Status.noChange(node); } - if (!node.args.every(child => Node.Type.isConstant(child, true))) { - return Node.Status.noChange(node); + if (!node.args.every(child => mathNode.Type.isConstant(child, true))) { + return mathNode.Status.noChange(node); } // we want to eval each arg so unary minuses around constant nodes become // constant nodes with negative values node.args.forEach((arg, i) => { - node.args[i] = Node.Creator.constant(evaluate(arg)); + node.args[i] = mathNode.Creator.constant(evaluate(arg)); }); // Only resolve division of integers if we get an integer result. // Note that a fraction of decimals will be divided out. - if (Node.Type.isIntegerFraction(node)) { + if (mathNode.Type.isIntegerFraction(node)) { const numeratorValue = parseInt(node.args[0]); const denominatorValue = parseInt(node.args[1]); if (numeratorValue % denominatorValue === 0) { - const newNode = Node.Creator.constant(numeratorValue/denominatorValue); - return Node.Status.nodeChanged( + const newNode = mathNode.Creator.constant(numeratorValue/denominatorValue); + return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } else { const evaluatedValue = evaluateAndRound(node); - const newNode = Node.Creator.constant(evaluatedValue); - return Node.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); + const newNode = mathNode.Creator.constant(evaluatedValue); + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); } } // Evaluates a math expression to a constant, e.g. 3+4 -> 7 and rounds if // necessary +function evaluateAndRound(node: any); function evaluateAndRound(node) { let result = evaluate(node); if (result < 1) { @@ -58,4 +60,4 @@ function evaluateAndRound(node) { return result; } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/basicsSearch/index.js b/lib/simplifyExpression/basicsSearch/index.ts similarity index 56% rename from lib/simplifyExpression/basicsSearch/index.js rename to lib/simplifyExpression/basicsSearch/index.ts index d524cc68..86f94ba3 100644 --- a/lib/simplifyExpression/basicsSearch/index.js +++ b/lib/simplifyExpression/basicsSearch/index.ts @@ -3,21 +3,19 @@ * These are always the first simplifications that are attempted. */ -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); - -const rearrangeCoefficient = require('./rearrangeCoefficient'); -const reduceExponentByZero = require('./reduceExponentByZero'); -const reduceMultiplicationByZero = require('./reduceMultiplicationByZero'); -const reduceZeroDividedByAnything = require('./reduceZeroDividedByAnything'); -const removeAdditionOfZero = require('./removeAdditionOfZero'); -const removeDivisionByOne = require('./removeDivisionByOne'); -const removeExponentBaseOne = require('./removeExponentBaseOne'); -const removeExponentByOne = require('./removeExponentByOne'); -const removeMultiplicationByNegativeOne = require('./removeMultiplicationByNegativeOne'); -const removeMultiplicationByOne = require('./removeMultiplicationByOne'); -const simplifyDoubleUnaryMinus = require('./simplifyDoubleUnaryMinus'); - +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); +import rearrangeCoefficient = require('./rearrangeCoefficient'); +import reduceExponentByZero = require('./reduceExponentByZero'); +import reduceMultiplicationByZero = require('./reduceMultiplicationByZero'); +import reduceZeroDividedByAnything = require('./reduceZeroDividedByAnything'); +import removeAdditionOfZero = require('./removeAdditionOfZero'); +import removeDivisionByOne = require('./removeDivisionByOne'); +import removeExponentBaseOne = require('./removeExponentBaseOne'); +import removeExponentByOne = require('./removeExponentByOne'); +import removeMultiplicationByNegativeOne = require('./removeMultiplicationByNegativeOne'); +import removeMultiplicationByOne = require('./removeMultiplicationByOne'); +import simplifyDoubleUnaryMinus = require('./simplifyDoubleUnaryMinus'); const SIMPLIFICATION_FUNCTIONS = [ // multiplication by 0 yields 0 reduceMultiplicationByZero, @@ -46,7 +44,8 @@ const SIMPLIFICATION_FUNCTIONS = [ const search = TreeSearch.preOrder(basics); -// Look for basic step(s) to perform on a node. Returns a Node.Status object. +// Look for basic step(s) to perform on a node. Returns a mathNode.Status object. +function basics(node: any); function basics(node) { for (let i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) { const nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node); @@ -57,7 +56,7 @@ function basics(node) { node = nodeStatus.newNode; } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js deleted file mode 100644 index 03c148a9..00000000 --- a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js +++ /dev/null @@ -1,27 +0,0 @@ -const checks = require('../../checks'); -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// Rearranges something of the form x * 5 to be 5x, ie putting the coefficient -// in the right place. -// Returns a Node.Status object -function rearrangeCoefficient(node) { - if (!checks.canRearrangeCoefficient(node)) { - return Node.Status.noChange(node); - } - - let newNode = clone(node); - - const polyNode = new Node.PolynomialTerm(newNode.args[0]); - const constNode = newNode.args[1]; - const exponentNode = polyNode.getExponentNode(); - newNode = Node.Creator.polynomialTerm( - polyNode.getSymbolNode(), exponentNode, constNode); - - return Node.Status.nodeChanged( - ChangeTypes.REARRANGE_COEFF, node, newNode); -} - -module.exports = rearrangeCoefficient; diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts new file mode 100644 index 00000000..5d1d9b18 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts @@ -0,0 +1,27 @@ +import checks = require('../../checks'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// Rearranges something of the form x * 5 to be 5x, ie putting the coefficient +// in the right place. +// Returns a mathNode.Status object +function rearrangeCoefficient(node: any); +function rearrangeCoefficient(node) { + if (!checks.canRearrangeCoefficient(node)) { + return mathNode.Status.noChange(node); + } + + let newNode = clone(node); + + const polyNode = new mathNode.PolynomialTerm(newNode.args[0]); + const constNode = newNode.args[1]; + const exponentNode = polyNode.getExponentNode(); + newNode = mathNode.Creator.polynomialTerm( + polyNode.getSymbolNode(), exponentNode, constNode); + + return mathNode.Status.nodeChanged( + ChangeTypes.REARRANGE_COEFF, node, newNode); +} + +export = rearrangeCoefficient; diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js deleted file mode 100644 index c24d43c6..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js +++ /dev/null @@ -1,21 +0,0 @@ -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// If `node` is an exponent of something to 0, we can reduce that to just 1. -// Returns a Node.Status object. -function reduceExponentByZero(node) { - if (node.op !== '^') { - return Node.Status.noChange(node); - } - const exponent = node.args[1]; - if (Node.Type.isConstant(exponent) && exponent.value === '0') { - const newNode = Node.Creator.constant(1); - return Node.Status.nodeChanged( - ChangeTypes.REDUCE_EXPONENT_BY_ZERO, node, newNode); - } - else { - return Node.Status.noChange(node); - } -} - -module.exports = reduceExponentByZero; diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts new file mode 100644 index 00000000..b8e4025f --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts @@ -0,0 +1,22 @@ +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// If `node` is an exponent of something to 0, we can reduce that to just 1. +// Returns a mathNode.Status object. +function reduceExponentByZero(node: any); +function reduceExponentByZero(node) { + if (node.op !== '^') { + return mathNode.Status.noChange(node); + } + const exponent = node.args[1]; + if (mathNode.Type.isConstant(exponent) && exponent.value === '0') { + const newNode = mathNode.Creator.constant(1); + return mathNode.Status.nodeChanged( + ChangeTypes.REDUCE_EXPONENT_BY_ZERO, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} + +export = reduceExponentByZero; diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js deleted file mode 100644 index b9bc4d57..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js +++ /dev/null @@ -1,31 +0,0 @@ -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// If `node` is a multiplication node with 0 as one of its operands, -// reduce the node to 0. Returns a Node.Status object. -function reduceMultiplicationByZero(node) { - if (node.op !== '*') { - return Node.Status.noChange(node); - } - const zeroIndex = node.args.findIndex(arg => { - if (Node.Type.isConstant(arg) && arg.value === '0') { - return true; - } - if (Node.PolynomialTerm.isPolynomialTerm(arg)) { - const polyTerm = new Node.PolynomialTerm(arg); - return polyTerm.getCoeffValue() === 0; - } - return false; - }); - if (zeroIndex >= 0) { - // reduce to just the 0 node - const newNode = Node.Creator.constant(0); - return Node.Status.nodeChanged( - ChangeTypes.MULTIPLY_BY_ZERO, node, newNode); - } - else { - return Node.Status.noChange(node); - } -} - -module.exports = reduceMultiplicationByZero; diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts new file mode 100644 index 00000000..76494c1f --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts @@ -0,0 +1,32 @@ +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// If `node` is a multiplication node with 0 as one of its operands, +// reduce the node to 0. Returns a mathNode.Status object. +function reduceMultiplicationByZero(node: any); +function reduceMultiplicationByZero(node) { + if (node.op !== '*') { + return mathNode.Status.noChange(node); + } + const zeroIndex = node.args.findIndex(arg => { + if (mathNode.Type.isConstant(arg) && arg.value === '0') { + return true; + } + if (mathNode.PolynomialTerm.isPolynomialTerm(arg)) { + const polyTerm = new mathNode.PolynomialTerm(arg); + return polyTerm.getCoeffValue() === 0; + } + return false; + }); + if (zeroIndex >= 0) { + // reduce to just the 0 node + const newNode = mathNode.Creator.constant(0); + return mathNode.Status.nodeChanged( + ChangeTypes.MULTIPLY_BY_ZERO, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} + +export = reduceMultiplicationByZero; diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js deleted file mode 100644 index b6c4aed3..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js +++ /dev/null @@ -1,20 +0,0 @@ -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// If `node` is a fraction with 0 as the numerator, reduce the node to 0. -// Returns a Node.Status object. -function reduceZeroDividedByAnything(node) { - if (node.op !== '/') { - return Node.Status.noChange(node); - } - if (node.args[0].value === '0') { - const newNode = Node.Creator.constant(0); - return Node.Status.nodeChanged( - ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); - } - else { - return Node.Status.noChange(node); - } -} - -module.exports = reduceZeroDividedByAnything; diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts new file mode 100644 index 00000000..e56f546d --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts @@ -0,0 +1,21 @@ +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// If `node` is a fraction with 0 as the numerator, reduce the node to 0. +// Returns a mathNode.Status object. +function reduceZeroDividedByAnything(node: any); +function reduceZeroDividedByAnything(node) { + if (node.op !== '/') { + return mathNode.Status.noChange(node); + } + if (node.args[0].value === '0') { + const newNode = mathNode.Creator.constant(0); + return mathNode.Status.nodeChanged( + ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} + +export = reduceZeroDividedByAnything; diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts similarity index 54% rename from lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js rename to lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts index 696c360b..6ecb2957 100644 --- a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js +++ b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts @@ -1,16 +1,16 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); // If `node` is an addition node with 0 as one of its operands, -// remove 0 from the operands list. Returns a Node.Status object. +// remove 0 from the operands list. Returns a mathNode.Status object. +function removeAdditionOfZero(node: any); function removeAdditionOfZero(node) { if (node.op !== '+') { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const zeroIndex = node.args.findIndex(arg => { - return Node.Type.isConstant(arg) && arg.value === '0'; + return mathNode.Type.isConstant(arg) && arg.value === '0'; }); let newNode = clone(node); if (zeroIndex >= 0) { @@ -21,10 +21,10 @@ function removeAdditionOfZero(node) { if (newNode.args.length === 1) { newNode = newNode.args[0]; } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.REMOVE_ADDING_ZERO, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } -module.exports = removeAdditionOfZero; +export = removeAdditionOfZero; diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts similarity index 52% rename from lib/simplifyExpression/basicsSearch/removeDivisionByOne.js rename to lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts index 3cef9349..3be1b1d8 100644 --- a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js +++ b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts @@ -1,18 +1,18 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Negative = require('../../Negative'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +import Negative = require('../../Negative'); +const mathNode = require('../../node'); // If `node` is a division operation of something by 1 or -1, we can remove the -// denominator. Returns a Node.Status object. +// denominator. Returns a mathNode.Status object. +function removeDivisionByOne(node: any); function removeDivisionByOne(node) { if (node.op !== '/') { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const denominator = node.args[1]; - if (!Node.Type.isConstant(denominator)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isConstant(denominator)) { + return mathNode.Status.noChange(node); } let numerator = clone(node.args[0]); @@ -21,22 +21,22 @@ function removeDivisionByOne(node) { // If the numerator was an operation, wrap it in parens before adding - // to the front. // e.g. 2+3 / -1 ---> -(2+3) - if (Node.Type.isOperator(numerator)) { - numerator = Node.Creator.parenthesis(numerator); + if (mathNode.Type.isOperator(numerator)) { + numerator = mathNode.Creator.parenthesis(numerator); } const changeType = Negative.isNegative(numerator) ? ChangeTypes.RESOLVE_DOUBLE_MINUS : ChangeTypes.DIVISION_BY_NEGATIVE_ONE; numerator = Negative.negate(numerator); - return Node.Status.nodeChanged(changeType, node, numerator); + return mathNode.Status.nodeChanged(changeType, node, numerator); } else if (parseFloat(denominator.value) === 1) { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.DIVISION_BY_ONE, node, numerator); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } -module.exports = removeDivisionByOne; +export = removeDivisionByOne; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js deleted file mode 100644 index e93595f2..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js +++ /dev/null @@ -1,21 +0,0 @@ -const checks = require('../../checks'); -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// If `node` is of the form 1^x, reduces it to a node of the form 1. -// Returns a Node.Status object. -function removeExponentBaseOne(node) { - if (node.op === '^' && // an exponent with - checks.resolvesToConstant(node.args[1]) && // a power not a symbol and - Node.Type.isConstant(node.args[0]) && // a constant base - node.args[0].value === '1') { // of value 1 - const newNode = clone(node.args[0]); - return Node.Status.nodeChanged( - ChangeTypes.REMOVE_EXPONENT_BASE_ONE, node, newNode); - } - return Node.Status.noChange(node); -} - -module.exports = removeExponentBaseOne; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts new file mode 100644 index 00000000..1d998d73 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts @@ -0,0 +1,21 @@ +import checks = require('../../checks'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// If `node` is of the form 1^x, reduces it to a node of the form 1. +// Returns a mathNode.Status object. +function removeExponentBaseOne(node: any); +function removeExponentBaseOne(node) { + if (node.op === '^' && // an exponent with + checks.resolvesToConstant(node.args[1]) && // a power not a symbol and + mathNode.Type.isConstant(node.args[0]) && // a constant base + node.args[0].value === '1') { // of value 1 + const newNode = clone(node.args[0]); + return mathNode.Status.nodeChanged( + ChangeTypes.REMOVE_EXPONENT_BASE_ONE, node, newNode); + } + return mathNode.Status.noChange(node); +} + +export = removeExponentBaseOne; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js deleted file mode 100644 index 85a0400e..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js +++ /dev/null @@ -1,19 +0,0 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// If `node` is of the form x^1, reduces it to a node of the form x. -// Returns a Node.Status object. -function removeExponentByOne(node) { - if (node.op === '^' && // exponent of anything - Node.Type.isConstant(node.args[1]) && // to a constant - node.args[1].value === '1') { // of value 1 - const newNode = clone(node.args[0]); - return Node.Status.nodeChanged( - ChangeTypes.REMOVE_EXPONENT_BY_ONE, node, newNode); - } - return Node.Status.noChange(node); -} - -module.exports = removeExponentByOne; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts new file mode 100644 index 00000000..a10ff3fb --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts @@ -0,0 +1,19 @@ +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// If `node` is of the form x^1, reduces it to a node of the form x. +// Returns a mathNode.Status object. +function removeExponentByOne(node: any); +function removeExponentByOne(node) { + if (node.op === '^' && // exponent of anything + mathNode.Type.isConstant(node.args[1]) && // to a constant + node.args[1].value === '1') { // of value 1 + const newNode = clone(node.args[0]); + return mathNode.Status.nodeChanged( + ChangeTypes.REMOVE_EXPONENT_BY_ONE, node, newNode); + } + return mathNode.Status.noChange(node); +} + +export = removeExponentByOne; diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts similarity index 69% rename from lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js rename to lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts index 20d9df99..79d01ac5 100644 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts @@ -1,22 +1,22 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Negative = require('../../Negative'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +import Negative = require('../../Negative'); +const mathNode = require('../../node'); // If `node` is a multiplication node with -1 as one of its operands, // and a non constant as the next operand, remove -1 from the operands // list and make the next term have a unary minus. -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function removeMultiplicationByNegativeOne(node: any); function removeMultiplicationByNegativeOne(node) { if (node.op !== '*') { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const minusOneIndex = node.args.findIndex(arg => { - return Node.Type.isConstant(arg) && arg.value === '-1'; + return mathNode.Type.isConstant(arg) && arg.value === '-1'; }); if (minusOneIndex < 0) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // We might merge/combine the negative one into another node. This stores @@ -32,8 +32,8 @@ function removeMultiplicationByNegativeOne(node) { let nodeToCombine = node.args[nodeToCombineIndex]; // If it's a constant, the combining of those terms is handled elsewhere. - if (Node.Type.isConstant(nodeToCombine)) { - return Node.Status.noChange(node); + if (mathNode.Type.isConstant(nodeToCombine)) { + return mathNode.Status.noChange(node); } let newNode = clone(node); @@ -49,8 +49,8 @@ function removeMultiplicationByNegativeOne(node) { if (newNode.args.length === 1) { newNode = newNode.args[0]; } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.REMOVE_MULTIPLYING_BY_NEGATIVE_ONE, node, newNode); } -module.exports = removeMultiplicationByNegativeOne; +export = removeMultiplicationByNegativeOne; diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts similarity index 54% rename from lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js rename to lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts index be05c435..e04b7401 100644 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts @@ -1,16 +1,16 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); // If `node` is a multiplication node with 1 as one of its operands, -// remove 1 from the operands list. Returns a Node.Status object. +// remove 1 from the operands list. Returns a mathNode.Status object. +function removeMultiplicationByOne(node: any); function removeMultiplicationByOne(node) { if (node.op !== '*') { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const oneIndex = node.args.findIndex(arg => { - return Node.Type.isConstant(arg) && arg.value === '1'; + return mathNode.Type.isConstant(arg) && arg.value === '1'; }); if (oneIndex >= 0) { let newNode = clone(node); @@ -21,10 +21,10 @@ function removeMultiplicationByOne(node) { if (newNode.args.length === 1) { newNode = newNode.args[0]; } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.REMOVE_MULTIPLYING_BY_ONE, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } -module.exports = removeMultiplicationByOne; +export = removeMultiplicationByOne; diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js deleted file mode 100644 index 749d050a..00000000 --- a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js +++ /dev/null @@ -1,38 +0,0 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// Simplifies two unary minuses in a row by removing both of them. -// e.g. -(- 4) --> 4 -function simplifyDoubleUnaryMinus(node) { - if (!Node.Type.isUnaryMinus(node)) { - return Node.Status.noChange(node); - } - const unaryArg = node.args[0]; - // e.g. in - -x, -x is the unary arg, and we'd want to reduce to just x - if (Node.Type.isUnaryMinus(unaryArg)) { - const newNode = clone(unaryArg.args[0]); - return Node.Status.nodeChanged( - ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - // e.g. - -4, -4 could be a constant with negative value - else if (Node.Type.isConstant(unaryArg) && parseFloat(unaryArg.value) < 0) { - const newNode = Node.Creator.constant(parseFloat(unaryArg.value) * -1); - return Node.Status.nodeChanged( - ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - // e.g. -(-(5+2)) - else if (Node.Type.isParenthesis(unaryArg)) { - const parenthesisNode = unaryArg; - const parenthesisContent = parenthesisNode.content; - if (Node.Type.isUnaryMinus(parenthesisContent)) { - const newNode = Node.Creator.parenthesis(parenthesisContent.args[0]); - return Node.Status.nodeChanged( - ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - } - return Node.Status.noChange(node); -} - -module.exports = simplifyDoubleUnaryMinus; diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts new file mode 100644 index 00000000..ac02104c --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts @@ -0,0 +1,38 @@ +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); + +// Simplifies two unary minuses in a row by removing both of them. +// e.g. -(- 4) --> 4 +function simplifyDoubleUnaryMinus(node: any); +function simplifyDoubleUnaryMinus(node) { + if (!mathNode.Type.isUnaryMinus(node)) { + return mathNode.Status.noChange(node); + } + const unaryArg = node.args[0]; + // e.g. in - -x, -x is the unary arg, and we'd want to reduce to just x + if (mathNode.Type.isUnaryMinus(unaryArg)) { + const newNode = clone(unaryArg.args[0]); + return mathNode.Status.nodeChanged( + ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); + } + // e.g. - -4, -4 could be a constant with negative value + else if (mathNode.Type.isConstant(unaryArg) && parseFloat(unaryArg.value) < 0) { + const newNode = mathNode.Creator.constant(parseFloat(unaryArg.value) * -1); + return mathNode.Status.nodeChanged( + ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); + } + // e.g. -(-(5+2)) + else if (mathNode.Type.isParenthesis(unaryArg)) { + const parenthesisNode = unaryArg; + const parenthesisContent = parenthesisNode.content; + if (mathNode.Type.isUnaryMinus(parenthesisContent)) { + const newNode = mathNode.Creator.parenthesis(parenthesisContent.args[0]); + return mathNode.Status.nodeChanged( + ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); + } + } + return mathNode.Status.noChange(node); +} + +export = simplifyDoubleUnaryMinus; diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.js b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts similarity index 57% rename from lib/simplifyExpression/breakUpNumeratorSearch/index.js rename to lib/simplifyExpression/breakUpNumeratorSearch/index.ts index 2dcff7a2..7b2ff84f 100644 --- a/lib/simplifyExpression/breakUpNumeratorSearch/index.js +++ b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts @@ -1,27 +1,28 @@ -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); // Breaks up any fraction (deeper nodes getting priority) that has a numerator // that is a sum. e.g. (2+x)/5 -> (2/5 + x/5) // This step must happen after things have been collected and combined, or // else things will infinite loop, so it's a tree search of its own. -// Returns a Node.Status object +// Returns a mathNode.Status object const search = TreeSearch.postOrder(breakUpNumerator); // If `node` is a fraction with a numerator that is a sum, breaks up the // fraction e.g. (2+x)/5 -> (2/5 + x/5) -// Returns a Node.Status object +// Returns a mathNode.Status object +function breakUpNumerator(node: any); function breakUpNumerator(node) { - if (!Node.Type.isOperator(node) || node.op !== '/') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '/') { + return mathNode.Status.noChange(node); } let numerator = node.args[0]; - if (Node.Type.isParenthesis(numerator)) { + if (mathNode.Type.isParenthesis(numerator)) { numerator = numerator.content; } - if (!Node.Type.isOperator(numerator) || numerator.op !== '+') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(numerator) || numerator.op !== '+') { + return mathNode.Status.noChange(node); } // At this point, we know that node is a fraction and its numerator is a sum @@ -29,17 +30,17 @@ function breakUpNumerator(node) { const fractionList = []; const denominator = node.args[1]; numerator.args.forEach(arg => { - const newFraction = Node.Creator.operator('/', [arg, denominator]); + const newFraction = mathNode.Creator.operator('/', [arg, denominator]); newFraction.changeGroup = 1; fractionList.push(newFraction); }); - let newNode = Node.Creator.operator('+', fractionList); + let newNode = mathNode.Creator.operator('+', fractionList); // Wrap in parens for cases like 2*(2+3)/5 => 2*(2/5 + 3/5) - newNode = Node.Creator.parenthesis(newNode); + newNode = mathNode.Creator.parenthesis(newNode); node.changeGroup = 1; - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.BREAK_UP_FRACTION, node, newNode, false); } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts similarity index 50% rename from lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js rename to lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts index e9ec462f..5f7b9575 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js +++ b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts @@ -1,10 +1,8 @@ -const clone = require('../../util/clone'); -const print = require('../../util/print'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); -const Util = require('../../util/Util'); - +import clone = require('../../util/clone'); +import print = require('../../util/print'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); +import Util = require('../../util/Util'); const CONSTANT = 'constant'; const CONSTANT_FRACTION = 'constantFraction'; const OTHER = 'other'; @@ -13,115 +11,117 @@ const LikeTermCollector = {}; // Given an expression tree, returns true if there are terms that can be // collected -LikeTermCollector.canCollectLikeTerms = function(node) { - // We can collect like terms through + or through * - // Note that we never collect like terms with - or /, those expressions will - // always be manipulated in flattenOperands so that the top level operation is - // + or *. - if (!(Node.Type.isOperator(node, '+') || Node.Type.isOperator(node, '*'))) { - return false; - } +LikeTermCollector.canCollectLikeTerms = node => { + // We can collect like terms through + or through * + // Note that we never collect like terms with - or /, those expressions will + // always be manipulated in flattenOperands so that the top level operation is + // + or *. + if (!(mathNode.Type.isOperator(node, '+') || mathNode.Type.isOperator(node, '*'))) { + return false; + } - let terms; - if (node.op === '+') { - terms = getTermsForCollectingAddition(node); - } - else if (node.op === '*') { - terms = getTermsForCollectingMultiplication(node); - } - else { - throw Error('Operation not supported: ' + node.op); - } + let terms; + if (node.op === '+') { + terms = getTermsForCollectingAddition(node); + } + else if (node.op === '*') { + terms = getTermsForCollectingMultiplication(node); + } + else { + throw Error('Operation not supported: ' + node.op); + } - // Conditions we need to meet to decide to to reorganize (collect) the terms: - // - more than 1 term type - // - more than 1 of at least one type (not including other) - // (note that this means x^2 + x + x + 2 -> x^2 + (x + x) + 2, - // which will be recorded as a step, but doesn't change the order of terms) - const termTypes = Object.keys(terms); - const filteredTermTypes = termTypes.filter(x => x !== OTHER); - return (termTypes.length > 1 && - filteredTermTypes.some(x => terms[x].length > 1)); + // Conditions we need to meet to decide to to reorganize (collect) the terms: + // - more than 1 term type + // - more than 1 of at least one type (not including other) + // (note that this means x^2 + x + x + 2 -> x^2 + (x + x) + 2, + // which will be recorded as a step, but doesn't change the order of terms) + const termTypes = Object.keys(terms); + const filteredTermTypes = termTypes.filter(x => x !== OTHER); + return (termTypes.length > 1 && + filteredTermTypes.some(x => terms[x].length > 1)); }; -// Collects like terms for an operation node and returns a Node.Status object. -LikeTermCollector.collectLikeTerms = function(node) { - if (!LikeTermCollector.canCollectLikeTerms(node)) { - return Node.Status.noChange(node); - } - - const op = node.op; - let terms = []; - if (op === '+') { - terms = getTermsForCollectingAddition(node); - } - else if (op === '*') { - terms = getTermsForCollectingMultiplication(node); - } - else { - throw Error('Operation not supported: ' + op); - } - - // List the symbols alphabetically - const termTypesSorted = Object.keys(terms) - .filter(x => (x !== CONSTANT && x !== CONSTANT_FRACTION && x !== OTHER)) - .sort(sortTerms); - +// Collects like terms for an operation node and returns a mathNode.Status object. +LikeTermCollector.collectLikeTerms = node => { + if (!LikeTermCollector.canCollectLikeTerms(node)) { + return mathNode.Status.noChange(node); + } - // Then add const - if (terms[CONSTANT]) { - // at the end for addition (since we'd expect x^2 + (x + x) + 4) + const op = node.op; + let terms = []; if (op === '+') { - termTypesSorted.push(CONSTANT); + terms = getTermsForCollectingAddition(node); } - // for multipliation it should be at the front (e.g. (3*4) * x^2) - if (op === '*') { - termTypesSorted.unshift(CONSTANT); + else if (op === '*') { + terms = getTermsForCollectingMultiplication(node); } - } - if (terms[CONSTANT_FRACTION]) { - termTypesSorted.push(CONSTANT_FRACTION); - } + else { + throw Error('Operation not supported: ' + op); + } + + // List the symbols alphabetically + const termTypesSorted = Object.keys(terms) + .filter(x => (x !== CONSTANT && x !== CONSTANT_FRACTION && x !== OTHER)) + .sort(sortTerms); + - // Collect the new operands under op. - let newOperands = []; - let changeGroup = 1; - termTypesSorted.forEach(termType => { - const termsOfType = terms[termType]; - if (termsOfType.length === 1) { - const singleTerm = clone(termsOfType[0]); - singleTerm.changeGroup = changeGroup; - newOperands.push(singleTerm); + // Then add const + if (terms[CONSTANT]) { + // at the end for addition (since we'd expect x^2 + (x + x) + 4) + if (op === '+') { + termTypesSorted.push(CONSTANT); + } + // for multipliation it should be at the front (e.g. (3*4) * x^2) + if (op === '*') { + termTypesSorted.unshift(CONSTANT); + } } - // Any like terms should be wrapped in parens. - else { - const termList = clone(Node.Creator.parenthesis( - Node.Creator.operator(op, termsOfType))); - termList.changeGroup = changeGroup; - newOperands.push(termList); + if (terms[CONSTANT_FRACTION]) { + termTypesSorted.push(CONSTANT_FRACTION); } - termsOfType.forEach(term => { - term.changeGroup = changeGroup; + + // Collect the new operands under op. + let newOperands = []; + let changeGroup = 1; + termTypesSorted.forEach(termType => { + const termsOfType = terms[termType]; + if (termsOfType.length === 1) { + const singleTerm = clone(termsOfType[0]); + singleTerm.changeGroup = changeGroup; + newOperands.push(singleTerm); + } + // Any like terms should be wrapped in parens. + else { + const termList = clone(mathNode.Creator.parenthesis( + mathNode.Creator.operator(op, termsOfType))); + termList.changeGroup = changeGroup; + newOperands.push(termList); + } + termsOfType.forEach(term => { + term.changeGroup = changeGroup; + }); + changeGroup++; }); - changeGroup++; - }); - // then stick anything else (paren nodes, operator nodes) at the end - if (terms[OTHER]) { - newOperands = newOperands.concat(terms[OTHER]); - } + // then stick anything else (paren nodes, operator nodes) at the end + if (terms[OTHER]) { + newOperands = newOperands.concat(terms[OTHER]); + } - const newNode = clone(node); - newNode.args = newOperands; - return Node.Status.nodeChanged( - ChangeTypes.COLLECT_LIKE_TERMS, node, newNode, false); + const newNode = clone(node); + newNode.args = newOperands; + return mathNode.Status.nodeChanged( + ChangeTypes.COLLECT_LIKE_TERMS, node, newNode, false); }; // Polyonomial terms are collected by categorizing them by their 'name' // which is used to separate them into groups that can be combined. getTermName // returns this group 'name' +function getTermName(node: any, op: "+"); +function getTermName(node: any, op: any); function getTermName(node, op) { - const polyNode = new Node.PolynomialTerm(node); + const polyNode = new mathNode.PolynomialTerm(node); // we 'name' polynomial terms by their symbol name let termName = polyNode.getSymbolName(); // when adding terms, the exponent matters too (e.g. 2x^2 + 5x^3 can't be combined) @@ -136,26 +136,27 @@ function getTermName(node, op) { // Returns a dictionary of termname to lists of nodes with that name // e.g. 2x + 4 + 5x would return {'x': [2x, 5x], CONSTANT: [4]} // (where 2x, 5x, and 4 would actually be expression trees) +function getTermsForCollectingAddition(node: any); function getTermsForCollectingAddition(node) { let terms = {}; for (let i = 0; i < node.args.length; i++) { const child = node.args[i]; - if (Node.PolynomialTerm.isPolynomialTerm(child)) { + if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { const termName = getTermName(child, '+'); terms = Util.appendToArrayInObject(terms, termName, child); } - else if (Node.Type.isIntegerFraction(child)) { + else if (mathNode.Type.isIntegerFraction(child)) { terms = Util.appendToArrayInObject(terms, CONSTANT_FRACTION, child); } - else if (Node.Type.isConstant(child)) { + else if (mathNode.Type.isConstant(child)) { terms = Util.appendToArrayInObject(terms, CONSTANT, child); } - else if (Node.Type.isOperator(node) || - Node.Type.isFunction(node) || - Node.Type.isParenthesis(node) || - Node.Type.isUnaryMinus(node)) { + else if (mathNode.Type.isOperator(node) || + mathNode.Type.isFunction(node) || + mathNode.Type.isParenthesis(node) || + mathNode.Type.isUnaryMinus(node)) { terms = Util.appendToArrayInObject(terms, OTHER, child); } else { @@ -184,30 +185,31 @@ function getTermsForCollectingAddition(node) { // Returns a dictionary of termname to lists of nodes with that name // e.g. 2x + 4 + 5x^2 would return {'x': [x, x^2], CONSTANT: [2, 4, 5]} // (where x, x^2, 2, 4, and 5 would actually be expression trees) +function getTermsForCollectingMultiplication(node: any); function getTermsForCollectingMultiplication(node) { let terms = {}; for (let i = 0; i < node.args.length; i++) { let child = node.args[i]; - if (Node.Type.isUnaryMinus(child)) { + if (mathNode.Type.isUnaryMinus(child)) { terms = Util.appendToArrayInObject( - terms, CONSTANT, Node.Creator.constant(-1)); + terms, CONSTANT, mathNode.Creator.constant(-1)); child = child.args[0]; } - if (Node.PolynomialTerm.isPolynomialTerm(child)) { + if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { terms = addToTermsforPolynomialMultiplication(terms, child); } - else if (Node.Type.isIntegerFraction(child)) { + else if (mathNode.Type.isIntegerFraction(child)) { terms = Util.appendToArrayInObject(terms, CONSTANT, child); } - else if (Node.Type.isConstant(child)) { + else if (mathNode.Type.isConstant(child)) { terms = Util.appendToArrayInObject(terms, CONSTANT, child); } - else if (Node.Type.isOperator(node) || - Node.Type.isFunction(node) || - Node.Type.isParenthesis(node) || - Node.Type.isUnaryMinus(node)) { + else if (mathNode.Type.isOperator(node) || + mathNode.Type.isFunction(node) || + mathNode.Type.isParenthesis(node) || + mathNode.Type.isUnaryMinus(node)) { terms = Util.appendToArrayInObject(terms, OTHER, child); } else { @@ -224,8 +226,9 @@ function getTermsForCollectingMultiplication(node) { // e.g. 2x^4 -> 2 (coeffient) and x^4 (symbolic, named after the symbol node) // Takes the terms list and the polynomial term node, and returns an updated // terms list. +function addToTermsforPolynomialMultiplication(terms: any, node: any); function addToTermsforPolynomialMultiplication(terms, node) { - const polyNode = new Node.PolynomialTerm(node); + const polyNode = new mathNode.PolynomialTerm(node); let termName; if (!polyNode.hasCoeff()) { @@ -236,7 +239,7 @@ function addToTermsforPolynomialMultiplication(terms, node) { const coefficient = polyNode.getCoeffNode(); let termWithoutCoefficient = polyNode.getSymbolNode(); if (polyNode.getExponentNode()) { - termWithoutCoefficient = Node.Creator.operator( + termWithoutCoefficient = mathNode.Creator.operator( '^', [termWithoutCoefficient, polyNode.getExponentNode()]); } @@ -248,6 +251,7 @@ function addToTermsforPolynomialMultiplication(terms, node) { } // Sort function for termnames. Sort first by symbol name, and then by exponent. +function sortTerms(a: any, b: any); function sortTerms(a, b) { if (a === b) { return 0; @@ -271,4 +275,4 @@ function sortTerms(a, b) { } } -module.exports = LikeTermCollector; +export = LikeTermCollector; diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts similarity index 69% rename from lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js rename to lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts index 1e1b39a3..b82c4ea3 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js +++ b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts @@ -1,14 +1,13 @@ -const checks = require('../../checks'); -const clone = require('../../util/clone'); -const evaluateConstantSum = require('./evaluateConstantSum'); +import checks = require('../../checks'); +import clone = require('../../util/clone'); +import evaluateConstantSum = require('./evaluateConstantSum'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); - -// Adds a list of nodes that are polynomial terms. Returns a Node.Status object. +// Adds a list of nodes that are polynomial terms. Returns a mathNode.Status object. function addLikeTerms(node, polynomialOnly=false) { - if (!Node.Type.isOperator(node)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node)) { + return mathNode.Status.noChange(node); } let status; @@ -24,12 +23,13 @@ function addLikeTerms(node, polynomialOnly=false) { return status; } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } +function addLikePolynomialTerms(node: any); function addLikePolynomialTerms(node) { if (!checks.canAddLikeTermPolynomialNodes(node)) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const substeps = []; @@ -41,7 +41,7 @@ function addLikePolynomialTerms(node) { let status = addPositiveOneCoefficient(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // STEP 2: If any nodes have a unary minus, make it have coefficient -1 @@ -50,20 +50,20 @@ function addLikePolynomialTerms(node) { status = addNegativeOneCoefficient(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // STEP 3: group the coefficients in a sum status = groupCoefficientsForAdding(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // STEP 4: evaluate the sum (could include fractions) status = evaluateCoefficientSum(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.ADD_POLYNOMIAL_TERMS, node, newNode, true, substeps); } @@ -72,19 +72,20 @@ function addLikePolynomialTerms(node) { // into a term with an explicit coefficient of 1. This is for pedagogy, and // makes the adding coefficients step clearer. // e.g. 2x + x -> 2x + 1x -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function addPositiveOneCoefficient(node: any); function addPositiveOneCoefficient(node) { const newNode = clone(node, false); let change = false; let changeGroup = 1; newNode.args.forEach((child, i) => { - const polyTerm = new Node.PolynomialTerm(child); + const polyTerm = new mathNode.PolynomialTerm(child); if (polyTerm.getCoeffValue() === 1) { - newNode.args[i] = Node.Creator.polynomialTerm( + newNode.args[i] = mathNode.Creator.polynomialTerm( polyTerm.getSymbolNode(), polyTerm.getExponentNode(), - Node.Creator.constant(1), + mathNode.Creator.constant(1), true /* explicit coefficient */); newNode.args[i].changeGroup = changeGroup; @@ -96,11 +97,11 @@ function addPositiveOneCoefficient(node) { }); if (change) { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.ADD_COEFFICIENT_OF_ONE, node, newNode, false); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } @@ -108,16 +109,17 @@ function addPositiveOneCoefficient(node) { // coefficient into a term with an explicit coefficient of -1. This is for // pedagogy, and makes the adding coefficients step clearer. // e.g. 2x - x -> 2x - 1x -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function addNegativeOneCoefficient(node: any); function addNegativeOneCoefficient(node) { const newNode = clone(node); let change = false; let changeGroup = 1; newNode.args.forEach((child, i) => { - const polyTerm = new Node.PolynomialTerm(child); + const polyTerm = new mathNode.PolynomialTerm(child); if (polyTerm.getCoeffValue() === -1) { - newNode.args[i] = Node.Creator.polynomialTerm( + newNode.args[i] = mathNode.Creator.polynomialTerm( polyTerm.getSymbolNode(), polyTerm.getExponentNode(), polyTerm.getCoeffNode(), @@ -132,24 +134,25 @@ function addNegativeOneCoefficient(node) { }); if (change) { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.UNARY_MINUS_TO_NEGATIVE_ONE, node, newNode, false); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } // Given a sum of like polynomial terms, groups the coefficients // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function groupCoefficientsForAdding(node: any); function groupCoefficientsForAdding(node) { let newNode = clone(node); - const polynomialTermList = newNode.args.map(n => new Node.PolynomialTerm(n)); + const polynomialTermList = newNode.args.map(n => new mathNode.PolynomialTerm(n)); const coefficientList = polynomialTermList.map(p => p.getCoeffNode(true)); - const sumOfCoefficents = Node.Creator.parenthesis( - Node.Creator.operator('+', coefficientList)); + const sumOfCoefficents = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', coefficientList)); // TODO: changegroups should also be on the before node, on all the // coefficients, but changegroups with polyTerm gets messy so let's tackle // that later. @@ -160,23 +163,24 @@ function groupCoefficientsForAdding(node) { const firstTerm = polynomialTermList[0]; const exponentNode = firstTerm.getExponentNode(); const symbolNode = firstTerm.getSymbolNode(); - newNode = Node.Creator.polynomialTerm( + newNode = mathNode.Creator.polynomialTerm( symbolNode, exponentNode, sumOfCoefficents); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.GROUP_COEFFICIENTS, node, newNode); } // Given a node of the form (2 + 4 + 5)x -- ie the coefficients have been // grouped for adding -- add the coefficients together to make a new coeffient // that is a constant or constant fraction. +function evaluateCoefficientSum(node: any); function evaluateCoefficientSum(node) { // the node is now always a * node with the left child the coefficent sum // e.g. (2 + 4 + 5) and the right node the symbol part e.g. x or y^2 // so we want to evaluate args[0] const coefficientSum = clone(node).args[0]; const childStatus = evaluateConstantSum(coefficientSum); - return Node.Status.childChanged(node, childStatus, 0); + return mathNode.Status.childChanged(node, childStatus, 0); } -module.exports = addLikeTerms; +export = addLikeTerms; diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts similarity index 62% rename from lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js rename to lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts index e2c517b9..0e37b99d 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js +++ b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts @@ -1,23 +1,23 @@ -const addConstantAndFraction = require('../fractionsSearch/addConstantAndFraction'); -const addConstantFractions = require('../fractionsSearch/addConstantFractions'); -const arithmeticSearch = require('../arithmeticSearch'); -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); +import addConstantAndFraction = require('../fractionsSearch/addConstantAndFraction'); +import addConstantFractions = require('../fractionsSearch/addConstantFractions'); +import arithmeticSearch = require('../arithmeticSearch'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); // Evaluates a sum of constant numbers and integer fractions to a single // constant number or integer fraction. e.g. e.g. 2/3 + 5 + 5/2 => 49/6 -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function evaluateConstantSum(node: any); function evaluateConstantSum(node) { - if (Node.Type.isParenthesis(node)) { + if (mathNode.Type.isParenthesis(node)) { node = node.content; } - if (!Node.Type.isOperator(node) || node.op !== '+') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '+') { + return mathNode.Status.noChange(node); } - if (node.args.some(node => !Node.Type.isConstantOrConstantFraction(node))) { - return Node.Status.noChange(node); + if (node.args.some(node => !mathNode.Type.isConstantOrConstantFraction(node))) { + return mathNode.Status.noChange(node); } // functions needed to evaluate the sum @@ -29,7 +29,7 @@ function evaluateConstantSum(node) { for (let i = 0; i < summingFunctions.length; i++) { const status = summingFunctions[i](node); if (status.hasChanged()) { - if (Node.Type.isConstantOrConstantFraction(status.newNode)) { + if (mathNode.Type.isConstantOrConstantFraction(status.newNode)) { return status; } } @@ -42,29 +42,29 @@ function evaluateConstantSum(node) { // STEP 1: group fractions and constants separately status = groupConstantsAndFractions(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); const constants = newNode.args[0]; const fractions = newNode.args[1]; // STEP 2A: evaluate arithmetic IF there's > 1 constant // (which is the case if it's a list surrounded by parenthesis) - if (Node.Type.isParenthesis(constants)) { + if (mathNode.Type.isParenthesis(constants)) { const constantList = constants.content; const evaluateStatus = arithmeticSearch(constantList); - status = Node.Status.childChanged(newNode, evaluateStatus, 0); + status = mathNode.Status.childChanged(newNode, evaluateStatus, 0); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // STEP 2B: add fractions IF there's > 1 fraction // (which is the case if it's a list surrounded by parenthesis) - if (Node.Type.isParenthesis(fractions)) { + if (mathNode.Type.isParenthesis(fractions)) { const fractionList = fractions.content; const evaluateStatus = addConstantFractions(fractionList); - status = Node.Status.childChanged(newNode, evaluateStatus, 1); + status = mathNode.Status.childChanged(newNode, evaluateStatus, 1); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // STEP 3: combine the evaluated constant and fraction @@ -72,9 +72,9 @@ function evaluateConstantSum(node) { // so we just call evaluateConstantSum again to cycle through status = evaluateConstantSum(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); } @@ -82,11 +82,12 @@ function evaluateConstantSum(node) { // fractions and constants. So we need to group them together so we can later // add them. // Expects a node that is a sum of integer fractions and constants. -// Returns a Node.Status object. +// Returns a mathNode.Status object. // e.g. 2/3 + 5 + 5/2 => (2/3 + 5/2) + 5 +function groupConstantsAndFractions(node: any); function groupConstantsAndFractions(node) { - let fractions = node.args.filter(Node.Type.isIntegerFraction); - let constants = node.args.filter(Node.Type.isConstant); + let fractions = node.args.filter(mathNode.Type.isIntegerFraction); + let constants = node.args.filter(mathNode.Type.isConstant); if (fractions.length === 0 || constants.length === 0) { throw Error('expected both integer fractions and constants, got ' + node); @@ -104,7 +105,7 @@ function groupConstantsAndFractions(node) { }); // wrap in parenthesis if there's more than one, to group them if (constants.length > 1) { - constants = Node.Creator.parenthesis(Node.Creator.operator('+', constants)); + constants = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', constants)); } else { constants = constants[0]; @@ -118,15 +119,15 @@ function groupConstantsAndFractions(node) { }); // wrap in parenthesis if there's more than one, to group them if (fractions.length > 1) { - fractions = Node.Creator.parenthesis(Node.Creator.operator('+', fractions)); + fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', fractions)); } else { fractions = fractions[0]; } - const newNode = Node.Creator.operator('+', [constants, fractions]); - return Node.Status.nodeChanged( + const newNode = mathNode.Creator.operator('+', [constants, fractions]); + return mathNode.Status.nodeChanged( ChangeTypes.COLLECT_LIKE_TERMS, node, newNode); } -module.exports = evaluateConstantSum; +export = evaluateConstantSum; diff --git a/lib/simplifyExpression/collectAndCombineSearch/index.js b/lib/simplifyExpression/collectAndCombineSearch/index.ts similarity index 73% rename from lib/simplifyExpression/collectAndCombineSearch/index.js rename to lib/simplifyExpression/collectAndCombineSearch/index.ts index 33ddb342..755ddfd9 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/index.js +++ b/lib/simplifyExpression/collectAndCombineSearch/index.ts @@ -1,26 +1,25 @@ // Collects and combines like terms -const addLikeTerms = require('./addLikeTerms'); -const clone = require('../../util/clone'); -const multiplyLikeTerms = require('./multiplyLikeTerms'); - -const ChangeTypes = require('../../ChangeTypes'); -const LikeTermCollector = require('./LikeTermCollector'); -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); - +import addLikeTerms = require('./addLikeTerms'); +import clone = require('../../util/clone'); +import multiplyLikeTerms = require('./multiplyLikeTerms'); +import ChangeTypes = require('../../ChangeTypes'); +import LikeTermCollector = require('./LikeTermCollector'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); const termCollectorFunctions = { '+': addLikeTerms, '*': multiplyLikeTerms }; // Iterates through the tree looking for like terms to collect and combine. -// Will prioritize deeper expressions. Returns a Node.Status object. +// Will prioritize deeper expressions. Returns a mathNode.Status object. const search = TreeSearch.postOrder(collectAndCombineLikeTerms); // Given an operator node, maybe collects and then combines if possible // e.g. 2x + 4x + y => 6x + y // e.g. 2x * x^2 * 5x => 10 x^4 +function collectAndCombineLikeTerms(node: any); function collectAndCombineLikeTerms(node) { if (node.op === '+') { const status = collectAndCombineOperation(node); @@ -45,12 +44,13 @@ function collectAndCombineLikeTerms(node) { return multiplyLikeTerms(node, true); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } // Collects and combines (if possible) the arguments of an addition or // multiplication +function collectAndCombineOperation(node: any); function collectAndCombineOperation(node) { let substeps = []; @@ -61,7 +61,7 @@ function collectAndCombineOperation(node) { // STEP 1: collect like terms, e.g. 2x + 4x^2 + 5x => 4x^2 + (2x + 5x) substeps.push(status); - let newNode = Node.Status.resetChangeGroups(status.newNode); + let newNode = mathNode.Status.resetChangeGroups(status.newNode); // STEP 2 onwards: combine like terms for each group that can be combined // e.g. (x + 3x) + (2 + 2) has two groups @@ -69,10 +69,10 @@ function collectAndCombineOperation(node) { if (combineSteps.length > 0) { substeps = substeps.concat(combineSteps); const lastStep = combineSteps[combineSteps.length - 1]; - newNode = Node.Status.resetChangeGroups(lastStep.newNode); + newNode = mathNode.Status.resetChangeGroups(lastStep.newNode); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.COLLECT_AND_COMBINE_LIKE_TERMS, node, newNode, true, substeps); } @@ -81,6 +81,7 @@ function collectAndCombineOperation(node) { // combine like terms for each group that can be combined // e.g. (x + 3x) + (2 + 2) has two groups // returns a list of combine steps +function combineLikeTerms(node: any); function combineLikeTerms(node) { const steps = []; let newNode = clone(node); @@ -88,19 +89,19 @@ function combineLikeTerms(node) { for (let i = 0; i < node.args.length; i++) { let child = node.args[i]; // All groups of terms will be surrounded by parenthesis - if (!Node.Type.isParenthesis(child)) { + if (!mathNode.Type.isParenthesis(child)) { continue; } child = child.content; const childStatus = termCollectorFunctions[newNode.op](child); if (childStatus.hasChanged()) { - const status = Node.Status.childChanged(newNode, childStatus, i); + const status = mathNode.Status.childChanged(newNode, childStatus, i); steps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } } return steps; } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts similarity index 68% rename from lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js rename to lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts index 079d3b17..e131aa62 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js +++ b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts @@ -1,17 +1,16 @@ -const arithmeticSearch = require('../arithmeticSearch'); -const checks = require('../../checks'); -const clone = require('../../util/clone'); -const multiplyFractionsSearch = require('../multiplyFractionsSearch'); - -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); +import arithmeticSearch = require('../arithmeticSearch'); +import checks = require('../../checks'); +import clone = require('../../util/clone'); +import multiplyFractionsSearch = require('../multiplyFractionsSearch'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); // Multiplies a list of nodes that are polynomial like terms. Returns a node. // The polynomial nodes should *not* have coefficients. (multiplying // coefficients is handled in collecting like terms for multiplication) function multiplyLikeTerms(node, polynomialOnly=false) { - if (!Node.Type.isOperator(node)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node)) { + return mathNode.Status.noChange(node); } let status; @@ -35,12 +34,13 @@ function multiplyLikeTerms(node, polynomialOnly=false) { return status; } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } +function multiplyPolynomialTerms(node: any); function multiplyPolynomialTerms(node) { if (!checks.canMultiplyLikeTermPolynomialNodes(node)) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const substeps = []; @@ -53,14 +53,14 @@ function multiplyPolynomialTerms(node) { let status = addOneExponent(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // STEP 2: collect exponents to a single exponent sum // e.g. x^1 * x^3 -> x^(1+3) status = collectExponents(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // STEP 3: add exponents together. // NOTE: This might not be a step if the exponents aren't all constants, @@ -70,16 +70,16 @@ function multiplyPolynomialTerms(node) { const exponentSum = newNode.args[1].content; const sumStatus = arithmeticSearch(exponentSum); if (sumStatus.hasChanged()) { - status = Node.Status.childChanged(newNode, sumStatus, 1); + status = mathNode.Status.childChanged(newNode, sumStatus, 1); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } if (substeps.length === 1) { // possible if only step 2 happens return substeps[0]; } else { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_POLYNOMIAL_TERMS, node, newNode, true, substeps); } @@ -89,18 +89,19 @@ function multiplyPolynomialTerms(node) { // into a term with an explicit exponent of 1. This is for pedagogy, and // makes the adding coefficients step clearer. // e.g. x^2 * x -> x^2 * x^1 -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function addOneExponent(node: any); function addOneExponent(node) { const newNode = clone(node); let change = false; let changeGroup = 1; newNode.args.forEach((child, i) => { - const polyTerm = new Node.PolynomialTerm(child); + const polyTerm = new mathNode.PolynomialTerm(child); if (!polyTerm.getExponentNode()) { - newNode.args[i] = Node.Creator.polynomialTerm( + newNode.args[i] = mathNode.Creator.polynomialTerm( polyTerm.getSymbolNode(), - Node.Creator.constant(1), + mathNode.Creator.constant(1), polyTerm.getCoeffNode()); newNode.args[i].changeGroup = changeGroup; @@ -112,19 +113,20 @@ function addOneExponent(node) { }); if (change) { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.ADD_EXPONENT_OF_ONE, node, newNode, false); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } // Given a product of polynomial terms, groups the exponents into a sum // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function collectExponents(node: any); function collectExponents(node) { - const polynomialTermList = node.args.map(n => new Node.PolynomialTerm(n)); + const polynomialTermList = node.args.map(n => new mathNode.PolynomialTerm(n)); // If we're multiplying polynomial nodes together, they all share the same // symbol. Get that from the first node. @@ -133,11 +135,11 @@ function collectExponents(node) { // The new exponent will be a sum of exponents (an operation, wrapped in // parens) e.g. x^(3+4+5) const exponentNodeList = polynomialTermList.map(p => p.getExponentNode(true)); - const newExponent = Node.Creator.parenthesis( - Node.Creator.operator('+', exponentNodeList)); - const newNode = Node.Creator.polynomialTerm(symbolNode, newExponent, null); - return Node.Status.nodeChanged( + const newExponent = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', exponentNodeList)); + const newNode = mathNode.Creator.polynomialTerm(symbolNode, newExponent, null); + return mathNode.Status.nodeChanged( ChangeTypes.COLLECT_EXPONENTS, node, newNode); } -module.exports = multiplyLikeTerms; +export = multiplyLikeTerms; diff --git a/lib/simplifyExpression/distributeSearch/index.js b/lib/simplifyExpression/distributeSearch/index.ts similarity index 68% rename from lib/simplifyExpression/distributeSearch/index.js rename to lib/simplifyExpression/distributeSearch/index.ts index c63a597f..afc60e34 100644 --- a/lib/simplifyExpression/distributeSearch/index.js +++ b/lib/simplifyExpression/distributeSearch/index.ts @@ -1,46 +1,46 @@ -const arithmeticSearch = require('../arithmeticSearch'); -const clone = require('../../util/clone'); -const collectAndCombineSearch = require('../collectAndCombineSearch'); -const rearrangeCoefficient = require('../basicsSearch/rearrangeCoefficient'); - -const ChangeTypes = require('../../ChangeTypes'); -const Negative = require('../../Negative'); -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); - +import arithmeticSearch = require('../arithmeticSearch'); +import clone = require('../../util/clone'); +import collectAndCombineSearch = require('../collectAndCombineSearch'); +import rearrangeCoefficient = require('../basicsSearch/rearrangeCoefficient'); +import ChangeTypes = require('../../ChangeTypes'); +import Negative = require('../../Negative'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); const search = TreeSearch.postOrder(distribute); // Distributes through parenthesis. // e.g. 2(x+3) -> (2*x + 2*3) // e.g. -(x+5) -> (-x + -5) -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function distribute(node: any); function distribute(node) { - if (Node.Type.isUnaryMinus(node)) { + if (mathNode.Type.isUnaryMinus(node)) { return distributeUnaryMinus(node); } - else if (Node.Type.isOperator(node)) { + else if (mathNode.Type.isOperator(node)) { return distributeAndSimplifyOperationNode(node); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } // Distributes unary minus into a parenthesis node. // e.g. -(4*9*x^2) --> (-4 * 9 * x^2) // e.g. -(x + y - 5) --> (-x + -y + 5) -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function distributeUnaryMinus(node: any); function distributeUnaryMinus(node) { - if (!Node.Type.isUnaryMinus(node)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isUnaryMinus(node)) { + return mathNode.Status.noChange(node); } const unaryContent = node.args[0]; - if (!Node.Type.isParenthesis(unaryContent)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isParenthesis(unaryContent)) { + return mathNode.Status.noChange(node); } const content = unaryContent.content; - if (!Node.Type.isOperator(content)) { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(content)) { + return mathNode.Status.noChange(node); } const newContent = clone(content); node.changeGroup = 1; @@ -50,8 +50,8 @@ function distributeUnaryMinus(node) { if (content.op === '*' || content.op === '/') { newContent.args[0] = Negative.negate(newContent.args[0]); newContent.args[0].changeGroup = 1; - const newNode = Node.Creator.parenthesis(newContent); - return Node.Status.nodeChanged( + const newNode = mathNode.Creator.parenthesis(newContent); + return mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); } else if (content.op === '+') { @@ -65,12 +65,12 @@ function distributeUnaryMinus(node) { return newArg; }); newContent.args = newArgs; - const newNode = Node.Creator.parenthesis(newContent); - return Node.Status.nodeChanged( + const newNode = mathNode.Creator.parenthesis(newContent); + return mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } @@ -78,10 +78,11 @@ function distributeUnaryMinus(node) { // can be distributed. To be distributed, there must be two terms beside // each other, and at least one of them must be a parenthesis node. // e.g. 2*(3+x) or (4+x^2+x^3)*(x+3) -// Returns a Node.Status object with substeps +// Returns a mathNode.Status object with substeps +function distributeAndSimplifyOperationNode(node: any); function distributeAndSimplifyOperationNode(node) { - if (!Node.Type.isOperator(node) || node.op !== '*') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '*') { + return mathNode.Status.noChange(node); } // STEP 1: distribute with `distributeTwoNodes` @@ -112,30 +113,30 @@ function distributeAndSimplifyOperationNode(node) { newNode.changeGroup = 1; } - status = Node.Status.nodeChanged( + status = mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE, node, newNode, false); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // case 1: there were more than two operands in this multiplication // e.g. 3*7*(2+x)*(3+x)*(4+x) is a multiplication node with 5 children // and the new node will be 3*(14+7x)*(3+x)*(4+x) with 4 children. - if (Node.Type.isOperator(newNode, '*')) { + if (mathNode.Type.isOperator(newNode, '*')) { const childStatus = simplifyWithParens(newNode.args[i]); if (childStatus.hasChanged()) { - status = Node.Status.childChanged(newNode, childStatus, i); + status = mathNode.Status.childChanged(newNode, childStatus, i); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } } // case 2: there were only two operands and we multiplied them together. // e.g. 7*(2+x) -> (7*2 + 7*x) // Now we can just simplify it. - else if (Node.Type.isParenthesis(newNode)){ + else if (mathNode.Type.isParenthesis(newNode)){ status = simplifyWithParens(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } } else { @@ -146,16 +147,17 @@ function distributeAndSimplifyOperationNode(node) { return substeps[0]; } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE, node, newNode, false, substeps); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Distributes two nodes together. At least one node must be parenthesis node // e.g. 2*(x+3) -> (2*x + 2*3) (5+x)*x -> 5*x + x*x // e.g. (5+x)*(x+3) -> (5*x + 5*3 + x*x + x*3) // Returns a node. +function distributeTwoNodes(firstNode: any, secondNode: any); function distributeTwoNodes(firstNode, secondNode) { // lists of terms we'll be multiplying together from each node let firstArgs, secondArgs; @@ -184,12 +186,12 @@ function distributeTwoNodes(firstNode, secondNode) { fractionNodes.forEach((node) => { let arg; if (isFraction(node)) { - let numerator = Node.Creator.operator('*', [node.args[0], nonFractionTerm]); - numerator = Node.Creator.parenthesis(numerator); - arg = Node.Creator.operator('/', [numerator, node.args[1]]); + let numerator = mathNode.Creator.operator('*', [node.args[0], nonFractionTerm]); + numerator = mathNode.Creator.parenthesis(numerator); + arg = mathNode.Creator.operator('/', [numerator, node.args[1]]); } else { - arg = Node.Creator.operator('*', [node, nonFractionTerm]); + arg = mathNode.Creator.operator('*', [node, nonFractionTerm]); } arg.changeGroup = 1; newArgs.push(arg); @@ -199,7 +201,7 @@ function distributeTwoNodes(firstNode, secondNode) { // step. else if (firstArgs.length > 1 && secondArgs.length > 1) { firstArgs.forEach(leftArg => { - const arg = Node.Creator.operator('*', [leftArg, secondNode]); + const arg = mathNode.Creator.operator('*', [leftArg, secondNode]); arg.changeGroup = 1; newArgs.push(arg); }); @@ -208,21 +210,23 @@ function distributeTwoNodes(firstNode, secondNode) { // a list of all pairs of nodes between the two arg lists firstArgs.forEach(leftArg => { secondArgs.forEach(rightArg => { - const arg = Node.Creator.operator('*', [leftArg, rightArg]); + const arg = mathNode.Creator.operator('*', [leftArg, rightArg]); arg.changeGroup = 1; newArgs.push(arg); }); }); } - return Node.Creator.parenthesis(Node.Creator.operator('+', newArgs)); + return mathNode.Creator.parenthesis(mathNode.Creator.operator('+', newArgs)); } +function hasFraction(args: any); function hasFraction(args) { return args.filter(isFraction).length > 0; } +function isFraction(node: any); function isFraction(node) { - return Node.Type.isOperator(node, '/'); + return mathNode.Type.isOperator(node, '/'); } // Simplifies a sum of terms (a result of distribution) that's in parens @@ -230,25 +234,27 @@ function isFraction(node) { // e.g. 2x*(4 + x) distributes to (2x*4 + 2x*x) // This is a separate function from simplify to make the flow more readable, // but this is literally just a wrapper around 'simplify'. -// Returns a Node.Status object +// Returns a mathNode.Status object +function simplifyWithParens(node: any); function simplifyWithParens(node) { - if (!Node.Type.isParenthesis(node)) { + if (!mathNode.Type.isParenthesis(node)) { throw Error('expected ' + node + ' to be a parenthesis node'); } const status = simplify(node.content); if (status.hasChanged()) { - return Node.Status.childChanged(node, status); + return mathNode.Status.childChanged(node, status); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } // Simplifies a sum of terms that are a result of distribution. // e.g. (2x+3)*(4x+5) -distribute-> 2x*(4x+5) + 3*(4x+5) <- 2 terms to simplify // e.g. 2x*(4x+5) --distribute--> 2x*4x + 2x*5 --simplify--> 8x^2 + 10x -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function simplify(node: any); function simplify(node) { const substeps = []; const simplifyFunctions = [ @@ -263,30 +269,31 @@ function simplify(node) { for (let j = 0; j < simplifyFunctions.length; j++) { const childStatus = simplifyFunctions[j](newNode.args[i]); if (childStatus.hasChanged()) { - const status = Node.Status.childChanged(newNode, childStatus, i); + const status = mathNode.Status.childChanged(newNode, childStatus, i); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } } } // possible in cases like 2(x + y) -> 2x + 2y -> doesn't need simplifying if (substeps.length === 0) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } else { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_TERMS, node, newNode, false, substeps); } } // returns true if `node` is of the type (node + node + ...) +function isParenthesisOfAddition(node: any); function isParenthesisOfAddition(node) { - if (!Node.Type.isParenthesis(node)) { + if (!mathNode.Type.isParenthesis(node)) { return false; } const content = node.content; - return Node.Type.isOperator(content, '+'); + return mathNode.Type.isOperator(content, '+'); } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/divisionSearch/index.js b/lib/simplifyExpression/divisionSearch/index.ts similarity index 65% rename from lib/simplifyExpression/divisionSearch/index.js rename to lib/simplifyExpression/divisionSearch/index.ts index ffd78b92..75e9d7e6 100644 --- a/lib/simplifyExpression/divisionSearch/index.js +++ b/lib/simplifyExpression/divisionSearch/index.ts @@ -1,14 +1,15 @@ -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); // Searches for and simplifies any chains of division or nested division. -// Returns a Node.Status object +// Returns a mathNode.Status object const search = TreeSearch.preOrder(division); +function division(node: any); function division(node) { - if (!Node.Type.isOperator(node) || node.op !== '/') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '/') { + return mathNode.Status.noChange(node); } // e.g. 2/(x/6) => 2 * 6/x let nodeStatus = multiplyByInverse(node); @@ -20,35 +21,37 @@ function division(node) { if (nodeStatus.hasChanged()) { return nodeStatus; } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // If `node` is a fraction with a denominator that is also a fraction, multiply // by the inverse. // e.g. x/(2/3) -> x * 3/2 +function multiplyByInverse(node: any); function multiplyByInverse(node) { let denominator = node.args[1]; - if (Node.Type.isParenthesis(denominator)) { + if (mathNode.Type.isParenthesis(denominator)) { denominator = denominator.content; } - if (!Node.Type.isOperator(denominator) || denominator.op !== '/') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(denominator) || denominator.op !== '/') { + return mathNode.Status.noChange(node); } // At this point, we know that node is a fraction and denonimator is the // fraction we need to inverse. const inverseNumerator = denominator.args[1]; const inverseDenominator = denominator.args[0]; - const inverseFraction = Node.Creator.operator( + const inverseFraction = mathNode.Creator.operator( '/', [inverseNumerator, inverseDenominator]); - const newNode = Node.Creator.operator('*', [node.args[0], inverseFraction]); - return Node.Status.nodeChanged( + const newNode = mathNode.Creator.operator('*', [node.args[0], inverseFraction]); + return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_BY_INVERSE, node, newNode); } // Simplifies any chains of division into a single division operation. // e.g. 2/x/6 -> 2/(x*6) -// Returns a Node.Status object +// Returns a mathNode.Status object +function simplifyDivisionChain(node: any); function simplifyDivisionChain(node) { // check for a chain of division const denominatorList = getDenominatorList(node); @@ -57,18 +60,19 @@ function simplifyDivisionChain(node) { const numerator = denominatorList.shift(); // the new single denominator is all the chained denominators // multiplied together, in parentheses. - const denominator = Node.Creator.parenthesis( - Node.Creator.operator('*', denominatorList)); - const newNode = Node.Creator.operator('/', [numerator, denominator]); - return Node.Status.nodeChanged( + const denominator = mathNode.Creator.parenthesis( + mathNode.Creator.operator('*', denominatorList)); + const newNode = mathNode.Creator.operator('/', [numerator, denominator]); + return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_DIVISION, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Given a the denominator of a division node, returns all the nested // denominator nodess. e.g. 2/3/4/5 would return [2,3,4,5] // (note: all the numbers in the example are actually constant nodes) +function getDenominatorList(denominator: any); function getDenominatorList(denominator) { let node = denominator; const denominatorList = []; @@ -83,4 +87,4 @@ function getDenominatorList(denominator) { return denominatorList; } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts similarity index 63% rename from lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js rename to lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts index ed23c8dc..37bd3353 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts @@ -1,43 +1,43 @@ -const addConstantFractions = require('./addConstantFractions'); -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const evaluate = require('../../util/evaluate'); -const Node = require('../../node'); +import addConstantFractions = require('./addConstantFractions'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +import evaluate = require('../../util/evaluate'); +const mathNode = require('../../node'); // Adds a constant to a fraction by: // - collapsing the fraction to decimal if the constant is not an integer // e.g. 5.3 + 1/2 -> 5.3 + 0.2 // - turning the constant into a fraction with the same denominator if it is // an integer, e.g. 5 + 1/2 -> 10/2 + 1/2 +function addConstantAndFraction(node: any); function addConstantAndFraction(node) { - if (!Node.Type.isOperator(node) || node.op !== '+' || node.args.length !== 2) { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '+' || node.args.length !== 2) { + return mathNode.Status.noChange(node); } const firstArg = node.args[0]; const secondArg = node.args[1]; let constNode, fractionNode; - if (Node.Type.isConstant(firstArg)) { - if (Node.Type.isIntegerFraction(secondArg)) { + if (mathNode.Type.isConstant(firstArg)) { + if (mathNode.Type.isIntegerFraction(secondArg)) { constNode = firstArg; fractionNode = secondArg; } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } - else if (Node.Type.isConstant(secondArg)) { - if (Node.Type.isIntegerFraction(firstArg)) { + else if (mathNode.Type.isConstant(secondArg)) { + if (mathNode.Type.isIntegerFraction(firstArg)) { constNode = secondArg; fractionNode = firstArg; } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } let newNode = clone(node); @@ -51,9 +51,9 @@ function addConstantAndFraction(node) { const denominatorNode = fractionNode.args[1]; const denominatorValue = parseInt(denominatorNode); const constNodeValue = parseInt(constNode.value); - const newNumeratorNode = Node.Creator.constant( + const newNumeratorNode = mathNode.Creator.constant( constNodeValue * denominatorValue); - newConstNode = Node.Creator.operator( + newConstNode = mathNode.Creator.operator( '/', [newNumeratorNode, denominatorNode]); newFractionNode = fractionNode; changeType = ChangeTypes.CONVERT_INTEGER_TO_FRACTION; @@ -67,12 +67,12 @@ function addConstantAndFraction(node) { else { dividedValue = parseFloat(dividedValue.toFixed(4)); } - newFractionNode = Node.Creator.constant(dividedValue); + newFractionNode = mathNode.Creator.constant(dividedValue); newConstNode = constNode; changeType = ChangeTypes.DIVIDE_FRACTION_FOR_ADDITION; } - if (Node.Type.isConstant(firstArg)) { + if (mathNode.Type.isConstant(firstArg)) { newNode.args[0] = newConstNode; newNode.args[1] = newFractionNode; } @@ -81,8 +81,8 @@ function addConstantAndFraction(node) { newNode.args[1] = newConstNode; } - substeps.push(Node.Status.nodeChanged(changeType, node, newNode)); - newNode = Node.Status.resetChangeGroups(newNode); + substeps.push(mathNode.Status.nodeChanged(changeType, node, newNode)); + newNode = mathNode.Status.resetChangeGroups(newNode); // If we changed an integer to a fraction, we need to add the steps for // adding the fractions. @@ -92,16 +92,16 @@ function addConstantAndFraction(node) { } // Otherwise, add the two constants else { - const evalNode = Node.Creator.constant(evaluate(newNode)); - substeps.push(Node.Status.nodeChanged( + const evalNode = mathNode.Creator.constant(evaluate(newNode)); + substeps.push(mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_ARITHMETIC, newNode, evalNode)); } const lastStep = substeps[substeps.length - 1]; - newNode = Node.Status.resetChangeGroups(lastStep.newNode); + newNode = mathNode.Status.resetChangeGroups(lastStep.newNode); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); } -module.exports = addConstantAndFraction; +export = addConstantAndFraction; diff --git a/lib/simplifyExpression/fractionsSearch/addConstantFractions.js b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts similarity index 60% rename from lib/simplifyExpression/fractionsSearch/addConstantFractions.js rename to lib/simplifyExpression/fractionsSearch/addConstantFractions.ts index 1179c366..079a5974 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantFractions.js +++ b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts @@ -1,10 +1,9 @@ -const clone = require('../../util/clone'); -const divideByGCD = require('./divideByGCD'); -const math = require('mathjs'); - -const ChangeTypes = require('../../ChangeTypes'); -const evaluate = require('../../util/evaluate'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import divideByGCD = require('./divideByGCD'); +import math = require('mathjs'); +import ChangeTypes = require('../../ChangeTypes'); +import evaluate = require('../../util/evaluate'); +const mathNode = require('../../node'); // Adds constant fractions -- can start from either step 1 or 2 // 1A. Find the LCD if denominators are different and multiplies to make @@ -13,15 +12,16 @@ const Node = require('../../node'); // e.g. (2*2)/(3*2) + 4/6 -> 4/6 + 4/6 // 2A. Combines numerators, e.g. 4/6 + 4/6 -> e.g. 2/5 + 4/5 --> (2+4)/5 // 2B. Adds numerators together, e.g. (2+4)/5 -> 6/5 -// Returns a Node.Status object with substeps +// Returns a mathNode.Status object with substeps +function addConstantFractions(node: any); function addConstantFractions(node) { let newNode = clone(node); - if (!Node.Type.isOperator(node) || node.op !== '+') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '+') { + return mathNode.Status.noChange(node); } - if (!node.args.every(n => Node.Type.isIntegerFraction(n, true))) { - return Node.Status.noChange(node); + if (!node.args.every(n => mathNode.Type.isIntegerFraction(n, true))) { + return mathNode.Status.noChange(node); } const denominators = node.args.map(fraction => { return parseFloat(evaluate(fraction.args[1])); @@ -35,51 +35,52 @@ function addConstantFractions(node) { if (!denominators.every(denominator => denominator === denominators[0])) { status = makeCommonDenominator(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // 1B. Multiply out the denominators status = evaluateDenominators(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // 1B. Multiply out the numerators status = evaluateNumerators(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // 2A. Now that they all have the same denominator, combine the numerators // e.g. 2/3 + 5/3 -> (2+5)/3 status = combineNumeratorsAboveCommonDenominator(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // 2B. Finally, add the numerators together status = addNumeratorsTogether(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // 2C. If the numerator is 0, simplify to just 0 status = reduceNumerator(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // 2D. If we can simplify the fraction, do so status = divideByGCD(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.ADD_FRACTIONS, node, newNode, true, substeps); } // Given a + operation node with a list of fraction nodes as args that all have // the same denominator, add them together. e.g. 2/3 + 5/3 -> (2+5)/3 // Returns the new node. +function combineNumeratorsAboveCommonDenominator(node: any); function combineNumeratorsAboveCommonDenominator(node) { let newNode = clone(node); @@ -88,40 +89,43 @@ function combineNumeratorsAboveCommonDenominator(node) { newNode.args.forEach(fraction => { numeratorArgs.push(fraction.args[0]); }); - const newNumerator = Node.Creator.parenthesis( - Node.Creator.operator('+', numeratorArgs)); + const newNumerator = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', numeratorArgs)); - newNode = Node.Creator.operator('/', [newNumerator, commonDenominator]); - return Node.Status.nodeChanged( + newNode = mathNode.Creator.operator('/', [newNumerator, commonDenominator]); + return mathNode.Status.nodeChanged( ChangeTypes.COMBINE_NUMERATORS, node, newNode); } // Given a node with a numerator that is an addition node, will add // all the numerators and return the result +function addNumeratorsTogether(node: any); function addNumeratorsTogether(node) { const newNode = clone(node); - newNode.args[0] = Node.Creator.constant(evaluate(newNode.args[0])); - return Node.Status.nodeChanged( + newNode.args[0] = mathNode.Creator.constant(evaluate(newNode.args[0])); + return mathNode.Status.nodeChanged( ChangeTypes.ADD_NUMERATORS, node, newNode); } +function reduceNumerator(node: any); function reduceNumerator(node) { let newNode = clone(node); if (newNode.args[0].value === '0') { - newNode = Node.Creator.constant(0); - return Node.Status.nodeChanged( + newNode = mathNode.Creator.constant(0); + return mathNode.Status.nodeChanged( ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Takes `node`, a sum of fractions, and returns a node that's a sum of // fractions with denominators that evaluate to the same common denominator // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) // Returns the new node. +function makeCommonDenominator(node: any); function makeCommonDenominator(node) { const newNode = clone(node); @@ -135,39 +139,41 @@ function makeCommonDenominator(node) { // so that the denominator is the LCD const missingFactor = commonDenominator / denominators[i]; if (missingFactor !== 1) { - const missingFactorNode = Node.Creator.constant(missingFactor); - const newNumerator = Node.Creator.parenthesis( - Node.Creator.operator('*', [child.args[0], missingFactorNode])); - const newDeominator = Node.Creator.parenthesis( - Node.Creator.operator('*', [child.args[1], missingFactorNode])); - newNode.args[i] = Node.Creator.operator('/', [newNumerator, newDeominator]); + const missingFactorNode = mathNode.Creator.constant(missingFactor); + const newNumerator = mathNode.Creator.parenthesis( + mathNode.Creator.operator('*', [child.args[0], missingFactorNode])); + const newDeominator = mathNode.Creator.parenthesis( + mathNode.Creator.operator('*', [child.args[1], missingFactorNode])); + newNode.args[i] = mathNode.Creator.operator('/', [newNumerator, newDeominator]); } }); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.COMMON_DENOMINATOR, node, newNode); } +function evaluateDenominators(node: any); function evaluateDenominators(node) { const newNode = clone(node); newNode.args.map(fraction => { - fraction.args[1] = Node.Creator.constant(evaluate(fraction.args[1])); + fraction.args[1] = mathNode.Creator.constant(evaluate(fraction.args[1])); }); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_DENOMINATORS, node, newNode); } +function evaluateNumerators(node: any); function evaluateNumerators(node) { const newNode = clone(node); newNode.args.map(fraction => { - fraction.args[0] = Node.Creator.constant(evaluate(fraction.args[0])); + fraction.args[0] = mathNode.Creator.constant(evaluate(fraction.args[0])); }); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_NUMERATORS, node, newNode); } -module.exports = addConstantFractions; +export = addConstantFractions; diff --git a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.js b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts similarity index 78% rename from lib/simplifyExpression/fractionsSearch/cancelLikeTerms.js rename to lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts index dd7818e6..a3f9d7f1 100644 --- a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.js +++ b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts @@ -1,9 +1,8 @@ -const clone = require('../../util/clone'); -const print = require('../../util/print'); - -const ChangeTypes = require('../../ChangeTypes'); -const Negative = require('../../Negative'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import print = require('../../util/print'); +import ChangeTypes = require('../../ChangeTypes'); +import Negative = require('../../Negative'); +const mathNode = require('../../node'); // Used for cancelTerms to return a (possibly updated) numerator and denominator class CancelOutStatus { @@ -16,10 +15,11 @@ class CancelOutStatus { // Cancels like terms in a fraction node // e.g. (2x^2 * 5) / 2x^2 => 5 / 1 -// Returns a Node.Status object +// Returns a mathNode.Status object +function cancelLikeTerms(node: any); function cancelLikeTerms(node) { - if (!Node.Type.isOperator(node) || node.op !== '/') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '/') { + return mathNode.Status.noChange(node); } let newNode = clone(node); const numerator = newNode.args[0]; @@ -30,7 +30,7 @@ function cancelLikeTerms(node) { !isMultiplicationOfTerms(denominator)) { const cancelStatus = cancelTerms(numerator, denominator); if (cancelStatus.hasChanged) { - newNode.args[0] = cancelStatus.numerator || Node.Creator.constant(1); + newNode.args[0] = cancelStatus.numerator || mathNode.Creator.constant(1); if (cancelStatus.denominator) { newNode.args[1] = cancelStatus.denominator; } @@ -39,11 +39,11 @@ function cancelLikeTerms(node) { // e.g. (2x*y) / 2x => y (note y isn't a fraction) newNode = newNode.args[0]; } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_TERMS, node, newNode); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } @@ -53,7 +53,7 @@ function cancelLikeTerms(node) { // away because we always adjust the exponent in the numerator) else if (isMultiplicationOfTerms(numerator) && !isMultiplicationOfTerms(denominator)) { - const numeratorArgs = Node.Type.isParenthesis(numerator) ? + const numeratorArgs = mathNode.Type.isParenthesis(numerator) ? numerator.content.args : numerator.args; for (let i = 0; i < numeratorArgs.length; i++) { const cancelStatus = cancelTerms(numeratorArgs[i], denominator); @@ -79,11 +79,11 @@ function cancelLikeTerms(node) { // e.g. (2x*y) / 2x => y (note y isn't a fraction) newNode = newNode.args[0]; } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_TERMS, node, newNode); } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // case 3: denominator is a multiplication of terms and numerator is not @@ -91,12 +91,12 @@ function cancelLikeTerms(node) { // e.g. x / (x^2*y) => x^(1-2) / y else if (isMultiplicationOfTerms(denominator) && !isMultiplicationOfTerms(numerator)) { - const denominatorArgs = Node.Type.isParenthesis(denominator) ? + const denominatorArgs = mathNode.Type.isParenthesis(denominator) ? denominator.content.args : denominator.args; for (let i = 0; i < denominatorArgs.length; i++) { const cancelStatus = cancelTerms(numerator, denominatorArgs[i]); if (cancelStatus.hasChanged) { - newNode.args[0] = cancelStatus.numerator || Node.Creator.constant(1); + newNode.args[0] = cancelStatus.numerator || mathNode.Creator.constant(1); if (cancelStatus.denominator) { denominatorArgs[i] = cancelStatus.denominator; } @@ -110,18 +110,18 @@ function cancelLikeTerms(node) { newNode.args[1] = denominatorArgs[0]; } } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_TERMS, node, newNode); } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // case 4: the numerator and denominator are both multiplications of terms else { - const numeratorArgs = Node.Type.isParenthesis(numerator) ? + const numeratorArgs = mathNode.Type.isParenthesis(numerator) ? numerator.content.args : numerator.args; - const denominatorArgs = Node.Type.isParenthesis(denominator) ? + const denominatorArgs = mathNode.Type.isParenthesis(denominator) ? denominator.content.args : denominator.args; for (let i = 0; i < numeratorArgs.length; i++) { for (let j = 0; j < denominatorArgs.length; j++) { @@ -153,12 +153,12 @@ function cancelLikeTerms(node) { newNode.args[1] = denominatorArgs[0]; } } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_TERMS, node, newNode); } } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } @@ -168,12 +168,13 @@ function cancelLikeTerms(node) { // Returns the new nodes for numerator and denominator with the common terms // removed. If the entire numerator or denominator is cancelled out, it is // returned as null. e.g. 4, 4x => null, x +function cancelTerms(numerator: any, denominator: any); function cancelTerms(numerator, denominator) { // Deal with unary minuses by recursing on the argument - if (Node.Type.isUnaryMinus(numerator)) { + if (mathNode.Type.isUnaryMinus(numerator)) { const cancelStatus = cancelTerms(numerator.args[0], denominator); if (!cancelStatus.numerator) { - numerator = Node.Creator.constant(-1); + numerator = mathNode.Creator.constant(-1); } else if (Negative.isNegative(cancelStatus.numerator)) { numerator = Negative.negate(cancelStatus.numerator); @@ -184,7 +185,7 @@ function cancelTerms(numerator, denominator) { denominator = cancelTerms.denominator; return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); } - if (Node.Type.isUnaryMinus(denominator)) { + if (mathNode.Type.isUnaryMinus(denominator)) { const cancelStatus = cancelTerms(numerator, denominator.args[0]); numerator = cancelStatus.numerator; if (cancelStatus.denominator) { @@ -196,14 +197,14 @@ function cancelTerms(numerator, denominator) { numerator = Negative.negate(numerator); } else { - numerator = Node.Creator.constant(-1); + numerator = mathNode.Creator.constant(-1); } } return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); } // Deal with parens similarily - if (Node.Type.isParenthesis(numerator)) { + if (mathNode.Type.isParenthesis(numerator)) { const cancelStatus = cancelTerms(numerator.content, denominator); if (cancelStatus.numerator) { numerator.content = cancelStatus.numerator; @@ -216,7 +217,7 @@ function cancelTerms(numerator, denominator) { denominator = cancelStatus.denominator; return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); } - if (Node.Type.isParenthesis(denominator)) { + if (mathNode.Type.isParenthesis(denominator)) { const cancelStatus = cancelTerms(numerator, denominator.content); if (cancelStatus.denominator) { denominator.content = cancelStatus.denominator; @@ -240,17 +241,17 @@ function cancelTerms(numerator, denominator) { // case 2: they're both exponent nodes with the same base // e.g. (2x+5)^8 and (2x+5)^2 - if (Node.Type.isOperator(numerator, '^') && - Node.Type.isOperator(denominator, '^') && + if (mathNode.Type.isOperator(numerator, '^') && + mathNode.Type.isOperator(denominator, '^') && print(numerator.args[0]) === print(denominator.args[0])) { const numeratorExponent = numerator.args[1]; let denominatorExponent = denominator.args[1]; // wrap the denominatorExponent in parens, in case it's complicated. // If the parens aren't needed, they'll be removed with // removeUnnecessaryParens at the end of this step. - denominatorExponent = Node.Creator.parenthesis(denominatorExponent); - const newExponent = Node.Creator.parenthesis( - Node.Creator.operator('-', [numeratorExponent, denominatorExponent])); + denominatorExponent = mathNode.Creator.parenthesis(denominatorExponent); + const newExponent = mathNode.Creator.parenthesis( + mathNode.Creator.operator('-', [numeratorExponent, denominatorExponent])); numerator.args[1] = newExponent; return new CancelOutStatus(numerator, null, true); } @@ -258,10 +259,10 @@ function cancelTerms(numerator, denominator) { // case 3: they're both polynomial terms, check if they have the same symbol // e.g. 4x^2 / 5x^2 => 4 / 5 // e.g. 4x^3 / 5x^2 => 4x^(3-2) / 5 - if (Node.PolynomialTerm.isPolynomialTerm(numerator) && - Node.PolynomialTerm.isPolynomialTerm(denominator)) { - const numeratorTerm = new Node.PolynomialTerm(numerator); - const denominatorTerm = new Node.PolynomialTerm(denominator); + if (mathNode.PolynomialTerm.isPolynomialTerm(numerator) && + mathNode.PolynomialTerm.isPolynomialTerm(denominator)) { + const numeratorTerm = new mathNode.PolynomialTerm(numerator); + const denominatorTerm = new mathNode.PolynomialTerm(denominator); if (numeratorTerm.getSymbolName() !== denominatorTerm.getSymbolName()) { return new CancelOutStatus(numerator, denominator); } @@ -275,10 +276,10 @@ function cancelTerms(numerator, denominator) { // wrap the denominatorExponent in parens, in case it's complicated. // If the parens aren't needed, they'll be removed with // removeUnnecessaryParens at the end of this step. - denominatorExponent = Node.Creator.parenthesis(denominatorExponent); - const newExponent = Node.Creator.parenthesis( - Node.Creator.operator('-', [numeratorExponent, denominatorExponent])); - numerator = Node.Creator.polynomialTerm( + denominatorExponent = mathNode.Creator.parenthesis(denominatorExponent); + const newExponent = mathNode.Creator.parenthesis( + mathNode.Creator.operator('-', [numeratorExponent, denominatorExponent])); + numerator = mathNode.Creator.polynomialTerm( numeratorTerm.getSymbolNode(), newExponent, numeratorTerm.getCoeffNode()); @@ -295,12 +296,13 @@ function cancelTerms(numerator, denominator) { // e.g. 2 + 6 => false // e.g. (2 * 6^y) => true // e.g. 2x^2 => false (polynomial terms are considered as one single term) +function isMultiplicationOfTerms(node: any); function isMultiplicationOfTerms(node) { - if (Node.Type.isParenthesis(node)) { + if (mathNode.Type.isParenthesis(node)) { return isMultiplicationOfTerms(node.content); } - return (Node.Type.isOperator(node, '*') && - !Node.PolynomialTerm.isPolynomialTerm(node)); + return (mathNode.Type.isOperator(node, '*') && + !mathNode.PolynomialTerm.isPolynomialTerm(node)); } -module.exports = cancelLikeTerms; +export = cancelLikeTerms; diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.js b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts similarity index 64% rename from lib/simplifyExpression/fractionsSearch/divideByGCD.js rename to lib/simplifyExpression/fractionsSearch/divideByGCD.ts index c225f68d..e350dd7e 100644 --- a/lib/simplifyExpression/fractionsSearch/divideByGCD.js +++ b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts @@ -1,8 +1,7 @@ -const math = require('mathjs'); - -const ChangeTypes = require('../../ChangeTypes'); -const evaluate = require('../../util/evaluate'); -const Node = require('../../node'); +import math = require('mathjs'); +import ChangeTypes = require('../../ChangeTypes'); +import evaluate = require('../../util/evaluate'); +const mathNode = require('../../node'); // Simplifies a fraction (with constant numerator and denominator) by dividing // the top and bottom by the GCD, if possible. @@ -12,14 +11,15 @@ const Node = require('../../node'); // Note that -4/5 doesn't need to be simplified. // Note that our goal is for the denominator to always be positive. If it // isn't, we can simplify signs. -// Returns a Node.Status object +// Returns a mathNode.Status object +function divideByGCD(fraction: any); function divideByGCD(fraction) { - if (!Node.Type.isOperator(fraction) || fraction.op !== '/') { - return Node.Status.noChange(fraction); + if (!mathNode.Type.isOperator(fraction) || fraction.op !== '/') { + return mathNode.Status.noChange(fraction); } // If it's not an integer fraction, all we can do is simplify signs - if (!Node.Type.isIntegerFraction(fraction, true)) { - return Node.Status.noChange(fraction); + if (!mathNode.Type.isIntegerFraction(fraction, true)) { + return mathNode.Status.noChange(fraction); } const numeratorValue = parseInt(evaluate(fraction.args[0])); @@ -37,22 +37,22 @@ function divideByGCD(fraction) { } if (gcd === 1) { - return Node.Status.noChange(fraction); + return mathNode.Status.noChange(fraction); } - const newNumeratorNode = Node.Creator.constant(numeratorValue/gcd); - const newDenominatorNode = Node.Creator.constant(denominatorValue/gcd); + const newNumeratorNode = mathNode.Creator.constant(numeratorValue/gcd); + const newDenominatorNode = mathNode.Creator.constant(denominatorValue/gcd); let newFraction; if (parseFloat(newDenominatorNode.value) === 1) { newFraction = newNumeratorNode; } else { - newFraction = Node.Creator.operator( + newFraction = mathNode.Creator.operator( '/', [newNumeratorNode, newDenominatorNode]); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_FRACTION, fraction, newFraction); } -module.exports = divideByGCD; +export = divideByGCD; diff --git a/lib/simplifyExpression/fractionsSearch/index.js b/lib/simplifyExpression/fractionsSearch/index.ts similarity index 63% rename from lib/simplifyExpression/fractionsSearch/index.js rename to lib/simplifyExpression/fractionsSearch/index.ts index 6650cd55..78a3f50b 100644 --- a/lib/simplifyExpression/fractionsSearch/index.js +++ b/lib/simplifyExpression/fractionsSearch/index.ts @@ -9,16 +9,14 @@ */ -const addConstantAndFraction = require('./addConstantAndFraction'); -const addConstantFractions = require('./addConstantFractions'); -const cancelLikeTerms = require('./cancelLikeTerms'); -const divideByGCD = require('./divideByGCD'); -const simplifyFractionSigns = require('./simplifyFractionSigns'); -const simplifyPolynomialFraction = require('./simplifyPolynomialFraction'); - -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); - +import addConstantAndFraction = require('./addConstantAndFraction'); +import addConstantFractions = require('./addConstantFractions'); +import cancelLikeTerms = require('./cancelLikeTerms'); +import divideByGCD = require('./divideByGCD'); +import simplifyFractionSigns = require('./simplifyFractionSigns'); +import simplifyPolynomialFraction = require('./simplifyPolynomialFraction'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); const SIMPLIFICATION_FUNCTIONS = [ // e.g. 2/3 + 5/6 addConstantFractions, @@ -36,7 +34,8 @@ const SIMPLIFICATION_FUNCTIONS = [ const search = TreeSearch.preOrder(simplifyFractions); -// Look for step(s) to perform on a node. Returns a Node.Status object. +// Look for step(s) to perform on a node. Returns a mathNode.Status object. +function simplifyFractions(node: any); function simplifyFractions(node) { for (let i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) { const nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node); @@ -47,8 +46,7 @@ function simplifyFractions(node) { node = nodeStatus.newNode; } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } - -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts similarity index 54% rename from lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js rename to lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts index 41d52bcf..7273b56e 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js +++ b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts @@ -1,18 +1,18 @@ -const clone = require('../../util/clone'); - -const ChangeTypes = require('../../ChangeTypes'); -const Negative = require('../../Negative'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import ChangeTypes = require('../../ChangeTypes'); +import Negative = require('../../Negative'); +const mathNode = require('../../node'); // Simplifies negative signs if possible // e.g. -1/-3 --> 1/3 4/-5 --> -4/5 // Note that -4/5 doesn't need to be simplified. // Note that our goal is for the denominator to always be positive. If it // isn't, we can simplify signs. -// Returns a Node.Status object +// Returns a mathNode.Status object +function simplifySigns(fraction: any); function simplifySigns(fraction) { - if (!Node.Type.isOperator(fraction) || fraction.op !== '/') { - return Node.Status.noChange(fraction); + if (!mathNode.Type.isOperator(fraction) || fraction.op !== '/') { + return mathNode.Status.noChange(fraction); } const oldFraction = clone(fraction); let numerator = fraction.args[0]; @@ -24,12 +24,12 @@ function simplifySigns(fraction) { ChangeTypes.CANCEL_MINUSES : ChangeTypes.SIMPLIFY_SIGNS; numerator = Negative.negate(numerator); - const newFraction = Node.Creator.operator('/', [numerator, denominator]); - return Node.Status.nodeChanged(changeType, oldFraction, newFraction); + const newFraction = mathNode.Creator.operator('/', [numerator, denominator]); + return mathNode.Status.nodeChanged(changeType, oldFraction, newFraction); } else { - return Node.Status.noChange(fraction); + return mathNode.Status.noChange(fraction); } } -module.exports = simplifySigns; +export = simplifySigns; diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts similarity index 55% rename from lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js rename to lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts index a130a4f9..bc92c32f 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts @@ -1,21 +1,22 @@ -const arithmeticSearch = require('../arithmeticSearch'); -const clone = require('../../util/clone'); -const divideByGCD = require('./divideByGCD'); -const Node = require('../../node'); +import arithmeticSearch = require('../arithmeticSearch'); +import clone = require('../../util/clone'); +import divideByGCD = require('./divideByGCD'); +const mathNode = require('../../node'); // Simplifies a polynomial term with a fraction as its coefficients. // e.g. 2x/4 --> x/2 10x/5 --> 2x // Also simplified negative signs // e.g. -y/-3 --> y/3 4x/-5 --> -4x/5 -// returns the new simplified node in a Node.Status object +// returns the new simplified node in a mathNode.Status object +function simplifyPolynomialFraction(node: any); function simplifyPolynomialFraction(node) { - if (!Node.PolynomialTerm.isPolynomialTerm(node)) { - return Node.Status.noChange(node); + if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { + return mathNode.Status.noChange(node); } - const polyNode = new Node.PolynomialTerm(clone(node)); + const polyNode = new mathNode.PolynomialTerm(clone(node)); if (!polyNode.hasFractionCoeff()) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const coefficientSimplifications = [ @@ -32,13 +33,13 @@ function simplifyPolynomialFraction(node) { newCoeff = null; } const exponentNode = polyNode.getExponentNode(); - const newNode = Node.Creator.polynomialTerm( + const newNode = mathNode.Creator.polynomialTerm( polyNode.getSymbolNode(), exponentNode, newCoeff); - return Node.Status.nodeChanged(newCoeffStatus.changeType, node, newNode); + return mathNode.Status.nodeChanged(newCoeffStatus.changeType, node, newNode); } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } -module.exports = simplifyPolynomialFraction; +export = simplifyPolynomialFraction; diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.js b/lib/simplifyExpression/functionsSearch/absoluteValue.js deleted file mode 100644 index aa4ab9b7..00000000 --- a/lib/simplifyExpression/functionsSearch/absoluteValue.js +++ /dev/null @@ -1,38 +0,0 @@ -const clone = require('../../util/clone'); -const math = require('mathjs'); - -const ChangeTypes = require('../../ChangeTypes'); -const evaluate = require('../../util/evaluate'); -const Node = require('../../node'); - -// Evaluates abs() function if it's on a single constant value. -// Returns a Node.Status object. -function absoluteValue(node) { - if (!Node.Type.isFunction(node, 'abs')) { - return Node.Status.noChange(node); - } - if (node.args.length > 1) { - return Node.Status.noChange(node); - } - let newNode = clone(node); - const argument = newNode.args[0]; - if (Node.Type.isConstant(argument, true)) { - newNode = Node.Creator.constant(math.abs(evaluate(argument))); - return Node.Status.nodeChanged( - ChangeTypes.ABSOLUTE_VALUE, node, newNode); - } - else if (Node.Type.isConstantFraction(argument, true)) { - const newNumerator = Node.Creator.constant( - math.abs(evaluate(argument.args[0]))); - const newDenominator = Node.Creator.constant( - math.abs(evaluate(argument.args[1]))); - newNode = Node.Creator.operator('/', [newNumerator, newDenominator]); - return Node.Status.nodeChanged( - ChangeTypes.ABSOLUTE_VALUE, node, newNode); - } - else { - return Node.Status.noChange(node); - } -} - -module.exports = absoluteValue; diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.ts b/lib/simplifyExpression/functionsSearch/absoluteValue.ts new file mode 100644 index 00000000..dbe2558f --- /dev/null +++ b/lib/simplifyExpression/functionsSearch/absoluteValue.ts @@ -0,0 +1,38 @@ +import clone = require('../../util/clone'); +import math = require('mathjs'); +import ChangeTypes = require('../../ChangeTypes'); +import evaluate = require('../../util/evaluate'); +const mathNode = require('../../node'); + +// Evaluates abs() function if it's on a single constant value. +// Returns a mathNode.Status object. +function absoluteValue(node: any); +function absoluteValue(node) { + if (!mathNode.Type.isFunction(node, 'abs')) { + return mathNode.Status.noChange(node); + } + if (node.args.length > 1) { + return mathNode.Status.noChange(node); + } + let newNode = clone(node); + const argument = newNode.args[0]; + if (mathNode.Type.isConstant(argument, true)) { + newNode = mathNode.Creator.constant(math.abs(evaluate(argument))); + return mathNode.Status.nodeChanged( + ChangeTypes.ABSOLUTE_VALUE, node, newNode); + } + else if (mathNode.Type.isConstantFraction(argument, true)) { + const newNumerator = mathNode.Creator.constant( + math.abs(evaluate(argument.args[0]))); + const newDenominator = mathNode.Creator.constant( + math.abs(evaluate(argument.args[1]))); + newNode = mathNode.Creator.operator('/', [newNumerator, newDenominator]); + return mathNode.Status.nodeChanged( + ChangeTypes.ABSOLUTE_VALUE, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} + +export = absoluteValue; diff --git a/lib/simplifyExpression/functionsSearch/index.js b/lib/simplifyExpression/functionsSearch/index.js deleted file mode 100644 index 95d11b25..00000000 --- a/lib/simplifyExpression/functionsSearch/index.js +++ /dev/null @@ -1,32 +0,0 @@ -const absoluteValue = require('./absoluteValue'); -const nthRoot = require('./nthRoot'); - -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); - -const FUNCTIONS = [ - nthRoot, - absoluteValue -]; - -// Searches through the tree, prioritizing deeper nodes, and evaluates -// functions (e.g. abs(-4)) if possible. -// Returns a Node.Status object. -const search = TreeSearch.postOrder(functions); - -// Evaluates a function call if possible. Returns a Node.Status object. -function functions(node) { - if (!Node.Type.isFunction(node)) { - return Node.Status.noChange(node); - } - - for (let i = 0; i < FUNCTIONS.length; i++) { - const nodeStatus = FUNCTIONS[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - } - return Node.Status.noChange(node); -} - -module.exports = search; diff --git a/lib/simplifyExpression/functionsSearch/index.ts b/lib/simplifyExpression/functionsSearch/index.ts new file mode 100644 index 00000000..2bf3d183 --- /dev/null +++ b/lib/simplifyExpression/functionsSearch/index.ts @@ -0,0 +1,31 @@ +import absoluteValue = require('./absoluteValue'); +import nthRoot = require('./nthRoot'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); +const FUNCTIONS = [ + nthRoot, + absoluteValue +]; + +// Searches through the tree, prioritizing deeper nodes, and evaluates +// functions (e.g. abs(-4)) if possible. +// Returns a mathNode.Status object. +const search = TreeSearch.postOrder(functions); + +// Evaluates a function call if possible. Returns a mathNode.Status object. +function functions(node: any); +function functions(node) { + if (!mathNode.Type.isFunction(node)) { + return mathNode.Status.noChange(node); + } + + for (let i = 0; i < FUNCTIONS.length; i++) { + const nodeStatus = FUNCTIONS[i](node); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + } + return mathNode.Status.noChange(node); +} + +export = search; diff --git a/lib/simplifyExpression/functionsSearch/nthRoot.js b/lib/simplifyExpression/functionsSearch/nthRoot.ts similarity index 66% rename from lib/simplifyExpression/functionsSearch/nthRoot.js rename to lib/simplifyExpression/functionsSearch/nthRoot.ts index bb747746..ecc29c61 100644 --- a/lib/simplifyExpression/functionsSearch/nthRoot.js +++ b/lib/simplifyExpression/functionsSearch/nthRoot.ts @@ -1,20 +1,20 @@ -const clone = require('../../util/clone'); -const math = require('mathjs'); - -const ChangeTypes = require('../../ChangeTypes'); -const ConstantFactors = require('../../factor/ConstantFactors'); -const Negative = require('../../Negative'); -const Node = require('../../node'); +import clone = require('../../util/clone'); +import math = require('mathjs'); +import ChangeTypes = require('../../ChangeTypes'); +import ConstantFactors = require('../../factor/ConstantFactors'); +import Negative = require('../../Negative'); +const mathNode = require('../../node'); // Evaluate nthRoot() function. -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function nthRoot(node: any); function nthRoot(node) { - if (!Node.Type.isFunction(node, 'nthRoot')) { - return Node.Status.noChange(node); + if (!mathNode.Type.isFunction(node, 'nthRoot')) { + return mathNode.Status.noChange(node); } const radicandNode = getRadicandNode(node); - if (Node.Type.isOperator(radicandNode)) { + if (mathNode.Type.isOperator(radicandNode)) { if (radicandNode.op === '^') { return nthRootExponent(node); } @@ -22,11 +22,11 @@ function nthRoot(node) { return nthRootMultiplication(node); } } - else if (Node.Type.isConstant(radicandNode)) { + else if (mathNode.Type.isConstant(radicandNode)) { return nthRootConstant(node); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Returns the nthRoot evaluated for an exponent node. Expects an exponent under @@ -34,41 +34,42 @@ function nthRoot(node) { // equal: nthRoot(2^x, x) = 2 // root > exponent: nthRoot(x^2, 4) = nthRoot(x, 2) // exponent > root: nthRoot(x^4, 2) = x^2 +function nthRootExponent(node: any); function nthRootExponent(node) { let newNode = clone(node); const radicandNode = getRadicandNode(node); const rootNode = getRootNode(node); const baseNode = radicandNode.args[0]; - const exponentNode = Node.Type.isParenthesis(radicandNode.args[1]) ? + const exponentNode = mathNode.Type.isParenthesis(radicandNode.args[1]) ? radicandNode.args[1].content : radicandNode.args[1]; if (rootNode.equals(exponentNode)) { newNode = baseNode; - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_EXPONENT_AND_ROOT, node, newNode); } - else if (Node.Type.isConstant(rootNode) && Node.Type.isConstant(exponentNode)) { + else if (mathNode.Type.isConstant(rootNode) && mathNode.Type.isConstant(exponentNode)) { const rootValue = parseFloat(rootNode.value); const exponentValue = parseFloat(exponentNode.value); if (rootValue % exponentValue === 0) { const newRootValue = rootValue/exponentValue; - const newRootNode = Node.Creator.constant(newRootValue); + const newRootNode = mathNode.Creator.constant(newRootValue); - newNode = Node.Creator.nthRoot(baseNode, newRootNode); - return Node.Status.nodeChanged( + newNode = mathNode.Creator.nthRoot(baseNode, newRootNode); + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_EXPONENT, node, newNode); } else if (exponentValue % rootValue === 0) { const newExponentValue = exponentValue/rootValue; - const newExponentNode = Node.Creator.constant(newExponentValue); + const newExponentNode = mathNode.Creator.constant(newExponentValue); - newNode = Node.Creator.operator('^', [baseNode, newExponentNode]); - return Node.Status.nodeChanged( + newNode = mathNode.Creator.operator('^', [baseNode, newExponentNode]); + return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_ROOT, node, newNode); } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Returns the nthRoot evaluated for a multiplication node. @@ -81,36 +82,37 @@ function nthRootExponent(node) { // 2A: Distributes the nthRoot into the children nodes, // 2B: evaluates those nthRoots // 2C: combines them +function nthRootMultiplication(node: any); function nthRootMultiplication(node) { let newNode = clone(node); const rootNode = getRootNode(node); const substeps = []; let status; - if (Node.Type.isConstant(rootNode) && !Negative.isNegative(rootNode)) { + if (mathNode.Type.isConstant(rootNode) && !Negative.isNegative(rootNode)) { // Step 1A status = factorMultiplicands(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // Step 1B status = groupTermsByRoot(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } // Step 1C status = convertMultiplicationToExponent(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); if (newNode.args[0].op === '^') { status = nthRootExponent(newNode); substeps.push(status); - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.NTH_ROOT_VALUE, node, status.newNode, true, substeps); } } @@ -119,31 +121,32 @@ function nthRootMultiplication(node) { // Step 2A status = distributeNthRoot(newNode); substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // Step 2B status = evaluateNthRootForChildren(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); // Step 2C status = combineRoots(newNode); if (status.hasChanged()) { substeps.push(status); - newNode = Node.Status.resetChangeGroups(status.newNode); + newNode = mathNode.Status.resetChangeGroups(status.newNode); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.NTH_ROOT_VALUE, node, newNode, true, substeps); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Given an nthRoot node with a constant positive root, will do the step of // factoring all the multiplicands under the radicand // e.g. nthRoot(2 * 9 * 5 * 12) = nthRoot(2 * 3 * 3 * 5 * 2 * 2 * 3) +function factorMultiplicands(node: any); function factorMultiplicands(node) { const newNode = clone(node); const radicandNode = getRadicandNode(node); @@ -151,10 +154,10 @@ function factorMultiplicands(node) { let children = []; let factored = false; radicandNode.args.forEach(child => { - if (Node.PolynomialTerm.isPolynomialTerm(child)) { - const polyTerm = new Node.PolynomialTerm(child); + if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { + const polyTerm = new mathNode.PolynomialTerm(child); const coeffNode = polyTerm.getCoeffNode(); - const polyTermNoCoeff = Node.Creator.polynomialTerm( + const polyTermNoCoeff = mathNode.Creator.polynomialTerm( polyTerm.getSymbolNode(), polyTerm.getExponentNode(), null); if (coeffNode) { const factorNodes = getFactorNodes(coeffNode); @@ -175,19 +178,20 @@ function factorMultiplicands(node) { }); if (factored) { - newNode.args[0] = Node.Creator.operator('*', children); - return Node.Status.nodeChanged( + newNode.args[0] = mathNode.Creator.operator('*', children); + return mathNode.Status.nodeChanged( ChangeTypes.FACTOR_INTO_PRIMES, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } +function getFactorNodes(node: any); function getFactorNodes(node) { - if (Node.Type.isConstant(node) && !Negative.isNegative(node)) { + if (mathNode.Type.isConstant(node) && !Negative.isNegative(node)) { const value = parseFloat(node.value); const factors = ConstantFactors.getPrimeFactors(value); - const factorNodes = factors.map(Node.Creator.constant); + const factorNodes = factors.map(mathNode.Creator.constant); return factorNodes; } return [node]; @@ -196,6 +200,7 @@ function getFactorNodes(node) { // Given an nthRoot node with a constant positive root, will group the arguments // into groups of the root as a step // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2, 2) +function groupTermsByRoot(node: any); function groupTermsByRoot(node) { const newNode = clone(node); const radicandNode = getRadicandNode(node); @@ -219,8 +224,8 @@ function groupTermsByRoot(node) { } if (j - i === rootValue) { hasGroups = true; - const groupedNode = Node.Creator.parenthesis( - Node.Creator.operator('*', radicandNode.args.slice(i, j))); + const groupedNode = mathNode.Creator.parenthesis( + mathNode.Creator.operator('*', radicandNode.args.slice(i, j))); children.push(groupedNode); } else { @@ -231,58 +236,60 @@ function groupTermsByRoot(node) { if (hasGroups) { newNode.args[0] = children.length === 1 ? - children[0] : Node.Creator.operator('*', children); - return Node.Status.nodeChanged( + children[0] : mathNode.Creator.operator('*', children); + return mathNode.Status.nodeChanged( ChangeTypes.GROUP_TERMS_BY_ROOT, node, newNode); } // if we don't group any factors, then we can't simplify it any more - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Given an nthRoot node with a constant positive root, // will convert any grouped factors into exponent nodes as a step // e.g. nthRoot((2 * 2) * 2, 2) -> nthRoot(2^2 * 2, 2) +function convertMultiplicationToExponent(node: any); function convertMultiplicationToExponent(node) { const newNode = clone(node); const radicandNode = getRadicandNode(node); - if (Node.Type.isParenthesis(radicandNode)) { + if (mathNode.Type.isParenthesis(radicandNode)) { const child = radicandNode.content; if (isMultiplicationOfEqualNodes(child)) { const baseNode = child.args[0]; - const exponentNode = Node.Creator.constant(child.args.length); - newNode.args[0] = Node.Creator.operator('^', [baseNode, exponentNode]); - return Node.Status.nodeChanged( + const exponentNode = mathNode.Creator.constant(child.args.length); + newNode.args[0] = mathNode.Creator.operator('^', [baseNode, exponentNode]); + return mathNode.Status.nodeChanged( ChangeTypes.CONVERT_MULTIPLICATION_TO_EXPONENT, node, newNode); } } - else if (Node.Type.isOperator(radicandNode, '*')) { + else if (mathNode.Type.isOperator(radicandNode, '*')) { const children = []; radicandNode.args.forEach(child => { - if (Node.Type.isParenthesis(child)) { + if (mathNode.Type.isParenthesis(child)) { const grandChild = child.content; if (isMultiplicationOfEqualNodes(grandChild)) { const baseNode = grandChild.args[0]; - const exponentNode = Node.Creator.constant(grandChild.args.length); - children.push(Node.Creator.operator('^', [baseNode, exponentNode])); + const exponentNode = mathNode.Creator.constant(grandChild.args.length); + children.push(mathNode.Creator.operator('^', [baseNode, exponentNode])); return; } } children.push(child); }); - newNode.args[0] = Node.Creator.operator('*', children); - return Node.Status.nodeChanged( + newNode.args[0] = mathNode.Creator.operator('*', children); + return mathNode.Status.nodeChanged( ChangeTypes.CONVERT_MULTIPLICATION_TO_EXPONENT, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Given an nthRoot node with a multiplication under the radicand, will // distribute the nthRoot to all the arguments under the radicand as a step // e.g. nthRoot(2 * x^2, 2) -> nthRoot(2) * nthRoot(x^2) +function distributeNthRoot(node: any); function distributeNthRoot(node) { let newNode = clone(node); const radicandNode = getRadicandNode(node); @@ -291,17 +298,18 @@ function distributeNthRoot(node) { const children = []; for (let i = 0; i < radicandNode.args.length; i++) { const child = radicandNode.args[i]; - children.push(Node.Creator.nthRoot(child, rootNode)); + children.push(mathNode.Creator.nthRoot(child, rootNode)); } - newNode = Node.Creator.operator('*', children); - return Node.Status.nodeChanged( + newNode = mathNode.Creator.operator('*', children); + return mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE_NTH_ROOT, node, newNode); } // Given a multiplication node of nthRoots (with the same root) // will evaluate the nthRoot of each child as a substep // e.g. nthRoot(2) * nthRoot(x^2) -> nthRoot(2) * x +function evaluateNthRootForChildren(node: any); function evaluateNthRootForChildren(node) { const newNode = clone(node); @@ -311,18 +319,18 @@ function evaluateNthRootForChildren(node) { const childNodeStatus = nthRoot(child); if (childNodeStatus.hasChanged()) { newNode.args[i] = childNodeStatus.newNode; - substeps.push(Node.Status.childChanged(newNode, childNodeStatus, i)); + substeps.push(mathNode.Status.childChanged(newNode, childNodeStatus, i)); } } if (substeps.length === 0) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } else if (substeps.length === 1) { return substeps[0]; } else { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.EVALUATE_DISTRIBUTED_NTH_ROOT, node, newNode, true, substeps); } } @@ -332,6 +340,7 @@ function evaluateNthRootForChildren(node) { // e.g. 2 * nthRoot(2) * nthRoot(x) -> 2 * nthRoot(2 * x) // Assumes that all the roots are the same (that this is occuring right // after distributeNthRoot and evaluateNthRootForChildren) +function combineRoots(node: any); function combineRoots(node) { let newNode = clone(node); @@ -340,7 +349,7 @@ function combineRoots(node) { const radicandArgs = []; for (let i = 0; i < newNode.args.length; i++) { const child = newNode.args[i]; - if (Node.Type.isFunction(child, 'nthRoot')) { + if (mathNode.Type.isFunction(child, 'nthRoot')) { radicandArgs.push(child.args[0]); rootNode = getRootNode(child); } @@ -352,34 +361,35 @@ function combineRoots(node) { if (children.length > 0) { if (radicandArgs.length > 0) { const radicandNode = radicandArgs.length === 1 ? - radicandArgs[0] : Node.Creator.operator('*', radicandArgs); - children.push(Node.Creator.nthRoot(radicandNode, rootNode)); + radicandArgs[0] : mathNode.Creator.operator('*', radicandArgs); + children.push(mathNode.Creator.nthRoot(radicandNode, rootNode)); } - newNode = Node.Creator.operator('*', children); + newNode = mathNode.Creator.operator('*', children); if (!newNode.equals(node)) { - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.COMBINE_UNDER_ROOT, node, newNode); } } // if there are no items moved out of the root, then nothing has changed - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Returns the nthRoot evaluated on a constant node // Potentially factors the constant node into primes, and calls // nthRootMultiplication on the new nthRoot +function nthRootConstant(node: any); function nthRootConstant(node) { let newNode = clone(node); const radicandNode = getRadicandNode(node); const rootNode = getRootNode(node); if (Negative.isNegative(radicandNode)) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } - else if (!Node.Type.isConstant(rootNode) || Negative.isNegative(rootNode)) { - return Node.Status.noChange(node); + else if (!mathNode.Type.isConstant(rootNode) || Negative.isNegative(rootNode)) { + return mathNode.Status.noChange(node); } const radicandValue = parseFloat(radicandNode.value); @@ -387,8 +397,8 @@ function nthRootConstant(node) { const nthRootValue = math.nthRoot(radicandValue, rootValue); // Perfect root e.g. nthRoot(4, 2) = 2 if (nthRootValue % 1 === 0) { - newNode = Node.Creator.constant(nthRootValue); - return Node.Status.nodeChanged( + newNode = mathNode.Creator.constant(nthRootValue); + return mathNode.Status.nodeChanged( ChangeTypes.NTH_ROOT_VALUE, node, newNode); } // Try to find if we can simplify by finding factors that can be @@ -398,10 +408,10 @@ function nthRootConstant(node) { const factors = ConstantFactors.getPrimeFactors(radicandValue); if (factors.length > 1) { let substeps = []; - const factorNodes = factors.map(Node.Creator.constant); + const factorNodes = factors.map(mathNode.Creator.constant); - newNode.args[0] = Node.Creator.operator('*', factorNodes); - substeps.push(Node.Status.nodeChanged( + newNode.args[0] = mathNode.Creator.operator('*', factorNodes); + substeps.push(mathNode.Status.nodeChanged( ChangeTypes.FACTOR_INTO_PRIMES, node, newNode)); // run nthRoot on the new node @@ -410,13 +420,13 @@ function nthRootConstant(node) { substeps = substeps.concat(nodeStatus.substeps); newNode = nodeStatus.newNode; - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.NTH_ROOT_VALUE, node, newNode, true, substeps); } } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Helpers @@ -424,17 +434,19 @@ function nthRootConstant(node) { // Given an nthRoot node, will return the root node. // The root node is the second child of the nthRoot node, but if one doesn't // exist, we assume it's a square root and return 2. +function getRootNode(node: any); function getRootNode(node) { - if (!Node.Type.isFunction(node, 'nthRoot')) { + if (!mathNode.Type.isFunction(node, 'nthRoot')) { throw Error('Expected nthRoot'); } - return node.args.length === 2 ? node.args[1] : Node.Creator.constant(2); + return node.args.length === 2 ? node.args[1] : mathNode.Creator.constant(2); } // Given an nthRoot node, will return the radicand node. +function getRadicandNode(node: any); function getRadicandNode(node) { - if (!Node.Type.isFunction(node, 'nthRoot')) { + if (!mathNode.Type.isFunction(node, 'nthRoot')) { throw Error('Expected nthRoot'); } @@ -443,14 +455,15 @@ function getRadicandNode(node) { // Sorts nodes, ordering constants nodes from smallest to largest and symbol // nodes after +function sortNodes(a: any, b: any); function sortNodes(a, b) { - if (Node.Type.isConstant(a) && Node.Type.isConstant(b)) { + if (mathNode.Type.isConstant(a) && mathNode.Type.isConstant(b)) { return parseFloat(a.value) - parseFloat(b.value); } - else if (Node.Type.isConstant(a)) { + else if (mathNode.Type.isConstant(a)) { return -1; } - else if (Node.Type.isConstant(b)) { + else if (mathNode.Type.isConstant(b)) { return 1; } return 0; @@ -458,8 +471,9 @@ function sortNodes(a, b) { // Simple helper function which determines a node is a multiplication node // of all equal nodes +function isMultiplicationOfEqualNodes(node: any); function isMultiplicationOfEqualNodes(node) { - if (!Node.Type.isOperator(node) || node.op !== '*') { + if (!mathNode.Type.isOperator(node) || node.op !== '*') { return false; } @@ -470,4 +484,4 @@ function isMultiplicationOfEqualNodes(node) { } -module.exports = nthRoot; +export = nthRoot; diff --git a/lib/simplifyExpression/index.js b/lib/simplifyExpression/index.ts similarity index 67% rename from lib/simplifyExpression/index.js rename to lib/simplifyExpression/index.ts index ab919afb..d9ca4744 100644 --- a/lib/simplifyExpression/index.js +++ b/lib/simplifyExpression/index.ts @@ -1,5 +1,5 @@ -const math = require('mathjs'); -const stepThrough = require('./stepThrough'); +import math = require('mathjs'); +import stepThrough = require('./stepThrough'); function simplifyExpressionString(expressionString, debug=false) { let exprNode; @@ -15,4 +15,4 @@ function simplifyExpressionString(expressionString, debug=false) { return []; } -module.exports = simplifyExpressionString; +export = simplifyExpressionString; diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js b/lib/simplifyExpression/multiplyFractionsSearch/index.ts similarity index 59% rename from lib/simplifyExpression/multiplyFractionsSearch/index.js rename to lib/simplifyExpression/multiplyFractionsSearch/index.ts index e19165d9..3b9f497d 100644 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.js +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.ts @@ -1,6 +1,6 @@ -const ChangeTypes = require('../../ChangeTypes'); -const Node = require('../../node'); -const TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require('../../ChangeTypes'); +const mathNode = require('../../node'); +import TreeSearch = require('../../TreeSearch'); // If `node` is a product of terms where some are fractions (but none are // polynomial terms), multiplies them together. @@ -10,30 +10,31 @@ const TreeSearch = require('../../TreeSearch'); // denominator (so the 5s would cancel out on the next step after this) // This step must happen after things have been distributed, or else the answer // will be formatted badly, so it's a tree search of its own. -// Returns a Node.Status object. +// Returns a mathNode.Status object. const search = TreeSearch.postOrder(multiplyFractions); // If `node` is a product of terms where some are fractions (but none are // polynomial terms), multiplies them together. // e.g. 2 * 5/x -> (2*5)/x // e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) -// Returns a Node.Status object. +// Returns a mathNode.Status object. +function multiplyFractions(node: any); function multiplyFractions(node) { - if (!Node.Type.isOperator(node) || node.op !== '*') { - return Node.Status.noChange(node); + if (!mathNode.Type.isOperator(node) || node.op !== '*') { + return mathNode.Status.noChange(node); } const atLeastOneFraction = node.args.some( - arg => Node.Type.isOperator(arg, '/')); + arg => mathNode.Type.isOperator(arg, '/')); const hasPolynomialTerms = node.args.some( - arg => Node.PolynomialTerm.isPolynomialTerm(arg)); + arg => mathNode.PolynomialTerm.isPolynomialTerm(arg)); if (!atLeastOneFraction || hasPolynomialTerms) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const numeratorArgs = []; const denominatorArgs = []; node.args.forEach(operand => { - if (Node.Type.isOperator(operand, '/')) { + if (mathNode.Type.isOperator(operand, '/')) { numeratorArgs.push(operand.args[0]); denominatorArgs.push(operand.args[1]); } @@ -42,15 +43,15 @@ function multiplyFractions(node) { } }); - const newNumerator = Node.Creator.parenthesis( - Node.Creator.operator('*', numeratorArgs)); + const newNumerator = mathNode.Creator.parenthesis( + mathNode.Creator.operator('*', numeratorArgs)); const newDenominator = denominatorArgs.length === 1 ? denominatorArgs[0] - : Node.Creator.parenthesis(Node.Creator.operator('*', denominatorArgs)); + : mathNode.Creator.parenthesis(mathNode.Creator.operator('*', denominatorArgs)); - const newNode = Node.Creator.operator('/', [newNumerator, newDenominator]); - return Node.Status.nodeChanged( + const newNode = mathNode.Creator.operator('/', [newNumerator, newDenominator]); + return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_FRACTIONS, node, newNode); } -module.exports = search; +export = search; diff --git a/lib/simplifyExpression/simplify.js b/lib/simplifyExpression/simplify.js index 37090a16..5b3294d3 100644 --- a/lib/simplifyExpression/simplify.js +++ b/lib/simplifyExpression/simplify.js @@ -1,37 +1,31 @@ -const math = require('mathjs'); - -const checks = require('../checks'); -const flattenOperands = require('../util/flattenOperands'); -const print = require('../util/print'); -const removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); -const stepThrough = require('./stepThrough'); - - +"use strict"; +var math = require("mathjs"); +var checks = require("../checks"); +var flattenOperands = require("../util/flattenOperands"); +var print = require("../util/print"); +var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); +var stepThrough = require("./stepThrough"); // Given a mathjs expression node, steps through simplifying the expression. // Returns the simplified expression node. -function simplify(node, debug=false) { - if (checks.hasUnsupportedNodes(node)) { - return node; - } - - const steps = stepThrough(node, debug); - let simplifiedNode; - if (steps.length > 0) { - simplifiedNode = steps.pop().newNode; - } - else { - // removing parens isn't counted as a step, so try it here - simplifiedNode = removeUnnecessaryParens(flattenOperands(node), true); - } - // unflatten the node. - return unflatten(simplifiedNode); +function simplify(node, debug) { + if (debug === void 0) { debug = false; } + if (checks.hasUnsupportedNodes(node)) { + return node; + } + var steps = stepThrough(node, debug); + var simplifiedNode; + if (steps.length > 0) { + simplifiedNode = steps.pop().newNode; + } + else { + // removing parens isn't counted as a step, so try it here + simplifiedNode = removeUnnecessaryParens(flattenOperands(node), true); + } + // unflatten the node. + return unflatten(simplifiedNode); } - -// Unflattens a node so it is in the math.js style, by printing and parsing it -// again function unflatten(node) { - return math.parse(print(node)); + return math.parse(print(node)); } - - module.exports = simplify; +//# sourceMappingURL=simplify.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/simplify.js.map b/lib/simplifyExpression/simplify.js.map new file mode 100644 index 00000000..aaa0a9f0 --- /dev/null +++ b/lib/simplifyExpression/simplify.js.map @@ -0,0 +1 @@ +{"version":3,"file":"simplify.js","sourceRoot":"","sources":["simplify.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,kCAAqC;AACrC,yDAA4D;AAC5D,qCAAwC;AACxC,yEAA4E;AAC5E,2CAA8C;AAG9C,4EAA4E;AAC5E,0CAA0C;AAC1C,kBAAkB,IAAI,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IACjC,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IAED,IAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvC,IAAI,cAAc,CAAC;IACnB,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,cAAc,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;IACvC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,0DAA0D;QAC1D,cAAc,GAAG,uBAAuB,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;IACD,sBAAsB;IACtB,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AACnC,CAAC;AAKD,mBAAmB,IAAI;IACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/simplify.ts b/lib/simplifyExpression/simplify.ts new file mode 100644 index 00000000..7687b297 --- /dev/null +++ b/lib/simplifyExpression/simplify.ts @@ -0,0 +1,36 @@ +import math = require('mathjs'); +import checks = require('../checks'); +import flattenOperands = require('../util/flattenOperands'); +import print = require('../util/print'); +import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); +import stepThrough = require('./stepThrough'); + + +// Given a mathjs expression node, steps through simplifying the expression. +// Returns the simplified expression node. +function simplify(node, debug=false) { + if (checks.hasUnsupportedNodes(node)) { + return node; + } + + const steps = stepThrough(node, debug); + let simplifiedNode; + if (steps.length > 0) { + simplifiedNode = steps.pop().newNode; + } + else { + // removing parens isn't counted as a step, so try it here + simplifiedNode = removeUnnecessaryParens(flattenOperands(node), true); + } + // unflatten the node. + return unflatten(simplifiedNode); +} + +// Unflattens a node so it is in the math.js style, by printing and parsing it +// again +function unflatten(node: any); +function unflatten(node) { + return math.parse(print(node)); +} + +export = simplify; diff --git a/lib/simplifyExpression/stepThrough.js b/lib/simplifyExpression/stepThrough.ts similarity index 76% rename from lib/simplifyExpression/stepThrough.js rename to lib/simplifyExpression/stepThrough.ts index 9a5dad53..5e4353c9 100644 --- a/lib/simplifyExpression/stepThrough.js +++ b/lib/simplifyExpression/stepThrough.ts @@ -1,21 +1,19 @@ -const checks = require('../checks'); -const Node = require('../node'); +import checks = require('../checks'); +const mathNode = require('../node'); const Status = require('../node/Status'); - -const arithmeticSearch = require('./arithmeticSearch'); -const basicsSearch = require('./basicsSearch'); -const breakUpNumeratorSearch = require('./breakUpNumeratorSearch'); -const collectAndCombineSearch = require('./collectAndCombineSearch'); -const distributeSearch = require('./distributeSearch'); -const divisionSearch = require('./divisionSearch'); -const fractionsSearch = require('./fractionsSearch'); -const functionsSearch = require('./functionsSearch'); -const multiplyFractionsSearch = require('./multiplyFractionsSearch'); - -const clone = require('../util/clone'); -const flattenOperands = require('../util/flattenOperands'); -const print = require('../util/print'); -const removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); +import arithmeticSearch = require('./arithmeticSearch'); +import basicsSearch = require('./basicsSearch'); +import breakUpNumeratorSearch = require('./breakUpNumeratorSearch'); +import collectAndCombineSearch = require('./collectAndCombineSearch'); +import distributeSearch = require('./distributeSearch'); +import divisionSearch = require('./divisionSearch'); +import fractionsSearch = require('./fractionsSearch'); +import functionsSearch = require('./functionsSearch'); +import multiplyFractionsSearch = require('./multiplyFractionsSearch'); +import clone = require('../util/clone'); +import flattenOperands = require('../util/flattenOperands'); +import print = require('../util/print'); +import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); // Given a mathjs expression node, steps through simplifying the expression. // Returns a list of details about each step. @@ -57,7 +55,8 @@ function stepThrough(node, debug=false) { } // Given a mathjs expression node, performs a single step to simplify the -// expression. Returns a Node.Status object. +// expression. Returns a mathNode.Status object. +function step(node: any); function step(node) { let nodeStatus; @@ -102,11 +101,12 @@ function step(node) { node = flattenOperands(node); } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Removes unnecessary parens throughout the steps. // TODO: Ideally this would happen in NodeStatus instead. +function removeUnnecessaryParensInStep(nodeStatus: any); function removeUnnecessaryParensInStep(nodeStatus) { if (nodeStatus.substeps.length > 0) { nodeStatus.substeps.map(removeUnnecessaryParensInStep); @@ -117,6 +117,7 @@ function removeUnnecessaryParensInStep(nodeStatus) { return nodeStatus; } +function logSteps(nodeStatus: any); function logSteps(nodeStatus) { // eslint-disable-next-line console.log(nodeStatus.changeType); @@ -130,4 +131,4 @@ function logSteps(nodeStatus) { } } -module.exports = stepThrough; +export = stepThrough; diff --git a/lib/solveEquation/EquationOperations.js b/lib/solveEquation/EquationOperations.js deleted file mode 100644 index 78d29a19..00000000 --- a/lib/solveEquation/EquationOperations.js +++ /dev/null @@ -1,232 +0,0 @@ -// Operations on equation nodes - -const ChangeTypes = require('../ChangeTypes'); -const clone = require('../util/clone'); -const Equation = require('../equation/Equation'); -const EquationStatus = require('../equation/Status'); -const Negative = require('../Negative'); -const Node = require('../node'); -const Symbols = require('../Symbols'); - -const COMPARATOR_TO_INVERSE = { - '>': '<', - '>=': '<=', - '<': '>', - '<=': '>=', - '=': '=' -}; - -const EquationOperations = {}; - -// Ensures that the given equation has the given symbolName on the left side, -// by swapping the right and left sides if it is only in the right side. -// So 3 = x would become x = 3. -EquationOperations.ensureSymbolInLeftNode = function(equation, symbolName) { - const leftSideSymbolTerm = Symbols.getLastSymbolTerm( - equation.leftNode, symbolName); - const rightSideSymbolTerm = Symbols.getLastSymbolTerm( - equation.rightNode, symbolName); - - if (!leftSideSymbolTerm) { - if (rightSideSymbolTerm) { - const comparator = COMPARATOR_TO_INVERSE[equation.comparator]; - const oldEquation = equation; - const newEquation = new Equation( - equation.rightNode, equation.leftNode, comparator); - // no change groups are set for this step because everything changes, so - // they wouldn't be pedagogically helpful. - return new EquationStatus( - ChangeTypes.SWAP_SIDES, oldEquation, newEquation); - } - else { - throw Error('No term with symbol: ' + symbolName); - } - } - return EquationStatus.noChange(equation); -}; - -// TODO: Ensures that a symbol is not in the denominator by multiplying -// both sides by the whatever order of the symbol necessary. -// This is blocked on the simplifying functionality of canceling symbols in -// fractions (needs factoring for full canceling support) -EquationOperations.removeSymbolFromDenominator = function(equation) { - // pass for now - return EquationStatus.noChange(equation); -}; - -// Removes the given symbolName from the right side by adding or subtracting -// it from both sides as appropriate. -// e.g. 2x = 3x + 5 --> 2x - 3x = 5 -// There are actually no cases where we'd remove symbols from the right side -// by multiplying or dividing by a symbol term. -// TODO: support inverting functions e.g. sqrt, ^, log etc. -EquationOperations.removeSymbolFromRightSide = function(equation, symbolName) { - const rightNode = equation.rightNode; - let symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); - - let inverseOp, inverseTerm, changeType; - if (!symbolTerm){ - return EquationStatus.noChange(equation); - } - - // Clone it so that any operations on it don't affect the node already - // in the equation - symbolTerm = clone(symbolTerm); - - if (Node.PolynomialTerm.isPolynomialTerm(rightNode)) { - if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } - else { - inverseOp = '-'; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } - else if (Node.Type.isOperator(rightNode)) { - if (rightNode.op === '+') { - if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } - else { - inverseOp = '-'; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } - else { - // Note that operator '-' won't show up here because subtraction is - // flattened into adding the negative. See 'TRICKY catch' in the README - // for more details. - throw Error('Unsupported operation: ' + symbolTerm.op); - } - } - else if (Node.Type.isUnaryMinus(rightNode)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = symbolTerm.args[0]; - } - else { - throw Error('Unsupported node type: ' + rightNode.type); - } - return performTermOperationOnEquation( - equation, inverseOp, inverseTerm, changeType); -}; - -// Isolates the given symbolName to the left side by adding, multiplying, subtracting -// or dividing all other symbols and constants from both sides appropriately -// TODO: support inverting functions e.g. sqrt, ^, log etc. -EquationOperations.isolateSymbolOnLeftSide = function(equation, symbolName) { - const leftNode = equation.leftNode; - let nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); - - let inverseOp, inverseTerm, changeType; - if (!nonSymbolTerm) { - return EquationStatus.noChange(equation); - } - - // Clone it so that any operations on it don't affect the node already - // in the equation - nonSymbolTerm = clone(nonSymbolTerm); - - if (Node.Type.isOperator(leftNode)) { - if (leftNode.op === '+') { - if (Negative.isNegative(nonSymbolTerm)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(nonSymbolTerm); - } - else { - inverseOp = '-'; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } - else if (leftNode.op === '*') { - if (Node.Type.isConstantFraction(nonSymbolTerm)) { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = Node.Creator.operator( - '/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - else { - inverseOp = '/'; - changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } - else if (leftNode.op === '/') { - // The non symbol term is always a fraction because it's the - // coefficient of our symbol term. - // If the numerator is 1, we multiply both sides by the denominator, - // otherwise we multiply by the inverse - if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; - inverseTerm = nonSymbolTerm.args[1]; - } - else { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = Node.Creator.operator( - '/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - } - else if (leftNode.op === '^') { - // TODO: support roots - return EquationStatus.noChange(equation); - } - else { - throw Error('Unsupported operation: ' + leftNode.op); - } - } - else if (Node.Type.isUnaryMinus(leftNode)) { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; - inverseTerm = Node.Creator.constant(-1); - } - else { - throw Error('Unsupported node type: ' + leftNode.type); - } - - return performTermOperationOnEquation( - equation, inverseOp, inverseTerm, changeType); -}; - -// Modifies the left and right sides of an equation by `op`-ing `term` -// to both sides. Returns an Status object. -function performTermOperationOnEquation(equation, op, term, changeType) { - const oldEquation = equation.clone(); - - const leftTerm = clone(term); - const rightTerm = clone(term); - const leftNode = performTermOperationOnExpression( - equation.leftNode, op, leftTerm); - const rightNode = performTermOperationOnExpression( - equation.rightNode, op, rightTerm); - - let comparator = equation.comparator; - if (Negative.isNegative(term) && (op === '*' || op === '/')) { - comparator = COMPARATOR_TO_INVERSE[comparator]; - } - - const newEquation = new Equation(leftNode, rightNode, comparator); - return new EquationStatus(changeType, oldEquation, newEquation); -} - -// Performs an operation of a term on an entire given expression -function performTermOperationOnExpression(expression, op, term) { - const node = (Node.Type.isOperator(expression) ? - Node.Creator.parenthesis(expression) : expression); - - term.changeGroup = 1; - const newNode = Node.Creator.operator(op, [node, term]); - - return newNode; -} - -module.exports = EquationOperations; diff --git a/lib/solveEquation/EquationOperations.ts b/lib/solveEquation/EquationOperations.ts new file mode 100644 index 00000000..ba683510 --- /dev/null +++ b/lib/solveEquation/EquationOperations.ts @@ -0,0 +1,230 @@ +// Operations on equation nodes + +import ChangeTypes = require('../ChangeTypes'); +import clone = require('../util/clone'); +import Equation = require('../equation/Equation'); +import EquationStatus = require('../equation/Status'); +import Negative = require('../Negative'); +const mathNode = require('../node'); +import Symbols = require('../Symbols'); +const COMPARATOR_TO_INVERSE = { + '>': '<', + '>=': '<=', + '<': '>', + '<=': '>=', + '=': '=' +}; + +const EquationOperations = {}; + +// Ensures that the given equation has the given symbolName on the left side, +// by swapping the right and left sides if it is only in the right side. +// So 3 = x would become x = 3. +EquationOperations.ensureSymbolInLeftNode = (equation, symbolName) => { + const leftSideSymbolTerm = Symbols.getLastSymbolTerm( + equation.leftNode, symbolName); + const rightSideSymbolTerm = Symbols.getLastSymbolTerm( + equation.rightNode, symbolName); + + if (!leftSideSymbolTerm) { + if (rightSideSymbolTerm) { + const comparator = COMPARATOR_TO_INVERSE[equation.comparator]; + const oldEquation = equation; + const newEquation = new Equation( + equation.rightNode, equation.leftNode, comparator); + // no change groups are set for this step because everything changes, so + // they wouldn't be pedagogically helpful. + return new EquationStatus( + ChangeTypes.SWAP_SIDES, oldEquation, newEquation); + } + else { + throw Error('No term with symbol: ' + symbolName); + } + } + return EquationStatus.noChange(equation); +}; + +// TODO: Ensures that a symbol is not in the denominator by multiplying +// both sides by the whatever order of the symbol necessary. +// This is blocked on the simplifying functionality of canceling symbols in +// fractions (needs factoring for full canceling support) +EquationOperations.removeSymbolFromDenominator = equation => EquationStatus.noChange(equation); + +// Removes the given symbolName from the right side by adding or subtracting +// it from both sides as appropriate. +// e.g. 2x = 3x + 5 --> 2x - 3x = 5 +// There are actually no cases where we'd remove symbols from the right side +// by multiplying or dividing by a symbol term. +// TODO: support inverting functions e.g. sqrt, ^, log etc. +EquationOperations.removeSymbolFromRightSide = (equation, symbolName) => { + const rightNode = equation.rightNode; + let symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); + + let inverseOp, inverseTerm, changeType; + if (!symbolTerm){ + return EquationStatus.noChange(equation); + } + + // Clone it so that any operations on it don't affect the node already + // in the equation + symbolTerm = clone(symbolTerm); + + if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { + if (Negative.isNegative(symbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(symbolTerm); + } + else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = symbolTerm; + } + } + else if (mathNode.Type.isOperator(rightNode)) { + if (rightNode.op === '+') { + if (Negative.isNegative(symbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(symbolTerm); + } + else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = symbolTerm; + } + } + else { + // Note that operator '-' won't show up here because subtraction is + // flattened into adding the negative. See 'TRICKY catch' in the README + // for more details. + throw Error('Unsupported operation: ' + symbolTerm.op); + } + } + else if (mathNode.Type.isUnaryMinus(rightNode)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = symbolTerm.args[0]; + } + else { + throw Error('Unsupported node type: ' + rightNode.type); + } + return performTermOperationOnEquation( + equation, inverseOp, inverseTerm, changeType); +}; + +// Isolates the given symbolName to the left side by adding, multiplying, subtracting +// or dividing all other symbols and constants from both sides appropriately +// TODO: support inverting functions e.g. sqrt, ^, log etc. +EquationOperations.isolateSymbolOnLeftSide = (equation, symbolName) => { + const leftNode = equation.leftNode; + let nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); + + let inverseOp, inverseTerm, changeType; + if (!nonSymbolTerm) { + return EquationStatus.noChange(equation); + } + + // Clone it so that any operations on it don't affect the node already + // in the equation + nonSymbolTerm = clone(nonSymbolTerm); + + if (mathNode.Type.isOperator(leftNode)) { + if (leftNode.op === '+') { + if (Negative.isNegative(nonSymbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(nonSymbolTerm); + } + else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = nonSymbolTerm; + } + } + else if (leftNode.op === '*') { + if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; + inverseTerm = mathNode.Creator.operator( + '/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + } + else { + inverseOp = '/'; + changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; + inverseTerm = nonSymbolTerm; + } + } + else if (leftNode.op === '/') { + // The non symbol term is always a fraction because it's the + // coefficient of our symbol term. + // If the numerator is 1, we multiply both sides by the denominator, + // otherwise we multiply by the inverse + if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; + inverseTerm = nonSymbolTerm.args[1]; + } + else { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; + inverseTerm = mathNode.Creator.operator( + '/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + } + } + else if (leftNode.op === '^') { + // TODO: support roots + return EquationStatus.noChange(equation); + } + else { + throw Error('Unsupported operation: ' + leftNode.op); + } + } + else if (mathNode.Type.isUnaryMinus(leftNode)) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; + inverseTerm = mathNode.Creator.constant(-1); + } + else { + throw Error('Unsupported node type: ' + leftNode.type); + } + + return performTermOperationOnEquation( + equation, inverseOp, inverseTerm, changeType); +}; + +// Modifies the left and right sides of an equation by `op`-ing `term` +// to both sides. Returns an Status object. +function performTermOperationOnEquation(equation: any, op: any, term: any, changeType: any); +function performTermOperationOnEquation(equation, op, term, changeType) { + const oldEquation = equation.clone(); + + const leftTerm = clone(term); + const rightTerm = clone(term); + const leftNode = performTermOperationOnExpression( + equation.leftNode, op, leftTerm); + const rightNode = performTermOperationOnExpression( + equation.rightNode, op, rightTerm); + + let comparator = equation.comparator; + if (Negative.isNegative(term) && (op === '*' || op === '/')) { + comparator = COMPARATOR_TO_INVERSE[comparator]; + } + + const newEquation = new Equation(leftNode, rightNode, comparator); + return new EquationStatus(changeType, oldEquation, newEquation); +} + +// Performs an operation of a term on an entire given expression +function performTermOperationOnExpression(expression: any, op: any, term: any); +function performTermOperationOnExpression(expression, op, term) { + const node = (mathNode.Type.isOperator(expression) ? + mathNode.Creator.parenthesis(expression) : expression); + + term.changeGroup = 1; + const newNode = mathNode.Creator.operator(op, [node, term]); + + return newNode; +} + +export = EquationOperations; diff --git a/lib/solveEquation/index.js b/lib/solveEquation/index.ts similarity index 86% rename from lib/solveEquation/index.js rename to lib/solveEquation/index.ts index c990bcd8..5ef908e2 100644 --- a/lib/solveEquation/index.js +++ b/lib/solveEquation/index.ts @@ -1,6 +1,5 @@ -const math = require('mathjs'); - -const stepThrough = require('./stepThrough'); +import math = require('mathjs'); +import stepThrough = require('./stepThrough'); function solveEquationString(equationString, debug=false) { const comparators = ['<=', '>=', '=', '<', '>']; @@ -34,4 +33,4 @@ function solveEquationString(equationString, debug=false) { return []; } -module.exports = solveEquationString; +export = solveEquationString; diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.ts similarity index 87% rename from lib/solveEquation/stepThrough.js rename to lib/solveEquation/stepThrough.ts index 969836c2..f88d1c40 100644 --- a/lib/solveEquation/stepThrough.js +++ b/lib/solveEquation/stepThrough.ts @@ -1,21 +1,20 @@ -const ChangeTypes = require('../ChangeTypes'); -const checks = require('../checks'); -const Equation = require('../equation/Equation'); -const EquationOperations = require('./EquationOperations'); -const EquationStatus = require('../equation/Status'); -const evaluate = require('../util/evaluate'); -const flattenOperands = require('../util/flattenOperands'); -const Node = require('../node'); -const removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); -const simplifyExpressionNode = require('../simplifyExpression/stepThrough'); -const Symbols = require('../Symbols'); - +import ChangeTypes = require('../ChangeTypes'); +import checks = require('../checks'); +import Equation = require('../equation/Equation'); +import EquationOperations = require('./EquationOperations'); +import EquationStatus = require('../equation/Status'); +import evaluate = require('../util/evaluate'); +import flattenOperands = require('../util/flattenOperands'); +const mathNode = require('../node'); +import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); +import simplifyExpressionNode = require('../simplifyExpression/stepThrough'); +import Symbols = require('../Symbols'); const COMPARATOR_TO_FUNCTION = { - '=': function(left, right) { return left === right; }, - '>': function(left, right) { return left > right; }, - '>=': function(left, right) { return left >= right; }, - '<': function(left, right) { return left < right; }, - '<=': function(left, right) { return left <= right; }, + '='(left, right) { return left === right; }, + '>'(left, right) { return left > right; }, + '>='(left, right) { return left >= right; }, + '<'(left, right) { return left < right; }, + '<='(left, right) { return left <= right; }, }; // Given a leftNode, rightNode and a comparator, will return the steps to get @@ -128,8 +127,8 @@ 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)) { + if (!mathNode.Type.isConstantOrConstantFraction(equation.leftNode, true) || + !mathNode.Type.isConstantOrConstantFraction(equation.rightNode, true)) { throw Error('Expected both nodes to be constants, instead got: ' + equation.print()); } @@ -156,6 +155,7 @@ function solveConstantEquation(equation, debug, steps=[]) { // Given a symbol and an equation, performs a single step to // solve for the symbol. Returns an Status object. +function step(equation: any, symbolName: any); function step(equation, symbolName) { const solveFunctions = [ // ensure the symbol is always on the left node @@ -247,6 +247,7 @@ function addSimplificationSteps(steps, equation, debug=false) { return steps; } +function logSteps(equationStatus: any); function logSteps(equationStatus) { // eslint-disable-next-line console.log('\n' + equationStatus.changeType); @@ -259,5 +260,4 @@ function logSteps(equationStatus) { } } - -module.exports = stepThrough; +export = stepThrough; diff --git a/lib/util/Util.js b/lib/util/Util.js index 033395ab..bc168bf2 100644 --- a/lib/util/Util.js +++ b/lib/util/Util.js @@ -1,18 +1,22 @@ +"use strict"; /* Various utility functions used in the math stepper */ -const Util = {}; - -// Adds `value` to a list in `dict`, creating a new list if the key isn't in -// the dictionary yet. Returns the updated dictionary. -Util.appendToArrayInObject = function(dict, key, value) { - if (dict[key]) { - dict[key].push(value); - } - else { - dict[key] = [value]; - } - return dict; -}; - +var Util = (function () { + function Util() { + // Adds `value` to a list in `dict`, creating a new list if the key isn't in + // the dictionary yet. Returns the updated dictionary. + this.appendToArrayInObject = function (dict, key, value) { + if (dict[key]) { + dict[key].push(value); + } + else { + dict[key] = [value]; + } + return dict; + }; + } + return Util; +}()); module.exports = Util; +//# sourceMappingURL=Util.js.map \ No newline at end of file diff --git a/lib/util/Util.js.map b/lib/util/Util.js.map new file mode 100644 index 00000000..c99bc463 --- /dev/null +++ b/lib/util/Util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Util.js","sourceRoot":"","sources":["Util.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH;IAAA;QAEA,4EAA4E;QAC5E,sDAAsD;QAClD,0BAAqB,GAAG,UAAC,IAAI,EAAE,GAAG,EAAE,KAAK;YACrC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACZ,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;YAAC,IAAI,CAAC,CAAC;gBACJ,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC,CAAC;IACN,CAAC;IAAD,WAAC;AAAD,CAAC,AAZD,IAYC;AAED,iBAAS,IAAI,CAAC"} \ No newline at end of file diff --git a/lib/util/Util.ts b/lib/util/Util.ts new file mode 100644 index 00000000..712fbab4 --- /dev/null +++ b/lib/util/Util.ts @@ -0,0 +1,18 @@ +/* + Various utility functions used in the math stepper + */ +class Util { + +// Adds `value` to a list in `dict`, creating a new list if the key isn't in +// the dictionary yet. Returns the updated dictionary. + appendToArrayInObject = (dict, key, value) => { + if (dict[key]) { + dict[key].push(value); + } else { + dict[key] = [value]; + } + return dict; + }; +} + +export = Util; diff --git a/lib/util/clone.js b/lib/util/clone.js index 7debbad4..f06ff1fb 100644 --- a/lib/util/clone.js +++ b/lib/util/clone.js @@ -1,18 +1,16 @@ -// Simple clone function, which creates a deep copy of the given node -// And recurses on the children (due to the shallow nature of the mathjs node -// clone) +"use strict"; function clone(node) { - const copy = node.clone(); - copy.changeGroup = node.changeGroup; - if (node.args) { - node.args.forEach((child, i) => { - copy.args[i] = clone(child); - }); - } - else if (node.content) { - copy.content = clone(node.content); - } - return copy; + var copy = node.clone(); + copy.changeGroup = node.changeGroup; + if (node.args) { + node.args.forEach(function (child, i) { + copy.args[i] = clone(child); + }); + } + else if (node.content) { + copy.content = clone(node.content); + } + return copy; } - module.exports = clone; +//# sourceMappingURL=clone.js.map \ No newline at end of file diff --git a/lib/util/clone.js.map b/lib/util/clone.js.map new file mode 100644 index 00000000..708c34e2 --- /dev/null +++ b/lib/util/clone.js.map @@ -0,0 +1 @@ +{"version":3,"file":"clone.js","sourceRoot":"","sources":["clone.ts"],"names":[],"mappings":";AAIA,eAAe,IAAI;IACjB,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AACd,CAAC;AAED,iBAAS,KAAK,CAAC"} \ No newline at end of file diff --git a/lib/util/clone.ts b/lib/util/clone.ts new file mode 100644 index 00000000..3c2c70da --- /dev/null +++ b/lib/util/clone.ts @@ -0,0 +1,19 @@ +// Simple clone function, which creates a deep copy of the given node +// And recurses on the children (due to the shallow nature of the mathjs node +// clone) +function clone(node: any); +function clone(node) { + const copy = node.clone(); + copy.changeGroup = node.changeGroup; + if (node.args) { + node.args.forEach((child, i) => { + copy.args[i] = clone(child); + }); + } + else if (node.content) { + copy.content = clone(node.content); + } + return copy; +} + +export = clone; diff --git a/lib/util/evaluate.js b/lib/util/evaluate.js index 53d79728..a5898b8e 100644 --- a/lib/util/evaluate.js +++ b/lib/util/evaluate.js @@ -1,10 +1,10 @@ // Evaluates a node to a numerical value // e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 // it's important that `node` does not contain any symbol nodes - +"use strict"; function evaluate(node) { - // TODO: once we swap in math-parser, call its evaluate function instead - return node.eval(); + // TODO: once we swap in math-parser, call its evaluate function instead + return node.eval(); } - module.exports = evaluate; +//# sourceMappingURL=evaluate.js.map \ No newline at end of file diff --git a/lib/util/evaluate.js.map b/lib/util/evaluate.js.map new file mode 100644 index 00000000..58bb1d2a --- /dev/null +++ b/lib/util/evaluate.js.map @@ -0,0 +1 @@ +{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["evaluate.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,6EAA6E;AAC7E,+DAA+D;;AAG/D,kBAAkB,IAAI;IACpB,wEAAwE;IACxE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/util/evaluate.ts b/lib/util/evaluate.ts new file mode 100644 index 00000000..9761d84e --- /dev/null +++ b/lib/util/evaluate.ts @@ -0,0 +1,11 @@ +// Evaluates a node to a numerical value +// e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 +// it's important that `node` does not contain any symbol nodes + +function evaluate(node: any); +function evaluate(node) { + // TODO: once we swap in math-parser, call its evaluate function instead + return node.eval(); +} + +export = evaluate; diff --git a/lib/util/flattenOperands.js b/lib/util/flattenOperands.ts similarity index 95% rename from lib/util/flattenOperands.js rename to lib/util/flattenOperands.ts index b85c81d4..1cc67605 100644 --- a/lib/util/flattenOperands.js +++ b/lib/util/flattenOperands.ts @@ -1,6 +1,6 @@ -const evaluate = require('./evaluate'); -const Negative = require('../Negative'); -const Node = require('../node'); +import evaluate = require('./evaluate'); +import Negative = require('../Negative'); +import Node = require('../node'); /* Background: @@ -34,6 +34,7 @@ interested in how that works // 2+2+2, ie one + node that has three children. // Input: an expression tree // Output: the expression tree updated with flattened operations +function flattenOperands(node: any); function flattenOperands(node) { if (Node.Type.isConstant(node, true)) { // the evaluate() changes unary minuses around constant nodes to constant nodes @@ -104,6 +105,7 @@ function flattenOperands(node) { // NOTE: the returned node will be of operation type `parentOp`, regardless of // the operation type of `node`, unless `node` wasn't changed // e.g. 2 * 3 / 4 would be * of 2 and 3/4, but 2/3 would stay 2/3 and division +function flattenSupportedOperation(node: any, parentOp: any); function flattenSupportedOperation(node, parentOp) { // First get the list of operands that this operator operates on. // e.g. 2 + 3 + 4 + 5 is stored as (((2 + 3) + 4) + 5) in the tree and we @@ -150,6 +152,9 @@ function flattenSupportedOperation(node, parentOp) { // of type `op`. // Op is a string e.g. '+' or '*' // returns the list of all the node operated on by `parentOp` +function getOperands(node: any, parentOp: "*"); +function getOperands(node: any, parentOp: "+"); +function getOperands(node: any, parentOp: any); function getOperands(node, parentOp) { // We can only recurse on operations of type op. // If the node is not an operator node or of the right operation type, @@ -221,6 +226,7 @@ function getOperands(node, parentOp) { // 2*2*x (which has three children). // So this function would return true for the input 2*2x, if it was stored as // an expression tree with root node * and children 2*2 and x +function isPolynomialTermMultiplication(node: any); function isPolynomialTermMultiplication(node) { // This concept only applies when we're flattening multiplication operations if (node.op !== '*') { @@ -246,6 +252,7 @@ function isPolynomialTermMultiplication(node) { // and flattens it appropriately so the coefficient and symbol are grouped // together. Returns a new list of operands from this node that should be // multiplied together. +function maybeFlattenPolynomialTerm(node: any); function maybeFlattenPolynomialTerm(node) { // We recurse on the left side of the tree to find operands so far const operands = getOperands(node.args[0], '*'); @@ -280,6 +287,7 @@ function maybeFlattenPolynomialTerm(node) { // are to be multiplied together. Otherwise, a list of length one with // just the division node is returned. getOperands might change the // operator accordingly. +function flattenDivision(node: any); function flattenDivision(node) { // We recurse on the left side of the tree to find operands so far // Flattening division is always considered part of a bigger picture @@ -309,6 +317,7 @@ function flattenDivision(node) { // operators or parentheses between them. // e.g. returns true: 2*3/4, 2 / 5 / 6 * 7 / 8 // e.g. returns false: 3/4/5, ((3*2) - 5) / 7, (2*5)/6 +function hasMultiplicationBesideDivision(node: any); function hasMultiplicationBesideDivision(node) { if (!Node.Type.isOperator(node)) { return false; @@ -323,4 +332,4 @@ function hasMultiplicationBesideDivision(node) { return node.args.some(hasMultiplicationBesideDivision); } -module.exports = flattenOperands; +export = flattenOperands; diff --git a/lib/util/print.js b/lib/util/print.ts similarity index 94% rename from lib/util/print.js rename to lib/util/print.ts index 3bfb02bd..5db16bd6 100644 --- a/lib/util/print.js +++ b/lib/util/print.ts @@ -1,6 +1,6 @@ -const clone = require('./clone'); -const flatten = require('./flattenOperands'); -const Node = require('../node'); +import clone = require('./clone'); +import flatten = require('./flattenOperands'); +import Node = require('../node'); // Prints an expression node in asciimath // If showPlusMinus is true, print + - (e.g. 2 + -3) @@ -17,6 +17,7 @@ function print(node, showPlusMinus=false) { return string; } +function printTreeTraversal(node: any, parentNode: any); function printTreeTraversal(node, parentNode) { if (Node.PolynomialTerm.isPolynomialTerm(node)) { const polyTerm = new Node.PolynomialTerm(node); @@ -106,4 +107,4 @@ function printTreeTraversal(node, parentNode) { } } -module.exports = print; +export = print; diff --git a/lib/util/removeUnnecessaryParens.js b/lib/util/removeUnnecessaryParens.ts similarity index 92% rename from lib/util/removeUnnecessaryParens.js rename to lib/util/removeUnnecessaryParens.ts index 3bbf796d..0a87a34c 100644 --- a/lib/util/removeUnnecessaryParens.js +++ b/lib/util/removeUnnecessaryParens.ts @@ -1,6 +1,6 @@ -const checks = require('../checks'); -const LikeTermCollector = require('../simplifyExpression/collectAndCombineSearch/LikeTermCollector'); -const Node = require('../node'); +import checks = require('../checks'); +import LikeTermCollector = require('../simplifyExpression/collectAndCombineSearch/LikeTermCollector'); +import Node = require('../node'); // Removes any parenthesis around nodes that can't be resolved further. // Input must be a top level expression. @@ -23,6 +23,7 @@ function removeUnnecessaryParens(node, rootNode=false) { // it doesn't change the value of the expression. Returns a node. // NOTE: after this function is called, every parenthesis node in the // tree should always have an operator node or unary minus as its child. +function removeUnnecessaryParensSearch(node: any); function removeUnnecessaryParensSearch(node) { if (Node.Type.isOperator(node)) { return removeUnnecessaryParensInOperatorNode(node); @@ -49,6 +50,7 @@ function removeUnnecessaryParensSearch(node) { // Removes unncessary parens for each operator in an operator node, and removes // unncessary parens around operators that can't be simplified further. // Returns a node. +function removeUnnecessaryParensInOperatorNode(node: any); function removeUnnecessaryParensInOperatorNode(node) { // Special case: if the node is an exponent node and the base // is an operator, we should keep the parentheses for the base. @@ -96,6 +98,7 @@ function removeUnnecessaryParensInOperatorNode(node) { // Removes unncessary parens for each argument in a function node. // Returns a node. +function removeUnnecessaryParensInFunctionNode(node: any); function removeUnnecessaryParensInFunctionNode(node) { node.args.forEach((child, i) => { if (Node.Type.isParenthesis(child)) { @@ -113,6 +116,7 @@ function removeUnnecessaryParensInFunctionNode(node) { // Note that this means that the type of the content of a ParenthesisNode after // this step should now always be an OperatorNode (including unary minus). // Returns a node. +function removeUnnecessaryParensInParenthesisNode(node: any); function removeUnnecessaryParensInParenthesisNode(node) { // polynomials terms can be complex trees (e.g. 3x^2/5) but don't need parens // around them @@ -165,10 +169,11 @@ function removeUnnecessaryParensInParenthesisNode(node) { // Returns true if any of the collect or combine steps can be applied to the // expression tree `node`. +function canCollectOrCombine(node: any); function canCollectOrCombine(node) { return LikeTermCollector.canCollectLikeTerms(node) || checks.resolvesToConstant(node) || checks.canSimplifyPolynomialTerms(node); } -module.exports = removeUnnecessaryParens; +export = removeUnnecessaryParens; diff --git a/test/Negative.test.js b/test/Negative.test.js deleted file mode 100644 index a20cf1af..00000000 --- a/test/Negative.test.js +++ /dev/null @@ -1,28 +0,0 @@ -const math = require('mathjs'); - -const flatten = require('../lib/util/flattenOperands'); -const print = require('../lib/util/print'); - -const Negative = require('../lib/Negative'); - -const TestUtil = require('./TestUtil'); - -function testNegate(exprString, outputStr) { - const inputStr = Negative.negate(flatten(math.parse(exprString))); - TestUtil.testFunctionOutput(print, inputStr, outputStr); -} - -describe('negate', function() { - const tests = [ - ['1', '-1'], - ['-1', '1'], - ['1/2', '-1/2'], - ['(x+2)', '-(x + 2)'], - ['x', '-x'], - ['x^2', '-x^2'], - ['-y^3', 'y^3'], - ['2/3 x', '-2/3 x'], - ['-5/6 z', '5/6 z'], - ]; - tests.forEach(t => testNegate(t[0], t[1])); -}); diff --git a/test/Negative.test.ts b/test/Negative.test.ts new file mode 100644 index 00000000..4791709e --- /dev/null +++ b/test/Negative.test.ts @@ -0,0 +1,26 @@ +import math = require('mathjs'); +import flatten = require('../lib/util/flattenOperands'); +import print = require('../lib/util/print'); +import Negative = require('../lib/Negative'); +import TestUtil = require('./TestUtil'); + +function testNegate(exprString: any, outputStr: any); +function testNegate(exprString, outputStr) { + const inputStr = Negative.negate(flatten(math.parse(exprString))); + TestUtil.testFunctionOutput(print, inputStr, outputStr); +} + +describe('negate', () => { + const tests = [ + ['1', '-1'], + ['-1', '1'], + ['1/2', '-1/2'], + ['(x+2)', '-(x + 2)'], + ['x', '-x'], + ['x^2', '-x^2'], + ['-y^3', 'y^3'], + ['2/3 x', '-2/3 x'], + ['-5/6 z', '5/6 z'], + ]; + tests.forEach(t => testNegate(t[0], t[1])); +}); diff --git a/test/Node/PolynomialTerm.test.js b/test/Node/PolynomialTerm.test.js deleted file mode 100644 index 30489e62..00000000 --- a/test/Node/PolynomialTerm.test.js +++ /dev/null @@ -1,24 +0,0 @@ -const PolynomialTerm = require('../../lib/node/PolynomialTerm'); - -const TestUtil = require('../TestUtil'); - -function testIsPolynomialTerm(exprStr, isTerm) { - TestUtil.testBooleanFunction(PolynomialTerm.isPolynomialTerm, exprStr, isTerm); -} - -describe('classifies symbol terms correctly', function() { - const tests = [ - ['x', true], - ['x', true], - ['x^2', true], - ['y^55', true], - ['y^4/4', true], - ['5y/3', true], - ['x^y', true], - ['3', false], - ['2^5', false], - ['x*y^5', false], - ['-12y^5/-3', true], - ]; - tests.forEach(t => testIsPolynomialTerm(t[0], t[1])); -}); diff --git a/test/Node/PolynomialTerm.test.ts b/test/Node/PolynomialTerm.test.ts new file mode 100644 index 00000000..624cb94c --- /dev/null +++ b/test/Node/PolynomialTerm.test.ts @@ -0,0 +1,24 @@ +const PolynomialTerm = require('../../lib/node/PolynomialTerm'); +import TestUtil = require('../TestUtil'); + +function testIsPolynomialTerm(exprStr: any, isTerm: any); +function testIsPolynomialTerm(exprStr, isTerm) { + TestUtil.testBooleanFunction(PolynomialTerm.isPolynomialTerm, exprStr, isTerm); +} + +describe('classifies symbol terms correctly', () => { + const tests = [ + ['x', true], + ['x', true], + ['x^2', true], + ['y^55', true], + ['y^4/4', true], + ['5y/3', true], + ['x^y', true], + ['3', false], + ['2^5', false], + ['x*y^5', false], + ['-12y^5/-3', true], + ]; + tests.forEach(t => testIsPolynomialTerm(t[0], t[1])); +}); diff --git a/test/Node/Type.test.js b/test/Node/Type.test.js deleted file mode 100644 index 82407533..00000000 --- a/test/Node/Type.test.js +++ /dev/null @@ -1,110 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const Node = require('../../lib/node'); - -const constNode = Node.Creator.constant; - -describe('Node.Type works', function () { - it('(2+2) parenthesis', function () { - assert.deepEqual( - Node.Type.isParenthesis(math.parse('(2+2)')), - true); - }); - it('10 constant', function () { - assert.deepEqual( - Node.Type.isConstant(math.parse(10)), - true); - }); - it('-2 constant', function () { - assert.deepEqual( - Node.Type.isConstant(constNode(-2)), - true); - }); - it('2+2 operator without operator param', function () { - assert.deepEqual( - Node.Type.isOperator(math.parse('2+2')), - true); - }); - it('2+2 operator with correct operator param', function () { - assert.deepEqual( - Node.Type.isOperator(math.parse('2+2'), '+'), - true); - }); - it('2+2 operator with incorrect operator param', function () { - assert.deepEqual( - Node.Type.isOperator(math.parse('2+2'), '-'), - false); - }); - it('-x not operator', function () { - assert.deepEqual( - Node.Type.isOperator(math.parse('-x')), - false); - }); - it('-x symbol', function () { - assert.deepEqual( - Node.Type.isSymbol(math.parse('-x')), - true); - }); - it('y symbol', function () { - assert.deepEqual( - Node.Type.isSymbol(math.parse('y')), - true); - }); - it('abs(5) is abs function', function () { - assert.deepEqual( - Node.Type.isFunction(math.parse('abs(5)'), 'abs'), - true); - }); - it('sqrt(5) is not abs function', function () { - assert.deepEqual( - Node.Type.isFunction(math.parse('sqrt(5)'), 'abs'), - false); - }); - // it('nthRoot(4) is an nthRoot function', function () { - // assert.deepEqual( - // Node.Type.isFunction(math.parse('nthRoot(5)'), 'nthRoot'), - // true); - // }); -}); - -describe('isConstantOrConstantFraction', function () { - it('2 true', function () { - assert.deepEqual( - Node.Type.isConstantOrConstantFraction(math.parse('2')), - true); - }); - it('2/9 true', function () { - assert.deepEqual( - Node.Type.isConstantOrConstantFraction(math.parse('4/9')), - true); - }); - it('x/2 false', function () { - assert.deepEqual( - Node.Type.isConstantOrConstantFraction(math.parse('x/2')), - false); - }); -}); - -describe('isIntegerFraction', function () { - it('4/5 true', function () { - assert.deepEqual( - Node.Type.isIntegerFraction(math.parse('4/5')), - true); - }); - it('4.3/5 false', function () { - assert.deepEqual( - Node.Type.isIntegerFraction(math.parse('4.3/5')), - false); - }); - it('4x/5 false', function () { - assert.deepEqual( - Node.Type.isIntegerFraction(math.parse('4x/5')), - false); - }); - it('5 false', function () { - assert.deepEqual( - Node.Type.isIntegerFraction(math.parse('5')), - false); - }); -}); diff --git a/test/Node/Type.test.ts b/test/Node/Type.test.ts new file mode 100644 index 00000000..c1ee8020 --- /dev/null +++ b/test/Node/Type.test.ts @@ -0,0 +1,109 @@ +const assert = require('assert'); +import math = require('mathjs'); +const mathNode = require('../../lib/node'); + +const constNode = mathNode.Creator.constant; + +describe('mathNode.Type works', () => { + it('(2+2) parenthesis', () => { + assert.deepEqual( + mathNode.Type.isParenthesis(math.parse('(2+2)')), + true); + }); + it('10 constant', () => { + assert.deepEqual( + mathNode.Type.isConstant(math.parse(10)), + true); + }); + it('-2 constant', () => { + assert.deepEqual( + mathNode.Type.isConstant(constNode(-2)), + true); + }); + it('2+2 operator without operator param', () => { + assert.deepEqual( + mathNode.Type.isOperator(math.parse('2+2')), + true); + }); + it('2+2 operator with correct operator param', () => { + assert.deepEqual( + mathNode.Type.isOperator(math.parse('2+2'), '+'), + true); + }); + it('2+2 operator with incorrect operator param', () => { + assert.deepEqual( + mathNode.Type.isOperator(math.parse('2+2'), '-'), + false); + }); + it('-x not operator', () => { + assert.deepEqual( + mathNode.Type.isOperator(math.parse('-x')), + false); + }); + it('-x symbol', () => { + assert.deepEqual( + mathNode.Type.isSymbol(math.parse('-x')), + true); + }); + it('y symbol', () => { + assert.deepEqual( + mathNode.Type.isSymbol(math.parse('y')), + true); + }); + it('abs(5) is abs function', () => { + assert.deepEqual( + mathNode.Type.isFunction(math.parse('abs(5)'), 'abs'), + true); + }); + it('sqrt(5) is not abs function', () => { + assert.deepEqual( + mathNode.Type.isFunction(math.parse('sqrt(5)'), 'abs'), + false); + }); + // it('nthRoot(4) is an nthRoot function', function () { + // assert.deepEqual( + // mathNode.Type.isFunction(math.parse('nthRoot(5)'), 'nthRoot'), + // true); + // }); +}); + +describe('isConstantOrConstantFraction', () => { + it('2 true', () => { + assert.deepEqual( + mathNode.Type.isConstantOrConstantFraction(math.parse('2')), + true); + }); + it('2/9 true', () => { + assert.deepEqual( + mathNode.Type.isConstantOrConstantFraction(math.parse('4/9')), + true); + }); + it('x/2 false', () => { + assert.deepEqual( + mathNode.Type.isConstantOrConstantFraction(math.parse('x/2')), + false); + }); +}); + +describe('isIntegerFraction', () => { + it('4/5 true', () => { + assert.deepEqual( + mathNode.Type.isIntegerFraction(math.parse('4/5')), + true); + }); + it('4.3/5 false', () => { + assert.deepEqual( + mathNode.Type.isIntegerFraction(math.parse('4.3/5')), + false); + }); + it('4x/5 false', () => { + assert.deepEqual( + mathNode.Type.isIntegerFraction(math.parse('4x/5')), + false); + }); + it('5 false', () => { + assert.deepEqual( + mathNode.Type.isIntegerFraction(math.parse('5')), + false); + }); +}); diff --git a/test/TestUtil.js b/test/TestUtil.js deleted file mode 100644 index 246d889b..00000000 --- a/test/TestUtil.js +++ /dev/null @@ -1,56 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const flatten = require('../lib/util/flattenOperands'); -const print = require('../lib/util/print'); - -// TestUtil contains helper methods to share code across tests -const TestUtil = {}; - -// Tests a function that takes an input string and check its output -TestUtil.testFunctionOutput = function (fn, input, output) { - it(input + ' -> ' + output, () => { - assert.deepEqual(fn(input),output); - }); -}; - -// tests a function that takes in a node and returns a boolean value -TestUtil.testBooleanFunction = function (simplifier, exprString, expectedBooleanValue) { - it(exprString + ' ' + expectedBooleanValue, () => { - const inputNode = flatten(math.parse(exprString)); - assert.equal(simplifier(inputNode),expectedBooleanValue); - }); -}; - -// Tests a simplification function -TestUtil.testSimplification = function (simplifyingFunction, exprString, - expectedOutputString) { - it (exprString + ' -> ' + expectedOutputString, () => { - assert.deepEqual( - print(simplifyingFunction(flatten(math.parse(exprString))).newNode), - expectedOutputString); - }); -}; - -// Test the substeps in the expression -TestUtil.testSubsteps = function (fn, exprString, outputList, - outputStr) { - it(exprString + ' -> ' + outputStr, () => { - const status = fn(flatten(math.parse(exprString))); - const substeps = status.substeps; - - assert.deepEqual(substeps.length, outputList.length); - substeps.forEach((step, i) => { - assert.deepEqual( - print(step.newNode), - outputList[i]); - }); - if (outputStr) { - assert.deepEqual( - print(status.newNode), - outputStr); - } - }); -}; - -module.exports = TestUtil; diff --git a/test/TestUtil.ts b/test/TestUtil.ts new file mode 100644 index 00000000..cfd715e9 --- /dev/null +++ b/test/TestUtil.ts @@ -0,0 +1,52 @@ +const assert = require('assert'); +import math = require('mathjs'); +import flatten = require('../lib/util/flattenOperands'); +import print = require('../lib/util/print'); + +// TestUtil contains helper methods to share code across tests +const TestUtil = {}; + +// Tests a function that takes an input string and check its output +TestUtil.testFunctionOutput = (fn, input, output) => { + it(input + ' -> ' + output, () => { + assert.deepEqual(fn(input),output); + }); +}; + +// tests a function that takes in a node and returns a boolean value +TestUtil.testBooleanFunction = (simplifier, exprString, expectedBooleanValue) => { + it(exprString + ' ' + expectedBooleanValue, () => { + const inputNode = flatten(math.parse(exprString)); + assert.equal(simplifier(inputNode),expectedBooleanValue); + }); +}; + +// Tests a simplification function +TestUtil.testSimplification = (simplifyingFunction, exprString, expectedOutputString) => { + it (exprString + ' -> ' + expectedOutputString, () => { + assert.deepEqual( + print(simplifyingFunction(flatten(math.parse(exprString))).newNode), + expectedOutputString); + }); +}; + +// Test the substeps in the expression +TestUtil.testSubsteps = (fn, exprString, outputList, outputStr) => { + it(exprString + ' -> ' + outputStr, () => { + const status = fn(flatten(math.parse(exprString))); + const substeps = status.substeps; + + assert.deepEqual(substeps.length, outputList.length); + substeps.forEach((step, i) => { + assert.deepEqual( + print(step.newNode), + outputList[i]); + }); + if (outputStr) { + assert.deepEqual( + print(status.newNode), + outputStr); + } + }); +}; +export = TestUtil; diff --git a/test/canAddLikeTermPolynomialNodes.test.js b/test/canAddLikeTermPolynomialNodes.test.ts similarity index 63% rename from test/canAddLikeTermPolynomialNodes.test.js rename to test/canAddLikeTermPolynomialNodes.test.ts index cc5ca4f2..7ca1d3a4 100644 --- a/test/canAddLikeTermPolynomialNodes.test.js +++ b/test/canAddLikeTermPolynomialNodes.test.ts @@ -1,7 +1,7 @@ -const canAddLikeTermPolynomialNodes = require('../lib/checks/canAddLikeTermPolynomialNodes'); - -const TestUtil = require('./TestUtil'); +import canAddLikeTermPolynomialNodes = require('../lib/checks/canAddLikeTermPolynomialNodes'); +import TestUtil = require('./TestUtil'); +function testCanBeAdded(expr: any, addable: any); function testCanBeAdded(expr, addable) { TestUtil.testBooleanFunction(canAddLikeTermPolynomialNodes, expr, addable); } diff --git a/test/canMultiplyLikeTermPolynomialNodes.test.js b/test/canMultiplyLikeTermPolynomialNodes.test.ts similarity index 63% rename from test/canMultiplyLikeTermPolynomialNodes.test.js rename to test/canMultiplyLikeTermPolynomialNodes.test.ts index d176dc4d..df30087b 100644 --- a/test/canMultiplyLikeTermPolynomialNodes.test.js +++ b/test/canMultiplyLikeTermPolynomialNodes.test.ts @@ -1,7 +1,7 @@ -const canMultiplyLikeTermPolynomialNodes = require('../lib/checks/canMultiplyLikeTermPolynomialNodes'); - -const TestUtil = require('./TestUtil'); +import canMultiplyLikeTermPolynomialNodes = require('../lib/checks/canMultiplyLikeTermPolynomialNodes'); +import TestUtil = require('./TestUtil'); +function testCanBeMultiplied(expr: any, multipliable: any); function testCanBeMultiplied(expr, multipliable) { TestUtil.testBooleanFunction(canMultiplyLikeTermPolynomialNodes, expr, multipliable); } diff --git a/test/canRearrangeCoefficient.test.js b/test/canRearrangeCoefficient.test.ts similarity index 62% rename from test/canRearrangeCoefficient.test.js rename to test/canRearrangeCoefficient.test.ts index 09d7f1e1..192a64b4 100644 --- a/test/canRearrangeCoefficient.test.js +++ b/test/canRearrangeCoefficient.test.ts @@ -1,7 +1,7 @@ -const canRearrangeCoefficient = require('../lib/checks/canRearrangeCoefficient'); - -const TestUtil = require('./TestUtil'); +import canRearrangeCoefficient = require('../lib/checks/canRearrangeCoefficient'); +import TestUtil = require('./TestUtil'); +function testCanBeRearranged(expr: any, arrangeable: any); function testCanBeRearranged(expr, arrangeable) { TestUtil.testBooleanFunction(canRearrangeCoefficient, expr, arrangeable); } diff --git a/test/checks/checks.test.js b/test/checks/checks.test.js deleted file mode 100644 index 4df3005f..00000000 --- a/test/checks/checks.test.js +++ /dev/null @@ -1,31 +0,0 @@ -const checks = require('../../lib/checks'); - -const TestUtil = require('../TestUtil'); - -function testCanCombine(exprStr, canCombine) { - TestUtil.testBooleanFunction(checks.canSimplifyPolynomialTerms, exprStr, canCombine); -} - -describe('canSimplifyPolynomialTerms multiplication', function() { - const tests = [ - ['x^2 * x * x', true], - // false b/c coefficient - ['x^2 * 3x * x', false], - ['y * y^3', true], - ['5 * y^3', false], // just needs flattening - ['5/7 * x', false], // just needs flattening - ['5/7 * 9 * x', false], - ]; - tests.forEach(t => testCanCombine(t[0], t[1])); -}); - - -describe('canSimplifyPolynomialTerms addition', function() { - const tests = [ - ['x + x', true], - ['4y^2 + 7y^2 + y^2', true], - ['4y^2 + 7y^2 + y^2 + y', false], - ['y', false], - ]; - tests.forEach(t => testCanCombine(t[0], t[1])); -}); diff --git a/test/checks/checks.test.ts b/test/checks/checks.test.ts new file mode 100644 index 00000000..2c79b483 --- /dev/null +++ b/test/checks/checks.test.ts @@ -0,0 +1,31 @@ +import checks = require('../../lib/checks'); +import TestUtil = require('../TestUtil'); + +function testCanCombine(exprStr: any, canCombine: any); +function testCanCombine(exprStr, canCombine) { + TestUtil.testBooleanFunction(checks.canSimplifyPolynomialTerms, exprStr, canCombine); +} + +describe('canSimplifyPolynomialTerms multiplication', () => { + const tests = [ + ['x^2 * x * x', true], + // false b/c coefficient + ['x^2 * 3x * x', false], + ['y * y^3', true], + ['5 * y^3', false], // just needs flattening + ['5/7 * x', false], // just needs flattening + ['5/7 * 9 * x', false], + ]; + tests.forEach(t => testCanCombine(t[0], t[1])); +}); + + +describe('canSimplifyPolynomialTerms addition', () => { + const tests = [ + ['x + x', true], + ['4y^2 + 7y^2 + y^2', true], + ['4y^2 + 7y^2 + y^2 + y', false], + ['y', false], + ]; + tests.forEach(t => testCanCombine(t[0], t[1])); +}); diff --git a/test/checks/hasUnsupportedNodes.test.js b/test/checks/hasUnsupportedNodes.test.js deleted file mode 100644 index 7b71a5f5..00000000 --- a/test/checks/hasUnsupportedNodes.test.js +++ /dev/null @@ -1,30 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const checks = require('../../lib/checks'); - -describe('arithmetic stepping', function () { - it('4 + sqrt(16) no support for sqrt', function () { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('4 + sqrt(4)')), - true); - }); - - it('x = 5 no support for assignment', function () { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('x = 5')), - true); - }); - - it('x + (-5)^2 - 8*y/2 is fine', function () { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('x + (-5)^2 - 8*y/2')), - false); - }); - - it('nthRoot() with no args has no support', function () { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('nthRoot()')), - true); - }); -}); diff --git a/test/checks/hasUnsupportedNodes.test.ts b/test/checks/hasUnsupportedNodes.test.ts new file mode 100644 index 00000000..f07916b2 --- /dev/null +++ b/test/checks/hasUnsupportedNodes.test.ts @@ -0,0 +1,28 @@ +const assert = require('assert'); +import math = require('mathjs'); +import checks = require('../../lib/checks'); +describe('arithmetic stepping', () => { + it('4 + sqrt(16) no support for sqrt', () => { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('4 + sqrt(4)')), + true); + }); + + it('x = 5 no support for assignment', () => { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('x = 5')), + true); + }); + + it('x + (-5)^2 - 8*y/2 is fine', () => { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('x + (-5)^2 - 8*y/2')), + false); + }); + + it('nthRoot() with no args has no support', () => { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('nthRoot()')), + true); + }); +}); diff --git a/test/checks/isQuadratic.test.js b/test/checks/isQuadratic.test.js deleted file mode 100644 index d5c98d01..00000000 --- a/test/checks/isQuadratic.test.js +++ /dev/null @@ -1,28 +0,0 @@ -const checks = require('../../lib/checks'); -const TestUtil = require('../TestUtil'); - -function testIsQuadratic(input, output) { - TestUtil.testBooleanFunction(checks.isQuadratic, input, output); -} - -describe('isQuadratic', function () { - const tests = [ - ['2 + 2', false], - ['x', false], - ['x^2 - 4', true], - ['x^2 + 2x + 1', true], - ['x^2 - 2x + 1', true], - ['x^2 + 3x + 2', true], - ['x^2 - 3x + 2', true], - ['x^2 + x - 2', true], - ['x^2 + x', true], - ['x^2 + 4', true], - ['x^2 + 4x + 1', true], - ['x^2', false], - ['x^3 + x^2 + x + 1', false], - ['x^2 + 4 + 2^x', false], - ['x^2 + 4 + 2y', false], - ['y^2 + 4 + 2x', false], - ]; - tests.forEach(t => testIsQuadratic(t[0], t[1])); -}); diff --git a/test/checks/isQuadratic.test.ts b/test/checks/isQuadratic.test.ts new file mode 100644 index 00000000..9297b537 --- /dev/null +++ b/test/checks/isQuadratic.test.ts @@ -0,0 +1,29 @@ +import checks = require('../../lib/checks'); +import TestUtil = require('../TestUtil'); + +function testIsQuadratic(input: any, output: any); +function testIsQuadratic(input, output) { + TestUtil.testBooleanFunction(checks.isQuadratic, input, output); +} + +describe('isQuadratic', () => { + const tests = [ + ['2 + 2', false], + ['x', false], + ['x^2 - 4', true], + ['x^2 + 2x + 1', true], + ['x^2 - 2x + 1', true], + ['x^2 + 3x + 2', true], + ['x^2 - 3x + 2', true], + ['x^2 + x - 2', true], + ['x^2 + x', true], + ['x^2 + 4', true], + ['x^2 + 4x + 1', true], + ['x^2', false], + ['x^3 + x^2 + x + 1', false], + ['x^2 + 4 + 2^x', false], + ['x^2 + 4 + 2y', false], + ['y^2 + 4 + 2x', false], + ]; + tests.forEach(t => testIsQuadratic(t[0], t[1])); +}); diff --git a/test/checks/resolvesToConstant.test.js b/test/checks/resolvesToConstant.test.js deleted file mode 100644 index 8d08d296..00000000 --- a/test/checks/resolvesToConstant.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const checks = require('../../lib/checks'); - -const TestUtil = require('../TestUtil'); - -function testResolvesToConstant(exprString, resolves) { - TestUtil.testBooleanFunction(checks.resolvesToConstant, exprString, resolves); -} - -describe('resolvesToConstant', function () { - const tests = [ - ['(2+2)', true], - ['10', true], - ['((2^2 + 4)) * 7 / 8', true], - ['2 * 3^x', false], - ['-(2) * -3', true], - ]; - tests.forEach(t => testResolvesToConstant(t[0], t[1])); -}); diff --git a/test/checks/resolvesToConstant.test.ts b/test/checks/resolvesToConstant.test.ts new file mode 100644 index 00000000..e09d66c9 --- /dev/null +++ b/test/checks/resolvesToConstant.test.ts @@ -0,0 +1,18 @@ +import checks = require('../../lib/checks'); +import TestUtil = require('../TestUtil'); + +function testResolvesToConstant(exprString: any, resolves: any); +function testResolvesToConstant(exprString, resolves) { + TestUtil.testBooleanFunction(checks.resolvesToConstant, exprString, resolves); +} + +describe('resolvesToConstant', () => { + const tests = [ + ['(2+2)', true], + ['10', true], + ['((2^2 + 4)) * 7 / 8', true], + ['2 * 3^x', false], + ['-(2) * -3', true], + ]; + tests.forEach(t => testResolvesToConstant(t[0], t[1])); +}); diff --git a/test/equation.test.js b/test/equation.test.ts similarity index 74% rename from test/equation.test.js rename to test/equation.test.ts index 3cecd055..da753250 100644 --- a/test/equation.test.js +++ b/test/equation.test.ts @@ -1,8 +1,8 @@ const assert = require('assert'); -const math = require('mathjs'); - -const Equation = require('../lib/equation/Equation'); +import math = require('mathjs'); +import Equation = require('../lib/equation/Equation'); +function constructAndPrintEquation(left: any, right: any, comp: any); function constructAndPrintEquation(left, right, comp) { const leftNode = math.parse(left); const rightNode = math.parse(right); @@ -10,6 +10,7 @@ function constructAndPrintEquation(left, right, comp) { return equation.print(); } +function testEquationConstructor(left: any, right: any, comp: any, output: any); function testEquationConstructor(left, right, comp, output) { it (output, () => { assert.equal( diff --git a/test/factor/ConstantFactors.test.js b/test/factor/ConstantFactors.test.js deleted file mode 100644 index 9fb102fa..00000000 --- a/test/factor/ConstantFactors.test.js +++ /dev/null @@ -1,44 +0,0 @@ -const ConstantFactors = require('../../lib/factor/ConstantFactors'); - -const TestUtil = require('../TestUtil'); - -function testPrimeFactors(input, output) { - TestUtil.testFunctionOutput(ConstantFactors.getPrimeFactors, input, output); -} - -describe('prime factors', function() { - const tests = [ - [1, [1]], - [-1, [-1, 1]], - [-2, [-1, 2]], - [5, [5]], - [12, [2, 2, 3]], - [15, [3, 5]], - [36, [2, 2, 3, 3]], - [49, [7, 7]], - [1260, [2, 2, 3, 3, 5, 7]], - [13195, [5, 7, 13, 29]], - [1234567891, [1234567891]] - ]; - tests.forEach(t => testPrimeFactors(t[0], t[1])); -}); - -function testFactorPairs(input, output) { - TestUtil.testFunctionOutput(ConstantFactors.getFactorPairs, input, output); -} - -describe('factor pairs', function() { - const tests = [ - [1, [[-1, -1], [1, 1]]], - [5, [[-1, -5], [1, 5]]], - [12, [[-3, -4], [-2, -6], [-1, -12], [1, 12], [2, 6], [3, 4]]], - [-12, [[-3, 4], [-2, 6], [-1, 12], [1, -12], [2, -6], [3, -4]]], - [15, [[-3, -5], [-1, -15], [1, 15], [3, 5]]], - [36, [[-6, -6], [-4, -9], [-3, -12], [-2, -18], [-1, -36], [1, 36], [2, 18], [3, 12], [4, 9], [6, 6,]]], - [49, [[-7, -7], [-1, -49], [1, 49], [7, 7]]], - [1260, [[-35, -36], [-30, -42], [-28, -45], [-21, -60], [-20, -63], [-18, -70], [-15, -84], [-14, -90], [-12, -105], [-10, -126], [-9, -140], [-7, -180], [-6, -210], [-5, -252], [-4, -315], [-3, -420], [-2, -630], [-1, -1260], [1, 1260], [2, 630], [3, 420], [4, 315], [5, 252], [6, 210], [7, 180], [9, 140], [10, 126], [12, 105], [14, 90], [15, 84], [18, 70], [20, 63], [21, 60], [28, 45], [30, 42], [35, 36]]], - [13195, [[-91, -145], [-65, -203], [-35, -377], [-29, -455], [-13, -1015], [-7, -1885], [-5, -2639], [-1, -13195], [1, 13195], [5, 2639], [7, 1885], [13, 1015], [29, 455], [35, 377], [65, 203], [91, 145]]], - [1234567891, [[-1, -1234567891], [1, 1234567891]]] - ]; - tests.forEach(t => testFactorPairs(t[0], t[1])); -}); diff --git a/test/factor/ConstantFactors.test.ts b/test/factor/ConstantFactors.test.ts new file mode 100644 index 00000000..48f12615 --- /dev/null +++ b/test/factor/ConstantFactors.test.ts @@ -0,0 +1,45 @@ +import ConstantFactors = require('../../lib/factor/ConstantFactors'); +import TestUtil = require('../TestUtil'); + +function testPrimeFactors(input: any, output: any); +function testPrimeFactors(input, output) { + TestUtil.testFunctionOutput(ConstantFactors.getPrimeFactors, input, output); +} + +describe('prime factors', () => { + const tests = [ + [1, [1]], + [-1, [-1, 1]], + [-2, [-1, 2]], + [5, [5]], + [12, [2, 2, 3]], + [15, [3, 5]], + [36, [2, 2, 3, 3]], + [49, [7, 7]], + [1260, [2, 2, 3, 3, 5, 7]], + [13195, [5, 7, 13, 29]], + [1234567891, [1234567891]] + ]; + tests.forEach(t => testPrimeFactors(t[0], t[1])); +}); + +function testFactorPairs(input: any, output: any); +function testFactorPairs(input, output) { + TestUtil.testFunctionOutput(ConstantFactors.getFactorPairs, input, output); +} + +describe('factor pairs', () => { + const tests = [ + [1, [[-1, -1], [1, 1]]], + [5, [[-1, -5], [1, 5]]], + [12, [[-3, -4], [-2, -6], [-1, -12], [1, 12], [2, 6], [3, 4]]], + [-12, [[-3, 4], [-2, 6], [-1, 12], [1, -12], [2, -6], [3, -4]]], + [15, [[-3, -5], [-1, -15], [1, 15], [3, 5]]], + [36, [[-6, -6], [-4, -9], [-3, -12], [-2, -18], [-1, -36], [1, 36], [2, 18], [3, 12], [4, 9], [6, 6,]]], + [49, [[-7, -7], [-1, -49], [1, 49], [7, 7]]], + [1260, [[-35, -36], [-30, -42], [-28, -45], [-21, -60], [-20, -63], [-18, -70], [-15, -84], [-14, -90], [-12, -105], [-10, -126], [-9, -140], [-7, -180], [-6, -210], [-5, -252], [-4, -315], [-3, -420], [-2, -630], [-1, -1260], [1, 1260], [2, 630], [3, 420], [4, 315], [5, 252], [6, 210], [7, 180], [9, 140], [10, 126], [12, 105], [14, 90], [15, 84], [18, 70], [20, 63], [21, 60], [28, 45], [30, 42], [35, 36]]], + [13195, [[-91, -145], [-65, -203], [-35, -377], [-29, -455], [-13, -1015], [-7, -1885], [-5, -2639], [-1, -13195], [1, 13195], [5, 2639], [7, 1885], [13, 1015], [29, 455], [35, 377], [65, 203], [91, 145]]], + [1234567891, [[-1, -1234567891], [1, 1234567891]]] + ]; + tests.forEach(t => testFactorPairs(t[0], t[1])); +}); diff --git a/test/factor/factorQuadratic.test.js b/test/factor/factorQuadratic.test.js deleted file mode 100644 index ec8e46b5..00000000 --- a/test/factor/factorQuadratic.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const factorQuadratic = require('../../lib/factor/factorQuadratic'); -const TestUtil = require('../TestUtil'); - -function testFactorQuadratic(input, output) { - TestUtil.testSimplification(factorQuadratic, input, output); -} - -describe('factorQuadratic', function () { - const tests = [ - ['x^2', 'x^2'], - ['x^2 + x^2', 'x^2 + x^2'], - ['x^2 + 2 - 3', 'x^2 + 2 - 3'], - ['x^2 + 2y + 2x + 3', 'x^2 + 2y + 2x + 3'], - ['x^2 + 2x', 'x * (x + 2)'], - ['-x^2 - 2x', '-x * (x + 2)'], - ['x^2 - 3x', 'x * (x - 3)'], - ['2x^2 + 2x', '2x * (x + 1)'], - ['x^2 - 4', '(x + 2) * (x - 2)'], - ['x^2 + 4', 'x^2 + 4'], - ['x^2 + 2x + 1', '(x + 1)^2'], - ['x^2 - 2x + 1', '(x - 1)^2'], - ['x^2 + 3x + 2', '(x + 1) * (x + 2)'], - ['x^2 - 3x + 2', '(x - 1) * (x - 2)'], - ['x^2 + x - 2', '(x - 1) * (x + 2)'], - ['x^2 + 4x + 1', 'x^2 + 4x + 1'], - ['x^2 - 3x + 1', 'x^2 - 3x + 1'], - ['x^2 + 4 + 2^x', 'x^2 + 4 + 2^x'], - ['-x^2 - 2x - 1', '-(x + 1)^2'], - ['-x^2 - 3x - 2', '-(x + 1) * (x + 2)'], - ['-x^2 + 1', '-(x + 1) * (x - 1)'], - ['-x^2 - 1', '-x^2 - 1'], - ]; - tests.forEach(t => testFactorQuadratic(t[0], t[1])); -}); diff --git a/test/factor/factorQuadratic.test.ts b/test/factor/factorQuadratic.test.ts new file mode 100644 index 00000000..311d2738 --- /dev/null +++ b/test/factor/factorQuadratic.test.ts @@ -0,0 +1,35 @@ +import factorQuadratic = require('../../lib/factor/factorQuadratic'); +import TestUtil = require('../TestUtil'); + +function testFactorQuadratic(input: any, output: any); +function testFactorQuadratic(input, output) { + TestUtil.testSimplification(factorQuadratic, input, output); +} + +describe('factorQuadratic', () => { + const tests = [ + ['x^2', 'x^2'], + ['x^2 + x^2', 'x^2 + x^2'], + ['x^2 + 2 - 3', 'x^2 + 2 - 3'], + ['x^2 + 2y + 2x + 3', 'x^2 + 2y + 2x + 3'], + ['x^2 + 2x', 'x * (x + 2)'], + ['-x^2 - 2x', '-x * (x + 2)'], + ['x^2 - 3x', 'x * (x - 3)'], + ['2x^2 + 2x', '2x * (x + 1)'], + ['x^2 - 4', '(x + 2) * (x - 2)'], + ['x^2 + 4', 'x^2 + 4'], + ['x^2 + 2x + 1', '(x + 1)^2'], + ['x^2 - 2x + 1', '(x - 1)^2'], + ['x^2 + 3x + 2', '(x + 1) * (x + 2)'], + ['x^2 - 3x + 2', '(x - 1) * (x - 2)'], + ['x^2 + x - 2', '(x - 1) * (x + 2)'], + ['x^2 + 4x + 1', 'x^2 + 4x + 1'], + ['x^2 - 3x + 1', 'x^2 - 3x + 1'], + ['x^2 + 4 + 2^x', 'x^2 + 4 + 2^x'], + ['-x^2 - 2x - 1', '-(x + 1)^2'], + ['-x^2 - 3x - 2', '-(x + 1) * (x + 2)'], + ['-x^2 + 1', '-(x + 1) * (x - 1)'], + ['-x^2 - 1', '-x^2 - 1'], + ]; + tests.forEach(t => testFactorQuadratic(t[0], t[1])); +}); diff --git a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js deleted file mode 100644 index 0503b586..00000000 --- a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js +++ /dev/null @@ -1,16 +0,0 @@ -const arithmeticSearch = require('../../../lib/simplifyExpression/arithmeticSearch'); - -const TestUtil = require('../../TestUtil'); - -function testArithmeticSearch(exprStr, outputStr) { - TestUtil.testSimplification(arithmeticSearch, exprStr, outputStr); -} - -describe('evaluate arithmeticSearch', function () { - const tests = [ - ['2+2', '4'], - ['2*3*5', '30'], - ['9/4', '9/4'], // does not divide - ]; - tests.forEach(t => testArithmeticSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts new file mode 100644 index 00000000..b09df7e7 --- /dev/null +++ b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts @@ -0,0 +1,16 @@ +import arithmeticSearch = require('../../../lib/simplifyExpression/arithmeticSearch'); +import TestUtil = require('../../TestUtil'); + +function testArithmeticSearch(exprStr: any, outputStr: any); +function testArithmeticSearch(exprStr, outputStr) { + TestUtil.testSimplification(arithmeticSearch, exprStr, outputStr); +} + +describe('evaluate arithmeticSearch', () => { + const tests = [ + ['2+2', '4'], + ['2*3*5', '30'], + ['9/4', '9/4'], // does not divide + ]; + tests.forEach(t => testArithmeticSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js deleted file mode 100644 index d163dd7e..00000000 --- a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js +++ /dev/null @@ -1,11 +0,0 @@ -const rearrangeCoefficient = require('../../../lib/simplifyExpression/basicsSearch/rearrangeCoefficient'); - -const testSimplify = require('./testSimplify'); - -describe('rearrangeCoefficient', function() { - const tests = [ - ['2 * x^2', '2x^2'], - ['y^3 * 5', '5y^3'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], rearrangeCoefficient)); -}); diff --git a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts new file mode 100644 index 00000000..649258f8 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts @@ -0,0 +1,9 @@ +import rearrangeCoefficient = require('../../../lib/simplifyExpression/basicsSearch/rearrangeCoefficient'); +import testSimplify = require('./testSimplify'); +describe('rearrangeCoefficient', () => { + const tests = [ + ['2 * x^2', '2x^2'], + ['y^3 * 5', '5y^3'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], rearrangeCoefficient)); +}); diff --git a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js deleted file mode 100644 index 506728f8..00000000 --- a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js +++ /dev/null @@ -1,7 +0,0 @@ -const reduceExponentByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceExponentByZero'); - -const testSimplify = require('./testSimplify'); - -describe('reduceExponentByZero', function() { - testSimplify('(x+3)^0', '1', reduceExponentByZero); -}); diff --git a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts new file mode 100644 index 00000000..2e6e92f6 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts @@ -0,0 +1,5 @@ +import reduceExponentByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceExponentByZero'); +import testSimplify = require('./testSimplify'); +describe('reduceExponentByZero', () => { + testSimplify('(x+3)^0', '1', reduceExponentByZero); +}); diff --git a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js deleted file mode 100644 index 490a6f91..00000000 --- a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js +++ /dev/null @@ -1,11 +0,0 @@ -const reduceMultiplicationByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero'); - -const testSimplify = require('./testSimplify'); - -describe('reduce multiplication by 0', function () { - const tests = [ - ['0x', '0'], - ['2*0*z^2','0'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], reduceMultiplicationByZero)); -}); diff --git a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts new file mode 100644 index 00000000..b959246b --- /dev/null +++ b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts @@ -0,0 +1,9 @@ +import reduceMultiplicationByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero'); +import testSimplify = require('./testSimplify'); +describe('reduce multiplication by 0', () => { + const tests = [ + ['0x', '0'], + ['2*0*z^2','0'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], reduceMultiplicationByZero)); +}); diff --git a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js deleted file mode 100644 index 2c24f182..00000000 --- a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js +++ /dev/null @@ -1,11 +0,0 @@ -const reduceZeroDividedByAnything = require('../../../lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything'); - -const testSimplify = require('./testSimplify'); - -describe('simplify basics', function () { - const tests = [ - ['0/5', '0'], - ['0/(x+6+7+x^2+2^y)', '0'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], reduceZeroDividedByAnything)); -}); diff --git a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts new file mode 100644 index 00000000..9990c284 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts @@ -0,0 +1,9 @@ +import reduceZeroDividedByAnything = require('../../../lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything'); +import testSimplify = require('./testSimplify'); +describe('simplify basics', () => { + const tests = [ + ['0/5', '0'], + ['0/(x+6+7+x^2+2^y)', '0'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], reduceZeroDividedByAnything)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js deleted file mode 100644 index 1d288236..00000000 --- a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const removeAdditionOfZero = require('../../../lib/simplifyExpression/basicsSearch/removeAdditionOfZero'); - -const testSimplify = require('./testSimplify'); - -describe('removeAdditionOfZero', function() { - var tests = [ - ['2+0+x', '2 + x'], - ['2+x+0', '2 + x'], - ['0+2+x', '2 + x'] - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeAdditionOfZero)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts new file mode 100644 index 00000000..8f5d637b --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts @@ -0,0 +1,10 @@ +import removeAdditionOfZero = require('../../../lib/simplifyExpression/basicsSearch/removeAdditionOfZero'); +import testSimplify = require('./testSimplify'); +describe('removeAdditionOfZero', () => { + var tests = [ + ['2+0+x', '2 + x'], + ['2+x+0', '2 + x'], + ['0+2+x', '2 + x'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeAdditionOfZero)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js deleted file mode 100644 index acee1f9f..00000000 --- a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js +++ /dev/null @@ -1,7 +0,0 @@ -const removeDivisionByOne = require('../../../lib/simplifyExpression/basicsSearch/removeDivisionByOne'); - -const testSimplify = require('./testSimplify'); - -describe('removeDivisionByOne', function() { - testSimplify('x/1', 'x', removeDivisionByOne); -}); diff --git a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts new file mode 100644 index 00000000..0b53539f --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts @@ -0,0 +1,5 @@ +import removeDivisionByOne = require('../../../lib/simplifyExpression/basicsSearch/removeDivisionByOne'); +import testSimplify = require('./testSimplify'); +describe('removeDivisionByOne', () => { + testSimplify('x/1', 'x', removeDivisionByOne); +}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js deleted file mode 100644 index 5aac993f..00000000 --- a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const removeExponentBaseOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentBaseOne'); - -const testSimplify = require('./testSimplify'); - -describe('removeExponentBaseOne', function() { - const tests = [ - ['1^3', '1'], - ['1^x', '1^x'], - ['1^(2 + 3 + 5/4 + 7 - 6/7)', '1'] - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeExponentBaseOne)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts new file mode 100644 index 00000000..6ce29e8e --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts @@ -0,0 +1,10 @@ +import removeExponentBaseOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentBaseOne'); +import testSimplify = require('./testSimplify'); +describe('removeExponentBaseOne', () => { + const tests = [ + ['1^3', '1'], + ['1^x', '1^x'], + ['1^(2 + 3 + 5/4 + 7 - 6/7)', '1'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeExponentBaseOne)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.js b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.js deleted file mode 100644 index 047d1de4..00000000 --- a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.js +++ /dev/null @@ -1,7 +0,0 @@ -const removeExponentByOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentByOne'); - -const testSimplify = require('./testSimplify'); - -describe('removeExponentByOne', function() { - testSimplify('x^1', 'x', removeExponentByOne); -}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts new file mode 100644 index 00000000..83457192 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts @@ -0,0 +1,5 @@ +import removeExponentByOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentByOne'); +import testSimplify = require('./testSimplify'); +describe('removeExponentByOne', () => { + testSimplify('x^1', 'x', removeExponentByOne); +}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js deleted file mode 100644 index e701c1f1..00000000 --- a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const removeMultiplicationByNegativeOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne'); - -const testSimplify = require('./testSimplify'); - -describe('removeMultiplicationByNegativeOne', function() { - const tests = [ - ['-1*x', '-x'], - ['x^2*-1', '-x^2'], - ['2x*2*-1', '2x * 2 * -1'], // does not remove multiplication by -1 - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByNegativeOne)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts new file mode 100644 index 00000000..2d6c5e52 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts @@ -0,0 +1,10 @@ +import removeMultiplicationByNegativeOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne'); +import testSimplify = require('./testSimplify'); +describe('removeMultiplicationByNegativeOne', () => { + const tests = [ + ['-1*x', '-x'], + ['x^2*-1', '-x^2'], + ['2x*2*-1', '2x * 2 * -1'], // does not remove multiplication by -1 + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByNegativeOne)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js deleted file mode 100644 index 0e554444..00000000 --- a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js +++ /dev/null @@ -1,13 +0,0 @@ -const removeMultiplicationByOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByOne'); - -const testSimplify = require('./testSimplify'); - -describe('removeMultiplicationByOne', function() { - const tests = [ - ['x*1', 'x'], - ['1x', 'x'], - ['1*z^2', 'z^2'], - ['2*1*z^2', '2 * 1z^2'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByOne)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts new file mode 100644 index 00000000..f868f402 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts @@ -0,0 +1,11 @@ +import removeMultiplicationByOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByOne'); +import testSimplify = require('./testSimplify'); +describe('removeMultiplicationByOne', () => { + const tests = [ + ['x*1', 'x'], + ['1x', 'x'], + ['1*z^2', 'z^2'], + ['2*1*z^2', '2 * 1z^2'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByOne)); +}); diff --git a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js deleted file mode 100644 index 33c13a44..00000000 --- a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const simplifyDoubleUnaryMinus = require('../../../lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus'); - -const testSimplify = require('./testSimplify'); - - -describe('simplifyDoubleUnaryMinus', function() { - var tests = [ - ['--5', '5'], - ['--x', 'x'] - ]; - tests.forEach(t => testSimplify(t[0], t[1], simplifyDoubleUnaryMinus)); -}); diff --git a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts new file mode 100644 index 00000000..4fddcfc3 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts @@ -0,0 +1,9 @@ +import simplifyDoubleUnaryMinus = require('../../../lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus'); +import testSimplify = require('./testSimplify'); +describe('simplifyDoubleUnaryMinus', () => { + var tests = [ + ['--5', '5'], + ['--x', 'x'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], simplifyDoubleUnaryMinus)); +}); diff --git a/test/simplifyExpression/basicsSearch/testSimplify.js b/test/simplifyExpression/basicsSearch/testSimplify.js deleted file mode 100644 index fdf6be37..00000000 --- a/test/simplifyExpression/basicsSearch/testSimplify.js +++ /dev/null @@ -1,18 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const flatten = require('../../../lib/util/flattenOperands'); -const print = require('../../../lib/util/print'); - - -function testSimplify(exprStr, outputStr, simplifyOperation) { - it(exprStr + ' -> ' + outputStr, function () { - const inputNode = flatten(math.parse(exprStr)); - const newNode = simplifyOperation(inputNode).newNode; - assert.equal( - print(newNode), - outputStr); - }); -} - -module.exports = testSimplify; diff --git a/test/simplifyExpression/basicsSearch/testSimplify.ts b/test/simplifyExpression/basicsSearch/testSimplify.ts new file mode 100644 index 00000000..7669b340 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/testSimplify.ts @@ -0,0 +1,17 @@ +const assert = require('assert'); +import math = require('mathjs'); +import flatten = require('../../../lib/util/flattenOperands'); +import print = require('../../../lib/util/print'); + +function testSimplify(exprStr: any, outputStr: any, simplifyOperation: any); +function testSimplify(exprStr, outputStr, simplifyOperation) { + it(exprStr + ' -> ' + outputStr, () => { + const inputNode = flatten(math.parse(exprStr)); + const newNode = simplifyOperation(inputNode).newNode; + assert.equal( + print(newNode), + outputStr); + }); +} + +export = testSimplify; diff --git a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js deleted file mode 100644 index 73aef5c1..00000000 --- a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js +++ /dev/null @@ -1,16 +0,0 @@ -const breakUpNumeratorSearch = require('../../../lib/simplifyExpression/breakUpNumeratorSearch'); - -const TestUtil = require('../../TestUtil'); - -function testBreakUpNumeratorSearch(exprStr, outputStr) { - TestUtil.testSimplification(breakUpNumeratorSearch, exprStr, outputStr); -} - -describe('breakUpNumerator', function() { - const tests = [ - ['(x+3+y)/3', '(x / 3 + 3/3 + y / 3)'], - ['(2+x)/4', '(2/4 + x / 4)'], - ['2(x+3)/3', '2 * (x / 3 + 3/3)'], - ]; - tests.forEach(t => testBreakUpNumeratorSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts new file mode 100644 index 00000000..bb9f8b52 --- /dev/null +++ b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts @@ -0,0 +1,16 @@ +import breakUpNumeratorSearch = require('../../../lib/simplifyExpression/breakUpNumeratorSearch'); +import TestUtil = require('../../TestUtil'); + +function testBreakUpNumeratorSearch(exprStr: any, outputStr: any); +function testBreakUpNumeratorSearch(exprStr, outputStr) { + TestUtil.testSimplification(breakUpNumeratorSearch, exprStr, outputStr); +} + +describe('breakUpNumerator', () => { + const tests = [ + ['(x+3+y)/3', '(x / 3 + 3/3 + y / 3)'], + ['(2+x)/4', '(2/4 + x / 4)'], + ['2(x+3)/3', '2 * (x / 3 + 3/3)'], + ]; + tests.forEach(t => testBreakUpNumeratorSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js deleted file mode 100644 index baad5b9d..00000000 --- a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js +++ /dev/null @@ -1,97 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const flatten = require('../../../lib/util/flattenOperands'); -const print = require('../../../lib/util/print'); - -const LikeTermCollector = require('../../../lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector'); - -function testCollectLikeTerms(exprStr, outputStr, explanation='', debug=false) { - let description = `${exprStr} -> ${outputStr}`; - - if (explanation) { - description += ` (${explanation})`; - } - - it(description, () => { - const exprTree = flatten(math.parse(exprStr)); - const collected = print(LikeTermCollector.collectLikeTerms(exprTree).newNode); - if (debug) { - // eslint-disable-next-line - console.log(collected); - } - assert.equal(collected, outputStr); - }); -} - -function testCanCollectLikeTerms(exprStr, canCollect, explanation) { - let description = `${exprStr} -> ${canCollect}`; - - if (explanation) { - description += ` (${explanation})`; - } - - it(description , () => { - const exprTree = flatten(math.parse(exprStr)); - assert.equal( - LikeTermCollector.canCollectLikeTerms(exprTree), - canCollect); - }); -} - -describe('can collect like terms for addition', function () { - const tests = [ - ['2+2', false, 'because only one type'], - ['x^2+x^2', false, 'because only one type'], - ['x+2', false, 'because all types have only one'], - ['(x+2+x)', false, 'because in parenthesis, need to be collected first'], - ['x+2+x', true], - ['x^2 + 5 + x + x^2', true], - ]; - tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe('can collect like terms for multiplication', function () { - const tests = [ - ['2*2', false, 'because only one type'], - ['x^2 * 2x^2', true], - ['x * 2', false, 'because all types have only one'], - ['((2x^2)) * y * x * y^3', true], - ]; - tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe('basic addition collect like terms, no exponents or coefficients', function() { - const tests = [ - ['2+x+7', 'x + (2 + 7)'], - ['x + 4 + x + 5', '(x + x) + (4 + 5)'], - ['x + 4 + y', 'x + 4 + y'], - ['x + 4 + x + 4/9 + y + 5/7', '(x + x) + y + 4 + (4/9 + 5/7)'], - ['x + 4 + x + 2^x + 5', '(x + x) + (4 + 5) + 2^x', - 'because 2^x is an \'other\''], - ['z + 2*(y + x) + 4 + z', '(z + z) + 4 + 2 * (y + x)', - '2*(y + x) is an \'other\' cause it has parens'], - ]; - tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe('collect like terms with exponents and coefficients', function() { - const tests = [ - ['x^2 + x + x^2 + x', '(x^2 + x^2) + (x + x)'], - ['y^2 + 5 + y^2 + 5', '(y^2 + y^2) + (5 + 5)'], - ['y + 5 + z^2', 'y + 5 + z^2'], - ['2x^2 + x + x^2 + 3x', '(2x^2 + x^2) + (x + 3x)'], - ]; - tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe('collect like terms for multiplication', function() { - const tests = [ - ['2x^2 * y * x * y^3', '2 * (x^2 * x) * (y * y^3)'], - ['y^2 * 5 * y * 9', '(5 * 9) * (y^2 * y)'], - ['5y^2 * -4y * 9', '(5 * -4 * 9) * (y^2 * y)'], - ['5y^2 * -y * 9', '(5 * -1 * 9) * (y^2 * y)'], - ['y * 5 * (2+x) * y^2 * 1/3', '(5 * 1/3) * (y * y^2) * (2 + x)'], - ]; - tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); -}); diff --git a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts new file mode 100644 index 00000000..02bc9bd2 --- /dev/null +++ b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts @@ -0,0 +1,96 @@ +const assert = require('assert'); +import math = require('mathjs'); +import flatten = require('../../../lib/util/flattenOperands'); +import print = require('../../../lib/util/print'); +import LikeTermCollector = require('../../../lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector'); + +function testCollectLikeTerms(exprStr, outputStr, explanation='', debug=false) { + let description = `${exprStr} -> ${outputStr}`; + + if (explanation) { + description += ` (${explanation})`; + } + + it(description, () => { + const exprTree = flatten(math.parse(exprStr)); + const collected = print(LikeTermCollector.collectLikeTerms(exprTree).newNode); + if (debug) { + // eslint-disable-next-line + console.log(collected); + } + assert.equal(collected, outputStr); + }); +} + +function testCanCollectLikeTerms(exprStr: any, canCollect: any, explanation: any); +function testCanCollectLikeTerms(exprStr, canCollect, explanation) { + let description = `${exprStr} -> ${canCollect}`; + + if (explanation) { + description += ` (${explanation})`; + } + + it(description , () => { + const exprTree = flatten(math.parse(exprStr)); + assert.equal( + LikeTermCollector.canCollectLikeTerms(exprTree), + canCollect); + }); +} + +describe('can collect like terms for addition', () => { + const tests = [ + ['2+2', false, 'because only one type'], + ['x^2+x^2', false, 'because only one type'], + ['x+2', false, 'because all types have only one'], + ['(x+2+x)', false, 'because in parenthesis, need to be collected first'], + ['x+2+x', true], + ['x^2 + 5 + x + x^2', true], + ]; + tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('can collect like terms for multiplication', () => { + const tests = [ + ['2*2', false, 'because only one type'], + ['x^2 * 2x^2', true], + ['x * 2', false, 'because all types have only one'], + ['((2x^2)) * y * x * y^3', true], + ]; + tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('basic addition collect like terms, no exponents or coefficients', () => { + const tests = [ + ['2+x+7', 'x + (2 + 7)'], + ['x + 4 + x + 5', '(x + x) + (4 + 5)'], + ['x + 4 + y', 'x + 4 + y'], + ['x + 4 + x + 4/9 + y + 5/7', '(x + x) + y + 4 + (4/9 + 5/7)'], + ['x + 4 + x + 2^x + 5', '(x + x) + (4 + 5) + 2^x', + 'because 2^x is an \'other\''], + ['z + 2*(y + x) + 4 + z', '(z + z) + 4 + 2 * (y + x)', + '2*(y + x) is an \'other\' cause it has parens'], + ]; + tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('collect like terms with exponents and coefficients', () => { + const tests = [ + ['x^2 + x + x^2 + x', '(x^2 + x^2) + (x + x)'], + ['y^2 + 5 + y^2 + 5', '(y^2 + y^2) + (5 + 5)'], + ['y + 5 + z^2', 'y + 5 + z^2'], + ['2x^2 + x + x^2 + 3x', '(2x^2 + x^2) + (x + 3x)'], + ]; + tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('collect like terms for multiplication', () => { + const tests = [ + ['2x^2 * y * x * y^3', '2 * (x^2 * x) * (y * y^3)'], + ['y^2 * 5 * y * 9', '(5 * 9) * (y^2 * y)'], + ['5y^2 * -4y * 9', '(5 * -4 * 9) * (y^2 * y)'], + ['5y^2 * -y * 9', '(5 * -1 * 9) * (y^2 * y)'], + ['y * 5 * (2+x) * y^2 * 1/3', '(5 * 1/3) * (y * y^2) * (2 + x)'], + ]; + tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); +}); diff --git a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js deleted file mode 100644 index b2335179..00000000 --- a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js +++ /dev/null @@ -1,62 +0,0 @@ -const collectAndCombineSearch = require('../../../lib/simplifyExpression/collectAndCombineSearch'); - -const TestUtil = require('../../TestUtil'); - -function testCollectAndCombineSubsteps(exprString, outputList, outputStr) { - TestUtil.testSubsteps(collectAndCombineSearch, exprString, outputList, outputStr); -} - -function testSimpleCollectAndCombineSearch(exprString, outputStr) { - TestUtil.testSimplification(collectAndCombineSearch, exprString, outputStr); -} - -describe('combinePolynomialTerms multiplication', function() { - const tests = [ - ['x^2 * x * x', - ['x^2 * x^1 * x^1', - 'x^(2 + 1 + 1)', - 'x^4'], - ], - ['y * y^3', - ['y^1 * y^3', - 'y^(1 + 3)', - 'y^4'], - ], - ['2x * x^2 * 5x', - ['(2 * 5) * (x * x^2 * x)', - '10 * (x * x^2 * x)', - '10x^4'], - '10x^4' - ], - ]; - tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1], t[2])); -}); - -describe('combinePolynomialTerms addition', function() { - const tests = [ - ['x+x', - ['1x + 1x', - '(1 + 1) * x', - '2x'] - ], - ['4y^2 + 7y^2 + y^2', - ['4y^2 + 7y^2 + 1y^2', - '(4 + 7 + 1) * y^2', - '12y^2'] - ], - ['2x + 4x + y', - ['(2x + 4x) + y', - '6x + y'], - '6x + y' - ], - ]; - tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1])); -}); - -describe('collectAndCombineSearch with no substeps', function () { - const tests = [ - ['2x + 4x + x', '7x'], - ['x * x^2 * x', 'x^4'] - ]; - tests.forEach(t => testSimpleCollectAndCombineSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts new file mode 100644 index 00000000..7ebd2402 --- /dev/null +++ b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts @@ -0,0 +1,63 @@ +import collectAndCombineSearch = require('../../../lib/simplifyExpression/collectAndCombineSearch'); +import TestUtil = require('../../TestUtil'); + +function testCollectAndCombineSubsteps(exprString: any, outputList: any, outputStr: any); +function testCollectAndCombineSubsteps(exprString, outputList, outputStr) { + TestUtil.testSubsteps(collectAndCombineSearch, exprString, outputList, outputStr); +} + +function testSimpleCollectAndCombineSearch(exprString: any, outputStr: any); +function testSimpleCollectAndCombineSearch(exprString, outputStr) { + TestUtil.testSimplification(collectAndCombineSearch, exprString, outputStr); +} + +describe('combinePolynomialTerms multiplication', () => { + const tests = [ + ['x^2 * x * x', + ['x^2 * x^1 * x^1', + 'x^(2 + 1 + 1)', + 'x^4'], + ], + ['y * y^3', + ['y^1 * y^3', + 'y^(1 + 3)', + 'y^4'], + ], + ['2x * x^2 * 5x', + ['(2 * 5) * (x * x^2 * x)', + '10 * (x * x^2 * x)', + '10x^4'], + '10x^4' + ], + ]; + tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1], t[2])); +}); + +describe('combinePolynomialTerms addition', () => { + const tests = [ + ['x+x', + ['1x + 1x', + '(1 + 1) * x', + '2x'] + ], + ['4y^2 + 7y^2 + y^2', + ['4y^2 + 7y^2 + 1y^2', + '(4 + 7 + 1) * y^2', + '12y^2'] + ], + ['2x + 4x + y', + ['(2x + 4x) + y', + '6x + y'], + '6x + y' + ], + ]; + tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1])); +}); + +describe('collectAndCombineSearch with no substeps', () => { + const tests = [ + ['2x + 4x + x', '7x'], + ['x * x^2 * x', 'x^4'] + ]; + tests.forEach(t => testSimpleCollectAndCombineSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js deleted file mode 100644 index 972c2f57..00000000 --- a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js +++ /dev/null @@ -1,33 +0,0 @@ -const evaluateConstantSum = require('../../../lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum'); - -const TestUtil = require('../../TestUtil'); - -function testEvaluateConstantSum(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(evaluateConstantSum, exprString, outputList, lastString); -} - -describe('evaluateConstantSum', function () { - const tests = [ - ['4/10 + 3/5', - ['4/10 + (3 * 2) / (5 * 2)', - '4/10 + (3 * 2) / 10', - '4/10 + 6/10', - '(4 + 6) / 10', - '10/10', - '1'] - ], - ['4/5 + 3/5 + 2', - ['2 + (4/5 + 3/5)', - '2 + 7/5', - '17/5'] - ], - ['9 + 4/5 + 1/5 + 2', - ['(9 + 2) + (4/5 + 1/5)', - '11 + (4/5 + 1/5)', - '11 + 1', - '12'] - ], - ]; - tests.forEach(t => testEvaluateConstantSum(t[0], t[1])); -}); diff --git a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts new file mode 100644 index 00000000..9b24eabc --- /dev/null +++ b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts @@ -0,0 +1,33 @@ +import evaluateConstantSum = require('../../../lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum'); +import TestUtil = require('../../TestUtil'); + +function testEvaluateConstantSum(exprString: any, outputList: any); +function testEvaluateConstantSum(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(evaluateConstantSum, exprString, outputList, lastString); +} + +describe('evaluateConstantSum', () => { + const tests = [ + ['4/10 + 3/5', + ['4/10 + (3 * 2) / (5 * 2)', + '4/10 + (3 * 2) / 10', + '4/10 + 6/10', + '(4 + 6) / 10', + '10/10', + '1'] + ], + ['4/5 + 3/5 + 2', + ['2 + (4/5 + 3/5)', + '2 + 7/5', + '17/5'] + ], + ['9 + 4/5 + 1/5 + 2', + ['(9 + 2) + (4/5 + 1/5)', + '11 + (4/5 + 1/5)', + '11 + 1', + '12'] + ], + ]; + tests.forEach(t => testEvaluateConstantSum(t[0], t[1])); +}); diff --git a/test/simplifyExpression/distributeSearch/distributeSearch.test.js b/test/simplifyExpression/distributeSearch/distributeSearch.test.js deleted file mode 100644 index 0aa38c6c..00000000 --- a/test/simplifyExpression/distributeSearch/distributeSearch.test.js +++ /dev/null @@ -1,89 +0,0 @@ -const distributeSearch = require('../../../lib/simplifyExpression/distributeSearch'); - -const TestUtil = require('../../TestUtil'); - -function testDistribute(exprStr, outputStr) { - TestUtil.testSimplification(distributeSearch, exprStr, outputStr); -} - -describe('distribute - into paren with addition', function () { - const tests = [ - ['-(x+3)', '(-x - 3)'], - ['-(x - 3)', '(-x + 3)'], - ['-(-x^2 + 3y^6)' , '(x^2 - 3y^6)'], - ]; - tests.forEach(t => testDistribute(t[0], t[1])); -}); - -describe('distribute - into paren with multiplication/division', function () { - const tests = [ - ['-(x*3)', '(-x * 3)'], - ['-(-x * 3)', '(x * 3)'], - ['-(-x^2 * 3y^6)', '(x^2 * 3y^6)'], - ]; - tests.forEach(t => testDistribute(t[0], t[1])); -}); - -function testDistributeSteps(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(distributeSearch, exprString, outputList, lastString); -} - -describe('distribute', function () { - const tests = [ - ['x*(x+2+y)', - ['(x * x + x * 2 + x * y)', - '(x^2 + 2x + x * y)'] - ], - ['(x+2+y)*x*7', - ['(x * x + 2x + y * x) * 7', - '(x^2 + 2x + y * x) * 7'] - ], - ['(5+x)*(x+3)', - ['(5 * (x + 3) + x * (x + 3))', - '((5x + 15) + (x^2 + 3x))'] - ], - ['-2x^2 * (3x - 4)', - ['(-2x^2 * 3x - 2x^2 * -4)', - '(-6x^3 + 8x^2)'] - ], - ]; - tests.forEach(t => testDistributeSteps(t[0], t[1])); -}); - -describe('distribute with fractions', function () { - const tests = [ - // distribute the non-fraction term into the numerator(s) - ['(3 / x^2 + x / (x^2 + 3)) * (x^2 + 3)', - '((3 * (x^2 + 3)) / (x^2) + (x * (x^2 + 3)) / (x^2 + 3))', - ], - - // if both groupings have fraction, the rule does not apply - ['(3 / x^2 + x / (x^2 + 3)) * (5 / x + x^5)', - '((3 / (x^2) * 5 / x + 3 / (x^2) * x^5) + (x / (x^2 + 3) * 5 / x + x / (x^2 + 3) * x^5))', - ], - ]; - - const multiStepTests = [ - - ['(2 / x + 3x^2) * (x^3 + 1)', - ['((2 * (x^3 + 1)) / x + 3x^2 * (x^3 + 1))', - '((2 * (x^3 + 1)) / x + (3x^5 + 3x^2))'] - ], - - ['(2x + x^2) * (1 / (x^2 -4) + 4x^2)', - ['((1 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', - '((1 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] - ], - - ['(2x + x^2) * (3x^2 / (x^2 -4) + 4x^2)', - ['((3x^2 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', - '((3x^2 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] - ], - - ]; - - tests.forEach(t => testDistribute(t[0], t[1])); - - multiStepTests.forEach(t => testDistributeSteps(t[0], t[1])); -}); diff --git a/test/simplifyExpression/distributeSearch/distributeSearch.test.ts b/test/simplifyExpression/distributeSearch/distributeSearch.test.ts new file mode 100644 index 00000000..5f9f1190 --- /dev/null +++ b/test/simplifyExpression/distributeSearch/distributeSearch.test.ts @@ -0,0 +1,90 @@ +import distributeSearch = require('../../../lib/simplifyExpression/distributeSearch'); +import TestUtil = require('../../TestUtil'); + +function testDistribute(exprStr: any, outputStr: any); +function testDistribute(exprStr, outputStr) { + TestUtil.testSimplification(distributeSearch, exprStr, outputStr); +} + +describe('distribute - into paren with addition', () => { + const tests = [ + ['-(x+3)', '(-x - 3)'], + ['-(x - 3)', '(-x + 3)'], + ['-(-x^2 + 3y^6)' , '(x^2 - 3y^6)'], + ]; + tests.forEach(t => testDistribute(t[0], t[1])); +}); + +describe('distribute - into paren with multiplication/division', () => { + const tests = [ + ['-(x*3)', '(-x * 3)'], + ['-(-x * 3)', '(x * 3)'], + ['-(-x^2 * 3y^6)', '(x^2 * 3y^6)'], + ]; + tests.forEach(t => testDistribute(t[0], t[1])); +}); + +function testDistributeSteps(exprString: any, outputList: any); +function testDistributeSteps(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(distributeSearch, exprString, outputList, lastString); +} + +describe('distribute', () => { + const tests = [ + ['x*(x+2+y)', + ['(x * x + x * 2 + x * y)', + '(x^2 + 2x + x * y)'] + ], + ['(x+2+y)*x*7', + ['(x * x + 2x + y * x) * 7', + '(x^2 + 2x + y * x) * 7'] + ], + ['(5+x)*(x+3)', + ['(5 * (x + 3) + x * (x + 3))', + '((5x + 15) + (x^2 + 3x))'] + ], + ['-2x^2 * (3x - 4)', + ['(-2x^2 * 3x - 2x^2 * -4)', + '(-6x^3 + 8x^2)'] + ], + ]; + tests.forEach(t => testDistributeSteps(t[0], t[1])); +}); + +describe('distribute with fractions', () => { + const tests = [ + // distribute the non-fraction term into the numerator(s) + ['(3 / x^2 + x / (x^2 + 3)) * (x^2 + 3)', + '((3 * (x^2 + 3)) / (x^2) + (x * (x^2 + 3)) / (x^2 + 3))', + ], + + // if both groupings have fraction, the rule does not apply + ['(3 / x^2 + x / (x^2 + 3)) * (5 / x + x^5)', + '((3 / (x^2) * 5 / x + 3 / (x^2) * x^5) + (x / (x^2 + 3) * 5 / x + x / (x^2 + 3) * x^5))', + ], + ]; + + const multiStepTests = [ + + ['(2 / x + 3x^2) * (x^3 + 1)', + ['((2 * (x^3 + 1)) / x + 3x^2 * (x^3 + 1))', + '((2 * (x^3 + 1)) / x + (3x^5 + 3x^2))'] + ], + + ['(2x + x^2) * (1 / (x^2 -4) + 4x^2)', + ['((1 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', + '((1 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] + ], + + ['(2x + x^2) * (3x^2 / (x^2 -4) + 4x^2)', + ['((3x^2 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', + '((3x^2 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] + ], + + ]; + + tests.forEach(t => testDistribute(t[0], t[1])); + + multiStepTests.forEach(t => testDistributeSteps(t[0], t[1])); +}); diff --git a/test/simplifyExpression/divisionSearch/divisionSearch.test.js b/test/simplifyExpression/divisionSearch/divisionSearch.test.js deleted file mode 100644 index 2d4a3a5b..00000000 --- a/test/simplifyExpression/divisionSearch/divisionSearch.test.js +++ /dev/null @@ -1,21 +0,0 @@ -const divisionSearch = require('../../../lib/simplifyExpression/divisionSearch'); - -const TestUtil = require('../../TestUtil'); - -function testSimplifyDivision(exprStr, outputStr) { - TestUtil.testSimplification(divisionSearch, exprStr, outputStr); -} - -describe('simplifyDivision', function () { - const tests = [ - ['6/x/5', '6 / (x * 5)'], - ['-(6/x/5)', '-(6 / (x * 5))'], - ['-6/x/5', '-6 / (x * 5)'], - ['(2+2)/x/6/(y-z)','(2 + 2) / (x * 6 * (y - z))'], - ['2/x', '2 / x'], - ['x/(2/3)', 'x * 3/2'], - ['x / (y/(z+a))', 'x * (z + a) / y'], - ['x/((2+z)/(3/y))', 'x * (3 / y) / (2 + z)'], - ]; - tests.forEach(t => testSimplifyDivision(t[0], t[1])); -}); diff --git a/test/simplifyExpression/divisionSearch/divisionSearch.test.ts b/test/simplifyExpression/divisionSearch/divisionSearch.test.ts new file mode 100644 index 00000000..b56ea72d --- /dev/null +++ b/test/simplifyExpression/divisionSearch/divisionSearch.test.ts @@ -0,0 +1,21 @@ +import divisionSearch = require('../../../lib/simplifyExpression/divisionSearch'); +import TestUtil = require('../../TestUtil'); + +function testSimplifyDivision(exprStr: any, outputStr: any); +function testSimplifyDivision(exprStr, outputStr) { + TestUtil.testSimplification(divisionSearch, exprStr, outputStr); +} + +describe('simplifyDivision', () => { + const tests = [ + ['6/x/5', '6 / (x * 5)'], + ['-(6/x/5)', '-(6 / (x * 5))'], + ['-6/x/5', '-6 / (x * 5)'], + ['(2+2)/x/6/(y-z)','(2 + 2) / (x * 6 * (y - z))'], + ['2/x', '2 / x'], + ['x/(2/3)', 'x * 3/2'], + ['x / (y/(z+a))', 'x * (z + a) / y'], + ['x/((2+z)/(3/y))', 'x * (3 / y) / (2 + z)'], + ]; + tests.forEach(t => testSimplifyDivision(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js deleted file mode 100644 index 0219bb8b..00000000 --- a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js +++ /dev/null @@ -1,32 +0,0 @@ -const addConstantAndFraction = require('../../../lib/simplifyExpression/fractionsSearch/addConstantAndFraction'); - -const TestUtil = require('../../TestUtil'); - -function testAddConstantAndFraction(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(addConstantAndFraction, exprString, outputList, lastString); -} - -describe('addConstantAndFraction', function () { - const tests = [ - ['7 + 1/2', - ['14/2 + 1/2', - '(14 + 1) / 2', - '15/2'] - ], - ['5/6 + 3', - ['5/6 + 18/6', - '(5 + 18) / 6', - '23/6'], - ], - ['1/2 + 5.8', - ['0.5 + 5.8', - '6.3'], - ], - ['1/3 + 5.8', - ['0.3333 + 5.8', - '6.1333'] - ], - ]; - tests.forEach(t => testAddConstantAndFraction(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts new file mode 100644 index 00000000..0b7a2603 --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts @@ -0,0 +1,32 @@ +import addConstantAndFraction = require('../../../lib/simplifyExpression/fractionsSearch/addConstantAndFraction'); +import TestUtil = require('../../TestUtil'); + +function testAddConstantAndFraction(exprString: any, outputList: any); +function testAddConstantAndFraction(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(addConstantAndFraction, exprString, outputList, lastString); +} + +describe('addConstantAndFraction', () => { + const tests = [ + ['7 + 1/2', + ['14/2 + 1/2', + '(14 + 1) / 2', + '15/2'] + ], + ['5/6 + 3', + ['5/6 + 18/6', + '(5 + 18) / 6', + '23/6'], + ], + ['1/2 + 5.8', + ['0.5 + 5.8', + '6.3'], + ], + ['1/3 + 5.8', + ['0.3333 + 5.8', + '6.1333'] + ], + ]; + tests.forEach(t => testAddConstantAndFraction(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.js b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.js deleted file mode 100644 index c023d94c..00000000 --- a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.js +++ /dev/null @@ -1,38 +0,0 @@ -const addConstantFractions = require('../../../lib/simplifyExpression/fractionsSearch/addConstantFractions'); - -const TestUtil = require('../../TestUtil'); - -function testAddConstantFractions(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(addConstantFractions, exprString, outputList, lastString); -} - -describe('addConstantFractions', function () { - const tests = [ - ['4/5 + 3/5', - ['(4 + 3) / 5', - '7/5'] - ], - ['4/10 + 3/5', - ['4/10 + (3 * 2) / (5 * 2)', - '4/10 + (3 * 2) / 10', - '4/10 + 6/10', - '(4 + 6) / 10', - '10/10', - '1'] - ], - ['4/9 + 3/5', - ['(4 * 5) / (9 * 5) + (3 * 9) / (5 * 9)', - '(4 * 5) / 45 + (3 * 9) / 45', - '20/45 + 27/45', - '(20 + 27) / 45', - '47/45'] - ], - ['4/5 - 4/5', - ['(4 - 4) / 5', - '0/5', - '0'] - ], - ]; - tests.forEach(t => testAddConstantFractions(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts new file mode 100644 index 00000000..5aefc818 --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts @@ -0,0 +1,38 @@ +import addConstantFractions = require('../../../lib/simplifyExpression/fractionsSearch/addConstantFractions'); +import TestUtil = require('../../TestUtil'); + +function testAddConstantFractions(exprString: any, outputList: any); +function testAddConstantFractions(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(addConstantFractions, exprString, outputList, lastString); +} + +describe('addConstantFractions', () => { + const tests = [ + ['4/5 + 3/5', + ['(4 + 3) / 5', + '7/5'] + ], + ['4/10 + 3/5', + ['4/10 + (3 * 2) / (5 * 2)', + '4/10 + (3 * 2) / 10', + '4/10 + 6/10', + '(4 + 6) / 10', + '10/10', + '1'] + ], + ['4/9 + 3/5', + ['(4 * 5) / (9 * 5) + (3 * 9) / (5 * 9)', + '(4 * 5) / 45 + (3 * 9) / 45', + '20/45 + 27/45', + '(20 + 27) / 45', + '47/45'] + ], + ['4/5 - 4/5', + ['(4 - 4) / 5', + '0/5', + '0'] + ], + ]; + tests.forEach(t => testAddConstantFractions(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js deleted file mode 100644 index 936d6ffe..00000000 --- a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js +++ /dev/null @@ -1,33 +0,0 @@ -const cancelLikeTerms = require('../../../lib/simplifyExpression/fractionsSearch/cancelLikeTerms'); - -const TestUtil = require('../../TestUtil'); - -function testCancelLikeTerms(exprStr, expectedStr) { - TestUtil.testSimplification(cancelLikeTerms, exprStr, expectedStr); -} - -describe('cancel like terms', function () { - const tests = [ - ['2/2', '1'], - ['x^2/x^2', '1'], - ['x^3/x^2', 'x^(3 - (2))'], // parens will be removed at end of step - ['(x^3*y)/x^2', '(x^(3 - (2)) * y)'], - ['-(7+x)^8/(7+x)^2', '-((7 + x)^(8 - (2)))'], - ['(2x^2 * 5) / (2x^2)', '5'], // these parens have to stay around 2x^2 to be parsed correctly. - ['(x^2 * y) / x', '(x^(2 - (1)) * y)'], - ['2x^2 / (2x^2 * 5)', '1/5'], - ['x / (x^2*y)', 'x^(1 - (2)) / y'], - ['(4x^2) / (5x^2)', '(4) / (5)'], - ['(2x+5)^8 / (2x+5)^2', '(2x + 5)^(8 - (2))'], - ['(4x^3) / (5x^2)', '(4x^(3 - (2))) / (5)'], - ['-x / -x', '1'], - ]; - - tests.forEach(t => { - const before = t[0]; - const after = t[1]; - it(before + ' -> ' + after, function () { - testCancelLikeTerms(before, after); - }); - }); -}); diff --git a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts new file mode 100644 index 00000000..f769f9ae --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts @@ -0,0 +1,33 @@ +import cancelLikeTerms = require('../../../lib/simplifyExpression/fractionsSearch/cancelLikeTerms'); +import TestUtil = require('../../TestUtil'); + +function testCancelLikeTerms(exprStr: any, expectedStr: any); +function testCancelLikeTerms(exprStr, expectedStr) { + TestUtil.testSimplification(cancelLikeTerms, exprStr, expectedStr); +} + +describe('cancel like terms', () => { + const tests = [ + ['2/2', '1'], + ['x^2/x^2', '1'], + ['x^3/x^2', 'x^(3 - (2))'], // parens will be removed at end of step + ['(x^3*y)/x^2', '(x^(3 - (2)) * y)'], + ['-(7+x)^8/(7+x)^2', '-((7 + x)^(8 - (2)))'], + ['(2x^2 * 5) / (2x^2)', '5'], // these parens have to stay around 2x^2 to be parsed correctly. + ['(x^2 * y) / x', '(x^(2 - (1)) * y)'], + ['2x^2 / (2x^2 * 5)', '1/5'], + ['x / (x^2*y)', 'x^(1 - (2)) / y'], + ['(4x^2) / (5x^2)', '(4) / (5)'], + ['(2x+5)^8 / (2x+5)^2', '(2x + 5)^(8 - (2))'], + ['(4x^3) / (5x^2)', '(4x^(3 - (2))) / (5)'], + ['-x / -x', '1'], + ]; + + tests.forEach(t => { + const before = t[0]; + const after = t[1]; + it(before + ' -> ' + after, () => { + testCancelLikeTerms(before, after); + }); + }); +}); diff --git a/test/simplifyExpression/fractionsSearch/divideByGCD.test.js b/test/simplifyExpression/fractionsSearch/divideByGCD.test.js deleted file mode 100644 index 73a4d090..00000000 --- a/test/simplifyExpression/fractionsSearch/divideByGCD.test.js +++ /dev/null @@ -1,19 +0,0 @@ -const divideByGCD = require('../../../lib/simplifyExpression/fractionsSearch/divideByGCD'); - -const TestUtil = require('../../TestUtil'); - -function testdivideByGCD(exprStr, outputStr) { - TestUtil.testSimplification(divideByGCD, exprStr, outputStr); -} - -describe('simplifyFraction', function() { - const tests = [ - ['2/4', '1/2'], - ['9/3', '3'], - ['12/27', '4/9'], - ['1/-3', '-1/3'], - ['-3/-2', '3/2'], - ['-1/-1', '1'], - ]; - tests.forEach(t => testdivideByGCD(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts b/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts new file mode 100644 index 00000000..7e898268 --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts @@ -0,0 +1,19 @@ +import divideByGCD = require('../../../lib/simplifyExpression/fractionsSearch/divideByGCD'); +import TestUtil = require('../../TestUtil'); + +function testdivideByGCD(exprStr: any, outputStr: any); +function testdivideByGCD(exprStr, outputStr) { + TestUtil.testSimplification(divideByGCD, exprStr, outputStr); +} + +describe('simplifyFraction', () => { + const tests = [ + ['2/4', '1/2'], + ['9/3', '3'], + ['12/27', '4/9'], + ['1/-3', '-1/3'], + ['-3/-2', '3/2'], + ['-1/-1', '1'], + ]; + tests.forEach(t => testdivideByGCD(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js deleted file mode 100644 index c4aa000a..00000000 --- a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const simplifyFractionSigns = require('../../../lib/simplifyExpression/fractionsSearch/simplifyFractionSigns'); - -const TestUtil = require('../../TestUtil'); - -function testSimplifyFractionSigns(exprStr, outputStr) { - TestUtil.testSimplification(simplifyFractionSigns, exprStr, outputStr); -} - -describe('simplify signs', function() { - const tests = [ - ['-12x / -27', '12x / 27'], - ['x / -y', '-x / y'], - ]; - tests.forEach(t => testSimplifyFractionSigns(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts new file mode 100644 index 00000000..a956e01a --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts @@ -0,0 +1,15 @@ +import simplifyFractionSigns = require('../../../lib/simplifyExpression/fractionsSearch/simplifyFractionSigns'); +import TestUtil = require('../../TestUtil'); + +function testSimplifyFractionSigns(exprStr: any, outputStr: any); +function testSimplifyFractionSigns(exprStr, outputStr) { + TestUtil.testSimplification(simplifyFractionSigns, exprStr, outputStr); +} + +describe('simplify signs', () => { + const tests = [ + ['-12x / -27', '12x / 27'], + ['x / -y', '-x / y'], + ]; + tests.forEach(t => testSimplifyFractionSigns(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js deleted file mode 100644 index 1d16748d..00000000 --- a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js +++ /dev/null @@ -1,20 +0,0 @@ -const simplifyPolynomialFraction = require('../../../lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction'); - -const TestUtil = require('../../TestUtil'); - -function testSimplifyPolynomialFraction(exprStr, outputStr) { - TestUtil.testSimplification(simplifyPolynomialFraction, exprStr, outputStr); -} - -describe('simplifyPolynomialFraction', function() { - const tests = [ - ['2x/4', '1/2 x'], - ['9y/3', '3y'], - ['y/-3', '-1/3 y'], - ['-3y/-2', '3/2 y'], - ['-y/-1', 'y'], - ['12z^2/27', '4/9 z^2'], - ['1.6x / 1.6', 'x'], - ]; - tests.forEach(t => testSimplifyPolynomialFraction(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts new file mode 100644 index 00000000..26958821 --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts @@ -0,0 +1,20 @@ +import simplifyPolynomialFraction = require('../../../lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction'); +import TestUtil = require('../../TestUtil'); + +function testSimplifyPolynomialFraction(exprStr: any, outputStr: any); +function testSimplifyPolynomialFraction(exprStr, outputStr) { + TestUtil.testSimplification(simplifyPolynomialFraction, exprStr, outputStr); +} + +describe('simplifyPolynomialFraction', () => { + const tests = [ + ['2x/4', '1/2 x'], + ['9y/3', '3y'], + ['y/-3', '-1/3 y'], + ['-3y/-2', '3/2 y'], + ['-y/-1', 'y'], + ['12z^2/27', '4/9 z^2'], + ['1.6x / 1.6', 'x'], + ]; + tests.forEach(t => testSimplifyPolynomialFraction(t[0], t[1])); +}); diff --git a/test/simplifyExpression/functionsSearch/absoluteValue.test.js b/test/simplifyExpression/functionsSearch/absoluteValue.test.js deleted file mode 100644 index 923c6561..00000000 --- a/test/simplifyExpression/functionsSearch/absoluteValue.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const absoluteValue = require('../../../lib/simplifyExpression/functionsSearch/absoluteValue'); - -const TestUtil = require('../../TestUtil'); - -function testAbsoluteValue(exprString, outputStr) { - TestUtil.testSimplification(absoluteValue, exprString, outputStr); -} - -describe('abs', function () { - const tests = [ - ['abs(4)', '4'], - ['abs(-5)', '5'], - ]; - tests.forEach(t => testAbsoluteValue(t[0], t[1])); -}); diff --git a/test/simplifyExpression/functionsSearch/absoluteValue.test.ts b/test/simplifyExpression/functionsSearch/absoluteValue.test.ts new file mode 100644 index 00000000..de6ebe97 --- /dev/null +++ b/test/simplifyExpression/functionsSearch/absoluteValue.test.ts @@ -0,0 +1,15 @@ +import absoluteValue = require('../../../lib/simplifyExpression/functionsSearch/absoluteValue'); +import TestUtil = require('../../TestUtil'); + +function testAbsoluteValue(exprString: any, outputStr: any); +function testAbsoluteValue(exprString, outputStr) { + TestUtil.testSimplification(absoluteValue, exprString, outputStr); +} + +describe('abs', () => { + const tests = [ + ['abs(4)', '4'], + ['abs(-5)', '5'], + ]; + tests.forEach(t => testAbsoluteValue(t[0], t[1])); +}); diff --git a/test/simplifyExpression/functionsSearch/nthRoot.test.js b/test/simplifyExpression/functionsSearch/nthRoot.test.js deleted file mode 100644 index 21352c5b..00000000 --- a/test/simplifyExpression/functionsSearch/nthRoot.test.js +++ /dev/null @@ -1,72 +0,0 @@ -const nthRoot = require('../../../lib/simplifyExpression/functionsSearch/nthRoot'); - -const TestUtil = require('../../TestUtil'); - -function testNthRoot(exprString, outputStr) { - TestUtil.testSimplification(nthRoot, exprString, outputStr); -} - -describe('simplify nthRoot', function () { - const tests = [ - ['nthRoot(4)', '2'], - ['nthRoot(8, 3)', '2'], - ['nthRoot(5 * 7)', 'nthRoot(5 * 7)'], - ['nthRoot(4, 3)', 'nthRoot(4, 3)'], - ['nthRoot(12)', '2 * nthRoot(3, 2)'], - ['nthRoot(36)', '6'], - ['nthRoot(72)', '2 * 3 * nthRoot(2, 2)'], - ['nthRoot(x^2)', 'x'], - ['nthRoot(x ^ 3)', 'nthRoot(x ^ 3)'], - ['nthRoot(x^3, 3)', 'x'], - ['nthRoot(-2)', 'nthRoot(-2)'], - ['nthRoot(2 ^ x, x)', '2'], - ['nthRoot(x ^ (1/2), 1/2)', 'x'], - ['nthRoot(2 * 2, 2)', '2'], - ['nthRoot(3 * 2 * 3 * 2, 2)', '2 * 3'], - ['nthRoot(36*x)', '2 * 3 * nthRoot(x, 2)'], - ['nthRoot(2 * 18 * x ^ 2, 2)', '2 * 3 * x'], - ['nthRoot(x * x, 2)', 'x'], - ['nthRoot(x * x * (2 + 3), 2)', 'x * nthRoot((2 + 3), 2)'], - ]; - tests.forEach(t => testNthRoot(t[0], t[1])); -}); - -function testNthRootSteps(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(nthRoot, exprString, outputList, lastString); -} - -describe('nthRoot steps', function () { - const tests = [ - ['nthRoot(12)', - ['nthRoot(2 * 2 * 3)', - 'nthRoot((2 * 2) * 3)', - 'nthRoot(2 ^ 2 * 3)', - 'nthRoot(2 ^ 2, 2) * nthRoot(3, 2)', - '2 * nthRoot(3, 2)'] - ], - ['nthRoot(72)', - ['nthRoot(2 * 2 * 2 * 3 * 3)', - 'nthRoot((2 * 2) * 2 * (3 * 3))', - 'nthRoot(2 ^ 2 * 2 * 3 ^ 2)', - 'nthRoot(2 ^ 2, 2) * nthRoot(2, 2) * nthRoot(3 ^ 2, 2)', - '2 * nthRoot(2, 2) * 3', - '2 * 3 * nthRoot(2, 2)'] - ], - ['nthRoot(36*x)', - ['nthRoot(2 * 2 * 3 * 3 * x)', - 'nthRoot((2 * 2) * (3 * 3) * x)', - 'nthRoot(2 ^ 2 * 3 ^ 2 * x)', - 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x, 2)', - '2 * 3 * nthRoot(x, 2)'] - ], - ['nthRoot(2 * 18 * x ^ 2, 2)', - ['nthRoot(2 * 2 * 3 * 3 * x ^ 2, 2)', - 'nthRoot((2 * 2) * (3 * 3) * x ^ 2, 2)', - 'nthRoot(2 ^ 2 * 3 ^ 2 * x ^ 2, 2)', - 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x ^ 2, 2)', - '2 * 3 * x'] - ] - ]; - tests.forEach(t => testNthRootSteps(t[0], t[1])); -}); diff --git a/test/simplifyExpression/functionsSearch/nthRoot.test.ts b/test/simplifyExpression/functionsSearch/nthRoot.test.ts new file mode 100644 index 00000000..0f867258 --- /dev/null +++ b/test/simplifyExpression/functionsSearch/nthRoot.test.ts @@ -0,0 +1,73 @@ +import nthRoot = require('../../../lib/simplifyExpression/functionsSearch/nthRoot'); +import TestUtil = require('../../TestUtil'); + +function testNthRoot(exprString: any, outputStr: any); +function testNthRoot(exprString, outputStr) { + TestUtil.testSimplification(nthRoot, exprString, outputStr); +} + +describe('simplify nthRoot', () => { + const tests = [ + ['nthRoot(4)', '2'], + ['nthRoot(8, 3)', '2'], + ['nthRoot(5 * 7)', 'nthRoot(5 * 7)'], + ['nthRoot(4, 3)', 'nthRoot(4, 3)'], + ['nthRoot(12)', '2 * nthRoot(3, 2)'], + ['nthRoot(36)', '6'], + ['nthRoot(72)', '2 * 3 * nthRoot(2, 2)'], + ['nthRoot(x^2)', 'x'], + ['nthRoot(x ^ 3)', 'nthRoot(x ^ 3)'], + ['nthRoot(x^3, 3)', 'x'], + ['nthRoot(-2)', 'nthRoot(-2)'], + ['nthRoot(2 ^ x, x)', '2'], + ['nthRoot(x ^ (1/2), 1/2)', 'x'], + ['nthRoot(2 * 2, 2)', '2'], + ['nthRoot(3 * 2 * 3 * 2, 2)', '2 * 3'], + ['nthRoot(36*x)', '2 * 3 * nthRoot(x, 2)'], + ['nthRoot(2 * 18 * x ^ 2, 2)', '2 * 3 * x'], + ['nthRoot(x * x, 2)', 'x'], + ['nthRoot(x * x * (2 + 3), 2)', 'x * nthRoot((2 + 3), 2)'], + ]; + tests.forEach(t => testNthRoot(t[0], t[1])); +}); + +function testNthRootSteps(exprString: any, outputList: any); +function testNthRootSteps(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(nthRoot, exprString, outputList, lastString); +} + +describe('nthRoot steps', () => { + const tests = [ + ['nthRoot(12)', + ['nthRoot(2 * 2 * 3)', + 'nthRoot((2 * 2) * 3)', + 'nthRoot(2 ^ 2 * 3)', + 'nthRoot(2 ^ 2, 2) * nthRoot(3, 2)', + '2 * nthRoot(3, 2)'] + ], + ['nthRoot(72)', + ['nthRoot(2 * 2 * 2 * 3 * 3)', + 'nthRoot((2 * 2) * 2 * (3 * 3))', + 'nthRoot(2 ^ 2 * 2 * 3 ^ 2)', + 'nthRoot(2 ^ 2, 2) * nthRoot(2, 2) * nthRoot(3 ^ 2, 2)', + '2 * nthRoot(2, 2) * 3', + '2 * 3 * nthRoot(2, 2)'] + ], + ['nthRoot(36*x)', + ['nthRoot(2 * 2 * 3 * 3 * x)', + 'nthRoot((2 * 2) * (3 * 3) * x)', + 'nthRoot(2 ^ 2 * 3 ^ 2 * x)', + 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x, 2)', + '2 * 3 * nthRoot(x, 2)'] + ], + ['nthRoot(2 * 18 * x ^ 2, 2)', + ['nthRoot(2 * 2 * 3 * 3 * x ^ 2, 2)', + 'nthRoot((2 * 2) * (3 * 3) * x ^ 2, 2)', + 'nthRoot(2 ^ 2 * 3 ^ 2 * x ^ 2, 2)', + 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x ^ 2, 2)', + '2 * 3 * x'] + ] + ]; + tests.forEach(t => testNthRootSteps(t[0], t[1])); +}); diff --git a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js deleted file mode 100644 index 0e319d8b..00000000 --- a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js +++ /dev/null @@ -1,16 +0,0 @@ -const multiplyFractionsSearch = require('../../../lib/simplifyExpression//multiplyFractionsSearch'); - -const TestUtil = require('../../TestUtil'); - -function testMultiplyFractionsSearch(exprString, outputStr) { - TestUtil.testSimplification(multiplyFractionsSearch, exprString, outputStr); -} - -describe('multiplyFractions', function () { - const tests = [ - ['3 * 1/5 * 5/9', '(3 * 1 * 5) / (5 * 9)'], - ['3/7 * 10/11', '(3 * 10) / (7 * 11)'], - ['2 * 5/x', '(2 * 5) / x'] - ]; - tests.forEach(t => testMultiplyFractionsSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts new file mode 100644 index 00000000..5dae28d4 --- /dev/null +++ b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts @@ -0,0 +1,16 @@ +import multiplyFractionsSearch = require('../../../lib/simplifyExpression//multiplyFractionsSearch'); +import TestUtil = require('../../TestUtil'); + +function testMultiplyFractionsSearch(exprString: any, outputStr: any); +function testMultiplyFractionsSearch(exprString, outputStr) { + TestUtil.testSimplification(multiplyFractionsSearch, exprString, outputStr); +} + +describe('multiplyFractions', () => { + const tests = [ + ['3 * 1/5 * 5/9', '(3 * 1 * 5) / (5 * 9)'], + ['3/7 * 10/11', '(3 * 10) / (7 * 11)'], + ['2 * 5/x', '(2 * 5) / x'] + ]; + tests.forEach(t => testMultiplyFractionsSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/oneStep.test.js b/test/simplifyExpression/oneStep.test.js deleted file mode 100644 index ead906be..00000000 --- a/test/simplifyExpression/oneStep.test.js +++ /dev/null @@ -1,96 +0,0 @@ -const assert = require('assert'); - -const print = require('../../lib/util/print'); - -const ChangeTypes = require('../../lib/ChangeTypes'); -const simplifyExpression = require('../../lib/simplifyExpression'); - -function testOneStep(exprStr, outputStr, debug=false) { - const steps = simplifyExpression(exprStr); - if (!steps.length) { - return exprStr; - } - const nodeStatus = steps[0]; - if (debug) { - if (!nodeStatus.changeType) { - throw Error('missing or bad change type'); - } - // eslint-disable-next-line - console.log(nodeStatus.changeType); - // eslint-disable-next-line - console.log(print(nodeStatus.newNode)); - } - it(exprStr + ' -> ' + outputStr, function () { - assert.deepEqual( - print(nodeStatus.newNode), - outputStr); - }); -} - -describe('arithmetic stepping', function() { - const tests = [ - ['(2+2)', '4'], - ['(2+2)*5', '4 * 5'], - ['5*(2+2)', '5 * 4'], - ['2*(2+2) + 2^3', '2 * 4 + 2^3'], - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe('adding symbols without breaking things', function() { - // nothing old breaks - const tests = [ - ['2+x', '2 + x'], - ['(2+2)*x', '4x'], - ['(2+2)*x+3', '4x + 3'], - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe('collecting like terms within the context of the stepper', function() { - const tests = [ - ['2+x+7', 'x + 9'], // substeps not tested here -// ['2x^2 * y * x * y^3', '2 * x^3 * y^4'], // substeps not tested here - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe('collects and combines like terms', function() { - const tests = [ - ['(x + x) + (x^2 + x^2)', '2x + (x^2 + x^2)'], // substeps not tested here - ['10 + (y^2 + y^2)', '10 + 2y^2'], // substeps not tested here - ['10y^2 + 1/2 y^2 + 3/2 y^2', '12y^2'], // substeps not tested here - ['x + y + y^2', 'x + y + y^2'], - ['2x^(2+1)', '2x^3'], - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe('stepThrough returning no steps', function() { - it('12x^2 already simplified', function () { - assert.deepEqual( - simplifyExpression('12x^2'), - []); - }); - it('2*5x^2 + sqrt(5) has unsupported sqrt', function () { - assert.deepEqual( - simplifyExpression('2*5x^2 + sqrt(5)'), - []); - }); -}); - -describe('keeping parens in important places, on printing', function() { - testOneStep('5 + (3*6) + 2 / (x / y)', '5 + (3 * 6) + 2 * y / x'); - testOneStep('-(x + y) + 5+3', '8 - (x + y)'); -}); - -describe('fractions', function() { - testOneStep('2 + 5/2 + 3', '5 + 5/2'); // collect and combine without substeps -}); - -describe('simplifyDoubleUnaryMinus step actually happens', function () { - it('22 - (-7) -> 22 + 7', function() { - const steps = simplifyExpression('22 - (-7)'); - assert.equal(steps[0].changeType, ChangeTypes.RESOLVE_DOUBLE_MINUS); - }); -}); diff --git a/test/simplifyExpression/oneStep.test.ts b/test/simplifyExpression/oneStep.test.ts new file mode 100644 index 00000000..73b882bd --- /dev/null +++ b/test/simplifyExpression/oneStep.test.ts @@ -0,0 +1,94 @@ +const assert = require('assert'); +import print = require('../../lib/util/print'); +import ChangeTypes = require('../../lib/ChangeTypes'); +import simplifyExpression = require('../../lib/simplifyExpression'); + +function testOneStep(exprStr, outputStr, debug=false) { + const steps = simplifyExpression(exprStr); + if (!steps.length) { + return exprStr; + } + const nodeStatus = steps[0]; + if (debug) { + if (!nodeStatus.changeType) { + throw Error('missing or bad change type'); + } + // eslint-disable-next-line + console.log(nodeStatus.changeType); + // eslint-disable-next-line + console.log(print(nodeStatus.newNode)); + } + it(exprStr + ' -> ' + outputStr, () => { + assert.deepEqual( + print(nodeStatus.newNode), + outputStr); + }); +} + +describe('arithmetic stepping', () => { + const tests = [ + ['(2+2)', '4'], + ['(2+2)*5', '4 * 5'], + ['5*(2+2)', '5 * 4'], + ['2*(2+2) + 2^3', '2 * 4 + 2^3'], + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('adding symbols without breaking things', () => { + // nothing old breaks + const tests = [ + ['2+x', '2 + x'], + ['(2+2)*x', '4x'], + ['(2+2)*x+3', '4x + 3'], + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('collecting like terms within the context of the stepper', () => { + const tests = [ + ['2+x+7', 'x + 9'], // substeps not tested here +// ['2x^2 * y * x * y^3', '2 * x^3 * y^4'], // substeps not tested here + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('collects and combines like terms', () => { + const tests = [ + ['(x + x) + (x^2 + x^2)', '2x + (x^2 + x^2)'], // substeps not tested here + ['10 + (y^2 + y^2)', '10 + 2y^2'], // substeps not tested here + ['10y^2 + 1/2 y^2 + 3/2 y^2', '12y^2'], // substeps not tested here + ['x + y + y^2', 'x + y + y^2'], + ['2x^(2+1)', '2x^3'], + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('stepThrough returning no steps', () => { + it('12x^2 already simplified', () => { + assert.deepEqual( + simplifyExpression('12x^2'), + []); + }); + it('2*5x^2 + sqrt(5) has unsupported sqrt', () => { + assert.deepEqual( + simplifyExpression('2*5x^2 + sqrt(5)'), + []); + }); +}); + +describe('keeping parens in important places, on printing', () => { + testOneStep('5 + (3*6) + 2 / (x / y)', '5 + (3 * 6) + 2 * y / x'); + testOneStep('-(x + y) + 5+3', '8 - (x + y)'); +}); + +describe('fractions', () => { + testOneStep('2 + 5/2 + 3', '5 + 5/2'); // collect and combine without substeps +}); + +describe('simplifyDoubleUnaryMinus step actually happens', () => { + it('22 - (-7) -> 22 + 7', () => { + const steps = simplifyExpression('22 - (-7)'); + assert.equal(steps[0].changeType, ChangeTypes.RESOLVE_DOUBLE_MINUS); + }); +}); diff --git a/test/simplifyExpression/simplify.test.js b/test/simplifyExpression/simplify.test.js deleted file mode 100644 index 1cefba3b..00000000 --- a/test/simplifyExpression/simplify.test.js +++ /dev/null @@ -1,168 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const print = require('../../lib/util/print'); - -const simplify = require('../../lib/simplifyExpression/simplify'); - -function testSimplify(exprStr, outputStr, debug=false) { - it(exprStr + ' -> ' + outputStr, function () { - assert.deepEqual( - print(simplify(math.parse(exprStr), debug)), - outputStr); - }); -} - -describe('simplify (arithmetic)', function () { - const tests = [ - ['(2+2)*5', '20'], - ['(8+(-4))*5', '20'], - ['5*(2+2)*10', '200'], - ['(2+(2)+7)', '11'], - ['(8-2) * 2^2 * (1+1) / (4 /2) / 5', '24/5'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('collects and combines like terms', function() { - const tests = [ - ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], - ['2x^2 * y * x * y^3', '2x^3 * y^4'], - ['4y*3*5', '60y'], - ['(2x^2 - 4) + (4x^2 + 3)', '6x^2 - 1'], - ['(2x^1 + 4) + (4x^2 + 3)', '4x^2 + 2x + 7'], - ['y * 2x * 10', '20x * y'], - ['x^y * x^z', 'x^(y + z)'], - ['x^(3+y) + x^(3+y)+ 4', '2x^(3 + y) + 4'], - ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - - -describe('can simplify with division', function () { - const tests = [ - ['2 * 4 / 5 * 10 + 3', '19'], - ['2x * 5x / 2', '5x^2'], - ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], - ['2x * 4x / 2 / 4', 'x^2'], - ['2x * y / z * 10', '20x * y / z'], - ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], - ['2x/x', '2'], - ['2x/4/3', '1/6 x'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); - // TODO: factor the numerator to cancel out with denominator - // e.g. (x^2 - 3 + 2)/(x-2) -> (x-1) -}); - -describe('subtraction support', function() { - const tests = [ - ['-(-(2+3))', '5'], - ['-(-5)', '5'], - ['-(-(2+x))', '2 + x'], - ['-------5', '-5'], - ['--(-----5) + 6', '1'], - ['x^2 + 3 - x*x', '3'], - ['-(2*x) * -(2 + 2)', '8x'], - ['(x-4)-5', 'x - 9'], - ['5-x-4', '-x + 1'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('support for more * and ( that come from latex conversion', function () { - const tests = [ - ['(3*x)*(4*x)', '12x^2'], - ['(12*z^(2))/27', '4/9 z^2'], - ['x^2 - 12x^2 + 5x^2 - 7', '-6x^2 - 7'], - ['-(12 x ^ 2)', '-12x^2'] - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('distribution', function () { - const tests = [ - ['(3*x)*(4*x)', '12x^2'], - ['(3+x)*(4+x)*(x+5)', 'x^3 + 12x^2 + 47x + 60'], - ['-2x^2 * (3x - 4)', '-6x^3 + 8x^2'], - ['x^2 - x^2*(12 + 5x) - 7', '-5x^3 - 11x^2 - 7'], - ['(5+x)*(x+3)', 'x^2 + 8x + 15'], - ['(x-2)(x-4)', 'x^2 - 6x + 8'], - ['- x*y^4 (6x * y^2 + 5x*y - 3x)', - '-6x^2 * y^6 - 5x^2 * y^5 + 3x^2 * y^4'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('fractions', function() { - const tests = [ - ['5x + (1/2)x', '11/2 x'], - ['x + x/2', '3/2 x'], - ['1 + 1/2', '3/2'], - ['2 + 5/2 + 3', '15/2'], - ['9/18-5/18', '2/9'], - ['2(x+3)/3', '2x / 3 + 2'], - ['5/18 - 9/18', '-2/9'], - ['9/18', '1/2'], - ['x/(2/3) + 5', '3/2 x + 5'], - ['(2+x)/6', '1/3 + x / 6'] - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('floating point', function() { - testSimplify('1.983*10', '19.83'); -}); - -describe('cancelling out', function() { - const tests = [ - ['(x^3*y)/x^2 + 5', 'x * y + 5'], - ['(x^(2)+y^(2))/(5x-6x) + 5', '-x - y^2 / x + 5'], - ['( p ^ ( 2) + 1)/( p ^ ( 2) + 1)', '1'], - ['(-x)/(x)', '-1'], - ['(x)/(-x)', '-1'], - ['((2x^3 y^2)/(-x^2 y^5))^(-2)', '(-2x * y^-3)^-2'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('absolute value support', function() { - const tests = [ - ['(x^3*y)/x^2 + abs(-5)', 'x * y + 5'], - ['-6 + -5 - abs(-4) + -10 - 3 abs(-4)', '-37'], - ['5*abs((2+2))*10', '200'], - ['5x + (1/abs(-2))x', '11/2 x'], - ['abs(5/18-abs(9/-18))', '2/9'], - // handle parens around abs() - ['( abs( -3) )/(3)', '1'], - ['- abs( -40)', '-40'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('nthRoot support', function() { - const tests = [ - ['nthRoot(4x, 2)', '2 * nthRoot(x, 2)'], - ['2 * nthRoot(4x, 2)', '4 * nthRoot(x, 2)'], - ['(x^3*y)/x^2 + nthRoot(4x, 2)', 'x * y + 2 * nthRoot(x, 2)'], - ['2 + nthRoot(4)', '4'], - ['x * nthRoot(x^4, 2)', 'x^3'], - ['x * nthRoot(2 + 2, 3)', 'x * nthRoot(4, 3)'], - ['x * nthRoot((2 + 2) * 2, 3)', '2x'], - ['nthRoot(x * (2 + 3) * x, 2)', 'x * nthRoot(5, 2)'] - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('handles unnecessary parens at root level', function() { - const tests = [ - ['(x+(y))', 'x + y'], - ['((x+y) + ((z^3)))', 'x + y + z^3'], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe('keeping parens in important places, on printing', function() { - testSimplify('2 / (2x^2) + 5', '2 / (2x^2) + 5'); -}); diff --git a/test/simplifyExpression/simplify.test.ts b/test/simplifyExpression/simplify.test.ts new file mode 100644 index 00000000..57275cfb --- /dev/null +++ b/test/simplifyExpression/simplify.test.ts @@ -0,0 +1,166 @@ +const assert = require('assert'); +import math = require('mathjs'); +import print = require('../../lib/util/print'); +import simplify = require('../../lib/simplifyExpression/simplify'); + +function testSimplify(exprStr, outputStr, debug=false) { + it(exprStr + ' -> ' + outputStr, () => { + assert.deepEqual( + print(simplify(math.parse(exprStr), debug)), + outputStr); + }); +} + +describe('simplify (arithmetic)', () => { + const tests = [ + ['(2+2)*5', '20'], + ['(8+(-4))*5', '20'], + ['5*(2+2)*10', '200'], + ['(2+(2)+7)', '11'], + ['(8-2) * 2^2 * (1+1) / (4 /2) / 5', '24/5'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('collects and combines like terms', () => { + const tests = [ + ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], + ['2x^2 * y * x * y^3', '2x^3 * y^4'], + ['4y*3*5', '60y'], + ['(2x^2 - 4) + (4x^2 + 3)', '6x^2 - 1'], + ['(2x^1 + 4) + (4x^2 + 3)', '4x^2 + 2x + 7'], + ['y * 2x * 10', '20x * y'], + ['x^y * x^z', 'x^(y + z)'], + ['x^(3+y) + x^(3+y)+ 4', '2x^(3 + y) + 4'], + ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + + +describe('can simplify with division', () => { + const tests = [ + ['2 * 4 / 5 * 10 + 3', '19'], + ['2x * 5x / 2', '5x^2'], + ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], + ['2x * 4x / 2 / 4', 'x^2'], + ['2x * y / z * 10', '20x * y / z'], + ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], + ['2x/x', '2'], + ['2x/4/3', '1/6 x'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); + // TODO: factor the numerator to cancel out with denominator + // e.g. (x^2 - 3 + 2)/(x-2) -> (x-1) +}); + +describe('subtraction support', () => { + const tests = [ + ['-(-(2+3))', '5'], + ['-(-5)', '5'], + ['-(-(2+x))', '2 + x'], + ['-------5', '-5'], + ['--(-----5) + 6', '1'], + ['x^2 + 3 - x*x', '3'], + ['-(2*x) * -(2 + 2)', '8x'], + ['(x-4)-5', 'x - 9'], + ['5-x-4', '-x + 1'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('support for more * and ( that come from latex conversion', () => { + const tests = [ + ['(3*x)*(4*x)', '12x^2'], + ['(12*z^(2))/27', '4/9 z^2'], + ['x^2 - 12x^2 + 5x^2 - 7', '-6x^2 - 7'], + ['-(12 x ^ 2)', '-12x^2'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('distribution', () => { + const tests = [ + ['(3*x)*(4*x)', '12x^2'], + ['(3+x)*(4+x)*(x+5)', 'x^3 + 12x^2 + 47x + 60'], + ['-2x^2 * (3x - 4)', '-6x^3 + 8x^2'], + ['x^2 - x^2*(12 + 5x) - 7', '-5x^3 - 11x^2 - 7'], + ['(5+x)*(x+3)', 'x^2 + 8x + 15'], + ['(x-2)(x-4)', 'x^2 - 6x + 8'], + ['- x*y^4 (6x * y^2 + 5x*y - 3x)', + '-6x^2 * y^6 - 5x^2 * y^5 + 3x^2 * y^4'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('fractions', () => { + const tests = [ + ['5x + (1/2)x', '11/2 x'], + ['x + x/2', '3/2 x'], + ['1 + 1/2', '3/2'], + ['2 + 5/2 + 3', '15/2'], + ['9/18-5/18', '2/9'], + ['2(x+3)/3', '2x / 3 + 2'], + ['5/18 - 9/18', '-2/9'], + ['9/18', '1/2'], + ['x/(2/3) + 5', '3/2 x + 5'], + ['(2+x)/6', '1/3 + x / 6'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('floating point', () => { + testSimplify('1.983*10', '19.83'); +}); + +describe('cancelling out', () => { + const tests = [ + ['(x^3*y)/x^2 + 5', 'x * y + 5'], + ['(x^(2)+y^(2))/(5x-6x) + 5', '-x - y^2 / x + 5'], + ['( p ^ ( 2) + 1)/( p ^ ( 2) + 1)', '1'], + ['(-x)/(x)', '-1'], + ['(x)/(-x)', '-1'], + ['((2x^3 y^2)/(-x^2 y^5))^(-2)', '(-2x * y^-3)^-2'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('absolute value support', () => { + const tests = [ + ['(x^3*y)/x^2 + abs(-5)', 'x * y + 5'], + ['-6 + -5 - abs(-4) + -10 - 3 abs(-4)', '-37'], + ['5*abs((2+2))*10', '200'], + ['5x + (1/abs(-2))x', '11/2 x'], + ['abs(5/18-abs(9/-18))', '2/9'], + // handle parens around abs() + ['( abs( -3) )/(3)', '1'], + ['- abs( -40)', '-40'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('nthRoot support', () => { + const tests = [ + ['nthRoot(4x, 2)', '2 * nthRoot(x, 2)'], + ['2 * nthRoot(4x, 2)', '4 * nthRoot(x, 2)'], + ['(x^3*y)/x^2 + nthRoot(4x, 2)', 'x * y + 2 * nthRoot(x, 2)'], + ['2 + nthRoot(4)', '4'], + ['x * nthRoot(x^4, 2)', 'x^3'], + ['x * nthRoot(2 + 2, 3)', 'x * nthRoot(4, 3)'], + ['x * nthRoot((2 + 2) * 2, 3)', '2x'], + ['nthRoot(x * (2 + 3) * x, 2)', 'x * nthRoot(5, 2)'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('handles unnecessary parens at root level', () => { + const tests = [ + ['(x+(y))', 'x + y'], + ['((x+y) + ((z^3)))', 'x + y + z^3'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('keeping parens in important places, on printing', () => { + testSimplify('2 / (2x^2) + 5', '2 / (2x^2) + 5'); +}); diff --git a/test/solveEquation/solveEquation.test.js b/test/solveEquation/solveEquation.test.js deleted file mode 100644 index c127674c..00000000 --- a/test/solveEquation/solveEquation.test.js +++ /dev/null @@ -1,130 +0,0 @@ -const assert = require('assert'); - -const ChangeTypes = require('../../lib/ChangeTypes'); -const solveEquation = require('../../lib/solveEquation'); - -const NO_STEPS = 'no-steps'; - -function testSolve(equationString, outputStr, debug=false) { - const steps = solveEquation(equationString, debug); - let lastStep; - if (steps.length === 0) { - lastStep = NO_STEPS; - } - else { - lastStep = steps[steps.length -1].newEquation.print(); - } - it(equationString + ' -> ' + outputStr, (done) => { - assert.equal(lastStep, outputStr); - done(); - }); -} - -describe('solveEquation for =', function () { - const tests = [ - // can't solve this because two symbols: g and x -- so there's no steps - ['g *( x ) = ( x - 4) ^ ( 2) - 3', NO_STEPS], - // can't solve this because we don't deal with the complicated fraction yet - ['( x )/( 2x + 7) >= 4', NO_STEPS], - ['y - x - 2 = 3*2', 'y = 8 + x'], - ['2y - x - 2 = x', 'y = x + 1'], - ['x = 1', NO_STEPS], - ['2 = x', 'x = 2'], - ['2 + -3 = x', 'x = -1'], - ['x + 3 = 4', 'x = 1'], - ['2x - 3 = 0', 'x = 3/2'], - ['x/3 - 2 = -1', 'x = 3'], - ['5x/2 + 2 = 3x/2 + 10', 'x = 8'], - ['2x - 1 = -x', 'x = 1/3'], - ['2 - x = -4 + x', 'x = 3'], - ['2x/3 = 2', 'x = 3'], - ['2x - 3 = x', 'x = 3'], - ['8 - 2a = a + 3 - 1', 'a = 2'], - ['2 - x = 4', 'x = -2'], - ['2 - 4x = x', 'x = 2/5'], - ['9x + 4 - 3 = 2x', 'x = -1/7'], - ['9x + 4 - 3 = -2x', 'x = -1/11'], - ['(2x^2 - 1)(x^2 - 5)(x^2 + 5) = 0', '2x^6 - x^4 - 50x^2 = -25'], - ['(-x ^ 2 - 4x + 2)(-3x^2 - 6x + 3) = 0', '3x^4 + 18x^3 + 15x^2 - 24x = -6'], - ['5x + (1/2)x = 27 ', 'x = 54/11'], - ['2x/3 = 2x - 4 ', 'x = 3'], - ['(-2/3)x + 3/7 = 1/2', 'x = -3/28'], - ['-9/4v + 4/5 = 7/8 ', 'v = -1/30'], - // TODO: update test once we have root support - ['x^2 - 2 = 0', 'x^2 = 2'], - ['x/(2/3) = 1', 'x = 2/3'], - ['(x+1)/3 = 4', 'x = 11'], - ['2(x+3)/3 = 2', 'x = 0'], - ['( u )/( 0.3) = 4u + 6.28', 'u = -9.42'], - ['- q - 4.36= ( 2.2q )/( 1.8)', 'q = -1.962'], - // TODO: figure out what to do about errors from rounding midway through - // this gives us 6.3995 when it should actually be 6.4 :( - // ['x - 3.4= ( x - 2.5)/( 1.3)', 'x = 6.4'] - ]; - tests.forEach(t => testSolve(t[0], t[1], t[2])); -}); - -describe('solveEquation for non = comparators', function() { - const tests = [ - ['x + 2 > 3', 'x > 1'], - ['2x < 6', 'x < 3'], - ['-x > 1', 'x < -1'], - ['2 - x < 3', 'x > -1'], - ['9.5j / 6+ 5.5j >= 3( 5j - 2)', 'j <= 0.7579'] - ]; - tests.forEach(t => testSolve(t[0], t[1], t[2])); -}); - -function testSolveConstantEquation(equationString, expectedChange, debug=false) { - const steps = solveEquation(equationString, debug); - const actualChange = steps[steps.length -1].changeType; - it(equationString + ' -> ' + expectedChange, (done) => { - assert.equal(actualChange, expectedChange); - done(); - }); -} - -describe('constant comparison support', function () { - const tests = [ - ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], - ['3 + 5 = 8', ChangeTypes.STATEMENT_IS_TRUE], - ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], - ['2 - 3 = 5', ChangeTypes.STATEMENT_IS_FALSE], - ['2 > 1', ChangeTypes.STATEMENT_IS_TRUE], - ['2/3 > 1/3', ChangeTypes.STATEMENT_IS_TRUE], - ['1 > 2', ChangeTypes.STATEMENT_IS_FALSE], - ['1/3 > 2/3', ChangeTypes.STATEMENT_IS_FALSE], - ['1 >= 1', ChangeTypes.STATEMENT_IS_TRUE], - ['2 >= 1', ChangeTypes.STATEMENT_IS_TRUE], - ['1 >= 2', ChangeTypes.STATEMENT_IS_FALSE], - ['2 < 1', ChangeTypes.STATEMENT_IS_FALSE], - ['2/3 < 1/3', ChangeTypes.STATEMENT_IS_FALSE], - ['1 < 2', ChangeTypes.STATEMENT_IS_TRUE], - ['1/3 < 2/3', ChangeTypes.STATEMENT_IS_TRUE], - ['1 <= 1', ChangeTypes.STATEMENT_IS_TRUE], - ['2 <= 1', ChangeTypes.STATEMENT_IS_FALSE], - ['1 <= 2', ChangeTypes.STATEMENT_IS_TRUE], - ['( 1) = ( 14)', ChangeTypes.STATEMENT_IS_FALSE], - // TODO: when we support fancy exponent and sqrt things - // ['(1/64)^(-5/6) = 32', ChangeTypes.STATEMENT_IS_TRUE], - // With variables that cancel - ['( r )/( ( r ) ) = ( 1)/( 10)', ChangeTypes.STATEMENT_IS_FALSE], - ['5 + (x - 5) = x', ChangeTypes.STATEMENT_IS_TRUE], - ['4x - 4= 4x', ChangeTypes.STATEMENT_IS_FALSE], - ]; - tests.forEach(t => testSolveConstantEquation(t[0], t[1], t[2])); -}); - -function testEquationError(equationString, debug=false) { - it(equationString + ' throws error', (done) => { - assert.throws(() => solveEquation(equationString, debug),Error); - done(); - }); -} - -describe('solveEquation errors', function() { - const tests = [ - ['( x + 2) ^ ( 2) - x ^ ( 2) = 4( x + 1)'] - ]; - tests.forEach(t => testEquationError(t[0], t[1])); -}); diff --git a/test/solveEquation/solveEquation.test.ts b/test/solveEquation/solveEquation.test.ts new file mode 100644 index 00000000..86bffb85 --- /dev/null +++ b/test/solveEquation/solveEquation.test.ts @@ -0,0 +1,128 @@ +const assert = require('assert'); +import ChangeTypes = require('../../lib/ChangeTypes'); +import solveEquation = require('../../lib/solveEquation'); +const NO_STEPS = 'no-steps'; + +function testSolve(equationString, outputStr, debug=false) { + const steps = solveEquation(equationString, debug); + let lastStep; + if (steps.length === 0) { + lastStep = NO_STEPS; + } + else { + lastStep = steps[steps.length -1].newEquation.print(); + } + it(equationString + ' -> ' + outputStr, (done) => { + assert.equal(lastStep, outputStr); + done(); + }); +} + +describe('solveEquation for =', () => { + const tests = [ + // can't solve this because two symbols: g and x -- so there's no steps + ['g *( x ) = ( x - 4) ^ ( 2) - 3', NO_STEPS], + // can't solve this because we don't deal with the complicated fraction yet + ['( x )/( 2x + 7) >= 4', NO_STEPS], + ['y - x - 2 = 3*2', 'y = 8 + x'], + ['2y - x - 2 = x', 'y = x + 1'], + ['x = 1', NO_STEPS], + ['2 = x', 'x = 2'], + ['2 + -3 = x', 'x = -1'], + ['x + 3 = 4', 'x = 1'], + ['2x - 3 = 0', 'x = 3/2'], + ['x/3 - 2 = -1', 'x = 3'], + ['5x/2 + 2 = 3x/2 + 10', 'x = 8'], + ['2x - 1 = -x', 'x = 1/3'], + ['2 - x = -4 + x', 'x = 3'], + ['2x/3 = 2', 'x = 3'], + ['2x - 3 = x', 'x = 3'], + ['8 - 2a = a + 3 - 1', 'a = 2'], + ['2 - x = 4', 'x = -2'], + ['2 - 4x = x', 'x = 2/5'], + ['9x + 4 - 3 = 2x', 'x = -1/7'], + ['9x + 4 - 3 = -2x', 'x = -1/11'], + ['(2x^2 - 1)(x^2 - 5)(x^2 + 5) = 0', '2x^6 - x^4 - 50x^2 = -25'], + ['(-x ^ 2 - 4x + 2)(-3x^2 - 6x + 3) = 0', '3x^4 + 18x^3 + 15x^2 - 24x = -6'], + ['5x + (1/2)x = 27 ', 'x = 54/11'], + ['2x/3 = 2x - 4 ', 'x = 3'], + ['(-2/3)x + 3/7 = 1/2', 'x = -3/28'], + ['-9/4v + 4/5 = 7/8 ', 'v = -1/30'], + // TODO: update test once we have root support + ['x^2 - 2 = 0', 'x^2 = 2'], + ['x/(2/3) = 1', 'x = 2/3'], + ['(x+1)/3 = 4', 'x = 11'], + ['2(x+3)/3 = 2', 'x = 0'], + ['( u )/( 0.3) = 4u + 6.28', 'u = -9.42'], + ['- q - 4.36= ( 2.2q )/( 1.8)', 'q = -1.962'], + // TODO: figure out what to do about errors from rounding midway through + // this gives us 6.3995 when it should actually be 6.4 :( + // ['x - 3.4= ( x - 2.5)/( 1.3)', 'x = 6.4'] + ]; + tests.forEach(t => testSolve(t[0], t[1], t[2])); +}); + +describe('solveEquation for non = comparators', () => { + const tests = [ + ['x + 2 > 3', 'x > 1'], + ['2x < 6', 'x < 3'], + ['-x > 1', 'x < -1'], + ['2 - x < 3', 'x > -1'], + ['9.5j / 6+ 5.5j >= 3( 5j - 2)', 'j <= 0.7579'] + ]; + tests.forEach(t => testSolve(t[0], t[1], t[2])); +}); + +function testSolveConstantEquation(equationString, expectedChange, debug=false) { + const steps = solveEquation(equationString, debug); + const actualChange = steps[steps.length -1].changeType; + it(equationString + ' -> ' + expectedChange, (done) => { + assert.equal(actualChange, expectedChange); + done(); + }); +} + +describe('constant comparison support', () => { + const tests = [ + ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], + ['3 + 5 = 8', ChangeTypes.STATEMENT_IS_TRUE], + ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], + ['2 - 3 = 5', ChangeTypes.STATEMENT_IS_FALSE], + ['2 > 1', ChangeTypes.STATEMENT_IS_TRUE], + ['2/3 > 1/3', ChangeTypes.STATEMENT_IS_TRUE], + ['1 > 2', ChangeTypes.STATEMENT_IS_FALSE], + ['1/3 > 2/3', ChangeTypes.STATEMENT_IS_FALSE], + ['1 >= 1', ChangeTypes.STATEMENT_IS_TRUE], + ['2 >= 1', ChangeTypes.STATEMENT_IS_TRUE], + ['1 >= 2', ChangeTypes.STATEMENT_IS_FALSE], + ['2 < 1', ChangeTypes.STATEMENT_IS_FALSE], + ['2/3 < 1/3', ChangeTypes.STATEMENT_IS_FALSE], + ['1 < 2', ChangeTypes.STATEMENT_IS_TRUE], + ['1/3 < 2/3', ChangeTypes.STATEMENT_IS_TRUE], + ['1 <= 1', ChangeTypes.STATEMENT_IS_TRUE], + ['2 <= 1', ChangeTypes.STATEMENT_IS_FALSE], + ['1 <= 2', ChangeTypes.STATEMENT_IS_TRUE], + ['( 1) = ( 14)', ChangeTypes.STATEMENT_IS_FALSE], + // TODO: when we support fancy exponent and sqrt things + // ['(1/64)^(-5/6) = 32', ChangeTypes.STATEMENT_IS_TRUE], + // With variables that cancel + ['( r )/( ( r ) ) = ( 1)/( 10)', ChangeTypes.STATEMENT_IS_FALSE], + ['5 + (x - 5) = x', ChangeTypes.STATEMENT_IS_TRUE], + ['4x - 4= 4x', ChangeTypes.STATEMENT_IS_FALSE], + ]; + tests.forEach(t => testSolveConstantEquation(t[0], t[1], t[2])); +}); + +function testEquationError(equationString, debug=false) { + it(equationString + ' throws error', (done) => { + assert.throws(() => solveEquation(equationString, debug),Error); + done(); + }); +} + +describe('solveEquation errors', () => { + const tests = [ + ['( x + 2) ^ ( 2) - x ^ ( 2) = 4( x + 1)'] + ]; + tests.forEach(t => testEquationError(t[0], t[1])); +}); diff --git a/test/util/Util.test.js b/test/util/Util.test.js deleted file mode 100644 index a1706f84..00000000 --- a/test/util/Util.test.js +++ /dev/null @@ -1,22 +0,0 @@ -const assert = require('assert'); - -const Util = require('../../lib/util/Util'); - -describe('appendToArrayInObject', function () { - it('creates empty array', function () { - const object = {}; - Util.appendToArrayInObject(object, 'key', 'value'); - assert.deepEqual( - object, - {'key': ['value']} - ); - }); - it('appends to array if it exists', function () { - const object = {'key': ['old_value']}; - Util.appendToArrayInObject(object, 'key', 'new_value'); - assert.deepEqual( - object, - {'key': ['old_value', 'new_value']} - ); - }); -}); diff --git a/test/util/Util.test.ts b/test/util/Util.test.ts new file mode 100644 index 00000000..0cb1bc67 --- /dev/null +++ b/test/util/Util.test.ts @@ -0,0 +1,20 @@ +const assert = require('assert'); +import Util = require('../../lib/util/Util'); +describe('appendToArrayInObject', () => { + it('creates empty array', () => { + const object = {}; + Util.appendToArrayInObject(object, 'key', 'value'); + assert.deepEqual( + object, + {'key': ['value']} + ); + }); + it('appends to array if it exists', () => { + const object = {'key': ['old_value']}; + Util.appendToArrayInObject(object, 'key', 'new_value'); + assert.deepEqual( + object, + {'key': ['old_value', 'new_value']} + ); + }); +}); diff --git a/test/util/flattenOperands.test.js b/test/util/flattenOperands.test.js deleted file mode 100644 index 41ce2c67..00000000 --- a/test/util/flattenOperands.test.js +++ /dev/null @@ -1,103 +0,0 @@ -const assert = require('assert'); -const math = require('mathjs'); - -const flattenOperands = require('../../lib/util/flattenOperands'); -const print = require('../../lib/util/print'); - -const Node = require('../../lib/node'); - -function testFlatten(exprStr, afterNode, debug=false) { - const flattened = flattenOperands(math.parse(exprStr)); - if (debug) { - // eslint-disable-next-line - console.log(print(flattened)); - } - removeComments(flattened); - removeComments(afterNode); - it(print(flattened), function() { - assert.deepEqual(flattened, afterNode); - }); -} - -// to create nodes, for testing -const opNode = Node.Creator.operator; -const constNode = Node.Creator.constant; -const symbolNode = Node.Creator.symbol; -const parenNode = Node.Creator.parenthesis; - -describe('flattens + and *', function () { - const tests = [ - ['2+2', math.parse('2+2')], - ['2+2+7', opNode('+', [constNode(2), constNode(2), constNode(7)])], - ['9*8*6+3+4', - opNode('+', [ - opNode('*', [constNode(9), constNode(8), constNode(6)]), - constNode(3), - constNode(4)])], - ['5*(2+3+2)*10', - opNode('*', [ - constNode(5), - parenNode(opNode('+', [constNode(2), constNode(3),constNode(2)])), - constNode(10)])], - // keeps the polynomial term - ['9x*8*6+3+4', - opNode('+', [ - opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), - constNode(3), - constNode(4)])], - ['9x*8*6+3y^2+4', - opNode('+', [ - opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), - math.parse('3y^2'), - constNode(4)])], - // doesn't flatten - ['2 x ^ (2 + 1) * y', math.parse('2 x ^ (2 + 1) * y')], - ['2 x ^ (2 + 1 + 2) * y', - opNode('*', [ - opNode('*', [constNode(2), - opNode('^', [symbolNode('x'), parenNode( - opNode('+', [constNode(2), constNode(1), constNode(2)]))]), - ], true), symbolNode('y')]) - ], - ['3x*4x', opNode('*', [math.parse('3x'), math.parse('4x')])] - ]; - tests.forEach(t => testFlatten(t[0], t[1])); -}); - -describe('flattens division', function () { - const tests = [ - // groups x/4 and continues to flatten * - ['2 * x / 4 * 6 ', - opNode('*', [opNode('/', [ - math.parse('2x'), math.parse('4')]), constNode(6)])], - ['2*3/4/5*6', - opNode('*', [constNode(2), math.parse('3/4/5'), constNode(6)])], - // combines coefficient with x - ['x / (4 * x) / 8', - math.parse('x / (4x) / 8')], - ['2 x * 4 x / 8', - opNode('*', [math.parse('2x'), opNode( - '/', [math.parse('4x'), constNode(8)])])], - ]; - tests.forEach(t => testFlatten(t[0], t[1])); -}); - -describe('subtraction', function () { - const tests = [ - ['1 + 2 - 3 - 4 + 5', - opNode('+', [ - constNode(1), constNode(2), constNode(-3), constNode(-4), constNode(5)])], - ['x - 3', opNode('+', [symbolNode('x'), constNode(-3)])], - ['x + 4 - (y+4)', - opNode('+', [symbolNode('x'), constNode(4), math.parse('-(y+4)')])], - ]; - tests.forEach(t => testFlatten(t[0], t[1])); -}); - - -// Remove some property used in mathjs that we don't need and prevents node -// equality checks from passing -function removeComments(node) { - node.filter(node => node.comment !== undefined).forEach( - node => delete node.comment); -} diff --git a/test/util/flattenOperands.test.ts b/test/util/flattenOperands.test.ts new file mode 100644 index 00000000..7ade71fc --- /dev/null +++ b/test/util/flattenOperands.test.ts @@ -0,0 +1,102 @@ +const assert = require('assert'); +import math = require('mathjs'); +import flattenOperands = require('../../lib/util/flattenOperands'); +import print = require('../../lib/util/print'); +const mathNode = require('../../lib/node'); + +function testFlatten(exprStr, afterNode, debug=false) { + const flattened = flattenOperands(math.parse(exprStr)); + if (debug) { + // eslint-disable-next-line + console.log(print(flattened)); + } + removeComments(flattened); + removeComments(afterNode); + it(print(flattened), () => { + assert.deepEqual(flattened, afterNode); + }); +} + +// to create nodes, for testing +const opNode = mathNode.Creator.operator; +const constNode = mathNode.Creator.constant; +const symbolNode = mathNode.Creator.symbol; +const parenNode = mathNode.Creator.parenthesis; + +describe('flattens + and *', () => { + const tests = [ + ['2+2', math.parse('2+2')], + ['2+2+7', opNode('+', [constNode(2), constNode(2), constNode(7)])], + ['9*8*6+3+4', + opNode('+', [ + opNode('*', [constNode(9), constNode(8), constNode(6)]), + constNode(3), + constNode(4)])], + ['5*(2+3+2)*10', + opNode('*', [ + constNode(5), + parenNode(opNode('+', [constNode(2), constNode(3),constNode(2)])), + constNode(10)])], + // keeps the polynomial term + ['9x*8*6+3+4', + opNode('+', [ + opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), + constNode(3), + constNode(4)])], + ['9x*8*6+3y^2+4', + opNode('+', [ + opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), + math.parse('3y^2'), + constNode(4)])], + // doesn't flatten + ['2 x ^ (2 + 1) * y', math.parse('2 x ^ (2 + 1) * y')], + ['2 x ^ (2 + 1 + 2) * y', + opNode('*', [ + opNode('*', [constNode(2), + opNode('^', [symbolNode('x'), parenNode( + opNode('+', [constNode(2), constNode(1), constNode(2)]))]), + ], true), symbolNode('y')]) + ], + ['3x*4x', opNode('*', [math.parse('3x'), math.parse('4x')])] + ]; + tests.forEach(t => testFlatten(t[0], t[1])); +}); + +describe('flattens division', () => { + const tests = [ + // groups x/4 and continues to flatten * + ['2 * x / 4 * 6 ', + opNode('*', [opNode('/', [ + math.parse('2x'), math.parse('4')]), constNode(6)])], + ['2*3/4/5*6', + opNode('*', [constNode(2), math.parse('3/4/5'), constNode(6)])], + // combines coefficient with x + ['x / (4 * x) / 8', + math.parse('x / (4x) / 8')], + ['2 x * 4 x / 8', + opNode('*', [math.parse('2x'), opNode( + '/', [math.parse('4x'), constNode(8)])])], + ]; + tests.forEach(t => testFlatten(t[0], t[1])); +}); + +describe('subtraction', () => { + const tests = [ + ['1 + 2 - 3 - 4 + 5', + opNode('+', [ + constNode(1), constNode(2), constNode(-3), constNode(-4), constNode(5)])], + ['x - 3', opNode('+', [symbolNode('x'), constNode(-3)])], + ['x + 4 - (y+4)', + opNode('+', [symbolNode('x'), constNode(4), math.parse('-(y+4)')])], + ]; + tests.forEach(t => testFlatten(t[0], t[1])); +}); + + +// Remove some property used in mathjs that we don't need and prevents node +// equality checks from passing +function removeComments(node: any); +function removeComments(node) { + node.filter(node => node.comment !== undefined).forEach( + node => delete node.comment); +} diff --git a/test/util/print.test.js b/test/util/print.test.js deleted file mode 100644 index 232e8cc9..00000000 --- a/test/util/print.test.js +++ /dev/null @@ -1,48 +0,0 @@ -const math = require('mathjs'); - -const Node = require('../../lib/node'); -const print = require('../../lib/util/print'); - -const TestUtil = require('../TestUtil'); - -// to create nodes, for testing -const opNode = Node.Creator.operator; -const constNode = Node.Creator.constant; -const symbolNode = Node.Creator.symbol; - -function testPrintStr(exprStr, outputStr) { - const input = math.parse(exprStr); - TestUtil.testFunctionOutput(print, input, outputStr); -} - -function testPrintNode(node, outputStr) { - TestUtil.testFunctionOutput(print, node, outputStr); -} - -describe('print asciimath', function () { - const tests = [ - ['2+3+4', '2 + 3 + 4'], - ['2 + (4 - x) + - 4', '2 + (4 - x) - 4'], - ['2/3 x^2', '2/3 x^2'], - ['-2/3', '-2/3'], - ]; - tests.forEach(t => testPrintStr(t[0], t[1])); -}); - -describe('print with parenthesis', function () { - const tests = [ - [opNode('*', [ - opNode('+', [constNode(2), constNode(3)]), - symbolNode('x') - ]), '(2 + 3) * x'], - [opNode('^', [ - opNode('-', [constNode(7), constNode(4)]), - symbolNode('x') - ]), '(7 - 4)^x'], - [opNode('/', [ - opNode('+', [constNode(9), constNode(2)]), - symbolNode('x') - ]), '(9 + 2) / x'], - ]; - tests.forEach(t => testPrintNode(t[0], t[1])); -}); diff --git a/test/util/print.test.ts b/test/util/print.test.ts new file mode 100644 index 00000000..ff8b3b52 --- /dev/null +++ b/test/util/print.test.ts @@ -0,0 +1,48 @@ +import math = require('mathjs'); +const mathNode = require('../../lib/node'); +import print = require('../../lib/util/print'); +import TestUtil = require('../TestUtil'); + +// to create nodes, for testing +const opNode = mathNode.Creator.operator; +const constNode = mathNode.Creator.constant; +const symbolNode = mathNode.Creator.symbol; + +function testPrintStr(exprStr: any, outputStr: any); +function testPrintStr(exprStr, outputStr) { + const input = math.parse(exprStr); + TestUtil.testFunctionOutput(print, input, outputStr); +} + +function testPrintNode(node: any, outputStr: any); +function testPrintNode(node, outputStr) { + TestUtil.testFunctionOutput(print, node, outputStr); +} + +describe('print asciimath', () => { + const tests = [ + ['2+3+4', '2 + 3 + 4'], + ['2 + (4 - x) + - 4', '2 + (4 - x) - 4'], + ['2/3 x^2', '2/3 x^2'], + ['-2/3', '-2/3'], + ]; + tests.forEach(t => testPrintStr(t[0], t[1])); +}); + +describe('print with parenthesis', () => { + const tests = [ + [opNode('*', [ + opNode('+', [constNode(2), constNode(3)]), + symbolNode('x') + ]), '(2 + 3) * x'], + [opNode('^', [ + opNode('-', [constNode(7), constNode(4)]), + symbolNode('x') + ]), '(7 - 4)^x'], + [opNode('/', [ + opNode('+', [constNode(9), constNode(2)]), + symbolNode('x') + ]), '(9 + 2) / x'], + ]; + tests.forEach(t => testPrintNode(t[0], t[1])); +}); diff --git a/test/util/removeUnnecessaryParens.test.js b/test/util/removeUnnecessaryParens.test.js deleted file mode 100644 index 9078cd33..00000000 --- a/test/util/removeUnnecessaryParens.test.js +++ /dev/null @@ -1,30 +0,0 @@ -const math = require('mathjs'); - -const print = require('../../lib/util/print'); -const removeUnnecessaryParens = require('../../lib/util/removeUnnecessaryParens'); - -const TestUtil = require('../TestUtil'); - -function testRemoveUnnecessaryParens(exprStr, outputStr) { - const input = removeUnnecessaryParens(math.parse(exprStr)); - TestUtil.testFunctionOutput(print, input, outputStr); -} - -describe('removeUnnecessaryParens', function () { - const tests = [ - ['(x+4) + 12', 'x + 4 + 12'], - ['-(x+4x) + 12', '-(x + 4x) + 12'], - ['x + (12)', 'x + 12'], - ['x + (y)', 'x + y'], - ['x + -(y)', 'x - y'], - ['((3 - 5)) * x', '(3 - 5) * x'], - ['((3 - 5)) * x', '(3 - 5) * x'], - ['(((-5)))', '-5'], - ['((4+5)) + ((2^3))', '(4 + 5) + 2^3'], - ['(2x^6 + -50 x^2) - (x^4)', '2x^6 - 50x^2 - x^4'], - ['(x+4) - (12 + x)', 'x + 4 - (12 + x)'], - ['(2x)^2', '(2x)^2'], - ['((4+x)-5)^(2)', '(4 + x - 5)^2'], - ]; - tests.forEach(t => testRemoveUnnecessaryParens(t[0], t[1])); -}); diff --git a/test/util/removeUnnecessaryParens.test.ts b/test/util/removeUnnecessaryParens.test.ts new file mode 100644 index 00000000..129f683c --- /dev/null +++ b/test/util/removeUnnecessaryParens.test.ts @@ -0,0 +1,29 @@ +import math = require('mathjs'); +import print = require('../../lib/util/print'); +import removeUnnecessaryParens = require('../../lib/util/removeUnnecessaryParens'); +import TestUtil = require('../TestUtil'); + +function testRemoveUnnecessaryParens(exprStr: any, outputStr: any); +function testRemoveUnnecessaryParens(exprStr, outputStr) { + const input = removeUnnecessaryParens(math.parse(exprStr)); + TestUtil.testFunctionOutput(print, input, outputStr); +} + +describe('removeUnnecessaryParens', () => { + const tests = [ + ['(x+4) + 12', 'x + 4 + 12'], + ['-(x+4x) + 12', '-(x + 4x) + 12'], + ['x + (12)', 'x + 12'], + ['x + (y)', 'x + y'], + ['x + -(y)', 'x - y'], + ['((3 - 5)) * x', '(3 - 5) * x'], + ['((3 - 5)) * x', '(3 - 5) * x'], + ['(((-5)))', '-5'], + ['((4+5)) + ((2^3))', '(4 + 5) + 2^3'], + ['(2x^6 + -50 x^2) - (x^4)', '2x^6 - 50x^2 - x^4'], + ['(x+4) - (12 + x)', 'x + 4 - (12 + x)'], + ['(2x)^2', '(2x)^2'], + ['((4+x)-5)^(2)', '(4 + x - 5)^2'], + ]; + tests.forEach(t => testRemoveUnnecessaryParens(t[0], t[1])); +}); From 37123f19ad66ad2176277369d4385686b6443d3c Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 7 Apr 2017 23:23:46 -0700 Subject: [PATCH 02/12] Porting some of the other files/directories --- index.js | 12 + index.js.map | 1 + lib/Negative.js | 93 ++++++ lib/Negative.js.map | 1 + lib/Negative.ts | 6 +- lib/Symbols.ts | 6 +- lib/TreeSearch.js | 59 ++++ lib/TreeSearch.js.map | 1 + lib/TreeSearch.ts | 8 +- lib/checks/canAddLikeTermPolynomialNodes.ts | 2 +- .../canMultiplyLikeTermPolynomialNodes.ts | 3 +- lib/checks/canRearrangeCoefficient.ts | 3 +- lib/checks/canSimplifyPolynomialTerms.js | 11 + lib/checks/canSimplifyPolynomialTerms.js.map | 1 + lib/checks/hasUnsupportedNodes.js | 34 ++ lib/checks/hasUnsupportedNodes.js.map | 1 + lib/checks/hasUnsupportedNodes.ts | 2 +- lib/checks/index.js | 20 ++ lib/checks/index.js.map | 1 + lib/checks/isQuadratic.ts | 2 +- lib/checks/resolvesToConstant.js | 24 ++ lib/checks/resolvesToConstant.js.map | 1 + lib/checks/resolvesToConstant.ts | 3 +- lib/equation/Equation.js | 41 +++ lib/equation/Equation.js.map | 1 + lib/equation/Equation.ts | 31 +- lib/equation/Status.js | 65 ++++ lib/equation/Status.js.map | 1 + lib/equation/Status.ts | 116 ++++--- lib/factor/ConstantFactors.ts | 8 +- lib/factor/factorQuadratic.ts | 116 +++---- lib/mathNode/Creator.ts | 2 +- lib/mathNode/PolynomialTerm.ts | 306 +++++++++--------- lib/mathNode/Status.ts | 2 +- lib/mathNode/Type.ts | 4 +- .../arithmeticSearch/index.js | 56 ++++ .../arithmeticSearch/index.js.map | 1 + .../arithmeticSearch/index.ts | 4 +- lib/simplifyExpression/basicsSearch/index.ts | 2 +- .../basicsSearch/rearrangeCoefficient.ts | 2 +- .../basicsSearch/reduceExponentByZero.ts | 2 +- .../reduceMultiplicationByZero.ts | 2 +- .../reduceZeroDividedByAnything.ts | 2 +- .../basicsSearch/removeAdditionOfZero.ts | 2 +- .../basicsSearch/removeDivisionByOne.ts | 2 +- .../basicsSearch/removeExponentBaseOne.ts | 2 +- .../basicsSearch/removeExponentByOne.ts | 2 +- .../removeMultiplicationByNegativeOne.ts | 2 +- .../basicsSearch/removeMultiplicationByOne.ts | 3 +- .../basicsSearch/simplifyDoubleUnaryMinus.ts | 2 +- .../breakUpNumeratorSearch/index.ts | 2 +- .../LikeTermCollector.ts | 16 +- .../collectAndCombineSearch/addLikeTerms.js | 126 ++++++++ .../addLikeTerms.js.map | 1 + .../collectAndCombineSearch/addLikeTerms.ts | 4 +- .../evaluateConstantSum.js | 106 ++++++ .../evaluateConstantSum.js.map | 1 + .../evaluateConstantSum.ts | 2 +- .../collectAndCombineSearch/index.ts | 4 +- .../multiplyLikeTerms.js | 109 +++++++ .../multiplyLikeTerms.js.map | 1 + .../multiplyLikeTerms.ts | 2 +- .../distributeSearch/index.js | 231 +++++++++++++ .../distributeSearch/index.js.map | 1 + .../distributeSearch/index.ts | 2 +- .../divisionSearch/index.ts | 2 +- .../fractionsSearch/addConstantAndFraction.js | 89 +++++ .../addConstantAndFraction.js.map | 1 + .../fractionsSearch/addConstantAndFraction.ts | 4 +- .../fractionsSearch/addConstantFractions.ts | 2 +- .../fractionsSearch/cancelLikeTerms.ts | 8 +- .../fractionsSearch/divideByGCD.ts | 2 +- .../fractionsSearch/index.js | 48 +++ .../fractionsSearch/index.js.map | 1 + .../fractionsSearch/index.ts | 2 +- .../fractionsSearch/simplifyFractionSigns.ts | 2 +- .../simplifyPolynomialFraction.js | 34 ++ .../simplifyPolynomialFraction.js.map | 1 + .../simplifyPolynomialFraction.ts | 2 +- .../functionsSearch/nthRoot.ts | 3 +- lib/simplifyExpression/index.js | 19 ++ lib/simplifyExpression/index.js.map | 1 + .../multiplyFractionsSearch/index.js | 43 +++ .../multiplyFractionsSearch/index.js.map | 1 + .../multiplyFractionsSearch/index.ts | 2 +- lib/simplifyExpression/simplify.ts | 1 - lib/simplifyExpression/stepThrough.js | 120 +++++++ lib/simplifyExpression/stepThrough.js.map | 1 + lib/simplifyExpression/stepThrough.ts | 10 +- lib/solveEquation/EquationOperations.js | 202 ++++++++++++ lib/solveEquation/EquationOperations.js.map | 1 + lib/solveEquation/EquationOperations.ts | 283 ++++++++-------- lib/solveEquation/index.js | 33 ++ lib/solveEquation/index.js.map | 1 + lib/solveEquation/stepThrough.js | 226 +++++++++++++ lib/solveEquation/stepThrough.js.map | 1 + lib/solveEquation/stepThrough.ts | 7 +- lib/util/Util.ts | 2 +- lib/util/clone.js | 3 + lib/util/clone.js.map | 2 +- lib/util/clone.ts | 1 - lib/util/evaluate.js | 2 +- lib/util/evaluate.js.map | 2 +- lib/util/evaluate.ts | 2 - lib/util/flattenOperands.ts | 16 +- lib/util/print.ts | 30 +- lib/util/removeUnnecessaryParens.ts | 42 ++- 107 files changed, 2374 insertions(+), 563 deletions(-) create mode 100644 index.js create mode 100644 index.js.map create mode 100644 lib/Negative.js create mode 100644 lib/Negative.js.map create mode 100644 lib/TreeSearch.js create mode 100644 lib/TreeSearch.js.map create mode 100644 lib/checks/canSimplifyPolynomialTerms.js create mode 100644 lib/checks/canSimplifyPolynomialTerms.js.map create mode 100644 lib/checks/hasUnsupportedNodes.js create mode 100644 lib/checks/hasUnsupportedNodes.js.map create mode 100644 lib/checks/index.js create mode 100644 lib/checks/index.js.map create mode 100644 lib/checks/resolvesToConstant.js create mode 100644 lib/checks/resolvesToConstant.js.map create mode 100644 lib/equation/Equation.js create mode 100644 lib/equation/Equation.js.map create mode 100644 lib/equation/Status.js create mode 100644 lib/equation/Status.js.map create mode 100644 lib/simplifyExpression/arithmeticSearch/index.js create mode 100644 lib/simplifyExpression/arithmeticSearch/index.js.map create mode 100644 lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js create mode 100644 lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map create mode 100644 lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js create mode 100644 lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map create mode 100644 lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js create mode 100644 lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map create mode 100644 lib/simplifyExpression/distributeSearch/index.js create mode 100644 lib/simplifyExpression/distributeSearch/index.js.map create mode 100644 lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js create mode 100644 lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map create mode 100644 lib/simplifyExpression/fractionsSearch/index.js create mode 100644 lib/simplifyExpression/fractionsSearch/index.js.map create mode 100644 lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js create mode 100644 lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map create mode 100644 lib/simplifyExpression/index.js create mode 100644 lib/simplifyExpression/index.js.map create mode 100644 lib/simplifyExpression/multiplyFractionsSearch/index.js create mode 100644 lib/simplifyExpression/multiplyFractionsSearch/index.js.map create mode 100644 lib/simplifyExpression/stepThrough.js create mode 100644 lib/simplifyExpression/stepThrough.js.map create mode 100644 lib/solveEquation/EquationOperations.js create mode 100644 lib/solveEquation/EquationOperations.js.map create mode 100644 lib/solveEquation/index.js create mode 100644 lib/solveEquation/index.js.map create mode 100644 lib/solveEquation/stepThrough.js create mode 100644 lib/solveEquation/stepThrough.js.map diff --git a/index.js b/index.js new file mode 100644 index 00000000..e90ae9c4 --- /dev/null +++ b/index.js @@ -0,0 +1,12 @@ +"use strict"; +var ChangeTypes = require("./lib/ChangeTypes"); +var simplifyExpression = require("./lib/simplifyExpression"); +var solveEquation = require("./lib/solveEquation"); +var tmp; +tmp = { + simplifyExpression: simplifyExpression, + solveEquation: solveEquation, + ChangeTypes: ChangeTypes, +}; +module.exports = tmp; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/index.js.map b/index.js.map new file mode 100644 index 00000000..174e5983 --- /dev/null +++ b/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,6DAAgE;AAChE,mDAAsD;AACtD,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,kBAAkB,oBAAA;IAClB,aAAa,eAAA;IACb,WAAW,aAAA;CACd,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/Negative.js b/lib/Negative.js new file mode 100644 index 00000000..be84655b --- /dev/null +++ b/lib/Negative.js @@ -0,0 +1,93 @@ +"use strict"; +var mathNode = require("./mathNode"); +var Negative = (function () { + function Negative() { + } + // Returns if the given node is negative. Treats a unary minus as a negative, + // as well as a negative constant value or a constant fraction that would + // evaluate to a negative number + Negative.isNegative = function (node) { + if (mathNode.Type.isUnaryMinus(node)) { + return !Negative.isNegative(node.args[0]); + } + else if (mathNode.Type.isConstant(node)) { + return parseFloat(node.value) < 0; + } + else if (mathNode.Type.isConstantFraction(node)) { + var numeratorValue = parseFloat(node.args[0].value); + var denominatorValue = parseFloat(node.args[1].value); + if (numeratorValue < 0 || denominatorValue < 0) { + return !(numeratorValue < 0 && denominatorValue < 0); + } + } + else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + var polyNode = new mathNode.PolynomialTerm(node); + return Negative.isNegative(polyNode.getCoeffNode(true)); + } + return false; + }; + // Given a node, returns the negated node + // If naive is true, then we just add an extra unary minus to the expression + // otherwise, we do the actual negation + // E.g. + // not naive: -3 -> 3, x -> -x + // naive: -3 -> --3, x -> -x + Negative.negate = function (node, naive) { + if (naive === void 0) { naive = false; } + if (mathNode.Type.isConstantFraction(node)) { + node.args[0] = Negative.negate(node.args[0], naive); + return node; + } + else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + return Negative.negatePolynomialTerm(node, naive); + } + else if (!naive) { + if (mathNode.Type.isUnaryMinus(node)) { + return node.args[0]; + } + else if (mathNode.Type.isConstant(node)) { + return mathNode.Creator.constant(0 - parseFloat(node.value)); + } + } + return mathNode.Creator.unaryMinus(node); + }; + // Multiplies a polynomial term by -1 and returns the new node + // If naive is true, then we just add an extra unary minus to the expression + // otherwise, we do the actual negation + // E.g. + // not naive: -3x -> 3x, x -> -x + // naive: -3x -> --3x, x -> -x + Negative.negatePolynomialTerm = function (node, naive) { + if (naive === void 0) { naive = false; } + if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { + throw Error('node is not a polynomial term'); + } + var polyNode = new mathNode.PolynomialTerm(node); + var newCoeff; + if (!polyNode.hasCoeff()) { + newCoeff = mathNode.Creator.constant(-1); + } + else { + var oldCoeff = polyNode.getCoeffNode(); + if (oldCoeff.value === '-1') { + newCoeff = null; + } + else if (polyNode.hasFractionCoeff()) { + var numerator = oldCoeff.args[0]; + numerator = Negative.negate(numerator, naive); + var denominator = oldCoeff.args[1]; + newCoeff = mathNode.Creator.operator('/', [numerator, denominator]); + } + else { + newCoeff = Negative.negate(oldCoeff, naive); + if (newCoeff.value === '1') { + newCoeff = null; + } + } + } + return mathNode.Creator.polynomialTerm(polyNode.getSymbolNode(), polyNode.getExponentNode(), newCoeff); + }; + return Negative; +}()); +module.exports = Negative; +//# sourceMappingURL=Negative.js.map \ No newline at end of file diff --git a/lib/Negative.js.map b/lib/Negative.js.map new file mode 100644 index 00000000..c289cc26 --- /dev/null +++ b/lib/Negative.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Negative.js","sourceRoot":"","sources":["Negative.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Negative.ts b/lib/Negative.ts index d6ced34b..f4736873 100644 --- a/lib/Negative.ts +++ b/lib/Negative.ts @@ -4,7 +4,7 @@ class Negative { // Returns if the given node is negative. Treats a unary minus as a negative, // as well as a negative constant value or a constant fraction that would // evaluate to a negative number - isNegative(node) { + static isNegative(node) { if (mathNode.Type.isUnaryMinus(node)) { return !Negative.isNegative(node.args[0]); } else if (mathNode.Type.isConstant(node)) { @@ -29,7 +29,7 @@ class Negative { // E.g. // not naive: -3 -> 3, x -> -x // naive: -3 -> --3, x -> -x - negate(node, naive=false) { + static negate(node, naive=false) { if (mathNode.Type.isConstantFraction(node)) { node.args[0] = Negative.negate(node.args[0], naive); return node; @@ -51,7 +51,7 @@ class Negative { // E.g. // not naive: -3x -> 3x, x -> -x // naive: -3x -> --3x, x -> -x - negatePolynomialTerm(node, naive=false) { + static negatePolynomialTerm(node, naive=false) { if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { throw Error('node is not a polynomial term'); } diff --git a/lib/Symbols.ts b/lib/Symbols.ts index da423bc5..cdf93c82 100644 --- a/lib/Symbols.ts +++ b/lib/Symbols.ts @@ -2,7 +2,7 @@ import mathNode = require('./mathNode'); class Symbols { // returns the set of all the symbols in an equation - getSymbolsInEquation(equation) { + static getSymbolsInEquation(equation) { const leftSymbols = Symbols.getSymbolsInExpression(equation.leftNode); const rightSymbols = Symbols.getSymbolsInExpression(equation.rightNode); const symbols = new Set([...leftSymbols, ...rightSymbols]); @@ -21,7 +21,7 @@ class Symbols { // Iterates through a node and returns the polynomial term with the symbol name // Returns null if no terms with the symbol name are in the node. // e.g. 4x^2 + 2x + y + 2 with `symbolName=x` would return 2x - getLastSymbolTerm = (node, symbolName) => { + static getLastSymbolTerm = (node, symbolName) => { // First check if the node itself is a polyomial term with symbolName if (this.isSymbolTerm(node, symbolName)) { return node; @@ -45,7 +45,7 @@ class Symbols { // e.g. 4x^2 with `symbolName=x` would return 4 // e.g. 4x^2 + 2x + 2/4 with `symbolName=x` would return 2/4 // e.g. 4x^2 + 2x + y with `symbolName=x` would return y - getLastNonSymbolTerm = (node, symbolName) => { + static getLastNonSymbolTerm = (node, symbolName) => { if (this.isSymbolTerm(node, symbolName)) { return new mathNode.PolynomialTerm(node).getCoeffNode(); } else if (mathNode.Type.isOperator(node)) { diff --git a/lib/TreeSearch.js b/lib/TreeSearch.js new file mode 100644 index 00000000..1c3d400b --- /dev/null +++ b/lib/TreeSearch.js @@ -0,0 +1,59 @@ +"use strict"; +var mathNode = require("./mathNode"); +var TreeSearch = (function () { + function TreeSearch() { + var _this = this; + // Returns a function that performs a preorder search on the tree for the given + // simplifcation function + this.preOrder = function (simplificationFunction) { return function (node) { return _this.search(simplificationFunction, node, true); }; }; + // Returns a function that performs a postorder search on the tree for the given + // simplifcation function + this.postOrder = function (simplificationFunction) { return function (node) { return _this.search(simplificationFunction, node, false); }; }; + } + // A helper function for performing a tree search with a function + TreeSearch.prototype.search = function (simplificationFunction, node, preOrder) { + var status; + if (preOrder) { + status = simplificationFunction(node); + if (status.hasChanged()) { + return status; + } + } + if (mathNode.Type.isConstant(node) || mathNode.Type.isSymbol(node)) { + return mathNode.Status.noChange(node); + } + else if (mathNode.Type.isUnaryMinus(node)) { + status = this.search(simplificationFunction, node.args[0], preOrder); + if (status.hasChanged()) { + return mathNode.Status.childChanged(node, status); + } + } + else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { + for (var i = 0; i < node.args.length; i++) { + var child = node.args[i]; + var childNodeStatus = this.search(simplificationFunction, child, preOrder); + if (childNodeStatus.hasChanged()) { + return mathNode.Status.childChanged(node, childNodeStatus, i); + } + } + } + else if (mathNode.Type.isParenthesis(node)) { + status = this.search(simplificationFunction, node.content, preOrder); + if (status.hasChanged()) { + return mathNode.Status.childChanged(node, status); + } + } + else { + throw Error('Unsupported node type: ' + node); + } + if (!preOrder) { + return simplificationFunction(node); + } + else { + return mathNode.Status.noChange(node); + } + }; + return TreeSearch; +}()); +module.exports = TreeSearch; +//# sourceMappingURL=TreeSearch.js.map \ No newline at end of file diff --git a/lib/TreeSearch.js.map b/lib/TreeSearch.js.map new file mode 100644 index 00000000..319c9ec7 --- /dev/null +++ b/lib/TreeSearch.js.map @@ -0,0 +1 @@ +{"version":3,"file":"TreeSearch.js","sourceRoot":"","sources":["TreeSearch.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/TreeSearch.ts b/lib/TreeSearch.ts index 5f8f6ae8..b70ab6a7 100644 --- a/lib/TreeSearch.ts +++ b/lib/TreeSearch.ts @@ -4,11 +4,11 @@ class TreeSearch { // Returns a function that performs a preorder search on the tree for the given // simplifcation function - preOrder = simplificationFunction => node => search(simplificationFunction, node, true); + static preOrder = simplificationFunction => node => this.search(simplificationFunction, node, true); // Returns a function that performs a postorder search on the tree for the given // simplifcation function - postOrder = simplificationFunction => node => search(simplificationFunction, node, false); + static postOrder = simplificationFunction => node => this.search(simplificationFunction, node, false); // A helper function for performing a tree search with a function @@ -32,13 +32,13 @@ class TreeSearch { } else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { for (let i = 0; i < node.args.length; i++) { const child = node.args[i]; - const childNodeStatus = search(simplificationFunction, child, preOrder); + const childNodeStatus = this.search(simplificationFunction, child, preOrder); if (childNodeStatus.hasChanged()) { return mathNode.Status.childChanged(node, childNodeStatus, i); } } } else if (mathNode.Type.isParenthesis(node)) { - status = search(simplificationFunction, node.content, preOrder); + status = this.search(simplificationFunction, node.content, preOrder); if (status.hasChanged()) { return mathNode.Status.childChanged(node, status); } diff --git a/lib/checks/canAddLikeTermPolynomialNodes.ts b/lib/checks/canAddLikeTermPolynomialNodes.ts index 8e1792e4..089f8994 100644 --- a/lib/checks/canAddLikeTermPolynomialNodes.ts +++ b/lib/checks/canAddLikeTermPolynomialNodes.ts @@ -1,4 +1,4 @@ -const mathNode = require('../node'); +import mathNode = require('../mathnode'); // Returns true if the nodes are polynomial terms that can be added together. function canAddLikeTermPolynomialNodes(node: any); diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.ts b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts index 580ce8fc..10ab3134 100644 --- a/lib/checks/canMultiplyLikeTermPolynomialNodes.ts +++ b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts @@ -1,4 +1,5 @@ -const mathNode = require('../node'); +import mathNode = require('../mathnode'); + // Returns true if the nodes are symbolic terms with the same symbol and no // coefficients. diff --git a/lib/checks/canRearrangeCoefficient.ts b/lib/checks/canRearrangeCoefficient.ts index fffc5303..ecb6f1e4 100644 --- a/lib/checks/canRearrangeCoefficient.ts +++ b/lib/checks/canRearrangeCoefficient.ts @@ -1,4 +1,5 @@ -const mathNode = require('../node'); +import mathNode = require('../mathnode'); + // Returns true if the expression is a multiplication between a constant // and polynomial without a coefficient. diff --git a/lib/checks/canSimplifyPolynomialTerms.js b/lib/checks/canSimplifyPolynomialTerms.js new file mode 100644 index 00000000..a485d366 --- /dev/null +++ b/lib/checks/canSimplifyPolynomialTerms.js @@ -0,0 +1,11 @@ +"use strict"; +var canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); +var canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); +var canRearrangeCoefficient = require("./canRearrangeCoefficient"); +function canSimplifyPolynomialTerms(node) { + return (canAddLikeTermPolynomialNodes(node) || + canMultiplyLikeTermPolynomialNodes(node) || + canRearrangeCoefficient(node)); +} +module.exports = canSimplifyPolynomialTerms; +//# sourceMappingURL=canSimplifyPolynomialTerms.js.map \ No newline at end of file diff --git a/lib/checks/canSimplifyPolynomialTerms.js.map b/lib/checks/canSimplifyPolynomialTerms.js.map new file mode 100644 index 00000000..8e9fb471 --- /dev/null +++ b/lib/checks/canSimplifyPolynomialTerms.js.map @@ -0,0 +1 @@ +{"version":3,"file":"canSimplifyPolynomialTerms.js","sourceRoot":"","sources":["canSimplifyPolynomialTerms.ts"],"names":[],"mappings":";AAAA,+EAAkF;AAClF,yFAA4F;AAC5F,mEAAsE;AAKtE,oCAAoC,IAAI;IACtC,MAAM,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC;QACnC,kCAAkC,CAAC,IAAI,CAAC;QACxC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/checks/hasUnsupportedNodes.js b/lib/checks/hasUnsupportedNodes.js new file mode 100644 index 00000000..ac956738 --- /dev/null +++ b/lib/checks/hasUnsupportedNodes.js @@ -0,0 +1,34 @@ +"use strict"; +var mathNode = require("../mathnode"); +var resolvesToConstant = require("./resolvesToConstant"); +function hasUnsupportedNodes(node) { + if (mathNode.Type.isParenthesis(node)) { + return hasUnsupportedNodes(node.content); + } + else if (mathNode.Type.isUnaryMinus(node)) { + return hasUnsupportedNodes(node.args[0]); + } + else if (mathNode.Type.isOperator(node)) { + return node.args.some(hasUnsupportedNodes); + } + else if (mathNode.Type.isSymbol(node) || mathNode.Type.isConstant(node)) { + return false; + } + else if (mathNode.Type.isFunction(node, 'abs')) { + if (node.args.length !== 1) { + return true; + } + if (node.args.some(hasUnsupportedNodes)) { + return true; + } + return !resolvesToConstant(node.args[0]); + } + else if (mathNode.Type.isFunction(node, 'nthRoot')) { + return node.args.some(hasUnsupportedNodes) || node.args.length < 1; + } + else { + return true; + } +} +module.exports = hasUnsupportedNodes; +//# sourceMappingURL=hasUnsupportedNodes.js.map \ No newline at end of file diff --git a/lib/checks/hasUnsupportedNodes.js.map b/lib/checks/hasUnsupportedNodes.js.map new file mode 100644 index 00000000..b2d2f030 --- /dev/null +++ b/lib/checks/hasUnsupportedNodes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hasUnsupportedNodes.js","sourceRoot":"","sources":["hasUnsupportedNodes.ts"],"names":[],"mappings":";AAAA,sCAAyC;AACzC,yDAA4D;AAG5D,6BAA6B,IAAI;IAC/B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/C,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/checks/hasUnsupportedNodes.ts b/lib/checks/hasUnsupportedNodes.ts index c646791c..c5c1623d 100644 --- a/lib/checks/hasUnsupportedNodes.ts +++ b/lib/checks/hasUnsupportedNodes.ts @@ -1,4 +1,4 @@ -const mathNode = require('../node'); +import mathNode = require('../mathnode'); import resolvesToConstant = require('./resolvesToConstant'); function hasUnsupportedNodes(node: any); diff --git a/lib/checks/index.js b/lib/checks/index.js new file mode 100644 index 00000000..414e8a91 --- /dev/null +++ b/lib/checks/index.js @@ -0,0 +1,20 @@ +"use strict"; +var canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); +var canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); +var canRearrangeCoefficient = require("./canRearrangeCoefficient"); +var canSimplifyPolynomialTerms = require("./canSimplifyPolynomialTerms"); +var hasUnsupportedNodes = require("./hasUnsupportedNodes"); +var isQuadratic = require("./isQuadratic"); +var resolvesToConstant = require("./resolvesToConstant"); +var tmp; +tmp = { + canAddLikeTermPolynomialNodes: canAddLikeTermPolynomialNodes, + canMultiplyLikeTermPolynomialNodes: canMultiplyLikeTermPolynomialNodes, + canRearrangeCoefficient: canRearrangeCoefficient, + canSimplifyPolynomialTerms: canSimplifyPolynomialTerms, + hasUnsupportedNodes: hasUnsupportedNodes, + isQuadratic: isQuadratic, + resolvesToConstant: resolvesToConstant, +}; +module.exports = tmp; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/checks/index.js.map b/lib/checks/index.js.map new file mode 100644 index 00000000..2c6ec142 --- /dev/null +++ b/lib/checks/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+EAAkF;AAClF,yFAA4F;AAC5F,mEAAsE;AACtE,yEAA4E;AAC5E,2DAA8D;AAC9D,2CAA8C;AAC9C,yDAA4D;AAC5D,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,6BAA6B,+BAAA;IAC7B,kCAAkC,oCAAA;IAClC,uBAAuB,yBAAA;IACvB,0BAA0B,4BAAA;IAC1B,mBAAmB,qBAAA;IACnB,WAAW,aAAA;IACX,kBAAkB,oBAAA;CACrB,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/checks/isQuadratic.ts b/lib/checks/isQuadratic.ts index 06667853..b2001504 100644 --- a/lib/checks/isQuadratic.ts +++ b/lib/checks/isQuadratic.ts @@ -1,4 +1,4 @@ -const mathNode = require('../node'); +import mathNode = require('../mathnode'); import Symbols = require('../Symbols'); // Given a node, will determine if the expression is in the form of a quadratic diff --git a/lib/checks/resolvesToConstant.js b/lib/checks/resolvesToConstant.js new file mode 100644 index 00000000..065300d7 --- /dev/null +++ b/lib/checks/resolvesToConstant.js @@ -0,0 +1,24 @@ +"use strict"; +var mathNode = require("../mathnode"); +function resolvesToConstant(node) { + if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { + return node.args.every(function (child) { return resolvesToConstant(child); }); + } + else if (mathNode.Type.isParenthesis(node)) { + return resolvesToConstant(node.content); + } + else if (mathNode.Type.isConstant(node, true)) { + return true; + } + else if (mathNode.Type.isSymbol(node)) { + return false; + } + else if (mathNode.Type.isUnaryMinus(node)) { + return resolvesToConstant(node.args[0]); + } + else { + throw Error('Unsupported node type: ' + node.type); + } +} +module.exports = resolvesToConstant; +//# sourceMappingURL=resolvesToConstant.js.map \ No newline at end of file diff --git a/lib/checks/resolvesToConstant.js.map b/lib/checks/resolvesToConstant.js.map new file mode 100644 index 00000000..60090ef3 --- /dev/null +++ b/lib/checks/resolvesToConstant.js.map @@ -0,0 +1 @@ +{"version":3,"file":"resolvesToConstant.js","sourceRoot":"","sources":["resolvesToConstant.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAOzC,4BAA4B,IAAI;IAC9B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CACpB,UAAC,KAAK,IAAK,OAAA,kBAAkB,CAAC,KAAK,CAAC,EAAzB,CAAyB,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,iBAAS,kBAAkB,CAAC"} \ No newline at end of file diff --git a/lib/checks/resolvesToConstant.ts b/lib/checks/resolvesToConstant.ts index 197dc6ba..ea6ce257 100644 --- a/lib/checks/resolvesToConstant.ts +++ b/lib/checks/resolvesToConstant.ts @@ -1,4 +1,5 @@ -const mathNode = require('../node'); +import mathNode = require('../mathnode'); + // Returns true if the node is a constant or can eventually be resolved to // a constant. diff --git a/lib/equation/Equation.js b/lib/equation/Equation.js new file mode 100644 index 00000000..86c23922 --- /dev/null +++ b/lib/equation/Equation.js @@ -0,0 +1,41 @@ +"use strict"; +var math = require("mathjs"); +var clone = require("../util/clone"); +var printNode = require("../util/print"); +// This represents an equation, made up of the leftNode (LHS), the +// rightNode (RHS) and a comparator (=, <, >, <=, or >=) +var Equation = (function () { + function Equation(leftNode, rightNode, comparator) { + this.leftNode = leftNode; + this.rightNode = rightNode; + this.comparator = comparator; + } + // Prints an Equation properly using the print module + Equation.prototype.print = function (showPlusMinus) { + if (showPlusMinus === void 0) { showPlusMinus = false; } + var leftSide = printNode(this.leftNode, showPlusMinus); + var rightSide = printNode(this.rightNode, showPlusMinus); + var comparator = this.comparator; + return leftSide + " " + comparator + " " + rightSide; + }; + Equation.prototype.clone = function () { + var newLeft = clone(this.leftNode); + var newRight = clone(this.rightNode); + return new Equation(newLeft, newRight, this.comparator); + }; + return Equation; +}()); +// Splits a string on the given comparator and returns a new Equation object +// from the left and right hand sides +Equation.createEquationFromString = function (str, comparator) { + var sides = str.split(comparator); + if (sides.length !== 2) { + throw Error('Expected two sides of an equation using comparator: ' + + comparator); + } + var leftNode = math.parse(sides[0]); + var rightNode = math.parse(sides[1]); + return new Equation(leftNode, rightNode, comparator); +}; +module.exports = Equation; +//# sourceMappingURL=Equation.js.map \ No newline at end of file diff --git a/lib/equation/Equation.js.map b/lib/equation/Equation.js.map new file mode 100644 index 00000000..12aa5e5c --- /dev/null +++ b/lib/equation/Equation.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Equation.js","sourceRoot":"","sources":["Equation.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,qCAAwC;AACxC,yCAA4C;AAE5C,kEAAkE;AAClE,wDAAwD;AACxD;IACE,kBAAY,QAAQ,EAAE,SAAS,EAAE,UAAU;QACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,qDAAqD;IACrD,wBAAK,GAAL,UAAM,aAAmB;QAAnB,8BAAA,EAAA,qBAAmB;QACvB,IAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACzD,IAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC3D,IAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,MAAM,CAAI,QAAQ,SAAI,UAAU,SAAI,SAAW,CAAC;IAClD,CAAC;IAED,wBAAK,GAAL;QACE,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC;IAkBH,eAAC;AAAD,CAAC,AArCD;AAqBE,4EAA4E;AAC5E,qCAAqC;AAC9B,iCAAwB,GAAG,UAAC,GAAG,EAAE,UAAU;IAC9C,IAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC,sDAAsD;YAC9D,UAAU,CAAC,CAAC;IACpB,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC,CAAC;AAMJ,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/equation/Equation.ts b/lib/equation/Equation.ts index 60793454..dd29c8ec 100644 --- a/lib/equation/Equation.ts +++ b/lib/equation/Equation.ts @@ -16,7 +16,6 @@ class Equation { const leftSide = printNode(this.leftNode, showPlusMinus); const rightSide = printNode(this.rightNode, showPlusMinus); const comparator = this.comparator; - return `${leftSide} ${comparator} ${rightSide}`; } @@ -25,19 +24,23 @@ class Equation { const newRight = clone(this.rightNode); return new Equation(newLeft, newRight, this.comparator); } -} -// Splits a string on the given comparator and returns a new Equation object -// from the left and right hand sides -Equation.createEquationFromString = (str, comparator) => { - const sides = str.split(comparator); - if (sides.length !== 2) { - throw Error('Expected two sides of an equation using comparator: ' + - comparator); - } - const leftNode = math.parse(sides[0]); - const rightNode = math.parse(sides[1]); + // Splits a string on the given comparator and returns a new Equation object + // from the left and right hand sides + static createEquationFromString = (str, comparator) => { + const sides = str.split(comparator); + if (sides.length !== 2) { + throw Error('Expected two sides of an equation using comparator: ' + + comparator); + } + const leftNode = math.parse(sides[0]); + const rightNode = math.parse(sides[1]); + + return new Equation(leftNode, rightNode, comparator); + }; + leftNode; + rightNode; + comparator; +} - return new Equation(leftNode, rightNode, comparator); -}; export = Equation; diff --git a/lib/equation/Status.js b/lib/equation/Status.js new file mode 100644 index 00000000..42c8a507 --- /dev/null +++ b/lib/equation/Status.js @@ -0,0 +1,65 @@ +"use strict"; +var ChangeTypes = require("../ChangeTypes"); +var Equation = require("./Equation"); +var mathNode = require("../mathNode"); +// This represents the current equation we're solving. +// As we move step by step, an equation might be updated. Functions return this +// status object to pass on the updated equation and information on if/how it was +// changed. +var Status = (function () { + function Status(changeType, oldEquation, newEquation, substeps) { + if (substeps === void 0) { substeps = []; } + if (!newEquation) { + throw Error('new equation isn\'t defined'); + } + if (changeType === undefined || typeof (changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } + this.changeType = changeType; + this.oldEquation = oldEquation; + this.newEquation = newEquation; + this.substeps = substeps; + } + Status.prototype.hasChanged = function () { + return this.changeType !== ChangeTypes.NO_CHANGE; + }; + return Status; +}()); +// A wrapper around the Status constructor for the case where equation +// hasn't been changed. +Status.noChange = function (equation) { return new Status(ChangeTypes.NO_CHANGE, null, equation); }; +Status.addLeftStep = function (equation, leftStep) { + var substeps = []; + leftStep.substeps.forEach(function (substep) { + substeps.push(Status.addLeftStep(equation, substep)); + }); + var oldEquation = null; + if (leftStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.leftNode = leftStep.oldNode; + } + var newEquation = equation.clone(); + newEquation.leftNode = leftStep.newNode; + return new Status(leftStep.changeType, oldEquation, newEquation, substeps); +}; +Status.addRightStep = function (equation, rightStep) { + var substeps = []; + rightStep.substeps.forEach(function (substep) { + substeps.push(Status.addRightStep(equation, substep)); + }); + var oldEquation = null; + if (rightStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.rightNode = rightStep.oldNode; + } + var newEquation = equation.clone(); + newEquation.rightNode = rightStep.newNode; + return new Status(rightStep.changeType, oldEquation, newEquation, substeps); +}; +Status.resetChangeGroups = function (equation) { + var leftNode = mathNode.Status.resetChangeGroups(equation.leftNode); + var rightNode = mathNode.Status.resetChangeGroups(equation.rightNode); + return new Equation(leftNode, rightNode, equation.comparator); +}; +module.exports = Status; +//# sourceMappingURL=Status.js.map \ No newline at end of file diff --git a/lib/equation/Status.js.map b/lib/equation/Status.js.map new file mode 100644 index 00000000..bc75d320 --- /dev/null +++ b/lib/equation/Status.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Status.js","sourceRoot":"","sources":["Status.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/equation/Status.ts b/lib/equation/Status.ts index eb6174e7..ec928993 100644 --- a/lib/equation/Status.ts +++ b/lib/equation/Status.ts @@ -1,70 +1,80 @@ import ChangeTypes = require('../ChangeTypes'); import Equation = require('./Equation'); -const mathNode = require('../node'); +import mathNode = require('../mathNode'); // This represents the current equation we're solving. // As we move step by step, an equation might be updated. Functions return this // status object to pass on the updated equation and information on if/how it was // changed. class Status { - constructor(changeType, oldEquation, newEquation, substeps=[]) { - if (!newEquation) { - throw Error('new equation isn\'t defined'); - } - if (changeType === undefined || typeof(changeType) !== 'string') { - throw Error('changetype isn\'t valid'); - } + constructor(changeType, oldEquation, newEquation, substeps=[]) { + if (!newEquation) { + throw Error('new equation isn\'t defined'); + } + if (changeType === undefined || typeof(changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } - this.changeType = changeType; - this.oldEquation = oldEquation; - this.newEquation = newEquation; - this.substeps = substeps; - } + this.changeType = changeType; + this.oldEquation = oldEquation; + this.newEquation = newEquation; + this.substeps = substeps; + } - hasChanged() { - return this.changeType !== ChangeTypes.NO_CHANGE; - } -} + hasChanged() { + return this.changeType !== ChangeTypes.NO_CHANGE; + } // A wrapper around the Status constructor for the case where equation // hasn't been changed. -Status.noChange = equation => new Status(ChangeTypes.NO_CHANGE, null, equation); + static noChange = equation => new Status(ChangeTypes.NO_CHANGE, null, equation); + static addLeftStep = (equation, leftStep) => { + const substeps = []; + leftStep.substeps.forEach(substep => { + substeps.push(Status.addLeftStep(equation, substep)); + }); + let oldEquation = null; + if (leftStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.leftNode = leftStep.oldNode; + } + const newEquation = equation.clone(); + newEquation.leftNode = leftStep.newNode; + return new Status( + leftStep.changeType, + oldEquation, + newEquation, + substeps); + }; -Status.addLeftStep = (equation, leftStep) => { - const substeps = []; - leftStep.substeps.forEach(substep => { - substeps.push(Status.addLeftStep(equation, substep)); - }); - let oldEquation = null; - if (leftStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.leftNode = leftStep.oldNode; - } - const newEquation = equation.clone(); - newEquation.leftNode = leftStep.newNode; - return new Status( - leftStep.changeType, oldEquation, newEquation, substeps); -}; + static addRightStep = (equation, rightStep) => { + const substeps = []; + rightStep.substeps.forEach(substep => { + substeps.push(Status.addRightStep(equation, substep)); + }); + let oldEquation = null; + if (rightStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.rightNode = rightStep.oldNode; + } + const newEquation = equation.clone(); + newEquation.rightNode = rightStep.newNode; + return new Status( + rightStep.changeType, + oldEquation, + newEquation, + substeps); + }; -Status.addRightStep = (equation, rightStep) => { - const substeps = []; - rightStep.substeps.forEach(substep => { - substeps.push(Status.addRightStep(equation, substep)); - }); - let oldEquation = null; - if (rightStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.rightNode = rightStep.oldNode; - } - const newEquation = equation.clone(); - newEquation.rightNode = rightStep.newNode; - return new Status( - rightStep.changeType, oldEquation, newEquation, substeps); -}; + static resetChangeGroups = equation => { + const leftNode = mathNode.Status.resetChangeGroups(equation.leftNode); + const rightNode = mathNode.Status.resetChangeGroups(equation.rightNode); + return new Equation(leftNode, rightNode, equation.comparator); + }; + changeType; + oldEquation: Equation; + newEquation: Equation; + substeps: typeof undefined[]; +} -Status.resetChangeGroups = equation => { - const leftNode = mathNode.Status.resetChangeGroups(equation.leftNode); - const rightNode = mathNode.Status.resetChangeGroups(equation.rightNode); - return new Equation(leftNode, rightNode, equation.comparator); -}; export = Status; diff --git a/lib/factor/ConstantFactors.ts b/lib/factor/ConstantFactors.ts index 89859223..c987e6ee 100644 --- a/lib/factor/ConstantFactors.ts +++ b/lib/factor/ConstantFactors.ts @@ -5,11 +5,11 @@ class constantFactors { // Given a number, will return all the prime factors of that number as a list // sorted from smallest to largest - getPrimeFactors(number:number) { + static getPrimeFactors(number:number) { let factors = []; if (number < 0) { factors = [-1]; - factors = factors.concat(ConstantFactors.getPrimeFactors(-1 * number)); + factors = factors.concat(this.getPrimeFactors(-1 * number)); return factors; } @@ -30,7 +30,7 @@ class constantFactors { // our newly found prime factor in order to find more factors else { factors.push(candidate); - factors = factors.concat(ConstantFactors.getPrimeFactors(number / candidate)); + factors = factors.concat(this.getPrimeFactors(number / candidate)); } return factors; @@ -38,7 +38,7 @@ class constantFactors { // Given a number, will return all the factor pairs for that number as a list // of 2-item lists - getFactorPairs(number:number) { + static getFactorPairs(number:number) { const factors = []; const bound = Math.floor(Math.sqrt(Math.abs(number))); diff --git a/lib/factor/factorQuadratic.ts b/lib/factor/factorQuadratic.ts index f46ea762..efc0f51e 100644 --- a/lib/factor/factorQuadratic.ts +++ b/lib/factor/factorQuadratic.ts @@ -5,7 +5,7 @@ import checks = require('../checks'); import evaluate = require('../util/evaluate'); import flatten = require('../util/flattenOperands'); import Negative = require('../Negative'); -import Node = require('../node'); +import mathNode = require('../mathNode'); const FACTOR_FUNCTIONS = [ // factor just the symbol e.g. x^2 + 2x -> x(x + 2) factorSymbol, @@ -27,21 +27,20 @@ const FACTOR_FUNCTIONS = [ // - TODO: quadratic formula // requires us simplify the following only within the parens: // a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a) -function factorQuadratic(node: any); function factorQuadratic(node) { node = flatten(node); if (!checks.isQuadratic(node)) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // get a, b and c let symbol, aValue = 0, bValue = 0, cValue = 0; for (const term of node.args) { - if (Node.Type.isConstant(term)) { + if (mathNode.Type.isConstant(term)) { cValue = evaluate(term); } - else if (Node.PolynomialTerm.isPolynomialTerm(term)) { - const polyTerm = new Node.PolynomialTerm(term); + else if (mathNode.PolynomialTerm.isPolynomialTerm(term)) { + const polyTerm = new mathNode.PolynomialTerm(term); const exponent = polyTerm.getExponentNode(true); if (exponent.value === '2') { symbol = polyTerm.getSymbolNode(); @@ -51,16 +50,16 @@ function factorQuadratic(node) { bValue = polyTerm.getCoeffValue(); } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } else { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } } if (!symbol || !aValue) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } let negate = false; @@ -78,89 +77,80 @@ function factorQuadratic(node) { } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Will factor the node if it's in the form of ax^2 + bx -function factorSymbol(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { if (!bValue || cValue) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const gcd = math.gcd(aValue, bValue); - const gcdNode = Node.Creator.constant(gcd); - const aNode = Node.Creator.constant(aValue/gcd); - const bNode = Node.Creator.constant(bValue/gcd); + const gcdNode = mathNode.Creator.constant(gcd); + const aNode = mathNode.Creator.constant(aValue/gcd); + const bNode = mathNode.Creator.constant(bValue/gcd); - const factoredNode = Node.Creator.polynomialTerm(symbol, null, gcdNode); - const polyTerm = Node.Creator.polynomialTerm(symbol, null, aNode); - const paren = Node.Creator.parenthesis( - Node.Creator.operator('+', [polyTerm, bNode])); + const factoredNode = mathNode.Creator.polynomialTerm(symbol, null, gcdNode); + const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aNode); + const paren = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', [polyTerm, bNode])); - let newNode = Node.Creator.operator('*', [factoredNode, paren], true); + let newNode = mathNode.Creator.operator('*', [factoredNode, paren], true); if (negate) { newNode = Negative.negate(newNode); } - return Node.Status.nodeChanged(ChangeTypes.FACTOR_SYMBOL, node, newNode); + return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_SYMBOL, node, newNode); } // Will factor the node if it's in the form of ax^2 - c, and the aValue // and cValue are perfect squares // e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) -function factorDifferenceOfSquares(node: any, - symbol: any, - aValue: any, - bValue?: boolean, - cValue?: any, - negate?: any); -function factorDifferenceOfSquares(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorDifferenceOfSquares(node, symbol, aValue, bValue?, cValue?, negate?) { // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, // (iii) c is negative if (bValue || !cValue) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const aRootValue = Math.sqrt(Math.abs(aValue)); const cRootValue = Math.sqrt(Math.abs(cValue)); // must be a difference of squares - if (Number.isInteger(aRootValue) && - Number.isInteger(cRootValue) && + if ((aRootValue%1 === 0) && + (cRootValue % 1 === 0) && cValue < 0) { - const aRootNode = Node.Creator.constant(aRootValue); - const cRootNode = Node.Creator.constant(cRootValue); + const aRootNode = mathNode.Creator.constant(aRootValue); + const cRootNode = mathNode.Creator.constant(cRootValue); - const polyTerm = Node.Creator.polynomialTerm(symbol, null, aRootNode); - const firstParen = Node.Creator.parenthesis( - Node.Creator.operator('+', [polyTerm, cRootNode])); - const secondParen = Node.Creator.parenthesis( - Node.Creator.operator('-', [polyTerm, cRootNode])); + const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); + const firstParen = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', [polyTerm, cRootNode])); + const secondParen = mathNode.Creator.parenthesis( + mathNode.Creator.operator('-', [polyTerm, cRootNode])); // create node in difference of squares form - let newNode = Node.Creator.operator('*', [firstParen, secondParen], true); + let newNode = mathNode.Creator.operator('*', [firstParen, secondParen], true); if (negate) { newNode = Negative.negate(newNode); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.FACTOR_DIFFERENCE_OF_SQUARES, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Will factor the node if it's in the form of ax^2 + bx + c, where a and c // are perfect squares and b = 2*sqrt(a)*sqrt(c) // e.g. x^2 + 2x + 1 -> (x + 1)^2 -function factorPerfectSquare(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) if (!bValue || !cValue) { - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } const aRootValue = Math.sqrt(Math.abs(aValue)); @@ -174,60 +164,58 @@ function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { // apply the perfect square test const perfectProduct = 2 * aRootValue * cRootValue; - if (Number.isInteger(aRootValue) && - Number.isInteger(cRootValue) && + if ((aRootValue%1 === 0) && + (cRootValue %1 === 0) && bValue === perfectProduct) { - const aRootNode = Node.Creator.constant(aRootValue); - const cRootNode = Node.Creator.constant(cRootValue); + const aRootNode = mathNode.Creator.constant(aRootValue); + const cRootNode = mathNode.Creator.constant(cRootValue); - const polyTerm = Node.Creator.polynomialTerm(symbol, null, aRootNode); - const paren = Node.Creator.parenthesis( - Node.Creator.operator('+', [polyTerm, cRootNode])); - const exponent = Node.Creator.constant(2); + const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); + const paren = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', [polyTerm, cRootNode])); + const exponent = mathNode.Creator.constant(2); // create node in perfect square form - let newNode = Node.Creator.operator('^', [paren, exponent]); + let newNode = mathNode.Creator.operator('^', [paren, exponent]); if (negate) { newNode = Negative.negate(newNode); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.FACTOR_PERFECT_SQUARE, node, newNode); } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } // Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by // applying the sum product rule: finding factors of c that add up to b. // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) -function factorSumProductRule(node: any, symbol: any, aValue: number, bValue: any, cValue: any, negate: any); -function factorSumProductRule(node: any, symbol: any, aValue: any, bValue: any, cValue: any, negate: any); function factorSumProductRule(node, symbol, aValue, bValue, cValue, negate) { if (aValue === 1 && bValue && cValue) { // try sum/product rule: find a factor pair of c that adds up to b - const factorPairs = ConstantFactors.getFactorPairs(cValue, true); + const factorPairs = ConstantFactors.getFactorPairs(cValue); for (const pair of factorPairs) { if (pair[0] + pair[1] === bValue) { - const firstParen = Node.Creator.parenthesis( - Node.Creator.operator('+', [symbol, Node.Creator.constant(pair[0])])); - const secondParen = Node.Creator.parenthesis( - Node.Creator.operator('+', [symbol, Node.Creator.constant(pair[1])])); + const firstParen = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', [symbol, mathNode.Creator.constant(pair[0])])); + const secondParen = mathNode.Creator.parenthesis( + mathNode.Creator.operator('+', [symbol, mathNode.Creator.constant(pair[1])])); // create a node in the general factored form for expression - let newNode = Node.Creator.operator('*', [firstParen, secondParen], true); + let newNode = mathNode.Creator.operator('*', [firstParen, secondParen], true); if (negate) { newNode = Negative.negate(newNode); } - return Node.Status.nodeChanged( + return mathNode.Status.nodeChanged( ChangeTypes.FACTOR_SUM_PRODUCT_RULE, node, newNode); } } } - return Node.Status.noChange(node); + return mathNode.Status.noChange(node); } export = factorQuadratic; diff --git a/lib/mathNode/Creator.ts b/lib/mathNode/Creator.ts index e7d2ca06..6fef8f0d 100644 --- a/lib/mathNode/Creator.ts +++ b/lib/mathNode/Creator.ts @@ -9,7 +9,7 @@ import NodeType = require('./Type'); const NodeCreator = { operator (op, args, implicit=false) { switch (op) { - case '+': + case '+': return new math.expression.node.OperatorNode('+', 'add', args); case '-': return new math.expression.node.OperatorNode('-', 'subtract', args); diff --git a/lib/mathNode/PolynomialTerm.ts b/lib/mathNode/PolynomialTerm.ts index dfd7c1d9..75fb4270 100644 --- a/lib/mathNode/PolynomialTerm.ts +++ b/lib/mathNode/PolynomialTerm.ts @@ -14,174 +14,176 @@ import evaluate = require('../util/evaluate'); (might be null if no exponent) */ class PolynomialTerm { - // if onlyImplicitMultiplication is true, an error will be thrown if `node` - // is a polynomial term without implicit multiplication - // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. - constructor(node, onlyImplicitMultiplication=false) { - if (NodeType.isOperator(node)) { - if (node.op === '^') { - const symbolNode = node.args[0]; - if (!NodeType.isSymbol(symbolNode)) { - throw Error('Expected symbol term, got ' + symbolNode); - } - this.symbol = symbolNode; - this.exponent = node.args[1]; - } - // it's '*' ie it has a coefficient - else if (node.op === '*') { - if (onlyImplicitMultiplication && !node.implicit) { - throw Error('Expected implicit multiplication'); - } - if (node.args.length !== 2) { - throw Error('Expected two arguments to *'); - } - const coeffNode = node.args[0]; - if (!NodeType.isConstantOrConstantFraction(coeffNode)) { - throw Error('Expected coefficient to be constant or fraction of ' + - 'constants term, got ' + coeffNode); - } - this.coeff = coeffNode; - const nonCoefficientTerm = new PolynomialTerm( - node.args[1], onlyImplicitMultiplication); - if (nonCoefficientTerm.hasCoeff()) { - throw Error('Cannot have two coefficients ' + coeffNode + - ' and ' + nonCoefficientTerm.getCoeffNode()); - } - this.symbol = nonCoefficientTerm.getSymbolNode(); - this.exponent = nonCoefficientTerm.getExponentNode(); - } - // this means there's a fraction coefficient - else if (node.op === '/') { - const denominatorNode = node.args[1]; - if (!NodeType.isConstant(denominatorNode)) { - throw Error('denominator must be constant node, instead of ' + - denominatorNode); - } - const numeratorNode = new PolynomialTerm( - node.args[0], onlyImplicitMultiplication); - if (numeratorNode.hasFractionCoeff()) { - throw Error('Polynomial terms cannot have nested fractions'); + exponent; + symbol; + coeff; + + // if onlyImplicitMultiplication is true, an error will be thrown if `node` + // is a polynomial term without implicit multiplication + // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. + constructor(node, onlyImplicitMultiplication=false) { + if (NodeType.isOperator(node)) { + if (node.op === '^') { + const symbolNode = node.args[0]; + if (!NodeType.isSymbol(symbolNode)) { + throw Error('Expected symbol term, got ' + symbolNode); + } + this.symbol = symbolNode; + this.exponent = node.args[1]; + } + // it's '*' ie it has a coefficient + else if (node.op === '*') { + if (onlyImplicitMultiplication && !node.implicit) { + throw Error('Expected implicit multiplication'); + } + if (node.args.length !== 2) { + throw Error('Expected two arguments to *'); + } + const coeffNode = node.args[0]; + if (!NodeType.isConstantOrConstantFraction(coeffNode)) { + throw Error('Expected coefficient to be constant or fraction of ' + + 'constants term, got ' + + coeffNode); + } + this.coeff = coeffNode; + const nonCoefficientTerm = new PolynomialTerm( + node.args[1], + onlyImplicitMultiplication); + if (nonCoefficientTerm.hasCoeff()) { + throw Error('Cannot have two coefficients ' + + coeffNode + + ' and ' + + nonCoefficientTerm.getCoeffNode()); + } + this.symbol = nonCoefficientTerm.getSymbolNode(); + this.exponent = nonCoefficientTerm.getExponentNode(); + } + // this means there's a fraction coefficient + else if (node.op === '/') { + const denominatorNode = node.args[1]; + if (!NodeType.isConstant(denominatorNode)) { + throw Error('denominator must be constant node, instead of ' + + denominatorNode); + } + const numeratorNode = new PolynomialTerm( + node.args[0], + onlyImplicitMultiplication); + if (numeratorNode.hasFractionCoeff()) { + throw Error('Polynomial terms cannot have nested fractions'); + } + this.exponent = numeratorNode.getExponentNode(); + this.symbol = numeratorNode.getSymbolNode(); + const numeratorConstantNode = numeratorNode.getCoeffNode(true); + this.coeff = NodeCreator.operator( + '/', + [numeratorConstantNode, denominatorNode]); + } else { + throw Error('Unsupported operatation for polynomial node: ' + node.op); + } + } else if (NodeType.isUnaryMinus(node)) { + var arg = node.args[0]; + if (NodeType.isParenthesis(arg)) { + arg = arg.content; + } + const polyNode = new PolynomialTerm( + arg, + onlyImplicitMultiplication); + this.exponent = polyNode.getExponentNode(); + this.symbol = polyNode.getSymbolNode(); + if (!polyNode.hasCoeff()) { + this.coeff = NodeCreator.constant(-1); + } else { + this.coeff = this.negativeCoefficient(polyNode.getCoeffNode()); + } + } else if (NodeType.isSymbol(node)) { + this.symbol = node; + } else { + throw Error('Unsupported node type: ' + node.type); } - this.exponent = numeratorNode.getExponentNode(); - this.symbol = numeratorNode.getSymbolNode(); - const numeratorConstantNode = numeratorNode.getCoeffNode(true); - this.coeff = NodeCreator.operator( - '/', [numeratorConstantNode, denominatorNode]); - } - else { - throw Error('Unsupported operatation for polynomial node: ' + node.op); - } - } - else if (NodeType.isUnaryMinus(node)) { - var arg = node.args[0]; - if (NodeType.isParenthesis(arg)) { - arg = arg.content; - } - const polyNode = new PolynomialTerm( - arg, onlyImplicitMultiplication); - this.exponent = polyNode.getExponentNode(); - this.symbol = polyNode.getSymbolNode(); - if (!polyNode.hasCoeff()) { - this.coeff = NodeCreator.constant(-1); - } - else { - this.coeff = negativeCoefficient(polyNode.getCoeffNode()); - } - } - else if (NodeType.isSymbol(node)) { - this.symbol = node; - } - else { - throw Error('Unsupported node type: ' + node.type); } - } - /* GETTER FUNCTIONS */ - getSymbolNode() { - return this.symbol; - } + /* GETTER FUNCTIONS */ + getSymbolNode() { + return this.symbol; + } - getSymbolName() { - return this.symbol.name; - } + getSymbolName() { + return this.symbol.name; + } - getCoeffNode(defaultOne=false) { - if (!this.coeff && defaultOne) { - return NodeCreator.constant(1); + getCoeffNode(defaultOne=false) { + if (!this.coeff && defaultOne) { + return NodeCreator.constant(1); + } else { + return this.coeff; + } } - else { - return this.coeff; + + getCoeffValue() { + if (this.coeff) { + return evaluate(this.coeff); + } else { + return 1; // no coefficient is like a coeff of 1 + } } - } - getCoeffValue() { - if (this.coeff) { - return evaluate(this.coeff); + getExponentNode(defaultOne=false) { + if (!this.exponent && defaultOne) { + return NodeCreator.constant(1); + } else { + return this.exponent; + } } - else { - return 1; // no coefficient is like a coeff of 1 + + getRootNode() { + return NodeCreator.polynomialTerm( + this.symbol, + this.exponent, + this.coeff); } - } - getExponentNode(defaultOne=false) { - if (!this.exponent && defaultOne) { - return NodeCreator.constant(1); + // note: there is no exponent value getter function because the exponent + // can be any expresion and not necessarily a number. + + /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ + + // Returns true if the coefficient is a fraction + hasFractionCoeff() { + // coeffNode is either a constant or a division operation. + return this.coeff && NodeType.isOperator(this.coeff); } - else { - return this.exponent; + + hasCoeff() { + return !!this.coeff; } - } - - getRootNode() { - return NodeCreator.polynomialTerm( - this.symbol, this.exponent, this.coeff); - } - - // note: there is no exponent value getter function because the exponent - // can be any expresion and not necessarily a number. - - /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ - - // Returns true if the coefficient is a fraction - hasFractionCoeff() { - // coeffNode is either a constant or a division operation. - return this.coeff && NodeType.isOperator(this.coeff); - } - - hasCoeff() { - return !!this.coeff; - } - - // Returns if the node represents an expression that can be considered a term. - // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. - // See the tests for some more thorough examples of exactly what counts and - // what does not. - isPolynomialTerm = (node, onlyImplicitMultiplication = false) => { - try { - // will throw error if node isn't poly term - new PolynomialTerm(node, onlyImplicitMultiplication); - return true; - } - catch (err) { - return false; - } - }; + + // Returns if the node represents an expression that can be considered a term. + // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. + // See the tests for some more thorough examples of exactly what counts and + // what does not. + isPolynomialTerm = (node, onlyImplicitMultiplication = false) => { + try { + // will throw error if node isn't poly term + new PolynomialTerm(node, onlyImplicitMultiplication); + return true; + } catch (err) { + return false; + } + }; + // Multiplies `node`, a constant or fraction of two constant nodes, by -1 // Returns a node -function negativeCoefficient(node) { - if (NodeType.isConstant(node)) { - node = NodeCreator.constant(0 - parseFloat(node.value)); - } - else { - const numeratorValue = 0 - parseFloat(node.args[0].value); - node.args[0] = NodeCreator.constant(numeratorValue); + function + + negativeCoefficient(node) { + if (NodeType.isConstant(node)) { + node = NodeCreator.constant(0 - parseFloat(node.value)); + } else { + const numeratorValue = 0 - parseFloat(node.args[0].value); + node.args[0] = NodeCreator.constant(numeratorValue); + } + return node; } - return node; -} - exponent; - symbol; - coeff; } - export = PolynomialTerm; diff --git a/lib/mathNode/Status.ts b/lib/mathNode/Status.ts index 94ffec50..19123696 100644 --- a/lib/mathNode/Status.ts +++ b/lib/mathNode/Status.ts @@ -25,7 +25,7 @@ class Status { hasChanged() { return this.changeType !== ChangeTypes.NO_CHANGE; } - resetChangeGroups(node) { + static resetChangeGroups(node) { node = clone(node); node.filter(node => node.changeGroup).forEach(change => { delete change.changeGroup; diff --git a/lib/mathNode/Type.ts b/lib/mathNode/Type.ts index 0de6673e..97ec86aa 100644 --- a/lib/mathNode/Type.ts +++ b/lib/mathNode/Type.ts @@ -24,7 +24,7 @@ class NodeType { } return true; }; - isSymbol(node, allowUnaryMinus = true) { + static isSymbol(node, allowUnaryMinus = true) { if (node.type === 'SymbolNode') { return true; } @@ -60,7 +60,7 @@ class NodeType { return false; } }; - isConstantOrConstantFraction(node, allowUnaryMinus = false) { + static isConstantOrConstantFraction(node, allowUnaryMinus = false) { if (NodeType.isConstant(node, allowUnaryMinus) || NodeType.isConstantFraction(node, allowUnaryMinus)) { return true; diff --git a/lib/simplifyExpression/arithmeticSearch/index.js b/lib/simplifyExpression/arithmeticSearch/index.js new file mode 100644 index 00000000..d11ddc90 --- /dev/null +++ b/lib/simplifyExpression/arithmeticSearch/index.js @@ -0,0 +1,56 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var evaluate = require("../../util/evaluate"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +// Searches through the tree, prioritizing deeper nodes, and evaluates +// arithmetic (e.g. 2+2 or 3*5*2) on an operation node if possible. +// Returns a mathNode.Status object. +var search = TreeSearch.postOrder(arithmetic); +// evaluates arithmetic (e.g. 2+2 or 3*5*2) on an operation node. +// Returns a mathNode.Status object. +function arithmetic(node) { + if (!mathNode.Type.isOperator(node)) { + return mathNode.Status.noChange(node); + } + if (!node.args.every(function (child) { return mathNode.Type.isConstant(child, true); })) { + return mathNode.Status.noChange(node); + } + // we want to eval each arg so unary minuses around constant nodes become + // constant nodes with negative values + node.args.forEach(function (arg, i) { + node.args[i] = mathNode.Creator.constant(evaluate(arg)); + }); + // Only resolve division of integers if we get an integer result. + // Note that a fraction of decimals will be divided out. + if (mathNode.Type.isIntegerFraction(node)) { + var numeratorValue = parseInt(node.args[0]); + var denominatorValue = parseInt(node.args[1]); + if (numeratorValue % denominatorValue === 0) { + var newNode = mathNode.Creator.constant(numeratorValue / denominatorValue); + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } + } + else { + var evaluatedValue = evaluateAndRound(node); + var newNode = mathNode.Creator.constant(evaluatedValue); + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); + } +} +// Evaluates a math expression to a constant, e.g. 3+4 -> 7 and rounds if +// necessary +function evaluateAndRound(node) { + var result = evaluate(node); + if (result < 1) { + result = parseFloat(result.toPrecision(4)); + } + else { + result = parseFloat(result.toFixed(4)); + } + return result; +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/arithmeticSearch/index.js.map b/lib/simplifyExpression/arithmeticSearch/index.js.map new file mode 100644 index 00000000..aecc8952 --- /dev/null +++ b/lib/simplifyExpression/arithmeticSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,8CAAiD;AACjD,yCAA4C;AAC5C,6CAAgD;AAEhD,sEAAsE;AACtE,mEAAmE;AACnE,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAEhD,iEAAiE;AACjE,oCAAoC;AACpC,oBAAoB,IAAI;IACtB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAA,KAAK,IAAI,OAAA,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,EAArC,CAAqC,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,yEAAyE;IACzE,sCAAsC;IACtC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,iEAAiE;IACjE,wDAAwD;IACxD,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAM,gBAAgB,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,EAAE,CAAC,CAAC,cAAc,GAAG,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5C,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,GAAC,gBAAgB,CAAC,CAAC;YAC3E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,IAAM,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,YAAY;AACZ,0BAA0B,IAAI;IAC5B,IAAI,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,GAAI,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,GAAI,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,CAAC,MAAM,CAAC;AAChB,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/arithmeticSearch/index.ts b/lib/simplifyExpression/arithmeticSearch/index.ts index d6ee12ee..76990d57 100644 --- a/lib/simplifyExpression/arithmeticSearch/index.ts +++ b/lib/simplifyExpression/arithmeticSearch/index.ts @@ -1,6 +1,6 @@ import ChangeTypes = require('../../ChangeTypes'); import evaluate = require('../../util/evaluate'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); // Searches through the tree, prioritizing deeper nodes, and evaluates @@ -10,7 +10,6 @@ const search = TreeSearch.postOrder(arithmetic); // evaluates arithmetic (e.g. 2+2 or 3*5*2) on an operation node. // Returns a mathNode.Status object. -function arithmetic(node: any); function arithmetic(node) { if (!mathNode.Type.isOperator(node)) { return mathNode.Status.noChange(node); @@ -48,7 +47,6 @@ function arithmetic(node) { // Evaluates a math expression to a constant, e.g. 3+4 -> 7 and rounds if // necessary -function evaluateAndRound(node: any); function evaluateAndRound(node) { let result = evaluate(node); if (result < 1) { diff --git a/lib/simplifyExpression/basicsSearch/index.ts b/lib/simplifyExpression/basicsSearch/index.ts index 86f94ba3..66b86318 100644 --- a/lib/simplifyExpression/basicsSearch/index.ts +++ b/lib/simplifyExpression/basicsSearch/index.ts @@ -3,7 +3,7 @@ * These are always the first simplifications that are attempted. */ -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); import rearrangeCoefficient = require('./rearrangeCoefficient'); import reduceExponentByZero = require('./reduceExponentByZero'); diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts index 5d1d9b18..59d4b067 100644 --- a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts +++ b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts @@ -1,7 +1,7 @@ import checks = require('../../checks'); import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Rearranges something of the form x * 5 to be 5x, ie putting the coefficient // in the right place. diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts index b8e4025f..96393cf2 100644 --- a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts +++ b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts @@ -1,5 +1,5 @@ import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is an exponent of something to 0, we can reduce that to just 1. // Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts index 76494c1f..7925ec30 100644 --- a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts +++ b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts @@ -1,5 +1,5 @@ import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is a multiplication node with 0 as one of its operands, // reduce the node to 0. Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts index e56f546d..f79a04b5 100644 --- a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts +++ b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts @@ -1,5 +1,5 @@ import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is a fraction with 0 as the numerator, reduce the node to 0. // Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts index 6ecb2957..82b7d892 100644 --- a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts +++ b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts @@ -1,6 +1,6 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is an addition node with 0 as one of its operands, // remove 0 from the operands list. Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts index 3be1b1d8..e3770dd8 100644 --- a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts @@ -1,7 +1,7 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); import Negative = require('../../Negative'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is a division operation of something by 1 or -1, we can remove the // denominator. Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts index 1d998d73..6ec4cc80 100644 --- a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts @@ -1,7 +1,7 @@ import checks = require('../../checks'); import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is of the form 1^x, reduces it to a node of the form 1. // Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts index a10ff3fb..40ebebcb 100644 --- a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts @@ -1,6 +1,6 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is of the form x^1, reduces it to a node of the form x. // Returns a mathNode.Status object. diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts index 79d01ac5..89d6f5f2 100644 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts @@ -1,7 +1,7 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); import Negative = require('../../Negative'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is a multiplication node with -1 as one of its operands, // and a non constant as the next operand, remove -1 from the operands diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts index e04b7401..a409d8f9 100644 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts @@ -1,10 +1,9 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // If `node` is a multiplication node with 1 as one of its operands, // remove 1 from the operands list. Returns a mathNode.Status object. -function removeMultiplicationByOne(node: any); function removeMultiplicationByOne(node) { if (node.op !== '*') { return mathNode.Status.noChange(node); diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts index ac02104c..6422c8b9 100644 --- a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts +++ b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts @@ -1,6 +1,6 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Simplifies two unary minuses in a row by removing both of them. // e.g. -(- 4) --> 4 diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.ts b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts index 7b2ff84f..843183d3 100644 --- a/lib/simplifyExpression/breakUpNumeratorSearch/index.ts +++ b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts @@ -1,5 +1,5 @@ import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); // Breaks up any fraction (deeper nodes getting priority) that has a numerator diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts index 5f7b9575..f11f204d 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts @@ -1,17 +1,17 @@ import clone = require('../../util/clone'); import print = require('../../util/print'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import Util = require('../../util/Util'); const CONSTANT = 'constant'; const CONSTANT_FRACTION = 'constantFraction'; const OTHER = 'other'; -const LikeTermCollector = {}; +class LikeTermCollector{ // Given an expression tree, returns true if there are terms that can be // collected -LikeTermCollector.canCollectLikeTerms = node => { + static canCollectLikeTerms = node => { // We can collect like terms through + or through * // Note that we never collect like terms with - or /, those expressions will // always be manipulated in flattenOperands so that the top level operation is @@ -43,13 +43,13 @@ LikeTermCollector.canCollectLikeTerms = node => { }; // Collects like terms for an operation node and returns a mathNode.Status object. -LikeTermCollector.collectLikeTerms = node => { +collectLikeTerms = node => { if (!LikeTermCollector.canCollectLikeTerms(node)) { return mathNode.Status.noChange(node); } const op = node.op; - let terms = []; + let terms: {}; if (op === '+') { terms = getTermsForCollectingAddition(node); } @@ -114,12 +114,10 @@ LikeTermCollector.collectLikeTerms = node => { return mathNode.Status.nodeChanged( ChangeTypes.COLLECT_LIKE_TERMS, node, newNode, false); }; - +} // Polyonomial terms are collected by categorizing them by their 'name' // which is used to separate them into groups that can be combined. getTermName // returns this group 'name' -function getTermName(node: any, op: "+"); -function getTermName(node: any, op: any); function getTermName(node, op) { const polyNode = new mathNode.PolynomialTerm(node); // we 'name' polynomial terms by their symbol name @@ -136,7 +134,6 @@ function getTermName(node, op) { // Returns a dictionary of termname to lists of nodes with that name // e.g. 2x + 4 + 5x would return {'x': [2x, 5x], CONSTANT: [4]} // (where 2x, 5x, and 4 would actually be expression trees) -function getTermsForCollectingAddition(node: any); function getTermsForCollectingAddition(node) { let terms = {}; @@ -251,7 +248,6 @@ function addToTermsforPolynomialMultiplication(terms, node) { } // Sort function for termnames. Sort first by symbol name, and then by exponent. -function sortTerms(a: any, b: any); function sortTerms(a, b) { if (a === b) { return 0; diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js new file mode 100644 index 00000000..e4c18663 --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js @@ -0,0 +1,126 @@ +"use strict"; +var checks = require("../../checks"); +var clone = require("../../util/clone"); +var evaluateConstantSum = require("./evaluateConstantSum"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// Adds a list of nodes that are polynomial terms. Returns a mathNode.Status object. +function addLikeTerms(node, polynomialOnly) { + if (polynomialOnly === void 0) { polynomialOnly = false; } + if (!mathNode.Type.isOperator(node)) { + return mathNode.Status.noChange(node); + } + var status; + if (!polynomialOnly) { + status = evaluateConstantSum(node); + if (status.hasChanged()) { + return status; + } + } + status = addLikePolynomialTerms(node); + if (status.hasChanged()) { + return status; + } + return mathNode.Status.noChange(node); +} +function addLikePolynomialTerms(node) { + if (!checks.canAddLikeTermPolynomialNodes(node)) { + return mathNode.Status.noChange(node); + } + var substeps = []; + var newNode = clone(node); + // STEP 1: If any nodes have no coefficient, make it have coefficient 1 + // (this step only happens under certain conditions and later steps might + // happen even if step 1 does not) + var status = addPositiveOneCoefficient(newNode); + if (status.hasChanged()) { + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + } + // STEP 2: If any nodes have a unary minus, make it have coefficient -1 + // (this step only happens under certain conditions and later steps might + // happen even if step 2 does not) + status = addNegativeOneCoefficient(newNode); + if (status.hasChanged()) { + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + } + // STEP 3: group the coefficients in a sum + status = groupCoefficientsForAdding(newNode); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + // STEP 4: evaluate the sum (could include fractions) + status = evaluateCoefficientSum(newNode); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + return mathNode.Status.nodeChanged(ChangeTypes.ADD_POLYNOMIAL_TERMS, node, newNode, true, substeps); +} +function addPositiveOneCoefficient(node) { + var newNode = clone(node); + var change = false; + var changeGroup = 1; + newNode.args.forEach(function (child, i) { + var polyTerm = new mathNode.PolynomialTerm(child); + if (polyTerm.getCoeffValue() === 1) { + newNode.args[i] = mathNode.Creator.polynomialTerm(polyTerm.getSymbolNode(), polyTerm.getExponentNode(), mathNode.Creator.constant(1), true /* explicit coefficient */); + newNode.args[i].changeGroup = changeGroup; + node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" + change = true; + changeGroup++; + } + }); + if (change) { + return mathNode.Status.nodeChanged(ChangeTypes.ADD_COEFFICIENT_OF_ONE, node, newNode, false); + } + else { + return mathNode.Status.noChange(node); + } +} +function addNegativeOneCoefficient(node) { + var newNode = clone(node); + var change = false; + var changeGroup = 1; + newNode.args.forEach(function (child, i) { + var polyTerm = new mathNode.PolynomialTerm(child); + if (polyTerm.getCoeffValue() === -1) { + newNode.args[i] = mathNode.Creator.polynomialTerm(polyTerm.getSymbolNode(), polyTerm.getExponentNode(), polyTerm.getCoeffNode(), true /* explicit -1 coefficient */); + node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" + newNode.args[i].changeGroup = changeGroup; + change = true; + changeGroup++; + } + }); + if (change) { + return mathNode.Status.nodeChanged(ChangeTypes.UNARY_MINUS_TO_NEGATIVE_ONE, node, newNode, false); + } + else { + return mathNode.Status.noChange(node); + } +} +function groupCoefficientsForAdding(node) { + var newNode = clone(node); + var polynomialTermList = newNode.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); + var coefficientList = polynomialTermList.map(function (p) { return p.getCoeffNode(true); }); + var sumOfCoefficents = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', coefficientList)); + // TODO: changegroups should also be on the before node, on all the + // coefficients, but changegroups with polyTerm gets messy so let's tackle + // that later. + sumOfCoefficents.changeGroup = 1; + // Polynomial terms that can be added together must share the same symbol + // name and exponent. Get that name and exponent from the first term + var firstTerm = polynomialTermList[0]; + var exponentNode = firstTerm.getExponentNode(); + var symbolNode = firstTerm.getSymbolNode(); + newNode = mathNode.Creator.polynomialTerm(symbolNode, exponentNode, sumOfCoefficents); + return mathNode.Status.nodeChanged(ChangeTypes.GROUP_COEFFICIENTS, node, newNode); +} +function evaluateCoefficientSum(node) { + // the node is now always a * node with the left child the coefficent sum + // e.g. (2 + 4 + 5) and the right node the symbol part e.g. x or y^2 + // so we want to evaluate args[0] + var coefficientSum = clone(node).args[0]; + var childStatus = evaluateConstantSum(coefficientSum); + return mathNode.Status.childChanged(node, childStatus, 0); +} +module.exports = addLikeTerms; +//# sourceMappingURL=addLikeTerms.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map new file mode 100644 index 00000000..b1b0f3e8 --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map @@ -0,0 +1 @@ +{"version":3,"file":"addLikeTerms.js","sourceRoot":"","sources":["addLikeTerms.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts index b82c4ea3..9d72b8c1 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts @@ -2,7 +2,7 @@ import checks = require('../../checks'); import clone = require('../../util/clone'); import evaluateConstantSum = require('./evaluateConstantSum'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Adds a list of nodes that are polynomial terms. Returns a mathNode.Status object. function addLikeTerms(node, polynomialOnly=false) { @@ -75,7 +75,7 @@ function addLikePolynomialTerms(node) { // Returns a mathNode.Status object. function addPositiveOneCoefficient(node: any); function addPositiveOneCoefficient(node) { - const newNode = clone(node, false); + const newNode = clone(node); let change = false; let changeGroup = 1; diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js new file mode 100644 index 00000000..707681b7 --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js @@ -0,0 +1,106 @@ +"use strict"; +var addConstantAndFraction = require("../fractionsSearch/addConstantAndFraction"); +var addConstantFractions = require("../fractionsSearch/addConstantFractions"); +var arithmeticSearch = require("../arithmeticSearch"); +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +function evaluateConstantSum(node) { + if (mathNode.Type.isParenthesis(node)) { + node = node.content; + } + if (!mathNode.Type.isOperator(node) || node.op !== '+') { + return mathNode.Status.noChange(node); + } + if (node.args.some(function (node) { return !mathNode.Type.isConstantOrConstantFraction(node); })) { + return mathNode.Status.noChange(node); + } + // functions needed to evaluate the sum + var summingFunctions = [ + arithmeticSearch, + addConstantFractions, + addConstantAndFraction, + ]; + for (var i = 0; i < summingFunctions.length; i++) { + var status_1 = summingFunctions[i](node); + if (status_1.hasChanged()) { + if (mathNode.Type.isConstantOrConstantFraction(status_1.newNode)) { + return status_1; + } + } + } + var newNode = clone(node); + var substeps = []; + var status; + // STEP 1: group fractions and constants separately + status = groupConstantsAndFractions(newNode); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + var constants = newNode.args[0]; + var fractions = newNode.args[1]; + // STEP 2A: evaluate arithmetic IF there's > 1 constant + // (which is the case if it's a list surrounded by parenthesis) + if (mathNode.Type.isParenthesis(constants)) { + var constantList = constants.content; + var evaluateStatus = arithmeticSearch(constantList); + status = mathNode.Status.childChanged(newNode, evaluateStatus, 0); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + } + // STEP 2B: add fractions IF there's > 1 fraction + // (which is the case if it's a list surrounded by parenthesis) + if (mathNode.Type.isParenthesis(fractions)) { + var fractionList = fractions.content; + var evaluateStatus = addConstantFractions(fractionList); + status = mathNode.Status.childChanged(newNode, evaluateStatus, 1); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + } + // STEP 3: combine the evaluated constant and fraction + // the fraction might have simplified to a constant (e.g. 1/3 + 2/3 -> 2) + // so we just call evaluateConstantSum again to cycle through + status = evaluateConstantSum(newNode); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); +} +function groupConstantsAndFractions(node) { + var fractions = node.args.filter(mathNode.Type.isIntegerFraction); + var constants = node.args.filter(mathNode.Type.isConstant); + if (fractions.length === 0 || constants.length === 0) { + throw Error('expected both integer fractions and constants, got ' + node); + } + if (fractions.length + constants.length !== node.args.length) { + throw Error('can only evaluate integer fractions and constants'); + } + constants = constants.map(function (node) { + // set the changeGroup - this affects both the old and new node + node.changeGroup = 1; + // clone so that node and newNode aren't stored in the same memory + return clone(node); + }); + // wrap in parenthesis if there's more than one, to group them + if (constants.length > 1) { + constants = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', constants)); + } + else { + constants = constants[0]; + } + fractions = fractions.map(function (node) { + // set the changeGroup - this affects both the old and new node + node.changeGroup = 2; + // clone so that node and newNode aren't stored in the same memory + return clone(node); + }); + // wrap in parenthesis if there's more than one, to group them + if (fractions.length > 1) { + fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', fractions)); + } + else { + fractions = fractions[0]; + } + var newNode = mathNode.Creator.operator('+', [constants, fractions]); + return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_LIKE_TERMS, node, newNode); +} +module.exports = evaluateConstantSum; +//# sourceMappingURL=evaluateConstantSum.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map new file mode 100644 index 00000000..d00eda76 --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map @@ -0,0 +1 @@ +{"version":3,"file":"evaluateConstantSum.js","sourceRoot":"","sources":["evaluateConstantSum.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts index 0e37b99d..fe06263e 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts @@ -3,7 +3,7 @@ import addConstantFractions = require('../fractionsSearch/addConstantFractions') import arithmeticSearch = require('../arithmeticSearch'); import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Evaluates a sum of constant numbers and integer fractions to a single // constant number or integer fraction. e.g. e.g. 2/3 + 5 + 5/2 => 49/6 diff --git a/lib/simplifyExpression/collectAndCombineSearch/index.ts b/lib/simplifyExpression/collectAndCombineSearch/index.ts index 755ddfd9..78482c15 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/index.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/index.ts @@ -5,7 +5,7 @@ import clone = require('../../util/clone'); import multiplyLikeTerms = require('./multiplyLikeTerms'); import ChangeTypes = require('../../ChangeTypes'); import LikeTermCollector = require('./LikeTermCollector'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); const termCollectorFunctions = { '+': addLikeTerms, @@ -19,7 +19,6 @@ const search = TreeSearch.postOrder(collectAndCombineLikeTerms); // Given an operator node, maybe collects and then combines if possible // e.g. 2x + 4x + y => 6x + y // e.g. 2x * x^2 * 5x => 10 x^4 -function collectAndCombineLikeTerms(node: any); function collectAndCombineLikeTerms(node) { if (node.op === '+') { const status = collectAndCombineOperation(node); @@ -81,7 +80,6 @@ function collectAndCombineOperation(node) { // combine like terms for each group that can be combined // e.g. (x + 3x) + (2 + 2) has two groups // returns a list of combine steps -function combineLikeTerms(node: any); function combineLikeTerms(node) { const steps = []; let newNode = clone(node); diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js new file mode 100644 index 00000000..901d2565 --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js @@ -0,0 +1,109 @@ +"use strict"; +var arithmeticSearch = require("../arithmeticSearch"); +var checks = require("../../checks"); +var clone = require("../../util/clone"); +var multiplyFractionsSearch = require("../multiplyFractionsSearch"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// Multiplies a list of nodes that are polynomial like terms. Returns a node. +// The polynomial nodes should *not* have coefficients. (multiplying +// coefficients is handled in collecting like terms for multiplication) +function multiplyLikeTerms(node, polynomialOnly) { + if (polynomialOnly === void 0) { polynomialOnly = false; } + if (!mathNode.Type.isOperator(node)) { + return mathNode.Status.noChange(node); + } + var status; + if (!polynomialOnly) { + status = arithmeticSearch(node); + if (status.hasChanged()) { + status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; + return status; + } + status = multiplyFractionsSearch(node); + if (status.hasChanged()) { + status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; + return status; + } + } + status = multiplyPolynomialTerms(node); + if (status.hasChanged()) { + status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; + return status; + } + return mathNode.Status.noChange(node); +} +function multiplyPolynomialTerms(node) { + if (!checks.canMultiplyLikeTermPolynomialNodes(node)) { + return mathNode.Status.noChange(node); + } + var substeps = []; + var newNode = clone(node); + // STEP 1: If any term has no exponent, make it have exponent 1 + // e.g. x -> x^1 (this is for pedagogy reasons) + // (this step only happens under certain conditions and later steps might + // happen even if step 1 does not) + var status = addOneExponent(newNode); + if (status.hasChanged()) { + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + } + // STEP 2: collect exponents to a single exponent sum + // e.g. x^1 * x^3 -> x^(1+3) + status = collectExponents(newNode); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + // STEP 3: add exponents together. + // NOTE: This might not be a step if the exponents aren't all constants, + // but this case isn't that common and can be caught in other steps. + // e.g. x^(2+4+z) + // TODO: handle fractions, combining and collecting like terms, etc, here + var exponentSum = newNode.args[1].content; + var sumStatus = arithmeticSearch(exponentSum); + if (sumStatus.hasChanged()) { + status = mathNode.Status.childChanged(newNode, sumStatus, 1); + substeps.push(status); + newNode = mathNode.Status.resetChangeGroups(status.newNode); + } + if (substeps.length === 1) { + return substeps[0]; + } + else { + return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_POLYNOMIAL_TERMS, node, newNode, true, substeps); + } +} +function addOneExponent(node) { + var newNode = clone(node); + var change = false; + var changeGroup = 1; + newNode.args.forEach(function (child, i) { + var polyTerm = new mathNode.PolynomialTerm(child); + if (!polyTerm.getExponentNode()) { + newNode.args[i] = mathNode.Creator.polynomialTerm(polyTerm.getSymbolNode(), mathNode.Creator.constant(1), polyTerm.getCoeffNode()); + newNode.args[i].changeGroup = changeGroup; + node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" + change = true; + changeGroup++; + } + }); + if (change) { + return mathNode.Status.nodeChanged(ChangeTypes.ADD_EXPONENT_OF_ONE, node, newNode, false); + } + else { + return mathNode.Status.noChange(node); + } +} +function collectExponents(node) { + var polynomialTermList = node.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); + // If we're multiplying polynomial nodes together, they all share the same + // symbol. Get that from the first node. + var symbolNode = polynomialTermList[0].getSymbolNode(); + // The new exponent will be a sum of exponents (an operation, wrapped in + // parens) e.g. x^(3+4+5) + var exponentNodeList = polynomialTermList.map(function (p) { return p.getExponentNode(true); }); + var newExponent = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', exponentNodeList)); + var newNode = mathNode.Creator.polynomialTerm(symbolNode, newExponent, null); + return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_EXPONENTS, node, newNode); +} +module.exports = multiplyLikeTerms; +//# sourceMappingURL=multiplyLikeTerms.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map new file mode 100644 index 00000000..1f98974b --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map @@ -0,0 +1 @@ +{"version":3,"file":"multiplyLikeTerms.js","sourceRoot":"","sources":["multiplyLikeTerms.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts index e131aa62..9ed2fae9 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts @@ -3,7 +3,7 @@ import checks = require('../../checks'); import clone = require('../../util/clone'); import multiplyFractionsSearch = require('../multiplyFractionsSearch'); import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Multiplies a list of nodes that are polynomial like terms. Returns a node. // The polynomial nodes should *not* have coefficients. (multiplying diff --git a/lib/simplifyExpression/distributeSearch/index.js b/lib/simplifyExpression/distributeSearch/index.js new file mode 100644 index 00000000..15faf915 --- /dev/null +++ b/lib/simplifyExpression/distributeSearch/index.js @@ -0,0 +1,231 @@ +"use strict"; +var arithmeticSearch = require("../arithmeticSearch"); +var clone = require("../../util/clone"); +var collectAndCombineSearch = require("../collectAndCombineSearch"); +var rearrangeCoefficient = require("../basicsSearch/rearrangeCoefficient"); +var ChangeTypes = require("../../ChangeTypes"); +var Negative = require("../../Negative"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +var search = TreeSearch.postOrder(distribute); +function distribute(node) { + if (mathNode.Type.isUnaryMinus(node)) { + return distributeUnaryMinus(node); + } + else if (mathNode.Type.isOperator(node)) { + return distributeAndSimplifyOperationNode(node); + } + else { + return mathNode.Status.noChange(node); + } +} +function distributeUnaryMinus(node) { + if (!mathNode.Type.isUnaryMinus(node)) { + return mathNode.Status.noChange(node); + } + var unaryContent = node.args[0]; + if (!mathNode.Type.isParenthesis(unaryContent)) { + return mathNode.Status.noChange(node); + } + var content = unaryContent.content; + if (!mathNode.Type.isOperator(content)) { + return mathNode.Status.noChange(node); + } + var newContent = clone(content); + node.changeGroup = 1; + // For multiplication and division, we can push the unary minus in to + // the first argument. + // e.g. -(2/3) -> (-2/3) -(4*9*x^2) --> (-4 * 9 * x^2) + if (content.op === '*' || content.op === '/') { + newContent.args[0] = Negative.negate(newContent.args[0]); + newContent.args[0].changeGroup = 1; + var newNode = mathNode.Creator.parenthesis(newContent); + return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); + } + else if (content.op === '+') { + // Now we know `node` is of the form -(x + y + ...). + // We want to now return (-x + -y + ....) + // If any term is negative, we make it positive it right away + // e.g. -(2-4) => -2 + 4 + var newArgs = newContent.args.map(function (arg) { + var newArg = Negative.negate(arg); + newArg.changeGroup = 1; + return newArg; + }); + newContent.args = newArgs; + var newNode = mathNode.Creator.parenthesis(newContent); + return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); + } + else { + return mathNode.Status.noChange(node); + } +} +function distributeAndSimplifyOperationNode(node) { + if (!mathNode.Type.isOperator(node) || node.op !== '*') { + return mathNode.Status.noChange(node); + } + // STEP 1: distribute with `distributeTwoNodes` + // e.g. x*(2+x) -> x*2 + x*x + // STEP 2: simplifications of each operand in the new sum with `simplify` + // e.g. x*2 + x*x -> ... -> 2x + x^2 + for (var i = 0; i + 1 < node.args.length; i++) { + if (!isParenthesisOfAddition(node.args[i]) && + !isParenthesisOfAddition(node.args[i + 1])) { + continue; + } + var newNode = clone(node); + var substeps = []; + var status_1 = void 0; + var combinedNode = distributeTwoNodes(newNode.args[i], newNode.args[i + 1]); + node.args[i].changeGroup = 1; + node.args[i + 1].changeGroup = 1; + combinedNode.changeGroup = 1; + if (newNode.args.length > 2) { + newNode.args.splice(i, 2, combinedNode); + newNode.args[i].changeGroup = 1; + } + else { + newNode = combinedNode; + newNode.changeGroup = 1; + } + status_1 = mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE, node, newNode, false); + substeps.push(status_1); + newNode = mathNode.Status.resetChangeGroups(status_1.newNode); + // case 1: there were more than two operands in this multiplication + // e.g. 3*7*(2+x)*(3+x)*(4+x) is a multiplication node with 5 children + // and the new node will be 3*(14+7x)*(3+x)*(4+x) with 4 children. + if (mathNode.Type.isOperator(newNode, '*')) { + var childStatus = simplifyWithParens(newNode.args[i]); + if (childStatus.hasChanged()) { + status_1 = mathNode.Status.childChanged(newNode, childStatus, i); + substeps.push(status_1); + newNode = mathNode.Status.resetChangeGroups(status_1.newNode); + } + } + else if (mathNode.Type.isParenthesis(newNode)) { + status_1 = simplifyWithParens(newNode); + if (status_1.hasChanged()) { + substeps.push(status_1); + newNode = mathNode.Status.resetChangeGroups(status_1.newNode); + } + } + else { + throw Error('Unsupported node type for distribution: ' + node); + } + if (substeps.length === 1) { + return substeps[0]; + } + return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE, node, newNode, false, substeps); + } + return mathNode.Status.noChange(node); +} +function distributeTwoNodes(firstNode, secondNode) { + // lists of terms we'll be multiplying together from each node + var firstArgs, secondArgs; + if (isParenthesisOfAddition(firstNode)) { + firstArgs = firstNode.content.args; + } + else { + firstArgs = [firstNode]; + } + if (isParenthesisOfAddition(secondNode)) { + secondArgs = secondNode.content.args; + } + else { + secondArgs = [secondNode]; + } + // the new operands under addition, now products of terms + var newArgs = []; + // if exactly one group contains at least one fraction, multiply the + // non-fraction group into the numerators of the fraction group + if ([firstArgs, secondArgs].filter(hasFraction).length === 1) { + var firstArgsHasFraction = hasFraction(firstArgs); + var fractionNodes = firstArgsHasFraction ? firstArgs : secondArgs; + var nonFractionTerm_1 = firstArgsHasFraction ? secondNode : firstNode; + fractionNodes.forEach(function (node) { + var arg; + if (isFraction(node)) { + var numerator = mathNode.Creator.operator('*', [node.args[0], nonFractionTerm_1]); + numerator = mathNode.Creator.parenthesis(numerator); + arg = mathNode.Creator.operator('/', [numerator, node.args[1]]); + } + else { + arg = mathNode.Creator.operator('*', [node, nonFractionTerm_1]); + } + arg.changeGroup = 1; + newArgs.push(arg); + }); + } + else if (firstArgs.length > 1 && secondArgs.length > 1) { + firstArgs.forEach(function (leftArg) { + var arg = mathNode.Creator.operator('*', [leftArg, secondNode]); + arg.changeGroup = 1; + newArgs.push(arg); + }); + } + else { + // a list of all pairs of nodes between the two arg lists + firstArgs.forEach(function (leftArg) { + secondArgs.forEach(function (rightArg) { + var arg = mathNode.Creator.operator('*', [leftArg, rightArg]); + arg.changeGroup = 1; + newArgs.push(arg); + }); + }); + } + return mathNode.Creator.parenthesis(mathNode.Creator.operator('+', newArgs)); +} +function hasFraction(args) { + return args.filter(isFraction).length > 0; +} +function isFraction(node) { + return mathNode.Type.isOperator(node, '/'); +} +function simplifyWithParens(node) { + if (!mathNode.Type.isParenthesis(node)) { + throw Error('expected ' + node + ' to be a parenthesis node'); + } + var status = simplify(node.content); + if (status.hasChanged()) { + return mathNode.Status.childChanged(node, status); + } + else { + return mathNode.Status.noChange(node); + } +} +function simplify(node) { + var substeps = []; + var simplifyFunctions = [ + arithmeticSearch, + rearrangeCoefficient, + collectAndCombineSearch, + distributeAndSimplifyOperationNode, + ]; + var newNode = clone(node); + for (var i = 0; i < newNode.args.length; i++) { + for (var j = 0; j < simplifyFunctions.length; j++) { + var childStatus = simplifyFunctions[j](newNode.args[i]); + if (childStatus.hasChanged()) { + var status_2 = mathNode.Status.childChanged(newNode, childStatus, i); + substeps.push(status_2); + newNode = mathNode.Status.resetChangeGroups(status_2.newNode); + } + } + } + // possible in cases like 2(x + y) -> 2x + 2y -> doesn't need simplifying + if (substeps.length === 0) { + return mathNode.Status.noChange(node); + } + else { + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_TERMS, node, newNode, false, substeps); + } +} +function isParenthesisOfAddition(node) { + if (!mathNode.Type.isParenthesis(node)) { + return false; + } + var content = node.content; + return mathNode.Type.isOperator(content, '+'); +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/distributeSearch/index.js.map b/lib/simplifyExpression/distributeSearch/index.js.map new file mode 100644 index 00000000..537e8900 --- /dev/null +++ b/lib/simplifyExpression/distributeSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/distributeSearch/index.ts b/lib/simplifyExpression/distributeSearch/index.ts index afc60e34..5c2b06a8 100644 --- a/lib/simplifyExpression/distributeSearch/index.ts +++ b/lib/simplifyExpression/distributeSearch/index.ts @@ -4,7 +4,7 @@ import collectAndCombineSearch = require('../collectAndCombineSearch'); import rearrangeCoefficient = require('../basicsSearch/rearrangeCoefficient'); import ChangeTypes = require('../../ChangeTypes'); import Negative = require('../../Negative'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); const search = TreeSearch.postOrder(distribute); diff --git a/lib/simplifyExpression/divisionSearch/index.ts b/lib/simplifyExpression/divisionSearch/index.ts index 75e9d7e6..59bd7815 100644 --- a/lib/simplifyExpression/divisionSearch/index.ts +++ b/lib/simplifyExpression/divisionSearch/index.ts @@ -1,5 +1,5 @@ import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); // Searches for and simplifies any chains of division or nested division. diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js new file mode 100644 index 00000000..4e0273e0 --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js @@ -0,0 +1,89 @@ +"use strict"; +var addConstantFractions = require("./addConstantFractions"); +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var evaluate = require("../../util/evaluate"); +var mathNode = require("../../mathnode"); +function addConstantAndFraction(node) { + if (!mathNode.Type.isOperator(node) || node.op !== '+' || node.args.length !== 2) { + return mathNode.Status.noChange(node); + } + var firstArg = node.args[0]; + var secondArg = node.args[1]; + var constNode, fractionNode; + if (mathNode.Type.isConstant(firstArg)) { + if (mathNode.Type.isIntegerFraction(secondArg)) { + constNode = firstArg; + fractionNode = secondArg; + } + else { + return mathNode.Status.noChange(node); + } + } + else if (mathNode.Type.isConstant(secondArg)) { + if (mathNode.Type.isIntegerFraction(firstArg)) { + constNode = secondArg; + fractionNode = firstArg; + } + else { + return mathNode.Status.noChange(node); + } + } + else { + return mathNode.Status.noChange(node); + } + var newNode = clone(node); + var substeps = []; + // newConstNode and newFractionNode will end up both constants, or both + // fractions. I'm naming them based on their original form so we can keep + // track of which is which. + var newConstNode, newFractionNode; + var changeType; + if (parseFloat(constNode.value) % 1 === 0) { + var denominatorNode = fractionNode.args[1]; + var denominatorValue = parseInt(denominatorNode); + var constNodeValue = parseInt(constNode.value); + var newNumeratorNode = mathNode.Creator.constant(constNodeValue * denominatorValue); + newConstNode = mathNode.Creator.operator('/', [newNumeratorNode, denominatorNode]); + newFractionNode = fractionNode; + changeType = ChangeTypes.CONVERT_INTEGER_TO_FRACTION; + } + else { + // round to 4 decimal places + var dividedValue = evaluate(fractionNode); + if (dividedValue < 1) { + dividedValue = parseFloat(dividedValue.toPrecision(4)); + } + else { + dividedValue = parseFloat(dividedValue.toFixed(4)); + } + newFractionNode = mathNode.Creator.constant(dividedValue); + newConstNode = constNode; + changeType = ChangeTypes.DIVIDE_FRACTION_FOR_ADDITION; + } + if (mathNode.Type.isConstant(firstArg)) { + newNode.args[0] = newConstNode; + newNode.args[1] = newFractionNode; + } + else { + newNode.args[0] = newFractionNode; + newNode.args[1] = newConstNode; + } + substeps.push(mathNode.Status.nodeChanged(changeType, node, newNode)); + newNode = mathNode.Status.resetChangeGroups(newNode); + // If we changed an integer to a fraction, we need to add the steps for + // adding the fractions. + if (changeType === ChangeTypes.CONVERT_INTEGER_TO_FRACTION) { + var addFractionStatus = addConstantFractions(newNode); + substeps = substeps.concat(addFractionStatus.substeps); + } + else { + var evalNode = mathNode.Creator.constant(evaluate(newNode)); + substeps.push(mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, newNode, evalNode)); + } + var lastStep = substeps[substeps.length - 1]; + newNode = mathNode.Status.resetChangeGroups(lastStep.newNode); + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); +} +module.exports = addConstantAndFraction; +//# sourceMappingURL=addConstantAndFraction.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map new file mode 100644 index 00000000..f393260e --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map @@ -0,0 +1 @@ +{"version":3,"file":"addConstantAndFraction.js","sourceRoot":"","sources":["addConstantAndFraction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts index 37bd3353..e6675426 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts @@ -2,7 +2,7 @@ import addConstantFractions = require('./addConstantFractions'); import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); import evaluate = require('../../util/evaluate'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Adds a constant to a fraction by: // - collapsing the fraction to decimal if the constant is not an integer @@ -47,7 +47,7 @@ function addConstantAndFraction(node) { // track of which is which. let newConstNode, newFractionNode; let changeType; - if (Number.isInteger(parseFloat(constNode.value))) { + if (parseFloat(constNode.value) % 1 === 0) { const denominatorNode = fractionNode.args[1]; const denominatorValue = parseInt(denominatorNode); const constNodeValue = parseInt(constNode.value); diff --git a/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts index 079a5974..a8bd3a4b 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts +++ b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts @@ -3,7 +3,7 @@ import divideByGCD = require('./divideByGCD'); import math = require('mathjs'); import ChangeTypes = require('../../ChangeTypes'); import evaluate = require('../../util/evaluate'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Adds constant fractions -- can start from either step 1 or 2 // 1A. Find the LCD if denominators are different and multiplies to make diff --git a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts index a3f9d7f1..946c6211 100644 --- a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts +++ b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts @@ -2,7 +2,7 @@ import clone = require('../../util/clone'); import print = require('../../util/print'); import ChangeTypes = require('../../ChangeTypes'); import Negative = require('../../Negative'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Used for cancelTerms to return a (possibly updated) numerator and denominator class CancelOutStatus { @@ -11,12 +11,15 @@ class CancelOutStatus { this.denominator = denominator; this.hasChanged = hasChanged; } + + numerator; + denominator; + hasChanged: boolean; } // Cancels like terms in a fraction node // e.g. (2x^2 * 5) / 2x^2 => 5 / 1 // Returns a mathNode.Status object -function cancelLikeTerms(node: any); function cancelLikeTerms(node) { if (!mathNode.Type.isOperator(node) || node.op !== '/') { return mathNode.Status.noChange(node); @@ -168,7 +171,6 @@ function cancelLikeTerms(node) { // Returns the new nodes for numerator and denominator with the common terms // removed. If the entire numerator or denominator is cancelled out, it is // returned as null. e.g. 4, 4x => null, x -function cancelTerms(numerator: any, denominator: any); function cancelTerms(numerator, denominator) { // Deal with unary minuses by recursing on the argument if (mathNode.Type.isUnaryMinus(numerator)) { diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.ts b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts index e350dd7e..32dce915 100644 --- a/lib/simplifyExpression/fractionsSearch/divideByGCD.ts +++ b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts @@ -1,7 +1,7 @@ import math = require('mathjs'); import ChangeTypes = require('../../ChangeTypes'); import evaluate = require('../../util/evaluate'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Simplifies a fraction (with constant numerator and denominator) by dividing // the top and bottom by the GCD, if possible. diff --git a/lib/simplifyExpression/fractionsSearch/index.js b/lib/simplifyExpression/fractionsSearch/index.js new file mode 100644 index 00000000..5565b7c4 --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/index.js @@ -0,0 +1,48 @@ +/* + * Performs simpifications on fractions: adding and cancelling out. + * + * Note: division is represented in mathjs as an operator node with op '/' + * and two args, where arg[0] is the numerator and arg[1] is the denominator + +// This module manipulates fractions with constants in the numerator and +// denominator. For more complex/general fractions, see Fraction.js + + */ +"use strict"; +var addConstantAndFraction = require("./addConstantAndFraction"); +var addConstantFractions = require("./addConstantFractions"); +var cancelLikeTerms = require("./cancelLikeTerms"); +var divideByGCD = require("./divideByGCD"); +var simplifyFractionSigns = require("./simplifyFractionSigns"); +var simplifyPolynomialFraction = require("./simplifyPolynomialFraction"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +var SIMPLIFICATION_FUNCTIONS = [ + // e.g. 2/3 + 5/6 + addConstantFractions, + // e.g. 4 + 5/6 or 4.5 + 6/8 + addConstantAndFraction, + // e.g. 2/-9 -> -2/9 e.g. -2/-9 -> 2/9 + simplifyFractionSigns, + // e.g. 8/12 -> 2/3 (divide by GCD 4) + divideByGCD, + // e.g. 2x/4 -> x/2 (divideByGCD but for coefficients of polynomial terms) + simplifyPolynomialFraction, + // e.g. (2x * 5) / 2x -> 5 + cancelLikeTerms, +]; +var search = TreeSearch.preOrder(simplifyFractions); +function simplifyFractions(node) { + for (var i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) { + var nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + else { + node = nodeStatus.newNode; + } + } + return mathNode.Status.noChange(node); +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/index.js.map b/lib/simplifyExpression/fractionsSearch/index.js.map new file mode 100644 index 00000000..e327b9b1 --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;AAEH,iEAAoE;AACpE,6DAAgE;AAChE,mDAAsD;AACtD,2CAA8C;AAC9C,+DAAkE;AAClE,yEAA4E;AAC5E,yCAA4C;AAC5C,6CAAgD;AAChD,IAAM,wBAAwB,GAAG;IAC/B,iBAAiB;IACjB,oBAAoB;IACpB,4BAA4B;IAC5B,sBAAsB;IACtB,+CAA+C;IAC/C,qBAAqB;IACrB,uCAAuC;IACvC,WAAW;IACX,0EAA0E;IAC1E,0BAA0B;IAC1B,4BAA4B;IAC5B,eAAe;CAChB,CAAC;AAEF,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAItD,2BAA2B,IAAI;IAC7B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,wBAAwB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzD,IAAM,UAAU,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/index.ts b/lib/simplifyExpression/fractionsSearch/index.ts index 78a3f50b..c2ac4074 100644 --- a/lib/simplifyExpression/fractionsSearch/index.ts +++ b/lib/simplifyExpression/fractionsSearch/index.ts @@ -15,7 +15,7 @@ import cancelLikeTerms = require('./cancelLikeTerms'); import divideByGCD = require('./divideByGCD'); import simplifyFractionSigns = require('./simplifyFractionSigns'); import simplifyPolynomialFraction = require('./simplifyPolynomialFraction'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); const SIMPLIFICATION_FUNCTIONS = [ // e.g. 2/3 + 5/6 diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts index 7273b56e..75414c05 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts +++ b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts @@ -1,7 +1,7 @@ import clone = require('../../util/clone'); import ChangeTypes = require('../../ChangeTypes'); import Negative = require('../../Negative'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Simplifies negative signs if possible // e.g. -1/-3 --> 1/3 4/-5 --> -4/5 diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js new file mode 100644 index 00000000..0774240d --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js @@ -0,0 +1,34 @@ +"use strict"; +var arithmeticSearch = require("../arithmeticSearch"); +var clone = require("../../util/clone"); +var divideByGCD = require("./divideByGCD"); +var mathNode = require("../../mathnode"); +function simplifyPolynomialFraction(node) { + if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { + return mathNode.Status.noChange(node); + } + var polyNode = new mathNode.PolynomialTerm(clone(node)); + if (!polyNode.hasFractionCoeff()) { + return mathNode.Status.noChange(node); + } + var coefficientSimplifications = [ + divideByGCD, + arithmeticSearch, + ]; + for (var i = 0; i < coefficientSimplifications.length; i++) { + var coefficientFraction = polyNode.getCoeffNode(); // a division node + var newCoeffStatus = coefficientSimplifications[i](coefficientFraction); + if (newCoeffStatus.hasChanged()) { + var newCoeff = newCoeffStatus.newNode; + if (newCoeff.value === '1') { + newCoeff = null; + } + var exponentNode = polyNode.getExponentNode(); + var newNode = mathNode.Creator.polynomialTerm(polyNode.getSymbolNode(), exponentNode, newCoeff); + return mathNode.Status.nodeChanged(newCoeffStatus.changeType, node, newNode); + } + } + return mathNode.Status.noChange(node); +} +module.exports = simplifyPolynomialFraction; +//# sourceMappingURL=simplifyPolynomialFraction.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map new file mode 100644 index 00000000..4a7577b5 --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map @@ -0,0 +1 @@ +{"version":3,"file":"simplifyPolynomialFraction.js","sourceRoot":"","sources":["simplifyPolynomialFraction.ts"],"names":[],"mappings":";AAAA,sDAAyD;AACzD,wCAA2C;AAC3C,2CAA8C;AAC9C,yCAA4C;AAQ5C,oCAAoC,IAAI;IACtC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,0BAA0B,GAAG;QACjC,WAAW;QACX,gBAAgB;KACjB,CAAC;IAEF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,0BAA0B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,IAAM,mBAAmB,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,kBAAkB;QACvE,IAAM,cAAc,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC1E,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;YACtC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;gBAC3B,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;YACD,IAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC;YAChD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CAC3C,QAAQ,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;YACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts index bc92c32f..a64a3f7f 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts @@ -1,7 +1,7 @@ import arithmeticSearch = require('../arithmeticSearch'); import clone = require('../../util/clone'); import divideByGCD = require('./divideByGCD'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Simplifies a polynomial term with a fraction as its coefficients. // e.g. 2x/4 --> x/2 10x/5 --> 2x diff --git a/lib/simplifyExpression/functionsSearch/nthRoot.ts b/lib/simplifyExpression/functionsSearch/nthRoot.ts index ecc29c61..637c07bd 100644 --- a/lib/simplifyExpression/functionsSearch/nthRoot.ts +++ b/lib/simplifyExpression/functionsSearch/nthRoot.ts @@ -3,7 +3,7 @@ import math = require('mathjs'); import ChangeTypes = require('../../ChangeTypes'); import ConstantFactors = require('../../factor/ConstantFactors'); import Negative = require('../../Negative'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); // Evaluate nthRoot() function. // Returns a mathNode.Status object. @@ -379,7 +379,6 @@ function combineRoots(node) { // Returns the nthRoot evaluated on a constant node // Potentially factors the constant node into primes, and calls // nthRootMultiplication on the new nthRoot -function nthRootConstant(node: any); function nthRootConstant(node) { let newNode = clone(node); const radicandNode = getRadicandNode(node); diff --git a/lib/simplifyExpression/index.js b/lib/simplifyExpression/index.js new file mode 100644 index 00000000..32d58611 --- /dev/null +++ b/lib/simplifyExpression/index.js @@ -0,0 +1,19 @@ +"use strict"; +var math = require("mathjs"); +var stepThrough = require("./stepThrough"); +function simplifyExpressionString(expressionString, debug) { + if (debug === void 0) { debug = false; } + var exprNode; + try { + exprNode = math.parse(expressionString); + } + catch (err) { + return []; + } + if (exprNode) { + return stepThrough(exprNode, debug); + } + return []; +} +module.exports = simplifyExpressionString; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/index.js.map b/lib/simplifyExpression/index.js.map new file mode 100644 index 00000000..c6f6837c --- /dev/null +++ b/lib/simplifyExpression/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,2CAA8C;AAE9C,kCAAkC,gBAAgB,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IAC7D,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC1C,CAAC;IACD,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACX,MAAM,CAAC,EAAE,CAAC;IACZ,CAAC;IACD,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACb,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,CAAC,EAAE,CAAC;AACZ,CAAC;AAED,iBAAS,wBAAwB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js b/lib/simplifyExpression/multiplyFractionsSearch/index.js new file mode 100644 index 00000000..dc2dab1b --- /dev/null +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.js @@ -0,0 +1,43 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +// If `node` is a product of terms where some are fractions (but none are +// polynomial terms), multiplies them together. +// e.g. 2 * 5/x -> (2*5)/x +// e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) +// TODO: add a step somewhere to remove common terms in numerator and +// denominator (so the 5s would cancel out on the next step after this) +// This step must happen after things have been distributed, or else the answer +// will be formatted badly, so it's a tree search of its own. +// Returns a mathNode.Status object. +var search = TreeSearch.postOrder(multiplyFractions); +function multiplyFractions(node) { + if (!mathNode.Type.isOperator(node) || node.op !== '*') { + return mathNode.Status.noChange(node); + } + var atLeastOneFraction = node.args.some(function (arg) { return mathNode.Type.isOperator(arg, '/'); }); + var hasPolynomialTerms = node.args.some(function (arg) { return mathNode.PolynomialTerm.isPolynomialTerm(arg); }); + if (!atLeastOneFraction || hasPolynomialTerms) { + return mathNode.Status.noChange(node); + } + var numeratorArgs = []; + var denominatorArgs = []; + node.args.forEach(function (operand) { + if (mathNode.Type.isOperator(operand, '/')) { + numeratorArgs.push(operand.args[0]); + denominatorArgs.push(operand.args[1]); + } + else { + numeratorArgs.push(operand); + } + }); + var newNumerator = mathNode.Creator.parenthesis(mathNode.Creator.operator('*', numeratorArgs)); + var newDenominator = denominatorArgs.length === 1 + ? denominatorArgs[0] + : mathNode.Creator.parenthesis(mathNode.Creator.operator('*', denominatorArgs)); + var newNode = mathNode.Creator.operator('/', [newNumerator, newDenominator]); + return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_FRACTIONS, node, newNode); +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js.map b/lib/simplifyExpression/multiplyFractionsSearch/index.js.map new file mode 100644 index 00000000..5f769f32 --- /dev/null +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,yEAAyE;AACzE,+CAA+C;AAC/C,0BAA0B;AAC1B,qCAAqC;AACrC,qEAAqE;AACrE,uEAAuE;AACvE,+EAA+E;AAC/E,6DAA6D;AAC7D,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;AAQvD,2BAA2B,IAAI;IAC7B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAlC,CAAkC,CAAC,CAAC;IAC7C,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAA7C,CAA6C,CAAC,CAAC;IACxD,EAAE,CAAC,CAAC,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,aAAa,GAAG,EAAE,CAAC;IACzB,IAAM,eAAe,GAAG,EAAE,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAA,OAAO;QACvB,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAC/C,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC;IACjD,IAAM,cAAc,GAAG,eAAe,CAAC,MAAM,KAAK,CAAC;UAC/C,eAAe,CAAC,CAAC,CAAC;UAClB,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;IAElF,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IAC/E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.ts b/lib/simplifyExpression/multiplyFractionsSearch/index.ts index 3b9f497d..13af59a9 100644 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.ts +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.ts @@ -1,5 +1,5 @@ import ChangeTypes = require('../../ChangeTypes'); -const mathNode = require('../../node'); +import mathNode = require('../../mathnode'); import TreeSearch = require('../../TreeSearch'); // If `node` is a product of terms where some are fractions (but none are diff --git a/lib/simplifyExpression/simplify.ts b/lib/simplifyExpression/simplify.ts index 7687b297..5c1bf02b 100644 --- a/lib/simplifyExpression/simplify.ts +++ b/lib/simplifyExpression/simplify.ts @@ -28,7 +28,6 @@ function simplify(node, debug=false) { // Unflattens a node so it is in the math.js style, by printing and parsing it // again -function unflatten(node: any); function unflatten(node) { return math.parse(print(node)); } diff --git a/lib/simplifyExpression/stepThrough.js b/lib/simplifyExpression/stepThrough.js new file mode 100644 index 00000000..7b847b1a --- /dev/null +++ b/lib/simplifyExpression/stepThrough.js @@ -0,0 +1,120 @@ +"use strict"; +var checks = require("../checks"); +var mathNode = require("../mathNode"); +var Status = require("../mathnode/Status"); +var arithmeticSearch = require("./arithmeticSearch"); +var basicsSearch = require("./basicsSearch"); +var breakUpNumeratorSearch = require("./breakUpNumeratorSearch"); +var collectAndCombineSearch = require("./collectAndCombineSearch"); +var distributeSearch = require("./distributeSearch"); +var divisionSearch = require("./divisionSearch"); +var fractionsSearch = require("./fractionsSearch"); +var functionsSearch = require("./functionsSearch"); +var multiplyFractionsSearch = require("./multiplyFractionsSearch"); +var clone = require("../util/clone"); +var flattenOperands = require("../util/flattenOperands"); +var print = require("../util/print"); +var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); +// Given a mathjs expression node, steps through simplifying the expression. +// Returns a list of details about each step. +function stepThrough(node, debug) { + if (debug === void 0) { debug = false; } + if (debug) { + // eslint-disable-next-line + // again, unsure whether or not there should be a ternary argument + console.log('\n\nSimplifying: ' + print(node, false)); + } + if (checks.hasUnsupportedNodes(node)) { + return []; + } + var nodeStatus; + var steps = []; + var originalExpressionStr = print(node); + var MAX_STEP_COUNT = 20; + var iters = 0; + // Now, step through the math expression until nothing changes + nodeStatus = step(node); + while (nodeStatus.hasChanged()) { + if (debug) { + logSteps(nodeStatus); + } + steps.push(removeUnnecessaryParensInStep(nodeStatus)); + var nextNode = Status.resetChangeGroups(nodeStatus.newNode); + nodeStatus = step(nextNode); + if (iters++ === MAX_STEP_COUNT) { + // eslint-disable-next-line + console.error('Math error: Potential infinite loop for expression: ' + + originalExpressionStr + ', returning no steps'); + return []; + } + } + return steps; +} +// Given a mathjs expression node, performs a single step to simplify the +// expression. Returns a mathNode.Status object. +function step(node) { + var nodeStatus; + node = flattenOperands(node); + node = removeUnnecessaryParens(node, true); + var simplificationTreeSearches = [ + // Basic simplifications that we always try first e.g. (...)^0 => 1 + basicsSearch, + // Simplify any division chains so there's at most one division operation. + // e.g. 2/x/6 -> 2/(x*6) e.g. 2/(x/6) => 2 * 6/x + divisionSearch, + // Adding fractions, cancelling out things in fractions + fractionsSearch, + // e.g. 2 + 2 => 4 + arithmeticSearch, + // e.g. addition: 2x + 4x^2 + x => 4x^2 + 3x + // e.g. multiplication: 2x * x * x^2 => 2x^3 + collectAndCombineSearch, + // e.g. (2 + x) / 4 => 2/4 + x/4 + breakUpNumeratorSearch, + // e.g. 3/x * 2x/5 => (3 * 2x) / (x * 5) + multiplyFractionsSearch, + // e.g. (2x + 3)(x + 4) => 2x^2 + 11x + 12 + distributeSearch, + // e.g. abs(-4) => 4 + functionsSearch, + ]; + for (var i = 0; i < simplificationTreeSearches.length; i++) { + nodeStatus = simplificationTreeSearches[i](node); + // Always update node, since there might be changes that didn't count as + // a step. Remove unnecessary parens, in case one a step results in more + // parens than needed. + node = removeUnnecessaryParens(nodeStatus.newNode, true); + if (nodeStatus.hasChanged()) { + node = flattenOperands(node); + nodeStatus.newNode = clone(node); + return nodeStatus; + } + else { + node = flattenOperands(node); + } + } + return mathNode.Status.noChange(node); +} +// Removes unnecessary parens throughout the steps. +// TODO: Ideally this would happen in NodeStatus instead. +function removeUnnecessaryParensInStep(nodeStatus) { + if (nodeStatus.substeps.length > 0) { + nodeStatus.substeps.map(removeUnnecessaryParensInStep); + } + nodeStatus.oldNode = removeUnnecessaryParens(nodeStatus.oldNode, true); + nodeStatus.newNode = removeUnnecessaryParens(nodeStatus.newNode, true); + return nodeStatus; +} +function logSteps(nodeStatus) { + // eslint-disable-next-line + console.log(nodeStatus.changeType); + // eslint-disable-next-line + console.log(print(nodeStatus.newNode) + '\n'); + if (nodeStatus.substeps.length > 0) { + // eslint-disable-next-line + console.log('\nsubsteps: '); + nodeStatus.substeps.forEach(function (substep) { return substep; }); + } +} +module.exports = stepThrough; +//# sourceMappingURL=stepThrough.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/stepThrough.js.map b/lib/simplifyExpression/stepThrough.js.map new file mode 100644 index 00000000..adee22ec --- /dev/null +++ b/lib/simplifyExpression/stepThrough.js.map @@ -0,0 +1 @@ +{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/stepThrough.ts b/lib/simplifyExpression/stepThrough.ts index 5e4353c9..049afdb8 100644 --- a/lib/simplifyExpression/stepThrough.ts +++ b/lib/simplifyExpression/stepThrough.ts @@ -1,6 +1,6 @@ import checks = require('../checks'); -const mathNode = require('../node'); -const Status = require('../node/Status'); +import mathNode = require('../mathNode'); +import Status = require('../mathnode/Status'); import arithmeticSearch = require('./arithmeticSearch'); import basicsSearch = require('./basicsSearch'); import breakUpNumeratorSearch = require('./breakUpNumeratorSearch'); @@ -20,7 +20,8 @@ import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); function stepThrough(node, debug=false) { if (debug) { // eslint-disable-next-line - console.log('\n\nSimplifying: ' + print(node, false, true)); + // again, unsure whether or not there should be a ternary argument + console.log('\n\nSimplifying: ' + print(node, false)); } if (checks.hasUnsupportedNodes(node)) { @@ -56,7 +57,6 @@ function stepThrough(node, debug=false) { // Given a mathjs expression node, performs a single step to simplify the // expression. Returns a mathNode.Status object. -function step(node: any); function step(node) { let nodeStatus; @@ -106,7 +106,6 @@ function step(node) { // Removes unnecessary parens throughout the steps. // TODO: Ideally this would happen in NodeStatus instead. -function removeUnnecessaryParensInStep(nodeStatus: any); function removeUnnecessaryParensInStep(nodeStatus) { if (nodeStatus.substeps.length > 0) { nodeStatus.substeps.map(removeUnnecessaryParensInStep); @@ -117,7 +116,6 @@ function removeUnnecessaryParensInStep(nodeStatus) { return nodeStatus; } -function logSteps(nodeStatus: any); function logSteps(nodeStatus) { // eslint-disable-next-line console.log(nodeStatus.changeType); diff --git a/lib/solveEquation/EquationOperations.js b/lib/solveEquation/EquationOperations.js new file mode 100644 index 00000000..d4db5c27 --- /dev/null +++ b/lib/solveEquation/EquationOperations.js @@ -0,0 +1,202 @@ +// Operations on equation nodes +"use strict"; +var ChangeTypes = require("../ChangeTypes"); +var clone = require("../util/clone"); +var Equation = require("../equation/Equation"); +var EquationStatus = require("../equation/Status"); +var Negative = require("../Negative"); +var mathNode = require("../mathNode"); +var Symbols = require("../Symbols"); +var COMPARATOR_TO_INVERSE = { + '>': '<', + '>=': '<=', + '<': '>', + '<=': '>=', + '=': '=' +}; +var EquationOperations = (function () { + function EquationOperations() { + } + return EquationOperations; +}()); +// Ensures that the given equation has the given symbolName on the left side, +// by swapping the right and left sides if it is only in the right side. +// So 3 = x would become x = 3. +EquationOperations.ensureSymbolInLeftNode = function (equation, symbolName) { + var leftSideSymbolTerm = Symbols.getLastSymbolTerm(equation.leftNode, symbolName); + var rightSideSymbolTerm = Symbols.getLastSymbolTerm(equation.rightNode, symbolName); + if (!leftSideSymbolTerm) { + if (rightSideSymbolTerm) { + var comparator = COMPARATOR_TO_INVERSE[equation.comparator]; + var oldEquation = equation; + var newEquation = new Equation(equation.rightNode, equation.leftNode, comparator); + // no change groups are set for this step because everything changes, so + // they wouldn't be pedagogically helpful. + return new EquationStatus(ChangeTypes.SWAP_SIDES, oldEquation, newEquation); + } + else { + throw Error('No term with symbol: ' + symbolName); + } + } + return EquationStatus.noChange(equation); +}; +// TODO: Ensures that a symbol is not in the denominator by multiplying +// both sides by the whatever order of the symbol necessary. +// This is blocked on the simplifying functionality of canceling symbols in +// fractions (needs factoring for full canceling support) +EquationOperations.removeSymbolFromDenominator = function (equation) { return EquationStatus.noChange(equation); }; +// Removes the given symbolName from the right side by adding or subtracting +// it from both sides as appropriate. +// e.g. 2x = 3x + 5 --> 2x - 3x = 5 +// There are actually no cases where we'd remove symbols from the right side +// by multiplying or dividing by a symbol term. +// TODO: support inverting functions e.g. sqrt, ^, log etc. +EquationOperations.removeSymbolFromRightSide = function (equation, symbolName) { + var rightNode = equation.rightNode; + var symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); + var inverseOp, inverseTerm, changeType; + if (!symbolTerm) { + return EquationStatus.noChange(equation); + } + // Clone it so that any operations on it don't affect the node already + // in the equation + symbolTerm = clone(symbolTerm); + if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { + if (Negative.isNegative(symbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(symbolTerm); + } + else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = symbolTerm; + } + } + else if (mathNode.Type.isOperator(rightNode)) { + if (rightNode.op === '+') { + if (Negative.isNegative(symbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(symbolTerm); + } + else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = symbolTerm; + } + } + else { + // Note that operator '-' won't show up here because subtraction is + // flattened into adding the negative. See 'TRICKY catch' in the README + // for more details. + throw Error('Unsupported operation: ' + symbolTerm.op); + } + } + else if (mathNode.Type.isUnaryMinus(rightNode)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = symbolTerm.args[0]; + } + else { + throw Error('Unsupported node type: ' + rightNode.type); + } + return performTermOperationOnEquation(equation, inverseOp, inverseTerm, changeType); +}; +// Isolates the given symbolName to the left side by adding, multiplying, subtracting +// or dividing all other symbols and constants from both sides appropriately +// TODO: support inverting functions e.g. sqrt, ^, log etc. +EquationOperations.isolateSymbolOnLeftSide = function (equation, symbolName) { + var leftNode = equation.leftNode; + var nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); + var inverseOp, inverseTerm, changeType; + if (!nonSymbolTerm) { + return EquationStatus.noChange(equation); + } + // Clone it so that any operations on it don't affect the node already + // in the equation + nonSymbolTerm = clone(nonSymbolTerm); + if (mathNode.Type.isOperator(leftNode)) { + if (leftNode.op === '+') { + if (Negative.isNegative(nonSymbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(nonSymbolTerm); + } + else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = nonSymbolTerm; + } + } + else if (leftNode.op === '*') { + if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; + inverseTerm = mathNode.Creator.operator('/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + } + else { + inverseOp = '/'; + changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; + inverseTerm = nonSymbolTerm; + } + } + else if (leftNode.op === '/') { + // The non symbol term is always a fraction because it's the + // coefficient of our symbol term. + // If the numerator is 1, we multiply both sides by the denominator, + // otherwise we multiply by the inverse + if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; + inverseTerm = nonSymbolTerm.args[1]; + } + else { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; + inverseTerm = mathNode.Creator.operator('/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + } + } + else if (leftNode.op === '^') { + // TODO: support roots + return EquationStatus.noChange(equation); + } + else { + throw Error('Unsupported operation: ' + leftNode.op); + } + } + else if (mathNode.Type.isUnaryMinus(leftNode)) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; + inverseTerm = mathNode.Creator.constant(-1); + } + else { + throw Error('Unsupported node type: ' + leftNode.type); + } + return performTermOperationOnEquation(equation, inverseOp, inverseTerm, changeType); +}; +// Modifies the left and right sides of an equation by `op`-ing `term` +// to both sides. Returns an Status object. +function performTermOperationOnEquation(equation, op, term, changeType) { + var oldEquation = equation.clone(); + var leftTerm = clone(term); + var rightTerm = clone(term); + var leftNode = performTermOperationOnExpression(equation.leftNode, op, leftTerm); + var rightNode = performTermOperationOnExpression(equation.rightNode, op, rightTerm); + var comparator = equation.comparator; + if (Negative.isNegative(term) && (op === '*' || op === '/')) { + comparator = COMPARATOR_TO_INVERSE[comparator]; + } + var newEquation = new Equation(leftNode, rightNode, comparator); + return new EquationStatus(changeType, oldEquation, newEquation); +} +// Performs an operation of a term on an entire given expression +function performTermOperationOnExpression(expression, op, term) { + var node = (mathNode.Type.isOperator(expression) ? + mathNode.Creator.parenthesis(expression) : expression); + term.changeGroup = 1; + var newNode = mathNode.Creator.operator(op, [node, term]); + return newNode; +} +module.exports = EquationOperations; +//# sourceMappingURL=EquationOperations.js.map \ No newline at end of file diff --git a/lib/solveEquation/EquationOperations.js.map b/lib/solveEquation/EquationOperations.js.map new file mode 100644 index 00000000..df8f0e0e --- /dev/null +++ b/lib/solveEquation/EquationOperations.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EquationOperations.js","sourceRoot":"","sources":["EquationOperations.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/solveEquation/EquationOperations.ts b/lib/solveEquation/EquationOperations.ts index ba683510..2c75d712 100644 --- a/lib/solveEquation/EquationOperations.ts +++ b/lib/solveEquation/EquationOperations.ts @@ -5,7 +5,7 @@ import clone = require('../util/clone'); import Equation = require('../equation/Equation'); import EquationStatus = require('../equation/Status'); import Negative = require('../Negative'); -const mathNode = require('../node'); +import mathNode = require('../mathNode'); import Symbols = require('../Symbols'); const COMPARATOR_TO_INVERSE = { '>': '<', @@ -15,40 +15,45 @@ const COMPARATOR_TO_INVERSE = { '=': '=' }; -const EquationOperations = {}; +class EquationOperations { // Ensures that the given equation has the given symbolName on the left side, // by swapping the right and left sides if it is only in the right side. // So 3 = x would become x = 3. -EquationOperations.ensureSymbolInLeftNode = (equation, symbolName) => { - const leftSideSymbolTerm = Symbols.getLastSymbolTerm( - equation.leftNode, symbolName); - const rightSideSymbolTerm = Symbols.getLastSymbolTerm( - equation.rightNode, symbolName); - - if (!leftSideSymbolTerm) { - if (rightSideSymbolTerm) { - const comparator = COMPARATOR_TO_INVERSE[equation.comparator]; - const oldEquation = equation; - const newEquation = new Equation( - equation.rightNode, equation.leftNode, comparator); - // no change groups are set for this step because everything changes, so - // they wouldn't be pedagogically helpful. - return new EquationStatus( - ChangeTypes.SWAP_SIDES, oldEquation, newEquation); - } - else { - throw Error('No term with symbol: ' + symbolName); + static ensureSymbolInLeftNode = (equation, symbolName) => { + const leftSideSymbolTerm = Symbols.getLastSymbolTerm( + equation.leftNode, + symbolName); + const rightSideSymbolTerm = Symbols.getLastSymbolTerm( + equation.rightNode, + symbolName); + + if (!leftSideSymbolTerm) { + if (rightSideSymbolTerm) { + const comparator = COMPARATOR_TO_INVERSE[equation.comparator]; + const oldEquation = equation; + const newEquation = new Equation( + equation.rightNode, + equation.leftNode, + comparator); + // no change groups are set for this step because everything changes, so + // they wouldn't be pedagogically helpful. + return new EquationStatus( + ChangeTypes.SWAP_SIDES, + oldEquation, + newEquation); + } else { + throw Error('No term with symbol: ' + symbolName); + } } - } - return EquationStatus.noChange(equation); -}; + return EquationStatus.noChange(equation); + }; // TODO: Ensures that a symbol is not in the denominator by multiplying // both sides by the whatever order of the symbol necessary. // This is blocked on the simplifying functionality of canceling symbols in // fractions (needs factoring for full canceling support) -EquationOperations.removeSymbolFromDenominator = equation => EquationStatus.noChange(equation); + static removeSymbolFromDenominator = equation => EquationStatus.noChange(equation); // Removes the given symbolName from the right side by adding or subtracting // it from both sides as appropriate. @@ -56,146 +61,139 @@ EquationOperations.removeSymbolFromDenominator = equation => EquationStatus.noCh // There are actually no cases where we'd remove symbols from the right side // by multiplying or dividing by a symbol term. // TODO: support inverting functions e.g. sqrt, ^, log etc. -EquationOperations.removeSymbolFromRightSide = (equation, symbolName) => { - const rightNode = equation.rightNode; - let symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); + static removeSymbolFromRightSide = (equation, symbolName) => { + const rightNode = equation.rightNode; + let symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); - let inverseOp, inverseTerm, changeType; - if (!symbolTerm){ - return EquationStatus.noChange(equation); - } + let inverseOp, inverseTerm, changeType; + if (!symbolTerm) { + return EquationStatus.noChange(equation); + } - // Clone it so that any operations on it don't affect the node already - // in the equation - symbolTerm = clone(symbolTerm); + // Clone it so that any operations on it don't affect the node already + // in the equation + symbolTerm = clone(symbolTerm); - if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { - if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } - else { - inverseOp = '-'; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } - else if (mathNode.Type.isOperator(rightNode)) { - if (rightNode.op === '+') { + if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { if (Negative.isNegative(symbolTerm)) { inverseOp = '+'; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(symbolTerm); - } - else { + } else { inverseOp = '-'; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = symbolTerm; } + } else if (mathNode.Type.isOperator(rightNode)) { + if (rightNode.op === '+') { + if (Negative.isNegative(symbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(symbolTerm); + } else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = symbolTerm; + } + } else { + // Note that operator '-' won't show up here because subtraction is + // flattened into adding the negative. See 'TRICKY catch' in the README + // for more details. + throw Error('Unsupported operation: ' + symbolTerm.op); + } + } else if (mathNode.Type.isUnaryMinus(rightNode)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = symbolTerm.args[0]; + } else { + throw Error('Unsupported node type: ' + rightNode.type); } - else { - // Note that operator '-' won't show up here because subtraction is - // flattened into adding the negative. See 'TRICKY catch' in the README - // for more details. - throw Error('Unsupported operation: ' + symbolTerm.op); - } - } - else if (mathNode.Type.isUnaryMinus(rightNode)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = symbolTerm.args[0]; - } - else { - throw Error('Unsupported node type: ' + rightNode.type); - } - return performTermOperationOnEquation( - equation, inverseOp, inverseTerm, changeType); -}; + return performTermOperationOnEquation( + equation, + inverseOp, + inverseTerm, + changeType); + }; // Isolates the given symbolName to the left side by adding, multiplying, subtracting // or dividing all other symbols and constants from both sides appropriately // TODO: support inverting functions e.g. sqrt, ^, log etc. -EquationOperations.isolateSymbolOnLeftSide = (equation, symbolName) => { - const leftNode = equation.leftNode; - let nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); - - let inverseOp, inverseTerm, changeType; - if (!nonSymbolTerm) { - return EquationStatus.noChange(equation); - } + static isolateSymbolOnLeftSide = (equation, symbolName) => { + const leftNode = equation.leftNode; + let nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); - // Clone it so that any operations on it don't affect the node already - // in the equation - nonSymbolTerm = clone(nonSymbolTerm); - - if (mathNode.Type.isOperator(leftNode)) { - if (leftNode.op === '+') { - if (Negative.isNegative(nonSymbolTerm)) { - inverseOp = '+'; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(nonSymbolTerm); - } - else { - inverseOp = '-'; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } - else if (leftNode.op === '*') { - if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator( - '/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - else { - inverseOp = '/'; - changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } - else if (leftNode.op === '/') { - // The non symbol term is always a fraction because it's the - // coefficient of our symbol term. - // If the numerator is 1, we multiply both sides by the denominator, - // otherwise we multiply by the inverse - if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; - inverseTerm = nonSymbolTerm.args[1]; - } - else { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator( - '/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - } - else if (leftNode.op === '^') { - // TODO: support roots + let inverseOp, inverseTerm, changeType; + if (!nonSymbolTerm) { return EquationStatus.noChange(equation); } - else { - throw Error('Unsupported operation: ' + leftNode.op); + + // Clone it so that any operations on it don't affect the node already + // in the equation + nonSymbolTerm = clone(nonSymbolTerm); + + if (mathNode.Type.isOperator(leftNode)) { + if (leftNode.op === '+') { + if (Negative.isNegative(nonSymbolTerm)) { + inverseOp = '+'; + changeType = ChangeTypes.ADD_TO_BOTH_SIDES; + inverseTerm = Negative.negate(nonSymbolTerm); + } else { + inverseOp = '-'; + changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; + inverseTerm = nonSymbolTerm; + } + } else if (leftNode.op === '*') { + if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; + inverseTerm = mathNode.Creator.operator( + '/', + [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + } else { + inverseOp = '/'; + changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; + inverseTerm = nonSymbolTerm; + } + } else if (leftNode.op === '/') { + // The non symbol term is always a fraction because it's the + // coefficient of our symbol term. + // If the numerator is 1, we multiply both sides by the denominator, + // otherwise we multiply by the inverse + if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; + inverseTerm = nonSymbolTerm.args[1]; + } else { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; + inverseTerm = mathNode.Creator.operator( + '/', + [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + } + } else if (leftNode.op === '^') { + // TODO: support roots + return EquationStatus.noChange(equation); + } else { + throw Error('Unsupported operation: ' + leftNode.op); + } + } else if (mathNode.Type.isUnaryMinus(leftNode)) { + inverseOp = '*'; + changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; + inverseTerm = mathNode.Creator.constant(-1); + } else { + throw Error('Unsupported node type: ' + leftNode.type); } - } - else if (mathNode.Type.isUnaryMinus(leftNode)) { - inverseOp = '*'; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; - inverseTerm = mathNode.Creator.constant(-1); - } - else { - throw Error('Unsupported node type: ' + leftNode.type); - } - - return performTermOperationOnEquation( - equation, inverseOp, inverseTerm, changeType); -}; + + return performTermOperationOnEquation( + equation, + inverseOp, + inverseTerm, + changeType); + }; +} // Modifies the left and right sides of an equation by `op`-ing `term` // to both sides. Returns an Status object. -function performTermOperationOnEquation(equation: any, op: any, term: any, changeType: any); function performTermOperationOnEquation(equation, op, term, changeType) { const oldEquation = equation.clone(); @@ -216,7 +214,6 @@ function performTermOperationOnEquation(equation, op, term, changeType) { } // Performs an operation of a term on an entire given expression -function performTermOperationOnExpression(expression: any, op: any, term: any); function performTermOperationOnExpression(expression, op, term) { const node = (mathNode.Type.isOperator(expression) ? mathNode.Creator.parenthesis(expression) : expression); diff --git a/lib/solveEquation/index.js b/lib/solveEquation/index.js new file mode 100644 index 00000000..81aeb958 --- /dev/null +++ b/lib/solveEquation/index.js @@ -0,0 +1,33 @@ +"use strict"; +var math = require("mathjs"); +var stepThrough = require("./stepThrough"); +function solveEquationString(equationString, debug) { + if (debug === void 0) { debug = false; } + var comparators = ['<=', '>=', '=', '<', '>']; + for (var i = 0; i < comparators.length; i++) { + var comparator = comparators[i]; + var sides = equationString.split(comparator); + if (sides.length !== 2) { + continue; + } + var leftNode = void 0, rightNode = void 0; + var leftSide = sides[0].trim(); + var rightSide = sides[1].trim(); + if (!leftSide || !rightSide) { + return []; + } + try { + leftNode = math.parse(leftSide); + rightNode = math.parse(rightSide); + } + catch (err) { + return []; + } + if (leftNode && rightNode) { + return stepThrough(leftNode, rightNode, comparator, debug); + } + } + return []; +} +module.exports = solveEquationString; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/solveEquation/index.js.map b/lib/solveEquation/index.js.map new file mode 100644 index 00000000..724dec0a --- /dev/null +++ b/lib/solveEquation/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,2CAA8C;AAE9C,6BAA6B,cAAc,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IACtD,IAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAEhD,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAClC,IAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/C,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,QAAQ,CAAC;QACX,CAAC;QACD,IAAI,QAAQ,SAAA,EAAE,SAAS,SAAA,CAAC;QACxB,IAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjC,IAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAElC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAChC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACX,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC;QACD,EAAE,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC;YAC1B,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,CAAC,EAAE,CAAC;AACZ,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js new file mode 100644 index 00000000..84c82dcd --- /dev/null +++ b/lib/solveEquation/stepThrough.js @@ -0,0 +1,226 @@ +"use strict"; +var ChangeTypes = require("../ChangeTypes"); +var checks = require("../checks"); +var Equation = require("../equation/Equation"); +var EquationOperations = require("./EquationOperations"); +var EquationStatus = require("../equation/Status"); +var evaluate = require("../util/evaluate"); +var flattenOperands = require("../util/flattenOperands"); +var mathNode = require("../mathnode"); +var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); +var simplifyExpressionNode = require("../simplifyExpression/stepThrough"); +var Symbols = require("../Symbols"); +var COMPARATOR_TO_FUNCTION = { + '=': function (left, right) { return left === right; }, + '>': function (left, right) { return left > right; }, + '>=': function (left, right) { return left >= right; }, + '<': function (left, right) { return left < right; }, + '<=': function (left, right) { return left <= right; }, +}; +// Given a leftNode, rightNode and a comparator, will return the steps to get +// the solution. Possible solutions include: +// - solving for a variable (e.g. 'x=3' for '3x=4+5') +// - the result of comparing values (e.g. 'true' for 3 = 3, 'false' for 3 < 2) +function stepThrough(leftNode, rightNode, comparator, debug) { + if (debug === void 0) { debug = false; } + var equation = new Equation(leftNode, rightNode, comparator); + if (debug) { + // eslint-disable-next-line + // unsure whether or not the second paramter should be a thing? + console.log('\n\nSolving: ' + equation.print(false)); + } + // we can't solve/find steps if there are any unsupported nodes + if (checks.hasUnsupportedNodes(equation.leftNode) || + checks.hasUnsupportedNodes(equation.rightNode)) { + return []; + } + var symbolSet = Symbols.getSymbolsInEquation(equation); + if (symbolSet.size === 0) { + return solveConstantEquation(equation, debug); + } + var symbolName = symbolSet.values().next().value; + var equationStatus; + var steps = []; + var originalEquationStr = equation.print(); + var MAX_STEP_COUNT = 20; + var iters = 0; + // Step through the math equation until nothing changes + do { + steps = addSimplificationSteps(steps, equation, debug); + if (steps.length > 0) { + var lastStep = steps[steps.length - 1]; + equation = Equation.createEquationFromString(lastStep.newEquation.print(), equation.comparator); + } + equation.leftNode = flattenOperands(equation.leftNode); + equation.rightNode = flattenOperands(equation.rightNode); + // at this point, the symbols might have cancelled out. + if (Symbols.getSymbolsInEquation(equation).size === 0) { + return solveConstantEquation(equation, debug, steps); + } + try { + equationStatus = step(equation, symbolName); + } + catch (e) { + // This error happens for some math that we don't support + if (e.message.startsWith('No term with symbol: ')) { + // eslint-disable-next-line + console.error('Math error: ' + e.message + ', returning no steps'); + return []; + } + else { + throw e; // bubble up + } + } + if (equationStatus.hasChanged()) { + if (equationStatus.newEquation.print().length > 300) { + // eslint-disable-next-line + throw Error('Math error: Potential infinite loop for equation ' + + originalEquationStr + '. It reached over 300 characters ' + + ' long, so returning no steps'); + } + if (debug) { + logSteps(equationStatus); + } + steps.push(equationStatus); + } + equation = EquationStatus.resetChangeGroups(equationStatus.newEquation); + if (iters++ === MAX_STEP_COUNT) { + // eslint-disable-next-line + console.error('Math error: Potential infinite loop for equation: ' + + originalEquationStr + ', returning no steps'); + return []; + } + } while (equationStatus.hasChanged()); + return steps; +} +// Given an equation of constants, will simplify both sides, returning +// the steps and the result of the equation e.g. 'True' or 'False' +function solveConstantEquation(equation, debug, steps) { + if (steps === void 0) { steps = []; } + var compareFunction = COMPARATOR_TO_FUNCTION[equation.comparator]; + if (!compareFunction) { + throw Error('Unexpected comparator'); + } + steps = addSimplificationSteps(steps, equation, debug); + if (steps.length > 0) { + var lastStep = steps[steps.length - 1]; + equation = Equation.createEquationFromString(lastStep.newEquation.print(), equation.comparator); + } + // 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); + if (!mathNode.Type.isConstantOrConstantFraction(equation.leftNode, true) || + !mathNode.Type.isConstantOrConstantFraction(equation.rightNode, true)) { + throw Error('Expected both nodes to be constants, instead got: ' + + equation.print()); + } + var leftValue = evaluate(equation.leftNode); + var rightValue = evaluate(equation.rightNode); + var changeType; + if (compareFunction(leftValue, rightValue)) { + changeType = ChangeTypes.STATEMENT_IS_TRUE; + } + else { + changeType = ChangeTypes.STATEMENT_IS_FALSE; + } + // there's no oldEquation or change groups because nothing actually changes + // here, it's just a final step that states the solution + var equationStatus = new EquationStatus(changeType, null, equation); + if (debug) { + logSteps(equationStatus); + } + steps.push(equationStatus); + return steps; +} +function step(equation, symbolName) { + var solveFunctions = [ + // ensure the symbol is always on the left node + EquationOperations.ensureSymbolInLeftNode, + // get rid of denominators that have the symbol + EquationOperations.removeSymbolFromDenominator, + // remove the symbol from the right side + EquationOperations.removeSymbolFromRightSide, + // isolate the symbol on the left side + EquationOperations.isolateSymbolOnLeftSide, + ]; + for (var i = 0; i < solveFunctions.length; i++) { + var equationStatus = solveFunctions[i](equation, symbolName); + if (equationStatus.hasChanged()) { + return equationStatus; + } + } + return EquationStatus.noChange(equation); +} +// Simplifies the equation and returns the simplification steps +function addSimplificationSteps(steps, equation, debug) { + if (debug === void 0) { debug = false; } + var oldEquation = equation.clone(); + var leftSteps = simplifyExpressionNode(equation.leftNode, false); + var leftSubSteps = []; + for (var i = 0; i < leftSteps.length; i++) { + var step_1 = leftSteps[i]; + leftSubSteps.push(EquationStatus.addLeftStep(equation, step_1)); + } + if (leftSubSteps.length === 1) { + var step_2 = leftSubSteps[0]; + if (debug) { + logSteps(step_2); + } + steps.push(step_2); + } + else if (leftSubSteps.length > 1) { + var lastStep = leftSubSteps[leftSubSteps.length - 1]; + var finalEquation = EquationStatus.resetChangeGroups(lastStep.newEquation); + // no change groups are set here - too much is changing for it to be useful + var simplifyStatus = new EquationStatus(ChangeTypes.SIMPLIFY_LEFT_SIDE, oldEquation, finalEquation, leftSubSteps); + if (debug) { + logSteps(simplifyStatus); + } + steps.push(simplifyStatus); + } + // update `equation` to have the new simplified left node + if (steps.length > 0) { + equation = EquationStatus.resetChangeGroups(steps[steps.length - 1].newEquation); + } + // the updated equation from simplifing the left side is the old equation + // (ie the "before" of the before and after) for simplifying the right side. + oldEquation = equation.clone(); + var rightSteps = simplifyExpressionNode(equation.rightNode, false); + var rightSubSteps = []; + for (var i = 0; i < rightSteps.length; i++) { + var step_3 = rightSteps[i]; + rightSubSteps.push(EquationStatus.addRightStep(equation, step_3)); + } + if (rightSubSteps.length === 1) { + var step_4 = rightSubSteps[0]; + if (debug) { + logSteps(step_4); + } + steps.push(step_4); + } + else if (rightSubSteps.length > 1) { + var lastStep = rightSubSteps[rightSubSteps.length - 1]; + var finalEquation = EquationStatus.resetChangeGroups(lastStep.newEquation); + // no change groups are set here - too much is changing for it to be useful + var simplifyStatus = new EquationStatus(ChangeTypes.SIMPLIFY_RIGHT_SIDE, oldEquation, finalEquation, rightSubSteps); + if (debug) { + logSteps(simplifyStatus); + } + steps.push(simplifyStatus); + } + return steps; +} +function logSteps(equationStatus) { + // eslint-disable-next-line + console.log('\n' + equationStatus.changeType); + // eslint-disable-next-line + console.log(equationStatus.newEquation.print()); + if (equationStatus.substeps.length > 0) { + // eslint-disable-next-line + console.log('\n substeps: '); + equationStatus.substeps.forEach(logSteps); + } +} +module.exports = stepThrough; +//# sourceMappingURL=stepThrough.js.map \ No newline at end of file diff --git a/lib/solveEquation/stepThrough.js.map b/lib/solveEquation/stepThrough.js.map new file mode 100644 index 00000000..d8c322e8 --- /dev/null +++ b/lib/solveEquation/stepThrough.js.map @@ -0,0 +1 @@ +{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":";AAAA,4CAA+C;AAC/C,kCAAqC;AACrC,+CAAkD;AAClD,yDAA4D;AAC5D,mDAAsD;AACtD,2CAA8C;AAC9C,yDAA4D;AAC5D,sCAAyC;AACzC,yEAA4E;AAC5E,0EAA6E;AAC7E,oCAAuC;AACvC,IAAM,sBAAsB,GAAG;IAC3B,GAAG,YAAC,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC;IAC3C,GAAG,YAAC,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;IACzC,IAAI,YAAC,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;IAC3C,GAAG,YAAC,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;IACzC,IAAI,YAAC,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;CAC9C,CAAC;AAEF,6EAA6E;AAC7E,4CAA4C;AAC5C,qDAAqD;AACrD,8EAA8E;AAC9E,qBAAqB,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IAC/D,IAAI,QAAQ,GAAG,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAE7D,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACV,2BAA2B;QACzB,+DAA+D;QACjE,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,+DAA+D;IAC/D,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC7C,MAAM,CAAC,mBAAmB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,EAAE,CAAC;IACZ,CAAC;IAED,IAAM,SAAS,GAAG,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAEzD,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,qBAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IACD,IAAM,UAAU,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;IAEnD,IAAI,cAAc,CAAC;IACnB,IAAI,KAAK,GAAG,EAAE,CAAC;IAEf,IAAM,mBAAmB,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC7C,IAAM,cAAc,GAAG,EAAE,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,uDAAuD;IACvD,GAAG,CAAC;QACF,KAAK,GAAG,sBAAsB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACvD,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACrB,IAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACzC,QAAQ,GAAG,QAAQ,CAAC,wBAAwB,CAC1C,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvD,CAAC;QAED,QAAQ,CAAC,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACvD,QAAQ,CAAC,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEzD,uDAAuD;QACvD,EAAE,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;YACtD,MAAM,CAAC,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC;YACH,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACT,yDAAyD;YACzD,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;gBAClD,2BAA2B;gBAC3B,OAAO,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,OAAO,GAAG,sBAAsB,CAAC,CAAC;gBACnE,MAAM,CAAC,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,CAAC,CAAC;gBACJ,MAAM,CAAC,CAAC,CAAC,YAAY;YACvB,CAAC;QACH,CAAC;QAED,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChC,EAAE,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;gBACpD,2BAA2B;gBAC3B,MAAM,KAAK,CAAC,mDAAmD;oBACnD,mBAAmB,GAAI,mCAAmC;oBAC1D,8BAA8B,CAAC,CAAC;YAC9C,CAAC;YACD,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBACV,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC3B,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7B,CAAC;QAED,QAAQ,GAAG,cAAc,CAAC,iBAAiB,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QACxE,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,cAAc,CAAC,CAAC,CAAC;YAC/B,2BAA2B;YAC3B,OAAO,CAAC,KAAK,CAAC,oDAAoD;gBACpD,mBAAmB,GAAG,sBAAsB,CAAC,CAAC;YAC5D,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,QAAQ,cAAc,CAAC,UAAU,EAAE,EAAE;IAEtC,MAAM,CAAC,KAAK,CAAC;AACf,CAAC;AAED,sEAAsE;AACtE,kEAAkE;AAClE,+BAA+B,QAAQ,EAAE,KAAK,EAAE,KAAQ;IAAR,sBAAA,EAAA,UAAQ;IACtD,IAAM,eAAe,GAAG,sBAAsB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAEpE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,GAAG,sBAAsB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACvD,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,IAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzC,QAAQ,GAAG,QAAQ,CAAC,wBAAwB,CAC1C,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,sEAAsE;IACtE,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,GAAG,uBAAuB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/D,QAAQ,CAAC,SAAS,GAAG,uBAAuB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAEjE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;QACpE,CAAC,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1E,MAAM,KAAK,CAAC,oDAAoD;YACpD,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,IAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC;IACf,EAAE,CAAC,CAAC,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3C,UAAU,GAAG,WAAW,CAAC,iBAAiB,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,UAAU,GAAG,WAAW,CAAC,kBAAkB,CAAC;IAC9C,CAAC;IAED,2EAA2E;IAC3E,wDAAwD;IACxD,IAAM,cAAc,GAAG,IAAI,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACV,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC3B,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,MAAM,CAAC,KAAK,CAAC;AACf,CAAC;AAKD,cAAc,QAAQ,EAAE,UAAU;IAChC,IAAM,cAAc,GAAG;QACrB,+CAA+C;QAC/C,kBAAkB,CAAC,sBAAsB;QACzC,+CAA+C;QAC/C,kBAAkB,CAAC,2BAA2B;QAC9C,wCAAwC;QACxC,kBAAkB,CAAC,yBAAyB;QAC5C,sCAAsC;QACtC,kBAAkB,CAAC,uBAAuB;KAC3C,CAAC;IAEF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,IAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAE/D,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,cAAc,CAAC;QACxB,CAAC;IACH,CAAC;IACD,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,+DAA+D;AAC/D,gCAAgC,KAAK,EAAE,QAAQ,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IAC1D,IAAI,WAAW,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;IAEnC,IAAM,SAAS,GAAG,sBAAsB,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnE,IAAM,YAAY,GAAG,EAAE,CAAC;IACxB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,IAAM,MAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1B,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAI,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAM,MAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACV,QAAQ,CAAC,MAAI,CAAC,CAAC;QACjB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAI,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACjC,IAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvD,IAAM,aAAa,GAAG,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC7E,2EAA2E;QAC3E,IAAM,cAAc,GAAG,IAAI,cAAc,CACvC,WAAW,CAAC,kBAAkB,EAC9B,WAAW,EAAE,aAAa,EAAE,YAAY,CAAC,CAAC;QAC5C,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACV,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7B,CAAC;IAED,yDAAyD;IACzD,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,QAAQ,GAAG,cAAc,CAAC,iBAAiB,CACzC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC;IAED,yEAAyE;IACzE,4EAA4E;IAC5E,WAAW,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;IAE/B,IAAM,UAAU,GAAG,sBAAsB,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACrE,IAAM,aAAa,GAAG,EAAE,CAAC;IACzB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAM,MAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAI,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAM,MAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC9B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACV,QAAQ,CAAC,MAAI,CAAC,CAAC;QACjB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAI,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,IAAM,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzD,IAAM,aAAa,GAAG,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC7E,2EAA2E;QAC3E,IAAM,cAAc,GAAG,IAAI,cAAc,CACxC,WAAW,CAAC,mBAAmB,EAC/B,WAAW,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;QAC5C,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACV,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,KAAK,CAAC;AACf,CAAC;AAGD,kBAAkB,cAAc;IAC9B,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC9C,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC;IAChD,EAAE,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACvC,2BAA2B;QAC3B,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,iBAAS,WAAW,CAAC"} \ No newline at end of file diff --git a/lib/solveEquation/stepThrough.ts b/lib/solveEquation/stepThrough.ts index f88d1c40..7bd5a404 100644 --- a/lib/solveEquation/stepThrough.ts +++ b/lib/solveEquation/stepThrough.ts @@ -5,7 +5,7 @@ import EquationOperations = require('./EquationOperations'); import EquationStatus = require('../equation/Status'); import evaluate = require('../util/evaluate'); import flattenOperands = require('../util/flattenOperands'); -const mathNode = require('../node'); +import mathNode = require('../mathnode'); import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); import simplifyExpressionNode = require('../simplifyExpression/stepThrough'); import Symbols = require('../Symbols'); @@ -26,7 +26,8 @@ function stepThrough(leftNode, rightNode, comparator, debug=false) { if (debug) { // eslint-disable-next-line - console.log('\n\nSolving: ' + equation.print(false, true)); + // unsure whether or not the second paramter should be a thing? + console.log('\n\nSolving: ' + equation.print(false)); } // we can't solve/find steps if there are any unsupported nodes @@ -115,7 +116,7 @@ function solveConstantEquation(equation, debug, steps=[]) { throw Error('Unexpected comparator'); } - steps = addSimplificationSteps(steps, equation, true, debug); + steps = addSimplificationSteps(steps, equation, debug); if (steps.length > 0) { const lastStep = steps[steps.length - 1]; equation = Equation.createEquationFromString( diff --git a/lib/util/Util.ts b/lib/util/Util.ts index 712fbab4..d0832197 100644 --- a/lib/util/Util.ts +++ b/lib/util/Util.ts @@ -5,7 +5,7 @@ class Util { // Adds `value` to a list in `dict`, creating a new list if the key isn't in // the dictionary yet. Returns the updated dictionary. - appendToArrayInObject = (dict, key, value) => { + static appendToArrayInObject = (dict, key, value) => { if (dict[key]) { dict[key].push(value); } else { diff --git a/lib/util/clone.js b/lib/util/clone.js index f06ff1fb..74e0e3d4 100644 --- a/lib/util/clone.js +++ b/lib/util/clone.js @@ -1,4 +1,7 @@ "use strict"; +// Simple clone function, which creates a deep copy of the given node +// And recurses on the children (due to the shallow nature of the mathjs node +// clone) function clone(node) { var copy = node.clone(); copy.changeGroup = node.changeGroup; diff --git a/lib/util/clone.js.map b/lib/util/clone.js.map index 708c34e2..724d088f 100644 --- a/lib/util/clone.js.map +++ b/lib/util/clone.js.map @@ -1 +1 @@ -{"version":3,"file":"clone.js","sourceRoot":"","sources":["clone.ts"],"names":[],"mappings":";AAIA,eAAe,IAAI;IACjB,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AACd,CAAC;AAED,iBAAS,KAAK,CAAC"} \ No newline at end of file +{"version":3,"file":"clone.js","sourceRoot":"","sources":["clone.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,6EAA6E;AAC7E,SAAS;AACT,eAAe,IAAI;IACjB,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AACd,CAAC;AAED,iBAAS,KAAK,CAAC"} \ No newline at end of file diff --git a/lib/util/clone.ts b/lib/util/clone.ts index 3c2c70da..5c51688e 100644 --- a/lib/util/clone.ts +++ b/lib/util/clone.ts @@ -1,7 +1,6 @@ // Simple clone function, which creates a deep copy of the given node // And recurses on the children (due to the shallow nature of the mathjs node // clone) -function clone(node: any); function clone(node) { const copy = node.clone(); copy.changeGroup = node.changeGroup; diff --git a/lib/util/evaluate.js b/lib/util/evaluate.js index a5898b8e..995216fd 100644 --- a/lib/util/evaluate.js +++ b/lib/util/evaluate.js @@ -1,7 +1,7 @@ +"use strict"; // Evaluates a node to a numerical value // e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 // it's important that `node` does not contain any symbol nodes -"use strict"; function evaluate(node) { // TODO: once we swap in math-parser, call its evaluate function instead return node.eval(); diff --git a/lib/util/evaluate.js.map b/lib/util/evaluate.js.map index 58bb1d2a..45d425a8 100644 --- a/lib/util/evaluate.js.map +++ b/lib/util/evaluate.js.map @@ -1 +1 @@ -{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["evaluate.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,6EAA6E;AAC7E,+DAA+D;;AAG/D,kBAAkB,IAAI;IACpB,wEAAwE;IACxE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file +{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["evaluate.ts"],"names":[],"mappings":";AAAA,wCAAwC;AACxC,6EAA6E;AAC7E,+DAA+D;AAC/D,kBAAkB,IAAI;IACpB,wEAAwE;IACxE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/util/evaluate.ts b/lib/util/evaluate.ts index 9761d84e..c71181b1 100644 --- a/lib/util/evaluate.ts +++ b/lib/util/evaluate.ts @@ -1,8 +1,6 @@ // Evaluates a node to a numerical value // e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 // it's important that `node` does not contain any symbol nodes - -function evaluate(node: any); function evaluate(node) { // TODO: once we swap in math-parser, call its evaluate function instead return node.eval(); diff --git a/lib/util/flattenOperands.ts b/lib/util/flattenOperands.ts index 1cc67605..50a9ed7d 100644 --- a/lib/util/flattenOperands.ts +++ b/lib/util/flattenOperands.ts @@ -1,6 +1,6 @@ import evaluate = require('./evaluate'); import Negative = require('../Negative'); -import Node = require('../node'); +import mathNode = require('../mathNode'); /* Background: @@ -34,7 +34,6 @@ interested in how that works // 2+2+2, ie one + node that has three children. // Input: an expression tree // Output: the expression tree updated with flattened operations -function flattenOperands(node: any); function flattenOperands(node) { if (Node.Type.isConstant(node, true)) { // the evaluate() changes unary minuses around constant nodes to constant nodes @@ -226,7 +225,6 @@ function getOperands(node, parentOp) { // 2*2*x (which has three children). // So this function would return true for the input 2*2x, if it was stored as // an expression tree with root node * and children 2*2 and x -function isPolynomialTermMultiplication(node: any); function isPolynomialTermMultiplication(node) { // This concept only applies when we're flattening multiplication operations if (node.op !== '*') { @@ -239,8 +237,8 @@ function isPolynomialTermMultiplication(node) { // The second node should be for the form x or x^2 (ie a polynomial term // with no coefficient) const secondOperand = node.args[1]; - if (Node.PolynomialTerm.isPolynomialTerm(secondOperand)) { - const polyNode = new Node.PolynomialTerm(secondOperand); + if (mathNode.PolynomialTerm.isPolynomialTerm(secondOperand)) { + const polyNode = new mathNode.PolynomialTerm(secondOperand); return !polyNode.hasCoeff(); } else { @@ -269,10 +267,10 @@ function maybeFlattenPolynomialTerm(node) { const nextOperand = flattenOperands(node.args[1]); // a coefficient can be constant or a fraction of constants - if (Node.Type.isConstantOrConstantFraction(lastOperand)) { + if (mathNode.Type.isConstantOrConstantFraction(lastOperand)) { // we replace the constant (which we popped) with constant*symbol operands.push( - Node.Creator.operator('*', [lastOperand, nextOperand], true)); + mathNode.Creator.operator('*', [lastOperand, nextOperand], true)); } // Now we know it isn't a polynomial term, it's just another seperate operand else { @@ -306,7 +304,7 @@ function flattenDivision(node) { const denominator = flattenOperands(node.args[1]); // Note that this means 2 * 3 * 4 / 5 / 6 * 7 will flatten but keep the 4/5/6 // as an operand - in simplifyDivision.js this is changed to 4/(5*6) - const divisionNode = Node.Creator.operator('/', [numerator, denominator]); + const divisionNode = mathNode.Creator.operator('/', [numerator, denominator]); operands.push(divisionNode); } @@ -319,7 +317,7 @@ function flattenDivision(node) { // e.g. returns false: 3/4/5, ((3*2) - 5) / 7, (2*5)/6 function hasMultiplicationBesideDivision(node: any); function hasMultiplicationBesideDivision(node) { - if (!Node.Type.isOperator(node)) { + if (!mathNode.Type.isOperator(node)) { return false; } if (node.op === '*') { diff --git a/lib/util/print.ts b/lib/util/print.ts index 5db16bd6..5ce26853 100644 --- a/lib/util/print.ts +++ b/lib/util/print.ts @@ -1,6 +1,6 @@ import clone = require('./clone'); import flatten = require('./flattenOperands'); -import Node = require('../node'); +import mathNode = require('../mathNode'); // Prints an expression node in asciimath // If showPlusMinus is true, print + - (e.g. 2 + -3) @@ -16,18 +16,16 @@ function print(node, showPlusMinus=false) { } return string; } - -function printTreeTraversal(node: any, parentNode: any); -function printTreeTraversal(node, parentNode) { - if (Node.PolynomialTerm.isPolynomialTerm(node)) { - const polyTerm = new Node.PolynomialTerm(node); +function printTreeTraversal(node, parentNode?) { + if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + const polyTerm = new mathNode.PolynomialTerm(node); // This is so we don't print 2/3 x^2 as 2 / 3x^2 // Still print x/2 as x/2 and not 1/2 x though if (polyTerm.hasFractionCoeff() && node.op !== '/') { const coeffTerm = polyTerm.getCoeffNode(); const coeffStr = printTreeTraversal(coeffTerm); - const nonCoeffTerm = Node.Creator.polynomialTerm( + const nonCoeffTerm = mathNode.Creator.polynomialTerm( polyTerm.symbol, polyTerm.exponent, null); const nonCoeffStr = printTreeTraversal(nonCoeffTerm); @@ -35,12 +33,12 @@ function printTreeTraversal(node, parentNode) { } } - if (Node.Type.isIntegerFraction(node)) { + if (mathNode.Type.isIntegerFraction(node)) { return `${node.args[0]}/${node.args[1]}`; } - if (Node.Type.isOperator(node)) { - if (node.op === '/' && Node.Type.isOperator(node.args[1])) { + if (mathNode.Type.isOperator(node)) { + if (node.op === '/' && mathNode.Type.isOperator(node.args[1])) { return `${printTreeTraversal(node.args[0])} / (${printTreeTraversal(node.args[1])})`; } @@ -60,7 +58,7 @@ function printTreeTraversal(node, parentNode) { break; case '/': // no space for constant fraction divisions (slightly easier to read) - if (Node.Type.isConstantFraction(node, true)) { + if (mathNode.Type.isConstantFraction(node, true)) { opString = `${node.op}`; } else { @@ -80,7 +78,7 @@ function printTreeTraversal(node, parentNode) { // Check #120, #126 issues for more details. // { "/" [{ "+" ["x", "2"] }, "2"] } -> (x + 2) / 2. if (parentNode && - Node.Type.isOperator(parentNode) && + mathNode.Type.isOperator(parentNode) && node.op && parentNode.op && '*/^'.indexOf(parentNode.op) >= 0 && '+-'.indexOf(node.op) >= 0) { @@ -89,13 +87,13 @@ function printTreeTraversal(node, parentNode) { return str; } - else if (Node.Type.isParenthesis(node)) { + else if (mathNode.Type.isParenthesis(node)) { return `(${printTreeTraversal(node.content)})`; } - else if (Node.Type.isUnaryMinus(node)) { - if (Node.Type.isOperator(node.args[0]) && + else if (mathNode.Type.isUnaryMinus(node)) { + if (mathNode.Type.isOperator(node.args[0]) && '*/^'.indexOf(node.args[0].op) === -1 && - !Node.PolynomialTerm.isPolynomialTerm(node)) { + !mathNode.PolynomialTerm.isPolynomialTerm(node)) { return `-(${printTreeTraversal(node.args[0])})`; } else { diff --git a/lib/util/removeUnnecessaryParens.ts b/lib/util/removeUnnecessaryParens.ts index 0a87a34c..f07d99d3 100644 --- a/lib/util/removeUnnecessaryParens.ts +++ b/lib/util/removeUnnecessaryParens.ts @@ -1,6 +1,6 @@ import checks = require('../checks'); import LikeTermCollector = require('../simplifyExpression/collectAndCombineSearch/LikeTermCollector'); -import Node = require('../node'); +import mathNode = require('../mathNode'); // Removes any parenthesis around nodes that can't be resolved further. // Input must be a top level expression. @@ -12,7 +12,7 @@ function removeUnnecessaryParens(node, rootNode=false) { // e.g. (2 + 3) * 4 can't become 2 + 3 * 4, but if (2 + 3) as a top level // expression can become 2 + 3 if (rootNode) { - while (Node.Type.isParenthesis(node)) { + while (mathNode.Type.isParenthesis(node)) { node = node.content; } } @@ -23,21 +23,20 @@ function removeUnnecessaryParens(node, rootNode=false) { // it doesn't change the value of the expression. Returns a node. // NOTE: after this function is called, every parenthesis node in the // tree should always have an operator node or unary minus as its child. -function removeUnnecessaryParensSearch(node: any); function removeUnnecessaryParensSearch(node) { - if (Node.Type.isOperator(node)) { + if (mathNode.Type.isOperator(node)) { return removeUnnecessaryParensInOperatorNode(node); } - else if (Node.Type.isFunction(node)) { + else if (mathNode.Type.isFunction(node)) { return removeUnnecessaryParensInFunctionNode(node); } - else if (Node.Type.isParenthesis(node)) { + else if (mathNode.Type.isParenthesis(node)) { return removeUnnecessaryParensInParenthesisNode(node); } - else if (Node.Type.isConstant(node, true) || Node.Type.isSymbol(node)) { + else if (mathNode.Type.isConstant(node, true) || mathNode.Type.isSymbol(node)) { return node; } - else if (Node.Type.isUnaryMinus(node)) { + else if (mathNode.Type.isUnaryMinus(node)) { const content = node.args[0]; node.args[0] = removeUnnecessaryParensSearch(content); return node; @@ -55,9 +54,9 @@ function removeUnnecessaryParensInOperatorNode(node) { // Special case: if the node is an exponent node and the base // is an operator, we should keep the parentheses for the base. // e.g. (2x)^2 -> (2x)^2 instead of 2x^2 - if (node.op === '^' && Node.Type.isParenthesis(node.args[0])) { + if (node.op === '^' && mathNode.Type.isParenthesis(node.args[0])) { const base = node.args[0]; - if (Node.Type.isOperator(base.content)) { + if (mathNode.Type.isOperator(base.content)) { base.content = removeUnnecessaryParensSearch(base.content); node.args[1] = removeUnnecessaryParensSearch(node.args[1]); @@ -75,7 +74,7 @@ function removeUnnecessaryParensInOperatorNode(node) { // e.g. (x+4) + 12 -> x+4 + 12 if (node.op === '+') { node.args.forEach((child, i) => { - if (Node.Type.isParenthesis(child) && + if (mathNode.Type.isParenthesis(child) && !canCollectOrCombine(child.content)) { // remove the parens by replacing the child node (in its args list) // with its content @@ -87,7 +86,7 @@ function removeUnnecessaryParensInOperatorNode(node) { //in parenthesis, we want to distribute the subtraction. // e.g. `(2 + x) - (1 + x)` => `2 + x - (1 + x)` not `2 + x - 1 + x` else if (node.op === '-') { - if (Node.Type.isParenthesis(node.args[0]) && + if (mathNode.Type.isParenthesis(node.args[0]) && !canCollectOrCombine(node.args[0].content)) { node.args[0] = node.args[0].content; } @@ -101,7 +100,7 @@ function removeUnnecessaryParensInOperatorNode(node) { function removeUnnecessaryParensInFunctionNode(node: any); function removeUnnecessaryParensInFunctionNode(node) { node.args.forEach((child, i) => { - if (Node.Type.isParenthesis(child)) { + if (mathNode.Type.isParenthesis(child)) { child = child.content; } node.args[i] = removeUnnecessaryParensSearch(child); @@ -120,7 +119,7 @@ function removeUnnecessaryParensInParenthesisNode(node: any); function removeUnnecessaryParensInParenthesisNode(node) { // polynomials terms can be complex trees (e.g. 3x^2/5) but don't need parens // around them - if (Node.PolynomialTerm.isPolynomialTerm(node.content)) { + if (mathNode.PolynomialTerm.isPolynomialTerm(node.content)) { // also recurse to remove any unnecessary parens within the term // (e.g. the exponent might have parens around it) if (node.content.args) { @@ -132,19 +131,19 @@ function removeUnnecessaryParensInParenthesisNode(node) { } // If the content is just one symbol or constant, the parens are not // needed. - else if (Node.Type.isConstant(node.content, true) || - Node.Type.isIntegerFraction(node.content) || - Node.Type.isSymbol(node.content)) { + else if (mathNode.Type.isConstant(node.content, true) || + mathNode.Type.isIntegerFraction(node.content) || + mathNode.Type.isSymbol(node.content)) { node = node.content; } // If the content is just one function call, the parens are not needed. - else if (Node.Type.isFunction(node.content)) { + else if (mathNode.Type.isFunction(node.content)) { node = node.content; node = removeUnnecessaryParensSearch(node); } // If there is an operation within the parens, then the parens are // likely needed. So, recurse. - else if (Node.Type.isOperator(node.content)) { + else if (mathNode.Type.isOperator(node.content)) { node.content = removeUnnecessaryParensSearch(node.content); // exponent nodes don't need parens around them if (node.content.op === '^') { @@ -154,10 +153,10 @@ function removeUnnecessaryParensInParenthesisNode(node) { // If the content is also parens, we have doubly nested parens. First // recurse on the child node, then set the current node equal to its child // to get rid of the extra parens. - else if (Node.Type.isParenthesis(node.content)) { + else if (mathNode.Type.isParenthesis(node.content)) { node = removeUnnecessaryParensSearch(node.content); } - else if (Node.Type.isUnaryMinus(node.content)) { + else if (mathNode.Type.isUnaryMinus(node.content)) { node.content = removeUnnecessaryParensSearch(node.content); } else { @@ -169,7 +168,6 @@ function removeUnnecessaryParensInParenthesisNode(node) { // Returns true if any of the collect or combine steps can be applied to the // expression tree `node`. -function canCollectOrCombine(node: any); function canCollectOrCombine(node) { return LikeTermCollector.canCollectLikeTerms(node) || checks.resolvesToConstant(node) || From a0d46dea79b6c12587950cee55eac80c6817a367 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Mon, 10 Apr 2017 22:46:29 -0700 Subject: [PATCH 03/12] Add typings for mathjs.MathNodes, add typings file, remove uncessary function overloads. --- index.ts | 6 +- lib/ChangeTypes.ts | 138 +++++----- lib/Negative.js | 8 +- lib/Negative.js.map | 2 +- lib/Negative.ts | 16 +- lib/Symbols.ts | 14 +- lib/TreeSearch.ts | 12 +- lib/checks/canAddLikeTermPolynomialNodes.js | 29 +++ .../canAddLikeTermPolynomialNodes.js.map | 1 + lib/checks/canAddLikeTermPolynomialNodes.ts | 7 +- .../canMultiplyLikeTermPolynomialNodes.js | 26 ++ .../canMultiplyLikeTermPolynomialNodes.js.map | 1 + .../canMultiplyLikeTermPolynomialNodes.ts | 7 +- lib/checks/canRearrangeCoefficient.js | 22 ++ lib/checks/canRearrangeCoefficient.js.map | 1 + lib/checks/canRearrangeCoefficient.ts | 7 +- lib/checks/canSimplifyPolynomialTerms.js | 2 + lib/checks/canSimplifyPolynomialTerms.js.map | 2 +- lib/checks/canSimplifyPolynomialTerms.ts | 9 +- lib/checks/hasUnsupportedNodes.js | 4 +- lib/checks/hasUnsupportedNodes.ts | 11 +- lib/checks/index.ts | 14 +- lib/checks/isQuadratic.js | 47 ++++ lib/checks/isQuadratic.js.map | 1 + lib/checks/isQuadratic.ts | 10 +- lib/checks/resolvesToConstant.js | 2 +- lib/checks/resolvesToConstant.ts | 7 +- lib/equation/Equation.js | 3 +- lib/equation/Equation.js.map | 2 +- lib/equation/Equation.ts | 15 +- lib/equation/Status.js | 6 +- lib/equation/Status.js.map | 2 +- lib/equation/Status.ts | 14 +- lib/equation/index.ts | 4 +- lib/factor/ConstantFactors.js | 16 +- lib/factor/ConstantFactors.js.map | 2 +- lib/factor/ConstantFactors.ts | 4 +- lib/factor/factorQuadratic.js | 184 ++++++++++++++ lib/factor/factorQuadratic.js.map | 1 + lib/factor/factorQuadratic.ts | 57 ++--- lib/mathNode/Creator.ts | 40 +-- lib/mathNode/PolynomialTerm.js | 171 +++++++++++++ lib/mathNode/PolynomialTerm.js.map | 1 + lib/mathNode/PolynomialTerm.ts | 47 ++-- lib/mathNode/Status.ts | 32 ++- lib/mathNode/Type.js | 110 ++++++++ lib/mathNode/Type.js.map | 1 + lib/mathNode/Type.ts | 37 +-- lib/mathNode/index.ts | 8 +- .../arithmeticSearch/index.ts | 12 +- lib/simplifyExpression/basicsSearch/index.js | 59 +++++ .../basicsSearch/index.js.map | 1 + lib/simplifyExpression/basicsSearch/index.ts | 35 ++- .../basicsSearch/rearrangeCoefficient.js | 21 ++ .../basicsSearch/rearrangeCoefficient.js.map | 1 + .../basicsSearch/rearrangeCoefficient.ts | 11 +- .../basicsSearch/reduceExponentByZero.js | 20 ++ .../basicsSearch/reduceExponentByZero.js.map | 1 + .../basicsSearch/reduceExponentByZero.ts | 11 +- .../reduceMultiplicationByZero.js | 28 +++ .../reduceMultiplicationByZero.js.map | 1 + .../reduceMultiplicationByZero.ts | 11 +- .../reduceZeroDividedByAnything.js | 19 ++ .../reduceZeroDividedByAnything.js.map | 1 + .../reduceZeroDividedByAnything.ts | 11 +- .../basicsSearch/removeAdditionOfZero.js | 26 ++ .../basicsSearch/removeAdditionOfZero.js.map | 1 + .../basicsSearch/removeAdditionOfZero.ts | 13 +- .../basicsSearch/removeDivisionByOne.js | 39 +++ .../basicsSearch/removeDivisionByOne.js.map | 1 + .../basicsSearch/removeDivisionByOne.ts | 13 +- .../basicsSearch/removeExponentBaseOne.js | 19 ++ .../basicsSearch/removeExponentBaseOne.js.map | 1 + .../basicsSearch/removeExponentBaseOne.ts | 15 +- .../basicsSearch/removeExponentByOne.js | 17 ++ .../basicsSearch/removeExponentByOne.js.map | 1 + .../basicsSearch/removeExponentByOne.ts | 13 +- .../removeMultiplicationByNegativeOne.js | 44 ++++ .../removeMultiplicationByNegativeOne.js.map | 1 + .../removeMultiplicationByNegativeOne.ts | 15 +- .../basicsSearch/removeMultiplicationByOne.js | 28 +++ .../removeMultiplicationByOne.js.map | 1 + .../basicsSearch/removeMultiplicationByOne.ts | 12 +- .../basicsSearch/simplifyDoubleUnaryMinus.js | 32 +++ .../simplifyDoubleUnaryMinus.js.map | 1 + .../basicsSearch/simplifyDoubleUnaryMinus.ts | 11 +- .../breakUpNumeratorSearch/index.js | 38 +++ .../breakUpNumeratorSearch/index.js.map | 1 + .../breakUpNumeratorSearch/index.ts | 17 +- .../LikeTermCollector.js | 236 ++++++++++++++++++ .../LikeTermCollector.js.map | 1 + .../LikeTermCollector.ts | 104 ++++---- .../collectAndCombineSearch/addLikeTerms.js | 2 +- .../collectAndCombineSearch/addLikeTerms.ts | 23 +- .../evaluateConstantSum.js | 12 +- .../evaluateConstantSum.ts | 24 +- .../collectAndCombineSearch/index.ts | 18 +- .../multiplyLikeTerms.ts | 14 +- .../distributeSearch/index.js | 28 +-- .../distributeSearch/index.ts | 72 +++--- .../divisionSearch/index.js | 68 +++++ .../divisionSearch/index.js.map | 1 + .../divisionSearch/index.ts | 32 ++- .../fractionsSearch/addConstantAndFraction.js | 12 +- .../addConstantAndFraction.js.map | 2 +- .../fractionsSearch/addConstantAndFraction.ts | 23 +- .../fractionsSearch/addConstantFractions.ts | 49 ++-- .../fractionsSearch/cancelLikeTerms.ts | 29 ++- .../fractionsSearch/divideByGCD.js | 50 ++++ .../fractionsSearch/divideByGCD.js.map | 1 + .../fractionsSearch/divideByGCD.ts | 17 +- .../fractionsSearch/index.js | 6 +- .../fractionsSearch/index.js.map | 2 +- .../fractionsSearch/index.ts | 22 +- .../fractionsSearch/simplifyFractionSigns.js | 34 +++ .../simplifyFractionSigns.js.map | 1 + .../fractionsSearch/simplifyFractionSigns.ts | 14 +- .../simplifyPolynomialFraction.js | 7 +- .../simplifyPolynomialFraction.js.map | 2 +- .../simplifyPolynomialFraction.ts | 13 +- .../functionsSearch/absoluteValue.js | 33 +++ .../functionsSearch/absoluteValue.js.map | 1 + .../functionsSearch/absoluteValue.ts | 17 +- .../functionsSearch/index.js | 28 +++ .../functionsSearch/index.js.map | 1 + .../functionsSearch/index.ts | 11 +- .../functionsSearch/nthRoot.ts | 106 ++++---- lib/simplifyExpression/index.ts | 4 +- .../multiplyFractionsSearch/index.js | 17 +- .../multiplyFractionsSearch/index.js.map | 2 +- .../multiplyFractionsSearch/index.ts | 21 +- lib/simplifyExpression/simplify.js | 2 + lib/simplifyExpression/simplify.js.map | 2 +- lib/simplifyExpression/simplify.ts | 16 +- lib/simplifyExpression/stepThrough.js | 14 +- lib/simplifyExpression/stepThrough.js.map | 2 +- lib/simplifyExpression/stepThrough.ts | 50 ++-- lib/solveEquation/EquationOperations.js | 68 ++--- lib/solveEquation/EquationOperations.js.map | 2 +- lib/solveEquation/EquationOperations.ts | 88 +++---- lib/solveEquation/index.js | 2 +- lib/solveEquation/index.ts | 6 +- lib/solveEquation/stepThrough.js | 36 +-- lib/solveEquation/stepThrough.js.map | 2 +- lib/solveEquation/stepThrough.ts | 66 +++-- lib/util/Util.js | 22 +- lib/util/Util.js.map | 2 +- lib/util/flattenOperands.ts | 62 ++--- lib/util/print.js | 98 ++++++++ lib/util/print.js.map | 1 + lib/util/print.ts | 30 +-- lib/util/removeUnnecessaryParens.js | 142 +++++++++++ lib/util/removeUnnecessaryParens.js.map | 1 + lib/util/removeUnnecessaryParens.ts | 18 +- package.json | 1 + test/Negative.test.ts | 30 +-- test/Node/PolynomialTerm.test.ts | 30 +-- test/Node/Type.test.ts | 80 +++--- test/TestUtil.ts | 28 +-- test/canAddLikeTermPolynomialNodes.test.ts | 12 +- ...canMultiplyLikeTermPolynomialNodes.test.ts | 12 +- test/canRearrangeCoefficient.test.ts | 10 +- test/checks/checks.test.ts | 28 +-- test/checks/hasUnsupportedNodes.test.ts | 24 +- test/checks/isQuadratic.test.ts | 38 +-- test/checks/resolvesToConstant.test.ts | 16 +- test/equation.test.ts | 14 +- test/factor/ConstantFactors.test.ts | 8 +- test/factor/factorQuadratic.test.ts | 50 ++-- .../arithmeticSearch/arithmeticSearch.test.ts | 12 +- .../basicsSearch/rearrangeCoefficient.test.ts | 10 +- .../basicsSearch/reduceExponentByZero.test.ts | 8 +- .../reduceMutliplicationByZero.test.ts | 10 +- .../reduceZeroDividedByAnything.test.ts | 10 +- .../basicsSearch/removeAdditionOfZero.test.ts | 12 +- .../basicsSearch/removeDivisionByOne.test.ts | 8 +- .../removeExponentBaseOne.test.ts | 12 +- .../basicsSearch/removeExponentByOne.test.ts | 8 +- .../removeMultiplicationByNegativeOne.test.ts | 12 +- .../removeMultiplicationByOne.test.ts | 14 +- .../simplifyDoubleUnaryMinus.test.ts | 10 +- .../basicsSearch/testSimplify.ts | 10 +- .../breakUpNumeratorSearch.test.ts | 12 +- .../LikeTermCollector.test.ts | 76 +++--- .../collectAndCombineSearch.test.ts | 64 ++--- .../evaluateConstantSum.test.ts | 38 +-- .../distributeSearch/distributeSearch.test.ts | 74 +++--- .../divisionSearch/divisionSearch.test.ts | 22 +- .../addConstantAndFraction.test.ts | 34 +-- .../addConstantFractions.test.ts | 46 ++-- .../fractionsSearch/cancelLikeTerms.test.ts | 34 +-- .../fractionsSearch/divideByGCD.test.ts | 24 +- .../simplifyFractionSigns.test.ts | 10 +- .../simplifyPolynomialFraction.test.ts | 20 +- .../functionsSearch/absoluteValue.test.ts | 10 +- .../functionsSearch/nthRoot.test.ts | 96 +++---- .../multiplyFractionsSearch.test.ts | 12 +- test/simplifyExpression/oneStep.test.ts | 72 +++--- test/simplifyExpression/simplify.test.ts | 192 +++++++------- test/solveEquation/solveEquation.test.ts | 144 +++++------ test/util/Util.test.ts | 20 +- test/util/flattenOperands.test.ts | 92 +++---- test/util/print.test.ts | 44 ++-- test/util/removeUnnecessaryParens.test.ts | 36 +-- 204 files changed, 3501 insertions(+), 1846 deletions(-) create mode 100644 lib/checks/canAddLikeTermPolynomialNodes.js create mode 100644 lib/checks/canAddLikeTermPolynomialNodes.js.map create mode 100644 lib/checks/canMultiplyLikeTermPolynomialNodes.js create mode 100644 lib/checks/canMultiplyLikeTermPolynomialNodes.js.map create mode 100644 lib/checks/canRearrangeCoefficient.js create mode 100644 lib/checks/canRearrangeCoefficient.js.map create mode 100644 lib/checks/isQuadratic.js create mode 100644 lib/checks/isQuadratic.js.map create mode 100644 lib/factor/factorQuadratic.js create mode 100644 lib/factor/factorQuadratic.js.map create mode 100644 lib/mathNode/PolynomialTerm.js create mode 100644 lib/mathNode/PolynomialTerm.js.map create mode 100644 lib/mathNode/Type.js create mode 100644 lib/mathNode/Type.js.map create mode 100644 lib/simplifyExpression/basicsSearch/index.js create mode 100644 lib/simplifyExpression/basicsSearch/index.js.map create mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js create mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map create mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.js create mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map create mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js create mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map create mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js create mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map create mode 100644 lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js create mode 100644 lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map create mode 100644 lib/simplifyExpression/basicsSearch/removeDivisionByOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map create mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map create mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map create mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map create mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js create mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map create mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js create mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map create mode 100644 lib/simplifyExpression/breakUpNumeratorSearch/index.js create mode 100644 lib/simplifyExpression/breakUpNumeratorSearch/index.js.map create mode 100644 lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js create mode 100644 lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map create mode 100644 lib/simplifyExpression/divisionSearch/index.js create mode 100644 lib/simplifyExpression/divisionSearch/index.js.map create mode 100644 lib/simplifyExpression/fractionsSearch/divideByGCD.js create mode 100644 lib/simplifyExpression/fractionsSearch/divideByGCD.js.map create mode 100644 lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js create mode 100644 lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map create mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.js create mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.js.map create mode 100644 lib/simplifyExpression/functionsSearch/index.js create mode 100644 lib/simplifyExpression/functionsSearch/index.js.map create mode 100644 lib/util/print.js create mode 100644 lib/util/print.js.map create mode 100644 lib/util/removeUnnecessaryParens.js create mode 100644 lib/util/removeUnnecessaryParens.js.map diff --git a/index.ts b/index.ts index 451a4634..7df68bd6 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,6 @@ -import ChangeTypes = require('./lib/ChangeTypes'); -import simplifyExpression = require('./lib/simplifyExpression'); -import solveEquation = require('./lib/solveEquation'); +import ChangeTypes = require("./lib/ChangeTypes"); +import simplifyExpression = require("./lib/simplifyExpression"); +import solveEquation = require("./lib/solveEquation"); var tmp; tmp = { simplifyExpression, diff --git a/lib/ChangeTypes.ts b/lib/ChangeTypes.ts index d713b5ba..c90e6510 100644 --- a/lib/ChangeTypes.ts +++ b/lib/ChangeTypes.ts @@ -2,185 +2,185 @@ var tmp; tmp = { - NO_CHANGE: 'NO_CHANGE', + NO_CHANGE: "NO_CHANGE", // ARITHMETIC // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 - SIMPLIFY_ARITHMETIC: 'SIMPLIFY_ARITHMETIC', + SIMPLIFY_ARITHMETIC: "SIMPLIFY_ARITHMETIC", // BASICS // e.g. 2/-1 -> -2 - DIVISION_BY_NEGATIVE_ONE: 'DIVISION_BY_NEGATIVE_ONE', + DIVISION_BY_NEGATIVE_ONE: "DIVISION_BY_NEGATIVE_ONE", // e.g. 2/1 -> 2 - DIVISION_BY_ONE: 'DIVISION_BY_ONE', + DIVISION_BY_ONE: "DIVISION_BY_ONE", // e.g. x * 0 -> 0 - MULTIPLY_BY_ZERO: 'MULTIPLY_BY_ZERO', + MULTIPLY_BY_ZERO: "MULTIPLY_BY_ZERO", // e.g. x * 2 -> 2x - REARRANGE_COEFF: 'REARRANGE_COEFF', + REARRANGE_COEFF: "REARRANGE_COEFF", // e.g. x ^ 0 -> 1 - REDUCE_EXPONENT_BY_ZERO: 'REDUCE_EXPONENT_BY_ZERO', + REDUCE_EXPONENT_BY_ZERO: "REDUCE_EXPONENT_BY_ZERO", // e.g. 0/1 -> 0 - REDUCE_ZERO_NUMERATOR: 'REDUCE_ZERO_NUMERATOR', + REDUCE_ZERO_NUMERATOR: "REDUCE_ZERO_NUMERATOR", // e.g. 2 + 0 -> 2 - REMOVE_ADDING_ZERO: 'REMOVE_ADDING_ZERO', + REMOVE_ADDING_ZERO: "REMOVE_ADDING_ZERO", // e.g. x ^ 1 -> x - REMOVE_EXPONENT_BY_ONE: 'REMOVE_EXPONENT_BY_ONE', + REMOVE_EXPONENT_BY_ONE: "REMOVE_EXPONENT_BY_ONE", // e.g. 1 ^ x -> 1 - REMOVE_EXPONENT_BASE_ONE: 'REMOVE_EXPONENT_BASE_ONE', + REMOVE_EXPONENT_BASE_ONE: "REMOVE_EXPONENT_BASE_ONE", // e.g. x * -1 -> -x - REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: 'REMOVE_MULTIPLYING_BY_NEGATIVE_ONE', + REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: "REMOVE_MULTIPLYING_BY_NEGATIVE_ONE", // e.g. x * 1 -> x - REMOVE_MULTIPLYING_BY_ONE: 'REMOVE_MULTIPLYING_BY_ONE', + REMOVE_MULTIPLYING_BY_ONE: "REMOVE_MULTIPLYING_BY_ONE", // e.g. 2 - - 3 -> 2 + 3 - RESOLVE_DOUBLE_MINUS: 'RESOLVE_DOUBLE_MINUS', + RESOLVE_DOUBLE_MINUS: "RESOLVE_DOUBLE_MINUS", // COLLECT AND COMBINE // e.g. 2 + x + 3 + x -> 5 + 2x - COLLECT_AND_COMBINE_LIKE_TERMS: 'COLLECT_AND_COMBINE_LIKE_TERMS', + COLLECT_AND_COMBINE_LIKE_TERMS: "COLLECT_AND_COMBINE_LIKE_TERMS", // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) - COLLECT_LIKE_TERMS: 'COLLECT_LIKE_TERMS', + COLLECT_LIKE_TERMS: "COLLECT_LIKE_TERMS", // ADDING POLYNOMIALS // e.g. 2x + x -> 2x + 1x - ADD_COEFFICIENT_OF_ONE: 'ADD_COEFFICIENT_OF_ONE', + ADD_COEFFICIENT_OF_ONE: "ADD_COEFFICIENT_OF_ONE", // e.g. x^2 + x^2 -> 2x^2 - ADD_POLYNOMIAL_TERMS: 'ADD_POLYNOMIAL_TERMS', + ADD_POLYNOMIAL_TERMS: "ADD_POLYNOMIAL_TERMS", // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 - GROUP_COEFFICIENTS: 'GROUP_COEFFICIENTS', + GROUP_COEFFICIENTS: "GROUP_COEFFICIENTS", // e.g. -x + 2x => -1*x + 2x - UNARY_MINUS_TO_NEGATIVE_ONE: 'UNARY_MINUS_TO_NEGATIVE_ONE', + UNARY_MINUS_TO_NEGATIVE_ONE: "UNARY_MINUS_TO_NEGATIVE_ONE", // MULTIPLYING POLYNOMIALS // e.g. x^2 * x -> x^2 * x^1 - ADD_EXPONENT_OF_ONE: 'ADD_EXPONENT_OF_ONE', + ADD_EXPONENT_OF_ONE: "ADD_EXPONENT_OF_ONE", // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) - COLLECT_EXPONENTS: 'COLLECT_EXPONENTS', + COLLECT_EXPONENTS: "COLLECT_EXPONENTS", // e.g. 2x * 3x -> (2 * 3)(x * x) - MULTIPLY_COEFFICIENTS: 'MULTIPLY_COEFFICIENTS', + MULTIPLY_COEFFICIENTS: "MULTIPLY_COEFFICIENTS", // e.g. 2x * x -> 2x ^ 2 - MULTIPLY_POLYNOMIAL_TERMS: 'MULTIPLY_POLYNOMIAL_TERMS', + MULTIPLY_POLYNOMIAL_TERMS: "MULTIPLY_POLYNOMIAL_TERMS", // FRACTIONS // e.g. (x + 2)/2 -> x/2 + 2/2 - BREAK_UP_FRACTION: 'BREAK_UP_FRACTION', + BREAK_UP_FRACTION: "BREAK_UP_FRACTION", // e.g. -2/-3 => 2/3 - CANCEL_MINUSES: 'CANCEL_MINUSES', + CANCEL_MINUSES: "CANCEL_MINUSES", // e.g. 2x/2 -> x - CANCEL_TERMS: 'CANCEL_TERMS', + CANCEL_TERMS: "CANCEL_TERMS", // e.g. 2/6 -> 1/3 - SIMPLIFY_FRACTION: 'SIMPLIFY_FRACTION', + SIMPLIFY_FRACTION: "SIMPLIFY_FRACTION", // e.g. 2/-3 -> -2/3 - SIMPLIFY_SIGNS: 'SIMPLIFY_SIGNS', + SIMPLIFY_SIGNS: "SIMPLIFY_SIGNS", // ADDING FRACTIONS // e.g. 1/2 + 1/3 -> 5/6 - ADD_FRACTIONS: 'ADD_FRACTIONS', + ADD_FRACTIONS: "ADD_FRACTIONS", // e.g. (1 + 2)/3 -> 3/3 - ADD_NUMERATORS: 'ADD_NUMERATORS', + ADD_NUMERATORS: "ADD_NUMERATORS", // e.g. (2+1)/5 - COMBINE_NUMERATORS: 'COMBINE_NUMERATORS', + COMBINE_NUMERATORS: "COMBINE_NUMERATORS", // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) - COMMON_DENOMINATOR: 'COMMON_DENOMINATOR', + COMMON_DENOMINATOR: "COMMON_DENOMINATOR", // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) - CONVERT_INTEGER_TO_FRACTION: 'CONVERT_INTEGER_TO_FRACTION', + CONVERT_INTEGER_TO_FRACTION: "CONVERT_INTEGER_TO_FRACTION", // e.g. 1.2 + 1/2 -> 1.2 + 0.5 - DIVIDE_FRACTION_FOR_ADDITION: 'DIVIDE_FRACTION_FOR_ADDITION', + DIVIDE_FRACTION_FOR_ADDITION: "DIVIDE_FRACTION_FOR_ADDITION", // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 - MULTIPLY_DENOMINATORS: 'MULTIPLY_DENOMINATORS', + MULTIPLY_DENOMINATORS: "MULTIPLY_DENOMINATORS", // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 - MULTIPLY_NUMERATORS: 'MULTIPLY_NUMERATORS', + MULTIPLY_NUMERATORS: "MULTIPLY_NUMERATORS", // MULTIPLYING FRACTIONS // e.g. 1/2 * 2/3 -> 2/6 - MULTIPLY_FRACTIONS: 'MULTIPLY_FRACTIONS', + MULTIPLY_FRACTIONS: "MULTIPLY_FRACTIONS", // DIVISION // e.g. 2/3/4 -> 2/(3*4) - SIMPLIFY_DIVISION: 'SIMPLIFY_DIVISION', + SIMPLIFY_DIVISION: "SIMPLIFY_DIVISION", // e.g. x/(2/3) -> x * 3/2 - MULTIPLY_BY_INVERSE: 'MULTIPLY_BY_INVERSE', + MULTIPLY_BY_INVERSE: "MULTIPLY_BY_INVERSE", // DISTRIBUTION // e.g. 2(x + y) -> 2x + 2y - DISTRIBUTE: 'DISTRIBUTE', + DISTRIBUTE: "DISTRIBUTE", // e.g. -(2 + x) -> -2 - x - DISTRIBUTE_NEGATIVE_ONE: 'DISTRIBUTE_NEGATIVE_ONE', + DISTRIBUTE_NEGATIVE_ONE: "DISTRIBUTE_NEGATIVE_ONE", // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) - SIMPLIFY_TERMS: 'SIMPLIFY_TERMS', + SIMPLIFY_TERMS: "SIMPLIFY_TERMS", // ABSOLUTE // e.g. |-3| -> 3 - ABSOLUTE_VALUE: 'ABSOLUTE_VALUE', + ABSOLUTE_VALUE: "ABSOLUTE_VALUE", // ROOTS // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) - CANCEL_EXPONENT: 'CANCEL_EXPONENT', + CANCEL_EXPONENT: "CANCEL_EXPONENT", // e.g. nthRoot(x ^ 2, 2) -> x - CANCEL_EXPONENT_AND_ROOT: 'CANCEL_EXPONENT_AND_ROOT', + CANCEL_EXPONENT_AND_ROOT: "CANCEL_EXPONENT_AND_ROOT", // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 - CANCEL_ROOT: 'CANCEL_ROOT', + CANCEL_ROOT: "CANCEL_ROOT", // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) - COMBINE_UNDER_ROOT: 'COMBINE_UNDER_ROOT', + COMBINE_UNDER_ROOT: "COMBINE_UNDER_ROOT", // e.g. 2 * 2 * 2 -> 2 ^ 3 - CONVERT_MULTIPLICATION_TO_EXPONENT: 'CONVERT_MULTIPLICATION_TO_EXPONENT', + CONVERT_MULTIPLICATION_TO_EXPONENT: "CONVERT_MULTIPLICATION_TO_EXPONENT", // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) - DISTRIBUTE_NTH_ROOT: 'DISTRIBUTE_NTH_ROOT', + DISTRIBUTE_NTH_ROOT: "DISTRIBUTE_NTH_ROOT", // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x - EVALUATE_DISTRIBUTED_NTH_ROOT: 'EVALUATE_DISTRIBUTED_NTH_ROOT', + EVALUATE_DISTRIBUTED_NTH_ROOT: "EVALUATE_DISTRIBUTED_NTH_ROOT", // e.g. 12 -> 2 * 2 * 3 - FACTOR_INTO_PRIMES: 'FACTOR_INTO_PRIMES', + FACTOR_INTO_PRIMES: "FACTOR_INTO_PRIMES", // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) - GROUP_TERMS_BY_ROOT: 'GROUP_TERMS_BY_ROOT', + GROUP_TERMS_BY_ROOT: "GROUP_TERMS_BY_ROOT", // e.g. nthRoot(4) -> 2 - NTH_ROOT_VALUE: 'NTH_ROOT_VALUE', + NTH_ROOT_VALUE: "NTH_ROOT_VALUE", // SOLVING FOR A VARIABLE // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 - ADD_TO_BOTH_SIDES: 'ADD_TO_BOTH_SIDES', + ADD_TO_BOTH_SIDES: "ADD_TO_BOTH_SIDES", // e.g. 2x = 1 -> (2x)/2 = 1/2 - DIVIDE_FROM_BOTH_SIDES: 'DIVIDE_FROM_BOTH_SIDES', + DIVIDE_FROM_BOTH_SIDES: "DIVIDE_FROM_BOTH_SIDES", // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) - MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: 'MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION', + MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: "MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION", // e.g. -x = 2 -> -1 * -x = -1 * 2 - MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: 'MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE', + MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: "MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE", // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 - MULTIPLY_TO_BOTH_SIDES: 'MULTIPLY_TO_BOTH_SIDES', + MULTIPLY_TO_BOTH_SIDES: "MULTIPLY_TO_BOTH_SIDES", // e.g. x + 2 - 1 = 3 -> x + 1 = 3 - SIMPLIFY_LEFT_SIDE: 'SIMPLIFY_LEFT_SIDE', + SIMPLIFY_LEFT_SIDE: "SIMPLIFY_LEFT_SIDE", // e.g. x = 3 - 1 -> x = 2 - SIMPLIFY_RIGHT_SIDE: 'SIMPLIFY_RIGHT_SIDE', + SIMPLIFY_RIGHT_SIDE: "SIMPLIFY_RIGHT_SIDE", // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 - SUBTRACT_FROM_BOTH_SIDES: 'SUBTRACT_FROM_BOTH_SIDES', + SUBTRACT_FROM_BOTH_SIDES: "SUBTRACT_FROM_BOTH_SIDES", // e.g. 2 = x -> x = 2 - SWAP_SIDES: 'SWAP_SIDES', + SWAP_SIDES: "SWAP_SIDES", // CONSTANT EQUATION // e.g. 2 = 2 - STATEMENT_IS_TRUE: 'STATEMENT_IS_TRUE', + STATEMENT_IS_TRUE: "STATEMENT_IS_TRUE", // e.g. 2 = 3 - STATEMENT_IS_FALSE: 'STATEMENT_IS_FALSE', + STATEMENT_IS_FALSE: "STATEMENT_IS_FALSE", // FACTORING // e.g. x^2 - 4x -> x(x - 4) - FACTOR_SYMBOL: 'FACTOR_SYMBOL', + FACTOR_SYMBOL: "FACTOR_SYMBOL", // e.g. x^2 - 4 -> (x - 2)(x + 2) - FACTOR_DIFFERENCE_OF_SQUARES: 'FACTOR_DIFFERENCE_OF_SQUARES', + FACTOR_DIFFERENCE_OF_SQUARES: "FACTOR_DIFFERENCE_OF_SQUARES", // e.g. x^2 + 2x + 1 -> (x + 1)^2 - FACTOR_PERFECT_SQUARE: 'FACTOR_PERFECT_SQUARE', + FACTOR_PERFECT_SQUARE: "FACTOR_PERFECT_SQUARE", // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) - FACTOR_SUM_PRODUCT_RULE: 'FACTOR_SUM_PRODUCT_RULE', + FACTOR_SUM_PRODUCT_RULE: "FACTOR_SUM_PRODUCT_RULE", }; export = tmp; diff --git a/lib/Negative.js b/lib/Negative.js index be84655b..9ad59ce0 100644 --- a/lib/Negative.js +++ b/lib/Negative.js @@ -60,7 +60,7 @@ var Negative = (function () { Negative.negatePolynomialTerm = function (node, naive) { if (naive === void 0) { naive = false; } if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { - throw Error('node is not a polynomial term'); + throw Error("node is not a polynomial term"); } var polyNode = new mathNode.PolynomialTerm(node); var newCoeff; @@ -69,18 +69,18 @@ var Negative = (function () { } else { var oldCoeff = polyNode.getCoeffNode(); - if (oldCoeff.value === '-1') { + if (oldCoeff.value === "-1") { newCoeff = null; } else if (polyNode.hasFractionCoeff()) { var numerator = oldCoeff.args[0]; numerator = Negative.negate(numerator, naive); var denominator = oldCoeff.args[1]; - newCoeff = mathNode.Creator.operator('/', [numerator, denominator]); + newCoeff = mathNode.Creator.operator("/", [numerator, denominator]); } else { newCoeff = Negative.negate(oldCoeff, naive); - if (newCoeff.value === '1') { + if (newCoeff.value === "1") { newCoeff = null; } } diff --git a/lib/Negative.js.map b/lib/Negative.js.map index c289cc26..b82cc6b8 100644 --- a/lib/Negative.js.map +++ b/lib/Negative.js.map @@ -1 +1 @@ -{"version":3,"file":"Negative.js","sourceRoot":"","sources":["Negative.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Negative.js","sourceRoot":"","sources":["Negative.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Negative.ts b/lib/Negative.ts index f4736873..dbb23e53 100644 --- a/lib/Negative.ts +++ b/lib/Negative.ts @@ -1,10 +1,10 @@ -import mathNode = require('./mathNode'); +import mathNode = require("./mathNode"); class Negative { // Returns if the given node is negative. Treats a unary minus as a negative, // as well as a negative constant value or a constant fraction that would // evaluate to a negative number - static isNegative(node) { + static isNegative(node: mathjs.MathNode) { if (mathNode.Type.isUnaryMinus(node)) { return !Negative.isNegative(node.args[0]); } else if (mathNode.Type.isConstant(node)) { @@ -29,7 +29,7 @@ class Negative { // E.g. // not naive: -3 -> 3, x -> -x // naive: -3 -> --3, x -> -x - static negate(node, naive=false) { + static negate(node: mathjs.MathNode, naive: boolean=false) { if (mathNode.Type.isConstantFraction(node)) { node.args[0] = Negative.negate(node.args[0], naive); return node; @@ -51,9 +51,9 @@ class Negative { // E.g. // not naive: -3x -> 3x, x -> -x // naive: -3x -> --3x, x -> -x - static negatePolynomialTerm(node, naive=false) { + static negatePolynomialTerm(node: mathjs.MathNode, naive: boolean = false) { if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { - throw Error('node is not a polynomial term'); + throw Error("node is not a polynomial term"); } const polyNode = new mathNode.PolynomialTerm(node); @@ -62,17 +62,17 @@ class Negative { newCoeff = mathNode.Creator.constant(-1); } else { const oldCoeff = polyNode.getCoeffNode(); - if (oldCoeff.value === '-1') { + if (oldCoeff.value === "-1") { newCoeff = null; } else if (polyNode.hasFractionCoeff()) { let numerator = oldCoeff.args[0]; numerator = Negative.negate(numerator, naive); const denominator = oldCoeff.args[1]; - newCoeff = mathNode.Creator.operator('/', [numerator, denominator]); + newCoeff = mathNode.Creator.operator("/", [numerator, denominator]); } else { newCoeff = Negative.negate(oldCoeff, naive); - if (newCoeff.value === '1') { + if (newCoeff.value === "1") { newCoeff = null; } } diff --git a/lib/Symbols.ts b/lib/Symbols.ts index cdf93c82..1a6ea217 100644 --- a/lib/Symbols.ts +++ b/lib/Symbols.ts @@ -1,4 +1,4 @@ -import mathNode = require('./mathNode'); +import mathNode = require("./mathNode"); class Symbols { // returns the set of all the symbols in an equation @@ -23,15 +23,15 @@ class Symbols { // e.g. 4x^2 + 2x + y + 2 with `symbolName=x` would return 2x static getLastSymbolTerm = (node, symbolName) => { // First check if the node itself is a polyomial term with symbolName - if (this.isSymbolTerm(node, symbolName)) { + if (Symbols.isSymbolTerm(node, symbolName)) { return node; } // Otherwise, it's a sum of terms. Look through the operands for a term // with `symbolName` - else if (mathNode.Type.isOperator(node, '+')) { + else if (mathNode.Type.isOperator(node, "+")) { for (let i = node.args.length - 1; i >= 0; i--) { const child = node.args[i]; - if (this.isSymbolTerm(child, symbolName)) { + if (Symbols.isSymbolTerm(child, symbolName)) { return child; } } @@ -46,12 +46,12 @@ class Symbols { // e.g. 4x^2 + 2x + 2/4 with `symbolName=x` would return 2/4 // e.g. 4x^2 + 2x + y with `symbolName=x` would return y static getLastNonSymbolTerm = (node, symbolName) => { - if (this.isSymbolTerm(node, symbolName)) { + if (Symbols.isSymbolTerm(node, symbolName)) { return new mathNode.PolynomialTerm(node).getCoeffNode(); } else if (mathNode.Type.isOperator(node)) { for (let i = node.args.length - 1; i >= 0; i--) { const child = node.args[i]; - if (!this.isSymbolTerm(child, symbolName)) { + if (!Symbols.isSymbolTerm(child, symbolName)) { return child; } } @@ -61,7 +61,7 @@ class Symbols { }; // Returns if `node` is a polynomial term with symbol `symbolName` - isSymbolTerm(node, symbolName) { + static isSymbolTerm(node: mathjs.MathNode, symbolName) { if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { const polyTerm = new mathNode.PolynomialTerm(node); if (polyTerm.getSymbolName() === symbolName) { diff --git a/lib/TreeSearch.ts b/lib/TreeSearch.ts index b70ab6a7..e7643b8d 100644 --- a/lib/TreeSearch.ts +++ b/lib/TreeSearch.ts @@ -1,18 +1,18 @@ -import mathNode = require('./mathNode'); - +/// +import mathNode = require("./mathNode"); class TreeSearch { // Returns a function that performs a preorder search on the tree for the given // simplifcation function - static preOrder = simplificationFunction => node => this.search(simplificationFunction, node, true); + static preOrder = simplificationFunction => node => TreeSearch.search(simplificationFunction, node, true); // Returns a function that performs a postorder search on the tree for the given // simplifcation function - static postOrder = simplificationFunction => node => this.search(simplificationFunction, node, false); + static postOrder = simplificationFunction => node => TreeSearch.search(simplificationFunction, node, false); // A helper function for performing a tree search with a function - search(simplificationFunction, node, preOrder) { + static search(simplificationFunction, node: mathjs.MathNode, preOrder) { let status; if (preOrder) { @@ -43,7 +43,7 @@ class TreeSearch { return mathNode.Status.childChanged(node, status); } } else { - throw Error('Unsupported node type: ' + node); + throw Error("Unsupported node type: " + node); } if (!preOrder) { diff --git a/lib/checks/canAddLikeTermPolynomialNodes.js b/lib/checks/canAddLikeTermPolynomialNodes.js new file mode 100644 index 00000000..c64d4384 --- /dev/null +++ b/lib/checks/canAddLikeTermPolynomialNodes.js @@ -0,0 +1,29 @@ +"use strict"; +var mathNode = require("../mathnode"); +// Returns true if the nodes are polynomial terms that can be added together. +function canAddLikeTermPolynomialNodes(node) { + if (!mathNode.Type.isOperator(node) || node.op !== "+") { + return false; + } + var args = node.args; + if (!args.every(function (n) { return mathNode.PolynomialTerm.isPolynomialTerm(n); })) { + return false; + } + if (args.length === 1) { + return false; + } + var polynomialTermList = args.map(function (n) { return new mathNode.PolynomialTerm(n); }); + // to add terms, they must have the same symbol name *and* exponent + var firstTerm = polynomialTermList[0]; + var sharedSymbol = firstTerm.getSymbolName(); + var sharedExponentNode = firstTerm.getExponentNode(true); + var restTerms = polynomialTermList.slice(1); + return restTerms.every(function (term) { + var haveSameSymbol = sharedSymbol === term.getSymbolName(); + var exponentNode = term.getExponentNode(true); + var haveSameExponent = exponentNode.equals(sharedExponentNode); + return haveSameSymbol && haveSameExponent; + }); +} +module.exports = canAddLikeTermPolynomialNodes; +//# sourceMappingURL=canAddLikeTermPolynomialNodes.js.map \ No newline at end of file diff --git a/lib/checks/canAddLikeTermPolynomialNodes.js.map b/lib/checks/canAddLikeTermPolynomialNodes.js.map new file mode 100644 index 00000000..47da1209 --- /dev/null +++ b/lib/checks/canAddLikeTermPolynomialNodes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"canAddLikeTermPolynomialNodes.js","sourceRoot":"","sources":["canAddLikeTermPolynomialNodes.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAEzC,6EAA6E;AAC7E,uCAAuC,IAAqB;IAC1D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAA,CAAC,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAA3C,CAA2C,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAA9B,CAA8B,CAAC,CAAC;IAEzE,mEAAmE;IACnE,IAAM,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACxC,IAAM,YAAY,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;IAC/C,IAAM,kBAAkB,GAAG,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3D,IAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,UAAA,IAAI;QACzB,IAAM,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7D,IAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAChD,IAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACjE,MAAM,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iBAAS,6BAA6B,CAAC"} \ No newline at end of file diff --git a/lib/checks/canAddLikeTermPolynomialNodes.ts b/lib/checks/canAddLikeTermPolynomialNodes.ts index 089f8994..fe82272c 100644 --- a/lib/checks/canAddLikeTermPolynomialNodes.ts +++ b/lib/checks/canAddLikeTermPolynomialNodes.ts @@ -1,9 +1,8 @@ -import mathNode = require('../mathnode'); +import mathNode = require("../mathnode"); // Returns true if the nodes are polynomial terms that can be added together. -function canAddLikeTermPolynomialNodes(node: any); -function canAddLikeTermPolynomialNodes(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '+') { +function canAddLikeTermPolynomialNodes(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "+") { return false; } const args = node.args; diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.js b/lib/checks/canMultiplyLikeTermPolynomialNodes.js new file mode 100644 index 00000000..7e1b5f8f --- /dev/null +++ b/lib/checks/canMultiplyLikeTermPolynomialNodes.js @@ -0,0 +1,26 @@ +"use strict"; +var mathNode = require("../mathnode"); +// Returns true if the nodes are symbolic terms with the same symbol and no +// coefficients. +function canMultiplyLikeTermPolynomialNodes(node) { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { + return false; + } + var args = node.args; + if (!args.every(function (n) { return mathNode.PolynomialTerm.isPolynomialTerm(n); })) { + return false; + } + if (args.length === 1) { + return false; + } + var polynomialTermList = node.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); + if (!polynomialTermList.every(function (polyTerm) { return !polyTerm.hasCoeff(); })) { + return false; + } + var firstTerm = polynomialTermList[0]; + var restTerms = polynomialTermList.slice(1); + // they're considered like terms if they have the same symbol name + return restTerms.every(function (term) { return firstTerm.getSymbolName() === term.getSymbolName(); }); +} +module.exports = canMultiplyLikeTermPolynomialNodes; +//# sourceMappingURL=canMultiplyLikeTermPolynomialNodes.js.map \ No newline at end of file diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.js.map b/lib/checks/canMultiplyLikeTermPolynomialNodes.js.map new file mode 100644 index 00000000..578b5d6a --- /dev/null +++ b/lib/checks/canMultiplyLikeTermPolynomialNodes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"canMultiplyLikeTermPolynomialNodes.js","sourceRoot":"","sources":["canMultiplyLikeTermPolynomialNodes.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAGzC,2EAA2E;AAC3E,gBAAgB;AAChB,4CAA4C,IAAqB;IAC/D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAA,CAAC,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAA3C,CAA2C,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAA9B,CAA8B,CAAC,CAAC;IAC9E,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,UAAA,QAAQ,IAAI,OAAA,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAApB,CAAoB,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACxC,IAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9C,kEAAkE;IAClE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,UAAA,IAAI,IAAI,OAAA,SAAS,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,aAAa,EAAE,EAAlD,CAAkD,CAAC,CAAC;AACrF,CAAC;AAED,iBAAS,kCAAkC,CAAC"} \ No newline at end of file diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.ts b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts index 10ab3134..8caed1a6 100644 --- a/lib/checks/canMultiplyLikeTermPolynomialNodes.ts +++ b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts @@ -1,11 +1,10 @@ -import mathNode = require('../mathnode'); +import mathNode = require("../mathnode"); // Returns true if the nodes are symbolic terms with the same symbol and no // coefficients. -function canMultiplyLikeTermPolynomialNodes(node: any); -function canMultiplyLikeTermPolynomialNodes(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '*') { +function canMultiplyLikeTermPolynomialNodes(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { return false; } const args = node.args; diff --git a/lib/checks/canRearrangeCoefficient.js b/lib/checks/canRearrangeCoefficient.js new file mode 100644 index 00000000..83028413 --- /dev/null +++ b/lib/checks/canRearrangeCoefficient.js @@ -0,0 +1,22 @@ +"use strict"; +var mathNode = require("../mathnode"); +function canRearrangeCoefficient(node) { + // implicit multiplication doesn't count as multiplication here, since it + // represents a single term. + if (node.op !== "*" || node.implicit) { + return false; + } + if (node.args.length !== 2) { + return false; + } + if (!mathNode.Type.isConstantOrConstantFraction(node.args[1])) { + return false; + } + if (!mathNode.PolynomialTerm.isPolynomialTerm(node.args[0])) { + return false; + } + var polyNode = new mathNode.PolynomialTerm(node.args[0]); + return !polyNode.hasCoeff(); +} +module.exports = canRearrangeCoefficient; +//# sourceMappingURL=canRearrangeCoefficient.js.map \ No newline at end of file diff --git a/lib/checks/canRearrangeCoefficient.js.map b/lib/checks/canRearrangeCoefficient.js.map new file mode 100644 index 00000000..e4ed75cb --- /dev/null +++ b/lib/checks/canRearrangeCoefficient.js.map @@ -0,0 +1 @@ +{"version":3,"file":"canRearrangeCoefficient.js","sourceRoot":"","sources":["canRearrangeCoefficient.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAMzC,iCAAiC,IAAI;IACnC,yEAAyE;IACzE,4BAA4B;IAC5B,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED,iBAAS,uBAAuB,CAAC"} \ No newline at end of file diff --git a/lib/checks/canRearrangeCoefficient.ts b/lib/checks/canRearrangeCoefficient.ts index ecb6f1e4..dcfd0c96 100644 --- a/lib/checks/canRearrangeCoefficient.ts +++ b/lib/checks/canRearrangeCoefficient.ts @@ -1,13 +1,12 @@ -import mathNode = require('../mathnode'); +import mathNode = require("../mathnode"); // Returns true if the expression is a multiplication between a constant // and polynomial without a coefficient. -function canRearrangeCoefficient(node: any); -function canRearrangeCoefficient(node) { +function canRearrangeCoefficient(node: mathjs.MathNode) { // implicit multiplication doesn't count as multiplication here, since it // represents a single term. - if (node.op !== '*' || node.implicit) { + if (node.op !== "*" || node.implicit) { return false; } if (node.args.length !== 2) { diff --git a/lib/checks/canSimplifyPolynomialTerms.js b/lib/checks/canSimplifyPolynomialTerms.js index a485d366..14680ce1 100644 --- a/lib/checks/canSimplifyPolynomialTerms.js +++ b/lib/checks/canSimplifyPolynomialTerms.js @@ -2,6 +2,8 @@ var canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); var canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); var canRearrangeCoefficient = require("./canRearrangeCoefficient"); +// Returns true if the node is an operation node with parameters that are +// polynomial terms that can be combined in some way. function canSimplifyPolynomialTerms(node) { return (canAddLikeTermPolynomialNodes(node) || canMultiplyLikeTermPolynomialNodes(node) || diff --git a/lib/checks/canSimplifyPolynomialTerms.js.map b/lib/checks/canSimplifyPolynomialTerms.js.map index 8e9fb471..7a2c6ed1 100644 --- a/lib/checks/canSimplifyPolynomialTerms.js.map +++ b/lib/checks/canSimplifyPolynomialTerms.js.map @@ -1 +1 @@ -{"version":3,"file":"canSimplifyPolynomialTerms.js","sourceRoot":"","sources":["canSimplifyPolynomialTerms.ts"],"names":[],"mappings":";AAAA,+EAAkF;AAClF,yFAA4F;AAC5F,mEAAsE;AAKtE,oCAAoC,IAAI;IACtC,MAAM,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC;QACnC,kCAAkC,CAAC,IAAI,CAAC;QACxC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file +{"version":3,"file":"canSimplifyPolynomialTerms.js","sourceRoot":"","sources":["canSimplifyPolynomialTerms.ts"],"names":[],"mappings":";AAAA,+EAAkF;AAClF,yFAA4F;AAC5F,mEAAsE;AAEtE,yEAAyE;AACzE,qDAAqD;AACrD,oCAAoC,IAAqB;IACvD,MAAM,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC;QACnC,kCAAkC,CAAC,IAAI,CAAC;QACxC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/checks/canSimplifyPolynomialTerms.ts b/lib/checks/canSimplifyPolynomialTerms.ts index 9ccad33e..0d2ff413 100644 --- a/lib/checks/canSimplifyPolynomialTerms.ts +++ b/lib/checks/canSimplifyPolynomialTerms.ts @@ -1,11 +1,10 @@ -import canAddLikeTermPolynomialNodes = require('./canAddLikeTermPolynomialNodes'); -import canMultiplyLikeTermPolynomialNodes = require('./canMultiplyLikeTermPolynomialNodes'); -import canRearrangeCoefficient = require('./canRearrangeCoefficient'); +import canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); +import canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); +import canRearrangeCoefficient = require("./canRearrangeCoefficient"); // Returns true if the node is an operation node with parameters that are // polynomial terms that can be combined in some way. -function canSimplifyPolynomialTerms(node: any); -function canSimplifyPolynomialTerms(node) { +function canSimplifyPolynomialTerms(node: mathjs.MathNode) { return (canAddLikeTermPolynomialNodes(node) || canMultiplyLikeTermPolynomialNodes(node) || canRearrangeCoefficient(node)); diff --git a/lib/checks/hasUnsupportedNodes.js b/lib/checks/hasUnsupportedNodes.js index ac956738..78e19f8d 100644 --- a/lib/checks/hasUnsupportedNodes.js +++ b/lib/checks/hasUnsupportedNodes.js @@ -14,7 +14,7 @@ function hasUnsupportedNodes(node) { else if (mathNode.Type.isSymbol(node) || mathNode.Type.isConstant(node)) { return false; } - else if (mathNode.Type.isFunction(node, 'abs')) { + else if (mathNode.Type.isFunction(node, "abs")) { if (node.args.length !== 1) { return true; } @@ -23,7 +23,7 @@ function hasUnsupportedNodes(node) { } return !resolvesToConstant(node.args[0]); } - else if (mathNode.Type.isFunction(node, 'nthRoot')) { + else if (mathNode.Type.isFunction(node, "nthRoot")) { return node.args.some(hasUnsupportedNodes) || node.args.length < 1; } else { diff --git a/lib/checks/hasUnsupportedNodes.ts b/lib/checks/hasUnsupportedNodes.ts index c5c1623d..e38dad45 100644 --- a/lib/checks/hasUnsupportedNodes.ts +++ b/lib/checks/hasUnsupportedNodes.ts @@ -1,8 +1,7 @@ -import mathNode = require('../mathnode'); -import resolvesToConstant = require('./resolvesToConstant'); +import mathNode = require("../mathnode"); +import resolvesToConstant = require("./resolvesToConstant"); -function hasUnsupportedNodes(node: any); -function hasUnsupportedNodes(node) { +function hasUnsupportedNodes(node: mathjs.MathNode) { if (mathNode.Type.isParenthesis(node)) { return hasUnsupportedNodes(node.content); } @@ -15,7 +14,7 @@ function hasUnsupportedNodes(node) { else if (mathNode.Type.isSymbol(node) || mathNode.Type.isConstant(node)) { return false; } - else if (mathNode.Type.isFunction(node, 'abs')) { + else if (mathNode.Type.isFunction(node, "abs")) { if (node.args.length !== 1) { return true; } @@ -24,7 +23,7 @@ function hasUnsupportedNodes(node) { } return !resolvesToConstant(node.args[0]); } - else if (mathNode.Type.isFunction(node, 'nthRoot')) { + else if (mathNode.Type.isFunction(node, "nthRoot")) { return node.args.some(hasUnsupportedNodes) || node.args.length < 1; } else { diff --git a/lib/checks/index.ts b/lib/checks/index.ts index eab47622..6db90d19 100644 --- a/lib/checks/index.ts +++ b/lib/checks/index.ts @@ -1,10 +1,10 @@ -import canAddLikeTermPolynomialNodes = require('./canAddLikeTermPolynomialNodes'); -import canMultiplyLikeTermPolynomialNodes = require('./canMultiplyLikeTermPolynomialNodes'); -import canRearrangeCoefficient = require('./canRearrangeCoefficient'); -import canSimplifyPolynomialTerms = require('./canSimplifyPolynomialTerms'); -import hasUnsupportedNodes = require('./hasUnsupportedNodes'); -import isQuadratic = require('./isQuadratic'); -import resolvesToConstant = require('./resolvesToConstant'); +import canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); +import canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); +import canRearrangeCoefficient = require("./canRearrangeCoefficient"); +import canSimplifyPolynomialTerms = require("./canSimplifyPolynomialTerms"); +import hasUnsupportedNodes = require("./hasUnsupportedNodes"); +import isQuadratic = require("./isQuadratic"); +import resolvesToConstant = require("./resolvesToConstant"); var tmp; tmp = { canAddLikeTermPolynomialNodes, diff --git a/lib/checks/isQuadratic.js b/lib/checks/isQuadratic.js new file mode 100644 index 00000000..6d75149c --- /dev/null +++ b/lib/checks/isQuadratic.js @@ -0,0 +1,47 @@ +"use strict"; +var mathNode = require("../mathnode"); +var Symbols = require("../Symbols"); +// Given a node, will determine if the expression is in the form of a quadratic +// e.g. `x^2 + 2x + 1` OR `x^2 - 1` but not `x^3 + x^2 + x + 1` +function isQuadratic(node) { + if (!mathNode.Type.isOperator(node, "+")) { + return false; + } + if (node.args.length > 3) { + return false; + } + // make sure only one symbol appears in the expression + var symbolSet = Symbols.getSymbolsInExpression(node); + if (symbolSet.size !== 1) { + return false; + } + var secondDegreeTerms = node.args.filter(isPolynomialTermOfDegree(2)); + var firstDegreeTerms = node.args.filter(isPolynomialTermOfDegree(1)); + var constantTerms = node.args.filter(mathNode.Type.isConstant); + // Check that there is one second degree term and at most one first degree + // term and at most one constant term + if (secondDegreeTerms.length !== 1 || firstDegreeTerms.length > 1 || + constantTerms.length > 1) { + return false; + } + // check that there are no terms that don't fall into these groups + if ((secondDegreeTerms.length + firstDegreeTerms.length + + constantTerms.length) !== node.args.length) { + return false; + } + return true; +} +// Given a degree, returns a function that checks if a node +// is a polynomial term of the given degree. +function isPolynomialTermOfDegree(degree) { + return function (node) { + if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + var polyTerm = new mathNode.PolynomialTerm(node); + var exponent = polyTerm.getExponentNode(true); + return exponent && parseFloat(exponent.value) === degree; + } + return false; + }; +} +module.exports = isQuadratic; +//# sourceMappingURL=isQuadratic.js.map \ No newline at end of file diff --git a/lib/checks/isQuadratic.js.map b/lib/checks/isQuadratic.js.map new file mode 100644 index 00000000..3f0d8433 --- /dev/null +++ b/lib/checks/isQuadratic.js.map @@ -0,0 +1 @@ +{"version":3,"file":"isQuadratic.js","sourceRoot":"","sources":["isQuadratic.ts"],"names":[],"mappings":";AAAA,sCAAyC;AACzC,oCAAuC;AAEvC,+EAA+E;AAC/E,+DAA+D;AAC/D,qBAAqB,IAAqB;IACxC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,sDAAsD;IACtD,IAAM,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACvD,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,IAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEjE,0EAA0E;IAC1E,qCAAqC;IACrC,EAAE,CAAC,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAC/D,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,kEAAkE;IAClE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM;QACnD,aAAa,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,IAAI,CAAC;AACd,CAAC;AAED,2DAA2D;AAC3D,4CAA4C;AAC5C,kCAAkC,MAAM;IACtC,MAAM,CAAC,UAAA,IAAI;QACP,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACnD,IAAM,QAAQ,GAAG,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;QAC7D,CAAC;QACD,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC,CAAC;AACJ,CAAC;AAED,iBAAS,WAAW,CAAC"} \ No newline at end of file diff --git a/lib/checks/isQuadratic.ts b/lib/checks/isQuadratic.ts index b2001504..5931035b 100644 --- a/lib/checks/isQuadratic.ts +++ b/lib/checks/isQuadratic.ts @@ -1,11 +1,10 @@ -import mathNode = require('../mathnode'); -import Symbols = require('../Symbols'); +import mathNode = require("../mathnode"); +import Symbols = require("../Symbols"); // Given a node, will determine if the expression is in the form of a quadratic // e.g. `x^2 + 2x + 1` OR `x^2 - 1` but not `x^3 + x^2 + x + 1` -function isQuadratic(node: any); -function isQuadratic(node) { - if (!mathNode.Type.isOperator(node, '+')) { +function isQuadratic(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node, "+")) { return false; } @@ -41,7 +40,6 @@ function isQuadratic(node) { // Given a degree, returns a function that checks if a node // is a polynomial term of the given degree. -function isPolynomialTermOfDegree(degree: any); function isPolynomialTermOfDegree(degree) { return node => { if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { diff --git a/lib/checks/resolvesToConstant.js b/lib/checks/resolvesToConstant.js index 065300d7..152f42e3 100644 --- a/lib/checks/resolvesToConstant.js +++ b/lib/checks/resolvesToConstant.js @@ -17,7 +17,7 @@ function resolvesToConstant(node) { return resolvesToConstant(node.args[0]); } else { - throw Error('Unsupported node type: ' + node.type); + throw Error("Unsupported node type: " + node.type); } } module.exports = resolvesToConstant; diff --git a/lib/checks/resolvesToConstant.ts b/lib/checks/resolvesToConstant.ts index ea6ce257..a5254335 100644 --- a/lib/checks/resolvesToConstant.ts +++ b/lib/checks/resolvesToConstant.ts @@ -1,11 +1,10 @@ -import mathNode = require('../mathnode'); +import mathNode = require("../mathnode"); // Returns true if the node is a constant or can eventually be resolved to // a constant. // e.g. 2, 2+4, (2+4)^2 would all return true. x + 4 would return false -function resolvesToConstant(node: any); -function resolvesToConstant(node) { +function resolvesToConstant(node: mathjs.MathNode) { if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { return node.args.every( (child) => resolvesToConstant(child)); @@ -23,7 +22,7 @@ function resolvesToConstant(node) { return resolvesToConstant(node.args[0]); } else { - throw Error('Unsupported node type: ' + node.type); + throw Error("Unsupported node type: " + node.type); } } diff --git a/lib/equation/Equation.js b/lib/equation/Equation.js index 86c23922..1ad13fdf 100644 --- a/lib/equation/Equation.js +++ b/lib/equation/Equation.js @@ -1,4 +1,5 @@ "use strict"; +/// var math = require("mathjs"); var clone = require("../util/clone"); var printNode = require("../util/print"); @@ -30,7 +31,7 @@ var Equation = (function () { Equation.createEquationFromString = function (str, comparator) { var sides = str.split(comparator); if (sides.length !== 2) { - throw Error('Expected two sides of an equation using comparator: ' + + throw Error("Expected two sides of an equation using comparator: " + comparator); } var leftNode = math.parse(sides[0]); diff --git a/lib/equation/Equation.js.map b/lib/equation/Equation.js.map index 12aa5e5c..e403cc39 100644 --- a/lib/equation/Equation.js.map +++ b/lib/equation/Equation.js.map @@ -1 +1 @@ -{"version":3,"file":"Equation.js","sourceRoot":"","sources":["Equation.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,qCAAwC;AACxC,yCAA4C;AAE5C,kEAAkE;AAClE,wDAAwD;AACxD;IACE,kBAAY,QAAQ,EAAE,SAAS,EAAE,UAAU;QACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,qDAAqD;IACrD,wBAAK,GAAL,UAAM,aAAmB;QAAnB,8BAAA,EAAA,qBAAmB;QACvB,IAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACzD,IAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC3D,IAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,MAAM,CAAI,QAAQ,SAAI,UAAU,SAAI,SAAW,CAAC;IAClD,CAAC;IAED,wBAAK,GAAL;QACE,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC;IAkBH,eAAC;AAAD,CAAC,AArCD;AAqBE,4EAA4E;AAC5E,qCAAqC;AAC9B,iCAAwB,GAAG,UAAC,GAAG,EAAE,UAAU;IAC9C,IAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC,sDAAsD;YAC9D,UAAU,CAAC,CAAC;IACpB,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC,CAAC;AAMJ,iBAAS,QAAQ,CAAC"} \ No newline at end of file +{"version":3,"file":"Equation.js","sourceRoot":"","sources":["Equation.ts"],"names":[],"mappings":";AAAA,mEAAmE;AACnE,6BAAgC;AAChC,qCAAwC;AACxC,yCAA4C;AAE5C,kEAAkE;AAClE,wDAAwD;AACxD;IACI,kBAAY,QAAyB,EAAE,SAA0B,EAAE,UAAU;QAC7E,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,qDAAqD;IACrD,wBAAK,GAAL,UAAM,aAAmB;QAAnB,8BAAA,EAAA,qBAAmB;QACvB,IAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACzD,IAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC3D,IAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,MAAM,CAAI,QAAQ,SAAI,UAAU,SAAI,SAAW,CAAC;IAClD,CAAC;IAED,wBAAK,GAAL;QACE,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC;IAkBH,eAAC;AAAD,CAAC,AArCD;AAqBE,4EAA4E;AAC5E,qCAAqC;AAC9B,iCAAwB,GAAG,UAAC,GAAG,EAAE,UAAU;IAC9C,IAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC,sDAAsD;YAC9D,UAAU,CAAC,CAAC;IACpB,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC,CAAC;AAMJ,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/equation/Equation.ts b/lib/equation/Equation.ts index dd29c8ec..4b818015 100644 --- a/lib/equation/Equation.ts +++ b/lib/equation/Equation.ts @@ -1,11 +1,12 @@ -import math = require('mathjs'); -import clone = require('../util/clone'); -import printNode = require('../util/print'); +/// +import math = require("mathjs"); +import clone = require("../util/clone"); +import printNode = require("../util/print"); // This represents an equation, made up of the leftNode (LHS), the // rightNode (RHS) and a comparator (=, <, >, <=, or >=) class Equation { - constructor(leftNode, rightNode, comparator) { + constructor(leftNode: mathjs.MathNode, rightNode: mathjs.MathNode, comparator) { this.leftNode = leftNode; this.rightNode = rightNode; this.comparator = comparator; @@ -30,7 +31,7 @@ class Equation { static createEquationFromString = (str, comparator) => { const sides = str.split(comparator); if (sides.length !== 2) { - throw Error('Expected two sides of an equation using comparator: ' + + throw Error("Expected two sides of an equation using comparator: " + comparator); } const leftNode = math.parse(sides[0]); @@ -38,8 +39,8 @@ class Equation { return new Equation(leftNode, rightNode, comparator); }; - leftNode; - rightNode; + leftNode: mathjs.MathNode; + rightNode: mathjs.MathNode; comparator; } diff --git a/lib/equation/Status.js b/lib/equation/Status.js index 42c8a507..b79f4dff 100644 --- a/lib/equation/Status.js +++ b/lib/equation/Status.js @@ -10,10 +10,10 @@ var Status = (function () { function Status(changeType, oldEquation, newEquation, substeps) { if (substeps === void 0) { substeps = []; } if (!newEquation) { - throw Error('new equation isn\'t defined'); + throw Error("new equation isn't defined"); } - if (changeType === undefined || typeof (changeType) !== 'string') { - throw Error('changetype isn\'t valid'); + if (changeType === undefined || typeof (changeType) !== "string") { + throw Error("changetype isn't valid"); } this.changeType = changeType; this.oldEquation = oldEquation; diff --git a/lib/equation/Status.js.map b/lib/equation/Status.js.map index bc75d320..6916524f 100644 --- a/lib/equation/Status.js.map +++ b/lib/equation/Status.js.map @@ -1 +1 @@ -{"version":3,"file":"Status.js","sourceRoot":"","sources":["Status.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Status.js","sourceRoot":"","sources":["Status.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/equation/Status.ts b/lib/equation/Status.ts index ec928993..dc786c63 100644 --- a/lib/equation/Status.ts +++ b/lib/equation/Status.ts @@ -1,18 +1,18 @@ -import ChangeTypes = require('../ChangeTypes'); -import Equation = require('./Equation'); -import mathNode = require('../mathNode'); +import ChangeTypes = require("../ChangeTypes"); +import Equation = require("./Equation"); +import mathNode = require("../mathNode"); // This represents the current equation we're solving. // As we move step by step, an equation might be updated. Functions return this // status object to pass on the updated equation and information on if/how it was // changed. class Status { - constructor(changeType, oldEquation, newEquation, substeps=[]) { + constructor(changeType, oldEquation: Equation, newEquation: Equation, substeps=[]) { if (!newEquation) { - throw Error('new equation isn\'t defined'); + throw Error("new equation isn't defined"); } - if (changeType === undefined || typeof(changeType) !== 'string') { - throw Error('changetype isn\'t valid'); + if (changeType === undefined || typeof(changeType) !== "string") { + throw Error("changetype isn't valid"); } this.changeType = changeType; diff --git a/lib/equation/index.ts b/lib/equation/index.ts index 574fa000..504bb3e3 100644 --- a/lib/equation/index.ts +++ b/lib/equation/index.ts @@ -1,5 +1,5 @@ -import Equation = require('./Equation'); -import Status = require('./Status'); +import Equation = require("./Equation"); +import Status = require("./Status"); var tmp; tmp = { Equation, diff --git a/lib/factor/ConstantFactors.js b/lib/factor/ConstantFactors.js index 8e1cf69b..01b4b0a4 100644 --- a/lib/factor/ConstantFactors.js +++ b/lib/factor/ConstantFactors.js @@ -1,16 +1,16 @@ // This module deals with getting constant factors, including prime factors // and factor pairs of a number "use strict"; -var constantFactors = (function () { - function constantFactors() { +var ConstantFactors = (function () { + function ConstantFactors() { } // Given a number, will return all the prime factors of that number as a list // sorted from smallest to largest - constantFactors.prototype.getPrimeFactors = function (number) { + ConstantFactors.getPrimeFactors = function (number) { var factors = []; if (number < 0) { factors = [-1]; - factors = factors.concat(ConstantFactors.getPrimeFactors(-1 * number)); + factors = factors.concat(this.getPrimeFactors(-1 * number)); return factors; } var root = Math.sqrt(number); @@ -27,14 +27,14 @@ var constantFactors = (function () { } else { factors.push(candidate); - factors = factors.concat(ConstantFactors.getPrimeFactors(number / candidate)); + factors = factors.concat(this.getPrimeFactors(number / candidate)); } return factors; }; ; // Given a number, will return all the factor pairs for that number as a list // of 2-item lists - constantFactors.prototype.getFactorPairs = function (number) { + ConstantFactors.getFactorPairs = function (number) { var factors = []; var bound = Math.floor(Math.sqrt(Math.abs(number))); for (var divisor = -bound; divisor <= bound; divisor++) { @@ -49,7 +49,7 @@ var constantFactors = (function () { return factors; }; ; - return constantFactors; + return ConstantFactors; }()); -module.exports = constantFactors; +module.exports = ConstantFactors; //# sourceMappingURL=ConstantFactors.js.map \ No newline at end of file diff --git a/lib/factor/ConstantFactors.js.map b/lib/factor/ConstantFactors.js.map index d1edf44a..6a7163b4 100644 --- a/lib/factor/ConstantFactors.js.map +++ b/lib/factor/ConstantFactors.js.map @@ -1 +1 @@ -{"version":3,"file":"ConstantFactors.js","sourceRoot":"","sources":["ConstantFactors.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,+BAA+B;;AAE/B;IAAA;IAqDA,CAAC;IAnDD,6EAA6E;IAC7E,kCAAkC;IAC9B,yCAAe,GAAf,UAAgB,MAAa;QACzB,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACf,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;YACvE,MAAM,CAAC,OAAO,CAAC;QACnB,CAAC;QAED,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,SAAS,GAAG,CAAC,CAAC,CAAC,mBAAmB;YAClC,OAAO,MAAM,GAAG,SAAS,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC7C,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC;QAED,8CAA8C;QAC9C,EAAE,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAGD,IAAI,CAAC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IAEN,6EAA6E;IAC7E,kBAAkB;IACd,wCAAc,GAAd,UAAe,MAAa;QACxB,IAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,IAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YACrD,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBAChB,QAAQ,CAAC;YACb,CAAC;YACD,EAAE,CAAC,CAAC,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IACN,sBAAC;AAAD,CAAC,AArDD,IAqDC;AAED,iBAAS,eAAe,CAAC"} \ No newline at end of file +{"version":3,"file":"ConstantFactors.js","sourceRoot":"","sources":["ConstantFactors.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,+BAA+B;;AAE/B;IAAA;IAqDA,CAAC;IAnDD,6EAA6E;IAC7E,kCAAkC;IACvB,+BAAe,GAAtB,UAAuB,MAAa;QAChC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACf,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;YAC5D,MAAM,CAAC,OAAO,CAAC;QACnB,CAAC;QAED,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,SAAS,GAAG,CAAC,CAAC,CAAC,mBAAmB;YAClC,OAAO,MAAM,GAAG,SAAS,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC7C,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC;QAED,8CAA8C;QAC9C,EAAE,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAGD,IAAI,CAAC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IAEN,6EAA6E;IAC7E,kBAAkB;IACP,8BAAc,GAArB,UAAsB,MAAa;QAC/B,IAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,IAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YACrD,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBAChB,QAAQ,CAAC;YACb,CAAC;YACD,EAAE,CAAC,CAAC,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IACN,sBAAC;AAAD,CAAC,AArDD,IAqDC;AAED,iBAAS,eAAe,CAAC"} \ No newline at end of file diff --git a/lib/factor/ConstantFactors.ts b/lib/factor/ConstantFactors.ts index c987e6ee..6b5c4af8 100644 --- a/lib/factor/ConstantFactors.ts +++ b/lib/factor/ConstantFactors.ts @@ -1,7 +1,7 @@ // This module deals with getting constant factors, including prime factors // and factor pairs of a number -class constantFactors { +class ConstantFactors { // Given a number, will return all the prime factors of that number as a list // sorted from smallest to largest @@ -56,4 +56,4 @@ class constantFactors { }; } -export = constantFactors; +export = ConstantFactors; diff --git a/lib/factor/factorQuadratic.js b/lib/factor/factorQuadratic.js new file mode 100644 index 00000000..556b5c2a --- /dev/null +++ b/lib/factor/factorQuadratic.js @@ -0,0 +1,184 @@ +"use strict"; +/// +var math = require("mathjs"); +var ConstantFactors = require("./ConstantFactors"); +var ChangeTypes = require("../ChangeTypes"); +var checks = require("../checks"); +var evaluate = require("../util/evaluate"); +var flatten = require("../util/flattenOperands"); +var Negative = require("../Negative"); +var mathNode = require("../mathNode"); +var factorFunctions = [ + // factor just the symbol e.g. x^2 + 2x -> x(x + 2) + factorSymbol, + // factor difference of squares e.g. x^2 - 4 + factorDifferenceOfSquares, + // factor perfect square e.g. x^2 + 2x + 1 + factorPerfectSquare, + // factor sum product rule e.g. x^2 + 3x + 2 + factorSumProductRule +]; +// Given a node, will check if it's in the form of a quadratic equation +// `ax^2 + bx + c`, and +// if it is, will factor it using one of the following rules: +// - Factor out the symbol e.g. x^2 + 2x -> x(x + 2) +// - Difference of squares e.g. x^2 - 4 -> (x+2)(x-2) +// - Perfect square e.g. x^2 + 2x + 1 -> (x+1)^2 +// - Sum/product rule e.g. x^2 + 3x + 2 -> (x+1)(x+2) +// - TODO: quadratic formula +// requires us simplify the following only within the parens: +// a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a) +function factorQuadratic(node) { + node = flatten(node); + if (!checks.isQuadratic(node)) { + return mathNode.Status.noChange(node); + } + // get a, b and c + var symbol, aValue = 0, bValue = 0, cValue = 0; + for (var _i = 0, _a = node.args; _i < _a.length; _i++) { + var term = _a[_i]; + if (mathNode.Type.isConstant(term)) { + cValue = evaluate(term); + } + else if (mathNode.PolynomialTerm.isPolynomialTerm(term)) { + var polyTerm = new mathNode.PolynomialTerm(term); + var exponent = polyTerm.getExponentNode(true); + if (exponent.value === "2") { + symbol = polyTerm.getSymbolNode(); + aValue = polyTerm.getCoeffValue(); + } + else if (exponent.value === "1") { + bValue = polyTerm.getCoeffValue(); + } + else { + return mathNode.Status.noChange(node); + } + } + else { + return mathNode.Status.noChange(node); + } + } + if (!symbol || !aValue) { + return mathNode.Status.noChange(node); + } + var negate = false; + if (aValue < 0) { + negate = true; + aValue = -aValue; + bValue = -bValue; + cValue = -cValue; + } + for (var i = 0; i < factorFunctions.length; i++) { + var nodeStatus = factorFunctions[i](node, symbol, aValue, bValue, cValue, negate); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + } + return mathNode.Status.noChange(node); +} +// Will factor the node if it's in the form of ax^2 + bx +function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { + if (!bValue || cValue) { + return mathNode.Status.noChange(node); + } + var gcd = math.gcd(aValue, bValue); + var gcdNode = mathNode.Creator.constant(gcd); + var aNode = mathNode.Creator.constant(aValue / gcd); + var bNode = mathNode.Creator.constant(bValue / gcd); + var factoredNode = mathNode.Creator.polynomialTerm(symbol, null, gcdNode); + var polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aNode); + var paren = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [polyTerm, bNode])); + var newNode = mathNode.Creator.operator("*", [factoredNode, paren], true); + if (negate) { + newNode = Negative.negate(newNode); + } + return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_SYMBOL, node, newNode); +} +// Will factor the node if it's in the form of ax^2 - c, and the aValue +// and cValue are perfect squares +// e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) +function factorDifferenceOfSquares(node, symbol, aValue, bValue, cValue, negate) { + // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, + // (iii) c is negative + if (bValue || !cValue) { + return mathNode.Status.noChange(node); + } + var aRootValue = Math.sqrt(Math.abs(aValue)); + var cRootValue = Math.sqrt(Math.abs(cValue)); + // must be a difference of squares + if ((aRootValue % 1 === 0) && + (cRootValue % 1 === 0) && + cValue < 0) { + var aRootNode = mathNode.Creator.constant(aRootValue); + var cRootNode = mathNode.Creator.constant(cRootValue); + var polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); + var firstParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [polyTerm, cRootNode])); + var secondParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("-", [polyTerm, cRootNode])); + // create node in difference of squares form + var newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); + if (negate) { + newNode = Negative.negate(newNode); + } + return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_DIFFERENCE_OF_SQUARES, node, newNode); + } + return mathNode.Status.noChange(node); +} +// Will factor the node if it's in the form of ax^2 + bx + c, where a and c +// are perfect squares and b = 2*sqrt(a)*sqrt(c) +// e.g. x^2 + 2x + 1 -> (x + 1)^2 +function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { + // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) + if (!bValue || !cValue) { + return mathNode.Status.noChange(node); + } + var aRootValue = Math.sqrt(Math.abs(aValue)); + var cRootValue = Math.sqrt(Math.abs(cValue)); + // if the second term is negative, then the constant in the parens is + // subtracted: e.g. x^2 - 2x + 1 -> (x - 1)^2 + if (bValue < 0) { + cRootValue = cRootValue * -1; + } + // apply the perfect square test + var perfectProduct = 2 * aRootValue * cRootValue; + if ((aRootValue % 1 === 0) && + (cRootValue % 1 === 0) && + bValue === perfectProduct) { + var aRootNode = mathNode.Creator.constant(aRootValue); + var cRootNode = mathNode.Creator.constant(cRootValue); + var polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); + var paren = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [polyTerm, cRootNode])); + var exponent = mathNode.Creator.constant(2); + // create node in perfect square form + var newNode = mathNode.Creator.operator("^", [paren, exponent]); + if (negate) { + newNode = Negative.negate(newNode); + } + return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_PERFECT_SQUARE, node, newNode); + } + return mathNode.Status.noChange(node); +} +// Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by +// applying the sum product rule: finding factors of c that add up to b. +// e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) +function factorSumProductRule(node, symbol, aValue, bValue, cValue, negate) { + if (aValue === 1 && bValue && cValue) { + // try sum/product rule: find a factor pair of c that adds up to b + var factorPairs = ConstantFactors.getFactorPairs(cValue); + for (var _i = 0, factorPairs_1 = factorPairs; _i < factorPairs_1.length; _i++) { + var pair = factorPairs_1[_i]; + if (pair[0] + pair[1] === bValue) { + var firstParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[0])])); + var secondParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[1])])); + // create a node in the general factored form for expression + var newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); + if (negate) { + newNode = Negative.negate(newNode); + } + return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_SUM_PRODUCT_RULE, node, newNode); + } + } + } + return mathNode.Status.noChange(node); +} +module.exports = factorQuadratic; +//# sourceMappingURL=factorQuadratic.js.map \ No newline at end of file diff --git a/lib/factor/factorQuadratic.js.map b/lib/factor/factorQuadratic.js.map new file mode 100644 index 00000000..e4de1172 --- /dev/null +++ b/lib/factor/factorQuadratic.js.map @@ -0,0 +1 @@ +{"version":3,"file":"factorQuadratic.js","sourceRoot":"","sources":["factorQuadratic.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/factor/factorQuadratic.ts b/lib/factor/factorQuadratic.ts index efc0f51e..7a34a05e 100644 --- a/lib/factor/factorQuadratic.ts +++ b/lib/factor/factorQuadratic.ts @@ -1,12 +1,13 @@ -import math = require('mathjs'); -import ConstantFactors = require('./ConstantFactors'); -import ChangeTypes = require('../ChangeTypes'); -import checks = require('../checks'); -import evaluate = require('../util/evaluate'); -import flatten = require('../util/flattenOperands'); -import Negative = require('../Negative'); -import mathNode = require('../mathNode'); -const FACTOR_FUNCTIONS = [ +/// +import math = require("mathjs"); +import ConstantFactors = require("./ConstantFactors"); +import ChangeTypes = require("../ChangeTypes"); +import checks = require("../checks"); +import evaluate = require("../util/evaluate"); +import flatten = require("../util/flattenOperands"); +import Negative = require("../Negative"); +import mathNode = require("../mathNode"); +const factorFunctions = [ // factor just the symbol e.g. x^2 + 2x -> x(x + 2) factorSymbol, // factor difference of squares e.g. x^2 - 4 @@ -27,7 +28,7 @@ const FACTOR_FUNCTIONS = [ // - TODO: quadratic formula // requires us simplify the following only within the parens: // a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a) -function factorQuadratic(node) { +function factorQuadratic(node: mathjs.MathNode) { node = flatten(node); if (!checks.isQuadratic(node)) { return mathNode.Status.noChange(node); @@ -42,11 +43,11 @@ function factorQuadratic(node) { else if (mathNode.PolynomialTerm.isPolynomialTerm(term)) { const polyTerm = new mathNode.PolynomialTerm(term); const exponent = polyTerm.getExponentNode(true); - if (exponent.value === '2') { + if (exponent.value === "2") { symbol = polyTerm.getSymbolNode(); aValue = polyTerm.getCoeffValue(); } - else if (exponent.value === '1') { + else if (exponent.value === "1") { bValue = polyTerm.getCoeffValue(); } else { @@ -70,8 +71,8 @@ function factorQuadratic(node) { cValue = -cValue; } - for (let i = 0; i < FACTOR_FUNCTIONS.length; i++) { - const nodeStatus = FACTOR_FUNCTIONS[i](node, symbol, aValue, bValue, cValue, negate); + for (let i = 0; i < factorFunctions.length; i++) { + const nodeStatus = factorFunctions[i](node, symbol, aValue, bValue, cValue, negate); if (nodeStatus.hasChanged()) { return nodeStatus; } @@ -81,7 +82,7 @@ function factorQuadratic(node) { } // Will factor the node if it's in the form of ax^2 + bx -function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { +function factorSymbol(node: mathjs.MathNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { if (!bValue || cValue) { return mathNode.Status.noChange(node); } @@ -94,9 +95,9 @@ function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { const factoredNode = mathNode.Creator.polynomialTerm(symbol, null, gcdNode); const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aNode); const paren = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', [polyTerm, bNode])); + mathNode.Creator.operator("+", [polyTerm, bNode])); - let newNode = mathNode.Creator.operator('*', [factoredNode, paren], true); + let newNode = mathNode.Creator.operator("*", [factoredNode, paren], true); if (negate) { newNode = Negative.negate(newNode); } @@ -107,7 +108,7 @@ function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { // Will factor the node if it's in the form of ax^2 - c, and the aValue // and cValue are perfect squares // e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) -function factorDifferenceOfSquares(node, symbol, aValue, bValue?, cValue?, negate?) { +function factorDifferenceOfSquares(node: mathjs.MathNode, symbol, aValue: number, bValue?: number, cValue?: number, negate?: boolean) { // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, // (iii) c is negative if (bValue || !cValue) { @@ -127,12 +128,12 @@ function factorDifferenceOfSquares(node, symbol, aValue, bValue?, cValue?, negat const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); const firstParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', [polyTerm, cRootNode])); + mathNode.Creator.operator("+", [polyTerm, cRootNode])); const secondParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator('-', [polyTerm, cRootNode])); + mathNode.Creator.operator("-", [polyTerm, cRootNode])); // create node in difference of squares form - let newNode = mathNode.Creator.operator('*', [firstParen, secondParen], true); + let newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); if (negate) { newNode = Negative.negate(newNode); } @@ -147,7 +148,7 @@ function factorDifferenceOfSquares(node, symbol, aValue, bValue?, cValue?, negat // Will factor the node if it's in the form of ax^2 + bx + c, where a and c // are perfect squares and b = 2*sqrt(a)*sqrt(c) // e.g. x^2 + 2x + 1 -> (x + 1)^2 -function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { +function factorPerfectSquare(node: mathjs.MathNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) if (!bValue || !cValue) { return mathNode.Status.noChange(node); @@ -173,11 +174,11 @@ function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); const paren = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', [polyTerm, cRootNode])); + mathNode.Creator.operator("+", [polyTerm, cRootNode])); const exponent = mathNode.Creator.constant(2); // create node in perfect square form - let newNode = mathNode.Creator.operator('^', [paren, exponent]); + let newNode = mathNode.Creator.operator("^", [paren, exponent]); if (negate) { newNode = Negative.negate(newNode); } @@ -192,19 +193,19 @@ function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { // Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by // applying the sum product rule: finding factors of c that add up to b. // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) -function factorSumProductRule(node, symbol, aValue, bValue, cValue, negate) { +function factorSumProductRule(node: mathjs.MathNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { if (aValue === 1 && bValue && cValue) { // try sum/product rule: find a factor pair of c that adds up to b const factorPairs = ConstantFactors.getFactorPairs(cValue); for (const pair of factorPairs) { if (pair[0] + pair[1] === bValue) { const firstParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', [symbol, mathNode.Creator.constant(pair[0])])); + mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[0])])); const secondParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', [symbol, mathNode.Creator.constant(pair[1])])); + mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[1])])); // create a node in the general factored form for expression - let newNode = mathNode.Creator.operator('*', [firstParen, secondParen], true); + let newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); if (negate) { newNode = Negative.negate(newNode); } diff --git a/lib/mathNode/Creator.ts b/lib/mathNode/Creator.ts index 6fef8f0d..d38b4a79 100644 --- a/lib/mathNode/Creator.ts +++ b/lib/mathNode/Creator.ts @@ -3,25 +3,25 @@ see http://mathjs.org/docs/expressions/expression_trees.html#nodes for more information on nodes in mathJS */ - -import math = require('mathjs'); -import NodeType = require('./Type'); -const NodeCreator = { +/// +import math = require("mathjs"); +import NodeType = require("./Type"); +const nodeCreator = { operator (op, args, implicit=false) { switch (op) { - case '+': - return new math.expression.node.OperatorNode('+', 'add', args); - case '-': - return new math.expression.node.OperatorNode('-', 'subtract', args); - case '/': - return new math.expression.node.OperatorNode('/', 'divide', args); - case '*': + case "+": + return new math.expression.OperatorNode("+", "add", args); + case "-": + return new math.expression.OperatorNode("-", "subtract", args); + case "/": + return new math.expression.node.OperatorNode("/", "divide", args); + case "*": return new math.expression.node.OperatorNode( - '*', 'multiply', args, implicit); - case '^': - return new math.expression.node.OperatorNode('^', 'pow', args); + "*", "multiply", args, implicit); + case "^": + return new math.expression.node.OperatorNode("^", "pow", args); default: - throw Error('Unsupported operation: ' + op); + throw Error("Unsupported operation: " + op); } }, @@ -29,7 +29,7 @@ const NodeCreator = { // unary minus to your node, rather than calling this constructor directly unaryMinus (content) { return new math.expression.node.OperatorNode( - '-', 'unaryMinus', [content]); + "-", "unaryMinus", [content]); }, constant (val) { @@ -50,7 +50,7 @@ const NodeCreator = { polynomialTerm (symbol, exponent, coeff, explicitCoeff=false) { let polyTerm = symbol; if (exponent) { - polyTerm = this.operator('^', [polyTerm, exponent]); + polyTerm = this.operator("^", [polyTerm, exponent]); } if (coeff && (explicitCoeff || parseFloat(coeff.value) !== 1)) { if (NodeType.isConstant(coeff) && @@ -60,7 +60,7 @@ const NodeCreator = { polyTerm = this.unaryMinus(polyTerm); } else { - polyTerm = this.operator('*', [coeff, polyTerm], true); + polyTerm = this.operator("*", [coeff, polyTerm], true); } } return polyTerm; @@ -68,8 +68,8 @@ const NodeCreator = { // Given a root value and a radicand (what is under the radical) nthRoot (radicandNode, rootNode) { - const symbol = NodeCreator.symbol('nthRoot'); + const symbol = nodeCreator.symbol("nthRoot"); return new math.expression.node.FunctionNode(symbol, [radicandNode, rootNode]); } }; -export = NodeCreator; +export = nodeCreator; diff --git a/lib/mathNode/PolynomialTerm.js b/lib/mathNode/PolynomialTerm.js new file mode 100644 index 00000000..0263e8bf --- /dev/null +++ b/lib/mathNode/PolynomialTerm.js @@ -0,0 +1,171 @@ +"use strict"; +var NodeCreator = require("./Creator"); +var NodeType = require("./Type"); +var evaluate = require("../util/evaluate"); +// For storing polynomial terms. +// Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. +// These expressions are of the form of a PolynomialTerm: x^2, 2y, z, 3x/5 +// These expressions are not: 4, x^(3+4), 2+x, 3*7, x-z +/* Fields: + - coeff: either a constant node or a fraction of two constant nodes + (might be null if no coefficient) + - symbol: the node with the symbol (e.g. in x^2, the node x) + - exponent: a node that can take any form, e.g. x^(2+x^2) + (might be null if no exponent) +*/ +var PolynomialTerm = (function () { + // if onlyImplicitMultiplication is true, an error will be thrown if `node` + // is a polynomial term without implicit multiplication + // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. + function PolynomialTerm(node, onlyImplicitMultiplication) { + if (onlyImplicitMultiplication === void 0) { onlyImplicitMultiplication = false; } + // Returns if the node represents an expression that can be considered a term. + // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. + // See the tests for some more thorough examples of exactly what counts and + // what does not. + this.isPolynomialTerm = function (node, onlyImplicitMultiplication) { + if (onlyImplicitMultiplication === void 0) { onlyImplicitMultiplication = false; } + try { + // will throw error if node isn't poly term + new PolynomialTerm(node, onlyImplicitMultiplication); + return true; + } + catch (err) { + return false; + } + }; + if (NodeType.isOperator(node)) { + if (node.op === "^") { + var symbolNode = node.args[0]; + if (!NodeType.isSymbol(symbolNode)) { + throw Error("Expected symbol term, got " + symbolNode); + } + this.symbol = symbolNode; + this.exponent = node.args[1]; + } + else if (node.op === "*") { + if (onlyImplicitMultiplication && !node.implicit) { + throw Error("Expected implicit multiplication"); + } + if (node.args.length !== 2) { + throw Error("Expected two arguments to *"); + } + var coeffNode = node.args[0]; + if (!NodeType.isConstantOrConstantFraction(coeffNode)) { + throw Error("Expected coefficient to be constant or fraction of " + + "constants term, got " + + coeffNode); + } + this.coeff = coeffNode; + var nonCoefficientTerm = new PolynomialTerm(node.args[1], onlyImplicitMultiplication); + if (nonCoefficientTerm.hasCoeff()) { + throw Error("Cannot have two coefficients " + + coeffNode + + " and " + + nonCoefficientTerm.getCoeffNode()); + } + this.symbol = nonCoefficientTerm.getSymbolNode(); + this.exponent = nonCoefficientTerm.getExponentNode(); + } + else if (node.op === "/") { + var denominatorNode = node.args[1]; + if (!NodeType.isConstant(denominatorNode)) { + throw Error("denominator must be constant node, instead of " + + denominatorNode); + } + var numeratorNode = new PolynomialTerm(node.args[0], onlyImplicitMultiplication); + if (numeratorNode.hasFractionCoeff()) { + throw Error("Polynomial terms cannot have nested fractions"); + } + this.exponent = numeratorNode.getExponentNode(); + this.symbol = numeratorNode.getSymbolNode(); + var numeratorConstantNode = numeratorNode.getCoeffNode(true); + this.coeff = NodeCreator.operator("/", [numeratorConstantNode, denominatorNode]); + } + else { + throw Error("Unsupported operatation for polynomial node: " + node.op); + } + } + else if (NodeType.isUnaryMinus(node)) { + var arg = node.args[0]; + if (NodeType.isParenthesis(arg)) { + arg = arg.content; + } + var polyNode = new PolynomialTerm(arg, onlyImplicitMultiplication); + this.exponent = polyNode.getExponentNode(); + this.symbol = polyNode.getSymbolNode(); + if (!polyNode.hasCoeff()) { + this.coeff = NodeCreator.constant(-1); + } + else { + this.coeff = this.negativeCoefficient(polyNode.getCoeffNode()); + } + } + else if (NodeType.isSymbol(node)) { + this.symbol = node; + } + else { + throw Error("Unsupported node type: " + node.type); + } + } + /* GETTER FUNCTIONS */ + PolynomialTerm.prototype.getSymbolNode = function () { + return this.symbol; + }; + PolynomialTerm.prototype.getSymbolName = function () { + return this.symbol.name; + }; + PolynomialTerm.prototype.getCoeffNode = function (defaultOne) { + if (defaultOne === void 0) { defaultOne = false; } + if (!this.coeff && defaultOne) { + return NodeCreator.constant(1); + } + else { + return this.coeff; + } + }; + PolynomialTerm.prototype.getCoeffValue = function () { + if (this.coeff) { + return evaluate(this.coeff); + } + else { + return 1; // no coefficient is like a coeff of 1 + } + }; + PolynomialTerm.prototype.getExponentNode = function (defaultOne) { + if (defaultOne === void 0) { defaultOne = false; } + if (!this.exponent && defaultOne) { + return NodeCreator.constant(1); + } + else { + return this.exponent; + } + }; + PolynomialTerm.prototype.getRootNode = function () { + return NodeCreator.polynomialTerm(this.symbol, this.exponent, this.coeff); + }; + // note: there is no exponent value getter function because the exponent + // can be any expresion and not necessarily a number. + /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ + // Returns true if the coefficient is a fraction + PolynomialTerm.prototype.hasFractionCoeff = function () { + // coeffNode is either a constant or a division operation. + return this.coeff && NodeType.isOperator(this.coeff); + }; + PolynomialTerm.prototype.hasCoeff = function () { + return !!this.coeff; + }; + PolynomialTerm.prototype.negativeCoefficient = function (node) { + if (NodeType.isConstant(node)) { + node = NodeCreator.constant(0 - parseFloat(node.value)); + } + else { + var numeratorValue = 0 - parseFloat(node.args[0].value); + node.args[0] = NodeCreator.constant(numeratorValue); + } + return node; + }; + return PolynomialTerm; +}()); +module.exports = PolynomialTerm; +//# sourceMappingURL=PolynomialTerm.js.map \ No newline at end of file diff --git a/lib/mathNode/PolynomialTerm.js.map b/lib/mathNode/PolynomialTerm.js.map new file mode 100644 index 00000000..cd740944 --- /dev/null +++ b/lib/mathNode/PolynomialTerm.js.map @@ -0,0 +1 @@ +{"version":3,"file":"PolynomialTerm.js","sourceRoot":"","sources":["PolynomialTerm.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/mathNode/PolynomialTerm.ts b/lib/mathNode/PolynomialTerm.ts index 75fb4270..6fd3decb 100644 --- a/lib/mathNode/PolynomialTerm.ts +++ b/lib/mathNode/PolynomialTerm.ts @@ -1,6 +1,7 @@ -import NodeCreator = require('./Creator'); -import NodeType = require('./Type'); -import evaluate = require('../util/evaluate'); +/// +import NodeCreator = require("./Creator"); +import NodeType = require("./Type"); +import evaluate = require("../util/evaluate"); // For storing polynomial terms. // Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. @@ -21,28 +22,28 @@ class PolynomialTerm { // if onlyImplicitMultiplication is true, an error will be thrown if `node` // is a polynomial term without implicit multiplication // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. - constructor(node, onlyImplicitMultiplication=false) { + constructor(node: mathjs.MathNode, onlyImplicitMultiplication=false) { if (NodeType.isOperator(node)) { - if (node.op === '^') { + if (node.op === "^") { const symbolNode = node.args[0]; if (!NodeType.isSymbol(symbolNode)) { - throw Error('Expected symbol term, got ' + symbolNode); + throw Error("Expected symbol term, got " + symbolNode); } this.symbol = symbolNode; this.exponent = node.args[1]; } // it's '*' ie it has a coefficient - else if (node.op === '*') { + else if (node.op === "*") { if (onlyImplicitMultiplication && !node.implicit) { - throw Error('Expected implicit multiplication'); + throw Error("Expected implicit multiplication"); } if (node.args.length !== 2) { - throw Error('Expected two arguments to *'); + throw Error("Expected two arguments to *"); } const coeffNode = node.args[0]; if (!NodeType.isConstantOrConstantFraction(coeffNode)) { - throw Error('Expected coefficient to be constant or fraction of ' + - 'constants term, got ' + + throw Error("Expected coefficient to be constant or fraction of " + + "constants term, got " + coeffNode); } this.coeff = coeffNode; @@ -50,35 +51,35 @@ class PolynomialTerm { node.args[1], onlyImplicitMultiplication); if (nonCoefficientTerm.hasCoeff()) { - throw Error('Cannot have two coefficients ' + + throw Error("Cannot have two coefficients " + coeffNode + - ' and ' + + " and " + nonCoefficientTerm.getCoeffNode()); } this.symbol = nonCoefficientTerm.getSymbolNode(); this.exponent = nonCoefficientTerm.getExponentNode(); } // this means there's a fraction coefficient - else if (node.op === '/') { + else if (node.op === "/") { const denominatorNode = node.args[1]; if (!NodeType.isConstant(denominatorNode)) { - throw Error('denominator must be constant node, instead of ' + + throw Error("denominator must be constant node, instead of " + denominatorNode); } const numeratorNode = new PolynomialTerm( node.args[0], onlyImplicitMultiplication); if (numeratorNode.hasFractionCoeff()) { - throw Error('Polynomial terms cannot have nested fractions'); + throw Error("Polynomial terms cannot have nested fractions"); } this.exponent = numeratorNode.getExponentNode(); this.symbol = numeratorNode.getSymbolNode(); const numeratorConstantNode = numeratorNode.getCoeffNode(true); this.coeff = NodeCreator.operator( - '/', + "/", [numeratorConstantNode, denominatorNode]); } else { - throw Error('Unsupported operatation for polynomial node: ' + node.op); + throw Error("Unsupported operatation for polynomial node: " + node.op); } } else if (NodeType.isUnaryMinus(node)) { var arg = node.args[0]; @@ -98,7 +99,7 @@ class PolynomialTerm { } else if (NodeType.isSymbol(node)) { this.symbol = node; } else { - throw Error('Unsupported node type: ' + node.type); + throw Error("Unsupported node type: " + node.type); } } @@ -161,10 +162,10 @@ class PolynomialTerm { // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. // See the tests for some more thorough examples of exactly what counts and // what does not. - isPolynomialTerm = (node, onlyImplicitMultiplication = false) => { + isPolynomialTerm = (node: mathjs.MathNode, onlyImplicitMultiplication = false) => { try { // will throw error if node isn't poly term - new PolynomialTerm(node, onlyImplicitMultiplication); + const temp = new PolynomialTerm(node, onlyImplicitMultiplication); return true; } catch (err) { return false; @@ -173,9 +174,7 @@ class PolynomialTerm { // Multiplies `node`, a constant or fraction of two constant nodes, by -1 // Returns a node - function - - negativeCoefficient(node) { + negativeCoefficient(node: mathjs.MathNode) { if (NodeType.isConstant(node)) { node = NodeCreator.constant(0 - parseFloat(node.value)); } else { diff --git a/lib/mathNode/Status.ts b/lib/mathNode/Status.ts index 19123696..aee097b6 100644 --- a/lib/mathNode/Status.ts +++ b/lib/mathNode/Status.ts @@ -1,19 +1,20 @@ -import clone = require('../util/clone'); -import ChangeTypes = require('../ChangeTypes'); -import Type = require('./Type'); +/// +import clone = require("../util/clone"); +import ChangeTypes = require("../ChangeTypes"); +import Type = require("./Type"); -// This represents the current (sub)expression we're simplifying. +// This represents the current (sub)exp+ ression we're simplifying. // As we move step by step, a node might be updated. Functions return this // status object to pass on the updated node and information on if/how it was // changed. // Status(node) creates a Status object that signals no change class Status { - constructor(changeType, oldNode, newNode, substeps=[]) { + constructor(changeType, oldNode: mathjs.MathNode, newNode: mathjs.MathNode, substeps=[]) { if (!newNode) { - throw Error('node is not defined'); + throw Error("node is not defined"); } - if (changeType === undefined || typeof(changeType) !== 'string') { - throw Error('changetype isn\'t valid'); + if (changeType === undefined || typeof(changeType) !== "string") { + throw Error("changetype isn't valid"); } this.changeType = changeType; @@ -25,7 +26,7 @@ class Status { hasChanged() { return this.changeType !== ChangeTypes.NO_CHANGE; } - static resetChangeGroups(node) { + static resetChangeGroups(node: mathjs.MathNode) { node = clone(node); node.filter(node => node.changeGroup).forEach(change => { delete change.changeGroup; @@ -34,13 +35,13 @@ class Status { }; // A wrapper around the Status constructor for the case where node hasn't // been changed. - noChange(node) { + noChange(node: mathjs.MathNode) { return new Status(ChangeTypes.NO_CHANGE, null, node); }; // A wrapper around the Status constructor for the case of a change // that is happening at the level of oldNode + newNode // e.g. 2 + 2 --> 4 (an addition node becomes a constant node) - Status.nodeChanged(changeType, oldNode, newNode, defaultChangeGroup = true, steps = []) { + nodeChanged(changeType, oldNode: mathjs.MathNode, newNode: mathjs.MathNode, defaultChangeGroup = true, steps = []) { if (defaultChangeGroup) { oldNode.changeGroup = 1; newNode.changeGroup = 1; @@ -52,16 +53,15 @@ class Status { // a change that happened deeper `node`'s tree, and `node`'s children must be // updated to have the newNode/oldNode metadata (changeGroups) // e.g. (2 + 2) + x --> 4 + x has to update the left argument - childChanged(node, childStatus, childArgIndex = null) { + childChanged(node: mathjs.MathNode, childStatus, childArgIndex = null) { const oldNode = clone(node); const newNode = clone(node); let substeps = childStatus.substeps; if (!childStatus.oldNode) { - throw Error('Expected old node for changeType: ' + childStatus.changeType); + throw Error(`Expected old node for changeType: ${childStatus.changeType}`); } - function updateSubsteps(substeps: any, fn: any); function updateSubsteps(substeps, fn) { substeps.map((step) => { step = fn(step); @@ -111,14 +111,12 @@ class Status { }); } else { - throw Error('Unexpected node type: ' + node.type); + throw Error("Unexpected node type: " + node.type); } return new Status(childStatus.changeType, oldNode, newNode, substeps); }; changeType; - oldNode; - newNode; substeps; } export = Status; diff --git a/lib/mathNode/Type.js b/lib/mathNode/Type.js new file mode 100644 index 00000000..e5b5f74b --- /dev/null +++ b/lib/mathNode/Type.js @@ -0,0 +1,110 @@ +/// +/* + For determining the type of a mathJS node. + */ +"use strict"; +var NodeType = (function () { + function NodeType() { + } + NodeType.isOperator = function (node, operator) { + if (operator === void 0) { operator = null; } + return node.type === "OperatorNode" && + node.fn !== "unaryMinus" && + ("*+-/^".lastIndexOf(node.op) !== -1) && + (operator ? node.op === operator : true); + }; + ; + NodeType.isParenthesis = function (node) { + return node.type === "ParenthesisNode"; + }; + ; + NodeType.isUnaryMinus = function (node) { + return node.type === "OperatorNode" && node.fn === "unaryMinus"; + }; + ; + NodeType.isFunction = function (node, functionName) { + if (functionName === void 0) { functionName = null; } + if (node.type !== "FunctionNode") { + return false; + } + if (functionName && node.fn !== functionName) { + return false; + } + return true; + }; + ; + NodeType.isSymbol = function (node, allowUnaryMinus) { + if (allowUnaryMinus === void 0) { allowUnaryMinus = true; } + if (node.type === "SymbolNode") { + return true; + } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + return NodeType.isSymbol(node.args[0], false); + } + else { + return false; + } + }; + ; + NodeType.isConstant = function (node, allowUnaryMinus) { + if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } + if (node.type === "ConstantNode") { + return true; + } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + if (NodeType.isConstant(node.args[0], false)) { + var value = parseFloat(node.args[0].value); + return value >= 0; + } + else { + return false; + } + } + else { + return false; + } + }; + ; + NodeType.isConstantFraction = function (node, allowUnaryMinus) { + if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } + if (NodeType.isOperator(node, '/')) { + return node.args.every(function (n) { return NodeType.isConstant(n, allowUnaryMinus); }); + } + else { + return false; + } + }; + ; + NodeType.isConstantOrConstantFraction = function (node, allowUnaryMinus) { + if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } + if (NodeType.isConstant(node, allowUnaryMinus) || + NodeType.isConstantFraction(node, allowUnaryMinus)) { + return true; + } + else { + return false; + } + }; + ; + NodeType.prototype.isIntegerFraction = function (node, allowUnaryMinus) { + if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } + if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { + return false; + } + var _a = node.args, numerator = _a[0], denominator = _a[1]; + if (allowUnaryMinus) { + if (NodeType.isUnaryMinus(numerator)) { + numerator = numerator.args[0]; + } + if (NodeType.isUnaryMinus(denominator)) { + denominator = denominator.args[0]; + } + } + return ((parseFloat(numerator.value) % 1 === 0) && + (parseFloat(denominator.value) % 1 === 0)); + }; + ; + return NodeType; +}()); +module.exports = NodeType; +//# sourceMappingURL=Type.js.map \ No newline at end of file diff --git a/lib/mathNode/Type.js.map b/lib/mathNode/Type.js.map new file mode 100644 index 00000000..641ce358 --- /dev/null +++ b/lib/mathNode/Type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Type.js","sourceRoot":"","sources":["Type.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/mathNode/Type.ts b/lib/mathNode/Type.ts index 97ec86aa..42a5b624 100644 --- a/lib/mathNode/Type.ts +++ b/lib/mathNode/Type.ts @@ -1,31 +1,32 @@ +/// /* For determining the type of a mathJS node. */ class NodeType { - static isOperator (node, operator = null) { - return node.type === 'OperatorNode' && - node.fn !== 'unaryMinus' && - ('*+-/^'.lastIndexOf(node.op) !== -1) && + static isOperator(node: mathjs.MathNode, operator = null) { + return node.type === "OperatorNode" && + node.fn !== "unaryMinus" && + ("*+-/^".lastIndexOf(node.op) !== -1) && (operator ? node.op === operator : true); }; - static isParenthesis(node) { - return node.type === 'ParenthesisNode'; + static isParenthesis(node: mathjs.MathNode) { + return node.type === "ParenthesisNode"; }; - static isUnaryMinus(node) { - return node.type === 'OperatorNode' && node.fn === 'unaryMinus'; + static isUnaryMinus(node: mathjs.MathNode) { + return node.type === "OperatorNode" && node.fn === "unaryMinus"; }; - static isFunction(node, functionName = null) { - if (node.type !== 'FunctionNode') { + static isFunction(node: mathjs.MathNode, functionName = null) { + if (node.type !== "FunctionNode") { return false; } - if (functionName && node.fn.name !== functionName) { + if (functionName && node.fn !== functionName) { return false; } return true; }; - static isSymbol(node, allowUnaryMinus = true) { - if (node.type === 'SymbolNode') { + static isSymbol(node: mathjs.MathNode, allowUnaryMinus = true) { + if (node.type === "SymbolNode") { return true; } else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { @@ -35,8 +36,8 @@ class NodeType { return false; } }; - static isConstant(node, allowUnaryMinus = false) { - if (node.type === 'ConstantNode') { + static isConstant(node: mathjs.MathNode, allowUnaryMinus = false) { + if (node.type === "ConstantNode") { return true; } else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { @@ -52,7 +53,7 @@ class NodeType { return false; } }; - static isConstantFraction(node, allowUnaryMinus = false) { + static isConstantFraction(node: mathjs.MathNode, allowUnaryMinus = false) { if (NodeType.isOperator(node, '/')) { return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); } @@ -60,7 +61,7 @@ class NodeType { return false; } }; - static isConstantOrConstantFraction(node, allowUnaryMinus = false) { + static isConstantOrConstantFraction(node: mathjs.MathNode, allowUnaryMinus = false) { if (NodeType.isConstant(node, allowUnaryMinus) || NodeType.isConstantFraction(node, allowUnaryMinus)) { return true; @@ -69,7 +70,7 @@ class NodeType { return false; } }; - isIntegerFraction(node, allowUnaryMinus = false) { + isIntegerFraction(node: mathjs.MathNode, allowUnaryMinus = false) { if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { return false; } diff --git a/lib/mathNode/index.ts b/lib/mathNode/index.ts index c0cc8281..5ef72d2a 100644 --- a/lib/mathNode/index.ts +++ b/lib/mathNode/index.ts @@ -1,7 +1,7 @@ -import Creator = require('./Creator'); -import PolynomialTerm = require('./PolynomialTerm'); -import Status = require('./Status'); -import Type = require('./Type'); +import Creator = require("./Creator"); +import PolynomialTerm = require("./PolynomialTerm"); +import Status = require("./Status"); +import Type = require("./Type"); var tmp; tmp = { Creator, diff --git a/lib/simplifyExpression/arithmeticSearch/index.ts b/lib/simplifyExpression/arithmeticSearch/index.ts index 76990d57..bb2fce50 100644 --- a/lib/simplifyExpression/arithmeticSearch/index.ts +++ b/lib/simplifyExpression/arithmeticSearch/index.ts @@ -1,7 +1,7 @@ -import ChangeTypes = require('../../ChangeTypes'); -import evaluate = require('../../util/evaluate'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require("../../ChangeTypes"); +import evaluate = require("../../util/evaluate"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); // Searches through the tree, prioritizing deeper nodes, and evaluates // arithmetic (e.g. 2+2 or 3*5*2) on an operation node if possible. @@ -10,7 +10,7 @@ const search = TreeSearch.postOrder(arithmetic); // evaluates arithmetic (e.g. 2+2 or 3*5*2) on an operation node. // Returns a mathNode.Status object. -function arithmetic(node) { +function arithmetic(node: mathjs.MathNode) { if (!mathNode.Type.isOperator(node)) { return mathNode.Status.noChange(node); } @@ -47,7 +47,7 @@ function arithmetic(node) { // Evaluates a math expression to a constant, e.g. 3+4 -> 7 and rounds if // necessary -function evaluateAndRound(node) { +function evaluateAndRound(node: mathjs.MathNode) { let result = evaluate(node); if (result < 1) { result = parseFloat(result.toPrecision(4)); diff --git a/lib/simplifyExpression/basicsSearch/index.js b/lib/simplifyExpression/basicsSearch/index.js new file mode 100644 index 00000000..055d0989 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/index.js @@ -0,0 +1,59 @@ +/* + * Performs simpifications that are more basic and overaching like (...)^0 => 1 + * These are always the first simplifications that are attempted. + */ +"use strict"; +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +var rearrangeCoefficient = require("./rearrangeCoefficient"); +var reduceExponentByZero = require("./reduceExponentByZero"); +var reduceMultiplicationByZero = require("./reduceMultiplicationByZero"); +var reduceZeroDividedByAnything = require("./reduceZeroDividedByAnything"); +var removeAdditionOfZero = require("./removeAdditionOfZero"); +var removeDivisionByOne = require("./removeDivisionByOne"); +var removeExponentBaseOne = require("./removeExponentBaseOne"); +var removeExponentByOne = require("./removeExponentByOne"); +var removeMultiplicationByNegativeOne = require("./removeMultiplicationByNegativeOne"); +var removeMultiplicationByOne = require("./removeMultiplicationByOne"); +var simplifyDoubleUnaryMinus = require("./simplifyDoubleUnaryMinus"); +var simplificationFunctions = [ + // multiplication by 0 yields 0 + reduceMultiplicationByZero, + // division of 0 by something yields 0 + reduceZeroDividedByAnything, + // ____^0 --> 1 + reduceExponentByZero, + // Check for x^1 which should be reduced to x + removeExponentByOne, + // Check for 1^x which should be reduced to 1 + // if x can be simplified to a constant + removeExponentBaseOne, + // - - becomes + + simplifyDoubleUnaryMinus, + // If this is a + node and one of the operands is 0, get rid of the 0 + removeAdditionOfZero, + // If this is a * node and one of the operands is 1, get rid of the 1 + removeMultiplicationByOne, + // In some cases, remove multiplying by -1 + removeMultiplicationByNegativeOne, + // If this is a / node and the denominator is 1 or -1, get rid of it + removeDivisionByOne, + // e.g. x*5 -> 5x + rearrangeCoefficient, +]; +var search = TreeSearch.preOrder(basics); +// Look for basic step(s) to perform on a node. Returns a mathNode.Status object. +function basics(node) { + for (var i = 0; i < simplificationFunctions.length; i++) { + var nodeStatus = simplificationFunctions[i](node); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + else { + node = nodeStatus.newNode; + } + } + return mathNode.Status.noChange(node); +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/index.js.map b/lib/simplifyExpression/basicsSearch/index.js.map new file mode 100644 index 00000000..d03848f0 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,yCAA4C;AAC5C,6CAAgD;AAChD,6DAAgE;AAChE,6DAAgE;AAChE,yEAA4E;AAC5E,2EAA8E;AAC9E,6DAAgE;AAChE,2DAA8D;AAC9D,+DAAkE;AAClE,2DAA8D;AAC9D,uFAA0F;AAC1F,uEAA0E;AAC1E,qEAAwE;AACxE,IAAM,uBAAuB,GAAG;IAC9B,+BAA+B;IAC/B,0BAA0B;IAC1B,sCAAsC;IACtC,2BAA2B;IAC3B,eAAe;IACf,oBAAoB;IACpB,6CAA6C;IAC7C,mBAAmB;IACnB,6CAA6C;IAC7C,uCAAuC;IACvC,qBAAqB;IACrB,gBAAgB;IAChB,wBAAwB;IACxB,qEAAqE;IACrE,oBAAoB;IACpB,qEAAqE;IACrE,yBAAyB;IACzB,0CAA0C;IAC1C,iCAAiC;IACjC,oEAAoE;IACpE,mBAAmB;IACnB,iBAAiB;IACjB,oBAAoB;CACrB,CAAC;AAEF,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAE3C,iFAAiF;AACjF,gBAAgB,IAAqB;IACnC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,IAAM,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/index.ts b/lib/simplifyExpression/basicsSearch/index.ts index 66b86318..1c6dc2ca 100644 --- a/lib/simplifyExpression/basicsSearch/index.ts +++ b/lib/simplifyExpression/basicsSearch/index.ts @@ -3,20 +3,20 @@ * These are always the first simplifications that are attempted. */ -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); -import rearrangeCoefficient = require('./rearrangeCoefficient'); -import reduceExponentByZero = require('./reduceExponentByZero'); -import reduceMultiplicationByZero = require('./reduceMultiplicationByZero'); -import reduceZeroDividedByAnything = require('./reduceZeroDividedByAnything'); -import removeAdditionOfZero = require('./removeAdditionOfZero'); -import removeDivisionByOne = require('./removeDivisionByOne'); -import removeExponentBaseOne = require('./removeExponentBaseOne'); -import removeExponentByOne = require('./removeExponentByOne'); -import removeMultiplicationByNegativeOne = require('./removeMultiplicationByNegativeOne'); -import removeMultiplicationByOne = require('./removeMultiplicationByOne'); -import simplifyDoubleUnaryMinus = require('./simplifyDoubleUnaryMinus'); -const SIMPLIFICATION_FUNCTIONS = [ +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); +import rearrangeCoefficient = require("./rearrangeCoefficient"); +import reduceExponentByZero = require("./reduceExponentByZero"); +import reduceMultiplicationByZero = require("./reduceMultiplicationByZero"); +import reduceZeroDividedByAnything = require("./reduceZeroDividedByAnything"); +import removeAdditionOfZero = require("./removeAdditionOfZero"); +import removeDivisionByOne = require("./removeDivisionByOne"); +import removeExponentBaseOne = require("./removeExponentBaseOne"); +import removeExponentByOne = require("./removeExponentByOne"); +import removeMultiplicationByNegativeOne = require("./removeMultiplicationByNegativeOne"); +import removeMultiplicationByOne = require("./removeMultiplicationByOne"); +import simplifyDoubleUnaryMinus = require("./simplifyDoubleUnaryMinus"); +const simplificationFunctions = [ // multiplication by 0 yields 0 reduceMultiplicationByZero, // division of 0 by something yields 0 @@ -45,10 +45,9 @@ const SIMPLIFICATION_FUNCTIONS = [ const search = TreeSearch.preOrder(basics); // Look for basic step(s) to perform on a node. Returns a mathNode.Status object. -function basics(node: any); -function basics(node) { - for (let i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) { - const nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node); +function basics(node: mathjs.MathNode) { + for (let i = 0; i < simplificationFunctions.length; i++) { + const nodeStatus = simplificationFunctions[i](node); if (nodeStatus.hasChanged()) { return nodeStatus; } diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js new file mode 100644 index 00000000..32219a55 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js @@ -0,0 +1,21 @@ +"use strict"; +var checks = require("../../checks"); +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// Rearranges something of the form x * 5 to be 5x, ie putting the coefficient +// in the right place. +// Returns a mathNode.Status object +function rearrangeCoefficient(node) { + if (!checks.canRearrangeCoefficient(node)) { + return mathNode.Status.noChange(node); + } + var newNode = clone(node); + var polyNode = new mathNode.PolynomialTerm(newNode.args[0]); + var constNode = newNode.args[1]; + var exponentNode = polyNode.getExponentNode(); + newNode = mathNode.Creator.polynomialTerm(polyNode.getSymbolNode(), exponentNode, constNode); + return mathNode.Status.nodeChanged(ChangeTypes.REARRANGE_COEFF, node, newNode); +} +module.exports = rearrangeCoefficient; +//# sourceMappingURL=rearrangeCoefficient.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map new file mode 100644 index 00000000..0f28b645 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rearrangeCoefficient.js","sourceRoot":"","sources":["rearrangeCoefficient.ts"],"names":[],"mappings":";AAAA,qCAAwC;AACxC,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,8EAA8E;AAC9E,sBAAsB;AACtB,mCAAmC;AACnC,8BAA8B,IAAqB;IACjD,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAE1B,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,IAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC;IAChD,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CACvC,QAAQ,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;IAErD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,eAAe,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,iBAAS,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts index 59d4b067..de74dd3d 100644 --- a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts +++ b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts @@ -1,13 +1,12 @@ -import checks = require('../../checks'); -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import checks = require("../../checks"); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // Rearranges something of the form x * 5 to be 5x, ie putting the coefficient // in the right place. // Returns a mathNode.Status object -function rearrangeCoefficient(node: any); -function rearrangeCoefficient(node) { +function rearrangeCoefficient(node: mathjs.MathNode) { if (!checks.canRearrangeCoefficient(node)) { return mathNode.Status.noChange(node); } diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js new file mode 100644 index 00000000..2829d560 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js @@ -0,0 +1,20 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// If `node` is an exponent of something to 0, we can reduce that to just 1. +// Returns a mathNode.Status object. +function reduceExponentByZero(node) { + if (node.op !== "^") { + return mathNode.Status.noChange(node); + } + var exponent = node.args[1]; + if (mathNode.Type.isConstant(exponent) && exponent.value === "0") { + var newNode = mathNode.Creator.constant(1); + return mathNode.Status.nodeChanged(ChangeTypes.REDUCE_EXPONENT_BY_ZERO, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} +module.exports = reduceExponentByZero; +//# sourceMappingURL=reduceExponentByZero.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map new file mode 100644 index 00000000..f51f9869 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reduceExponentByZero.js","sourceRoot":"","sources":["reduceExponentByZero.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAE5C,4EAA4E;AAC5E,oCAAoC;AACpC,8BAA8B,IAAqB;IACjD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QACjE,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,uBAAuB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts index 96393cf2..d7151113 100644 --- a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts +++ b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts @@ -1,15 +1,14 @@ -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is an exponent of something to 0, we can reduce that to just 1. // Returns a mathNode.Status object. -function reduceExponentByZero(node: any); -function reduceExponentByZero(node) { - if (node.op !== '^') { +function reduceExponentByZero(node: mathjs.MathNode) { + if (node.op !== "^") { return mathNode.Status.noChange(node); } const exponent = node.args[1]; - if (mathNode.Type.isConstant(exponent) && exponent.value === '0') { + if (mathNode.Type.isConstant(exponent) && exponent.value === "0") { const newNode = mathNode.Creator.constant(1); return mathNode.Status.nodeChanged( ChangeTypes.REDUCE_EXPONENT_BY_ZERO, node, newNode); diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js new file mode 100644 index 00000000..7c7f6ef3 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js @@ -0,0 +1,28 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +function reduceMultiplicationByZero(node) { + if (node.op !== "*") { + return mathNode.Status.noChange(node); + } + var zeroIndex = node.args.findIndex(function (arg) { + if (mathNode.Type.isConstant(arg) && arg.value === "0") { + return true; + } + if (mathNode.PolynomialTerm.isPolynomialTerm(arg)) { + var polyTerm = new mathNode.PolynomialTerm(arg); + return polyTerm.getCoeffValue() === 0; + } + return false; + }); + if (zeroIndex >= 0) { + // reduce to just the 0 node + var newNode = mathNode.Creator.constant(0); + return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_BY_ZERO, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} +module.exports = reduceMultiplicationByZero; +//# sourceMappingURL=reduceMultiplicationByZero.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map new file mode 100644 index 00000000..963c1406 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reduceMultiplicationByZero.js","sourceRoot":"","sources":["reduceMultiplicationByZero.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAK5C,oCAAoC,IAAI;IACtC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QACvC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAClD,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,CAAC,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,4BAA4B;QAC5B,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,gBAAgB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts index 7925ec30..6ba40faf 100644 --- a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts +++ b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts @@ -1,15 +1,14 @@ -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is a multiplication node with 0 as one of its operands, // reduce the node to 0. Returns a mathNode.Status object. -function reduceMultiplicationByZero(node: any); -function reduceMultiplicationByZero(node) { - if (node.op !== '*') { +function reduceMultiplicationByZero(node: mathjs.MathNode) { + if (node.op !== "*") { return mathNode.Status.noChange(node); } const zeroIndex = node.args.findIndex(arg => { - if (mathNode.Type.isConstant(arg) && arg.value === '0') { + if (mathNode.Type.isConstant(arg) && arg.value === "0") { return true; } if (mathNode.PolynomialTerm.isPolynomialTerm(arg)) { diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js new file mode 100644 index 00000000..b55b65e3 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js @@ -0,0 +1,19 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// If `node` is a fraction with 0 as the numerator, reduce the node to 0. +// Returns a mathNode.Status object. +function reduceZeroDividedByAnything(node) { + if (node.op !== "/") { + return mathNode.Status.noChange(node); + } + if (node.args[0].value === "0") { + var newNode = mathNode.Creator.constant(0); + return mathNode.Status.nodeChanged(ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} +module.exports = reduceZeroDividedByAnything; +//# sourceMappingURL=reduceZeroDividedByAnything.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map new file mode 100644 index 00000000..21ebde07 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reduceZeroDividedByAnything.js","sourceRoot":"","sources":["reduceZeroDividedByAnything.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAE5C,yEAAyE;AACzE,oCAAoC;AACpC,qCAAqC,IAAqB;IACxD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,qBAAqB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,2BAA2B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts index f79a04b5..0d657c83 100644 --- a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts +++ b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts @@ -1,14 +1,13 @@ -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is a fraction with 0 as the numerator, reduce the node to 0. // Returns a mathNode.Status object. -function reduceZeroDividedByAnything(node: any); -function reduceZeroDividedByAnything(node) { - if (node.op !== '/') { +function reduceZeroDividedByAnything(node: mathjs.MathNode) { + if (node.op !== "/") { return mathNode.Status.noChange(node); } - if (node.args[0].value === '0') { + if (node.args[0].value === "0") { const newNode = mathNode.Creator.constant(0); return mathNode.Status.nodeChanged( ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js new file mode 100644 index 00000000..ac9ea30e --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js @@ -0,0 +1,26 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +function removeAdditionOfZero(node) { + if (node.op !== "+") { + return mathNode.Status.noChange(node); + } + var zeroIndex = node.args.findIndex(function (arg) { + return mathNode.Type.isConstant(arg) && arg.value === "0"; + }); + var newNode = clone(node); + if (zeroIndex >= 0) { + // remove the 0 node + newNode.args.splice(zeroIndex, 1); + // if there's only one operand left, there's nothing left to add it to, + // so move it up the tree + if (newNode.args.length === 1) { + newNode = newNode.args[0]; + } + return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_ADDING_ZERO, node, newNode); + } + return mathNode.Status.noChange(node); +} +module.exports = removeAdditionOfZero; +//# sourceMappingURL=removeAdditionOfZero.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map new file mode 100644 index 00000000..9ed4afe6 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeAdditionOfZero.js","sourceRoot":"","sources":["removeAdditionOfZero.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAK5C,8BAA8B,IAAI;IAChC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QACvC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC;IAC5D,CAAC,CAAC,CAAC;IACH,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,oBAAoB;QACpB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAClC,uEAAuE;QACvE,yBAAyB;QACzB,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts index 82b7d892..9fa8a1b2 100644 --- a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts +++ b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts @@ -1,16 +1,15 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is an addition node with 0 as one of its operands, // remove 0 from the operands list. Returns a mathNode.Status object. -function removeAdditionOfZero(node: any); -function removeAdditionOfZero(node) { - if (node.op !== '+') { +function removeAdditionOfZero(node: mathjs.MathNode) { + if (node.op !== "+") { return mathNode.Status.noChange(node); } const zeroIndex = node.args.findIndex(arg => { - return mathNode.Type.isConstant(arg) && arg.value === '0'; + return mathNode.Type.isConstant(arg) && arg.value === "0"; }); let newNode = clone(node); if (zeroIndex >= 0) { diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js new file mode 100644 index 00000000..dc487f1e --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js @@ -0,0 +1,39 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var Negative = require("../../Negative"); +var mathNode = require("../../mathnode"); +// If `node` is a division operation of something by 1 or -1, we can remove the +// denominator. Returns a mathNode.Status object. +function removeDivisionByOne(node) { + if (node.op !== "/") { + return mathNode.Status.noChange(node); + } + var denominator = node.args[1]; + if (!mathNode.Type.isConstant(denominator)) { + return mathNode.Status.noChange(node); + } + var numerator = clone(node.args[0]); + // if denominator is -1, we make the numerator negative + if (parseFloat(denominator.value) === -1) { + // If the numerator was an operation, wrap it in parens before adding - + // to the front. + // e.g. 2+3 / -1 ---> -(2+3) + if (mathNode.Type.isOperator(numerator)) { + numerator = mathNode.Creator.parenthesis(numerator); + } + var changeType = Negative.isNegative(numerator) ? + ChangeTypes.RESOLVE_DOUBLE_MINUS : + ChangeTypes.DIVISION_BY_NEGATIVE_ONE; + numerator = Negative.negate(numerator); + return mathNode.Status.nodeChanged(changeType, node, numerator); + } + else if (parseFloat(denominator.value) === 1) { + return mathNode.Status.nodeChanged(ChangeTypes.DIVISION_BY_ONE, node, numerator); + } + else { + return mathNode.Status.noChange(node); + } +} +module.exports = removeDivisionByOne; +//# sourceMappingURL=removeDivisionByOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map new file mode 100644 index 00000000..29121f74 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeDivisionByOne.js","sourceRoot":"","sources":["removeDivisionByOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAC5C,yCAA4C;AAE5C,+EAA+E;AAC/E,iDAAiD;AACjD,6BAA6B,IAAqB;IAChD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpC,uDAAuD;IACvD,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,uEAAuE;QACvE,gBAAgB;QAChB,4BAA4B;QAC5B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACxC,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACtD,CAAC;QACD,IAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;YAC/C,WAAW,CAAC,oBAAoB;YAChC,WAAW,CAAC,wBAAwB,CAAC;QACvC,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,eAAe,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts index e3770dd8..c889b825 100644 --- a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts @@ -1,13 +1,12 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import Negative = require('../../Negative'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import Negative = require("../../Negative"); +import mathNode = require("../../mathnode"); // If `node` is a division operation of something by 1 or -1, we can remove the // denominator. Returns a mathNode.Status object. -function removeDivisionByOne(node: any); -function removeDivisionByOne(node) { - if (node.op !== '/') { +function removeDivisionByOne(node: mathjs.MathNode) { + if (node.op !== "/") { return mathNode.Status.noChange(node); } const denominator = node.args[1]; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js new file mode 100644 index 00000000..b252c58a --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js @@ -0,0 +1,19 @@ +"use strict"; +var checks = require("../../checks"); +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// If `node` is of the form 1^x, reduces it to a node of the form 1. +// Returns a mathNode.Status object. +function removeExponentBaseOne(node) { + if (node.op === "^" && + checks.resolvesToConstant(node.args[1]) && + mathNode.Type.isConstant(node.args[0]) && + node.args[0].value === "1") { + var newNode = clone(node.args[0]); + return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_EXPONENT_BASE_ONE, node, newNode); + } + return mathNode.Status.noChange(node); +} +module.exports = removeExponentBaseOne; +//# sourceMappingURL=removeExponentBaseOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map new file mode 100644 index 00000000..d68ed4b5 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeExponentBaseOne.js","sourceRoot":"","sources":["removeExponentBaseOne.ts"],"names":[],"mappings":";AAAA,qCAAwC;AACxC,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,oEAAoE;AACpE,oCAAoC;AACpC,+BAA+B,IAAqB;IAClD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG;QACf,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,wBAAwB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,qBAAqB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts index 6ec4cc80..7a34e018 100644 --- a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts @@ -1,16 +1,15 @@ -import checks = require('../../checks'); -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import checks = require("../../checks"); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is of the form 1^x, reduces it to a node of the form 1. // Returns a mathNode.Status object. -function removeExponentBaseOne(node: any); -function removeExponentBaseOne(node) { - if (node.op === '^' && // an exponent with +function removeExponentBaseOne(node: mathjs.MathNode) { + if (node.op === "^" && // an exponent with checks.resolvesToConstant(node.args[1]) && // a power not a symbol and mathNode.Type.isConstant(node.args[0]) && // a constant base - node.args[0].value === '1') { // of value 1 + node.args[0].value === "1") { // of value 1 const newNode = clone(node.args[0]); return mathNode.Status.nodeChanged( ChangeTypes.REMOVE_EXPONENT_BASE_ONE, node, newNode); diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js new file mode 100644 index 00000000..6b3bc6e3 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js @@ -0,0 +1,17 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// If `node` is of the form x^1, reduces it to a node of the form x. +// Returns a mathNode.Status object. +function removeExponentByOne(node) { + if (node.op === "^" && + mathNode.Type.isConstant(node.args[1]) && + node.args[1].value === "1") { + var newNode = clone(node.args[0]); + return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_EXPONENT_BY_ONE, node, newNode); + } + return mathNode.Status.noChange(node); +} +module.exports = removeExponentByOne; +//# sourceMappingURL=removeExponentByOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map new file mode 100644 index 00000000..da09389d --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeExponentByOne.js","sourceRoot":"","sources":["removeExponentByOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,oEAAoE;AACpE,oCAAoC;AACpC,6BAA6B,IAAqB;IAChD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG;QACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,sBAAsB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts index 40ebebcb..a5a1dd89 100644 --- a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts @@ -1,14 +1,13 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is of the form x^1, reduces it to a node of the form x. // Returns a mathNode.Status object. -function removeExponentByOne(node: any); -function removeExponentByOne(node) { - if (node.op === '^' && // exponent of anything +function removeExponentByOne(node: mathjs.MathNode) { + if (node.op === "^" && // exponent of anything mathNode.Type.isConstant(node.args[1]) && // to a constant - node.args[1].value === '1') { // of value 1 + node.args[1].value === "1") { // of value 1 const newNode = clone(node.args[0]); return mathNode.Status.nodeChanged( ChangeTypes.REMOVE_EXPONENT_BY_ONE, node, newNode); diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js new file mode 100644 index 00000000..63ae4cb2 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js @@ -0,0 +1,44 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var Negative = require("../../Negative"); +var mathNode = require("../../mathnode"); +function removeMultiplicationByNegativeOne(node) { + if (node.op !== "*") { + return mathNode.Status.noChange(node); + } + var minusOneIndex = node.args.findIndex(function (arg) { + return mathNode.Type.isConstant(arg) && arg.value === "-1"; + }); + if (minusOneIndex < 0) { + return mathNode.Status.noChange(node); + } + // We might merge/combine the negative one into another node. This stores + // the index of that other node in the arg list. + var nodeToCombineIndex; + // If minus one is the last term, maybe combine with the term before + if (minusOneIndex + 1 === node.args.length) { + nodeToCombineIndex = minusOneIndex - 1; + } + else { + nodeToCombineIndex = minusOneIndex + 1; + } + var nodeToCombine = node.args[nodeToCombineIndex]; + // If it's a constant, the combining of those terms is handled elsewhere. + if (mathNode.Type.isConstant(nodeToCombine)) { + return mathNode.Status.noChange(node); + } + var newNode = clone(node); + // Get rid of the -1 + nodeToCombine = Negative.negate(clone(nodeToCombine)); + // replace the node next to -1 and remove -1 + newNode.args[nodeToCombineIndex] = nodeToCombine; + newNode.args.splice(minusOneIndex, 1); + // if there's only one operand left, move it up the tree + if (newNode.args.length === 1) { + newNode = newNode.args[0]; + } + return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_MULTIPLYING_BY_NEGATIVE_ONE, node, newNode); +} +module.exports = removeMultiplicationByNegativeOne; +//# sourceMappingURL=removeMultiplicationByNegativeOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map new file mode 100644 index 00000000..124b0d76 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeMultiplicationByNegativeOne.js","sourceRoot":"","sources":["removeMultiplicationByNegativeOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAC5C,yCAA4C;AAO5C,2CAA2C,IAAI;IAC7C,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QAC3C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC;IAC7D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,yEAAyE;IACzE,gDAAgD;IAChD,IAAI,kBAAkB,CAAC;IACvB,oEAAoE;IACpE,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3C,kBAAkB,GAAG,aAAa,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,kBAAkB,GAAG,aAAa,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClD,yEAAyE;IACzE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAE1B,oBAAoB;IACpB,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IAEtD,4CAA4C;IAC5C,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,aAAa,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAEtC,wDAAwD;IACxD,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kCAAkC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,iBAAS,iCAAiC,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts index 89d6f5f2..9f037d0f 100644 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts @@ -1,19 +1,18 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import Negative = require('../../Negative'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import Negative = require("../../Negative"); +import mathNode = require("../../mathnode"); // If `node` is a multiplication node with -1 as one of its operands, // and a non constant as the next operand, remove -1 from the operands // list and make the next term have a unary minus. // Returns a mathNode.Status object. -function removeMultiplicationByNegativeOne(node: any); -function removeMultiplicationByNegativeOne(node) { - if (node.op !== '*') { +function removeMultiplicationByNegativeOne(node: mathjs.MathNode) { + if (node.op !== "*") { return mathNode.Status.noChange(node); } const minusOneIndex = node.args.findIndex(arg => { - return mathNode.Type.isConstant(arg) && arg.value === '-1'; + return mathNode.Type.isConstant(arg) && arg.value === "-1"; }); if (minusOneIndex < 0) { return mathNode.Status.noChange(node); diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js new file mode 100644 index 00000000..8fa3527b --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js @@ -0,0 +1,28 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// If `node` is a multiplication node with 1 as one of its operands, +// remove 1 from the operands list. Returns a mathNode.Status object. +function removeMultiplicationByOne(node) { + if (node.op !== "*") { + return mathNode.Status.noChange(node); + } + var oneIndex = node.args.findIndex(function (arg) { + return mathNode.Type.isConstant(arg) && arg.value === "1"; + }); + if (oneIndex >= 0) { + var newNode = clone(node); + // remove the 1 node + newNode.args.splice(oneIndex, 1); + // if there's only one operand left, there's nothing left to multiply it + // to, so move it up the tree + if (newNode.args.length === 1) { + newNode = newNode.args[0]; + } + return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_MULTIPLYING_BY_ONE, node, newNode); + } + return mathNode.Status.noChange(node); +} +module.exports = removeMultiplicationByOne; +//# sourceMappingURL=removeMultiplicationByOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map new file mode 100644 index 00000000..5df017b6 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeMultiplicationByOne.js","sourceRoot":"","sources":["removeMultiplicationByOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,oEAAoE;AACpE,qEAAqE;AACrE,mCAAmC,IAAI;IACrC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QACtC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC;IAC5D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,oBAAoB;QACpB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACjC,wEAAwE;QACxE,6BAA6B;QAC7B,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,yBAAyB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,yBAAyB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts index a409d8f9..84c1f7bd 100644 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts +++ b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts @@ -1,15 +1,15 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // If `node` is a multiplication node with 1 as one of its operands, // remove 1 from the operands list. Returns a mathNode.Status object. -function removeMultiplicationByOne(node) { - if (node.op !== '*') { +function removeMultiplicationByOne(node: mathjs.MathNode) { + if (node.op !== "*") { return mathNode.Status.noChange(node); } const oneIndex = node.args.findIndex(arg => { - return mathNode.Type.isConstant(arg) && arg.value === '1'; + return mathNode.Type.isConstant(arg) && arg.value === "1"; }); if (oneIndex >= 0) { let newNode = clone(node); diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js new file mode 100644 index 00000000..0d943a7c --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js @@ -0,0 +1,32 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +// Simplifies two unary minuses in a row by removing both of them. +// e.g. -(- 4) --> 4 +function simplifyDoubleUnaryMinus(node) { + if (!mathNode.Type.isUnaryMinus(node)) { + return mathNode.Status.noChange(node); + } + var unaryArg = node.args[0]; + // e.g. in - -x, -x is the unary arg, and we'd want to reduce to just x + if (mathNode.Type.isUnaryMinus(unaryArg)) { + var newNode = clone(unaryArg.args[0]); + return mathNode.Status.nodeChanged(ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); + } + else if (mathNode.Type.isConstant(unaryArg) && parseFloat(unaryArg.value) < 0) { + var newNode = mathNode.Creator.constant(parseFloat(unaryArg.value) * -1); + return mathNode.Status.nodeChanged(ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); + } + else if (mathNode.Type.isParenthesis(unaryArg)) { + var parenthesisNode = unaryArg; + var parenthesisContent = parenthesisNode; + if (mathNode.Type.isUnaryMinus(parenthesisContent)) { + var newNode = mathNode.Creator.parenthesis(parenthesisContent.args[0]); + return mathNode.Status.nodeChanged(ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); + } + } + return mathNode.Status.noChange(node); +} +module.exports = simplifyDoubleUnaryMinus; +//# sourceMappingURL=simplifyDoubleUnaryMinus.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map new file mode 100644 index 00000000..e174a1c7 --- /dev/null +++ b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map @@ -0,0 +1 @@ +{"version":3,"file":"simplifyDoubleUnaryMinus.js","sourceRoot":"","sources":["simplifyDoubleUnaryMinus.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,kEAAkE;AAClE,oBAAoB;AACpB,kCAAkC,IAAqB;IACrD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,uEAAuE;IACvE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACzC,IAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9E,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAM,eAAe,GAAG,QAAQ,CAAC;QACjC,IAAM,kBAAkB,GAAG,eAAe,CAAC;QAC3C,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;YACnD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,wBAAwB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts index 6422c8b9..8a6efd16 100644 --- a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts +++ b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts @@ -1,11 +1,10 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // Simplifies two unary minuses in a row by removing both of them. // e.g. -(- 4) --> 4 -function simplifyDoubleUnaryMinus(node: any); -function simplifyDoubleUnaryMinus(node) { +function simplifyDoubleUnaryMinus(node: mathjs.MathNode) { if (!mathNode.Type.isUnaryMinus(node)) { return mathNode.Status.noChange(node); } @@ -25,7 +24,7 @@ function simplifyDoubleUnaryMinus(node) { // e.g. -(-(5+2)) else if (mathNode.Type.isParenthesis(unaryArg)) { const parenthesisNode = unaryArg; - const parenthesisContent = parenthesisNode.content; + const parenthesisContent = parenthesisNode; if (mathNode.Type.isUnaryMinus(parenthesisContent)) { const newNode = mathNode.Creator.parenthesis(parenthesisContent.args[0]); return mathNode.Status.nodeChanged( diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.js b/lib/simplifyExpression/breakUpNumeratorSearch/index.js new file mode 100644 index 00000000..36f0e233 --- /dev/null +++ b/lib/simplifyExpression/breakUpNumeratorSearch/index.js @@ -0,0 +1,38 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +// Breaks up any fraction (deeper nodes getting priority) that has a numerator +// that is a sum. e.g. (2+x)/5 -> (2/5 + x/5) +// This step must happen after things have been collected and combined, or +// else things will infinite loop, so it's a tree search of its own. +// Returns a mathNode.Status object +var search = TreeSearch.postOrder(breakUpNumerator); +function breakUpNumerator(node) { + if (!mathNode.Type.isOperator(node) || node.op !== "/") { + return mathNode.Status.noChange(node); + } + var numerator = node.args[0]; + if (mathNode.Type.isParenthesis(numerator)) { + numerator = numerator.content; + } + if (!mathNode.Type.isOperator(numerator) || numerator.op !== "+") { + return mathNode.Status.noChange(node); + } + // At this point, we know that node is a fraction and its numerator is a sum + // of terms that can't be collected or combined, so we should break it up. + var fractionList = []; + var denominator = node.args[1]; + numerator.args.forEach(function (arg) { + var newFraction = mathNode.Creator.operator("/", [arg, denominator]); + newFraction.changeGroup = 1; + fractionList.push(newFraction); + }); + var newNode = mathNode.Creator.operator("+", fractionList); + // Wrap in parens for cases like 2*(2+3)/5 => 2*(2/5 + 3/5) + newNode = mathNode.Creator.parenthesis(newNode); + node.changeGroup = 1; + return mathNode.Status.nodeChanged(ChangeTypes.BREAK_UP_FRACTION, node, newNode, false); +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.js.map b/lib/simplifyExpression/breakUpNumeratorSearch/index.js.map new file mode 100644 index 00000000..13853c0a --- /dev/null +++ b/lib/simplifyExpression/breakUpNumeratorSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,8EAA8E;AAC9E,6CAA6C;AAC7C,0EAA0E;AAC1E,oEAAoE;AACpE,mCAAmC;AACnC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAMtD,0BAA0B,IAAI;IAC5B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3C,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC;IAChC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,4EAA4E;IAC5E,0EAA0E;IAC1E,IAAM,YAAY,GAAG,EAAE,CAAC;IACxB,IAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAA,GAAG;QACxB,IAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;QACvE,WAAW,CAAC,WAAW,GAAG,CAAC,CAAC;QAC5B,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC3D,2DAA2D;IAC3D,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACrB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.ts b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts index 843183d3..a2a37e89 100644 --- a/lib/simplifyExpression/breakUpNumeratorSearch/index.ts +++ b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts @@ -1,6 +1,6 @@ -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); // Breaks up any fraction (deeper nodes getting priority) that has a numerator // that is a sum. e.g. (2+x)/5 -> (2/5 + x/5) @@ -12,16 +12,15 @@ const search = TreeSearch.postOrder(breakUpNumerator); // If `node` is a fraction with a numerator that is a sum, breaks up the // fraction e.g. (2+x)/5 -> (2/5 + x/5) // Returns a mathNode.Status object -function breakUpNumerator(node: any); -function breakUpNumerator(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '/') { +function breakUpNumerator(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "/") { return mathNode.Status.noChange(node); } let numerator = node.args[0]; if (mathNode.Type.isParenthesis(numerator)) { numerator = numerator.content; } - if (!mathNode.Type.isOperator(numerator) || numerator.op !== '+') { + if (!mathNode.Type.isOperator(numerator) || numerator.op !== "+") { return mathNode.Status.noChange(node); } @@ -30,12 +29,12 @@ function breakUpNumerator(node) { const fractionList = []; const denominator = node.args[1]; numerator.args.forEach(arg => { - const newFraction = mathNode.Creator.operator('/', [arg, denominator]); + const newFraction = mathNode.Creator.operator("/", [arg, denominator]); newFraction.changeGroup = 1; fractionList.push(newFraction); }); - let newNode = mathNode.Creator.operator('+', fractionList); + let newNode = mathNode.Creator.operator("+", fractionList); // Wrap in parens for cases like 2*(2+3)/5 => 2*(2/5 + 3/5) newNode = mathNode.Creator.parenthesis(newNode); node.changeGroup = 1; diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js new file mode 100644 index 00000000..d48fa5cc --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js @@ -0,0 +1,236 @@ +"use strict"; +var clone = require("../../util/clone"); +var print = require("../../util/print"); +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +var Util = require("../../util/Util"); +var CONSTANT = 'constant'; +var CONSTANT_FRACTION = 'constantFraction'; +var OTHER = 'other'; +var LikeTermCollector = (function () { + function LikeTermCollector() { + // Collects like terms for an operation node and returns a mathNode.Status object. + this.collectLikeTerms = function (node) { + if (!LikeTermCollector.canCollectLikeTerms(node)) { + return mathNode.Status.noChange(node); + } + var op = node.op; + var terms; + if (op === '+') { + terms = getTermsForCollectingAddition(node); + } + else if (op === '*') { + terms = getTermsForCollectingMultiplication(node); + } + else { + throw Error('Operation not supported: ' + op); + } + // List the symbols alphabetically + var termTypesSorted = Object.keys(terms) + .filter(function (x) { return (x !== CONSTANT && x !== CONSTANT_FRACTION && x !== OTHER); }) + .sort(sortTerms); + // Then add const + if (terms[CONSTANT]) { + // at the end for addition (since we'd expect x^2 + (x + x) + 4) + if (op === '+') { + termTypesSorted.push(CONSTANT); + } + // for multipliation it should be at the front (e.g. (3*4) * x^2) + if (op === '*') { + termTypesSorted.unshift(CONSTANT); + } + } + if (terms[CONSTANT_FRACTION]) { + termTypesSorted.push(CONSTANT_FRACTION); + } + // Collect the new operands under op. + var newOperands = []; + var changeGroup = 1; + termTypesSorted.forEach(function (termType) { + var termsOfType = terms[termType]; + if (termsOfType.length === 1) { + var singleTerm = clone(termsOfType[0]); + singleTerm.changeGroup = changeGroup; + newOperands.push(singleTerm); + } + else { + var termList = clone(mathNode.Creator.parenthesis(mathNode.Creator.operator(op, termsOfType))); + termList.changeGroup = changeGroup; + newOperands.push(termList); + } + termsOfType.forEach(function (term) { + term.changeGroup = changeGroup; + }); + changeGroup++; + }); + // then stick anything else (paren nodes, operator nodes) at the end + if (terms[OTHER]) { + newOperands = newOperands.concat(terms[OTHER]); + } + var newNode = clone(node); + newNode.args = newOperands; + return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_LIKE_TERMS, node, newNode, false); + }; + } + return LikeTermCollector; +}()); +// Given an expression tree, returns true if there are terms that can be +// collected +LikeTermCollector.canCollectLikeTerms = function (node) { + // We can collect like terms through + or through * + // Note that we never collect like terms with - or /, those expressions will + // always be manipulated in flattenOperands so that the top level operation is + // + or *. + if (!(mathNode.Type.isOperator(node, '+') || mathNode.Type.isOperator(node, '*'))) { + return false; + } + var terms; + if (node.op === '+') { + terms = getTermsForCollectingAddition(node); + } + else if (node.op === '*') { + terms = getTermsForCollectingMultiplication(node); + } + else { + throw Error('Operation not supported: ' + node.op); + } + // Conditions we need to meet to decide to to reorganize (collect) the terms: + // - more than 1 term type + // - more than 1 of at least one type (not including other) + // (note that this means x^2 + x + x + 2 -> x^2 + (x + x) + 2, + // which will be recorded as a step, but doesn't change the order of terms) + var termTypes = Object.keys(terms); + var filteredTermTypes = termTypes.filter(function (x) { return x !== OTHER; }); + return (termTypes.length > 1 && + filteredTermTypes.some(function (x) { return terms[x].length > 1; })); +}; +// Polyonomial terms are collected by categorizing them by their 'name' +// which is used to separate them into groups that can be combined. getTermName +// returns this group 'name' +function getTermName(node, op) { + var polyNode = new mathNode.PolynomialTerm(node); + // we 'name' polynomial terms by their symbol name + var termName = polyNode.getSymbolName(); + // when adding terms, the exponent matters too (e.g. 2x^2 + 5x^3 can't be combined) + if (op === '+') { + var exponent = print(polyNode.getExponentNode(true)); + termName += '^' + exponent; + } + return termName; +} +// Collects like terms in an addition expression tree into categories. +// Returns a dictionary of termname to lists of nodes with that name +// e.g. 2x + 4 + 5x would return {'x': [2x, 5x], CONSTANT: [4]} +// (where 2x, 5x, and 4 would actually be expression trees) +function getTermsForCollectingAddition(node) { + var terms = {}; + for (var i = 0; i < node.args.length; i++) { + var child = node.args[i]; + if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { + var termName = getTermName(child, '+'); + terms = Util.appendToArrayInObject(terms, termName, child); + } + else if (mathNode.Type.isIntegerFraction(child)) { + terms = Util.appendToArrayInObject(terms, CONSTANT_FRACTION, child); + } + else if (mathNode.Type.isConstant(child)) { + terms = Util.appendToArrayInObject(terms, CONSTANT, child); + } + else if (mathNode.Type.isOperator(node) || + mathNode.Type.isFunction(node) || + mathNode.Type.isParenthesis(node) || + mathNode.Type.isUnaryMinus(node)) { + terms = Util.appendToArrayInObject(terms, OTHER, child); + } + else { + // Note that we shouldn't get any symbol nodes in the switch statement + // since they would have been handled by isPolynomialTerm + throw Error('Unsupported node type: ' + child.type); + } + } + // If there's exactly one constant and one fraction, we collect them + // to add them together. + // e.g. 2 + 1/3 + 5 would collect the constants (2+5) + 1/3 + // but 2 + 1/3 + x would collect (2 + 1/3) + x so we can add them together + if (terms[CONSTANT] && terms[CONSTANT].length === 1 && + terms[CONSTANT_FRACTION] && terms[CONSTANT_FRACTION].length === 1) { + var fraction = terms[CONSTANT_FRACTION][0]; + terms = Util.appendToArrayInObject(terms, CONSTANT, fraction); + delete terms[CONSTANT_FRACTION]; + } + return terms; +} +function getTermsForCollectingMultiplication(node) { + var terms = {}; + for (var i = 0; i < node.args.length; i++) { + var child = node.args[i]; + if (mathNode.Type.isUnaryMinus(child)) { + terms = Util.appendToArrayInObject(terms, CONSTANT, mathNode.Creator.constant(-1)); + child = child.args[0]; + } + if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { + terms = addToTermsforPolynomialMultiplication(terms, child); + } + else if (mathNode.Type.isIntegerFraction(child)) { + terms = Util.appendToArrayInObject(terms, CONSTANT, child); + } + else if (mathNode.Type.isConstant(child)) { + terms = Util.appendToArrayInObject(terms, CONSTANT, child); + } + else if (mathNode.Type.isOperator(node) || + mathNode.Type.isFunction(node) || + mathNode.Type.isParenthesis(node) || + mathNode.Type.isUnaryMinus(node)) { + terms = Util.appendToArrayInObject(terms, OTHER, child); + } + else { + // Note that we shouldn't get any symbol nodes in the switch statement + // since they would have been handled by isPolynomialTerm + throw Error('Unsupported node type: ' + child.type); + } + } + return terms; +} +function addToTermsforPolynomialMultiplication(terms, node) { + var polyNode = new mathNode.PolynomialTerm(node); + var termName; + if (!polyNode.hasCoeff()) { + termName = getTermName(node, '*'); + terms = Util.appendToArrayInObject(terms, termName, node); + } + else { + var coefficient = polyNode.getCoeffNode(); + var termWithoutCoefficient = polyNode.getSymbolNode(); + if (polyNode.getExponentNode()) { + termWithoutCoefficient = mathNode.Creator.operator('^', [termWithoutCoefficient, polyNode.getExponentNode()]); + } + terms = Util.appendToArrayInObject(terms, CONSTANT, coefficient); + termName = getTermName(termWithoutCoefficient, '*'); + terms = Util.appendToArrayInObject(terms, termName, termWithoutCoefficient); + } + return terms; +} +// Sort function for termnames. Sort first by symbol name, and then by exponent. +function sortTerms(a, b) { + if (a === b) { + return 0; + } + // if no exponent, sort alphabetically + if (a.indexOf('^') === -1) { + return a < b ? -1 : 1; + } + else { + var symbA = a.split('^')[0]; + var expA = a.split('^')[1]; + var symbB = b.split('^')[0]; + var expB = b.split('^')[1]; + if (symbA !== symbB) { + return symbA < symbB ? -1 : 1; + } + else { + return expA > expB ? -1 : 1; + } + } +} +module.exports = LikeTermCollector; +//# sourceMappingURL=LikeTermCollector.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map new file mode 100644 index 00000000..4584c1b7 --- /dev/null +++ b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map @@ -0,0 +1 @@ +{"version":3,"file":"LikeTermCollector.js","sourceRoot":"","sources":["LikeTermCollector.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts index f11f204d..7affb9d0 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts @@ -1,11 +1,11 @@ -import clone = require('../../util/clone'); -import print = require('../../util/print'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); -import Util = require('../../util/Util'); -const CONSTANT = 'constant'; -const CONSTANT_FRACTION = 'constantFraction'; -const OTHER = 'other'; +import clone = require("../../util/clone"); +import print = require("../../util/print"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); +import Util = require("../../util/Util"); +const constant = "constant"; +const constantFraction = "constantFraction"; +const other = "other"; class LikeTermCollector{ @@ -16,19 +16,19 @@ class LikeTermCollector{ // Note that we never collect like terms with - or /, those expressions will // always be manipulated in flattenOperands so that the top level operation is // + or *. - if (!(mathNode.Type.isOperator(node, '+') || mathNode.Type.isOperator(node, '*'))) { + if (!(mathNode.Type.isOperator(node, "+") || mathNode.Type.isOperator(node, "*"))) { return false; } let terms; - if (node.op === '+') { + if (node.op === "+") { terms = getTermsForCollectingAddition(node); } - else if (node.op === '*') { + else if (node.op === "*") { terms = getTermsForCollectingMultiplication(node); } else { - throw Error('Operation not supported: ' + node.op); + throw Error("Operation not supported: " + node.op); } // Conditions we need to meet to decide to to reorganize (collect) the terms: @@ -37,7 +37,7 @@ class LikeTermCollector{ // (note that this means x^2 + x + x + 2 -> x^2 + (x + x) + 2, // which will be recorded as a step, but doesn't change the order of terms) const termTypes = Object.keys(terms); - const filteredTermTypes = termTypes.filter(x => x !== OTHER); + const filteredTermTypes = termTypes.filter(x => x !== other); return (termTypes.length > 1 && filteredTermTypes.some(x => terms[x].length > 1)); }; @@ -50,35 +50,35 @@ collectLikeTerms = node => { const op = node.op; let terms: {}; - if (op === '+') { + if (op === "+") { terms = getTermsForCollectingAddition(node); } - else if (op === '*') { + else if (op === "*") { terms = getTermsForCollectingMultiplication(node); } else { - throw Error('Operation not supported: ' + op); + throw Error("Operation not supported: " + op); } // List the symbols alphabetically const termTypesSorted = Object.keys(terms) - .filter(x => (x !== CONSTANT && x !== CONSTANT_FRACTION && x !== OTHER)) + .filter(x => (x !== constant && x !== constantFraction && x !== other)) .sort(sortTerms); // Then add const - if (terms[CONSTANT]) { + if (terms[constant]) { // at the end for addition (since we'd expect x^2 + (x + x) + 4) - if (op === '+') { - termTypesSorted.push(CONSTANT); + if (op === "+") { + termTypesSorted.push(constant); } // for multipliation it should be at the front (e.g. (3*4) * x^2) - if (op === '*') { - termTypesSorted.unshift(CONSTANT); + if (op === "*") { + termTypesSorted.unshift(constant); } } - if (terms[CONSTANT_FRACTION]) { - termTypesSorted.push(CONSTANT_FRACTION); + if (terms[constantFraction]) { + termTypesSorted.push(constantFraction); } // Collect the new operands under op. @@ -105,8 +105,8 @@ collectLikeTerms = node => { }); // then stick anything else (paren nodes, operator nodes) at the end - if (terms[OTHER]) { - newOperands = newOperands.concat(terms[OTHER]); + if (terms[other]) { + newOperands = newOperands.concat(terms[other]); } const newNode = clone(node); @@ -123,9 +123,9 @@ function getTermName(node, op) { // we 'name' polynomial terms by their symbol name let termName = polyNode.getSymbolName(); // when adding terms, the exponent matters too (e.g. 2x^2 + 5x^3 can't be combined) - if (op === '+') { + if (op === "+") { const exponent = print(polyNode.getExponentNode(true)); - termName += '^' + exponent; + termName += "^" + exponent; } return termName; } @@ -141,36 +141,36 @@ function getTermsForCollectingAddition(node) { const child = node.args[i]; if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { - const termName = getTermName(child, '+'); + const termName = getTermName(child, "+"); terms = Util.appendToArrayInObject(terms, termName, child); } else if (mathNode.Type.isIntegerFraction(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT_FRACTION, child); + terms = Util.appendToArrayInObject(terms, constantFraction, child); } else if (mathNode.Type.isConstant(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, child); + terms = Util.appendToArrayInObject(terms, constant, child); } else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node) || mathNode.Type.isParenthesis(node) || mathNode.Type.isUnaryMinus(node)) { - terms = Util.appendToArrayInObject(terms, OTHER, child); + terms = Util.appendToArrayInObject(terms, other, child); } else { // Note that we shouldn't get any symbol nodes in the switch statement // since they would have been handled by isPolynomialTerm - throw Error('Unsupported node type: ' + child.type); + throw Error("Unsupported node type: " + child.type); } } // If there's exactly one constant and one fraction, we collect them // to add them together. // e.g. 2 + 1/3 + 5 would collect the constants (2+5) + 1/3 // but 2 + 1/3 + x would collect (2 + 1/3) + x so we can add them together - if (terms[CONSTANT] && terms[CONSTANT].length === 1 && - terms[CONSTANT_FRACTION] && terms[CONSTANT_FRACTION].length === 1) { - const fraction = terms[CONSTANT_FRACTION][0]; - terms = Util.appendToArrayInObject(terms, CONSTANT, fraction); - delete terms[CONSTANT_FRACTION]; + if (terms[constant] && terms[constant].length === 1 && + terms[constantFraction] && terms[constantFraction].length === 1) { + const fraction = terms[constantFraction][0]; + terms = Util.appendToArrayInObject(terms, constant, fraction); + delete terms[constantFraction]; } return terms; @@ -191,28 +191,28 @@ function getTermsForCollectingMultiplication(node) { if (mathNode.Type.isUnaryMinus(child)) { terms = Util.appendToArrayInObject( - terms, CONSTANT, mathNode.Creator.constant(-1)); + terms, constant, mathNode.Creator.constant(-1)); child = child.args[0]; } if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { terms = addToTermsforPolynomialMultiplication(terms, child); } else if (mathNode.Type.isIntegerFraction(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, child); + terms = Util.appendToArrayInObject(terms, constant, child); } else if (mathNode.Type.isConstant(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, child); + terms = Util.appendToArrayInObject(terms, constant, child); } else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node) || mathNode.Type.isParenthesis(node) || mathNode.Type.isUnaryMinus(node)) { - terms = Util.appendToArrayInObject(terms, OTHER, child); + terms = Util.appendToArrayInObject(terms, other, child); } else { // Note that we shouldn't get any symbol nodes in the switch statement // since they would have been handled by isPolynomialTerm - throw Error('Unsupported node type: ' + child.type); + throw Error("Unsupported node type: " + child.type); } } return terms; @@ -229,7 +229,7 @@ function addToTermsforPolynomialMultiplication(terms, node) { let termName; if (!polyNode.hasCoeff()) { - termName = getTermName(node, '*'); + termName = getTermName(node, "*"); terms = Util.appendToArrayInObject(terms, termName, node); } else { @@ -237,11 +237,11 @@ function addToTermsforPolynomialMultiplication(terms, node) { let termWithoutCoefficient = polyNode.getSymbolNode(); if (polyNode.getExponentNode()) { termWithoutCoefficient = mathNode.Creator.operator( - '^', [termWithoutCoefficient, polyNode.getExponentNode()]); + "^", [termWithoutCoefficient, polyNode.getExponentNode()]); } - terms = Util.appendToArrayInObject(terms, CONSTANT, coefficient); - termName = getTermName(termWithoutCoefficient, '*'); + terms = Util.appendToArrayInObject(terms, constant, coefficient); + termName = getTermName(termWithoutCoefficient, "*"); terms = Util.appendToArrayInObject(terms, termName, termWithoutCoefficient); } return terms; @@ -253,15 +253,15 @@ function sortTerms(a, b) { return 0; } // if no exponent, sort alphabetically - if (a.indexOf('^') === -1) { + if (a.indexOf("^") === -1) { return a < b ? -1 : 1; } // if exponent: sort by symbol, but then exponent decreasing else { - const symbA = a.split('^')[0]; - const expA = a.split('^')[1]; - const symbB = b.split('^')[0]; - const expB = b.split('^')[1]; + const symbA = a.split("^")[0]; + const expA = a.split("^")[1]; + const symbB = b.split("^")[0]; + const expB = b.split("^")[1]; if (symbA !== symbB) { return symbA < symbB ? -1 : 1; } diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js index e4c18663..bf92d636 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js +++ b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js @@ -101,7 +101,7 @@ function groupCoefficientsForAdding(node) { var newNode = clone(node); var polynomialTermList = newNode.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); var coefficientList = polynomialTermList.map(function (p) { return p.getCoeffNode(true); }); - var sumOfCoefficents = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', coefficientList)); + var sumOfCoefficents = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", coefficientList)); // TODO: changegroups should also be on the before node, on all the // coefficients, but changegroups with polyTerm gets messy so let's tackle // that later. diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts index 9d72b8c1..7f2b7cf9 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts @@ -1,11 +1,11 @@ -import checks = require('../../checks'); -import clone = require('../../util/clone'); -import evaluateConstantSum = require('./evaluateConstantSum'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import checks = require("../../checks"); +import clone = require("../../util/clone"); +import evaluateConstantSum = require("./evaluateConstantSum"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // Adds a list of nodes that are polynomial terms. Returns a mathNode.Status object. -function addLikeTerms(node, polynomialOnly=false) { +function addLikeTerms(node: mathjs.MathNode, polynomialOnly=false) { if (!mathNode.Type.isOperator(node)) { return mathNode.Status.noChange(node); } @@ -26,8 +26,7 @@ function addLikeTerms(node, polynomialOnly=false) { return mathNode.Status.noChange(node); } -function addLikePolynomialTerms(node: any); -function addLikePolynomialTerms(node) { +function addLikePolynomialTerms(node: mathjs.MathNode) { if (!checks.canAddLikeTermPolynomialNodes(node)) { return mathNode.Status.noChange(node); } @@ -73,8 +72,7 @@ function addLikePolynomialTerms(node) { // makes the adding coefficients step clearer. // e.g. 2x + x -> 2x + 1x // Returns a mathNode.Status object. -function addPositiveOneCoefficient(node: any); -function addPositiveOneCoefficient(node) { +function addPositiveOneCoefficient(node: mathjs.MathNode) { const newNode = clone(node); let change = false; @@ -110,8 +108,7 @@ function addPositiveOneCoefficient(node) { // pedagogy, and makes the adding coefficients step clearer. // e.g. 2x - x -> 2x - 1x // Returns a mathNode.Status object. -function addNegativeOneCoefficient(node: any); -function addNegativeOneCoefficient(node) { +function addNegativeOneCoefficient(node: mathjs.MathNode) { const newNode = clone(node); let change = false; @@ -152,7 +149,7 @@ function groupCoefficientsForAdding(node) { const polynomialTermList = newNode.args.map(n => new mathNode.PolynomialTerm(n)); const coefficientList = polynomialTermList.map(p => p.getCoeffNode(true)); const sumOfCoefficents = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', coefficientList)); + mathNode.Creator.operator("+", coefficientList)); // TODO: changegroups should also be on the before node, on all the // coefficients, but changegroups with polyTerm gets messy so let's tackle // that later. diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js index 707681b7..53247734 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js +++ b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js @@ -9,7 +9,7 @@ function evaluateConstantSum(node) { if (mathNode.Type.isParenthesis(node)) { node = node.content; } - if (!mathNode.Type.isOperator(node) || node.op !== '+') { + if (!mathNode.Type.isOperator(node) || node.op !== "+") { return mathNode.Status.noChange(node); } if (node.args.some(function (node) { return !mathNode.Type.isConstantOrConstantFraction(node); })) { @@ -68,10 +68,10 @@ function groupConstantsAndFractions(node) { var fractions = node.args.filter(mathNode.Type.isIntegerFraction); var constants = node.args.filter(mathNode.Type.isConstant); if (fractions.length === 0 || constants.length === 0) { - throw Error('expected both integer fractions and constants, got ' + node); + throw Error("expected both integer fractions and constants, got " + node); } if (fractions.length + constants.length !== node.args.length) { - throw Error('can only evaluate integer fractions and constants'); + throw Error("can only evaluate integer fractions and constants"); } constants = constants.map(function (node) { // set the changeGroup - this affects both the old and new node @@ -81,7 +81,7 @@ function groupConstantsAndFractions(node) { }); // wrap in parenthesis if there's more than one, to group them if (constants.length > 1) { - constants = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', constants)); + constants = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", constants)); } else { constants = constants[0]; @@ -94,12 +94,12 @@ function groupConstantsAndFractions(node) { }); // wrap in parenthesis if there's more than one, to group them if (fractions.length > 1) { - fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', fractions)); + fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", fractions)); } else { fractions = fractions[0]; } - var newNode = mathNode.Creator.operator('+', [constants, fractions]); + var newNode = mathNode.Creator.operator("+", [constants, fractions]); return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_LIKE_TERMS, node, newNode); } module.exports = evaluateConstantSum; diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts index fe06263e..eb8e9768 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts @@ -1,9 +1,9 @@ -import addConstantAndFraction = require('../fractionsSearch/addConstantAndFraction'); -import addConstantFractions = require('../fractionsSearch/addConstantFractions'); -import arithmeticSearch = require('../arithmeticSearch'); -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import addConstantAndFraction = require("../fractionsSearch/addConstantAndFraction"); +import addConstantFractions = require("../fractionsSearch/addConstantFractions"); +import arithmeticSearch = require("../arithmeticSearch"); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // Evaluates a sum of constant numbers and integer fractions to a single // constant number or integer fraction. e.g. e.g. 2/3 + 5 + 5/2 => 49/6 @@ -13,7 +13,7 @@ function evaluateConstantSum(node) { if (mathNode.Type.isParenthesis(node)) { node = node.content; } - if (!mathNode.Type.isOperator(node) || node.op !== '+') { + if (!mathNode.Type.isOperator(node) || node.op !== "+") { return mathNode.Status.noChange(node); } if (node.args.some(node => !mathNode.Type.isConstantOrConstantFraction(node))) { @@ -90,11 +90,11 @@ function groupConstantsAndFractions(node) { let constants = node.args.filter(mathNode.Type.isConstant); if (fractions.length === 0 || constants.length === 0) { - throw Error('expected both integer fractions and constants, got ' + node); + throw Error("expected both integer fractions and constants, got " + node); } if (fractions.length + constants.length !== node.args.length) { - throw Error('can only evaluate integer fractions and constants'); + throw Error("can only evaluate integer fractions and constants"); } constants = constants.map(node => { @@ -105,7 +105,7 @@ function groupConstantsAndFractions(node) { }); // wrap in parenthesis if there's more than one, to group them if (constants.length > 1) { - constants = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', constants)); + constants = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", constants)); } else { constants = constants[0]; @@ -119,13 +119,13 @@ function groupConstantsAndFractions(node) { }); // wrap in parenthesis if there's more than one, to group them if (fractions.length > 1) { - fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', fractions)); + fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", fractions)); } else { fractions = fractions[0]; } - const newNode = mathNode.Creator.operator('+', [constants, fractions]); + const newNode = mathNode.Creator.operator("+", [constants, fractions]); return mathNode.Status.nodeChanged( ChangeTypes.COLLECT_LIKE_TERMS, node, newNode); } diff --git a/lib/simplifyExpression/collectAndCombineSearch/index.ts b/lib/simplifyExpression/collectAndCombineSearch/index.ts index 78482c15..bcd7ad4d 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/index.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/index.ts @@ -1,12 +1,12 @@ // Collects and combines like terms -import addLikeTerms = require('./addLikeTerms'); -import clone = require('../../util/clone'); -import multiplyLikeTerms = require('./multiplyLikeTerms'); -import ChangeTypes = require('../../ChangeTypes'); -import LikeTermCollector = require('./LikeTermCollector'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); +import addLikeTerms = require("./addLikeTerms"); +import clone = require("../../util/clone"); +import multiplyLikeTerms = require("./multiplyLikeTerms"); +import ChangeTypes = require("../../ChangeTypes"); +import LikeTermCollector = require("./LikeTermCollector"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); const termCollectorFunctions = { '+': addLikeTerms, '*': multiplyLikeTerms @@ -20,7 +20,7 @@ const search = TreeSearch.postOrder(collectAndCombineLikeTerms); // e.g. 2x + 4x + y => 6x + y // e.g. 2x * x^2 * 5x => 10 x^4 function collectAndCombineLikeTerms(node) { - if (node.op === '+') { + if (node.op === "+") { const status = collectAndCombineOperation(node); if (status.hasChanged()) { return status; @@ -29,7 +29,7 @@ function collectAndCombineLikeTerms(node) { // e.g. 2x + 4x + x (doesn't need collecting) return addLikeTerms(node, true); } - else if (node.op === '*') { + else if (node.op === "*") { // collect and combine involves there being coefficients pulled the front // e.g. 2x * x^2 * 5x => (2*5) * (x * x^2 * x) => ... => 10 x^4 const status = collectAndCombineOperation(node); diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts index 9ed2fae9..68f1a090 100644 --- a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts +++ b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts @@ -1,9 +1,9 @@ -import arithmeticSearch = require('../arithmeticSearch'); -import checks = require('../../checks'); -import clone = require('../../util/clone'); -import multiplyFractionsSearch = require('../multiplyFractionsSearch'); -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); +import arithmeticSearch = require("../arithmeticSearch"); +import checks = require("../../checks"); +import clone = require("../../util/clone"); +import multiplyFractionsSearch = require("../multiplyFractionsSearch"); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); // Multiplies a list of nodes that are polynomial like terms. Returns a node. // The polynomial nodes should *not* have coefficients. (multiplying @@ -136,7 +136,7 @@ function collectExponents(node) { // parens) e.g. x^(3+4+5) const exponentNodeList = polynomialTermList.map(p => p.getExponentNode(true)); const newExponent = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', exponentNodeList)); + mathNode.Creator.operator("+", exponentNodeList)); const newNode = mathNode.Creator.polynomialTerm(symbolNode, newExponent, null); return mathNode.Status.nodeChanged( ChangeTypes.COLLECT_EXPONENTS, node, newNode); diff --git a/lib/simplifyExpression/distributeSearch/index.js b/lib/simplifyExpression/distributeSearch/index.js index 15faf915..3a7c600f 100644 --- a/lib/simplifyExpression/distributeSearch/index.js +++ b/lib/simplifyExpression/distributeSearch/index.js @@ -36,13 +36,13 @@ function distributeUnaryMinus(node) { // For multiplication and division, we can push the unary minus in to // the first argument. // e.g. -(2/3) -> (-2/3) -(4*9*x^2) --> (-4 * 9 * x^2) - if (content.op === '*' || content.op === '/') { + if (content.op === "*" || content.op === "/") { newContent.args[0] = Negative.negate(newContent.args[0]); newContent.args[0].changeGroup = 1; var newNode = mathNode.Creator.parenthesis(newContent); return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); } - else if (content.op === '+') { + else if (content.op === "+") { // Now we know `node` is of the form -(x + y + ...). // We want to now return (-x + -y + ....) // If any term is negative, we make it positive it right away @@ -61,7 +61,7 @@ function distributeUnaryMinus(node) { } } function distributeAndSimplifyOperationNode(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '*') { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { return mathNode.Status.noChange(node); } // STEP 1: distribute with `distributeTwoNodes` @@ -94,7 +94,7 @@ function distributeAndSimplifyOperationNode(node) { // case 1: there were more than two operands in this multiplication // e.g. 3*7*(2+x)*(3+x)*(4+x) is a multiplication node with 5 children // and the new node will be 3*(14+7x)*(3+x)*(4+x) with 4 children. - if (mathNode.Type.isOperator(newNode, '*')) { + if (mathNode.Type.isOperator(newNode, "*")) { var childStatus = simplifyWithParens(newNode.args[i]); if (childStatus.hasChanged()) { status_1 = mathNode.Status.childChanged(newNode, childStatus, i); @@ -110,7 +110,7 @@ function distributeAndSimplifyOperationNode(node) { } } else { - throw Error('Unsupported node type for distribution: ' + node); + throw Error("Unsupported node type for distribution: " + node); } if (substeps.length === 1) { return substeps[0]; @@ -145,12 +145,12 @@ function distributeTwoNodes(firstNode, secondNode) { fractionNodes.forEach(function (node) { var arg; if (isFraction(node)) { - var numerator = mathNode.Creator.operator('*', [node.args[0], nonFractionTerm_1]); + var numerator = mathNode.Creator.operator("*", [node.args[0], nonFractionTerm_1]); numerator = mathNode.Creator.parenthesis(numerator); - arg = mathNode.Creator.operator('/', [numerator, node.args[1]]); + arg = mathNode.Creator.operator("/", [numerator, node.args[1]]); } else { - arg = mathNode.Creator.operator('*', [node, nonFractionTerm_1]); + arg = mathNode.Creator.operator("*", [node, nonFractionTerm_1]); } arg.changeGroup = 1; newArgs.push(arg); @@ -158,7 +158,7 @@ function distributeTwoNodes(firstNode, secondNode) { } else if (firstArgs.length > 1 && secondArgs.length > 1) { firstArgs.forEach(function (leftArg) { - var arg = mathNode.Creator.operator('*', [leftArg, secondNode]); + var arg = mathNode.Creator.operator("*", [leftArg, secondNode]); arg.changeGroup = 1; newArgs.push(arg); }); @@ -167,23 +167,23 @@ function distributeTwoNodes(firstNode, secondNode) { // a list of all pairs of nodes between the two arg lists firstArgs.forEach(function (leftArg) { secondArgs.forEach(function (rightArg) { - var arg = mathNode.Creator.operator('*', [leftArg, rightArg]); + var arg = mathNode.Creator.operator("*", [leftArg, rightArg]); arg.changeGroup = 1; newArgs.push(arg); }); }); } - return mathNode.Creator.parenthesis(mathNode.Creator.operator('+', newArgs)); + return mathNode.Creator.parenthesis(mathNode.Creator.operator("+", newArgs)); } function hasFraction(args) { return args.filter(isFraction).length > 0; } function isFraction(node) { - return mathNode.Type.isOperator(node, '/'); + return mathNode.Type.isOperator(node, "/"); } function simplifyWithParens(node) { if (!mathNode.Type.isParenthesis(node)) { - throw Error('expected ' + node + ' to be a parenthesis node'); + throw Error("expected " + node + " to be a parenthesis node"); } var status = simplify(node.content); if (status.hasChanged()) { @@ -225,7 +225,7 @@ function isParenthesisOfAddition(node) { return false; } var content = node.content; - return mathNode.Type.isOperator(content, '+'); + return mathNode.Type.isOperator(content, "+"); } module.exports = search; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/distributeSearch/index.ts b/lib/simplifyExpression/distributeSearch/index.ts index 5c2b06a8..e62e1f4b 100644 --- a/lib/simplifyExpression/distributeSearch/index.ts +++ b/lib/simplifyExpression/distributeSearch/index.ts @@ -1,19 +1,18 @@ -import arithmeticSearch = require('../arithmeticSearch'); -import clone = require('../../util/clone'); -import collectAndCombineSearch = require('../collectAndCombineSearch'); -import rearrangeCoefficient = require('../basicsSearch/rearrangeCoefficient'); -import ChangeTypes = require('../../ChangeTypes'); -import Negative = require('../../Negative'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); +import arithmeticSearch = require("../arithmeticSearch"); +import clone = require("../../util/clone"); +import collectAndCombineSearch = require("../collectAndCombineSearch"); +import rearrangeCoefficient = require("../basicsSearch/rearrangeCoefficient"); +import ChangeTypes = require("../../ChangeTypes"); +import Negative = require("../../Negative"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); const search = TreeSearch.postOrder(distribute); // Distributes through parenthesis. // e.g. 2(x+3) -> (2*x + 2*3) // e.g. -(x+5) -> (-x + -5) // Returns a mathNode.Status object. -function distribute(node: any); -function distribute(node) { +function distribute(node: mathjs.MathNode) { if (mathNode.Type.isUnaryMinus(node)) { return distributeUnaryMinus(node); } @@ -29,8 +28,7 @@ function distribute(node) { // e.g. -(4*9*x^2) --> (-4 * 9 * x^2) // e.g. -(x + y - 5) --> (-x + -y + 5) // Returns a mathNode.Status object. -function distributeUnaryMinus(node: any); -function distributeUnaryMinus(node) { +function distributeUnaryMinus(node: mathjs.MathNode) { if (!mathNode.Type.isUnaryMinus(node)) { return mathNode.Status.noChange(node); } @@ -38,7 +36,7 @@ function distributeUnaryMinus(node) { if (!mathNode.Type.isParenthesis(unaryContent)) { return mathNode.Status.noChange(node); } - const content = unaryContent.content; + const content = unaryContent; if (!mathNode.Type.isOperator(content)) { return mathNode.Status.noChange(node); } @@ -47,14 +45,14 @@ function distributeUnaryMinus(node) { // For multiplication and division, we can push the unary minus in to // the first argument. // e.g. -(2/3) -> (-2/3) -(4*9*x^2) --> (-4 * 9 * x^2) - if (content.op === '*' || content.op === '/') { + if (content.op === "*" || content.op === "/") { newContent.args[0] = Negative.negate(newContent.args[0]); newContent.args[0].changeGroup = 1; const newNode = mathNode.Creator.parenthesis(newContent); return mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); } - else if (content.op === '+') { + else if (content.op === "+") { // Now we know `node` is of the form -(x + y + ...). // We want to now return (-x + -y + ....) // If any term is negative, we make it positive it right away @@ -79,9 +77,8 @@ function distributeUnaryMinus(node) { // each other, and at least one of them must be a parenthesis node. // e.g. 2*(3+x) or (4+x^2+x^3)*(x+3) // Returns a mathNode.Status object with substeps -function distributeAndSimplifyOperationNode(node: any); -function distributeAndSimplifyOperationNode(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '*') { +function distributeAndSimplifyOperationNode(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { return mathNode.Status.noChange(node); } @@ -121,7 +118,7 @@ function distributeAndSimplifyOperationNode(node) { // case 1: there were more than two operands in this multiplication // e.g. 3*7*(2+x)*(3+x)*(4+x) is a multiplication node with 5 children // and the new node will be 3*(14+7x)*(3+x)*(4+x) with 4 children. - if (mathNode.Type.isOperator(newNode, '*')) { + if (mathNode.Type.isOperator(newNode, "*")) { const childStatus = simplifyWithParens(newNode.args[i]); if (childStatus.hasChanged()) { status = mathNode.Status.childChanged(newNode, childStatus, i); @@ -140,7 +137,7 @@ function distributeAndSimplifyOperationNode(node) { } } else { - throw Error('Unsupported node type for distribution: ' + node); + throw Error("Unsupported node type for distribution: " + node); } if (substeps.length === 1) { @@ -157,19 +154,18 @@ function distributeAndSimplifyOperationNode(node) { // e.g. 2*(x+3) -> (2*x + 2*3) (5+x)*x -> 5*x + x*x // e.g. (5+x)*(x+3) -> (5*x + 5*3 + x*x + x*3) // Returns a node. -function distributeTwoNodes(firstNode: any, secondNode: any); -function distributeTwoNodes(firstNode, secondNode) { +function distributeTwoNodes(firstNode: mathjs.MathNode, secondNode: mathjs.MathNode) { // lists of terms we'll be multiplying together from each node let firstArgs, secondArgs; if (isParenthesisOfAddition(firstNode)) { - firstArgs = firstNode.content.args; + firstArgs = firstNode.args; } else { firstArgs = [firstNode]; } if (isParenthesisOfAddition(secondNode)) { - secondArgs = secondNode.content.args; + secondArgs = secondNode.args; } else { secondArgs = [secondNode]; @@ -186,12 +182,12 @@ function distributeTwoNodes(firstNode, secondNode) { fractionNodes.forEach((node) => { let arg; if (isFraction(node)) { - let numerator = mathNode.Creator.operator('*', [node.args[0], nonFractionTerm]); + let numerator = mathNode.Creator.operator("*", [node.args[0], nonFractionTerm]); numerator = mathNode.Creator.parenthesis(numerator); - arg = mathNode.Creator.operator('/', [numerator, node.args[1]]); + arg = mathNode.Creator.operator("/", [numerator, node.args[1]]); } else { - arg = mathNode.Creator.operator('*', [node, nonFractionTerm]); + arg = mathNode.Creator.operator("*", [node, nonFractionTerm]); } arg.changeGroup = 1; newArgs.push(arg); @@ -201,7 +197,7 @@ function distributeTwoNodes(firstNode, secondNode) { // step. else if (firstArgs.length > 1 && secondArgs.length > 1) { firstArgs.forEach(leftArg => { - const arg = mathNode.Creator.operator('*', [leftArg, secondNode]); + const arg = mathNode.Creator.operator("*", [leftArg, secondNode]); arg.changeGroup = 1; newArgs.push(arg); }); @@ -210,23 +206,21 @@ function distributeTwoNodes(firstNode, secondNode) { // a list of all pairs of nodes between the two arg lists firstArgs.forEach(leftArg => { secondArgs.forEach(rightArg => { - const arg = mathNode.Creator.operator('*', [leftArg, rightArg]); + const arg = mathNode.Creator.operator("*", [leftArg, rightArg]); arg.changeGroup = 1; newArgs.push(arg); }); }); } - return mathNode.Creator.parenthesis(mathNode.Creator.operator('+', newArgs)); + return mathNode.Creator.parenthesis(mathNode.Creator.operator("+", newArgs)); } -function hasFraction(args: any); function hasFraction(args) { return args.filter(isFraction).length > 0; } -function isFraction(node: any); -function isFraction(node) { - return mathNode.Type.isOperator(node, '/'); +function isFraction(node: mathjs.MathNode) { + return mathNode.Type.isOperator(node, "/"); } // Simplifies a sum of terms (a result of distribution) that's in parens @@ -238,7 +232,7 @@ function isFraction(node) { function simplifyWithParens(node: any); function simplifyWithParens(node) { if (!mathNode.Type.isParenthesis(node)) { - throw Error('expected ' + node + ' to be a parenthesis node'); + throw Error(`expected ${node} to be a parenthesis node`); } const status = simplify(node.content); @@ -254,8 +248,7 @@ function simplifyWithParens(node) { // e.g. (2x+3)*(4x+5) -distribute-> 2x*(4x+5) + 3*(4x+5) <- 2 terms to simplify // e.g. 2x*(4x+5) --distribute--> 2x*4x + 2x*5 --simplify--> 8x^2 + 10x // Returns a mathNode.Status object. -function simplify(node: any); -function simplify(node) { +function simplify(node: mathjs.MathNode) { const substeps = []; const simplifyFunctions = [ arithmeticSearch, // e.g. 2*9 -> 18 @@ -287,13 +280,12 @@ function simplify(node) { } // returns true if `node` is of the type (node + node + ...) -function isParenthesisOfAddition(node: any); -function isParenthesisOfAddition(node) { +function isParenthesisOfAddition(node: mathjs.MathNode) { if (!mathNode.Type.isParenthesis(node)) { return false; } const content = node.content; - return mathNode.Type.isOperator(content, '+'); + return mathNode.Type.isOperator(content, "+"); } export = search; diff --git a/lib/simplifyExpression/divisionSearch/index.js b/lib/simplifyExpression/divisionSearch/index.js new file mode 100644 index 00000000..a1881d90 --- /dev/null +++ b/lib/simplifyExpression/divisionSearch/index.js @@ -0,0 +1,68 @@ +"use strict"; +var ChangeTypes = require("../../ChangeTypes"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +// Searches for and simplifies any chains of division or nested division. +// Returns a mathNode.Status object +var search = TreeSearch.preOrder(division); +function division(node) { + if (!mathNode.Type.isOperator(node) || node.op !== "/") { + return mathNode.Status.noChange(node); + } + // e.g. 2/(x/6) => 2 * 6/x + var nodeStatus = multiplyByInverse(node); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + // e.g. 2/x/6 -> 2/(x*6) + nodeStatus = simplifyDivisionChain(node); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + return mathNode.Status.noChange(node); +} +function multiplyByInverse(node) { + var denominator = node.args[1]; + if (mathNode.Type.isParenthesis(denominator)) { + denominator = denominator.content; + } + if (!mathNode.Type.isOperator(denominator) || denominator.op !== "/") { + return mathNode.Status.noChange(node); + } + // At this point, we know that node is a fraction and denonimator is the + // fraction we need to inverse. + var inverseNumerator = denominator.args[1]; + var inverseDenominator = denominator.args[0]; + var inverseFraction = mathNode.Creator.operator("/", [inverseNumerator, inverseDenominator]); + var newNode = mathNode.Creator.operator("*", [node.args[0], inverseFraction]); + return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_BY_INVERSE, node, newNode); +} +function simplifyDivisionChain(node) { + // check for a chain of division + var denominatorList = getDenominatorList(node); + // one for the numerator, and at least two terms in the denominator + if (denominatorList.length > 2) { + var numerator = denominatorList.shift(); + // the new single denominator is all the chained denominators + // multiplied together, in parentheses. + var denominator = mathNode.Creator.parenthesis(mathNode.Creator.operator("*", denominatorList)); + var newNode = mathNode.Creator.operator("/", [numerator, denominator]); + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_DIVISION, node, newNode); + } + return mathNode.Status.noChange(node); +} +function getDenominatorList(denominator) { + var node = denominator; + var denominatorList = []; + while (node.op === "/") { + // unshift the denominator to the front of the list, and recurse on + // the numerator + denominatorList.unshift(node.args[1]); + node = node.args[0]; + } + // unshift the final node, which wasn't a / node + denominatorList.unshift(node); + return denominatorList; +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/divisionSearch/index.js.map b/lib/simplifyExpression/divisionSearch/index.js.map new file mode 100644 index 00000000..0477903b --- /dev/null +++ b/lib/simplifyExpression/divisionSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,yEAAyE;AACzE,mCAAmC;AACnC,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAG7C,kBAAkB,IAAI;IACpB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,0BAA0B;IAC1B,IAAI,UAAU,GAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5B,MAAM,CAAC,UAAU,CAAC;IACpB,CAAC;IACD,wBAAwB;IACxB,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACzC,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5B,MAAM,CAAC,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAMD,2BAA2B,IAAI;IAC7B,IAAI,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC7C,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC;IACpC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,wEAAwE;IACxE,+BAA+B;IAC/B,IAAM,gBAAgB,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7C,IAAM,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/C,IAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAC/C,GAAG,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAE/C,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;IAChF,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC;AAMD,+BAA+B,IAAI;IACjC,gCAAgC;IAChC,IAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACjD,mEAAmE;IACnE,EAAE,CAAC,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAM,SAAS,GAAG,eAAe,CAAC,KAAK,EAAE,CAAC;QAC1C,6DAA6D;QAC7D,uCAAuC;QACvC,IAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAC9C,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;QACnD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;QACzE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,iBAAiB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAMD,4BAA4B,WAAW;IACrC,IAAI,IAAI,GAAG,WAAW,CAAC;IACvB,IAAM,eAAe,GAAG,EAAE,CAAC;IAC3B,OAAO,IAAI,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC;QACvB,mEAAmE;QACnE,gBAAgB;QAChB,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,gDAAgD;IAChD,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,eAAe,CAAC;AACzB,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/divisionSearch/index.ts b/lib/simplifyExpression/divisionSearch/index.ts index 59bd7815..370b1d00 100644 --- a/lib/simplifyExpression/divisionSearch/index.ts +++ b/lib/simplifyExpression/divisionSearch/index.ts @@ -1,14 +1,13 @@ -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); // Searches for and simplifies any chains of division or nested division. // Returns a mathNode.Status object const search = TreeSearch.preOrder(division); -function division(node: any); -function division(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '/') { +function division(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "/") { return mathNode.Status.noChange(node); } // e.g. 2/(x/6) => 2 * 6/x @@ -27,13 +26,13 @@ function division(node) { // If `node` is a fraction with a denominator that is also a fraction, multiply // by the inverse. // e.g. x/(2/3) -> x * 3/2 -function multiplyByInverse(node: any); -function multiplyByInverse(node) { + +function multiplyByInverse(node: mathjs.MathNode) { let denominator = node.args[1]; if (mathNode.Type.isParenthesis(denominator)) { denominator = denominator.content; } - if (!mathNode.Type.isOperator(denominator) || denominator.op !== '/') { + if (!mathNode.Type.isOperator(denominator) || denominator.op !== "/") { return mathNode.Status.noChange(node); } // At this point, we know that node is a fraction and denonimator is the @@ -41,9 +40,9 @@ function multiplyByInverse(node) { const inverseNumerator = denominator.args[1]; const inverseDenominator = denominator.args[0]; const inverseFraction = mathNode.Creator.operator( - '/', [inverseNumerator, inverseDenominator]); + "/", [inverseNumerator, inverseDenominator]); - const newNode = mathNode.Creator.operator('*', [node.args[0], inverseFraction]); + const newNode = mathNode.Creator.operator("*", [node.args[0], inverseFraction]); return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_BY_INVERSE, node, newNode); } @@ -51,8 +50,7 @@ function multiplyByInverse(node) { // Simplifies any chains of division into a single division operation. // e.g. 2/x/6 -> 2/(x*6) // Returns a mathNode.Status object -function simplifyDivisionChain(node: any); -function simplifyDivisionChain(node) { +function simplifyDivisionChain(node: mathjs.MathNode) { // check for a chain of division const denominatorList = getDenominatorList(node); // one for the numerator, and at least two terms in the denominator @@ -61,8 +59,8 @@ function simplifyDivisionChain(node) { // the new single denominator is all the chained denominators // multiplied together, in parentheses. const denominator = mathNode.Creator.parenthesis( - mathNode.Creator.operator('*', denominatorList)); - const newNode = mathNode.Creator.operator('/', [numerator, denominator]); + mathNode.Creator.operator("*", denominatorList)); + const newNode = mathNode.Creator.operator("/", [numerator, denominator]); return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_DIVISION, node, newNode); } @@ -72,11 +70,11 @@ function simplifyDivisionChain(node) { // Given a the denominator of a division node, returns all the nested // denominator nodess. e.g. 2/3/4/5 would return [2,3,4,5] // (note: all the numbers in the example are actually constant nodes) -function getDenominatorList(denominator: any); + function getDenominatorList(denominator) { let node = denominator; const denominatorList = []; - while (node.op === '/') { + while (node.op === "/") { // unshift the denominator to the front of the list, and recurse on // the numerator denominatorList.unshift(node.args[1]); diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js index 4e0273e0..c4724ded 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js @@ -4,12 +4,16 @@ var clone = require("../../util/clone"); var ChangeTypes = require("../../ChangeTypes"); var evaluate = require("../../util/evaluate"); var mathNode = require("../../mathnode"); +// Adds a constant to a fraction by: +// - collapsing the fraction to decimal if the constant is not an integer +// e.g. 5.3 + 1/2 -> 5.3 + 0.2 +// - turning the constant into a fraction with the same denominator if it is +// an integer, e.g. 5 + 1/2 -> 10/2 + 1/2 function addConstantAndFraction(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '+' || node.args.length !== 2) { + if (!mathNode.Type.isOperator(node) || node.op !== "+" || node.args.length !== 2) { return mathNode.Status.noChange(node); } - var firstArg = node.args[0]; - var secondArg = node.args[1]; + var _a = node.args, firstArg = _a[0], secondArg = _a[1]; var constNode, fractionNode; if (mathNode.Type.isConstant(firstArg)) { if (mathNode.Type.isIntegerFraction(secondArg)) { @@ -44,7 +48,7 @@ function addConstantAndFraction(node) { var denominatorValue = parseInt(denominatorNode); var constNodeValue = parseInt(constNode.value); var newNumeratorNode = mathNode.Creator.constant(constNodeValue * denominatorValue); - newConstNode = mathNode.Creator.operator('/', [newNumeratorNode, denominatorNode]); + newConstNode = mathNode.Creator.operator("/", [newNumeratorNode, denominatorNode]); newFractionNode = fractionNode; changeType = ChangeTypes.CONVERT_INTEGER_TO_FRACTION; } diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map index f393260e..f75ad718 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map @@ -1 +1 @@ -{"version":3,"file":"addConstantAndFraction.js","sourceRoot":"","sources":["addConstantAndFraction.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"addConstantAndFraction.js","sourceRoot":"","sources":["addConstantAndFraction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts index e6675426..de81aba4 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts +++ b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts @@ -1,23 +1,20 @@ -import addConstantFractions = require('./addConstantFractions'); -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import evaluate = require('../../util/evaluate'); -import mathNode = require('../../mathnode'); +import addConstantFractions = require("./addConstantFractions"); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import evaluate = require("../../util/evaluate"); +import mathNode = require("../../mathnode"); // Adds a constant to a fraction by: // - collapsing the fraction to decimal if the constant is not an integer // e.g. 5.3 + 1/2 -> 5.3 + 0.2 // - turning the constant into a fraction with the same denominator if it is // an integer, e.g. 5 + 1/2 -> 10/2 + 1/2 -function addConstantAndFraction(node: any); -function addConstantAndFraction(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '+' || node.args.length !== 2) { +function addConstantAndFraction(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "+" || node.args.length !== 2) { return mathNode.Status.noChange(node); } - - const firstArg = node.args[0]; - const secondArg = node.args[1]; - let constNode, fractionNode; + const [firstArg, secondArg] = node.args; + let constNode, fractionNode; if (mathNode.Type.isConstant(firstArg)) { if (mathNode.Type.isIntegerFraction(secondArg)) { constNode = firstArg; @@ -54,7 +51,7 @@ function addConstantAndFraction(node) { const newNumeratorNode = mathNode.Creator.constant( constNodeValue * denominatorValue); newConstNode = mathNode.Creator.operator( - '/', [newNumeratorNode, denominatorNode]); + "/", [newNumeratorNode, denominatorNode]); newFractionNode = fractionNode; changeType = ChangeTypes.CONVERT_INTEGER_TO_FRACTION; } diff --git a/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts index a8bd3a4b..009e23c9 100644 --- a/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts +++ b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts @@ -1,9 +1,9 @@ -import clone = require('../../util/clone'); -import divideByGCD = require('./divideByGCD'); -import math = require('mathjs'); -import ChangeTypes = require('../../ChangeTypes'); -import evaluate = require('../../util/evaluate'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import divideByGCD = require("./divideByGCD"); +import math = require("mathjs"); +import ChangeTypes = require("../../ChangeTypes"); +import evaluate = require("../../util/evaluate"); +import mathNode = require("../../mathnode"); // Adds constant fractions -- can start from either step 1 or 2 // 1A. Find the LCD if denominators are different and multiplies to make @@ -13,11 +13,10 @@ import mathNode = require('../../mathnode'); // 2A. Combines numerators, e.g. 4/6 + 4/6 -> e.g. 2/5 + 4/5 --> (2+4)/5 // 2B. Adds numerators together, e.g. (2+4)/5 -> 6/5 // Returns a mathNode.Status object with substeps -function addConstantFractions(node: any); -function addConstantFractions(node) { +function addConstantFractions(node: mathjs.MathNode) { let newNode = clone(node); - if (!mathNode.Type.isOperator(node) || node.op !== '+') { + if (!mathNode.Type.isOperator(node) || node.op !== "+") { return mathNode.Status.noChange(node); } if (!node.args.every(n => mathNode.Type.isIntegerFraction(n, true))) { @@ -80,8 +79,7 @@ function addConstantFractions(node) { // Given a + operation node with a list of fraction nodes as args that all have // the same denominator, add them together. e.g. 2/3 + 5/3 -> (2+5)/3 // Returns the new node. -function combineNumeratorsAboveCommonDenominator(node: any); -function combineNumeratorsAboveCommonDenominator(node) { +function combineNumeratorsAboveCommonDenominator(node: mathjs.MathNode) { let newNode = clone(node); const commonDenominator = newNode.args[0].args[1]; @@ -90,17 +88,16 @@ function combineNumeratorsAboveCommonDenominator(node) { numeratorArgs.push(fraction.args[0]); }); const newNumerator = mathNode.Creator.parenthesis( - mathNode.Creator.operator('+', numeratorArgs)); + mathNode.Creator.operator("+", numeratorArgs)); - newNode = mathNode.Creator.operator('/', [newNumerator, commonDenominator]); + newNode = mathNode.Creator.operator("/", [newNumerator, commonDenominator]); return mathNode.Status.nodeChanged( ChangeTypes.COMBINE_NUMERATORS, node, newNode); } // Given a node with a numerator that is an addition node, will add // all the numerators and return the result -function addNumeratorsTogether(node: any); -function addNumeratorsTogether(node) { +function addNumeratorsTogether(node: mathjs.MathNode) { const newNode = clone(node); newNode.args[0] = mathNode.Creator.constant(evaluate(newNode.args[0])); @@ -108,11 +105,10 @@ function addNumeratorsTogether(node) { ChangeTypes.ADD_NUMERATORS, node, newNode); } -function reduceNumerator(node: any); -function reduceNumerator(node) { +function reduceNumerator(node: mathjs.MathNode) { let newNode = clone(node); - if (newNode.args[0].value === '0') { + if (newNode.args[0].value === "0") { newNode = mathNode.Creator.constant(0); return mathNode.Status.nodeChanged( ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); @@ -125,14 +121,13 @@ function reduceNumerator(node) { // fractions with denominators that evaluate to the same common denominator // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) // Returns the new node. -function makeCommonDenominator(node: any); -function makeCommonDenominator(node) { +function makeCommonDenominator(node: mathjs.MathNode) { const newNode = clone(node); const denominators = newNode.args.map(fraction => { return parseFloat(fraction.args[1].value); }); - const commonDenominator = math.lcm(...denominators); + const commonDenominator = math.lcm(.denominators); newNode.args.forEach((child, i) => { // missingFactor is what we need to multiply the top and bottom by @@ -141,10 +136,10 @@ function makeCommonDenominator(node) { if (missingFactor !== 1) { const missingFactorNode = mathNode.Creator.constant(missingFactor); const newNumerator = mathNode.Creator.parenthesis( - mathNode.Creator.operator('*', [child.args[0], missingFactorNode])); + mathNode.Creator.operator("*", [child.args[0], missingFactorNode])); const newDeominator = mathNode.Creator.parenthesis( - mathNode.Creator.operator('*', [child.args[1], missingFactorNode])); - newNode.args[i] = mathNode.Creator.operator('/', [newNumerator, newDeominator]); + mathNode.Creator.operator("*", [child.args[1], missingFactorNode])); + newNode.args[i] = mathNode.Creator.operator("/", [newNumerator, newDeominator]); } }); @@ -152,8 +147,7 @@ function makeCommonDenominator(node) { ChangeTypes.COMMON_DENOMINATOR, node, newNode); } -function evaluateDenominators(node: any); -function evaluateDenominators(node) { +function evaluateDenominators(node: mathjs.MathNode) { const newNode = clone(node); newNode.args.map(fraction => { @@ -164,8 +158,7 @@ function evaluateDenominators(node) { ChangeTypes.MULTIPLY_DENOMINATORS, node, newNode); } -function evaluateNumerators(node: any); -function evaluateNumerators(node) { +function evaluateNumerators(node: mathjs.MathNode) { const newNode = clone(node); newNode.args.map(fraction => { diff --git a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts index 946c6211..985ae224 100644 --- a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts +++ b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts @@ -1,8 +1,8 @@ -import clone = require('../../util/clone'); -import print = require('../../util/print'); -import ChangeTypes = require('../../ChangeTypes'); -import Negative = require('../../Negative'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import print = require("../../util/print"); +import ChangeTypes = require("../../ChangeTypes"); +import Negative = require("../../Negative"); +import mathNode = require("../../mathnode"); // Used for cancelTerms to return a (possibly updated) numerator and denominator class CancelOutStatus { @@ -20,8 +20,8 @@ class CancelOutStatus { // Cancels like terms in a fraction node // e.g. (2x^2 * 5) / 2x^2 => 5 / 1 // Returns a mathNode.Status object -function cancelLikeTerms(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '/') { +function cancelLikeTerms(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "/") { return mathNode.Status.noChange(node); } let newNode = clone(node); @@ -243,8 +243,8 @@ function cancelTerms(numerator, denominator) { // case 2: they're both exponent nodes with the same base // e.g. (2x+5)^8 and (2x+5)^2 - if (mathNode.Type.isOperator(numerator, '^') && - mathNode.Type.isOperator(denominator, '^') && + if (mathNode.Type.isOperator(numerator, "^") && + mathNode.Type.isOperator(denominator, "^") && print(numerator.args[0]) === print(denominator.args[0])) { const numeratorExponent = numerator.args[1]; let denominatorExponent = denominator.args[1]; @@ -253,7 +253,7 @@ function cancelTerms(numerator, denominator) { // removeUnnecessaryParens at the end of this step. denominatorExponent = mathNode.Creator.parenthesis(denominatorExponent); const newExponent = mathNode.Creator.parenthesis( - mathNode.Creator.operator('-', [numeratorExponent, denominatorExponent])); + mathNode.Creator.operator("-", [numeratorExponent, denominatorExponent])); numerator.args[1] = newExponent; return new CancelOutStatus(numerator, null, true); } @@ -280,7 +280,7 @@ function cancelTerms(numerator, denominator) { // removeUnnecessaryParens at the end of this step. denominatorExponent = mathNode.Creator.parenthesis(denominatorExponent); const newExponent = mathNode.Creator.parenthesis( - mathNode.Creator.operator('-', [numeratorExponent, denominatorExponent])); + mathNode.Creator.operator("-", [numeratorExponent, denominatorExponent])); numerator = mathNode.Creator.polynomialTerm( numeratorTerm.getSymbolNode(), newExponent, @@ -298,12 +298,11 @@ function cancelTerms(numerator, denominator) { // e.g. 2 + 6 => false // e.g. (2 * 6^y) => true // e.g. 2x^2 => false (polynomial terms are considered as one single term) -function isMultiplicationOfTerms(node: any); -function isMultiplicationOfTerms(node) { +function isMultiplicationOfTerms(node: mathjs.MathNode) { if (mathNode.Type.isParenthesis(node)) { - return isMultiplicationOfTerms(node.content); + return isMultiplicationOfTerms(node); } - return (mathNode.Type.isOperator(node, '*') && + return (mathNode.Type.isOperator(node, "*") && !mathNode.PolynomialTerm.isPolynomialTerm(node)); } diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.js b/lib/simplifyExpression/fractionsSearch/divideByGCD.js new file mode 100644 index 00000000..7d92f70a --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/divideByGCD.js @@ -0,0 +1,50 @@ +"use strict"; +var math = require("mathjs"); +var ChangeTypes = require("../../ChangeTypes"); +var evaluate = require("../../util/evaluate"); +var mathNode = require("../../mathnode"); +// Simplifies a fraction (with constant numerator and denominator) by dividing +// the top and bottom by the GCD, if possible. +// e.g. 2/4 --> 1/2 10/5 --> 2x +// Also simplified negative signs +// e.g. -1/-3 --> 1/3 4/-5 --> -4/5 +// Note that -4/5 doesn't need to be simplified. +// Note that our goal is for the denominator to always be positive. If it +// isn't, we can simplify signs. +// Returns a mathNode.Status object +function divideByGcd(fraction) { + if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { + return mathNode.Status.noChange(fraction); + } + // If it's not an integer fraction, all we can do is simplify signs + if (!mathNode.Type.isIntegerFraction(fraction, true)) { + return mathNode.Status.noChange(fraction); + } + var numeratorValue = parseInt(evaluate(fraction.args[0])); + var denominatorValue = parseInt(evaluate(fraction.args[1])); + // The gcd is what we're dividing the numerator and denominator by. + var gcd = math.gcd(numeratorValue, denominatorValue); + // A greatest common denominator is technically defined as always positive, + // but since our goal is to reduce negative signs or move them to the + // numerator, a negative denominator always means we want to flip signs + // of both numerator and denominator. + // e.g. -1/-3 --> 1/3 4/-5 --> -4/5 + if (denominatorValue < 0) { + gcd *= -1; + } + if (gcd === 1) { + return mathNode.Status.noChange(fraction); + } + var newNumeratorNode = mathNode.Creator.constant(numeratorValue / gcd); + var newDenominatorNode = mathNode.Creator.constant(denominatorValue / gcd); + var newFraction; + if (parseFloat(newDenominatorNode.value) === 1) { + newFraction = newNumeratorNode; + } + else { + newFraction = mathNode.Creator.operator("/", [newNumeratorNode, newDenominatorNode]); + } + return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_FRACTION, fraction, newFraction); +} +module.exports = divideByGcd; +//# sourceMappingURL=divideByGCD.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.js.map b/lib/simplifyExpression/fractionsSearch/divideByGCD.js.map new file mode 100644 index 00000000..92d36304 --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/divideByGCD.js.map @@ -0,0 +1 @@ +{"version":3,"file":"divideByGCD.js","sourceRoot":"","sources":["divideByGCD.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,+CAAkD;AAClD,8CAAiD;AACjD,yCAA4C;AAE5C,8EAA8E;AAC9E,8CAA8C;AAC9C,kCAAkC;AAClC,iCAAiC;AACjC,qCAAqC;AACrC,gDAAgD;AAChD,yEAAyE;AACzE,gCAAgC;AAChC,mCAAmC;AACnC,qBAAqB,QAAQ;IAC3B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IACD,mEAAmE;IACnE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,IAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9D,mEAAmE;IACnE,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IACrD,2EAA2E;IAC3E,qEAAqE;IACrE,uEAAuE;IACvE,qCAAqC;IACrC,qCAAqC;IACrC,EAAE,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,GAAG,IAAI,CAAC,CAAC,CAAC;IACZ,CAAC;IAED,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,IAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,GAAC,GAAG,CAAC,CAAC;IACvE,IAAM,kBAAkB,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,GAAC,GAAG,CAAC,CAAC;IAC3E,IAAI,WAAW,CAAC;IAChB,EAAE,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/C,WAAW,GAAG,gBAAgB,CAAC;IACjC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CACrC,GAAG,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,iBAAiB,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AAC1D,CAAC;AAED,iBAAS,WAAW,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.ts b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts index 32dce915..8f0e5f46 100644 --- a/lib/simplifyExpression/fractionsSearch/divideByGCD.ts +++ b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts @@ -1,7 +1,7 @@ -import math = require('mathjs'); -import ChangeTypes = require('../../ChangeTypes'); -import evaluate = require('../../util/evaluate'); -import mathNode = require('../../mathnode'); +import math = require("mathjs"); +import ChangeTypes = require("../../ChangeTypes"); +import evaluate = require("../../util/evaluate"); +import mathNode = require("../../mathnode"); // Simplifies a fraction (with constant numerator and denominator) by dividing // the top and bottom by the GCD, if possible. @@ -12,9 +12,8 @@ import mathNode = require('../../mathnode'); // Note that our goal is for the denominator to always be positive. If it // isn't, we can simplify signs. // Returns a mathNode.Status object -function divideByGCD(fraction: any); -function divideByGCD(fraction) { - if (!mathNode.Type.isOperator(fraction) || fraction.op !== '/') { +function divideByGcd(fraction) { + if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { return mathNode.Status.noChange(fraction); } // If it's not an integer fraction, all we can do is simplify signs @@ -48,11 +47,11 @@ function divideByGCD(fraction) { } else { newFraction = mathNode.Creator.operator( - '/', [newNumeratorNode, newDenominatorNode]); + "/", [newNumeratorNode, newDenominatorNode]); } return mathNode.Status.nodeChanged( ChangeTypes.SIMPLIFY_FRACTION, fraction, newFraction); } -export = divideByGCD; +export = divideByGcd; diff --git a/lib/simplifyExpression/fractionsSearch/index.js b/lib/simplifyExpression/fractionsSearch/index.js index 5565b7c4..88e9b28e 100644 --- a/lib/simplifyExpression/fractionsSearch/index.js +++ b/lib/simplifyExpression/fractionsSearch/index.js @@ -17,7 +17,7 @@ var simplifyFractionSigns = require("./simplifyFractionSigns"); var simplifyPolynomialFraction = require("./simplifyPolynomialFraction"); var mathNode = require("../../mathnode"); var TreeSearch = require("../../TreeSearch"); -var SIMPLIFICATION_FUNCTIONS = [ +var simplificationFunctions = [ // e.g. 2/3 + 5/6 addConstantFractions, // e.g. 4 + 5/6 or 4.5 + 6/8 @@ -33,8 +33,8 @@ var SIMPLIFICATION_FUNCTIONS = [ ]; var search = TreeSearch.preOrder(simplifyFractions); function simplifyFractions(node) { - for (var i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) { - var nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node); + for (var i = 0; i < simplificationFunctions.length; i++) { + var nodeStatus = simplificationFunctions[i](node); if (nodeStatus.hasChanged()) { return nodeStatus; } diff --git a/lib/simplifyExpression/fractionsSearch/index.js.map b/lib/simplifyExpression/fractionsSearch/index.js.map index e327b9b1..4e2ce522 100644 --- a/lib/simplifyExpression/fractionsSearch/index.js.map +++ b/lib/simplifyExpression/fractionsSearch/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;AAEH,iEAAoE;AACpE,6DAAgE;AAChE,mDAAsD;AACtD,2CAA8C;AAC9C,+DAAkE;AAClE,yEAA4E;AAC5E,yCAA4C;AAC5C,6CAAgD;AAChD,IAAM,wBAAwB,GAAG;IAC/B,iBAAiB;IACjB,oBAAoB;IACpB,4BAA4B;IAC5B,sBAAsB;IACtB,+CAA+C;IAC/C,qBAAqB;IACrB,uCAAuC;IACvC,WAAW;IACX,0EAA0E;IAC1E,0BAA0B;IAC1B,4BAA4B;IAC5B,eAAe;CAChB,CAAC;AAEF,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAItD,2BAA2B,IAAI;IAC7B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,wBAAwB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzD,IAAM,UAAU,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;AAEH,iEAAoE;AACpE,6DAAgE;AAChE,mDAAsD;AACtD,2CAA8C;AAC9C,+DAAkE;AAClE,yEAA4E;AAC5E,yCAA4C;AAC5C,6CAAgD;AAChD,IAAM,uBAAuB,GAAe;IAC1C,iBAAiB;IACjB,oBAAoB;IACpB,4BAA4B;IAC5B,sBAAsB;IACtB,+CAA+C;IAC/C,qBAAqB;IACrB,uCAAuC;IACvC,WAAW;IACX,0EAA0E;IAC1E,0BAA0B;IAC1B,4BAA4B;IAC5B,eAAe;CAChB,CAAC;AAEF,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAItD,2BAA2B,IAAI;IAC7B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,IAAM,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/index.ts b/lib/simplifyExpression/fractionsSearch/index.ts index c2ac4074..e960db7f 100644 --- a/lib/simplifyExpression/fractionsSearch/index.ts +++ b/lib/simplifyExpression/fractionsSearch/index.ts @@ -9,15 +9,15 @@ */ -import addConstantAndFraction = require('./addConstantAndFraction'); -import addConstantFractions = require('./addConstantFractions'); -import cancelLikeTerms = require('./cancelLikeTerms'); -import divideByGCD = require('./divideByGCD'); -import simplifyFractionSigns = require('./simplifyFractionSigns'); -import simplifyPolynomialFraction = require('./simplifyPolynomialFraction'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); -const SIMPLIFICATION_FUNCTIONS = [ +import addConstantAndFraction = require("./addConstantAndFraction"); +import addConstantFractions = require("./addConstantFractions"); +import cancelLikeTerms = require("./cancelLikeTerms"); +import divideByGCD = require("./divideByGCD"); +import simplifyFractionSigns = require("./simplifyFractionSigns"); +import simplifyPolynomialFraction = require("./simplifyPolynomialFraction"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); +const simplificationFunctions: Array = [ // e.g. 2/3 + 5/6 addConstantFractions, // e.g. 4 + 5/6 or 4.5 + 6/8 @@ -37,8 +37,8 @@ const search = TreeSearch.preOrder(simplifyFractions); // Look for step(s) to perform on a node. Returns a mathNode.Status object. function simplifyFractions(node: any); function simplifyFractions(node) { - for (let i = 0; i < SIMPLIFICATION_FUNCTIONS.length; i++) { - const nodeStatus = SIMPLIFICATION_FUNCTIONS[i](node); + for (let i = 0; i < simplificationFunctions.length; i++) { + const nodeStatus = simplificationFunctions[i](node); if (nodeStatus.hasChanged()) { return nodeStatus; } diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js new file mode 100644 index 00000000..184aa5af --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js @@ -0,0 +1,34 @@ +"use strict"; +var clone = require("../../util/clone"); +var ChangeTypes = require("../../ChangeTypes"); +var Negative = require("../../Negative"); +var mathNode = require("../../mathnode"); +// Simplifies negative signs if possible +// e.g. -1/-3 --> 1/3 4/-5 --> -4/5 +// Note that -4/5 doesn't need to be simplified. +// Note that our goal is for the denominator to always be positive. If it +// isn't, we can simplify signs. +// Returns a mathNode.Status object +function simplifySigns(fraction) { + if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { + return mathNode.Status.noChange(fraction); + } + var oldFraction = clone(fraction); + var numerator = fraction.args[0]; + var denominator = fraction.args[1]; + // The denominator should never be negative. + if (Negative.isNegative(denominator)) { + denominator = Negative.negate(denominator); + var changeType = Negative.isNegative(numerator) ? + ChangeTypes.CANCEL_MINUSES : + ChangeTypes.SIMPLIFY_SIGNS; + numerator = Negative.negate(numerator); + var newFraction = mathNode.Creator.operator("/", [numerator, denominator]); + return mathNode.Status.nodeChanged(changeType, oldFraction, newFraction); + } + else { + return mathNode.Status.noChange(fraction); + } +} +module.exports = simplifySigns; +//# sourceMappingURL=simplifyFractionSigns.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map new file mode 100644 index 00000000..8ae3a150 --- /dev/null +++ b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map @@ -0,0 +1 @@ +{"version":3,"file":"simplifyFractionSigns.js","sourceRoot":"","sources":["simplifyFractionSigns.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAC5C,yCAA4C;AAE5C,wCAAwC;AACxC,qCAAqC;AACrC,gDAAgD;AAChD,yEAAyE;AACzE,gCAAgC;AAChC,mCAAmC;AAEnC,uBAAuB,QAAQ;IAC7B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IACD,IAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,4CAA4C;IAC5C,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACrC,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;YAC/C,WAAW,CAAC,cAAc;YAC1B,WAAW,CAAC,cAAc,CAAC;QAC7B,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvC,IAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,iBAAS,aAAa,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts index 75414c05..ab3c8b0f 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts +++ b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts @@ -1,7 +1,7 @@ -import clone = require('../../util/clone'); -import ChangeTypes = require('../../ChangeTypes'); -import Negative = require('../../Negative'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import ChangeTypes = require("../../ChangeTypes"); +import Negative = require("../../Negative"); +import mathNode = require("../../mathnode"); // Simplifies negative signs if possible // e.g. -1/-3 --> 1/3 4/-5 --> -4/5 @@ -9,9 +9,9 @@ import mathNode = require('../../mathnode'); // Note that our goal is for the denominator to always be positive. If it // isn't, we can simplify signs. // Returns a mathNode.Status object -function simplifySigns(fraction: any); + function simplifySigns(fraction) { - if (!mathNode.Type.isOperator(fraction) || fraction.op !== '/') { + if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { return mathNode.Status.noChange(fraction); } const oldFraction = clone(fraction); @@ -24,7 +24,7 @@ function simplifySigns(fraction) { ChangeTypes.CANCEL_MINUSES : ChangeTypes.SIMPLIFY_SIGNS; numerator = Negative.negate(numerator); - const newFraction = mathNode.Creator.operator('/', [numerator, denominator]); + const newFraction = mathNode.Creator.operator("/", [numerator, denominator]); return mathNode.Status.nodeChanged(changeType, oldFraction, newFraction); } else { diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js index 0774240d..00c0c88a 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js @@ -3,6 +3,11 @@ var arithmeticSearch = require("../arithmeticSearch"); var clone = require("../../util/clone"); var divideByGCD = require("./divideByGCD"); var mathNode = require("../../mathnode"); +// Simplifies a polynomial term with a fraction as its coefficients. +// e.g. 2x/4 --> x/2 10x/5 --> 2x +// Also simplified negative signs +// e.g. -y/-3 --> y/3 4x/-5 --> -4x/5 +// returns the new simplified node in a mathNode.Status object function simplifyPolynomialFraction(node) { if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { return mathNode.Status.noChange(node); @@ -20,7 +25,7 @@ function simplifyPolynomialFraction(node) { var newCoeffStatus = coefficientSimplifications[i](coefficientFraction); if (newCoeffStatus.hasChanged()) { var newCoeff = newCoeffStatus.newNode; - if (newCoeff.value === '1') { + if (newCoeff.value === "1") { newCoeff = null; } var exponentNode = polyNode.getExponentNode(); diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map index 4a7577b5..3ec6f21b 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map @@ -1 +1 @@ -{"version":3,"file":"simplifyPolynomialFraction.js","sourceRoot":"","sources":["simplifyPolynomialFraction.ts"],"names":[],"mappings":";AAAA,sDAAyD;AACzD,wCAA2C;AAC3C,2CAA8C;AAC9C,yCAA4C;AAQ5C,oCAAoC,IAAI;IACtC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,0BAA0B,GAAG;QACjC,WAAW;QACX,gBAAgB;KACjB,CAAC;IAEF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,0BAA0B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,IAAM,mBAAmB,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,kBAAkB;QACvE,IAAM,cAAc,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC1E,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;YACtC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;gBAC3B,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;YACD,IAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC;YAChD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CAC3C,QAAQ,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;YACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file +{"version":3,"file":"simplifyPolynomialFraction.js","sourceRoot":"","sources":["simplifyPolynomialFraction.ts"],"names":[],"mappings":";AAAA,sDAAyD;AACzD,wCAA2C;AAC3C,2CAA8C;AAC9C,yCAA4C;AAE5C,oEAAoE;AACpE,oCAAoC;AACpC,iCAAiC;AACjC,uCAAuC;AACvC,8DAA8D;AAC9D,oCAAoC,IAAqB;IACvD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,0BAA0B,GAAG;QACjC,WAAW;QACX,gBAAgB;KACjB,CAAC;IAEF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,0BAA0B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,IAAM,mBAAmB,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,kBAAkB;QACvE,IAAM,cAAc,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC1E,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;YACtC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;gBAC3B,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;YACD,IAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC;YAChD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CAC3C,QAAQ,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;YACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts index a64a3f7f..48e7d5ad 100644 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts +++ b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts @@ -1,15 +1,14 @@ -import arithmeticSearch = require('../arithmeticSearch'); -import clone = require('../../util/clone'); -import divideByGCD = require('./divideByGCD'); -import mathNode = require('../../mathnode'); +import arithmeticSearch = require("../arithmeticSearch"); +import clone = require("../../util/clone"); +import divideByGCD = require("./divideByGCD"); +import mathNode = require("../../mathnode"); // Simplifies a polynomial term with a fraction as its coefficients. // e.g. 2x/4 --> x/2 10x/5 --> 2x // Also simplified negative signs // e.g. -y/-3 --> y/3 4x/-5 --> -4x/5 // returns the new simplified node in a mathNode.Status object -function simplifyPolynomialFraction(node: any); -function simplifyPolynomialFraction(node) { +function simplifyPolynomialFraction(node: mathjs.MathNode) { if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { return mathNode.Status.noChange(node); } @@ -29,7 +28,7 @@ function simplifyPolynomialFraction(node) { const newCoeffStatus = coefficientSimplifications[i](coefficientFraction); if (newCoeffStatus.hasChanged()) { let newCoeff = newCoeffStatus.newNode; - if (newCoeff.value === '1') { + if (newCoeff.value === "1") { newCoeff = null; } const exponentNode = polyNode.getExponentNode(); diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.js b/lib/simplifyExpression/functionsSearch/absoluteValue.js new file mode 100644 index 00000000..8249c390 --- /dev/null +++ b/lib/simplifyExpression/functionsSearch/absoluteValue.js @@ -0,0 +1,33 @@ +"use strict"; +var clone = require("../../util/clone"); +var math = require("mathjs"); +var ChangeTypes = require("../../ChangeTypes"); +var evaluate = require("../../util/evaluate"); +var mathNode = require("../../mathnode"); +// Evaluates abs() function if it's on a single constant value. +// Returns a mathNode.Status object. +function absoluteValue(node) { + if (!mathNode.Type.isFunction(node, "abs")) { + return mathNode.Status.noChange(node); + } + if (node.args.length > 1) { + return mathNode.Status.noChange(node); + } + var newNode = clone(node); + var argument = newNode.args[0]; + if (mathNode.Type.isConstant(argument, true)) { + newNode = mathNode.Creator.constant(math.abs(evaluate(argument))); + return mathNode.Status.nodeChanged(ChangeTypes.ABSOLUTE_VALUE, node, newNode); + } + else if (mathNode.Type.isConstantFraction(argument, true)) { + var newNumerator = mathNode.Creator.constant(math.abs(evaluate(argument.args[0]))); + var newDenominator = mathNode.Creator.constant(math.abs(evaluate(argument.args[1]))); + newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); + return mathNode.Status.nodeChanged(ChangeTypes.ABSOLUTE_VALUE, node, newNode); + } + else { + return mathNode.Status.noChange(node); + } +} +module.exports = absoluteValue; +//# sourceMappingURL=absoluteValue.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.js.map b/lib/simplifyExpression/functionsSearch/absoluteValue.js.map new file mode 100644 index 00000000..d795a3b8 --- /dev/null +++ b/lib/simplifyExpression/functionsSearch/absoluteValue.js.map @@ -0,0 +1 @@ +{"version":3,"file":"absoluteValue.js","sourceRoot":"","sources":["absoluteValue.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,6BAAgC;AAChC,+CAAkD;AAClD,8CAAiD;AACjD,yCAA6C;AAE7C,+DAA+D;AAC/D,oCAAoC;AACpC,uBAAuB,IAAqB;IAC1C,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAC5C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,IAAM,cAAc,GAAI,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAC/C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;QACzE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,aAAa,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.ts b/lib/simplifyExpression/functionsSearch/absoluteValue.ts index dbe2558f..1864394e 100644 --- a/lib/simplifyExpression/functionsSearch/absoluteValue.ts +++ b/lib/simplifyExpression/functionsSearch/absoluteValue.ts @@ -1,14 +1,13 @@ -import clone = require('../../util/clone'); -import math = require('mathjs'); -import ChangeTypes = require('../../ChangeTypes'); -import evaluate = require('../../util/evaluate'); -const mathNode = require('../../node'); +import clone = require("../../util/clone"); +import math = require("mathjs"); +import ChangeTypes = require("../../ChangeTypes"); +import evaluate = require("../../util/evaluate"); +import mathNode = require("../../mathnode"); // Evaluates abs() function if it's on a single constant value. // Returns a mathNode.Status object. -function absoluteValue(node: any); -function absoluteValue(node) { - if (!mathNode.Type.isFunction(node, 'abs')) { +function absoluteValue(node: mathjs.MathNode) { + if (!mathNode.Type.isFunction(node, "abs")) { return mathNode.Status.noChange(node); } if (node.args.length > 1) { @@ -26,7 +25,7 @@ function absoluteValue(node) { math.abs(evaluate(argument.args[0]))); const newDenominator = mathNode.Creator.constant( math.abs(evaluate(argument.args[1]))); - newNode = mathNode.Creator.operator('/', [newNumerator, newDenominator]); + newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); return mathNode.Status.nodeChanged( ChangeTypes.ABSOLUTE_VALUE, node, newNode); } diff --git a/lib/simplifyExpression/functionsSearch/index.js b/lib/simplifyExpression/functionsSearch/index.js new file mode 100644 index 00000000..562743d5 --- /dev/null +++ b/lib/simplifyExpression/functionsSearch/index.js @@ -0,0 +1,28 @@ +"use strict"; +var absoluteValue = require("./absoluteValue"); +var nthRoot = require("./nthRoot"); +var mathNode = require("../../mathnode"); +var TreeSearch = require("../../TreeSearch"); +var FUNCTIONS = [ + nthRoot, + absoluteValue +]; +// Searches through the tree, prioritizing deeper nodes, and evaluates +// functions (e.g. abs(-4)) if possible. +// Returns a mathNode.Status object. +var search = TreeSearch.postOrder(functions); +// Evaluates a function call if possible. Returns a mathNode.Status object. +function functions(node) { + if (!mathNode.Type.isFunction(node)) { + return mathNode.Status.noChange(node); + } + for (var i = 0; i < FUNCTIONS.length; i++) { + var nodeStatus = FUNCTIONS[i](node); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + } + return mathNode.Status.noChange(node); +} +module.exports = search; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/index.js.map b/lib/simplifyExpression/functionsSearch/index.js.map new file mode 100644 index 00000000..b3c405bd --- /dev/null +++ b/lib/simplifyExpression/functionsSearch/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,mCAAsC;AACtC,yCAA4C;AAC5C,6CAAgD;AAChD,IAAM,SAAS,GAAG;IAChB,OAAO;IACP,aAAa;CACd,CAAC;AAEF,sEAAsE;AACtE,wCAAwC;AACxC,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAE/C,2EAA2E;AAC3E,mBAAmB,IAAqB;IACtC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,IAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/index.ts b/lib/simplifyExpression/functionsSearch/index.ts index 2bf3d183..a412a5be 100644 --- a/lib/simplifyExpression/functionsSearch/index.ts +++ b/lib/simplifyExpression/functionsSearch/index.ts @@ -1,7 +1,7 @@ -import absoluteValue = require('./absoluteValue'); -import nthRoot = require('./nthRoot'); -const mathNode = require('../../node'); -import TreeSearch = require('../../TreeSearch'); +import absoluteValue = require("./absoluteValue"); +import nthRoot = require("./nthRoot"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); const FUNCTIONS = [ nthRoot, absoluteValue @@ -13,8 +13,7 @@ const FUNCTIONS = [ const search = TreeSearch.postOrder(functions); // Evaluates a function call if possible. Returns a mathNode.Status object. -function functions(node: any); -function functions(node) { +function functions(node: mathjs.MathNode) { if (!mathNode.Type.isFunction(node)) { return mathNode.Status.noChange(node); } diff --git a/lib/simplifyExpression/functionsSearch/nthRoot.ts b/lib/simplifyExpression/functionsSearch/nthRoot.ts index 637c07bd..19102b37 100644 --- a/lib/simplifyExpression/functionsSearch/nthRoot.ts +++ b/lib/simplifyExpression/functionsSearch/nthRoot.ts @@ -1,24 +1,23 @@ -import clone = require('../../util/clone'); -import math = require('mathjs'); -import ChangeTypes = require('../../ChangeTypes'); -import ConstantFactors = require('../../factor/ConstantFactors'); -import Negative = require('../../Negative'); -import mathNode = require('../../mathnode'); +import clone = require("../../util/clone"); +import math = require("mathjs"); +import ChangeTypes = require("../../ChangeTypes"); +import ConstantFactors = require("../../factor/ConstantFactors"); +import Negative = require("../../Negative"); +import mathNode = require("../../mathnode"); // Evaluate nthRoot() function. // Returns a mathNode.Status object. -function nthRoot(node: any); -function nthRoot(node) { - if (!mathNode.Type.isFunction(node, 'nthRoot')) { +function nthRoot(node: mathjs.MathNode) { + if (!mathNode.Type.isFunction(node, "nthRoot")) { return mathNode.Status.noChange(node); } const radicandNode = getRadicandNode(node); if (mathNode.Type.isOperator(radicandNode)) { - if (radicandNode.op === '^') { + if (radicandNode.op === "^") { return nthRootExponent(node); } - else if (radicandNode.op === '*') { + else if (radicandNode.op === "*") { return nthRootMultiplication(node); } } @@ -34,8 +33,8 @@ function nthRoot(node) { // equal: nthRoot(2^x, x) = 2 // root > exponent: nthRoot(x^2, 4) = nthRoot(x, 2) // exponent > root: nthRoot(x^4, 2) = x^2 -function nthRootExponent(node: any); -function nthRootExponent(node) { +function nthRootExponent(node: mathjs.MathNode) { + // is this used anywhere? let newNode = clone(node); const radicandNode = getRadicandNode(node); @@ -63,7 +62,7 @@ function nthRootExponent(node) { const newExponentValue = exponentValue/rootValue; const newExponentNode = mathNode.Creator.constant(newExponentValue); - newNode = mathNode.Creator.operator('^', [baseNode, newExponentNode]); + newNode = mathNode.Creator.operator("^", [baseNode, newExponentNode]); return mathNode.Status.nodeChanged( ChangeTypes.CANCEL_ROOT, node, newNode); } @@ -82,8 +81,7 @@ function nthRootExponent(node) { // 2A: Distributes the nthRoot into the children nodes, // 2B: evaluates those nthRoots // 2C: combines them -function nthRootMultiplication(node: any); -function nthRootMultiplication(node) { +function nthRootMultiplication(node: mathjs.MathNode) { let newNode = clone(node); const rootNode = getRootNode(node); @@ -109,7 +107,7 @@ function nthRootMultiplication(node) { if (status.hasChanged()) { substeps.push(status); newNode = mathNode.Status.resetChangeGroups(status.newNode); - if (newNode.args[0].op === '^') { + if (newNode.args[0].op === "^") { status = nthRootExponent(newNode); substeps.push(status); return mathNode.Status.nodeChanged( @@ -146,8 +144,7 @@ function nthRootMultiplication(node) { // Given an nthRoot node with a constant positive root, will do the step of // factoring all the multiplicands under the radicand // e.g. nthRoot(2 * 9 * 5 * 12) = nthRoot(2 * 3 * 3 * 5 * 2 * 2 * 3) -function factorMultiplicands(node: any); -function factorMultiplicands(node) { +function factorMultiplicands(node: mathjs.MathNode) { const newNode = clone(node); const radicandNode = getRadicandNode(node); @@ -178,7 +175,7 @@ function factorMultiplicands(node) { }); if (factored) { - newNode.args[0] = mathNode.Creator.operator('*', children); + newNode.args[0] = mathNode.Creator.operator("*", children); return mathNode.Status.nodeChanged( ChangeTypes.FACTOR_INTO_PRIMES, node, newNode); } @@ -186,8 +183,7 @@ function factorMultiplicands(node) { return mathNode.Status.noChange(node); } -function getFactorNodes(node: any); -function getFactorNodes(node) { +function getFactorNodes(node: mathjs.MathNode): any { if (mathNode.Type.isConstant(node) && !Negative.isNegative(node)) { const value = parseFloat(node.value); const factors = ConstantFactors.getPrimeFactors(value); @@ -200,8 +196,7 @@ function getFactorNodes(node) { // Given an nthRoot node with a constant positive root, will group the arguments // into groups of the root as a step // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2, 2) -function groupTermsByRoot(node: any); -function groupTermsByRoot(node) { +function groupTermsByRoot(node: mathjs.MathNode) { const newNode = clone(node); const radicandNode = getRadicandNode(node); const rootNode = getRootNode(node); @@ -225,7 +220,7 @@ function groupTermsByRoot(node) { if (j - i === rootValue) { hasGroups = true; const groupedNode = mathNode.Creator.parenthesis( - mathNode.Creator.operator('*', radicandNode.args.slice(i, j))); + mathNode.Creator.operator("*", radicandNode.args.slice(i, j))); children.push(groupedNode); } else { @@ -236,7 +231,7 @@ function groupTermsByRoot(node) { if (hasGroups) { newNode.args[0] = children.length === 1 ? - children[0] : mathNode.Creator.operator('*', children); + children[0] : mathNode.Creator.operator("*", children); return mathNode.Status.nodeChanged( ChangeTypes.GROUP_TERMS_BY_ROOT, node, newNode); } @@ -247,8 +242,7 @@ function groupTermsByRoot(node) { // Given an nthRoot node with a constant positive root, // will convert any grouped factors into exponent nodes as a step // e.g. nthRoot((2 * 2) * 2, 2) -> nthRoot(2^2 * 2, 2) -function convertMultiplicationToExponent(node: any); -function convertMultiplicationToExponent(node) { +function convertMultiplicationToExponent(node: mathjs.MathNode) { const newNode = clone(node); const radicandNode = getRadicandNode(node); @@ -258,12 +252,12 @@ function convertMultiplicationToExponent(node) { if (isMultiplicationOfEqualNodes(child)) { const baseNode = child.args[0]; const exponentNode = mathNode.Creator.constant(child.args.length); - newNode.args[0] = mathNode.Creator.operator('^', [baseNode, exponentNode]); + newNode.args[0] = mathNode.Creator.operator("^", [baseNode, exponentNode]); return mathNode.Status.nodeChanged( ChangeTypes.CONVERT_MULTIPLICATION_TO_EXPONENT, node, newNode); } } - else if (mathNode.Type.isOperator(radicandNode, '*')) { + else if (mathNode.Type.isOperator(radicandNode, "*")) { const children = []; radicandNode.args.forEach(child => { if (mathNode.Type.isParenthesis(child)) { @@ -271,14 +265,14 @@ function convertMultiplicationToExponent(node) { if (isMultiplicationOfEqualNodes(grandChild)) { const baseNode = grandChild.args[0]; const exponentNode = mathNode.Creator.constant(grandChild.args.length); - children.push(mathNode.Creator.operator('^', [baseNode, exponentNode])); + children.push(mathNode.Creator.operator("^", [baseNode, exponentNode])); return; } } children.push(child); }); - newNode.args[0] = mathNode.Creator.operator('*', children); + newNode.args[0] = mathNode.Creator.operator("*", children); return mathNode.Status.nodeChanged( ChangeTypes.CONVERT_MULTIPLICATION_TO_EXPONENT, node, newNode); } @@ -289,8 +283,8 @@ function convertMultiplicationToExponent(node) { // Given an nthRoot node with a multiplication under the radicand, will // distribute the nthRoot to all the arguments under the radicand as a step // e.g. nthRoot(2 * x^2, 2) -> nthRoot(2) * nthRoot(x^2) -function distributeNthRoot(node: any); -function distributeNthRoot(node) { +function distributeNthRoot(node: mathjs.MathNode) { + //is this used anywhere? let newNode = clone(node); const radicandNode = getRadicandNode(node); const rootNode = getRootNode(node); @@ -301,7 +295,7 @@ function distributeNthRoot(node) { children.push(mathNode.Creator.nthRoot(child, rootNode)); } - newNode = mathNode.Creator.operator('*', children); + newNode = mathNode.Creator.operator("*", children); return mathNode.Status.nodeChanged( ChangeTypes.DISTRIBUTE_NTH_ROOT, node, newNode); } @@ -309,8 +303,7 @@ function distributeNthRoot(node) { // Given a multiplication node of nthRoots (with the same root) // will evaluate the nthRoot of each child as a substep // e.g. nthRoot(2) * nthRoot(x^2) -> nthRoot(2) * x -function evaluateNthRootForChildren(node: any); -function evaluateNthRootForChildren(node) { +function evaluateNthRootForChildren(node: mathjs.MathNode) { const newNode = clone(node); const substeps = []; @@ -340,8 +333,7 @@ function evaluateNthRootForChildren(node) { // e.g. 2 * nthRoot(2) * nthRoot(x) -> 2 * nthRoot(2 * x) // Assumes that all the roots are the same (that this is occuring right // after distributeNthRoot and evaluateNthRootForChildren) -function combineRoots(node: any); -function combineRoots(node) { +function combineRoots(node: mathjs.MathNode) { let newNode = clone(node); let rootNode; @@ -349,7 +341,7 @@ function combineRoots(node) { const radicandArgs = []; for (let i = 0; i < newNode.args.length; i++) { const child = newNode.args[i]; - if (mathNode.Type.isFunction(child, 'nthRoot')) { + if (mathNode.Type.isFunction(child, "nthRoot")) { radicandArgs.push(child.args[0]); rootNode = getRootNode(child); } @@ -361,11 +353,11 @@ function combineRoots(node) { if (children.length > 0) { if (radicandArgs.length > 0) { const radicandNode = radicandArgs.length === 1 ? - radicandArgs[0] : mathNode.Creator.operator('*', radicandArgs); + radicandArgs[0] : mathNode.Creator.operator("*", radicandArgs); children.push(mathNode.Creator.nthRoot(radicandNode, rootNode)); } - newNode = mathNode.Creator.operator('*', children); + newNode = mathNode.Creator.operator("*", children); if (!newNode.equals(node)) { return mathNode.Status.nodeChanged( ChangeTypes.COMBINE_UNDER_ROOT, node, newNode); @@ -379,7 +371,7 @@ function combineRoots(node) { // Returns the nthRoot evaluated on a constant node // Potentially factors the constant node into primes, and calls // nthRootMultiplication on the new nthRoot -function nthRootConstant(node) { +function nthRootConstant(node: mathjs.MathNode) { let newNode = clone(node); const radicandNode = getRadicandNode(node); const rootNode = getRootNode(node); @@ -391,9 +383,9 @@ function nthRootConstant(node) { return mathNode.Status.noChange(node); } - const radicandValue = parseFloat(radicandNode.value); - const rootValue = parseFloat(rootNode.value); - const nthRootValue = math.nthRoot(radicandValue, rootValue); + const radicandValue: number = parseFloat(radicandNode.value); + const rootValue: number = parseFloat(rootNode.value); + const nthRootValue: any = math.nthRoot(radicandValue, rootValue); // Perfect root e.g. nthRoot(4, 2) = 2 if (nthRootValue % 1 === 0) { newNode = mathNode.Creator.constant(nthRootValue); @@ -409,7 +401,7 @@ function nthRootConstant(node) { let substeps = []; const factorNodes = factors.map(mathNode.Creator.constant); - newNode.args[0] = mathNode.Creator.operator('*', factorNodes); + newNode.args[0] = mathNode.Creator.operator("*", factorNodes); substeps.push(mathNode.Status.nodeChanged( ChangeTypes.FACTOR_INTO_PRIMES, node, newNode)); @@ -433,20 +425,18 @@ function nthRootConstant(node) { // Given an nthRoot node, will return the root node. // The root node is the second child of the nthRoot node, but if one doesn't // exist, we assume it's a square root and return 2. -function getRootNode(node: any); -function getRootNode(node) { - if (!mathNode.Type.isFunction(node, 'nthRoot')) { - throw Error('Expected nthRoot'); +function getRootNode(node: mathjs.MathNode) { + if (!mathNode.Type.isFunction(node, "nthRoot")) { + throw Error("Expected nthRoot"); } return node.args.length === 2 ? node.args[1] : mathNode.Creator.constant(2); } // Given an nthRoot node, will return the radicand node. -function getRadicandNode(node: any); -function getRadicandNode(node) { - if (!mathNode.Type.isFunction(node, 'nthRoot')) { - throw Error('Expected nthRoot'); +function getRadicandNode(node: mathjs.MathNode) { + if (!mathNode.Type.isFunction(node, "nthRoot")) { + throw Error("Expected nthRoot"); } return node.args[0]; @@ -454,8 +444,7 @@ function getRadicandNode(node) { // Sorts nodes, ordering constants nodes from smallest to largest and symbol // nodes after -function sortNodes(a: any, b: any); -function sortNodes(a, b) { +function sortNodes(a: mathjs.MathNode, b: mathjs.MathNode) { if (mathNode.Type.isConstant(a) && mathNode.Type.isConstant(b)) { return parseFloat(a.value) - parseFloat(b.value); } @@ -470,9 +459,8 @@ function sortNodes(a, b) { // Simple helper function which determines a node is a multiplication node // of all equal nodes -function isMultiplicationOfEqualNodes(node: any); function isMultiplicationOfEqualNodes(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '*') { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { return false; } diff --git a/lib/simplifyExpression/index.ts b/lib/simplifyExpression/index.ts index d9ca4744..d5b586a4 100644 --- a/lib/simplifyExpression/index.ts +++ b/lib/simplifyExpression/index.ts @@ -1,5 +1,5 @@ -import math = require('mathjs'); -import stepThrough = require('./stepThrough'); +import math = require("mathjs"); +import stepThrough = require("./stepThrough"); function simplifyExpressionString(expressionString, debug=false) { let exprNode; diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js b/lib/simplifyExpression/multiplyFractionsSearch/index.js index dc2dab1b..4924acca 100644 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.js +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.js @@ -12,11 +12,16 @@ var TreeSearch = require("../../TreeSearch"); // will be formatted badly, so it's a tree search of its own. // Returns a mathNode.Status object. var search = TreeSearch.postOrder(multiplyFractions); +// If `node` is a product of terms where some are fractions (but none are +// polynomial terms), multiplies them together. +// e.g. 2 * 5/x -> (2*5)/x +// e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) +// Returns a mathNode.Status object. function multiplyFractions(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '*') { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { return mathNode.Status.noChange(node); } - var atLeastOneFraction = node.args.some(function (arg) { return mathNode.Type.isOperator(arg, '/'); }); + var atLeastOneFraction = node.args.some(function (arg) { return mathNode.Type.isOperator(arg, "/"); }); var hasPolynomialTerms = node.args.some(function (arg) { return mathNode.PolynomialTerm.isPolynomialTerm(arg); }); if (!atLeastOneFraction || hasPolynomialTerms) { return mathNode.Status.noChange(node); @@ -24,7 +29,7 @@ function multiplyFractions(node) { var numeratorArgs = []; var denominatorArgs = []; node.args.forEach(function (operand) { - if (mathNode.Type.isOperator(operand, '/')) { + if (mathNode.Type.isOperator(operand, "/")) { numeratorArgs.push(operand.args[0]); denominatorArgs.push(operand.args[1]); } @@ -32,11 +37,11 @@ function multiplyFractions(node) { numeratorArgs.push(operand); } }); - var newNumerator = mathNode.Creator.parenthesis(mathNode.Creator.operator('*', numeratorArgs)); + var newNumerator = mathNode.Creator.parenthesis(mathNode.Creator.operator("*", numeratorArgs)); var newDenominator = denominatorArgs.length === 1 ? denominatorArgs[0] - : mathNode.Creator.parenthesis(mathNode.Creator.operator('*', denominatorArgs)); - var newNode = mathNode.Creator.operator('/', [newNumerator, newDenominator]); + : mathNode.Creator.parenthesis(mathNode.Creator.operator("*", denominatorArgs)); + var newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_FRACTIONS, node, newNode); } module.exports = search; diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js.map b/lib/simplifyExpression/multiplyFractionsSearch/index.js.map index 5f769f32..477a5727 100644 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.js.map +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,yEAAyE;AACzE,+CAA+C;AAC/C,0BAA0B;AAC1B,qCAAqC;AACrC,qEAAqE;AACrE,uEAAuE;AACvE,+EAA+E;AAC/E,6DAA6D;AAC7D,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;AAQvD,2BAA2B,IAAI;IAC7B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAlC,CAAkC,CAAC,CAAC;IAC7C,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAA7C,CAA6C,CAAC,CAAC;IACxD,EAAE,CAAC,CAAC,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,aAAa,GAAG,EAAE,CAAC;IACzB,IAAM,eAAe,GAAG,EAAE,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAA,OAAO;QACvB,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAC/C,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC;IACjD,IAAM,cAAc,GAAG,eAAe,CAAC,MAAM,KAAK,CAAC;UAC/C,eAAe,CAAC,CAAC,CAAC;UAClB,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;IAElF,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IAC/E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,yEAAyE;AACzE,+CAA+C;AAC/C,0BAA0B;AAC1B,qCAAqC;AACrC,qEAAqE;AACrE,uEAAuE;AACvE,+EAA+E;AAC/E,6DAA6D;AAC7D,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;AAEvD,yEAAyE;AACzE,+CAA+C;AAC/C,0BAA0B;AAC1B,qCAAqC;AACrC,oCAAoC;AACpC,2BAA2B,IAAqB;IAC9C,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAlC,CAAkC,CAAC,CAAC;IAC7C,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAA7C,CAA6C,CAAC,CAAC;IACxD,EAAE,CAAC,CAAC,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,aAAa,GAAG,EAAE,CAAC;IACzB,IAAM,eAAe,GAAG,EAAE,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAA,OAAO;QACvB,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAC/C,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC;IACjD,IAAM,cAAc,GAAG,eAAe,CAAC,MAAM,KAAK,CAAC;UAC/C,eAAe,CAAC,CAAC,CAAC;UAClB,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;IAElF,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IAC/E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.ts b/lib/simplifyExpression/multiplyFractionsSearch/index.ts index 13af59a9..22feff3c 100644 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.ts +++ b/lib/simplifyExpression/multiplyFractionsSearch/index.ts @@ -1,6 +1,6 @@ -import ChangeTypes = require('../../ChangeTypes'); -import mathNode = require('../../mathnode'); -import TreeSearch = require('../../TreeSearch'); +import ChangeTypes = require("../../ChangeTypes"); +import mathNode = require("../../mathnode"); +import TreeSearch = require("../../TreeSearch"); // If `node` is a product of terms where some are fractions (but none are // polynomial terms), multiplies them together. @@ -18,13 +18,12 @@ const search = TreeSearch.postOrder(multiplyFractions); // e.g. 2 * 5/x -> (2*5)/x // e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) // Returns a mathNode.Status object. -function multiplyFractions(node: any); -function multiplyFractions(node) { - if (!mathNode.Type.isOperator(node) || node.op !== '*') { +function multiplyFractions(node: mathjs.MathNode) { + if (!mathNode.Type.isOperator(node) || node.op !== "*") { return mathNode.Status.noChange(node); } const atLeastOneFraction = node.args.some( - arg => mathNode.Type.isOperator(arg, '/')); + arg => mathNode.Type.isOperator(arg, "/")); const hasPolynomialTerms = node.args.some( arg => mathNode.PolynomialTerm.isPolynomialTerm(arg)); if (!atLeastOneFraction || hasPolynomialTerms) { @@ -34,7 +33,7 @@ function multiplyFractions(node) { const numeratorArgs = []; const denominatorArgs = []; node.args.forEach(operand => { - if (mathNode.Type.isOperator(operand, '/')) { + if (mathNode.Type.isOperator(operand, "/")) { numeratorArgs.push(operand.args[0]); denominatorArgs.push(operand.args[1]); } @@ -44,12 +43,12 @@ function multiplyFractions(node) { }); const newNumerator = mathNode.Creator.parenthesis( - mathNode.Creator.operator('*', numeratorArgs)); + mathNode.Creator.operator("*", numeratorArgs)); const newDenominator = denominatorArgs.length === 1 ? denominatorArgs[0] - : mathNode.Creator.parenthesis(mathNode.Creator.operator('*', denominatorArgs)); + : mathNode.Creator.parenthesis(mathNode.Creator.operator("*", denominatorArgs)); - const newNode = mathNode.Creator.operator('/', [newNumerator, newDenominator]); + const newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); return mathNode.Status.nodeChanged( ChangeTypes.MULTIPLY_FRACTIONS, node, newNode); } diff --git a/lib/simplifyExpression/simplify.js b/lib/simplifyExpression/simplify.js index 5b3294d3..67440b6b 100644 --- a/lib/simplifyExpression/simplify.js +++ b/lib/simplifyExpression/simplify.js @@ -24,6 +24,8 @@ function simplify(node, debug) { // unflatten the node. return unflatten(simplifiedNode); } +// Unflattens a node so it is in the math.js style, by printing and parsing it +// again function unflatten(node) { return math.parse(print(node)); } diff --git a/lib/simplifyExpression/simplify.js.map b/lib/simplifyExpression/simplify.js.map index aaa0a9f0..64c6227f 100644 --- a/lib/simplifyExpression/simplify.js.map +++ b/lib/simplifyExpression/simplify.js.map @@ -1 +1 @@ -{"version":3,"file":"simplify.js","sourceRoot":"","sources":["simplify.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,kCAAqC;AACrC,yDAA4D;AAC5D,qCAAwC;AACxC,yEAA4E;AAC5E,2CAA8C;AAG9C,4EAA4E;AAC5E,0CAA0C;AAC1C,kBAAkB,IAAI,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IACjC,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IAED,IAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvC,IAAI,cAAc,CAAC;IACnB,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,cAAc,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;IACvC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,0DAA0D;QAC1D,cAAc,GAAG,uBAAuB,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;IACD,sBAAsB;IACtB,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AACnC,CAAC;AAKD,mBAAmB,IAAI;IACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file +{"version":3,"file":"simplify.js","sourceRoot":"","sources":["simplify.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,kCAAqC;AACrC,yDAA4D;AAC5D,qCAAwC;AACxC,yEAA4E;AAC5E,2CAA8C;AAG9C,4EAA4E;AAC5E,0CAA0C;AAC1C,kBAAkB,IAAqB,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IAClD,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IAED,IAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvC,IAAI,cAAc,CAAC;IACnB,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,cAAc,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;IACvC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,0DAA0D;QAC1D,cAAc,GAAG,uBAAuB,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;IACD,sBAAsB;IACtB,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AACnC,CAAC;AAED,8EAA8E;AAC9E,QAAQ;AACR,mBAAmB,IAAqB;IACtC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/simplify.ts b/lib/simplifyExpression/simplify.ts index 5c1bf02b..cbcc3360 100644 --- a/lib/simplifyExpression/simplify.ts +++ b/lib/simplifyExpression/simplify.ts @@ -1,14 +1,14 @@ -import math = require('mathjs'); -import checks = require('../checks'); -import flattenOperands = require('../util/flattenOperands'); -import print = require('../util/print'); -import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); -import stepThrough = require('./stepThrough'); +import math = require("mathjs"); +import checks = require("../checks"); +import flattenOperands = require("../util/flattenOperands"); +import print = require("../util/print"); +import removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); +import stepThrough = require("./stepThrough"); // Given a mathjs expression node, steps through simplifying the expression. // Returns the simplified expression node. -function simplify(node, debug=false) { +function simplify(node: mathjs.MathNode, debug=false) { if (checks.hasUnsupportedNodes(node)) { return node; } @@ -28,7 +28,7 @@ function simplify(node, debug=false) { // Unflattens a node so it is in the math.js style, by printing and parsing it // again -function unflatten(node) { +function unflatten(node: mathjs.MathNode) { return math.parse(print(node)); } diff --git a/lib/simplifyExpression/stepThrough.js b/lib/simplifyExpression/stepThrough.js index 7b847b1a..93396eaf 100644 --- a/lib/simplifyExpression/stepThrough.js +++ b/lib/simplifyExpression/stepThrough.js @@ -22,7 +22,7 @@ function stepThrough(node, debug) { if (debug) { // eslint-disable-next-line // again, unsure whether or not there should be a ternary argument - console.log('\n\nSimplifying: ' + print(node, false)); + console.log("\n\nSimplifying: " + print(node, false)); } if (checks.hasUnsupportedNodes(node)) { return []; @@ -30,7 +30,7 @@ function stepThrough(node, debug) { var nodeStatus; var steps = []; var originalExpressionStr = print(node); - var MAX_STEP_COUNT = 20; + var maxStepCount = 20; var iters = 0; // Now, step through the math expression until nothing changes nodeStatus = step(node); @@ -41,10 +41,10 @@ function stepThrough(node, debug) { steps.push(removeUnnecessaryParensInStep(nodeStatus)); var nextNode = Status.resetChangeGroups(nodeStatus.newNode); nodeStatus = step(nextNode); - if (iters++ === MAX_STEP_COUNT) { + if (iters++ === maxStepCount) { // eslint-disable-next-line - console.error('Math error: Potential infinite loop for expression: ' + - originalExpressionStr + ', returning no steps'); + console.error("Math error: Potential infinite loop for expression: " + + originalExpressionStr + ", returning no steps"); return []; } } @@ -109,10 +109,10 @@ function logSteps(nodeStatus) { // eslint-disable-next-line console.log(nodeStatus.changeType); // eslint-disable-next-line - console.log(print(nodeStatus.newNode) + '\n'); + console.log(print(nodeStatus.newNode) + "\n"); if (nodeStatus.substeps.length > 0) { // eslint-disable-next-line - console.log('\nsubsteps: '); + console.log("\nsubsteps: "); nodeStatus.substeps.forEach(function (substep) { return substep; }); } } diff --git a/lib/simplifyExpression/stepThrough.js.map b/lib/simplifyExpression/stepThrough.js.map index adee22ec..34358d2f 100644 --- a/lib/simplifyExpression/stepThrough.js.map +++ b/lib/simplifyExpression/stepThrough.js.map @@ -1 +1 @@ -{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":";AAAA,kCAAqC;AACrC,sCAA0C;AAC1C,2CAA8C;AAC9C,qDAAwD;AACxD,6CAAgD;AAChD,iEAAoE;AACpE,mEAAsE;AACtE,qDAAwD;AACxD,iDAAoD;AACpD,mDAAsD;AACtD,mDAAsD;AACtD,mEAAsE;AACtE,qCAAwC;AACxC,yDAA4D;AAC5D,qCAAwC;AACxC,yEAA4E;AAE5E,4EAA4E;AAC5E,6CAA6C;AAC7C,qBAAqB,IAAI,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IACpC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACV,2BAA2B;QACzB,kEAAkE;QACpE,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,UAAU,CAAC;IACf,IAAM,KAAK,GAAG,EAAE,CAAC;IAEjB,IAAM,qBAAqB,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAM,cAAc,GAAG,EAAE,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,8DAA8D;IAC9D,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC;QAC/B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACV,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,UAAU,CAAC,CAAC,CAAC;QACtD,IAAM,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC9D,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,cAAc,CAAC,CAAC,CAAC;YAC/B,2BAA2B;YAC3B,OAAO,CAAC,KAAK,CAAC,sDAAsD;gBACtD,qBAAqB,GAAG,sBAAsB,CAAC,CAAC;YAC9D,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC;AACf,CAAC;AAED,yEAAyE;AACzE,gDAAgD;AAChD,cAAc,IAAI;IAChB,IAAI,UAAU,CAAC;IAEf,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,GAAG,uBAAuB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAE3C,IAAM,0BAA0B,GAAG;QACjC,mEAAmE;QACnE,YAAY;QACZ,0EAA0E;QAC1E,uDAAuD;QACvD,cAAc;QACd,uDAAuD;QACvD,eAAe;QACf,kBAAkB;QAClB,gBAAgB;QAChB,4CAA4C;QAC5C,4CAA4C;QAC5C,uBAAuB;QACvB,gCAAgC;QAChC,sBAAsB;QACtB,wCAAwC;QACxC,uBAAuB;QACvB,0CAA0C;QAC1C,gBAAgB;QAChB,oBAAoB;QACpB,eAAe;KAChB,CAAC;IAEF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,0BAA0B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,UAAU,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjD,wEAAwE;QACxE,wEAAwE;QACxE,sBAAsB;QACtB,IAAI,GAAG,uBAAuB,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACzD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;YAC7B,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,mDAAmD;AACnD,yDAAyD;AACzD,uCAAuC,UAAU;IAC/C,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACnC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IACzD,CAAC;IAED,UAAU,CAAC,OAAO,GAAG,uBAAuB,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvE,UAAU,CAAC,OAAO,GAAG,uBAAuB,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,UAAU,CAAC;AACpB,CAAC;AAED,kBAAkB,UAAU;IAC1B,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACnC,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAE9C,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACnC,2BAA2B;QAC3B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5B,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAA,OAAO,IAAI,OAAA,OAAO,EAAP,CAAO,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,iBAAS,WAAW,CAAC"} \ No newline at end of file +{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/stepThrough.ts b/lib/simplifyExpression/stepThrough.ts index 049afdb8..f8b9f1e4 100644 --- a/lib/simplifyExpression/stepThrough.ts +++ b/lib/simplifyExpression/stepThrough.ts @@ -1,27 +1,27 @@ -import checks = require('../checks'); -import mathNode = require('../mathNode'); -import Status = require('../mathnode/Status'); -import arithmeticSearch = require('./arithmeticSearch'); -import basicsSearch = require('./basicsSearch'); -import breakUpNumeratorSearch = require('./breakUpNumeratorSearch'); -import collectAndCombineSearch = require('./collectAndCombineSearch'); -import distributeSearch = require('./distributeSearch'); -import divisionSearch = require('./divisionSearch'); -import fractionsSearch = require('./fractionsSearch'); -import functionsSearch = require('./functionsSearch'); -import multiplyFractionsSearch = require('./multiplyFractionsSearch'); -import clone = require('../util/clone'); -import flattenOperands = require('../util/flattenOperands'); -import print = require('../util/print'); -import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); +import checks = require("../checks"); +import mathNode = require("../mathNode"); +import Status = require("../mathnode/Status"); +import arithmeticSearch = require("./arithmeticSearch"); +import basicsSearch = require("./basicsSearch"); +import breakUpNumeratorSearch = require("./breakUpNumeratorSearch"); +import collectAndCombineSearch = require("./collectAndCombineSearch"); +import distributeSearch = require("./distributeSearch"); +import divisionSearch = require("./divisionSearch"); +import fractionsSearch = require("./fractionsSearch"); +import functionsSearch = require("./functionsSearch"); +import multiplyFractionsSearch = require("./multiplyFractionsSearch"); +import clone = require("../util/clone"); +import flattenOperands = require("../util/flattenOperands"); +import print = require("../util/print"); +import removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); // Given a mathjs expression node, steps through simplifying the expression. // Returns a list of details about each step. -function stepThrough(node, debug=false) { +function stepThrough(node: mathjs.MathNode, debug=false) { if (debug) { // eslint-disable-next-line // again, unsure whether or not there should be a ternary argument - console.log('\n\nSimplifying: ' + print(node, false)); + console.log("\n\nSimplifying: " + print(node, false)); } if (checks.hasUnsupportedNodes(node)) { @@ -32,7 +32,7 @@ function stepThrough(node, debug=false) { const steps = []; const originalExpressionStr = print(node); - const MAX_STEP_COUNT = 20; + const maxStepCount = 20; let iters = 0; // Now, step through the math expression until nothing changes @@ -44,10 +44,10 @@ function stepThrough(node, debug=false) { steps.push(removeUnnecessaryParensInStep(nodeStatus)); const nextNode = Status.resetChangeGroups(nodeStatus.newNode); nodeStatus = step(nextNode); - if (iters++ === MAX_STEP_COUNT) { + if (iters++ === maxStepCount) { // eslint-disable-next-line - console.error('Math error: Potential infinite loop for expression: ' + - originalExpressionStr + ', returning no steps'); + console.error("Math error: Potential infinite loop for expression: " + + originalExpressionStr + ", returning no steps"); return []; } } @@ -57,7 +57,7 @@ function stepThrough(node, debug=false) { // Given a mathjs expression node, performs a single step to simplify the // expression. Returns a mathNode.Status object. -function step(node) { +function step(node: mathjs.MathNode) { let nodeStatus; node = flattenOperands(node); @@ -120,11 +120,11 @@ function logSteps(nodeStatus) { // eslint-disable-next-line console.log(nodeStatus.changeType); // eslint-disable-next-line - console.log(print(nodeStatus.newNode) + '\n'); + console.log(print(nodeStatus.newNode) + "\n"); if (nodeStatus.substeps.length > 0) { // eslint-disable-next-line - console.log('\nsubsteps: '); + console.log("\nsubsteps: "); nodeStatus.substeps.forEach(substep => substep); } } diff --git a/lib/solveEquation/EquationOperations.js b/lib/solveEquation/EquationOperations.js index d4db5c27..882ff1f8 100644 --- a/lib/solveEquation/EquationOperations.js +++ b/lib/solveEquation/EquationOperations.js @@ -7,12 +7,12 @@ var EquationStatus = require("../equation/Status"); var Negative = require("../Negative"); var mathNode = require("../mathNode"); var Symbols = require("../Symbols"); -var COMPARATOR_TO_INVERSE = { - '>': '<', - '>=': '<=', - '<': '>', - '<=': '>=', - '=': '=' +var comparatorToInverse = { + '>': "<", + '>=': "<=", + '<': ">", + '<=': ">=", + '=': "=" }; var EquationOperations = (function () { function EquationOperations() { @@ -27,7 +27,7 @@ EquationOperations.ensureSymbolInLeftNode = function (equation, symbolName) { var rightSideSymbolTerm = Symbols.getLastSymbolTerm(equation.rightNode, symbolName); if (!leftSideSymbolTerm) { if (rightSideSymbolTerm) { - var comparator = COMPARATOR_TO_INVERSE[equation.comparator]; + var comparator = comparatorToInverse[equation.comparator]; var oldEquation = equation; var newEquation = new Equation(equation.rightNode, equation.leftNode, comparator); // no change groups are set for this step because everything changes, so @@ -35,7 +35,7 @@ EquationOperations.ensureSymbolInLeftNode = function (equation, symbolName) { return new EquationStatus(ChangeTypes.SWAP_SIDES, oldEquation, newEquation); } else { - throw Error('No term with symbol: ' + symbolName); + throw Error("No term with symbol: " + symbolName); } } return EquationStatus.noChange(equation); @@ -63,25 +63,25 @@ EquationOperations.removeSymbolFromRightSide = function (equation, symbolName) { symbolTerm = clone(symbolTerm); if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(symbolTerm); } else { - inverseOp = '-'; + inverseOp = "-"; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = symbolTerm; } } else if (mathNode.Type.isOperator(rightNode)) { - if (rightNode.op === '+') { + if (rightNode.op === "+") { if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(symbolTerm); } else { - inverseOp = '-'; + inverseOp = "-"; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = symbolTerm; } @@ -90,16 +90,16 @@ EquationOperations.removeSymbolFromRightSide = function (equation, symbolName) { // Note that operator '-' won't show up here because subtraction is // flattened into adding the negative. See 'TRICKY catch' in the README // for more details. - throw Error('Unsupported operation: ' + symbolTerm.op); + throw Error("Unsupported operation: " + symbolTerm.op); } } else if (mathNode.Type.isUnaryMinus(rightNode)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = symbolTerm.args[0]; } else { - throw Error('Unsupported node type: ' + rightNode.type); + throw Error("Unsupported node type: " + rightNode.type); } return performTermOperationOnEquation(equation, inverseOp, inverseTerm, changeType); }; @@ -117,61 +117,61 @@ EquationOperations.isolateSymbolOnLeftSide = function (equation, symbolName) { // in the equation nonSymbolTerm = clone(nonSymbolTerm); if (mathNode.Type.isOperator(leftNode)) { - if (leftNode.op === '+') { + if (leftNode.op === "+") { if (Negative.isNegative(nonSymbolTerm)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(nonSymbolTerm); } else { - inverseOp = '-'; + inverseOp = "-"; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = nonSymbolTerm; } } - else if (leftNode.op === '*') { + else if (leftNode.op === "*") { if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { - inverseOp = '*'; + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator('/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + inverseTerm = mathNode.Creator.operator("/", [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); } else { - inverseOp = '/'; + inverseOp = "/"; changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; inverseTerm = nonSymbolTerm; } } - else if (leftNode.op === '/') { + else if (leftNode.op === "/") { // The non symbol term is always a fraction because it's the // coefficient of our symbol term. // If the numerator is 1, we multiply both sides by the denominator, // otherwise we multiply by the inverse - if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { - inverseOp = '*'; + if (["1", "-1"].indexOf(nonSymbolTerm.args[0].value) !== -1) { + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; inverseTerm = nonSymbolTerm.args[1]; } else { - inverseOp = '*'; + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator('/', [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); + inverseTerm = mathNode.Creator.operator("/", [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); } } - else if (leftNode.op === '^') { + else if (leftNode.op === "^") { // TODO: support roots return EquationStatus.noChange(equation); } else { - throw Error('Unsupported operation: ' + leftNode.op); + throw Error("Unsupported operation: " + leftNode.op); } } else if (mathNode.Type.isUnaryMinus(leftNode)) { - inverseOp = '*'; + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; inverseTerm = mathNode.Creator.constant(-1); } else { - throw Error('Unsupported node type: ' + leftNode.type); + throw Error("Unsupported node type: " + leftNode.type); } return performTermOperationOnEquation(equation, inverseOp, inverseTerm, changeType); }; @@ -184,8 +184,8 @@ function performTermOperationOnEquation(equation, op, term, changeType) { var leftNode = performTermOperationOnExpression(equation.leftNode, op, leftTerm); var rightNode = performTermOperationOnExpression(equation.rightNode, op, rightTerm); var comparator = equation.comparator; - if (Negative.isNegative(term) && (op === '*' || op === '/')) { - comparator = COMPARATOR_TO_INVERSE[comparator]; + if (Negative.isNegative(term) && (op === "*" || op === "/")) { + comparator = comparatorToInverse[comparator]; } var newEquation = new Equation(leftNode, rightNode, comparator); return new EquationStatus(changeType, oldEquation, newEquation); diff --git a/lib/solveEquation/EquationOperations.js.map b/lib/solveEquation/EquationOperations.js.map index df8f0e0e..22ea3649 100644 --- a/lib/solveEquation/EquationOperations.js.map +++ b/lib/solveEquation/EquationOperations.js.map @@ -1 +1 @@ -{"version":3,"file":"EquationOperations.js","sourceRoot":"","sources":["EquationOperations.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"EquationOperations.js","sourceRoot":"","sources":["EquationOperations.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/solveEquation/EquationOperations.ts b/lib/solveEquation/EquationOperations.ts index 2c75d712..a4acbd44 100644 --- a/lib/solveEquation/EquationOperations.ts +++ b/lib/solveEquation/EquationOperations.ts @@ -1,18 +1,18 @@ // Operations on equation nodes -import ChangeTypes = require('../ChangeTypes'); -import clone = require('../util/clone'); -import Equation = require('../equation/Equation'); -import EquationStatus = require('../equation/Status'); -import Negative = require('../Negative'); -import mathNode = require('../mathNode'); -import Symbols = require('../Symbols'); -const COMPARATOR_TO_INVERSE = { - '>': '<', - '>=': '<=', - '<': '>', - '<=': '>=', - '=': '=' +import ChangeTypes = require("../ChangeTypes"); +import clone = require("../util/clone"); +import Equation = require("../equation/Equation"); +import EquationStatus = require("../equation/Status"); +import Negative = require("../Negative"); +import mathNode = require("../mathNode"); +import Symbols = require("../Symbols"); +const comparatorToInverse = { + '>': "<", + '>=': "<=", + '<': ">", + '<=': ">=", + '=': "=" }; class EquationOperations { @@ -30,7 +30,7 @@ class EquationOperations { if (!leftSideSymbolTerm) { if (rightSideSymbolTerm) { - const comparator = COMPARATOR_TO_INVERSE[equation.comparator]; + const comparator = comparatorToInverse[equation.comparator]; const oldEquation = equation; const newEquation = new Equation( equation.rightNode, @@ -43,7 +43,7 @@ class EquationOperations { oldEquation, newEquation); } else { - throw Error('No term with symbol: ' + symbolName); + throw Error("No term with symbol: " + symbolName); } } return EquationStatus.noChange(equation); @@ -61,7 +61,7 @@ class EquationOperations { // There are actually no cases where we'd remove symbols from the right side // by multiplying or dividing by a symbol term. // TODO: support inverting functions e.g. sqrt, ^, log etc. - static removeSymbolFromRightSide = (equation, symbolName) => { + static removeSymbolFromRightSide = (equation: Equation, symbolName) => { const rightNode = equation.rightNode; let symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); @@ -76,22 +76,22 @@ class EquationOperations { if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(symbolTerm); } else { - inverseOp = '-'; + inverseOp = "-"; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = symbolTerm; } } else if (mathNode.Type.isOperator(rightNode)) { - if (rightNode.op === '+') { + if (rightNode.op === "+") { if (Negative.isNegative(symbolTerm)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(symbolTerm); } else { - inverseOp = '-'; + inverseOp = "-"; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = symbolTerm; } @@ -99,14 +99,14 @@ class EquationOperations { // Note that operator '-' won't show up here because subtraction is // flattened into adding the negative. See 'TRICKY catch' in the README // for more details. - throw Error('Unsupported operation: ' + symbolTerm.op); + throw Error("Unsupported operation: " + symbolTerm.op); } } else if (mathNode.Type.isUnaryMinus(rightNode)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = symbolTerm.args[0]; } else { - throw Error('Unsupported node type: ' + rightNode.type); + throw Error("Unsupported node type: " + rightNode.type); } return performTermOperationOnEquation( equation, @@ -118,7 +118,7 @@ class EquationOperations { // Isolates the given symbolName to the left side by adding, multiplying, subtracting // or dividing all other symbols and constants from both sides appropriately // TODO: support inverting functions e.g. sqrt, ^, log etc. - static isolateSymbolOnLeftSide = (equation, symbolName) => { + static isolateSymbolOnLeftSide = (equation: Equation, symbolName) => { const leftNode = equation.leftNode; let nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); @@ -132,56 +132,56 @@ class EquationOperations { nonSymbolTerm = clone(nonSymbolTerm); if (mathNode.Type.isOperator(leftNode)) { - if (leftNode.op === '+') { + if (leftNode.op === "+") { if (Negative.isNegative(nonSymbolTerm)) { - inverseOp = '+'; + inverseOp = "+"; changeType = ChangeTypes.ADD_TO_BOTH_SIDES; inverseTerm = Negative.negate(nonSymbolTerm); } else { - inverseOp = '-'; + inverseOp = "-"; changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; inverseTerm = nonSymbolTerm; } - } else if (leftNode.op === '*') { + } else if (leftNode.op === "*") { if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { - inverseOp = '*'; + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; inverseTerm = mathNode.Creator.operator( - '/', + "/", [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); } else { - inverseOp = '/'; + inverseOp = "/"; changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; inverseTerm = nonSymbolTerm; } - } else if (leftNode.op === '/') { + } else if (leftNode.op === "/") { // The non symbol term is always a fraction because it's the // coefficient of our symbol term. // If the numerator is 1, we multiply both sides by the denominator, // otherwise we multiply by the inverse - if (['1', '-1'].indexOf(nonSymbolTerm.args[0].value) !== -1) { - inverseOp = '*'; + if (["1", "-1"].indexOf(nonSymbolTerm.args[0].value) !== -1) { + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; inverseTerm = nonSymbolTerm.args[1]; } else { - inverseOp = '*'; + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; inverseTerm = mathNode.Creator.operator( - '/', + "/", [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); } - } else if (leftNode.op === '^') { + } else if (leftNode.op === "^") { // TODO: support roots return EquationStatus.noChange(equation); } else { - throw Error('Unsupported operation: ' + leftNode.op); + throw Error("Unsupported operation: " + leftNode.op); } } else if (mathNode.Type.isUnaryMinus(leftNode)) { - inverseOp = '*'; + inverseOp = "*"; changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; inverseTerm = mathNode.Creator.constant(-1); } else { - throw Error('Unsupported node type: ' + leftNode.type); + throw Error("Unsupported node type: " + leftNode.type); } return performTermOperationOnEquation( @@ -194,7 +194,7 @@ class EquationOperations { // Modifies the left and right sides of an equation by `op`-ing `term` // to both sides. Returns an Status object. -function performTermOperationOnEquation(equation, op, term, changeType) { +function performTermOperationOnEquation(equation: Equation, op, term, changeType) { const oldEquation = equation.clone(); const leftTerm = clone(term); @@ -205,8 +205,8 @@ function performTermOperationOnEquation(equation, op, term, changeType) { equation.rightNode, op, rightTerm); let comparator = equation.comparator; - if (Negative.isNegative(term) && (op === '*' || op === '/')) { - comparator = COMPARATOR_TO_INVERSE[comparator]; + if (Negative.isNegative(term) && (op === "*" || op === "/")) { + comparator = comparatorToInverse[comparator]; } const newEquation = new Equation(leftNode, rightNode, comparator); diff --git a/lib/solveEquation/index.js b/lib/solveEquation/index.js index 81aeb958..782a38ed 100644 --- a/lib/solveEquation/index.js +++ b/lib/solveEquation/index.js @@ -3,7 +3,7 @@ var math = require("mathjs"); var stepThrough = require("./stepThrough"); function solveEquationString(equationString, debug) { if (debug === void 0) { debug = false; } - var comparators = ['<=', '>=', '=', '<', '>']; + var comparators = ["<=", ">=", "=", "<", ">"]; for (var i = 0; i < comparators.length; i++) { var comparator = comparators[i]; var sides = equationString.split(comparator); diff --git a/lib/solveEquation/index.ts b/lib/solveEquation/index.ts index 5ef908e2..a81a0b7a 100644 --- a/lib/solveEquation/index.ts +++ b/lib/solveEquation/index.ts @@ -1,8 +1,8 @@ -import math = require('mathjs'); -import stepThrough = require('./stepThrough'); +import math = require("mathjs"); +import stepThrough = require("./stepThrough"); function solveEquationString(equationString, debug=false) { - const comparators = ['<=', '>=', '=', '<', '>']; + const comparators = ["<=", ">=", "=", "<", ">"]; for (let i = 0; i < comparators.length; i++) { const comparator = comparators[i]; diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js index 84c82dcd..da916e86 100644 --- a/lib/solveEquation/stepThrough.js +++ b/lib/solveEquation/stepThrough.js @@ -10,7 +10,7 @@ var mathNode = require("../mathnode"); var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); var simplifyExpressionNode = require("../simplifyExpression/stepThrough"); var Symbols = require("../Symbols"); -var COMPARATOR_TO_FUNCTION = { +var comparatorToFunction = { '=': function (left, right) { return left === right; }, '>': function (left, right) { return left > right; }, '>=': function (left, right) { return left >= right; }, @@ -27,7 +27,7 @@ function stepThrough(leftNode, rightNode, comparator, debug) { if (debug) { // eslint-disable-next-line // unsure whether or not the second paramter should be a thing? - console.log('\n\nSolving: ' + equation.print(false)); + console.log("\n\nSolving: " + equation.print(false)); } // we can't solve/find steps if there are any unsupported nodes if (checks.hasUnsupportedNodes(equation.leftNode) || @@ -42,7 +42,7 @@ function stepThrough(leftNode, rightNode, comparator, debug) { var equationStatus; var steps = []; var originalEquationStr = equation.print(); - var MAX_STEP_COUNT = 20; + var maxStepCount = 20; var iters = 0; // Step through the math equation until nothing changes do { @@ -62,9 +62,9 @@ function stepThrough(leftNode, rightNode, comparator, debug) { } catch (e) { // This error happens for some math that we don't support - if (e.message.startsWith('No term with symbol: ')) { + if (e.message.startsWith("No term with symbol: ")) { // eslint-disable-next-line - console.error('Math error: ' + e.message + ', returning no steps'); + console.error("Math error: " + e.message + ", returning no steps"); return []; } else { @@ -74,9 +74,9 @@ function stepThrough(leftNode, rightNode, comparator, debug) { if (equationStatus.hasChanged()) { if (equationStatus.newEquation.print().length > 300) { // eslint-disable-next-line - throw Error('Math error: Potential infinite loop for equation ' + - originalEquationStr + '. It reached over 300 characters ' + - ' long, so returning no steps'); + throw Error("Math error: Potential infinite loop for equation " + + originalEquationStr + ". It reached over 300 characters " + + " long, so returning no steps"); } if (debug) { logSteps(equationStatus); @@ -84,10 +84,10 @@ function stepThrough(leftNode, rightNode, comparator, debug) { steps.push(equationStatus); } equation = EquationStatus.resetChangeGroups(equationStatus.newEquation); - if (iters++ === MAX_STEP_COUNT) { + if (iters++ === maxStepCount) { // eslint-disable-next-line - console.error('Math error: Potential infinite loop for equation: ' + - originalEquationStr + ', returning no steps'); + console.error("Math error: Potential infinite loop for equation: " + + originalEquationStr + ", returning no steps"); return []; } } while (equationStatus.hasChanged()); @@ -97,9 +97,9 @@ function stepThrough(leftNode, rightNode, comparator, debug) { // the steps and the result of the equation e.g. 'True' or 'False' function solveConstantEquation(equation, debug, steps) { if (steps === void 0) { steps = []; } - var compareFunction = COMPARATOR_TO_FUNCTION[equation.comparator]; + var compareFunction = comparatorToFunction[equation.comparator]; if (!compareFunction) { - throw Error('Unexpected comparator'); + throw Error("Unexpected comparator"); } steps = addSimplificationSteps(steps, equation, debug); if (steps.length > 0) { @@ -112,7 +112,7 @@ function solveConstantEquation(equation, debug, steps) { equation.rightNode = removeUnnecessaryParens(equation.rightNode); if (!mathNode.Type.isConstantOrConstantFraction(equation.leftNode, true) || !mathNode.Type.isConstantOrConstantFraction(equation.rightNode, true)) { - throw Error('Expected both nodes to be constants, instead got: ' + + throw Error("Expected both nodes to be constants, instead got: " + equation.print()); } var leftValue = evaluate(equation.leftNode); @@ -130,9 +130,11 @@ function solveConstantEquation(equation, debug, steps) { if (debug) { logSteps(equationStatus); } - steps.push(equationStatus); + steps.push((equationStatus)); return steps; } +// Given a symbol and an equation, performs a single step to +// solve for the symbol. Returns an Status object. function step(equation, symbolName) { var solveFunctions = [ // ensure the symbol is always on the left node @@ -213,12 +215,12 @@ function addSimplificationSteps(steps, equation, debug) { } function logSteps(equationStatus) { // eslint-disable-next-line - console.log('\n' + equationStatus.changeType); + console.log("\n" + equationStatus.changeType); // eslint-disable-next-line console.log(equationStatus.newEquation.print()); if (equationStatus.substeps.length > 0) { // eslint-disable-next-line - console.log('\n substeps: '); + console.log("\n substeps: "); equationStatus.substeps.forEach(logSteps); } } diff --git a/lib/solveEquation/stepThrough.js.map b/lib/solveEquation/stepThrough.js.map index d8c322e8..29777e79 100644 --- a/lib/solveEquation/stepThrough.js.map +++ b/lib/solveEquation/stepThrough.js.map @@ -1 +1 @@ -{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/solveEquation/stepThrough.ts b/lib/solveEquation/stepThrough.ts index 7bd5a404..1fe10d02 100644 --- a/lib/solveEquation/stepThrough.ts +++ b/lib/solveEquation/stepThrough.ts @@ -1,15 +1,15 @@ -import ChangeTypes = require('../ChangeTypes'); -import checks = require('../checks'); -import Equation = require('../equation/Equation'); -import EquationOperations = require('./EquationOperations'); -import EquationStatus = require('../equation/Status'); -import evaluate = require('../util/evaluate'); -import flattenOperands = require('../util/flattenOperands'); -import mathNode = require('../mathnode'); -import removeUnnecessaryParens = require('../util/removeUnnecessaryParens'); -import simplifyExpressionNode = require('../simplifyExpression/stepThrough'); -import Symbols = require('../Symbols'); -const COMPARATOR_TO_FUNCTION = { +import ChangeTypes = require("../ChangeTypes"); +import checks = require("../checks"); +import Equation = require("../equation/Equation"); +import EquationOperations = require("./EquationOperations"); +import EquationStatus = require("../equation/Status"); +import evaluate = require("../util/evaluate"); +import flattenOperands = require("../util/flattenOperands"); +import mathNode = require("../mathnode"); +import removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); +import simplifyExpressionNode = require("../simplifyExpression/stepThrough"); +import Symbols = require("../Symbols"); +const comparatorToFunction = { '='(left, right) { return left === right; }, '>'(left, right) { return left > right; }, '>='(left, right) { return left >= right; }, @@ -21,13 +21,13 @@ const COMPARATOR_TO_FUNCTION = { // the solution. Possible solutions include: // - solving for a variable (e.g. 'x=3' for '3x=4+5') // - the result of comparing values (e.g. 'true' for 3 = 3, 'false' for 3 < 2) -function stepThrough(leftNode, rightNode, comparator, debug=false) { +function stepThrough(leftNode: mathjs.MathNode, rightNode: mathjs.MathNode, comparator, debug=false) { let equation = new Equation(leftNode, rightNode, comparator); if (debug) { // eslint-disable-next-line // unsure whether or not the second paramter should be a thing? - console.log('\n\nSolving: ' + equation.print(false)); + console.log("\n\nSolving: " + equation.print(false)); } // we can't solve/find steps if there are any unsupported nodes @@ -47,7 +47,7 @@ function stepThrough(leftNode, rightNode, comparator, debug=false) { let steps = []; const originalEquationStr = equation.print(); - const MAX_STEP_COUNT = 20; + const maxStepCount = 20; let iters = 0; // Step through the math equation until nothing changes @@ -72,9 +72,9 @@ function stepThrough(leftNode, rightNode, comparator, debug=false) { } catch (e) { // This error happens for some math that we don't support - if (e.message.startsWith('No term with symbol: ')) { + if (e.message.startsWith("No term with symbol: ")) { // eslint-disable-next-line - console.error('Math error: ' + e.message + ', returning no steps'); + console.error("Math error: " + e.message + ", returning no steps"); return []; } else { @@ -85,9 +85,9 @@ function stepThrough(leftNode, rightNode, comparator, debug=false) { if (equationStatus.hasChanged()) { if (equationStatus.newEquation.print().length > 300) { // eslint-disable-next-line - throw Error('Math error: Potential infinite loop for equation ' + - originalEquationStr + '. It reached over 300 characters '+ - ' long, so returning no steps'); + throw Error("Math error: Potential infinite loop for equation " + + originalEquationStr + ". It reached over 300 characters "+ + " long, so returning no steps"); } if (debug) { logSteps(equationStatus); @@ -96,10 +96,10 @@ function stepThrough(leftNode, rightNode, comparator, debug=false) { } equation = EquationStatus.resetChangeGroups(equationStatus.newEquation); - if (iters++ === MAX_STEP_COUNT) { + if (iters++ === maxStepCount) { // eslint-disable-next-line - console.error('Math error: Potential infinite loop for equation: ' + - originalEquationStr + ', returning no steps'); + console.error("Math error: Potential infinite loop for equation: " + + originalEquationStr + ", returning no steps"); return []; } } while (equationStatus.hasChanged()); @@ -109,11 +109,11 @@ function stepThrough(leftNode, rightNode, comparator, debug=false) { // Given an equation of constants, will simplify both sides, returning // the steps and the result of the equation e.g. 'True' or 'False' -function solveConstantEquation(equation, debug, steps=[]) { - const compareFunction = COMPARATOR_TO_FUNCTION[equation.comparator]; +function solveConstantEquation(equation: Equation, debug, steps=[]) { + const compareFunction = comparatorToFunction[equation.comparator]; if (!compareFunction) { - throw Error('Unexpected comparator'); + throw Error("Unexpected comparator"); } steps = addSimplificationSteps(steps, equation, debug); @@ -130,7 +130,7 @@ function solveConstantEquation(equation, debug, steps=[]) { if (!mathNode.Type.isConstantOrConstantFraction(equation.leftNode, true) || !mathNode.Type.isConstantOrConstantFraction(equation.rightNode, true)) { - throw Error('Expected both nodes to be constants, instead got: ' + + throw Error("Expected both nodes to be constants, instead got: " + equation.print()); } @@ -150,13 +150,12 @@ function solveConstantEquation(equation, debug, steps=[]) { if (debug) { logSteps(equationStatus); } - steps.push(equationStatus); + steps.push((equationStatus) as any); return steps; } // Given a symbol and an equation, performs a single step to // solve for the symbol. Returns an Status object. -function step(equation: any, symbolName: any); function step(equation, symbolName) { const solveFunctions = [ // ensure the symbol is always on the left node @@ -180,7 +179,7 @@ function step(equation, symbolName) { } // Simplifies the equation and returns the simplification steps -function addSimplificationSteps(steps, equation, debug=false) { +function addSimplificationSteps(steps, equation: Equation, debug=false) { let oldEquation = equation.clone(); const leftSteps = simplifyExpressionNode(equation.leftNode, false); @@ -248,15 +247,14 @@ function addSimplificationSteps(steps, equation, debug=false) { return steps; } -function logSteps(equationStatus: any); -function logSteps(equationStatus) { +function logSteps(equationStatus: EquationStatus) { // eslint-disable-next-line - console.log('\n' + equationStatus.changeType); + console.log("\n" + equationStatus.changeType); // eslint-disable-next-line console.log(equationStatus.newEquation.print()); if (equationStatus.substeps.length > 0) { // eslint-disable-next-line - console.log('\n substeps: '); + console.log("\n substeps: "); equationStatus.substeps.forEach(logSteps); } } diff --git a/lib/util/Util.js b/lib/util/Util.js index bc168bf2..ef5b4cc2 100644 --- a/lib/util/Util.js +++ b/lib/util/Util.js @@ -4,19 +4,19 @@ */ var Util = (function () { function Util() { - // Adds `value` to a list in `dict`, creating a new list if the key isn't in - // the dictionary yet. Returns the updated dictionary. - this.appendToArrayInObject = function (dict, key, value) { - if (dict[key]) { - dict[key].push(value); - } - else { - dict[key] = [value]; - } - return dict; - }; } return Util; }()); +// Adds `value` to a list in `dict`, creating a new list if the key isn't in +// the dictionary yet. Returns the updated dictionary. +Util.appendToArrayInObject = function (dict, key, value) { + if (dict[key]) { + dict[key].push(value); + } + else { + dict[key] = [value]; + } + return dict; +}; module.exports = Util; //# sourceMappingURL=Util.js.map \ No newline at end of file diff --git a/lib/util/Util.js.map b/lib/util/Util.js.map index c99bc463..f72d0420 100644 --- a/lib/util/Util.js.map +++ b/lib/util/Util.js.map @@ -1 +1 @@ -{"version":3,"file":"Util.js","sourceRoot":"","sources":["Util.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH;IAAA;QAEA,4EAA4E;QAC5E,sDAAsD;QAClD,0BAAqB,GAAG,UAAC,IAAI,EAAE,GAAG,EAAE,KAAK;YACrC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACZ,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;YAAC,IAAI,CAAC,CAAC;gBACJ,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC,CAAC;IACN,CAAC;IAAD,WAAC;AAAD,CAAC,AAZD,IAYC;AAED,iBAAS,IAAI,CAAC"} \ No newline at end of file +{"version":3,"file":"Util.js","sourceRoot":"","sources":["Util.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH;IAAA;IAYA,CAAC;IAAD,WAAC;AAAD,CAAC,AAZD;AAEA,4EAA4E;AAC5E,sDAAsD;AAC3C,0BAAqB,GAAG,UAAC,IAAI,EAAE,GAAG,EAAE,KAAK;IAC5C,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC,CAAC;AAGN,iBAAS,IAAI,CAAC"} \ No newline at end of file diff --git a/lib/util/flattenOperands.ts b/lib/util/flattenOperands.ts index 50a9ed7d..c3b14017 100644 --- a/lib/util/flattenOperands.ts +++ b/lib/util/flattenOperands.ts @@ -1,6 +1,6 @@ -import evaluate = require('./evaluate'); -import Negative = require('../Negative'); -import mathNode = require('../mathNode'); +import evaluate = require("./evaluate"); +import Negative = require("../Negative"); +import mathNode = require("../mathNode"); /* Background: @@ -45,17 +45,17 @@ function flattenOperands(node) { return constNode; } else if (Node.Type.isOperator(node)) { - if ('+-/*'.includes(node.op)) { + if ("+-/*".includes(node.op)) { let parentOp; - if (node.op === '/') { + if (node.op === "/") { // Division is flattened in partner with multiplication. This means // that after collecting the operands, they'll be children args of * - parentOp = '*'; + parentOp = "*"; } - else if (node.op === '-') { + else if (node.op === "-") { // Subtraction is flattened in partner with addition, This means that // after collecting the operands, they'll be children args of + - parentOp = '+'; + parentOp = "+"; } else { parentOp = node.op; @@ -82,11 +82,11 @@ function flattenOperands(node) { } return flattenedNode; } - else if (Node.Type.isFunction(node, 'abs')) { + else if (Node.Type.isFunction(node, "abs")) { node.args[0] = flattenOperands(node.args[0]); return node; } - else if (Node.Type.isFunction(node, 'nthRoot')) { + else if (Node.Type.isFunction(node, "nthRoot")) { node.args[0] = flattenOperands(node.args[0]); if (node.args[1]) { node.args[1] = flattenOperands(node.args[1]); @@ -125,13 +125,13 @@ function flattenSupportedOperation(node, parentOp) { // (which is impossible for division), then by recursing through the // original tree for any multiplication node - if there was one, it would // have ended up at the root. - if (node.op === '/' && (operands.length > 2 || + if (node.op === "/" && (operands.length > 2 || hasMultiplicationBesideDivision(node))) { - node = Node.Creator.operator('*', operands); + node = Node.Creator.operator("*", operands); } // similarily, - will become + always - else if (node.op === '-') { - node = Node.Creator.operator('+', operands); + else if (node.op === "-") { + node = Node.Creator.operator("+", operands); } // otherwise keep the operator, replace operands else { @@ -139,7 +139,7 @@ function flattenSupportedOperation(node, parentOp) { } // When we collect operands to flatten multiplication, the // multiplication of those operands should never be implicit - if (node.op === '*') { + if (node.op === "*") { node.implicit = false; } } @@ -164,15 +164,15 @@ function getOperands(node, parentOp) { } switch (node.op) { // division is part of flattening multiplication - case '*': - case '/': - if (parentOp !== '*') { + case "*": + case "/": + if (parentOp !== "*") { return [flattenOperands(node)]; } break; - case '+': - case '-': - if (parentOp !== '+') { + case "+": + case "-": + if (parentOp !== "+") { return [flattenOperands(node)]; } break; @@ -190,13 +190,13 @@ function getOperands(node, parentOp) { // coefficient multiplied by a symbol such as 2x^2 or 3y) // This is true if there's an implicit multiplication and the right operand // is a symbol or a symbol to an exponent. - else if (parentOp === '*' && isPolynomialTermMultiplication(node)) { + else if (parentOp === "*" && isPolynomialTermMultiplication(node)) { return maybeFlattenPolynomialTerm(node); } - else if (parentOp === '*' && node.op === '/') { + else if (parentOp === "*" && node.op === "/") { return flattenDivision(node); } - else if (node.op === '-') { + else if (node.op === "-") { // this operation will become addition e.g. 2 - 3 -> 2 + -(-3) const secondOperand = node.args[1]; const negativeSecondOperand = Negative.negate(secondOperand, true); @@ -227,7 +227,7 @@ function getOperands(node, parentOp) { // an expression tree with root node * and children 2*2 and x function isPolynomialTermMultiplication(node) { // This concept only applies when we're flattening multiplication operations - if (node.op !== '*') { + if (node.op !== "*") { return false; } // This only makes sense when we're flattening two arguments @@ -253,7 +253,7 @@ function isPolynomialTermMultiplication(node) { function maybeFlattenPolynomialTerm(node: any); function maybeFlattenPolynomialTerm(node) { // We recurse on the left side of the tree to find operands so far - const operands = getOperands(node.args[0], '*'); + const operands = getOperands(node.args[0], "*"); // If the last operand (so far) under * was a constant, then it's a // polynomial term. @@ -270,7 +270,7 @@ function maybeFlattenPolynomialTerm(node) { if (mathNode.Type.isConstantOrConstantFraction(lastOperand)) { // we replace the constant (which we popped) with constant*symbol operands.push( - mathNode.Creator.operator('*', [lastOperand, nextOperand], true)); + mathNode.Creator.operator("*", [lastOperand, nextOperand], true)); } // Now we know it isn't a polynomial term, it's just another seperate operand else { @@ -290,7 +290,7 @@ function flattenDivision(node) { // We recurse on the left side of the tree to find operands so far // Flattening division is always considered part of a bigger picture // of multiplication, so we get operands with '*' - let operands = getOperands(node.args[0], '*'); + let operands = getOperands(node.args[0], "*"); if (operands.length === 1) { node.args[0] = operands.pop(); @@ -304,7 +304,7 @@ function flattenDivision(node) { const denominator = flattenOperands(node.args[1]); // Note that this means 2 * 3 * 4 / 5 / 6 * 7 will flatten but keep the 4/5/6 // as an operand - in simplifyDivision.js this is changed to 4/(5*6) - const divisionNode = mathNode.Creator.operator('/', [numerator, denominator]); + const divisionNode = mathNode.Creator.operator("/", [numerator, denominator]); operands.push(divisionNode); } @@ -320,11 +320,11 @@ function hasMultiplicationBesideDivision(node) { if (!mathNode.Type.isOperator(node)) { return false; } - if (node.op === '*') { + if (node.op === "*") { return true; } // we ony recurse through division - if (node.op !== '/') { + if (node.op !== "/") { return false; } return node.args.some(hasMultiplicationBesideDivision); diff --git a/lib/util/print.js b/lib/util/print.js new file mode 100644 index 00000000..8d5b93e5 --- /dev/null +++ b/lib/util/print.js @@ -0,0 +1,98 @@ +"use strict"; +var clone = require("./clone"); +var flatten = require("./flattenOperands"); +var mathNode = require("../mathNode"); +// Prints an expression node in asciimath +// If showPlusMinus is true, print + - (e.g. 2 + -3) +// If it's false (the default) 2 + -3 would print as 2 - 3 +// (The + - is needed to support the conversion of subtraction to addition of +// negative terms. See flattenOperands for more details if you're curious.) +function print(node, showPlusMinus) { + if (showPlusMinus === void 0) { showPlusMinus = false; } + node = flatten(clone(node)); + var string = printTreeTraversal(node); + if (!showPlusMinus) { + string = string.replace(/\s*?\+\s*?\-\s*?/g, " - "); + } + return string; +} +function printTreeTraversal(node, parentNode) { + if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { + var polyTerm = new mathNode.PolynomialTerm(node); + // This is so we don't print 2/3 x^2 as 2 / 3x^2 + // Still print x/2 as x/2 and not 1/2 x though + if (polyTerm.hasFractionCoeff() && node.op !== "/") { + var coeffTerm = polyTerm.getCoeffNode(); + var coeffStr = printTreeTraversal(coeffTerm); + var nonCoeffTerm = mathNode.Creator.polynomialTerm(polyTerm.symbol, polyTerm.exponent, null); + var nonCoeffStr = printTreeTraversal(nonCoeffTerm); + return coeffStr + " " + nonCoeffStr; + } + } + if (mathNode.Type.isIntegerFraction(node)) { + return node.args[0] + "/" + node.args[1]; + } + if (mathNode.Type.isOperator(node)) { + if (node.op === "/" && mathNode.Type.isOperator(node.args[1])) { + return printTreeTraversal(node.args[0]) + " / (" + printTreeTraversal(node.args[1]) + ")"; + } + var opString = ""; + switch (node.op) { + case "+": + case "-": + // add space between operator and operands + opString = " " + node.op + " "; + break; + case "*": + if (node.implicit) { + break; + } + opString = " " + node.op + " "; + break; + case "/": + // no space for constant fraction divisions (slightly easier to read) + if (mathNode.Type.isConstantFraction(node, true)) { + opString = "" + node.op; + } + else { + opString = " " + node.op + " "; + } + break; + case "^": + // no space for exponents + opString = "" + node.op; + break; + } + var str = node.args.map(function (arg) { return printTreeTraversal(arg, node); }).join(opString); + // Need to add parens around any [+, -] operation + // nested in [/, *, ^] operation + // Check #120, #126 issues for more details. + // { "/" [{ "+" ["x", "2"] }, "2"] } -> (x + 2) / 2. + if (parentNode && + mathNode.Type.isOperator(parentNode) && + node.op && parentNode.op && + "*/^".indexOf(parentNode.op) >= 0 && + "+-".indexOf(node.op) >= 0) { + str = "(" + str + ")"; + } + return str; + } + else if (mathNode.Type.isParenthesis(node)) { + return "(" + printTreeTraversal(node.content) + ")"; + } + else if (mathNode.Type.isUnaryMinus(node)) { + if (mathNode.Type.isOperator(node.args[0]) && + "*/^".indexOf(node.args[0].op) === -1 && + !mathNode.PolynomialTerm.isPolynomialTerm(node)) { + return "-(" + printTreeTraversal(node.args[0]) + ")"; + } + else { + return "-" + printTreeTraversal(node.args[0]); + } + } + else { + return node.toString(); + } +} +module.exports = print; +//# sourceMappingURL=print.js.map \ No newline at end of file diff --git a/lib/util/print.js.map b/lib/util/print.js.map new file mode 100644 index 00000000..04410637 --- /dev/null +++ b/lib/util/print.js.map @@ -0,0 +1 @@ +{"version":3,"file":"print.js","sourceRoot":"","sources":["print.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/util/print.ts b/lib/util/print.ts index 5ce26853..745cfc49 100644 --- a/lib/util/print.ts +++ b/lib/util/print.ts @@ -1,6 +1,6 @@ -import clone = require('./clone'); -import flatten = require('./flattenOperands'); -import mathNode = require('../mathNode'); +import clone = require("./clone"); +import flatten = require("./flattenOperands"); +import mathNode = require("../mathNode"); // Prints an expression node in asciimath // If showPlusMinus is true, print + - (e.g. 2 + -3) @@ -12,7 +12,7 @@ function print(node, showPlusMinus=false) { let string = printTreeTraversal(node); if (!showPlusMinus) { - string = string.replace(/\s*?\+\s*?\-\s*?/g, ' - '); + string = string.replace(/\s*?\+\s*?\-\s*?/g, " - "); } return string; } @@ -21,7 +21,7 @@ function printTreeTraversal(node, parentNode?) { const polyTerm = new mathNode.PolynomialTerm(node); // This is so we don't print 2/3 x^2 as 2 / 3x^2 // Still print x/2 as x/2 and not 1/2 x though - if (polyTerm.hasFractionCoeff() && node.op !== '/') { + if (polyTerm.hasFractionCoeff() && node.op !== "/") { const coeffTerm = polyTerm.getCoeffNode(); const coeffStr = printTreeTraversal(coeffTerm); @@ -38,25 +38,25 @@ function printTreeTraversal(node, parentNode?) { } if (mathNode.Type.isOperator(node)) { - if (node.op === '/' && mathNode.Type.isOperator(node.args[1])) { + if (node.op === "/" && mathNode.Type.isOperator(node.args[1])) { return `${printTreeTraversal(node.args[0])} / (${printTreeTraversal(node.args[1])})`; } - let opString = ''; + let opString = ""; switch (node.op) { - case '+': - case '-': + case "+": + case "-": // add space between operator and operands opString = ` ${node.op} `; break; - case '*': + case "*": if (node.implicit) { break; } opString = ` ${node.op} `; break; - case '/': + case "/": // no space for constant fraction divisions (slightly easier to read) if (mathNode.Type.isConstantFraction(node, true)) { opString = `${node.op}`; @@ -65,7 +65,7 @@ function printTreeTraversal(node, parentNode?) { opString = ` ${node.op} `; } break; - case '^': + case "^": // no space for exponents opString = `${node.op}`; break; @@ -80,8 +80,8 @@ function printTreeTraversal(node, parentNode?) { if (parentNode && mathNode.Type.isOperator(parentNode) && node.op && parentNode.op && - '*/^'.indexOf(parentNode.op) >= 0 && - '+-'.indexOf(node.op) >= 0) { + "*/^".indexOf(parentNode.op) >= 0 && + "+-".indexOf(node.op) >= 0) { str = `(${str})`; } @@ -92,7 +92,7 @@ function printTreeTraversal(node, parentNode?) { } else if (mathNode.Type.isUnaryMinus(node)) { if (mathNode.Type.isOperator(node.args[0]) && - '*/^'.indexOf(node.args[0].op) === -1 && + "*/^".indexOf(node.args[0].op) === -1 && !mathNode.PolynomialTerm.isPolynomialTerm(node)) { return `-(${printTreeTraversal(node.args[0])})`; } diff --git a/lib/util/removeUnnecessaryParens.js b/lib/util/removeUnnecessaryParens.js new file mode 100644 index 00000000..d19e2223 --- /dev/null +++ b/lib/util/removeUnnecessaryParens.js @@ -0,0 +1,142 @@ +"use strict"; +var checks = require("../checks"); +var LikeTermCollector = require("../simplifyExpression/collectAndCombineSearch/LikeTermCollector"); +var mathNode = require("../mathNode"); +// Removes any parenthesis around nodes that can't be resolved further. +// Input must be a top level expression. +// Returns a node. +function removeUnnecessaryParens(node, rootNode) { + if (rootNode === void 0) { rootNode = false; } + // Parens that wrap everything are redundant. + // NOTE: removeUnnecessaryParensSearch recursively removes parens that aren't + // needed, while this step only applies to the very top level expression. + // e.g. (2 + 3) * 4 can't become 2 + 3 * 4, but if (2 + 3) as a top level + // expression can become 2 + 3 + if (rootNode) { + while (mathNode.Type.isParenthesis(node)) { + node = node.content; + } + } + return removeUnnecessaryParensSearch(node); +} +// Recursively moves parenthesis around nodes that can't be resolved further if +// it doesn't change the value of the expression. Returns a node. +// NOTE: after this function is called, every parenthesis node in the +// tree should always have an operator node or unary minus as its child. +function removeUnnecessaryParensSearch(node) { + if (mathNode.Type.isOperator(node)) { + return removeUnnecessaryParensInOperatorNode(node); + } + else if (mathNode.Type.isFunction(node)) { + return removeUnnecessaryParensInFunctionNode(node); + } + else if (mathNode.Type.isParenthesis(node)) { + return removeUnnecessaryParensInParenthesisNode(node); + } + else if (mathNode.Type.isConstant(node, true) || mathNode.Type.isSymbol(node)) { + return node; + } + else if (mathNode.Type.isUnaryMinus(node)) { + var content = node.args[0]; + node.args[0] = removeUnnecessaryParensSearch(content); + return node; + } + else { + throw Error('Unsupported node type: ' + node.type); + } +} +function removeUnnecessaryParensInOperatorNode(node) { + // Special case: if the node is an exponent node and the base + // is an operator, we should keep the parentheses for the base. + // e.g. (2x)^2 -> (2x)^2 instead of 2x^2 + if (node.op === '^' && mathNode.Type.isParenthesis(node.args[0])) { + var base = node.args[0]; + if (mathNode.Type.isOperator(base.content)) { + base.content = removeUnnecessaryParensSearch(base.content); + node.args[1] = removeUnnecessaryParensSearch(node.args[1]); + return node; + } + } + node.args.forEach(function (child, i) { + node.args[i] = removeUnnecessaryParensSearch(child); + }); + // Sometimes, parens are around expressions that have been simplified + // all they can be. If that expression is part of an addition or subtraction + // operation, we can remove the parenthesis. + // e.g. (x+4) + 12 -> x+4 + 12 + if (node.op === '+') { + node.args.forEach(function (child, i) { + if (mathNode.Type.isParenthesis(child) && + !canCollectOrCombine(child.content)) { + // remove the parens by replacing the child node (in its args list) + // with its content + node.args[i] = child.content; + } + }); + } + else if (node.op === '-') { + if (mathNode.Type.isParenthesis(node.args[0]) && + !canCollectOrCombine(node.args[0].content)) { + node.args[0] = node.args[0].content; + } + } + return node; +} +function removeUnnecessaryParensInFunctionNode(node) { + node.args.forEach(function (child, i) { + if (mathNode.Type.isParenthesis(child)) { + child = child.content; + } + node.args[i] = removeUnnecessaryParensSearch(child); + }); + return node; +} +function removeUnnecessaryParensInParenthesisNode(node) { + // polynomials terms can be complex trees (e.g. 3x^2/5) but don't need parens + // around them + if (mathNode.PolynomialTerm.isPolynomialTerm(node.content)) { + // also recurse to remove any unnecessary parens within the term + // (e.g. the exponent might have parens around it) + if (node.content.args) { + node.content.args.forEach(function (arg, i) { + node.content.args[i] = removeUnnecessaryParensSearch(arg); + }); + } + node = node.content; + } + else if (mathNode.Type.isConstant(node.content, true) || + mathNode.Type.isIntegerFraction(node.content) || + mathNode.Type.isSymbol(node.content)) { + node = node.content; + } + else if (mathNode.Type.isFunction(node.content)) { + node = node.content; + node = removeUnnecessaryParensSearch(node); + } + else if (mathNode.Type.isOperator(node.content)) { + node.content = removeUnnecessaryParensSearch(node.content); + // exponent nodes don't need parens around them + if (node.content.op === '^') { + node = node.content; + } + } + else if (mathNode.Type.isParenthesis(node.content)) { + node = removeUnnecessaryParensSearch(node.content); + } + else if (mathNode.Type.isUnaryMinus(node.content)) { + node.content = removeUnnecessaryParensSearch(node.content); + } + else { + throw Error('Unsupported node type: ' + node.content.type); + } + return node; +} +// Returns true if any of the collect or combine steps can be applied to the +// expression tree `node`. +function canCollectOrCombine(node) { + return LikeTermCollector.canCollectLikeTerms(node) || + checks.resolvesToConstant(node) || + checks.canSimplifyPolynomialTerms(node); +} +module.exports = removeUnnecessaryParens; +//# sourceMappingURL=removeUnnecessaryParens.js.map \ No newline at end of file diff --git a/lib/util/removeUnnecessaryParens.js.map b/lib/util/removeUnnecessaryParens.js.map new file mode 100644 index 00000000..74b8d5a7 --- /dev/null +++ b/lib/util/removeUnnecessaryParens.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeUnnecessaryParens.js","sourceRoot":"","sources":["removeUnnecessaryParens.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/util/removeUnnecessaryParens.ts b/lib/util/removeUnnecessaryParens.ts index f07d99d3..8420b4c7 100644 --- a/lib/util/removeUnnecessaryParens.ts +++ b/lib/util/removeUnnecessaryParens.ts @@ -1,6 +1,6 @@ -import checks = require('../checks'); -import LikeTermCollector = require('../simplifyExpression/collectAndCombineSearch/LikeTermCollector'); -import mathNode = require('../mathNode'); +import checks = require("../checks"); +import LikeTermCollector = require("../simplifyExpression/collectAndCombineSearch/LikeTermCollector"); +import mathNode = require("../mathNode"); // Removes any parenthesis around nodes that can't be resolved further. // Input must be a top level expression. @@ -42,7 +42,7 @@ function removeUnnecessaryParensSearch(node) { return node; } else { - throw Error('Unsupported node type: ' + node.type); + throw Error("Unsupported node type: " + node.type); } } @@ -54,7 +54,7 @@ function removeUnnecessaryParensInOperatorNode(node) { // Special case: if the node is an exponent node and the base // is an operator, we should keep the parentheses for the base. // e.g. (2x)^2 -> (2x)^2 instead of 2x^2 - if (node.op === '^' && mathNode.Type.isParenthesis(node.args[0])) { + if (node.op === "^" && mathNode.Type.isParenthesis(node.args[0])) { const base = node.args[0]; if (mathNode.Type.isOperator(base.content)) { base.content = removeUnnecessaryParensSearch(base.content); @@ -72,7 +72,7 @@ function removeUnnecessaryParensInOperatorNode(node) { // all they can be. If that expression is part of an addition or subtraction // operation, we can remove the parenthesis. // e.g. (x+4) + 12 -> x+4 + 12 - if (node.op === '+') { + if (node.op === "+") { node.args.forEach((child, i) => { if (mathNode.Type.isParenthesis(child) && !canCollectOrCombine(child.content)) { @@ -85,7 +85,7 @@ function removeUnnecessaryParensInOperatorNode(node) { // This is different from addition because when subtracting a group of terms //in parenthesis, we want to distribute the subtraction. // e.g. `(2 + x) - (1 + x)` => `2 + x - (1 + x)` not `2 + x - 1 + x` - else if (node.op === '-') { + else if (node.op === "-") { if (mathNode.Type.isParenthesis(node.args[0]) && !canCollectOrCombine(node.args[0].content)) { node.args[0] = node.args[0].content; @@ -146,7 +146,7 @@ function removeUnnecessaryParensInParenthesisNode(node) { else if (mathNode.Type.isOperator(node.content)) { node.content = removeUnnecessaryParensSearch(node.content); // exponent nodes don't need parens around them - if (node.content.op === '^') { + if (node.content.op === "^") { node = node.content; } } @@ -160,7 +160,7 @@ function removeUnnecessaryParensInParenthesisNode(node) { node.content = removeUnnecessaryParensSearch(node.content); } else { - throw Error('Unsupported node type: ' + node.content.type); + throw Error("Unsupported node type: " + node.content.type); } return node; diff --git a/package.json b/package.json index d54df282..d503fd33 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Step by step math solutions", "main": "index.js", "dependencies": { + "@types/mathjs": "0.0.34", "mathjs": "3.11.2" }, "engines": { diff --git a/test/Negative.test.ts b/test/Negative.test.ts index 4791709e..49700f13 100644 --- a/test/Negative.test.ts +++ b/test/Negative.test.ts @@ -1,8 +1,8 @@ -import math = require('mathjs'); -import flatten = require('../lib/util/flattenOperands'); -import print = require('../lib/util/print'); -import Negative = require('../lib/Negative'); -import TestUtil = require('./TestUtil'); +import math = require("mathjs"); +import flatten = require("../lib/util/flattenOperands"); +import print = require("../lib/util/print"); +import Negative = require("../lib/Negative"); +import TestUtil = require("./TestUtil"); function testNegate(exprString: any, outputStr: any); function testNegate(exprString, outputStr) { @@ -10,17 +10,17 @@ function testNegate(exprString, outputStr) { TestUtil.testFunctionOutput(print, inputStr, outputStr); } -describe('negate', () => { +describe("negate", () => { const tests = [ - ['1', '-1'], - ['-1', '1'], - ['1/2', '-1/2'], - ['(x+2)', '-(x + 2)'], - ['x', '-x'], - ['x^2', '-x^2'], - ['-y^3', 'y^3'], - ['2/3 x', '-2/3 x'], - ['-5/6 z', '5/6 z'], + ["1", "-1"], + ["-1", "1"], + ["1/2", "-1/2"], + ["(x+2)", "-(x + 2)"], + ["x", "-x"], + ["x^2", "-x^2"], + ["-y^3", "y^3"], + ["2/3 x", "-2/3 x"], + ["-5/6 z", "5/6 z"], ]; tests.forEach(t => testNegate(t[0], t[1])); }); diff --git a/test/Node/PolynomialTerm.test.ts b/test/Node/PolynomialTerm.test.ts index 624cb94c..14006755 100644 --- a/test/Node/PolynomialTerm.test.ts +++ b/test/Node/PolynomialTerm.test.ts @@ -1,24 +1,24 @@ -const PolynomialTerm = require('../../lib/node/PolynomialTerm'); -import TestUtil = require('../TestUtil'); +const polynomialTerm = require("../../lib/node/PolynomialTerm"); +import TestUtil = require("../TestUtil"); function testIsPolynomialTerm(exprStr: any, isTerm: any); function testIsPolynomialTerm(exprStr, isTerm) { - TestUtil.testBooleanFunction(PolynomialTerm.isPolynomialTerm, exprStr, isTerm); + TestUtil.testBooleanFunction(polynomialTerm.isPolynomialTerm, exprStr, isTerm); } -describe('classifies symbol terms correctly', () => { +describe("classifies symbol terms correctly", () => { const tests = [ - ['x', true], - ['x', true], - ['x^2', true], - ['y^55', true], - ['y^4/4', true], - ['5y/3', true], - ['x^y', true], - ['3', false], - ['2^5', false], - ['x*y^5', false], - ['-12y^5/-3', true], + ["x", true], + ["x", true], + ["x^2", true], + ["y^55", true], + ["y^4/4", true], + ["5y/3", true], + ["x^y", true], + ["3", false], + ["2^5", false], + ["x*y^5", false], + ["-12y^5/-3", true], ]; tests.forEach(t => testIsPolynomialTerm(t[0], t[1])); }); diff --git a/test/Node/Type.test.ts b/test/Node/Type.test.ts index c1ee8020..9f0f0946 100644 --- a/test/Node/Type.test.ts +++ b/test/Node/Type.test.ts @@ -1,63 +1,63 @@ -const assert = require('assert'); -import math = require('mathjs'); -const mathNode = require('../../lib/node'); +const assert = require("assert"); +import math = require("mathjs"); +const mathNode = require("../../lib/node"); const constNode = mathNode.Creator.constant; -describe('mathNode.Type works', () => { - it('(2+2) parenthesis', () => { +describe("mathNode.Type works", () => { + it("(2+2) parenthesis", () => { assert.deepEqual( - mathNode.Type.isParenthesis(math.parse('(2+2)')), + mathNode.Type.isParenthesis(math.parse("(2+2)")), true); }); - it('10 constant', () => { + it("10 constant", () => { assert.deepEqual( mathNode.Type.isConstant(math.parse(10)), true); }); - it('-2 constant', () => { + it("-2 constant", () => { assert.deepEqual( mathNode.Type.isConstant(constNode(-2)), true); }); - it('2+2 operator without operator param', () => { + it("2+2 operator without operator param", () => { assert.deepEqual( - mathNode.Type.isOperator(math.parse('2+2')), + mathNode.Type.isOperator(math.parse("2+2")), true); }); - it('2+2 operator with correct operator param', () => { + it("2+2 operator with correct operator param", () => { assert.deepEqual( - mathNode.Type.isOperator(math.parse('2+2'), '+'), + mathNode.Type.isOperator(math.parse("2+2"), "+"), true); }); - it('2+2 operator with incorrect operator param', () => { + it("2+2 operator with incorrect operator param", () => { assert.deepEqual( - mathNode.Type.isOperator(math.parse('2+2'), '-'), + mathNode.Type.isOperator(math.parse("2+2"), "-"), false); }); - it('-x not operator', () => { + it("-x not operator", () => { assert.deepEqual( - mathNode.Type.isOperator(math.parse('-x')), + mathNode.Type.isOperator(math.parse("-x")), false); }); - it('-x symbol', () => { + it("-x symbol", () => { assert.deepEqual( - mathNode.Type.isSymbol(math.parse('-x')), + mathNode.Type.isSymbol(math.parse("-x")), true); }); - it('y symbol', () => { + it("y symbol", () => { assert.deepEqual( - mathNode.Type.isSymbol(math.parse('y')), + mathNode.Type.isSymbol(math.parse("y")), true); }); - it('abs(5) is abs function', () => { + it("abs(5) is abs function", () => { assert.deepEqual( - mathNode.Type.isFunction(math.parse('abs(5)'), 'abs'), + mathNode.Type.isFunction(math.parse("abs(5)"), "abs"), true); }); - it('sqrt(5) is not abs function', () => { + it("sqrt(5) is not abs function", () => { assert.deepEqual( - mathNode.Type.isFunction(math.parse('sqrt(5)'), 'abs'), + mathNode.Type.isFunction(math.parse("sqrt(5)"), "abs"), false); }); // it('nthRoot(4) is an nthRoot function', function () { @@ -67,43 +67,43 @@ describe('mathNode.Type works', () => { // }); }); -describe('isConstantOrConstantFraction', () => { - it('2 true', () => { +describe("isConstantOrConstantFraction", () => { + it("2 true", () => { assert.deepEqual( - mathNode.Type.isConstantOrConstantFraction(math.parse('2')), + mathNode.Type.isConstantOrConstantFraction(math.parse("2")), true); }); - it('2/9 true', () => { + it("2/9 true", () => { assert.deepEqual( - mathNode.Type.isConstantOrConstantFraction(math.parse('4/9')), + mathNode.Type.isConstantOrConstantFraction(math.parse("4/9")), true); }); - it('x/2 false', () => { + it("x/2 false", () => { assert.deepEqual( - mathNode.Type.isConstantOrConstantFraction(math.parse('x/2')), + mathNode.Type.isConstantOrConstantFraction(math.parse("x/2")), false); }); }); -describe('isIntegerFraction', () => { - it('4/5 true', () => { +describe("isIntegerFraction", () => { + it("4/5 true", () => { assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse('4/5')), + mathNode.Type.isIntegerFraction(math.parse("4/5")), true); }); - it('4.3/5 false', () => { + it("4.3/5 false", () => { assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse('4.3/5')), + mathNode.Type.isIntegerFraction(math.parse("4.3/5")), false); }); - it('4x/5 false', () => { + it("4x/5 false", () => { assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse('4x/5')), + mathNode.Type.isIntegerFraction(math.parse("4x/5")), false); }); - it('5 false', () => { + it("5 false", () => { assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse('5')), + mathNode.Type.isIntegerFraction(math.parse("5")), false); }); }); diff --git a/test/TestUtil.ts b/test/TestUtil.ts index cfd715e9..cee19205 100644 --- a/test/TestUtil.ts +++ b/test/TestUtil.ts @@ -1,29 +1,29 @@ -const assert = require('assert'); -import math = require('mathjs'); -import flatten = require('../lib/util/flattenOperands'); -import print = require('../lib/util/print'); +const assert = require("assert"); +import math = require("mathjs"); +import flatten = require("../lib/util/flattenOperands"); +import print = require("../lib/util/print"); // TestUtil contains helper methods to share code across tests -const TestUtil = {}; +const testUtil = {}; // Tests a function that takes an input string and check its output -TestUtil.testFunctionOutput = (fn, input, output) => { - it(input + ' -> ' + output, () => { +testUtil.testFunctionOutput = (fn, input, output) => { + it(input + " -> " + output, () => { assert.deepEqual(fn(input),output); }); }; // tests a function that takes in a node and returns a boolean value -TestUtil.testBooleanFunction = (simplifier, exprString, expectedBooleanValue) => { - it(exprString + ' ' + expectedBooleanValue, () => { +testUtil.testBooleanFunction = (simplifier, exprString, expectedBooleanValue) => { + it(exprString + " " + expectedBooleanValue, () => { const inputNode = flatten(math.parse(exprString)); assert.equal(simplifier(inputNode),expectedBooleanValue); }); }; // Tests a simplification function -TestUtil.testSimplification = (simplifyingFunction, exprString, expectedOutputString) => { - it (exprString + ' -> ' + expectedOutputString, () => { +testUtil.testSimplification = (simplifyingFunction, exprString, expectedOutputString) => { + it (exprString + " -> " + expectedOutputString, () => { assert.deepEqual( print(simplifyingFunction(flatten(math.parse(exprString))).newNode), expectedOutputString); @@ -31,8 +31,8 @@ TestUtil.testSimplification = (simplifyingFunction, exprString, expectedOutputSt }; // Test the substeps in the expression -TestUtil.testSubsteps = (fn, exprString, outputList, outputStr) => { - it(exprString + ' -> ' + outputStr, () => { +testUtil.testSubsteps = (fn, exprString, outputList, outputStr) => { + it(exprString + " -> " + outputStr, () => { const status = fn(flatten(math.parse(exprString))); const substeps = status.substeps; @@ -49,4 +49,4 @@ TestUtil.testSubsteps = (fn, exprString, outputList, outputStr) => { } }); }; -export = TestUtil; +export = testUtil; diff --git a/test/canAddLikeTermPolynomialNodes.test.ts b/test/canAddLikeTermPolynomialNodes.test.ts index 7ca1d3a4..8ad3ae0a 100644 --- a/test/canAddLikeTermPolynomialNodes.test.ts +++ b/test/canAddLikeTermPolynomialNodes.test.ts @@ -1,16 +1,16 @@ -import canAddLikeTermPolynomialNodes = require('../lib/checks/canAddLikeTermPolynomialNodes'); -import TestUtil = require('./TestUtil'); +import canAddLikeTermPolynomialNodes = require("../lib/checks/canAddLikeTermPolynomialNodes"); +import TestUtil = require("./TestUtil"); function testCanBeAdded(expr: any, addable: any); function testCanBeAdded(expr, addable) { TestUtil.testBooleanFunction(canAddLikeTermPolynomialNodes, expr, addable); } -describe('can add like term polynomials', () => { +describe("can add like term polynomials", () => { const tests = [ - ['x^2 + x^2', true], - ['x + x', true], - ['x^3 + x', false], + ["x^2 + x^2", true], + ["x + x", true], + ["x^3 + x", false], ]; tests.forEach(t => testCanBeAdded(t[0], t[1])); }); diff --git a/test/canMultiplyLikeTermPolynomialNodes.test.ts b/test/canMultiplyLikeTermPolynomialNodes.test.ts index df30087b..9e1704fa 100644 --- a/test/canMultiplyLikeTermPolynomialNodes.test.ts +++ b/test/canMultiplyLikeTermPolynomialNodes.test.ts @@ -1,16 +1,16 @@ -import canMultiplyLikeTermPolynomialNodes = require('../lib/checks/canMultiplyLikeTermPolynomialNodes'); -import TestUtil = require('./TestUtil'); +import canMultiplyLikeTermPolynomialNodes = require("../lib/checks/canMultiplyLikeTermPolynomialNodes"); +import TestUtil = require("./TestUtil"); function testCanBeMultiplied(expr: any, multipliable: any); function testCanBeMultiplied(expr, multipliable) { TestUtil.testBooleanFunction(canMultiplyLikeTermPolynomialNodes, expr, multipliable); } -describe('can multiply like term polynomials', () => { +describe("can multiply like term polynomials", () => { const tests = [ - ['x^2 * x * x', true], - ['x^2 * 3x * x', false], - ['y * y^3', true] + ["x^2 * x * x", true], + ["x^2 * 3x * x", false], + ["y * y^3", true] ]; tests.forEach(t => testCanBeMultiplied(t[0], t[1])); }); diff --git a/test/canRearrangeCoefficient.test.ts b/test/canRearrangeCoefficient.test.ts index 192a64b4..275ca1e5 100644 --- a/test/canRearrangeCoefficient.test.ts +++ b/test/canRearrangeCoefficient.test.ts @@ -1,15 +1,15 @@ -import canRearrangeCoefficient = require('../lib/checks/canRearrangeCoefficient'); -import TestUtil = require('./TestUtil'); +import canRearrangeCoefficient = require("../lib/checks/canRearrangeCoefficient"); +import TestUtil = require("./TestUtil"); function testCanBeRearranged(expr: any, arrangeable: any); function testCanBeRearranged(expr, arrangeable) { TestUtil.testBooleanFunction(canRearrangeCoefficient, expr, arrangeable); } -describe('can rearrange coefficient', () => { +describe("can rearrange coefficient", () => { const tests = [ - ['x*2', true], - ['y^3 * 7', true] + ["x*2", true], + ["y^3 * 7", true] ]; tests.forEach(t => testCanBeRearranged(t[0], t[1])); }); diff --git a/test/checks/checks.test.ts b/test/checks/checks.test.ts index 2c79b483..b81a99de 100644 --- a/test/checks/checks.test.ts +++ b/test/checks/checks.test.ts @@ -1,31 +1,31 @@ -import checks = require('../../lib/checks'); -import TestUtil = require('../TestUtil'); +import checks = require("../../lib/checks"); +import TestUtil = require("../TestUtil"); function testCanCombine(exprStr: any, canCombine: any); function testCanCombine(exprStr, canCombine) { TestUtil.testBooleanFunction(checks.canSimplifyPolynomialTerms, exprStr, canCombine); } -describe('canSimplifyPolynomialTerms multiplication', () => { +describe("canSimplifyPolynomialTerms multiplication", () => { const tests = [ - ['x^2 * x * x', true], + ["x^2 * x * x", true], // false b/c coefficient - ['x^2 * 3x * x', false], - ['y * y^3', true], - ['5 * y^3', false], // just needs flattening - ['5/7 * x', false], // just needs flattening - ['5/7 * 9 * x', false], + ["x^2 * 3x * x", false], + ["y * y^3", true], + ["5 * y^3", false], // just needs flattening + ["5/7 * x", false], // just needs flattening + ["5/7 * 9 * x", false], ]; tests.forEach(t => testCanCombine(t[0], t[1])); }); -describe('canSimplifyPolynomialTerms addition', () => { +describe("canSimplifyPolynomialTerms addition", () => { const tests = [ - ['x + x', true], - ['4y^2 + 7y^2 + y^2', true], - ['4y^2 + 7y^2 + y^2 + y', false], - ['y', false], + ["x + x", true], + ["4y^2 + 7y^2 + y^2", true], + ["4y^2 + 7y^2 + y^2 + y", false], + ["y", false], ]; tests.forEach(t => testCanCombine(t[0], t[1])); }); diff --git a/test/checks/hasUnsupportedNodes.test.ts b/test/checks/hasUnsupportedNodes.test.ts index f07916b2..7641ad34 100644 --- a/test/checks/hasUnsupportedNodes.test.ts +++ b/test/checks/hasUnsupportedNodes.test.ts @@ -1,28 +1,28 @@ -const assert = require('assert'); -import math = require('mathjs'); -import checks = require('../../lib/checks'); -describe('arithmetic stepping', () => { - it('4 + sqrt(16) no support for sqrt', () => { +const assert = require("assert"); +import math = require("mathjs"); +import checks = require("../../lib/checks"); +describe("arithmetic stepping", () => { + it("4 + sqrt(16) no support for sqrt", () => { assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('4 + sqrt(4)')), + checks.hasUnsupportedNodes(math.parse("4 + sqrt(4)")), true); }); - it('x = 5 no support for assignment', () => { + it("x = 5 no support for assignment", () => { assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('x = 5')), + checks.hasUnsupportedNodes(math.parse("x = 5")), true); }); - it('x + (-5)^2 - 8*y/2 is fine', () => { + it("x + (-5)^2 - 8*y/2 is fine", () => { assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('x + (-5)^2 - 8*y/2')), + checks.hasUnsupportedNodes(math.parse("x + (-5)^2 - 8*y/2")), false); }); - it('nthRoot() with no args has no support', () => { + it("nthRoot() with no args has no support", () => { assert.deepEqual( - checks.hasUnsupportedNodes(math.parse('nthRoot()')), + checks.hasUnsupportedNodes(math.parse("nthRoot()")), true); }); }); diff --git a/test/checks/isQuadratic.test.ts b/test/checks/isQuadratic.test.ts index 9297b537..91bc0f93 100644 --- a/test/checks/isQuadratic.test.ts +++ b/test/checks/isQuadratic.test.ts @@ -1,29 +1,29 @@ -import checks = require('../../lib/checks'); -import TestUtil = require('../TestUtil'); +import checks = require("../../lib/checks"); +import TestUtil = require("../TestUtil"); function testIsQuadratic(input: any, output: any); function testIsQuadratic(input, output) { TestUtil.testBooleanFunction(checks.isQuadratic, input, output); } -describe('isQuadratic', () => { +describe("isQuadratic", () => { const tests = [ - ['2 + 2', false], - ['x', false], - ['x^2 - 4', true], - ['x^2 + 2x + 1', true], - ['x^2 - 2x + 1', true], - ['x^2 + 3x + 2', true], - ['x^2 - 3x + 2', true], - ['x^2 + x - 2', true], - ['x^2 + x', true], - ['x^2 + 4', true], - ['x^2 + 4x + 1', true], - ['x^2', false], - ['x^3 + x^2 + x + 1', false], - ['x^2 + 4 + 2^x', false], - ['x^2 + 4 + 2y', false], - ['y^2 + 4 + 2x', false], + ["2 + 2", false], + ["x", false], + ["x^2 - 4", true], + ["x^2 + 2x + 1", true], + ["x^2 - 2x + 1", true], + ["x^2 + 3x + 2", true], + ["x^2 - 3x + 2", true], + ["x^2 + x - 2", true], + ["x^2 + x", true], + ["x^2 + 4", true], + ["x^2 + 4x + 1", true], + ["x^2", false], + ["x^3 + x^2 + x + 1", false], + ["x^2 + 4 + 2^x", false], + ["x^2 + 4 + 2y", false], + ["y^2 + 4 + 2x", false], ]; tests.forEach(t => testIsQuadratic(t[0], t[1])); }); diff --git a/test/checks/resolvesToConstant.test.ts b/test/checks/resolvesToConstant.test.ts index e09d66c9..1e54c751 100644 --- a/test/checks/resolvesToConstant.test.ts +++ b/test/checks/resolvesToConstant.test.ts @@ -1,18 +1,18 @@ -import checks = require('../../lib/checks'); -import TestUtil = require('../TestUtil'); +import checks = require("../../lib/checks"); +import TestUtil = require("../TestUtil"); function testResolvesToConstant(exprString: any, resolves: any); function testResolvesToConstant(exprString, resolves) { TestUtil.testBooleanFunction(checks.resolvesToConstant, exprString, resolves); } -describe('resolvesToConstant', () => { +describe("resolvesToConstant", () => { const tests = [ - ['(2+2)', true], - ['10', true], - ['((2^2 + 4)) * 7 / 8', true], - ['2 * 3^x', false], - ['-(2) * -3', true], + ["(2+2)", true], + ["10", true], + ["((2^2 + 4)) * 7 / 8", true], + ["2 * 3^x", false], + ["-(2) * -3", true], ]; tests.forEach(t => testResolvesToConstant(t[0], t[1])); }); diff --git a/test/equation.test.ts b/test/equation.test.ts index da753250..eb517807 100644 --- a/test/equation.test.ts +++ b/test/equation.test.ts @@ -1,6 +1,6 @@ -const assert = require('assert'); -import math = require('mathjs'); -import Equation = require('../lib/equation/Equation'); +const assert = require("assert"); +import math = require("mathjs"); +import Equation = require("../lib/equation/Equation"); function constructAndPrintEquation(left: any, right: any, comp: any); function constructAndPrintEquation(left, right, comp) { @@ -19,11 +19,11 @@ function testEquationConstructor(left, right, comp, output) { }); } -describe('Equation constructor', () => { +describe("Equation constructor", () => { const tests = [ - ['2*x^2 + x', '4', '=', '2x^2 + x = 4'], - ['x^2 + 2*x + 2', '0', '>=', 'x^2 + 2x + 2 >= 0'], - ['2*x - 1', '0', '<=', '2x - 1 <= 0'] + ["2*x^2 + x", "4", "=", "2x^2 + x = 4"], + ["x^2 + 2*x + 2", "0", ">=", "x^2 + 2x + 2 >= 0"], + ["2*x - 1", "0", "<=", "2x - 1 <= 0"] ]; tests.forEach(t => testEquationConstructor(t[0], t[1], t[2], t[3])); }); diff --git a/test/factor/ConstantFactors.test.ts b/test/factor/ConstantFactors.test.ts index 48f12615..adb5dcf5 100644 --- a/test/factor/ConstantFactors.test.ts +++ b/test/factor/ConstantFactors.test.ts @@ -1,12 +1,12 @@ -import ConstantFactors = require('../../lib/factor/ConstantFactors'); -import TestUtil = require('../TestUtil'); +import ConstantFactors = require("../../lib/factor/ConstantFactors"); +import TestUtil = require("../TestUtil"); function testPrimeFactors(input: any, output: any); function testPrimeFactors(input, output) { TestUtil.testFunctionOutput(ConstantFactors.getPrimeFactors, input, output); } -describe('prime factors', () => { +describe("prime factors", () => { const tests = [ [1, [1]], [-1, [-1, 1]], @@ -28,7 +28,7 @@ function testFactorPairs(input, output) { TestUtil.testFunctionOutput(ConstantFactors.getFactorPairs, input, output); } -describe('factor pairs', () => { +describe("factor pairs", () => { const tests = [ [1, [[-1, -1], [1, 1]]], [5, [[-1, -5], [1, 5]]], diff --git a/test/factor/factorQuadratic.test.ts b/test/factor/factorQuadratic.test.ts index 311d2738..19ca4b1e 100644 --- a/test/factor/factorQuadratic.test.ts +++ b/test/factor/factorQuadratic.test.ts @@ -1,35 +1,35 @@ -import factorQuadratic = require('../../lib/factor/factorQuadratic'); -import TestUtil = require('../TestUtil'); +import factorQuadratic = require("../../lib/factor/factorQuadratic"); +import TestUtil = require("../TestUtil"); function testFactorQuadratic(input: any, output: any); function testFactorQuadratic(input, output) { TestUtil.testSimplification(factorQuadratic, input, output); } -describe('factorQuadratic', () => { +describe("factorQuadratic", () => { const tests = [ - ['x^2', 'x^2'], - ['x^2 + x^2', 'x^2 + x^2'], - ['x^2 + 2 - 3', 'x^2 + 2 - 3'], - ['x^2 + 2y + 2x + 3', 'x^2 + 2y + 2x + 3'], - ['x^2 + 2x', 'x * (x + 2)'], - ['-x^2 - 2x', '-x * (x + 2)'], - ['x^2 - 3x', 'x * (x - 3)'], - ['2x^2 + 2x', '2x * (x + 1)'], - ['x^2 - 4', '(x + 2) * (x - 2)'], - ['x^2 + 4', 'x^2 + 4'], - ['x^2 + 2x + 1', '(x + 1)^2'], - ['x^2 - 2x + 1', '(x - 1)^2'], - ['x^2 + 3x + 2', '(x + 1) * (x + 2)'], - ['x^2 - 3x + 2', '(x - 1) * (x - 2)'], - ['x^2 + x - 2', '(x - 1) * (x + 2)'], - ['x^2 + 4x + 1', 'x^2 + 4x + 1'], - ['x^2 - 3x + 1', 'x^2 - 3x + 1'], - ['x^2 + 4 + 2^x', 'x^2 + 4 + 2^x'], - ['-x^2 - 2x - 1', '-(x + 1)^2'], - ['-x^2 - 3x - 2', '-(x + 1) * (x + 2)'], - ['-x^2 + 1', '-(x + 1) * (x - 1)'], - ['-x^2 - 1', '-x^2 - 1'], + ["x^2", "x^2"], + ["x^2 + x^2", "x^2 + x^2"], + ["x^2 + 2 - 3", "x^2 + 2 - 3"], + ["x^2 + 2y + 2x + 3", "x^2 + 2y + 2x + 3"], + ["x^2 + 2x", "x * (x + 2)"], + ["-x^2 - 2x", "-x * (x + 2)"], + ["x^2 - 3x", "x * (x - 3)"], + ["2x^2 + 2x", "2x * (x + 1)"], + ["x^2 - 4", "(x + 2) * (x - 2)"], + ["x^2 + 4", "x^2 + 4"], + ["x^2 + 2x + 1", "(x + 1)^2"], + ["x^2 - 2x + 1", "(x - 1)^2"], + ["x^2 + 3x + 2", "(x + 1) * (x + 2)"], + ["x^2 - 3x + 2", "(x - 1) * (x - 2)"], + ["x^2 + x - 2", "(x - 1) * (x + 2)"], + ["x^2 + 4x + 1", "x^2 + 4x + 1"], + ["x^2 - 3x + 1", "x^2 - 3x + 1"], + ["x^2 + 4 + 2^x", "x^2 + 4 + 2^x"], + ["-x^2 - 2x - 1", "-(x + 1)^2"], + ["-x^2 - 3x - 2", "-(x + 1) * (x + 2)"], + ["-x^2 + 1", "-(x + 1) * (x - 1)"], + ["-x^2 - 1", "-x^2 - 1"], ]; tests.forEach(t => testFactorQuadratic(t[0], t[1])); }); diff --git a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts index b09df7e7..487dd7fb 100644 --- a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts +++ b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts @@ -1,16 +1,16 @@ -import arithmeticSearch = require('../../../lib/simplifyExpression/arithmeticSearch'); -import TestUtil = require('../../TestUtil'); +import arithmeticSearch = require("../../../lib/simplifyExpression/arithmeticSearch"); +import TestUtil = require("../../TestUtil"); function testArithmeticSearch(exprStr: any, outputStr: any); function testArithmeticSearch(exprStr, outputStr) { TestUtil.testSimplification(arithmeticSearch, exprStr, outputStr); } -describe('evaluate arithmeticSearch', () => { +describe("evaluate arithmeticSearch", () => { const tests = [ - ['2+2', '4'], - ['2*3*5', '30'], - ['9/4', '9/4'], // does not divide + ["2+2", "4"], + ["2*3*5", "30"], + ["9/4", "9/4"], // does not divide ]; tests.forEach(t => testArithmeticSearch(t[0], t[1])); }); diff --git a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts index 649258f8..19632507 100644 --- a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts +++ b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts @@ -1,9 +1,9 @@ -import rearrangeCoefficient = require('../../../lib/simplifyExpression/basicsSearch/rearrangeCoefficient'); -import testSimplify = require('./testSimplify'); -describe('rearrangeCoefficient', () => { +import rearrangeCoefficient = require("../../../lib/simplifyExpression/basicsSearch/rearrangeCoefficient"); +import testSimplify = require("./testSimplify"); +describe("rearrangeCoefficient", () => { const tests = [ - ['2 * x^2', '2x^2'], - ['y^3 * 5', '5y^3'], + ["2 * x^2", "2x^2"], + ["y^3 * 5", "5y^3"], ]; tests.forEach(t => testSimplify(t[0], t[1], rearrangeCoefficient)); }); diff --git a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts index 2e6e92f6..78beb915 100644 --- a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts +++ b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts @@ -1,5 +1,5 @@ -import reduceExponentByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceExponentByZero'); -import testSimplify = require('./testSimplify'); -describe('reduceExponentByZero', () => { - testSimplify('(x+3)^0', '1', reduceExponentByZero); +import reduceExponentByZero = require("../../../lib/simplifyExpression/basicsSearch/reduceExponentByZero"); +import testSimplify = require("./testSimplify"); +describe("reduceExponentByZero", () => { + testSimplify("(x+3)^0", "1", reduceExponentByZero); }); diff --git a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts index b959246b..2c2f3a28 100644 --- a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts +++ b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts @@ -1,9 +1,9 @@ -import reduceMultiplicationByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero'); -import testSimplify = require('./testSimplify'); -describe('reduce multiplication by 0', () => { +import reduceMultiplicationByZero = require("../../../lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero"); +import testSimplify = require("./testSimplify"); +describe("reduce multiplication by 0", () => { const tests = [ - ['0x', '0'], - ['2*0*z^2','0'], + ["0x", "0"], + ["2*0*z^2","0"], ]; tests.forEach(t => testSimplify(t[0], t[1], reduceMultiplicationByZero)); }); diff --git a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts index 9990c284..ee9f1baf 100644 --- a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts +++ b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts @@ -1,9 +1,9 @@ -import reduceZeroDividedByAnything = require('../../../lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything'); -import testSimplify = require('./testSimplify'); -describe('simplify basics', () => { +import reduceZeroDividedByAnything = require("../../../lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything"); +import testSimplify = require("./testSimplify"); +describe("simplify basics", () => { const tests = [ - ['0/5', '0'], - ['0/(x+6+7+x^2+2^y)', '0'], + ["0/5", "0"], + ["0/(x+6+7+x^2+2^y)", "0"], ]; tests.forEach(t => testSimplify(t[0], t[1], reduceZeroDividedByAnything)); }); diff --git a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts index 8f5d637b..cd8416cc 100644 --- a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts +++ b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts @@ -1,10 +1,10 @@ -import removeAdditionOfZero = require('../../../lib/simplifyExpression/basicsSearch/removeAdditionOfZero'); -import testSimplify = require('./testSimplify'); -describe('removeAdditionOfZero', () => { +import removeAdditionOfZero = require("../../../lib/simplifyExpression/basicsSearch/removeAdditionOfZero"); +import testSimplify = require("./testSimplify"); +describe("removeAdditionOfZero", () => { var tests = [ - ['2+0+x', '2 + x'], - ['2+x+0', '2 + x'], - ['0+2+x', '2 + x'] + ["2+0+x", "2 + x"], + ["2+x+0", "2 + x"], + ["0+2+x", "2 + x"] ]; tests.forEach(t => testSimplify(t[0], t[1], removeAdditionOfZero)); }); diff --git a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts index 0b53539f..e86cf27e 100644 --- a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts +++ b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts @@ -1,5 +1,5 @@ -import removeDivisionByOne = require('../../../lib/simplifyExpression/basicsSearch/removeDivisionByOne'); -import testSimplify = require('./testSimplify'); -describe('removeDivisionByOne', () => { - testSimplify('x/1', 'x', removeDivisionByOne); +import removeDivisionByOne = require("../../../lib/simplifyExpression/basicsSearch/removeDivisionByOne"); +import testSimplify = require("./testSimplify"); +describe("removeDivisionByOne", () => { + testSimplify("x/1", "x", removeDivisionByOne); }); diff --git a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts index 6ce29e8e..09fed31a 100644 --- a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts +++ b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts @@ -1,10 +1,10 @@ -import removeExponentBaseOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentBaseOne'); -import testSimplify = require('./testSimplify'); -describe('removeExponentBaseOne', () => { +import removeExponentBaseOne = require("../../../lib/simplifyExpression/basicsSearch/removeExponentBaseOne"); +import testSimplify = require("./testSimplify"); +describe("removeExponentBaseOne", () => { const tests = [ - ['1^3', '1'], - ['1^x', '1^x'], - ['1^(2 + 3 + 5/4 + 7 - 6/7)', '1'] + ["1^3", "1"], + ["1^x", "1^x"], + ["1^(2 + 3 + 5/4 + 7 - 6/7)", "1"] ]; tests.forEach(t => testSimplify(t[0], t[1], removeExponentBaseOne)); }); diff --git a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts index 83457192..8680afed 100644 --- a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts +++ b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts @@ -1,5 +1,5 @@ -import removeExponentByOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentByOne'); -import testSimplify = require('./testSimplify'); -describe('removeExponentByOne', () => { - testSimplify('x^1', 'x', removeExponentByOne); +import removeExponentByOne = require("../../../lib/simplifyExpression/basicsSearch/removeExponentByOne"); +import testSimplify = require("./testSimplify"); +describe("removeExponentByOne", () => { + testSimplify("x^1", "x", removeExponentByOne); }); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts index 2d6c5e52..0e0e5fff 100644 --- a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts +++ b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts @@ -1,10 +1,10 @@ -import removeMultiplicationByNegativeOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne'); -import testSimplify = require('./testSimplify'); -describe('removeMultiplicationByNegativeOne', () => { +import removeMultiplicationByNegativeOne = require("../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne"); +import testSimplify = require("./testSimplify"); +describe("removeMultiplicationByNegativeOne", () => { const tests = [ - ['-1*x', '-x'], - ['x^2*-1', '-x^2'], - ['2x*2*-1', '2x * 2 * -1'], // does not remove multiplication by -1 + ["-1*x", "-x"], + ["x^2*-1", "-x^2"], + ["2x*2*-1", "2x * 2 * -1"], // does not remove multiplication by -1 ]; tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByNegativeOne)); }); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts index f868f402..8f1e38a3 100644 --- a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts +++ b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts @@ -1,11 +1,11 @@ -import removeMultiplicationByOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByOne'); -import testSimplify = require('./testSimplify'); -describe('removeMultiplicationByOne', () => { +import removeMultiplicationByOne = require("../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByOne"); +import testSimplify = require("./testSimplify"); +describe("removeMultiplicationByOne", () => { const tests = [ - ['x*1', 'x'], - ['1x', 'x'], - ['1*z^2', 'z^2'], - ['2*1*z^2', '2 * 1z^2'], + ["x*1", "x"], + ["1x", "x"], + ["1*z^2", "z^2"], + ["2*1*z^2", "2 * 1z^2"], ]; tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByOne)); }); diff --git a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts index 4fddcfc3..5e2da1b5 100644 --- a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts +++ b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts @@ -1,9 +1,9 @@ -import simplifyDoubleUnaryMinus = require('../../../lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus'); -import testSimplify = require('./testSimplify'); -describe('simplifyDoubleUnaryMinus', () => { +import simplifyDoubleUnaryMinus = require("../../../lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus"); +import testSimplify = require("./testSimplify"); +describe("simplifyDoubleUnaryMinus", () => { var tests = [ - ['--5', '5'], - ['--x', 'x'] + ["--5", "5"], + ["--x", "x"] ]; tests.forEach(t => testSimplify(t[0], t[1], simplifyDoubleUnaryMinus)); }); diff --git a/test/simplifyExpression/basicsSearch/testSimplify.ts b/test/simplifyExpression/basicsSearch/testSimplify.ts index 7669b340..efee4364 100644 --- a/test/simplifyExpression/basicsSearch/testSimplify.ts +++ b/test/simplifyExpression/basicsSearch/testSimplify.ts @@ -1,11 +1,11 @@ -const assert = require('assert'); -import math = require('mathjs'); -import flatten = require('../../../lib/util/flattenOperands'); -import print = require('../../../lib/util/print'); +const assert = require("assert"); +import math = require("mathjs"); +import flatten = require("../../../lib/util/flattenOperands"); +import print = require("../../../lib/util/print"); function testSimplify(exprStr: any, outputStr: any, simplifyOperation: any); function testSimplify(exprStr, outputStr, simplifyOperation) { - it(exprStr + ' -> ' + outputStr, () => { + it(exprStr + " -> " + outputStr, () => { const inputNode = flatten(math.parse(exprStr)); const newNode = simplifyOperation(inputNode).newNode; assert.equal( diff --git a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts index bb9f8b52..643dab7f 100644 --- a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts +++ b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts @@ -1,16 +1,16 @@ -import breakUpNumeratorSearch = require('../../../lib/simplifyExpression/breakUpNumeratorSearch'); -import TestUtil = require('../../TestUtil'); +import breakUpNumeratorSearch = require("../../../lib/simplifyExpression/breakUpNumeratorSearch"); +import TestUtil = require("../../TestUtil"); function testBreakUpNumeratorSearch(exprStr: any, outputStr: any); function testBreakUpNumeratorSearch(exprStr, outputStr) { TestUtil.testSimplification(breakUpNumeratorSearch, exprStr, outputStr); } -describe('breakUpNumerator', () => { +describe("breakUpNumerator", () => { const tests = [ - ['(x+3+y)/3', '(x / 3 + 3/3 + y / 3)'], - ['(2+x)/4', '(2/4 + x / 4)'], - ['2(x+3)/3', '2 * (x / 3 + 3/3)'], + ["(x+3+y)/3", "(x / 3 + 3/3 + y / 3)"], + ["(2+x)/4", "(2/4 + x / 4)"], + ["2(x+3)/3", "2 * (x / 3 + 3/3)"], ]; tests.forEach(t => testBreakUpNumeratorSearch(t[0], t[1])); }); diff --git a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts index 02bc9bd2..2ed30322 100644 --- a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts +++ b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts @@ -1,10 +1,10 @@ -const assert = require('assert'); -import math = require('mathjs'); -import flatten = require('../../../lib/util/flattenOperands'); -import print = require('../../../lib/util/print'); -import LikeTermCollector = require('../../../lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector'); +const assert = require("assert"); +import math = require("mathjs"); +import flatten = require("../../../lib/util/flattenOperands"); +import print = require("../../../lib/util/print"); +import LikeTermCollector = require("../../../lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector"); -function testCollectLikeTerms(exprStr, outputStr, explanation='', debug=false) { +function testCollectLikeTerms(exprStr, outputStr, explanation="", debug=false) { let description = `${exprStr} -> ${outputStr}`; if (explanation) { @@ -38,59 +38,59 @@ function testCanCollectLikeTerms(exprStr, canCollect, explanation) { }); } -describe('can collect like terms for addition', () => { +describe("can collect like terms for addition", () => { const tests = [ - ['2+2', false, 'because only one type'], - ['x^2+x^2', false, 'because only one type'], - ['x+2', false, 'because all types have only one'], - ['(x+2+x)', false, 'because in parenthesis, need to be collected first'], - ['x+2+x', true], - ['x^2 + 5 + x + x^2', true], + ["2+2", false, "because only one type"], + ["x^2+x^2", false, "because only one type"], + ["x+2", false, "because all types have only one"], + ["(x+2+x)", false, "because in parenthesis, need to be collected first"], + ["x+2+x", true], + ["x^2 + 5 + x + x^2", true], ]; tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); }); -describe('can collect like terms for multiplication', () => { +describe("can collect like terms for multiplication", () => { const tests = [ - ['2*2', false, 'because only one type'], - ['x^2 * 2x^2', true], - ['x * 2', false, 'because all types have only one'], - ['((2x^2)) * y * x * y^3', true], + ["2*2", false, "because only one type"], + ["x^2 * 2x^2", true], + ["x * 2", false, "because all types have only one"], + ["((2x^2)) * y * x * y^3", true], ]; tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); }); -describe('basic addition collect like terms, no exponents or coefficients', () => { +describe("basic addition collect like terms, no exponents or coefficients", () => { const tests = [ - ['2+x+7', 'x + (2 + 7)'], - ['x + 4 + x + 5', '(x + x) + (4 + 5)'], - ['x + 4 + y', 'x + 4 + y'], - ['x + 4 + x + 4/9 + y + 5/7', '(x + x) + y + 4 + (4/9 + 5/7)'], - ['x + 4 + x + 2^x + 5', '(x + x) + (4 + 5) + 2^x', - 'because 2^x is an \'other\''], - ['z + 2*(y + x) + 4 + z', '(z + z) + 4 + 2 * (y + x)', - '2*(y + x) is an \'other\' cause it has parens'], + ["2+x+7", "x + (2 + 7)"], + ["x + 4 + x + 5", "(x + x) + (4 + 5)"], + ["x + 4 + y", "x + 4 + y"], + ["x + 4 + x + 4/9 + y + 5/7", "(x + x) + y + 4 + (4/9 + 5/7)"], + ["x + 4 + x + 2^x + 5", "(x + x) + (4 + 5) + 2^x", + "because 2^x is an 'other'"], + ["z + 2*(y + x) + 4 + z", "(z + z) + 4 + 2 * (y + x)", + "2*(y + x) is an 'other' cause it has parens"], ]; tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); }); -describe('collect like terms with exponents and coefficients', () => { +describe("collect like terms with exponents and coefficients", () => { const tests = [ - ['x^2 + x + x^2 + x', '(x^2 + x^2) + (x + x)'], - ['y^2 + 5 + y^2 + 5', '(y^2 + y^2) + (5 + 5)'], - ['y + 5 + z^2', 'y + 5 + z^2'], - ['2x^2 + x + x^2 + 3x', '(2x^2 + x^2) + (x + 3x)'], + ["x^2 + x + x^2 + x", "(x^2 + x^2) + (x + x)"], + ["y^2 + 5 + y^2 + 5", "(y^2 + y^2) + (5 + 5)"], + ["y + 5 + z^2", "y + 5 + z^2"], + ["2x^2 + x + x^2 + 3x", "(2x^2 + x^2) + (x + 3x)"], ]; tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); }); -describe('collect like terms for multiplication', () => { +describe("collect like terms for multiplication", () => { const tests = [ - ['2x^2 * y * x * y^3', '2 * (x^2 * x) * (y * y^3)'], - ['y^2 * 5 * y * 9', '(5 * 9) * (y^2 * y)'], - ['5y^2 * -4y * 9', '(5 * -4 * 9) * (y^2 * y)'], - ['5y^2 * -y * 9', '(5 * -1 * 9) * (y^2 * y)'], - ['y * 5 * (2+x) * y^2 * 1/3', '(5 * 1/3) * (y * y^2) * (2 + x)'], + ["2x^2 * y * x * y^3", "2 * (x^2 * x) * (y * y^3)"], + ["y^2 * 5 * y * 9", "(5 * 9) * (y^2 * y)"], + ["5y^2 * -4y * 9", "(5 * -4 * 9) * (y^2 * y)"], + ["5y^2 * -y * 9", "(5 * -1 * 9) * (y^2 * y)"], + ["y * 5 * (2+x) * y^2 * 1/3", "(5 * 1/3) * (y * y^2) * (2 + x)"], ]; tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); }); diff --git a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts index 7ebd2402..626042fb 100644 --- a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts +++ b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts @@ -1,5 +1,5 @@ -import collectAndCombineSearch = require('../../../lib/simplifyExpression/collectAndCombineSearch'); -import TestUtil = require('../../TestUtil'); +import collectAndCombineSearch = require("../../../lib/simplifyExpression/collectAndCombineSearch"); +import TestUtil = require("../../TestUtil"); function testCollectAndCombineSubsteps(exprString: any, outputList: any, outputStr: any); function testCollectAndCombineSubsteps(exprString, outputList, outputStr) { @@ -11,53 +11,53 @@ function testSimpleCollectAndCombineSearch(exprString, outputStr) { TestUtil.testSimplification(collectAndCombineSearch, exprString, outputStr); } -describe('combinePolynomialTerms multiplication', () => { +describe("combinePolynomialTerms multiplication", () => { const tests = [ - ['x^2 * x * x', - ['x^2 * x^1 * x^1', - 'x^(2 + 1 + 1)', - 'x^4'], + ["x^2 * x * x", + ["x^2 * x^1 * x^1", + "x^(2 + 1 + 1)", + "x^4"], ], - ['y * y^3', - ['y^1 * y^3', - 'y^(1 + 3)', - 'y^4'], + ["y * y^3", + ["y^1 * y^3", + "y^(1 + 3)", + "y^4"], ], - ['2x * x^2 * 5x', - ['(2 * 5) * (x * x^2 * x)', - '10 * (x * x^2 * x)', - '10x^4'], - '10x^4' + ["2x * x^2 * 5x", + ["(2 * 5) * (x * x^2 * x)", + "10 * (x * x^2 * x)", + "10x^4"], + "10x^4" ], ]; tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1], t[2])); }); -describe('combinePolynomialTerms addition', () => { +describe("combinePolynomialTerms addition", () => { const tests = [ - ['x+x', - ['1x + 1x', - '(1 + 1) * x', - '2x'] + ["x+x", + ["1x + 1x", + "(1 + 1) * x", + "2x"] ], - ['4y^2 + 7y^2 + y^2', - ['4y^2 + 7y^2 + 1y^2', - '(4 + 7 + 1) * y^2', - '12y^2'] + ["4y^2 + 7y^2 + y^2", + ["4y^2 + 7y^2 + 1y^2", + "(4 + 7 + 1) * y^2", + "12y^2"] ], - ['2x + 4x + y', - ['(2x + 4x) + y', - '6x + y'], - '6x + y' + ["2x + 4x + y", + ["(2x + 4x) + y", + "6x + y"], + "6x + y" ], ]; tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1])); }); -describe('collectAndCombineSearch with no substeps', () => { +describe("collectAndCombineSearch with no substeps", () => { const tests = [ - ['2x + 4x + x', '7x'], - ['x * x^2 * x', 'x^4'] + ["2x + 4x + x", "7x"], + ["x * x^2 * x", "x^4"] ]; tests.forEach(t => testSimpleCollectAndCombineSearch(t[0], t[1])); }); diff --git a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts index 9b24eabc..43505736 100644 --- a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts +++ b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts @@ -1,5 +1,5 @@ -import evaluateConstantSum = require('../../../lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum'); -import TestUtil = require('../../TestUtil'); +import evaluateConstantSum = require("../../../lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum"); +import TestUtil = require("../../TestUtil"); function testEvaluateConstantSum(exprString: any, outputList: any); function testEvaluateConstantSum(exprString, outputList) { @@ -7,26 +7,26 @@ function testEvaluateConstantSum(exprString, outputList) { TestUtil.testSubsteps(evaluateConstantSum, exprString, outputList, lastString); } -describe('evaluateConstantSum', () => { +describe("evaluateConstantSum", () => { const tests = [ - ['4/10 + 3/5', - ['4/10 + (3 * 2) / (5 * 2)', - '4/10 + (3 * 2) / 10', - '4/10 + 6/10', - '(4 + 6) / 10', - '10/10', - '1'] + ["4/10 + 3/5", + ["4/10 + (3 * 2) / (5 * 2)", + "4/10 + (3 * 2) / 10", + "4/10 + 6/10", + "(4 + 6) / 10", + "10/10", + "1"] ], - ['4/5 + 3/5 + 2', - ['2 + (4/5 + 3/5)', - '2 + 7/5', - '17/5'] + ["4/5 + 3/5 + 2", + ["2 + (4/5 + 3/5)", + "2 + 7/5", + "17/5"] ], - ['9 + 4/5 + 1/5 + 2', - ['(9 + 2) + (4/5 + 1/5)', - '11 + (4/5 + 1/5)', - '11 + 1', - '12'] + ["9 + 4/5 + 1/5 + 2", + ["(9 + 2) + (4/5 + 1/5)", + "11 + (4/5 + 1/5)", + "11 + 1", + "12"] ], ]; tests.forEach(t => testEvaluateConstantSum(t[0], t[1])); diff --git a/test/simplifyExpression/distributeSearch/distributeSearch.test.ts b/test/simplifyExpression/distributeSearch/distributeSearch.test.ts index 5f9f1190..20d9e65c 100644 --- a/test/simplifyExpression/distributeSearch/distributeSearch.test.ts +++ b/test/simplifyExpression/distributeSearch/distributeSearch.test.ts @@ -1,25 +1,25 @@ -import distributeSearch = require('../../../lib/simplifyExpression/distributeSearch'); -import TestUtil = require('../../TestUtil'); +import distributeSearch = require("../../../lib/simplifyExpression/distributeSearch"); +import TestUtil = require("../../TestUtil"); function testDistribute(exprStr: any, outputStr: any); function testDistribute(exprStr, outputStr) { TestUtil.testSimplification(distributeSearch, exprStr, outputStr); } -describe('distribute - into paren with addition', () => { +describe("distribute - into paren with addition", () => { const tests = [ - ['-(x+3)', '(-x - 3)'], - ['-(x - 3)', '(-x + 3)'], - ['-(-x^2 + 3y^6)' , '(x^2 - 3y^6)'], + ["-(x+3)", "(-x - 3)"], + ["-(x - 3)", "(-x + 3)"], + ["-(-x^2 + 3y^6)" , "(x^2 - 3y^6)"], ]; tests.forEach(t => testDistribute(t[0], t[1])); }); -describe('distribute - into paren with multiplication/division', () => { +describe("distribute - into paren with multiplication/division", () => { const tests = [ - ['-(x*3)', '(-x * 3)'], - ['-(-x * 3)', '(x * 3)'], - ['-(-x^2 * 3y^6)', '(x^2 * 3y^6)'], + ["-(x*3)", "(-x * 3)"], + ["-(-x * 3)", "(x * 3)"], + ["-(-x^2 * 3y^6)", "(x^2 * 3y^6)"], ]; tests.forEach(t => testDistribute(t[0], t[1])); }); @@ -30,56 +30,56 @@ function testDistributeSteps(exprString, outputList) { TestUtil.testSubsteps(distributeSearch, exprString, outputList, lastString); } -describe('distribute', () => { +describe("distribute", () => { const tests = [ - ['x*(x+2+y)', - ['(x * x + x * 2 + x * y)', - '(x^2 + 2x + x * y)'] + ["x*(x+2+y)", + ["(x * x + x * 2 + x * y)", + "(x^2 + 2x + x * y)"] ], - ['(x+2+y)*x*7', - ['(x * x + 2x + y * x) * 7', - '(x^2 + 2x + y * x) * 7'] + ["(x+2+y)*x*7", + ["(x * x + 2x + y * x) * 7", + "(x^2 + 2x + y * x) * 7"] ], - ['(5+x)*(x+3)', - ['(5 * (x + 3) + x * (x + 3))', - '((5x + 15) + (x^2 + 3x))'] + ["(5+x)*(x+3)", + ["(5 * (x + 3) + x * (x + 3))", + "((5x + 15) + (x^2 + 3x))"] ], - ['-2x^2 * (3x - 4)', - ['(-2x^2 * 3x - 2x^2 * -4)', - '(-6x^3 + 8x^2)'] + ["-2x^2 * (3x - 4)", + ["(-2x^2 * 3x - 2x^2 * -4)", + "(-6x^3 + 8x^2)"] ], ]; tests.forEach(t => testDistributeSteps(t[0], t[1])); }); -describe('distribute with fractions', () => { +describe("distribute with fractions", () => { const tests = [ // distribute the non-fraction term into the numerator(s) - ['(3 / x^2 + x / (x^2 + 3)) * (x^2 + 3)', - '((3 * (x^2 + 3)) / (x^2) + (x * (x^2 + 3)) / (x^2 + 3))', + ["(3 / x^2 + x / (x^2 + 3)) * (x^2 + 3)", + "((3 * (x^2 + 3)) / (x^2) + (x * (x^2 + 3)) / (x^2 + 3))", ], // if both groupings have fraction, the rule does not apply - ['(3 / x^2 + x / (x^2 + 3)) * (5 / x + x^5)', - '((3 / (x^2) * 5 / x + 3 / (x^2) * x^5) + (x / (x^2 + 3) * 5 / x + x / (x^2 + 3) * x^5))', + ["(3 / x^2 + x / (x^2 + 3)) * (5 / x + x^5)", + "((3 / (x^2) * 5 / x + 3 / (x^2) * x^5) + (x / (x^2 + 3) * 5 / x + x / (x^2 + 3) * x^5))", ], ]; const multiStepTests = [ - ['(2 / x + 3x^2) * (x^3 + 1)', - ['((2 * (x^3 + 1)) / x + 3x^2 * (x^3 + 1))', - '((2 * (x^3 + 1)) / x + (3x^5 + 3x^2))'] + ["(2 / x + 3x^2) * (x^3 + 1)", + ["((2 * (x^3 + 1)) / x + 3x^2 * (x^3 + 1))", + "((2 * (x^3 + 1)) / x + (3x^5 + 3x^2))"] ], - ['(2x + x^2) * (1 / (x^2 -4) + 4x^2)', - ['((1 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', - '((1 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] + ["(2x + x^2) * (1 / (x^2 -4) + 4x^2)", + ["((1 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))", + "((1 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))"] ], - ['(2x + x^2) * (3x^2 / (x^2 -4) + 4x^2)', - ['((3x^2 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', - '((3x^2 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] + ["(2x + x^2) * (3x^2 / (x^2 -4) + 4x^2)", + ["((3x^2 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))", + "((3x^2 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))"] ], ]; diff --git a/test/simplifyExpression/divisionSearch/divisionSearch.test.ts b/test/simplifyExpression/divisionSearch/divisionSearch.test.ts index b56ea72d..e5916155 100644 --- a/test/simplifyExpression/divisionSearch/divisionSearch.test.ts +++ b/test/simplifyExpression/divisionSearch/divisionSearch.test.ts @@ -1,21 +1,21 @@ -import divisionSearch = require('../../../lib/simplifyExpression/divisionSearch'); -import TestUtil = require('../../TestUtil'); +import divisionSearch = require("../../../lib/simplifyExpression/divisionSearch"); +import TestUtil = require("../../TestUtil"); function testSimplifyDivision(exprStr: any, outputStr: any); function testSimplifyDivision(exprStr, outputStr) { TestUtil.testSimplification(divisionSearch, exprStr, outputStr); } -describe('simplifyDivision', () => { +describe("simplifyDivision", () => { const tests = [ - ['6/x/5', '6 / (x * 5)'], - ['-(6/x/5)', '-(6 / (x * 5))'], - ['-6/x/5', '-6 / (x * 5)'], - ['(2+2)/x/6/(y-z)','(2 + 2) / (x * 6 * (y - z))'], - ['2/x', '2 / x'], - ['x/(2/3)', 'x * 3/2'], - ['x / (y/(z+a))', 'x * (z + a) / y'], - ['x/((2+z)/(3/y))', 'x * (3 / y) / (2 + z)'], + ["6/x/5", "6 / (x * 5)"], + ["-(6/x/5)", "-(6 / (x * 5))"], + ["-6/x/5", "-6 / (x * 5)"], + ["(2+2)/x/6/(y-z)","(2 + 2) / (x * 6 * (y - z))"], + ["2/x", "2 / x"], + ["x/(2/3)", "x * 3/2"], + ["x / (y/(z+a))", "x * (z + a) / y"], + ["x/((2+z)/(3/y))", "x * (3 / y) / (2 + z)"], ]; tests.forEach(t => testSimplifyDivision(t[0], t[1])); }); diff --git a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts index 0b7a2603..013c92a2 100644 --- a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts +++ b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts @@ -1,5 +1,5 @@ -import addConstantAndFraction = require('../../../lib/simplifyExpression/fractionsSearch/addConstantAndFraction'); -import TestUtil = require('../../TestUtil'); +import addConstantAndFraction = require("../../../lib/simplifyExpression/fractionsSearch/addConstantAndFraction"); +import TestUtil = require("../../TestUtil"); function testAddConstantAndFraction(exprString: any, outputList: any); function testAddConstantAndFraction(exprString, outputList) { @@ -7,25 +7,25 @@ function testAddConstantAndFraction(exprString, outputList) { TestUtil.testSubsteps(addConstantAndFraction, exprString, outputList, lastString); } -describe('addConstantAndFraction', () => { +describe("addConstantAndFraction", () => { const tests = [ - ['7 + 1/2', - ['14/2 + 1/2', - '(14 + 1) / 2', - '15/2'] + ["7 + 1/2", + ["14/2 + 1/2", + "(14 + 1) / 2", + "15/2"] ], - ['5/6 + 3', - ['5/6 + 18/6', - '(5 + 18) / 6', - '23/6'], + ["5/6 + 3", + ["5/6 + 18/6", + "(5 + 18) / 6", + "23/6"], ], - ['1/2 + 5.8', - ['0.5 + 5.8', - '6.3'], + ["1/2 + 5.8", + ["0.5 + 5.8", + "6.3"], ], - ['1/3 + 5.8', - ['0.3333 + 5.8', - '6.1333'] + ["1/3 + 5.8", + ["0.3333 + 5.8", + "6.1333"] ], ]; tests.forEach(t => testAddConstantAndFraction(t[0], t[1])); diff --git a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts index 5aefc818..75ae3531 100644 --- a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts +++ b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts @@ -1,5 +1,5 @@ -import addConstantFractions = require('../../../lib/simplifyExpression/fractionsSearch/addConstantFractions'); -import TestUtil = require('../../TestUtil'); +import addConstantFractions = require("../../../lib/simplifyExpression/fractionsSearch/addConstantFractions"); +import TestUtil = require("../../TestUtil"); function testAddConstantFractions(exprString: any, outputList: any); function testAddConstantFractions(exprString, outputList) { @@ -7,31 +7,31 @@ function testAddConstantFractions(exprString, outputList) { TestUtil.testSubsteps(addConstantFractions, exprString, outputList, lastString); } -describe('addConstantFractions', () => { +describe("addConstantFractions", () => { const tests = [ - ['4/5 + 3/5', - ['(4 + 3) / 5', - '7/5'] + ["4/5 + 3/5", + ["(4 + 3) / 5", + "7/5"] ], - ['4/10 + 3/5', - ['4/10 + (3 * 2) / (5 * 2)', - '4/10 + (3 * 2) / 10', - '4/10 + 6/10', - '(4 + 6) / 10', - '10/10', - '1'] + ["4/10 + 3/5", + ["4/10 + (3 * 2) / (5 * 2)", + "4/10 + (3 * 2) / 10", + "4/10 + 6/10", + "(4 + 6) / 10", + "10/10", + "1"] ], - ['4/9 + 3/5', - ['(4 * 5) / (9 * 5) + (3 * 9) / (5 * 9)', - '(4 * 5) / 45 + (3 * 9) / 45', - '20/45 + 27/45', - '(20 + 27) / 45', - '47/45'] + ["4/9 + 3/5", + ["(4 * 5) / (9 * 5) + (3 * 9) / (5 * 9)", + "(4 * 5) / 45 + (3 * 9) / 45", + "20/45 + 27/45", + "(20 + 27) / 45", + "47/45"] ], - ['4/5 - 4/5', - ['(4 - 4) / 5', - '0/5', - '0'] + ["4/5 - 4/5", + ["(4 - 4) / 5", + "0/5", + "0"] ], ]; tests.forEach(t => testAddConstantFractions(t[0], t[1])); diff --git a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts index f769f9ae..a55650c4 100644 --- a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts +++ b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts @@ -1,32 +1,32 @@ -import cancelLikeTerms = require('../../../lib/simplifyExpression/fractionsSearch/cancelLikeTerms'); -import TestUtil = require('../../TestUtil'); +import cancelLikeTerms = require("../../../lib/simplifyExpression/fractionsSearch/cancelLikeTerms"); +import TestUtil = require("../../TestUtil"); function testCancelLikeTerms(exprStr: any, expectedStr: any); function testCancelLikeTerms(exprStr, expectedStr) { TestUtil.testSimplification(cancelLikeTerms, exprStr, expectedStr); } -describe('cancel like terms', () => { +describe("cancel like terms", () => { const tests = [ - ['2/2', '1'], - ['x^2/x^2', '1'], - ['x^3/x^2', 'x^(3 - (2))'], // parens will be removed at end of step - ['(x^3*y)/x^2', '(x^(3 - (2)) * y)'], - ['-(7+x)^8/(7+x)^2', '-((7 + x)^(8 - (2)))'], - ['(2x^2 * 5) / (2x^2)', '5'], // these parens have to stay around 2x^2 to be parsed correctly. - ['(x^2 * y) / x', '(x^(2 - (1)) * y)'], - ['2x^2 / (2x^2 * 5)', '1/5'], - ['x / (x^2*y)', 'x^(1 - (2)) / y'], - ['(4x^2) / (5x^2)', '(4) / (5)'], - ['(2x+5)^8 / (2x+5)^2', '(2x + 5)^(8 - (2))'], - ['(4x^3) / (5x^2)', '(4x^(3 - (2))) / (5)'], - ['-x / -x', '1'], + ["2/2", "1"], + ["x^2/x^2", "1"], + ["x^3/x^2", "x^(3 - (2))"], // parens will be removed at end of step + ["(x^3*y)/x^2", "(x^(3 - (2)) * y)"], + ["-(7+x)^8/(7+x)^2", "-((7 + x)^(8 - (2)))"], + ["(2x^2 * 5) / (2x^2)", "5"], // these parens have to stay around 2x^2 to be parsed correctly. + ["(x^2 * y) / x", "(x^(2 - (1)) * y)"], + ["2x^2 / (2x^2 * 5)", "1/5"], + ["x / (x^2*y)", "x^(1 - (2)) / y"], + ["(4x^2) / (5x^2)", "(4) / (5)"], + ["(2x+5)^8 / (2x+5)^2", "(2x + 5)^(8 - (2))"], + ["(4x^3) / (5x^2)", "(4x^(3 - (2))) / (5)"], + ["-x / -x", "1"], ]; tests.forEach(t => { const before = t[0]; const after = t[1]; - it(before + ' -> ' + after, () => { + it(before + " -> " + after, () => { testCancelLikeTerms(before, after); }); }); diff --git a/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts b/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts index 7e898268..2a6f3ace 100644 --- a/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts +++ b/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts @@ -1,19 +1,19 @@ -import divideByGCD = require('../../../lib/simplifyExpression/fractionsSearch/divideByGCD'); -import TestUtil = require('../../TestUtil'); +import divideByGCD = require("../../../lib/simplifyExpression/fractionsSearch/divideByGCD"); +import TestUtil = require("../../TestUtil"); -function testdivideByGCD(exprStr: any, outputStr: any); -function testdivideByGCD(exprStr, outputStr) { +function testdivideByGcd(exprStr: any, outputStr: any); +function testdivideByGcd(exprStr, outputStr) { TestUtil.testSimplification(divideByGCD, exprStr, outputStr); } -describe('simplifyFraction', () => { +describe("simplifyFraction", () => { const tests = [ - ['2/4', '1/2'], - ['9/3', '3'], - ['12/27', '4/9'], - ['1/-3', '-1/3'], - ['-3/-2', '3/2'], - ['-1/-1', '1'], + ["2/4", "1/2"], + ["9/3", "3"], + ["12/27", "4/9"], + ["1/-3", "-1/3"], + ["-3/-2", "3/2"], + ["-1/-1", "1"], ]; - tests.forEach(t => testdivideByGCD(t[0], t[1])); + tests.forEach(t => testdivideByGcd(t[0], t[1])); }); diff --git a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts index a956e01a..845dfe08 100644 --- a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts +++ b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts @@ -1,15 +1,15 @@ -import simplifyFractionSigns = require('../../../lib/simplifyExpression/fractionsSearch/simplifyFractionSigns'); -import TestUtil = require('../../TestUtil'); +import simplifyFractionSigns = require("../../../lib/simplifyExpression/fractionsSearch/simplifyFractionSigns"); +import TestUtil = require("../../TestUtil"); function testSimplifyFractionSigns(exprStr: any, outputStr: any); function testSimplifyFractionSigns(exprStr, outputStr) { TestUtil.testSimplification(simplifyFractionSigns, exprStr, outputStr); } -describe('simplify signs', () => { +describe("simplify signs", () => { const tests = [ - ['-12x / -27', '12x / 27'], - ['x / -y', '-x / y'], + ["-12x / -27", "12x / 27"], + ["x / -y", "-x / y"], ]; tests.forEach(t => testSimplifyFractionSigns(t[0], t[1])); }); diff --git a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts index 26958821..5d7e5581 100644 --- a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts +++ b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts @@ -1,20 +1,20 @@ -import simplifyPolynomialFraction = require('../../../lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction'); -import TestUtil = require('../../TestUtil'); +import simplifyPolynomialFraction = require("../../../lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction"); +import TestUtil = require("../../TestUtil"); function testSimplifyPolynomialFraction(exprStr: any, outputStr: any); function testSimplifyPolynomialFraction(exprStr, outputStr) { TestUtil.testSimplification(simplifyPolynomialFraction, exprStr, outputStr); } -describe('simplifyPolynomialFraction', () => { +describe("simplifyPolynomialFraction", () => { const tests = [ - ['2x/4', '1/2 x'], - ['9y/3', '3y'], - ['y/-3', '-1/3 y'], - ['-3y/-2', '3/2 y'], - ['-y/-1', 'y'], - ['12z^2/27', '4/9 z^2'], - ['1.6x / 1.6', 'x'], + ["2x/4", "1/2 x"], + ["9y/3", "3y"], + ["y/-3", "-1/3 y"], + ["-3y/-2", "3/2 y"], + ["-y/-1", "y"], + ["12z^2/27", "4/9 z^2"], + ["1.6x / 1.6", "x"], ]; tests.forEach(t => testSimplifyPolynomialFraction(t[0], t[1])); }); diff --git a/test/simplifyExpression/functionsSearch/absoluteValue.test.ts b/test/simplifyExpression/functionsSearch/absoluteValue.test.ts index de6ebe97..b62cc5dd 100644 --- a/test/simplifyExpression/functionsSearch/absoluteValue.test.ts +++ b/test/simplifyExpression/functionsSearch/absoluteValue.test.ts @@ -1,15 +1,15 @@ -import absoluteValue = require('../../../lib/simplifyExpression/functionsSearch/absoluteValue'); -import TestUtil = require('../../TestUtil'); +import absoluteValue = require("../../../lib/simplifyExpression/functionsSearch/absoluteValue"); +import TestUtil = require("../../TestUtil"); function testAbsoluteValue(exprString: any, outputStr: any); function testAbsoluteValue(exprString, outputStr) { TestUtil.testSimplification(absoluteValue, exprString, outputStr); } -describe('abs', () => { +describe("abs", () => { const tests = [ - ['abs(4)', '4'], - ['abs(-5)', '5'], + ["abs(4)", "4"], + ["abs(-5)", "5"], ]; tests.forEach(t => testAbsoluteValue(t[0], t[1])); }); diff --git a/test/simplifyExpression/functionsSearch/nthRoot.test.ts b/test/simplifyExpression/functionsSearch/nthRoot.test.ts index 0f867258..d0c2766f 100644 --- a/test/simplifyExpression/functionsSearch/nthRoot.test.ts +++ b/test/simplifyExpression/functionsSearch/nthRoot.test.ts @@ -1,32 +1,32 @@ -import nthRoot = require('../../../lib/simplifyExpression/functionsSearch/nthRoot'); -import TestUtil = require('../../TestUtil'); +import nthRoot = require("../../../lib/simplifyExpression/functionsSearch/nthRoot"); +import TestUtil = require("../../TestUtil"); function testNthRoot(exprString: any, outputStr: any); function testNthRoot(exprString, outputStr) { TestUtil.testSimplification(nthRoot, exprString, outputStr); } -describe('simplify nthRoot', () => { +describe("simplify nthRoot", () => { const tests = [ - ['nthRoot(4)', '2'], - ['nthRoot(8, 3)', '2'], - ['nthRoot(5 * 7)', 'nthRoot(5 * 7)'], - ['nthRoot(4, 3)', 'nthRoot(4, 3)'], - ['nthRoot(12)', '2 * nthRoot(3, 2)'], - ['nthRoot(36)', '6'], - ['nthRoot(72)', '2 * 3 * nthRoot(2, 2)'], - ['nthRoot(x^2)', 'x'], - ['nthRoot(x ^ 3)', 'nthRoot(x ^ 3)'], - ['nthRoot(x^3, 3)', 'x'], - ['nthRoot(-2)', 'nthRoot(-2)'], - ['nthRoot(2 ^ x, x)', '2'], - ['nthRoot(x ^ (1/2), 1/2)', 'x'], - ['nthRoot(2 * 2, 2)', '2'], - ['nthRoot(3 * 2 * 3 * 2, 2)', '2 * 3'], - ['nthRoot(36*x)', '2 * 3 * nthRoot(x, 2)'], - ['nthRoot(2 * 18 * x ^ 2, 2)', '2 * 3 * x'], - ['nthRoot(x * x, 2)', 'x'], - ['nthRoot(x * x * (2 + 3), 2)', 'x * nthRoot((2 + 3), 2)'], + ["nthRoot(4)", "2"], + ["nthRoot(8, 3)", "2"], + ["nthRoot(5 * 7)", "nthRoot(5 * 7)"], + ["nthRoot(4, 3)", "nthRoot(4, 3)"], + ["nthRoot(12)", "2 * nthRoot(3, 2)"], + ["nthRoot(36)", "6"], + ["nthRoot(72)", "2 * 3 * nthRoot(2, 2)"], + ["nthRoot(x^2)", "x"], + ["nthRoot(x ^ 3)", "nthRoot(x ^ 3)"], + ["nthRoot(x^3, 3)", "x"], + ["nthRoot(-2)", "nthRoot(-2)"], + ["nthRoot(2 ^ x, x)", "2"], + ["nthRoot(x ^ (1/2), 1/2)", "x"], + ["nthRoot(2 * 2, 2)", "2"], + ["nthRoot(3 * 2 * 3 * 2, 2)", "2 * 3"], + ["nthRoot(36*x)", "2 * 3 * nthRoot(x, 2)"], + ["nthRoot(2 * 18 * x ^ 2, 2)", "2 * 3 * x"], + ["nthRoot(x * x, 2)", "x"], + ["nthRoot(x * x * (2 + 3), 2)", "x * nthRoot((2 + 3), 2)"], ]; tests.forEach(t => testNthRoot(t[0], t[1])); }); @@ -37,36 +37,36 @@ function testNthRootSteps(exprString, outputList) { TestUtil.testSubsteps(nthRoot, exprString, outputList, lastString); } -describe('nthRoot steps', () => { +describe("nthRoot steps", () => { const tests = [ - ['nthRoot(12)', - ['nthRoot(2 * 2 * 3)', - 'nthRoot((2 * 2) * 3)', - 'nthRoot(2 ^ 2 * 3)', - 'nthRoot(2 ^ 2, 2) * nthRoot(3, 2)', - '2 * nthRoot(3, 2)'] + ["nthRoot(12)", + ["nthRoot(2 * 2 * 3)", + "nthRoot((2 * 2) * 3)", + "nthRoot(2 ^ 2 * 3)", + "nthRoot(2 ^ 2, 2) * nthRoot(3, 2)", + "2 * nthRoot(3, 2)"] ], - ['nthRoot(72)', - ['nthRoot(2 * 2 * 2 * 3 * 3)', - 'nthRoot((2 * 2) * 2 * (3 * 3))', - 'nthRoot(2 ^ 2 * 2 * 3 ^ 2)', - 'nthRoot(2 ^ 2, 2) * nthRoot(2, 2) * nthRoot(3 ^ 2, 2)', - '2 * nthRoot(2, 2) * 3', - '2 * 3 * nthRoot(2, 2)'] + ["nthRoot(72)", + ["nthRoot(2 * 2 * 2 * 3 * 3)", + "nthRoot((2 * 2) * 2 * (3 * 3))", + "nthRoot(2 ^ 2 * 2 * 3 ^ 2)", + "nthRoot(2 ^ 2, 2) * nthRoot(2, 2) * nthRoot(3 ^ 2, 2)", + "2 * nthRoot(2, 2) * 3", + "2 * 3 * nthRoot(2, 2)"] ], - ['nthRoot(36*x)', - ['nthRoot(2 * 2 * 3 * 3 * x)', - 'nthRoot((2 * 2) * (3 * 3) * x)', - 'nthRoot(2 ^ 2 * 3 ^ 2 * x)', - 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x, 2)', - '2 * 3 * nthRoot(x, 2)'] + ["nthRoot(36*x)", + ["nthRoot(2 * 2 * 3 * 3 * x)", + "nthRoot((2 * 2) * (3 * 3) * x)", + "nthRoot(2 ^ 2 * 3 ^ 2 * x)", + "nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x, 2)", + "2 * 3 * nthRoot(x, 2)"] ], - ['nthRoot(2 * 18 * x ^ 2, 2)', - ['nthRoot(2 * 2 * 3 * 3 * x ^ 2, 2)', - 'nthRoot((2 * 2) * (3 * 3) * x ^ 2, 2)', - 'nthRoot(2 ^ 2 * 3 ^ 2 * x ^ 2, 2)', - 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x ^ 2, 2)', - '2 * 3 * x'] + ["nthRoot(2 * 18 * x ^ 2, 2)", + ["nthRoot(2 * 2 * 3 * 3 * x ^ 2, 2)", + "nthRoot((2 * 2) * (3 * 3) * x ^ 2, 2)", + "nthRoot(2 ^ 2 * 3 ^ 2 * x ^ 2, 2)", + "nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x ^ 2, 2)", + "2 * 3 * x"] ] ]; tests.forEach(t => testNthRootSteps(t[0], t[1])); diff --git a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts index 5dae28d4..b44f8d8e 100644 --- a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts +++ b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts @@ -1,16 +1,16 @@ -import multiplyFractionsSearch = require('../../../lib/simplifyExpression//multiplyFractionsSearch'); -import TestUtil = require('../../TestUtil'); +import multiplyFractionsSearch = require("../../../lib/simplifyExpression//multiplyFractionsSearch"); +import TestUtil = require("../../TestUtil"); function testMultiplyFractionsSearch(exprString: any, outputStr: any); function testMultiplyFractionsSearch(exprString, outputStr) { TestUtil.testSimplification(multiplyFractionsSearch, exprString, outputStr); } -describe('multiplyFractions', () => { +describe("multiplyFractions", () => { const tests = [ - ['3 * 1/5 * 5/9', '(3 * 1 * 5) / (5 * 9)'], - ['3/7 * 10/11', '(3 * 10) / (7 * 11)'], - ['2 * 5/x', '(2 * 5) / x'] + ["3 * 1/5 * 5/9", "(3 * 1 * 5) / (5 * 9)"], + ["3/7 * 10/11", "(3 * 10) / (7 * 11)"], + ["2 * 5/x", "(2 * 5) / x"] ]; tests.forEach(t => testMultiplyFractionsSearch(t[0], t[1])); }); diff --git a/test/simplifyExpression/oneStep.test.ts b/test/simplifyExpression/oneStep.test.ts index 73b882bd..4e00c1bc 100644 --- a/test/simplifyExpression/oneStep.test.ts +++ b/test/simplifyExpression/oneStep.test.ts @@ -1,7 +1,7 @@ -const assert = require('assert'); -import print = require('../../lib/util/print'); -import ChangeTypes = require('../../lib/ChangeTypes'); -import simplifyExpression = require('../../lib/simplifyExpression'); +const assert = require("assert"); +import print = require("../../lib/util/print"); +import ChangeTypes = require("../../lib/ChangeTypes"); +import simplifyExpression = require("../../lib/simplifyExpression"); function testOneStep(exprStr, outputStr, debug=false) { const steps = simplifyExpression(exprStr); @@ -11,84 +11,84 @@ function testOneStep(exprStr, outputStr, debug=false) { const nodeStatus = steps[0]; if (debug) { if (!nodeStatus.changeType) { - throw Error('missing or bad change type'); + throw Error("missing or bad change type"); } // eslint-disable-next-line console.log(nodeStatus.changeType); // eslint-disable-next-line console.log(print(nodeStatus.newNode)); } - it(exprStr + ' -> ' + outputStr, () => { + it(exprStr + " -> " + outputStr, () => { assert.deepEqual( print(nodeStatus.newNode), outputStr); }); } -describe('arithmetic stepping', () => { +describe("arithmetic stepping", () => { const tests = [ - ['(2+2)', '4'], - ['(2+2)*5', '4 * 5'], - ['5*(2+2)', '5 * 4'], - ['2*(2+2) + 2^3', '2 * 4 + 2^3'], + ["(2+2)", "4"], + ["(2+2)*5", "4 * 5"], + ["5*(2+2)", "5 * 4"], + ["2*(2+2) + 2^3", "2 * 4 + 2^3"], ]; tests.forEach(t => testOneStep(t[0], t[1])); }); -describe('adding symbols without breaking things', () => { +describe("adding symbols without breaking things", () => { // nothing old breaks const tests = [ - ['2+x', '2 + x'], - ['(2+2)*x', '4x'], - ['(2+2)*x+3', '4x + 3'], + ["2+x", "2 + x"], + ["(2+2)*x", "4x"], + ["(2+2)*x+3", "4x + 3"], ]; tests.forEach(t => testOneStep(t[0], t[1])); }); -describe('collecting like terms within the context of the stepper', () => { +describe("collecting like terms within the context of the stepper", () => { const tests = [ - ['2+x+7', 'x + 9'], // substeps not tested here + ["2+x+7", "x + 9"], // substeps not tested here // ['2x^2 * y * x * y^3', '2 * x^3 * y^4'], // substeps not tested here ]; tests.forEach(t => testOneStep(t[0], t[1])); }); -describe('collects and combines like terms', () => { +describe("collects and combines like terms", () => { const tests = [ - ['(x + x) + (x^2 + x^2)', '2x + (x^2 + x^2)'], // substeps not tested here - ['10 + (y^2 + y^2)', '10 + 2y^2'], // substeps not tested here - ['10y^2 + 1/2 y^2 + 3/2 y^2', '12y^2'], // substeps not tested here - ['x + y + y^2', 'x + y + y^2'], - ['2x^(2+1)', '2x^3'], + ["(x + x) + (x^2 + x^2)", "2x + (x^2 + x^2)"], // substeps not tested here + ["10 + (y^2 + y^2)", "10 + 2y^2"], // substeps not tested here + ["10y^2 + 1/2 y^2 + 3/2 y^2", "12y^2"], // substeps not tested here + ["x + y + y^2", "x + y + y^2"], + ["2x^(2+1)", "2x^3"], ]; tests.forEach(t => testOneStep(t[0], t[1])); }); -describe('stepThrough returning no steps', () => { - it('12x^2 already simplified', () => { +describe("stepThrough returning no steps", () => { + it("12x^2 already simplified", () => { assert.deepEqual( - simplifyExpression('12x^2'), + simplifyExpression("12x^2"), []); }); - it('2*5x^2 + sqrt(5) has unsupported sqrt', () => { + it("2*5x^2 + sqrt(5) has unsupported sqrt", () => { assert.deepEqual( - simplifyExpression('2*5x^2 + sqrt(5)'), + simplifyExpression("2*5x^2 + sqrt(5)"), []); }); }); -describe('keeping parens in important places, on printing', () => { - testOneStep('5 + (3*6) + 2 / (x / y)', '5 + (3 * 6) + 2 * y / x'); - testOneStep('-(x + y) + 5+3', '8 - (x + y)'); +describe("keeping parens in important places, on printing", () => { + testOneStep("5 + (3*6) + 2 / (x / y)", "5 + (3 * 6) + 2 * y / x"); + testOneStep("-(x + y) + 5+3", "8 - (x + y)"); }); -describe('fractions', () => { - testOneStep('2 + 5/2 + 3', '5 + 5/2'); // collect and combine without substeps +describe("fractions", () => { + testOneStep("2 + 5/2 + 3", "5 + 5/2"); // collect and combine without substeps }); -describe('simplifyDoubleUnaryMinus step actually happens', () => { - it('22 - (-7) -> 22 + 7', () => { - const steps = simplifyExpression('22 - (-7)'); +describe("simplifyDoubleUnaryMinus step actually happens", () => { + it("22 - (-7) -> 22 + 7", () => { + const steps = simplifyExpression("22 - (-7)"); assert.equal(steps[0].changeType, ChangeTypes.RESOLVE_DOUBLE_MINUS); }); }); diff --git a/test/simplifyExpression/simplify.test.ts b/test/simplifyExpression/simplify.test.ts index 57275cfb..3e60d869 100644 --- a/test/simplifyExpression/simplify.test.ts +++ b/test/simplifyExpression/simplify.test.ts @@ -1,166 +1,166 @@ -const assert = require('assert'); -import math = require('mathjs'); -import print = require('../../lib/util/print'); -import simplify = require('../../lib/simplifyExpression/simplify'); +const assert = require("assert"); +import math = require("mathjs"); +import print = require("../../lib/util/print"); +import simplify = require("../../lib/simplifyExpression/simplify"); function testSimplify(exprStr, outputStr, debug=false) { - it(exprStr + ' -> ' + outputStr, () => { + it(exprStr + " -> " + outputStr, () => { assert.deepEqual( print(simplify(math.parse(exprStr), debug)), outputStr); }); } -describe('simplify (arithmetic)', () => { +describe("simplify (arithmetic)", () => { const tests = [ - ['(2+2)*5', '20'], - ['(8+(-4))*5', '20'], - ['5*(2+2)*10', '200'], - ['(2+(2)+7)', '11'], - ['(8-2) * 2^2 * (1+1) / (4 /2) / 5', '24/5'], + ["(2+2)*5", "20"], + ["(8+(-4))*5", "20"], + ["5*(2+2)*10", "200"], + ["(2+(2)+7)", "11"], + ["(8-2) * 2^2 * (1+1) / (4 /2) / 5", "24/5"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('collects and combines like terms', () => { +describe("collects and combines like terms", () => { const tests = [ - ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], - ['2x^2 * y * x * y^3', '2x^3 * y^4'], - ['4y*3*5', '60y'], - ['(2x^2 - 4) + (4x^2 + 3)', '6x^2 - 1'], - ['(2x^1 + 4) + (4x^2 + 3)', '4x^2 + 2x + 7'], - ['y * 2x * 10', '20x * y'], - ['x^y * x^z', 'x^(y + z)'], - ['x^(3+y) + x^(3+y)+ 4', '2x^(3 + y) + 4'], - ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], + ["x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6", "5x^3 - 8x^2 + 6"], + ["2x^2 * y * x * y^3", "2x^3 * y^4"], + ["4y*3*5", "60y"], + ["(2x^2 - 4) + (4x^2 + 3)", "6x^2 - 1"], + ["(2x^1 + 4) + (4x^2 + 3)", "4x^2 + 2x + 7"], + ["y * 2x * 10", "20x * y"], + ["x^y * x^z", "x^(y + z)"], + ["x^(3+y) + x^(3+y)+ 4", "2x^(3 + y) + 4"], + ["x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6", "5x^3 - 8x^2 + 6"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('can simplify with division', () => { +describe("can simplify with division", () => { const tests = [ - ['2 * 4 / 5 * 10 + 3', '19'], - ['2x * 5x / 2', '5x^2'], - ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], - ['2x * 4x / 2 / 4', 'x^2'], - ['2x * y / z * 10', '20x * y / z'], - ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], - ['2x/x', '2'], - ['2x/4/3', '1/6 x'], + ["2 * 4 / 5 * 10 + 3", "19"], + ["2x * 5x / 2", "5x^2"], + ["2x * 4x / 5 * 10 + 3", "16x^2 + 3"], + ["2x * 4x / 2 / 4", "x^2"], + ["2x * y / z * 10", "20x * y / z"], + ["2x * 4x / 5 * 10 + 3", "16x^2 + 3"], + ["2x/x", "2"], + ["2x/4/3", "1/6 x"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); // TODO: factor the numerator to cancel out with denominator // e.g. (x^2 - 3 + 2)/(x-2) -> (x-1) }); -describe('subtraction support', () => { +describe("subtraction support", () => { const tests = [ - ['-(-(2+3))', '5'], - ['-(-5)', '5'], - ['-(-(2+x))', '2 + x'], - ['-------5', '-5'], - ['--(-----5) + 6', '1'], - ['x^2 + 3 - x*x', '3'], - ['-(2*x) * -(2 + 2)', '8x'], - ['(x-4)-5', 'x - 9'], - ['5-x-4', '-x + 1'], + ["-(-(2+3))", "5"], + ["-(-5)", "5"], + ["-(-(2+x))", "2 + x"], + ["-------5", "-5"], + ["--(-----5) + 6", "1"], + ["x^2 + 3 - x*x", "3"], + ["-(2*x) * -(2 + 2)", "8x"], + ["(x-4)-5", "x - 9"], + ["5-x-4", "-x + 1"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('support for more * and ( that come from latex conversion', () => { +describe("support for more * and ( that come from latex conversion", () => { const tests = [ - ['(3*x)*(4*x)', '12x^2'], - ['(12*z^(2))/27', '4/9 z^2'], - ['x^2 - 12x^2 + 5x^2 - 7', '-6x^2 - 7'], - ['-(12 x ^ 2)', '-12x^2'] + ["(3*x)*(4*x)", "12x^2"], + ["(12*z^(2))/27", "4/9 z^2"], + ["x^2 - 12x^2 + 5x^2 - 7", "-6x^2 - 7"], + ["-(12 x ^ 2)", "-12x^2"] ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('distribution', () => { +describe("distribution", () => { const tests = [ - ['(3*x)*(4*x)', '12x^2'], - ['(3+x)*(4+x)*(x+5)', 'x^3 + 12x^2 + 47x + 60'], - ['-2x^2 * (3x - 4)', '-6x^3 + 8x^2'], - ['x^2 - x^2*(12 + 5x) - 7', '-5x^3 - 11x^2 - 7'], - ['(5+x)*(x+3)', 'x^2 + 8x + 15'], - ['(x-2)(x-4)', 'x^2 - 6x + 8'], - ['- x*y^4 (6x * y^2 + 5x*y - 3x)', - '-6x^2 * y^6 - 5x^2 * y^5 + 3x^2 * y^4'], + ["(3*x)*(4*x)", "12x^2"], + ["(3+x)*(4+x)*(x+5)", "x^3 + 12x^2 + 47x + 60"], + ["-2x^2 * (3x - 4)", "-6x^3 + 8x^2"], + ["x^2 - x^2*(12 + 5x) - 7", "-5x^3 - 11x^2 - 7"], + ["(5+x)*(x+3)", "x^2 + 8x + 15"], + ["(x-2)(x-4)", "x^2 - 6x + 8"], + ["- x*y^4 (6x * y^2 + 5x*y - 3x)", + "-6x^2 * y^6 - 5x^2 * y^5 + 3x^2 * y^4"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('fractions', () => { +describe("fractions", () => { const tests = [ - ['5x + (1/2)x', '11/2 x'], - ['x + x/2', '3/2 x'], - ['1 + 1/2', '3/2'], - ['2 + 5/2 + 3', '15/2'], - ['9/18-5/18', '2/9'], - ['2(x+3)/3', '2x / 3 + 2'], - ['5/18 - 9/18', '-2/9'], - ['9/18', '1/2'], - ['x/(2/3) + 5', '3/2 x + 5'], - ['(2+x)/6', '1/3 + x / 6'] + ["5x + (1/2)x", "11/2 x"], + ["x + x/2", "3/2 x"], + ["1 + 1/2", "3/2"], + ["2 + 5/2 + 3", "15/2"], + ["9/18-5/18", "2/9"], + ["2(x+3)/3", "2x / 3 + 2"], + ["5/18 - 9/18", "-2/9"], + ["9/18", "1/2"], + ["x/(2/3) + 5", "3/2 x + 5"], + ["(2+x)/6", "1/3 + x / 6"] ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('floating point', () => { - testSimplify('1.983*10', '19.83'); +describe("floating point", () => { + testSimplify("1.983*10", "19.83"); }); -describe('cancelling out', () => { +describe("cancelling out", () => { const tests = [ - ['(x^3*y)/x^2 + 5', 'x * y + 5'], - ['(x^(2)+y^(2))/(5x-6x) + 5', '-x - y^2 / x + 5'], - ['( p ^ ( 2) + 1)/( p ^ ( 2) + 1)', '1'], - ['(-x)/(x)', '-1'], - ['(x)/(-x)', '-1'], - ['((2x^3 y^2)/(-x^2 y^5))^(-2)', '(-2x * y^-3)^-2'], + ["(x^3*y)/x^2 + 5", "x * y + 5"], + ["(x^(2)+y^(2))/(5x-6x) + 5", "-x - y^2 / x + 5"], + ["( p ^ ( 2) + 1)/( p ^ ( 2) + 1)", "1"], + ["(-x)/(x)", "-1"], + ["(x)/(-x)", "-1"], + ["((2x^3 y^2)/(-x^2 y^5))^(-2)", "(-2x * y^-3)^-2"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('absolute value support', () => { +describe("absolute value support", () => { const tests = [ - ['(x^3*y)/x^2 + abs(-5)', 'x * y + 5'], - ['-6 + -5 - abs(-4) + -10 - 3 abs(-4)', '-37'], - ['5*abs((2+2))*10', '200'], - ['5x + (1/abs(-2))x', '11/2 x'], - ['abs(5/18-abs(9/-18))', '2/9'], + ["(x^3*y)/x^2 + abs(-5)", "x * y + 5"], + ["-6 + -5 - abs(-4) + -10 - 3 abs(-4)", "-37"], + ["5*abs((2+2))*10", "200"], + ["5x + (1/abs(-2))x", "11/2 x"], + ["abs(5/18-abs(9/-18))", "2/9"], // handle parens around abs() - ['( abs( -3) )/(3)', '1'], - ['- abs( -40)', '-40'], + ["( abs( -3) )/(3)", "1"], + ["- abs( -40)", "-40"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('nthRoot support', () => { +describe("nthRoot support", () => { const tests = [ - ['nthRoot(4x, 2)', '2 * nthRoot(x, 2)'], - ['2 * nthRoot(4x, 2)', '4 * nthRoot(x, 2)'], - ['(x^3*y)/x^2 + nthRoot(4x, 2)', 'x * y + 2 * nthRoot(x, 2)'], - ['2 + nthRoot(4)', '4'], - ['x * nthRoot(x^4, 2)', 'x^3'], - ['x * nthRoot(2 + 2, 3)', 'x * nthRoot(4, 3)'], - ['x * nthRoot((2 + 2) * 2, 3)', '2x'], - ['nthRoot(x * (2 + 3) * x, 2)', 'x * nthRoot(5, 2)'] + ["nthRoot(4x, 2)", "2 * nthRoot(x, 2)"], + ["2 * nthRoot(4x, 2)", "4 * nthRoot(x, 2)"], + ["(x^3*y)/x^2 + nthRoot(4x, 2)", "x * y + 2 * nthRoot(x, 2)"], + ["2 + nthRoot(4)", "4"], + ["x * nthRoot(x^4, 2)", "x^3"], + ["x * nthRoot(2 + 2, 3)", "x * nthRoot(4, 3)"], + ["x * nthRoot((2 + 2) * 2, 3)", "2x"], + ["nthRoot(x * (2 + 3) * x, 2)", "x * nthRoot(5, 2)"] ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('handles unnecessary parens at root level', () => { +describe("handles unnecessary parens at root level", () => { const tests = [ - ['(x+(y))', 'x + y'], - ['((x+y) + ((z^3)))', 'x + y + z^3'], + ["(x+(y))", "x + y"], + ["((x+y) + ((z^3)))", "x + y + z^3"], ]; tests.forEach(t => testSimplify(t[0], t[1], t[2])); }); -describe('keeping parens in important places, on printing', () => { - testSimplify('2 / (2x^2) + 5', '2 / (2x^2) + 5'); +describe("keeping parens in important places, on printing", () => { + testSimplify("2 / (2x^2) + 5", "2 / (2x^2) + 5"); }); diff --git a/test/solveEquation/solveEquation.test.ts b/test/solveEquation/solveEquation.test.ts index 86bffb85..1964ed32 100644 --- a/test/solveEquation/solveEquation.test.ts +++ b/test/solveEquation/solveEquation.test.ts @@ -1,60 +1,60 @@ -const assert = require('assert'); -import ChangeTypes = require('../../lib/ChangeTypes'); -import solveEquation = require('../../lib/solveEquation'); -const NO_STEPS = 'no-steps'; +const assert = require("assert"); +import ChangeTypes = require("../../lib/ChangeTypes"); +import solveEquation = require("../../lib/solveEquation"); +const noSteps = "no-steps"; function testSolve(equationString, outputStr, debug=false) { const steps = solveEquation(equationString, debug); let lastStep; if (steps.length === 0) { - lastStep = NO_STEPS; + lastStep = noSteps; } else { lastStep = steps[steps.length -1].newEquation.print(); } - it(equationString + ' -> ' + outputStr, (done) => { + it(equationString + " -> " + outputStr, (done) => { assert.equal(lastStep, outputStr); done(); }); } -describe('solveEquation for =', () => { +describe("solveEquation for =", () => { const tests = [ // can't solve this because two symbols: g and x -- so there's no steps - ['g *( x ) = ( x - 4) ^ ( 2) - 3', NO_STEPS], + ["g *( x ) = ( x - 4) ^ ( 2) - 3", noSteps], // can't solve this because we don't deal with the complicated fraction yet - ['( x )/( 2x + 7) >= 4', NO_STEPS], - ['y - x - 2 = 3*2', 'y = 8 + x'], - ['2y - x - 2 = x', 'y = x + 1'], - ['x = 1', NO_STEPS], - ['2 = x', 'x = 2'], - ['2 + -3 = x', 'x = -1'], - ['x + 3 = 4', 'x = 1'], - ['2x - 3 = 0', 'x = 3/2'], - ['x/3 - 2 = -1', 'x = 3'], - ['5x/2 + 2 = 3x/2 + 10', 'x = 8'], - ['2x - 1 = -x', 'x = 1/3'], - ['2 - x = -4 + x', 'x = 3'], - ['2x/3 = 2', 'x = 3'], - ['2x - 3 = x', 'x = 3'], - ['8 - 2a = a + 3 - 1', 'a = 2'], - ['2 - x = 4', 'x = -2'], - ['2 - 4x = x', 'x = 2/5'], - ['9x + 4 - 3 = 2x', 'x = -1/7'], - ['9x + 4 - 3 = -2x', 'x = -1/11'], - ['(2x^2 - 1)(x^2 - 5)(x^2 + 5) = 0', '2x^6 - x^4 - 50x^2 = -25'], - ['(-x ^ 2 - 4x + 2)(-3x^2 - 6x + 3) = 0', '3x^4 + 18x^3 + 15x^2 - 24x = -6'], - ['5x + (1/2)x = 27 ', 'x = 54/11'], - ['2x/3 = 2x - 4 ', 'x = 3'], - ['(-2/3)x + 3/7 = 1/2', 'x = -3/28'], - ['-9/4v + 4/5 = 7/8 ', 'v = -1/30'], + ["( x )/( 2x + 7) >= 4", noSteps], + ["y - x - 2 = 3*2", "y = 8 + x"], + ["2y - x - 2 = x", "y = x + 1"], + ["x = 1", noSteps], + ["2 = x", "x = 2"], + ["2 + -3 = x", "x = -1"], + ["x + 3 = 4", "x = 1"], + ["2x - 3 = 0", "x = 3/2"], + ["x/3 - 2 = -1", "x = 3"], + ["5x/2 + 2 = 3x/2 + 10", "x = 8"], + ["2x - 1 = -x", "x = 1/3"], + ["2 - x = -4 + x", "x = 3"], + ["2x/3 = 2", "x = 3"], + ["2x - 3 = x", "x = 3"], + ["8 - 2a = a + 3 - 1", "a = 2"], + ["2 - x = 4", "x = -2"], + ["2 - 4x = x", "x = 2/5"], + ["9x + 4 - 3 = 2x", "x = -1/7"], + ["9x + 4 - 3 = -2x", "x = -1/11"], + ["(2x^2 - 1)(x^2 - 5)(x^2 + 5) = 0", "2x^6 - x^4 - 50x^2 = -25"], + ["(-x ^ 2 - 4x + 2)(-3x^2 - 6x + 3) = 0", "3x^4 + 18x^3 + 15x^2 - 24x = -6"], + ["5x + (1/2)x = 27 ", "x = 54/11"], + ["2x/3 = 2x - 4 ", "x = 3"], + ["(-2/3)x + 3/7 = 1/2", "x = -3/28"], + ["-9/4v + 4/5 = 7/8 ", "v = -1/30"], // TODO: update test once we have root support - ['x^2 - 2 = 0', 'x^2 = 2'], - ['x/(2/3) = 1', 'x = 2/3'], - ['(x+1)/3 = 4', 'x = 11'], - ['2(x+3)/3 = 2', 'x = 0'], - ['( u )/( 0.3) = 4u + 6.28', 'u = -9.42'], - ['- q - 4.36= ( 2.2q )/( 1.8)', 'q = -1.962'], + ["x^2 - 2 = 0", "x^2 = 2"], + ["x/(2/3) = 1", "x = 2/3"], + ["(x+1)/3 = 4", "x = 11"], + ["2(x+3)/3 = 2", "x = 0"], + ["( u )/( 0.3) = 4u + 6.28", "u = -9.42"], + ["- q - 4.36= ( 2.2q )/( 1.8)", "q = -1.962"], // TODO: figure out what to do about errors from rounding midway through // this gives us 6.3995 when it should actually be 6.4 :( // ['x - 3.4= ( x - 2.5)/( 1.3)', 'x = 6.4'] @@ -62,13 +62,13 @@ describe('solveEquation for =', () => { tests.forEach(t => testSolve(t[0], t[1], t[2])); }); -describe('solveEquation for non = comparators', () => { +describe("solveEquation for non = comparators", () => { const tests = [ - ['x + 2 > 3', 'x > 1'], - ['2x < 6', 'x < 3'], - ['-x > 1', 'x < -1'], - ['2 - x < 3', 'x > -1'], - ['9.5j / 6+ 5.5j >= 3( 5j - 2)', 'j <= 0.7579'] + ["x + 2 > 3", "x > 1"], + ["2x < 6", "x < 3"], + ["-x > 1", "x < -1"], + ["2 - x < 3", "x > -1"], + ["9.5j / 6+ 5.5j >= 3( 5j - 2)", "j <= 0.7579"] ]; tests.forEach(t => testSolve(t[0], t[1], t[2])); }); @@ -76,53 +76,53 @@ describe('solveEquation for non = comparators', () => { function testSolveConstantEquation(equationString, expectedChange, debug=false) { const steps = solveEquation(equationString, debug); const actualChange = steps[steps.length -1].changeType; - it(equationString + ' -> ' + expectedChange, (done) => { + it(equationString + " -> " + expectedChange, (done) => { assert.equal(actualChange, expectedChange); done(); }); } -describe('constant comparison support', () => { +describe("constant comparison support", () => { const tests = [ - ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], - ['3 + 5 = 8', ChangeTypes.STATEMENT_IS_TRUE], - ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], - ['2 - 3 = 5', ChangeTypes.STATEMENT_IS_FALSE], - ['2 > 1', ChangeTypes.STATEMENT_IS_TRUE], - ['2/3 > 1/3', ChangeTypes.STATEMENT_IS_TRUE], - ['1 > 2', ChangeTypes.STATEMENT_IS_FALSE], - ['1/3 > 2/3', ChangeTypes.STATEMENT_IS_FALSE], - ['1 >= 1', ChangeTypes.STATEMENT_IS_TRUE], - ['2 >= 1', ChangeTypes.STATEMENT_IS_TRUE], - ['1 >= 2', ChangeTypes.STATEMENT_IS_FALSE], - ['2 < 1', ChangeTypes.STATEMENT_IS_FALSE], - ['2/3 < 1/3', ChangeTypes.STATEMENT_IS_FALSE], - ['1 < 2', ChangeTypes.STATEMENT_IS_TRUE], - ['1/3 < 2/3', ChangeTypes.STATEMENT_IS_TRUE], - ['1 <= 1', ChangeTypes.STATEMENT_IS_TRUE], - ['2 <= 1', ChangeTypes.STATEMENT_IS_FALSE], - ['1 <= 2', ChangeTypes.STATEMENT_IS_TRUE], - ['( 1) = ( 14)', ChangeTypes.STATEMENT_IS_FALSE], + ["1 = 2", ChangeTypes.STATEMENT_IS_FALSE], + ["3 + 5 = 8", ChangeTypes.STATEMENT_IS_TRUE], + ["1 = 2", ChangeTypes.STATEMENT_IS_FALSE], + ["2 - 3 = 5", ChangeTypes.STATEMENT_IS_FALSE], + ["2 > 1", ChangeTypes.STATEMENT_IS_TRUE], + ["2/3 > 1/3", ChangeTypes.STATEMENT_IS_TRUE], + ["1 > 2", ChangeTypes.STATEMENT_IS_FALSE], + ["1/3 > 2/3", ChangeTypes.STATEMENT_IS_FALSE], + ["1 >= 1", ChangeTypes.STATEMENT_IS_TRUE], + ["2 >= 1", ChangeTypes.STATEMENT_IS_TRUE], + ["1 >= 2", ChangeTypes.STATEMENT_IS_FALSE], + ["2 < 1", ChangeTypes.STATEMENT_IS_FALSE], + ["2/3 < 1/3", ChangeTypes.STATEMENT_IS_FALSE], + ["1 < 2", ChangeTypes.STATEMENT_IS_TRUE], + ["1/3 < 2/3", ChangeTypes.STATEMENT_IS_TRUE], + ["1 <= 1", ChangeTypes.STATEMENT_IS_TRUE], + ["2 <= 1", ChangeTypes.STATEMENT_IS_FALSE], + ["1 <= 2", ChangeTypes.STATEMENT_IS_TRUE], + ["( 1) = ( 14)", ChangeTypes.STATEMENT_IS_FALSE], // TODO: when we support fancy exponent and sqrt things // ['(1/64)^(-5/6) = 32', ChangeTypes.STATEMENT_IS_TRUE], // With variables that cancel - ['( r )/( ( r ) ) = ( 1)/( 10)', ChangeTypes.STATEMENT_IS_FALSE], - ['5 + (x - 5) = x', ChangeTypes.STATEMENT_IS_TRUE], - ['4x - 4= 4x', ChangeTypes.STATEMENT_IS_FALSE], + ["( r )/( ( r ) ) = ( 1)/( 10)", ChangeTypes.STATEMENT_IS_FALSE], + ["5 + (x - 5) = x", ChangeTypes.STATEMENT_IS_TRUE], + ["4x - 4= 4x", ChangeTypes.STATEMENT_IS_FALSE], ]; tests.forEach(t => testSolveConstantEquation(t[0], t[1], t[2])); }); function testEquationError(equationString, debug=false) { - it(equationString + ' throws error', (done) => { + it(equationString + " throws error", (done) => { assert.throws(() => solveEquation(equationString, debug),Error); done(); }); } -describe('solveEquation errors', () => { +describe("solveEquation errors", () => { const tests = [ - ['( x + 2) ^ ( 2) - x ^ ( 2) = 4( x + 1)'] + ["( x + 2) ^ ( 2) - x ^ ( 2) = 4( x + 1)"] ]; tests.forEach(t => testEquationError(t[0], t[1])); }); diff --git a/test/util/Util.test.ts b/test/util/Util.test.ts index 0cb1bc67..2d0ae8f1 100644 --- a/test/util/Util.test.ts +++ b/test/util/Util.test.ts @@ -1,20 +1,20 @@ -const assert = require('assert'); -import Util = require('../../lib/util/Util'); -describe('appendToArrayInObject', () => { - it('creates empty array', () => { +const assert = require("assert"); +import Util = require("../../lib/util/Util"); +describe("appendToArrayInObject", () => { + it("creates empty array", () => { const object = {}; - Util.appendToArrayInObject(object, 'key', 'value'); + Util.appendToArrayInObject(object, "key", "value"); assert.deepEqual( object, - {'key': ['value']} + {'key': ["value"]} ); }); - it('appends to array if it exists', () => { - const object = {'key': ['old_value']}; - Util.appendToArrayInObject(object, 'key', 'new_value'); + it("appends to array if it exists", () => { + const object = {'key': ["old_value"]}; + Util.appendToArrayInObject(object, "key", "new_value"); assert.deepEqual( object, - {'key': ['old_value', 'new_value']} + {'key': ["old_value", "new_value"]} ); }); }); diff --git a/test/util/flattenOperands.test.ts b/test/util/flattenOperands.test.ts index 7ade71fc..0fd1545b 100644 --- a/test/util/flattenOperands.test.ts +++ b/test/util/flattenOperands.test.ts @@ -1,8 +1,8 @@ -const assert = require('assert'); -import math = require('mathjs'); -import flattenOperands = require('../../lib/util/flattenOperands'); -import print = require('../../lib/util/print'); -const mathNode = require('../../lib/node'); +const assert = require("assert"); +import math = require("mathjs"); +import flattenOperands = require("../../lib/util/flattenOperands"); +import print = require("../../lib/util/print"); +const mathNode = require("../../lib/node"); function testFlatten(exprStr, afterNode, debug=false) { const flattened = flattenOperands(math.parse(exprStr)); @@ -23,71 +23,71 @@ const constNode = mathNode.Creator.constant; const symbolNode = mathNode.Creator.symbol; const parenNode = mathNode.Creator.parenthesis; -describe('flattens + and *', () => { +describe("flattens + and *", () => { const tests = [ - ['2+2', math.parse('2+2')], - ['2+2+7', opNode('+', [constNode(2), constNode(2), constNode(7)])], - ['9*8*6+3+4', - opNode('+', [ - opNode('*', [constNode(9), constNode(8), constNode(6)]), + ["2+2", math.parse("2+2")], + ["2+2+7", opNode("+", [constNode(2), constNode(2), constNode(7)])], + ["9*8*6+3+4", + opNode("+", [ + opNode("*", [constNode(9), constNode(8), constNode(6)]), constNode(3), constNode(4)])], - ['5*(2+3+2)*10', - opNode('*', [ + ["5*(2+3+2)*10", + opNode("*", [ constNode(5), - parenNode(opNode('+', [constNode(2), constNode(3),constNode(2)])), + parenNode(opNode("+", [constNode(2), constNode(3),constNode(2)])), constNode(10)])], // keeps the polynomial term - ['9x*8*6+3+4', - opNode('+', [ - opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), + ["9x*8*6+3+4", + opNode("+", [ + opNode("*", [math.parse("9x"), constNode(8), constNode(6)]), constNode(3), constNode(4)])], - ['9x*8*6+3y^2+4', - opNode('+', [ - opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), - math.parse('3y^2'), + ["9x*8*6+3y^2+4", + opNode("+", [ + opNode("*", [math.parse("9x"), constNode(8), constNode(6)]), + math.parse("3y^2"), constNode(4)])], // doesn't flatten - ['2 x ^ (2 + 1) * y', math.parse('2 x ^ (2 + 1) * y')], - ['2 x ^ (2 + 1 + 2) * y', - opNode('*', [ - opNode('*', [constNode(2), - opNode('^', [symbolNode('x'), parenNode( - opNode('+', [constNode(2), constNode(1), constNode(2)]))]), - ], true), symbolNode('y')]) + ["2 x ^ (2 + 1) * y", math.parse("2 x ^ (2 + 1) * y")], + ["2 x ^ (2 + 1 + 2) * y", + opNode("*", [ + opNode("*", [constNode(2), + opNode("^", [symbolNode("x"), parenNode( + opNode("+", [constNode(2), constNode(1), constNode(2)]))]), + ], true), symbolNode("y")]) ], - ['3x*4x', opNode('*', [math.parse('3x'), math.parse('4x')])] + ["3x*4x", opNode("*", [math.parse("3x"), math.parse("4x")])] ]; tests.forEach(t => testFlatten(t[0], t[1])); }); -describe('flattens division', () => { +describe("flattens division", () => { const tests = [ // groups x/4 and continues to flatten * - ['2 * x / 4 * 6 ', - opNode('*', [opNode('/', [ - math.parse('2x'), math.parse('4')]), constNode(6)])], - ['2*3/4/5*6', - opNode('*', [constNode(2), math.parse('3/4/5'), constNode(6)])], + ["2 * x / 4 * 6 ", + opNode("*", [opNode("/", [ + math.parse("2x"), math.parse("4")]), constNode(6)])], + ["2*3/4/5*6", + opNode("*", [constNode(2), math.parse("3/4/5"), constNode(6)])], // combines coefficient with x - ['x / (4 * x) / 8', - math.parse('x / (4x) / 8')], - ['2 x * 4 x / 8', - opNode('*', [math.parse('2x'), opNode( - '/', [math.parse('4x'), constNode(8)])])], + ["x / (4 * x) / 8", + math.parse("x / (4x) / 8")], + ["2 x * 4 x / 8", + opNode("*", [math.parse("2x"), opNode( + "/", [math.parse("4x"), constNode(8)])])], ]; tests.forEach(t => testFlatten(t[0], t[1])); }); -describe('subtraction', () => { +describe("subtraction", () => { const tests = [ - ['1 + 2 - 3 - 4 + 5', - opNode('+', [ + ["1 + 2 - 3 - 4 + 5", + opNode("+", [ constNode(1), constNode(2), constNode(-3), constNode(-4), constNode(5)])], - ['x - 3', opNode('+', [symbolNode('x'), constNode(-3)])], - ['x + 4 - (y+4)', - opNode('+', [symbolNode('x'), constNode(4), math.parse('-(y+4)')])], + ["x - 3", opNode("+", [symbolNode("x"), constNode(-3)])], + ["x + 4 - (y+4)", + opNode("+", [symbolNode("x"), constNode(4), math.parse("-(y+4)")])], ]; tests.forEach(t => testFlatten(t[0], t[1])); }); diff --git a/test/util/print.test.ts b/test/util/print.test.ts index ff8b3b52..20a36cdc 100644 --- a/test/util/print.test.ts +++ b/test/util/print.test.ts @@ -1,7 +1,7 @@ -import math = require('mathjs'); -const mathNode = require('../../lib/node'); -import print = require('../../lib/util/print'); -import TestUtil = require('../TestUtil'); +import math = require("mathjs"); +const mathNode = require("../../lib/node"); +import print = require("../../lib/util/print"); +import TestUtil = require("../TestUtil"); // to create nodes, for testing const opNode = mathNode.Creator.operator; @@ -19,30 +19,30 @@ function testPrintNode(node, outputStr) { TestUtil.testFunctionOutput(print, node, outputStr); } -describe('print asciimath', () => { +describe("print asciimath", () => { const tests = [ - ['2+3+4', '2 + 3 + 4'], - ['2 + (4 - x) + - 4', '2 + (4 - x) - 4'], - ['2/3 x^2', '2/3 x^2'], - ['-2/3', '-2/3'], + ["2+3+4", "2 + 3 + 4"], + ["2 + (4 - x) + - 4", "2 + (4 - x) - 4"], + ["2/3 x^2", "2/3 x^2"], + ["-2/3", "-2/3"], ]; tests.forEach(t => testPrintStr(t[0], t[1])); }); -describe('print with parenthesis', () => { +describe("print with parenthesis", () => { const tests = [ - [opNode('*', [ - opNode('+', [constNode(2), constNode(3)]), - symbolNode('x') - ]), '(2 + 3) * x'], - [opNode('^', [ - opNode('-', [constNode(7), constNode(4)]), - symbolNode('x') - ]), '(7 - 4)^x'], - [opNode('/', [ - opNode('+', [constNode(9), constNode(2)]), - symbolNode('x') - ]), '(9 + 2) / x'], + [opNode("*", [ + opNode("+", [constNode(2), constNode(3)]), + symbolNode("x") + ]), "(2 + 3) * x"], + [opNode("^", [ + opNode("-", [constNode(7), constNode(4)]), + symbolNode("x") + ]), "(7 - 4)^x"], + [opNode("/", [ + opNode("+", [constNode(9), constNode(2)]), + symbolNode("x") + ]), "(9 + 2) / x"], ]; tests.forEach(t => testPrintNode(t[0], t[1])); }); diff --git a/test/util/removeUnnecessaryParens.test.ts b/test/util/removeUnnecessaryParens.test.ts index 129f683c..22920f21 100644 --- a/test/util/removeUnnecessaryParens.test.ts +++ b/test/util/removeUnnecessaryParens.test.ts @@ -1,7 +1,7 @@ -import math = require('mathjs'); -import print = require('../../lib/util/print'); -import removeUnnecessaryParens = require('../../lib/util/removeUnnecessaryParens'); -import TestUtil = require('../TestUtil'); +import math = require("mathjs"); +import print = require("../../lib/util/print"); +import removeUnnecessaryParens = require("../../lib/util/removeUnnecessaryParens"); +import TestUtil = require("../TestUtil"); function testRemoveUnnecessaryParens(exprStr: any, outputStr: any); function testRemoveUnnecessaryParens(exprStr, outputStr) { @@ -9,21 +9,21 @@ function testRemoveUnnecessaryParens(exprStr, outputStr) { TestUtil.testFunctionOutput(print, input, outputStr); } -describe('removeUnnecessaryParens', () => { +describe("removeUnnecessaryParens", () => { const tests = [ - ['(x+4) + 12', 'x + 4 + 12'], - ['-(x+4x) + 12', '-(x + 4x) + 12'], - ['x + (12)', 'x + 12'], - ['x + (y)', 'x + y'], - ['x + -(y)', 'x - y'], - ['((3 - 5)) * x', '(3 - 5) * x'], - ['((3 - 5)) * x', '(3 - 5) * x'], - ['(((-5)))', '-5'], - ['((4+5)) + ((2^3))', '(4 + 5) + 2^3'], - ['(2x^6 + -50 x^2) - (x^4)', '2x^6 - 50x^2 - x^4'], - ['(x+4) - (12 + x)', 'x + 4 - (12 + x)'], - ['(2x)^2', '(2x)^2'], - ['((4+x)-5)^(2)', '(4 + x - 5)^2'], + ["(x+4) + 12", "x + 4 + 12"], + ["-(x+4x) + 12", "-(x + 4x) + 12"], + ["x + (12)", "x + 12"], + ["x + (y)", "x + y"], + ["x + -(y)", "x - y"], + ["((3 - 5)) * x", "(3 - 5) * x"], + ["((3 - 5)) * x", "(3 - 5) * x"], + ["(((-5)))", "-5"], + ["((4+5)) + ((2^3))", "(4 + 5) + 2^3"], + ["(2x^6 + -50 x^2) - (x^4)", "2x^6 - 50x^2 - x^4"], + ["(x+4) - (12 + x)", "x + 4 - (12 + x)"], + ["(2x)^2", "(2x)^2"], + ["((4+x)-5)^(2)", "(4 + x - 5)^2"], ]; tests.forEach(t => testRemoveUnnecessaryParens(t[0], t[1])); }); From af04c454d4a477d6a76d91be3c8e11f3b1bc880a Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 13:16:01 -0700 Subject: [PATCH 04/12] Clean everything for rebase --- MathSteps-Ts.njsproj | 226 --------- MathSteps-Ts.sln | 22 - index.js | 12 - index.js.map | 1 - index.ts | 10 - lib/ChangeTypes.js | 159 ------ lib/ChangeTypes.js.map | 1 - lib/ChangeTypes.ts | 186 ------- lib/Negative.js | 93 ---- lib/Negative.js.map | 1 - lib/Negative.ts | 87 ---- lib/Symbols.ts | 75 --- lib/TreeSearch.js | 59 --- lib/TreeSearch.js.map | 1 - lib/TreeSearch.ts | 57 --- lib/checks/canAddLikeTermPolynomialNodes.js | 29 -- .../canAddLikeTermPolynomialNodes.js.map | 1 - lib/checks/canAddLikeTermPolynomialNodes.ts | 32 -- .../canMultiplyLikeTermPolynomialNodes.js | 26 - .../canMultiplyLikeTermPolynomialNodes.js.map | 1 - .../canMultiplyLikeTermPolynomialNodes.ts | 29 -- lib/checks/canRearrangeCoefficient.js | 22 - lib/checks/canRearrangeCoefficient.js.map | 1 - lib/checks/canRearrangeCoefficient.ts | 26 - lib/checks/canSimplifyPolynomialTerms.js | 13 - lib/checks/canSimplifyPolynomialTerms.js.map | 1 - lib/checks/canSimplifyPolynomialTerms.ts | 13 - lib/checks/hasUnsupportedNodes.js | 34 -- lib/checks/hasUnsupportedNodes.js.map | 1 - lib/checks/hasUnsupportedNodes.ts | 34 -- lib/checks/index.js | 20 - lib/checks/index.js.map | 1 - lib/checks/index.ts | 18 - lib/checks/isQuadratic.js | 47 -- lib/checks/isQuadratic.js.map | 1 - lib/checks/isQuadratic.ts | 54 -- lib/checks/resolvesToConstant.js | 24 - lib/checks/resolvesToConstant.js.map | 1 - lib/checks/resolvesToConstant.ts | 29 -- lib/equation/Equation.js | 42 -- lib/equation/Equation.js.map | 1 - lib/equation/Equation.ts | 47 -- lib/equation/Status.js | 65 --- lib/equation/Status.js.map | 1 - lib/equation/Status.ts | 80 --- lib/equation/index.js | 10 - lib/equation/index.js.map | 1 - lib/equation/index.ts | 8 - lib/factor/ConstantFactors.js | 55 -- lib/factor/ConstantFactors.js.map | 1 - lib/factor/ConstantFactors.ts | 59 --- lib/factor/factorQuadratic.js | 184 ------- lib/factor/factorQuadratic.js.map | 1 - lib/factor/factorQuadratic.ts | 222 -------- lib/mathNode/Creator.ts | 75 --- lib/mathNode/PolynomialTerm.js | 171 ------- lib/mathNode/PolynomialTerm.js.map | 1 - lib/mathNode/PolynomialTerm.ts | 188 ------- lib/mathNode/Status.ts | 122 ----- lib/mathNode/Type.js | 110 ---- lib/mathNode/Type.js.map | 1 - lib/mathNode/Type.ts | 91 ---- lib/mathNode/index.js | 14 - lib/mathNode/index.js.map | 1 - lib/mathNode/index.ts | 12 - .../arithmeticSearch/index.js | 56 --- .../arithmeticSearch/index.js.map | 1 - .../arithmeticSearch/index.ts | 61 --- lib/simplifyExpression/basicsSearch/index.js | 59 --- .../basicsSearch/index.js.map | 1 - lib/simplifyExpression/basicsSearch/index.ts | 61 --- .../basicsSearch/rearrangeCoefficient.js | 21 - .../basicsSearch/rearrangeCoefficient.js.map | 1 - .../basicsSearch/rearrangeCoefficient.ts | 26 - .../basicsSearch/reduceExponentByZero.js | 20 - .../basicsSearch/reduceExponentByZero.js.map | 1 - .../basicsSearch/reduceExponentByZero.ts | 21 - .../reduceMultiplicationByZero.js | 28 -- .../reduceMultiplicationByZero.js.map | 1 - .../reduceMultiplicationByZero.ts | 31 -- .../reduceZeroDividedByAnything.js | 19 - .../reduceZeroDividedByAnything.js.map | 1 - .../reduceZeroDividedByAnything.ts | 20 - .../basicsSearch/removeAdditionOfZero.js | 26 - .../basicsSearch/removeAdditionOfZero.js.map | 1 - .../basicsSearch/removeAdditionOfZero.ts | 29 -- .../basicsSearch/removeDivisionByOne.js | 39 -- .../basicsSearch/removeDivisionByOne.js.map | 1 - .../basicsSearch/removeDivisionByOne.ts | 41 -- .../basicsSearch/removeExponentBaseOne.js | 19 - .../basicsSearch/removeExponentBaseOne.js.map | 1 - .../basicsSearch/removeExponentBaseOne.ts | 20 - .../basicsSearch/removeExponentByOne.js | 17 - .../basicsSearch/removeExponentByOne.js.map | 1 - .../basicsSearch/removeExponentByOne.ts | 18 - .../removeMultiplicationByNegativeOne.js | 44 -- .../removeMultiplicationByNegativeOne.js.map | 1 - .../removeMultiplicationByNegativeOne.ts | 55 -- .../basicsSearch/removeMultiplicationByOne.js | 28 -- .../removeMultiplicationByOne.js.map | 1 - .../basicsSearch/removeMultiplicationByOne.ts | 29 -- .../basicsSearch/simplifyDoubleUnaryMinus.js | 32 -- .../simplifyDoubleUnaryMinus.js.map | 1 - .../basicsSearch/simplifyDoubleUnaryMinus.ts | 37 -- .../breakUpNumeratorSearch/index.js | 38 -- .../breakUpNumeratorSearch/index.js.map | 1 - .../breakUpNumeratorSearch/index.ts | 45 -- .../LikeTermCollector.js | 236 --------- .../LikeTermCollector.js.map | 1 - .../LikeTermCollector.ts | 274 ---------- .../collectAndCombineSearch/addLikeTerms.js | 126 ----- .../addLikeTerms.js.map | 1 - .../collectAndCombineSearch/addLikeTerms.ts | 183 ------- .../evaluateConstantSum.js | 106 ---- .../evaluateConstantSum.js.map | 1 - .../evaluateConstantSum.ts | 133 ----- .../collectAndCombineSearch/index.ts | 105 ---- .../multiplyLikeTerms.js | 109 ---- .../multiplyLikeTerms.js.map | 1 - .../multiplyLikeTerms.ts | 145 ------ .../distributeSearch/index.js | 231 --------- .../distributeSearch/index.js.map | 1 - .../distributeSearch/index.ts | 291 ----------- .../divisionSearch/index.js | 68 --- .../divisionSearch/index.js.map | 1 - .../divisionSearch/index.ts | 88 ---- .../fractionsSearch/addConstantAndFraction.js | 93 ---- .../addConstantAndFraction.js.map | 1 - .../fractionsSearch/addConstantAndFraction.ts | 104 ---- .../fractionsSearch/addConstantFractions.ts | 172 ------- .../fractionsSearch/cancelLikeTerms.ts | 309 ------------ .../fractionsSearch/divideByGCD.js | 50 -- .../fractionsSearch/divideByGCD.js.map | 1 - .../fractionsSearch/divideByGCD.ts | 57 --- .../fractionsSearch/index.js | 48 -- .../fractionsSearch/index.js.map | 1 - .../fractionsSearch/index.ts | 52 -- .../fractionsSearch/simplifyFractionSigns.js | 34 -- .../simplifyFractionSigns.js.map | 1 - .../fractionsSearch/simplifyFractionSigns.ts | 35 -- .../simplifyPolynomialFraction.js | 39 -- .../simplifyPolynomialFraction.js.map | 1 - .../simplifyPolynomialFraction.ts | 44 -- .../functionsSearch/absoluteValue.js | 33 -- .../functionsSearch/absoluteValue.js.map | 1 - .../functionsSearch/absoluteValue.ts | 37 -- .../functionsSearch/index.js | 28 -- .../functionsSearch/index.js.map | 1 - .../functionsSearch/index.ts | 30 -- .../functionsSearch/nthRoot.ts | 474 ------------------ lib/simplifyExpression/index.js | 19 - lib/simplifyExpression/index.js.map | 1 - lib/simplifyExpression/index.ts | 18 - .../multiplyFractionsSearch/index.js | 48 -- .../multiplyFractionsSearch/index.js.map | 1 - .../multiplyFractionsSearch/index.ts | 56 --- lib/simplifyExpression/simplify.js | 33 -- lib/simplifyExpression/simplify.js.map | 1 - lib/simplifyExpression/simplify.ts | 35 -- lib/simplifyExpression/stepThrough.js | 120 ----- lib/simplifyExpression/stepThrough.js.map | 1 - lib/simplifyExpression/stepThrough.ts | 132 ----- lib/solveEquation/EquationOperations.js | 202 -------- lib/solveEquation/EquationOperations.js.map | 1 - lib/solveEquation/EquationOperations.ts | 227 --------- lib/solveEquation/index.js | 33 -- lib/solveEquation/index.js.map | 1 - lib/solveEquation/index.ts | 36 -- lib/solveEquation/stepThrough.js | 228 --------- lib/solveEquation/stepThrough.js.map | 1 - lib/solveEquation/stepThrough.ts | 262 ---------- lib/util/Util.js | 22 - lib/util/Util.js.map | 1 - lib/util/Util.ts | 18 - lib/util/clone.js | 19 - lib/util/clone.js.map | 1 - lib/util/clone.ts | 18 - lib/util/evaluate.js | 10 - lib/util/evaluate.js.map | 1 - lib/util/evaluate.ts | 9 - lib/util/flattenOperands.ts | 333 ------------ lib/util/print.js | 98 ---- lib/util/print.js.map | 1 - lib/util/print.ts | 108 ---- lib/util/removeUnnecessaryParens.js | 142 ------ lib/util/removeUnnecessaryParens.js.map | 1 - lib/util/removeUnnecessaryParens.ts | 177 ------- package.json | 3 +- test/Negative.test.ts | 26 - test/Node/PolynomialTerm.test.ts | 24 - test/Node/Type.test.ts | 109 ---- test/TestUtil.ts | 52 -- test/canAddLikeTermPolynomialNodes.test.ts | 16 - ...canMultiplyLikeTermPolynomialNodes.test.ts | 16 - test/canRearrangeCoefficient.test.ts | 15 - test/checks/checks.test.ts | 31 -- test/checks/hasUnsupportedNodes.test.ts | 28 -- test/checks/isQuadratic.test.ts | 29 -- test/checks/resolvesToConstant.test.ts | 18 - test/equation.test.ts | 29 -- test/factor/ConstantFactors.test.ts | 45 -- test/factor/factorQuadratic.test.ts | 35 -- .../arithmeticSearch/arithmeticSearch.test.ts | 16 - .../basicsSearch/rearrangeCoefficient.test.ts | 9 - .../basicsSearch/reduceExponentByZero.test.ts | 5 - .../reduceMutliplicationByZero.test.ts | 9 - .../reduceZeroDividedByAnything.test.ts | 9 - .../basicsSearch/removeAdditionOfZero.test.ts | 10 - .../basicsSearch/removeDivisionByOne.test.ts | 5 - .../removeExponentBaseOne.test.ts | 10 - .../basicsSearch/removeExponentByOne.test.ts | 5 - .../removeMultiplicationByNegativeOne.test.ts | 10 - .../removeMultiplicationByOne.test.ts | 11 - .../simplifyDoubleUnaryMinus.test.ts | 9 - .../basicsSearch/testSimplify.ts | 17 - .../breakUpNumeratorSearch.test.ts | 16 - .../LikeTermCollector.test.ts | 96 ---- .../collectAndCombineSearch.test.ts | 63 --- .../evaluateConstantSum.test.ts | 33 -- .../distributeSearch/distributeSearch.test.ts | 90 ---- .../divisionSearch/divisionSearch.test.ts | 21 - .../addConstantAndFraction.test.ts | 32 -- .../addConstantFractions.test.ts | 38 -- .../fractionsSearch/cancelLikeTerms.test.ts | 33 -- .../fractionsSearch/divideByGCD.test.ts | 19 - .../simplifyFractionSigns.test.ts | 15 - .../simplifyPolynomialFraction.test.ts | 20 - .../functionsSearch/absoluteValue.test.ts | 15 - .../functionsSearch/nthRoot.test.ts | 73 --- .../multiplyFractionsSearch.test.ts | 16 - test/simplifyExpression/oneStep.test.ts | 94 ---- test/simplifyExpression/simplify.test.ts | 166 ------ test/solveEquation/solveEquation.test.ts | 128 ----- test/util/Util.test.ts | 20 - test/util/flattenOperands.test.ts | 102 ---- test/util/print.test.ts | 48 -- test/util/removeUnnecessaryParens.test.ts | 29 -- 237 files changed, 2 insertions(+), 11893 deletions(-) delete mode 100644 MathSteps-Ts.njsproj delete mode 100644 MathSteps-Ts.sln delete mode 100644 index.js delete mode 100644 index.js.map delete mode 100644 index.ts delete mode 100644 lib/ChangeTypes.js delete mode 100644 lib/ChangeTypes.js.map delete mode 100644 lib/ChangeTypes.ts delete mode 100644 lib/Negative.js delete mode 100644 lib/Negative.js.map delete mode 100644 lib/Negative.ts delete mode 100644 lib/Symbols.ts delete mode 100644 lib/TreeSearch.js delete mode 100644 lib/TreeSearch.js.map delete mode 100644 lib/TreeSearch.ts delete mode 100644 lib/checks/canAddLikeTermPolynomialNodes.js delete mode 100644 lib/checks/canAddLikeTermPolynomialNodes.js.map delete mode 100644 lib/checks/canAddLikeTermPolynomialNodes.ts delete mode 100644 lib/checks/canMultiplyLikeTermPolynomialNodes.js delete mode 100644 lib/checks/canMultiplyLikeTermPolynomialNodes.js.map delete mode 100644 lib/checks/canMultiplyLikeTermPolynomialNodes.ts delete mode 100644 lib/checks/canRearrangeCoefficient.js delete mode 100644 lib/checks/canRearrangeCoefficient.js.map delete mode 100644 lib/checks/canRearrangeCoefficient.ts delete mode 100644 lib/checks/canSimplifyPolynomialTerms.js delete mode 100644 lib/checks/canSimplifyPolynomialTerms.js.map delete mode 100644 lib/checks/canSimplifyPolynomialTerms.ts delete mode 100644 lib/checks/hasUnsupportedNodes.js delete mode 100644 lib/checks/hasUnsupportedNodes.js.map delete mode 100644 lib/checks/hasUnsupportedNodes.ts delete mode 100644 lib/checks/index.js delete mode 100644 lib/checks/index.js.map delete mode 100644 lib/checks/index.ts delete mode 100644 lib/checks/isQuadratic.js delete mode 100644 lib/checks/isQuadratic.js.map delete mode 100644 lib/checks/isQuadratic.ts delete mode 100644 lib/checks/resolvesToConstant.js delete mode 100644 lib/checks/resolvesToConstant.js.map delete mode 100644 lib/checks/resolvesToConstant.ts delete mode 100644 lib/equation/Equation.js delete mode 100644 lib/equation/Equation.js.map delete mode 100644 lib/equation/Equation.ts delete mode 100644 lib/equation/Status.js delete mode 100644 lib/equation/Status.js.map delete mode 100644 lib/equation/Status.ts delete mode 100644 lib/equation/index.js delete mode 100644 lib/equation/index.js.map delete mode 100644 lib/equation/index.ts delete mode 100644 lib/factor/ConstantFactors.js delete mode 100644 lib/factor/ConstantFactors.js.map delete mode 100644 lib/factor/ConstantFactors.ts delete mode 100644 lib/factor/factorQuadratic.js delete mode 100644 lib/factor/factorQuadratic.js.map delete mode 100644 lib/factor/factorQuadratic.ts delete mode 100644 lib/mathNode/Creator.ts delete mode 100644 lib/mathNode/PolynomialTerm.js delete mode 100644 lib/mathNode/PolynomialTerm.js.map delete mode 100644 lib/mathNode/PolynomialTerm.ts delete mode 100644 lib/mathNode/Status.ts delete mode 100644 lib/mathNode/Type.js delete mode 100644 lib/mathNode/Type.js.map delete mode 100644 lib/mathNode/Type.ts delete mode 100644 lib/mathNode/index.js delete mode 100644 lib/mathNode/index.js.map delete mode 100644 lib/mathNode/index.ts delete mode 100644 lib/simplifyExpression/arithmeticSearch/index.js delete mode 100644 lib/simplifyExpression/arithmeticSearch/index.js.map delete mode 100644 lib/simplifyExpression/arithmeticSearch/index.ts delete mode 100644 lib/simplifyExpression/basicsSearch/index.js delete mode 100644 lib/simplifyExpression/basicsSearch/index.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/index.ts delete mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js delete mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts delete mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.js delete mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts delete mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js delete mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts delete mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js delete mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js delete mode 100644 lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeDivisionByOne.js delete mode 100644 lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.js delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/removeExponentByOne.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js delete mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts delete mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js delete mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts delete mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js delete mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map delete mode 100644 lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts delete mode 100644 lib/simplifyExpression/breakUpNumeratorSearch/index.js delete mode 100644 lib/simplifyExpression/breakUpNumeratorSearch/index.js.map delete mode 100644 lib/simplifyExpression/breakUpNumeratorSearch/index.ts delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/index.ts delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map delete mode 100644 lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts delete mode 100644 lib/simplifyExpression/distributeSearch/index.js delete mode 100644 lib/simplifyExpression/distributeSearch/index.js.map delete mode 100644 lib/simplifyExpression/distributeSearch/index.ts delete mode 100644 lib/simplifyExpression/divisionSearch/index.js delete mode 100644 lib/simplifyExpression/divisionSearch/index.js.map delete mode 100644 lib/simplifyExpression/divisionSearch/index.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js delete mode 100644 lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map delete mode 100644 lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/addConstantFractions.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/divideByGCD.js delete mode 100644 lib/simplifyExpression/fractionsSearch/divideByGCD.js.map delete mode 100644 lib/simplifyExpression/fractionsSearch/divideByGCD.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/index.js delete mode 100644 lib/simplifyExpression/fractionsSearch/index.js.map delete mode 100644 lib/simplifyExpression/fractionsSearch/index.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js delete mode 100644 lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map delete mode 100644 lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts delete mode 100644 lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js delete mode 100644 lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map delete mode 100644 lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts delete mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.js delete mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.js.map delete mode 100644 lib/simplifyExpression/functionsSearch/absoluteValue.ts delete mode 100644 lib/simplifyExpression/functionsSearch/index.js delete mode 100644 lib/simplifyExpression/functionsSearch/index.js.map delete mode 100644 lib/simplifyExpression/functionsSearch/index.ts delete mode 100644 lib/simplifyExpression/functionsSearch/nthRoot.ts delete mode 100644 lib/simplifyExpression/index.js delete mode 100644 lib/simplifyExpression/index.js.map delete mode 100644 lib/simplifyExpression/index.ts delete mode 100644 lib/simplifyExpression/multiplyFractionsSearch/index.js delete mode 100644 lib/simplifyExpression/multiplyFractionsSearch/index.js.map delete mode 100644 lib/simplifyExpression/multiplyFractionsSearch/index.ts delete mode 100644 lib/simplifyExpression/simplify.js delete mode 100644 lib/simplifyExpression/simplify.js.map delete mode 100644 lib/simplifyExpression/simplify.ts delete mode 100644 lib/simplifyExpression/stepThrough.js delete mode 100644 lib/simplifyExpression/stepThrough.js.map delete mode 100644 lib/simplifyExpression/stepThrough.ts delete mode 100644 lib/solveEquation/EquationOperations.js delete mode 100644 lib/solveEquation/EquationOperations.js.map delete mode 100644 lib/solveEquation/EquationOperations.ts delete mode 100644 lib/solveEquation/index.js delete mode 100644 lib/solveEquation/index.js.map delete mode 100644 lib/solveEquation/index.ts delete mode 100644 lib/solveEquation/stepThrough.js delete mode 100644 lib/solveEquation/stepThrough.js.map delete mode 100644 lib/solveEquation/stepThrough.ts delete mode 100644 lib/util/Util.js delete mode 100644 lib/util/Util.js.map delete mode 100644 lib/util/Util.ts delete mode 100644 lib/util/clone.js delete mode 100644 lib/util/clone.js.map delete mode 100644 lib/util/clone.ts delete mode 100644 lib/util/evaluate.js delete mode 100644 lib/util/evaluate.js.map delete mode 100644 lib/util/evaluate.ts delete mode 100644 lib/util/flattenOperands.ts delete mode 100644 lib/util/print.js delete mode 100644 lib/util/print.js.map delete mode 100644 lib/util/print.ts delete mode 100644 lib/util/removeUnnecessaryParens.js delete mode 100644 lib/util/removeUnnecessaryParens.js.map delete mode 100644 lib/util/removeUnnecessaryParens.ts delete mode 100644 test/Negative.test.ts delete mode 100644 test/Node/PolynomialTerm.test.ts delete mode 100644 test/Node/Type.test.ts delete mode 100644 test/TestUtil.ts delete mode 100644 test/canAddLikeTermPolynomialNodes.test.ts delete mode 100644 test/canMultiplyLikeTermPolynomialNodes.test.ts delete mode 100644 test/canRearrangeCoefficient.test.ts delete mode 100644 test/checks/checks.test.ts delete mode 100644 test/checks/hasUnsupportedNodes.test.ts delete mode 100644 test/checks/isQuadratic.test.ts delete mode 100644 test/checks/resolvesToConstant.test.ts delete mode 100644 test/equation.test.ts delete mode 100644 test/factor/ConstantFactors.test.ts delete mode 100644 test/factor/factorQuadratic.test.ts delete mode 100644 test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts delete mode 100644 test/simplifyExpression/basicsSearch/testSimplify.ts delete mode 100644 test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts delete mode 100644 test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts delete mode 100644 test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts delete mode 100644 test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts delete mode 100644 test/simplifyExpression/distributeSearch/distributeSearch.test.ts delete mode 100644 test/simplifyExpression/divisionSearch/divisionSearch.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/divideByGCD.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts delete mode 100644 test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts delete mode 100644 test/simplifyExpression/functionsSearch/absoluteValue.test.ts delete mode 100644 test/simplifyExpression/functionsSearch/nthRoot.test.ts delete mode 100644 test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts delete mode 100644 test/simplifyExpression/oneStep.test.ts delete mode 100644 test/simplifyExpression/simplify.test.ts delete mode 100644 test/solveEquation/solveEquation.test.ts delete mode 100644 test/util/Util.test.ts delete mode 100644 test/util/flattenOperands.test.ts delete mode 100644 test/util/print.test.ts delete mode 100644 test/util/removeUnnecessaryParens.test.ts diff --git a/MathSteps-Ts.njsproj b/MathSteps-Ts.njsproj deleted file mode 100644 index c5f36ccf..00000000 --- a/MathSteps-Ts.njsproj +++ /dev/null @@ -1,226 +0,0 @@ - - - - Debug - 2.0 - {d741bb67-79e4-48ae-91fe-723afef84328} - - ShowAllFiles - index.ts - . - . - {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD} - true - CommonJS - true - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - True - 0 - / - http://localhost:48022/ - False - True - http://localhost:1337 - False - - - - - - - CurrentPage - True - False - False - False - - - - - - - - - False - False - - - - - \ No newline at end of file diff --git a/MathSteps-Ts.sln b/MathSteps-Ts.sln deleted file mode 100644 index 6f69851b..00000000 --- a/MathSteps-Ts.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "MathSteps-Ts", "MathSteps-Ts.njsproj", "{D741BB67-79E4-48AE-91FE-723AFEF84328}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D741BB67-79E4-48AE-91FE-723AFEF84328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D741BB67-79E4-48AE-91FE-723AFEF84328}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D741BB67-79E4-48AE-91FE-723AFEF84328}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D741BB67-79E4-48AE-91FE-723AFEF84328}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/index.js b/index.js deleted file mode 100644 index e90ae9c4..00000000 --- a/index.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -var ChangeTypes = require("./lib/ChangeTypes"); -var simplifyExpression = require("./lib/simplifyExpression"); -var solveEquation = require("./lib/solveEquation"); -var tmp; -tmp = { - simplifyExpression: simplifyExpression, - solveEquation: solveEquation, - ChangeTypes: ChangeTypes, -}; -module.exports = tmp; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/index.js.map b/index.js.map deleted file mode 100644 index 174e5983..00000000 --- a/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,6DAAgE;AAChE,mDAAsD;AACtD,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,kBAAkB,oBAAA;IAClB,aAAa,eAAA;IACb,WAAW,aAAA;CACd,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/index.ts b/index.ts deleted file mode 100644 index 7df68bd6..00000000 --- a/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import ChangeTypes = require("./lib/ChangeTypes"); -import simplifyExpression = require("./lib/simplifyExpression"); -import solveEquation = require("./lib/solveEquation"); -var tmp; -tmp = { - simplifyExpression, - solveEquation, - ChangeTypes, -}; -export = tmp; diff --git a/lib/ChangeTypes.js b/lib/ChangeTypes.js deleted file mode 100644 index 862f06c7..00000000 --- a/lib/ChangeTypes.js +++ /dev/null @@ -1,159 +0,0 @@ -// The text to identify rules for each possible step that can be taken -"use strict"; -var tmp; -tmp = { - NO_CHANGE: 'NO_CHANGE', - // ARITHMETIC - // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 - SIMPLIFY_ARITHMETIC: 'SIMPLIFY_ARITHMETIC', - // BASICS - // e.g. 2/-1 -> -2 - DIVISION_BY_NEGATIVE_ONE: 'DIVISION_BY_NEGATIVE_ONE', - // e.g. 2/1 -> 2 - DIVISION_BY_ONE: 'DIVISION_BY_ONE', - // e.g. x * 0 -> 0 - MULTIPLY_BY_ZERO: 'MULTIPLY_BY_ZERO', - // e.g. x * 2 -> 2x - REARRANGE_COEFF: 'REARRANGE_COEFF', - // e.g. x ^ 0 -> 1 - REDUCE_EXPONENT_BY_ZERO: 'REDUCE_EXPONENT_BY_ZERO', - // e.g. 0/1 -> 0 - REDUCE_ZERO_NUMERATOR: 'REDUCE_ZERO_NUMERATOR', - // e.g. 2 + 0 -> 2 - REMOVE_ADDING_ZERO: 'REMOVE_ADDING_ZERO', - // e.g. x ^ 1 -> x - REMOVE_EXPONENT_BY_ONE: 'REMOVE_EXPONENT_BY_ONE', - // e.g. 1 ^ x -> 1 - REMOVE_EXPONENT_BASE_ONE: 'REMOVE_EXPONENT_BASE_ONE', - // e.g. x * -1 -> -x - REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: 'REMOVE_MULTIPLYING_BY_NEGATIVE_ONE', - // e.g. x * 1 -> x - REMOVE_MULTIPLYING_BY_ONE: 'REMOVE_MULTIPLYING_BY_ONE', - // e.g. 2 - - 3 -> 2 + 3 - RESOLVE_DOUBLE_MINUS: 'RESOLVE_DOUBLE_MINUS', - // COLLECT AND COMBINE - // e.g. 2 + x + 3 + x -> 5 + 2x - COLLECT_AND_COMBINE_LIKE_TERMS: 'COLLECT_AND_COMBINE_LIKE_TERMS', - // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) - COLLECT_LIKE_TERMS: 'COLLECT_LIKE_TERMS', - // ADDING POLYNOMIALS - // e.g. 2x + x -> 2x + 1x - ADD_COEFFICIENT_OF_ONE: 'ADD_COEFFICIENT_OF_ONE', - // e.g. x^2 + x^2 -> 2x^2 - ADD_POLYNOMIAL_TERMS: 'ADD_POLYNOMIAL_TERMS', - // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 - GROUP_COEFFICIENTS: 'GROUP_COEFFICIENTS', - // e.g. -x + 2x => -1*x + 2x - UNARY_MINUS_TO_NEGATIVE_ONE: 'UNARY_MINUS_TO_NEGATIVE_ONE', - // MULTIPLYING POLYNOMIALS - // e.g. x^2 * x -> x^2 * x^1 - ADD_EXPONENT_OF_ONE: 'ADD_EXPONENT_OF_ONE', - // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) - COLLECT_EXPONENTS: 'COLLECT_EXPONENTS', - // e.g. 2x * 3x -> (2 * 3)(x * x) - MULTIPLY_COEFFICIENTS: 'MULTIPLY_COEFFICIENTS', - // e.g. 2x * x -> 2x ^ 2 - MULTIPLY_POLYNOMIAL_TERMS: 'MULTIPLY_POLYNOMIAL_TERMS', - // FRACTIONS - // e.g. (x + 2)/2 -> x/2 + 2/2 - BREAK_UP_FRACTION: 'BREAK_UP_FRACTION', - // e.g. -2/-3 => 2/3 - CANCEL_MINUSES: 'CANCEL_MINUSES', - // e.g. 2x/2 -> x - CANCEL_TERMS: 'CANCEL_TERMS', - // e.g. 2/6 -> 1/3 - SIMPLIFY_FRACTION: 'SIMPLIFY_FRACTION', - // e.g. 2/-3 -> -2/3 - SIMPLIFY_SIGNS: 'SIMPLIFY_SIGNS', - // ADDING FRACTIONS - // e.g. 1/2 + 1/3 -> 5/6 - ADD_FRACTIONS: 'ADD_FRACTIONS', - // e.g. (1 + 2)/3 -> 3/3 - ADD_NUMERATORS: 'ADD_NUMERATORS', - // e.g. (2+1)/5 - COMBINE_NUMERATORS: 'COMBINE_NUMERATORS', - // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) - COMMON_DENOMINATOR: 'COMMON_DENOMINATOR', - // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) - CONVERT_INTEGER_TO_FRACTION: 'CONVERT_INTEGER_TO_FRACTION', - // e.g. 1.2 + 1/2 -> 1.2 + 0.5 - DIVIDE_FRACTION_FOR_ADDITION: 'DIVIDE_FRACTION_FOR_ADDITION', - // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 - MULTIPLY_DENOMINATORS: 'MULTIPLY_DENOMINATORS', - // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 - MULTIPLY_NUMERATORS: 'MULTIPLY_NUMERATORS', - // MULTIPLYING FRACTIONS - // e.g. 1/2 * 2/3 -> 2/6 - MULTIPLY_FRACTIONS: 'MULTIPLY_FRACTIONS', - // DIVISION - // e.g. 2/3/4 -> 2/(3*4) - SIMPLIFY_DIVISION: 'SIMPLIFY_DIVISION', - // e.g. x/(2/3) -> x * 3/2 - MULTIPLY_BY_INVERSE: 'MULTIPLY_BY_INVERSE', - // DISTRIBUTION - // e.g. 2(x + y) -> 2x + 2y - DISTRIBUTE: 'DISTRIBUTE', - // e.g. -(2 + x) -> -2 - x - DISTRIBUTE_NEGATIVE_ONE: 'DISTRIBUTE_NEGATIVE_ONE', - // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) - SIMPLIFY_TERMS: 'SIMPLIFY_TERMS', - // ABSOLUTE - // e.g. |-3| -> 3 - ABSOLUTE_VALUE: 'ABSOLUTE_VALUE', - // ROOTS - // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) - CANCEL_EXPONENT: 'CANCEL_EXPONENT', - // e.g. nthRoot(x ^ 2, 2) -> x - CANCEL_EXPONENT_AND_ROOT: 'CANCEL_EXPONENT_AND_ROOT', - // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 - CANCEL_ROOT: 'CANCEL_ROOT', - // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) - COMBINE_UNDER_ROOT: 'COMBINE_UNDER_ROOT', - // e.g. 2 * 2 * 2 -> 2 ^ 3 - CONVERT_MULTIPLICATION_TO_EXPONENT: 'CONVERT_MULTIPLICATION_TO_EXPONENT', - // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) - DISTRIBUTE_NTH_ROOT: 'DISTRIBUTE_NTH_ROOT', - // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x - EVALUATE_DISTRIBUTED_NTH_ROOT: 'EVALUATE_DISTRIBUTED_NTH_ROOT', - // e.g. 12 -> 2 * 2 * 3 - FACTOR_INTO_PRIMES: 'FACTOR_INTO_PRIMES', - // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) - GROUP_TERMS_BY_ROOT: 'GROUP_TERMS_BY_ROOT', - // e.g. nthRoot(4) -> 2 - NTH_ROOT_VALUE: 'NTH_ROOT_VALUE', - // SOLVING FOR A VARIABLE - // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 - ADD_TO_BOTH_SIDES: 'ADD_TO_BOTH_SIDES', - // e.g. 2x = 1 -> (2x)/2 = 1/2 - DIVIDE_FROM_BOTH_SIDES: 'DIVIDE_FROM_BOTH_SIDES', - // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) - MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: 'MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION', - // e.g. -x = 2 -> -1 * -x = -1 * 2 - MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: 'MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE', - // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 - MULTIPLY_TO_BOTH_SIDES: 'MULTIPLY_TO_BOTH_SIDES', - // e.g. x + 2 - 1 = 3 -> x + 1 = 3 - SIMPLIFY_LEFT_SIDE: 'SIMPLIFY_LEFT_SIDE', - // e.g. x = 3 - 1 -> x = 2 - SIMPLIFY_RIGHT_SIDE: 'SIMPLIFY_RIGHT_SIDE', - // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 - SUBTRACT_FROM_BOTH_SIDES: 'SUBTRACT_FROM_BOTH_SIDES', - // e.g. 2 = x -> x = 2 - SWAP_SIDES: 'SWAP_SIDES', - // CONSTANT EQUATION - // e.g. 2 = 2 - STATEMENT_IS_TRUE: 'STATEMENT_IS_TRUE', - // e.g. 2 = 3 - STATEMENT_IS_FALSE: 'STATEMENT_IS_FALSE', - // FACTORING - // e.g. x^2 - 4x -> x(x - 4) - FACTOR_SYMBOL: 'FACTOR_SYMBOL', - // e.g. x^2 - 4 -> (x - 2)(x + 2) - FACTOR_DIFFERENCE_OF_SQUARES: 'FACTOR_DIFFERENCE_OF_SQUARES', - // e.g. x^2 + 2x + 1 -> (x + 1)^2 - FACTOR_PERFECT_SQUARE: 'FACTOR_PERFECT_SQUARE', - // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) - FACTOR_SUM_PRODUCT_RULE: 'FACTOR_SUM_PRODUCT_RULE', -}; -module.exports = tmp; -//# sourceMappingURL=ChangeTypes.js.map \ No newline at end of file diff --git a/lib/ChangeTypes.js.map b/lib/ChangeTypes.js.map deleted file mode 100644 index ed45886e..00000000 --- a/lib/ChangeTypes.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ChangeTypes.js","sourceRoot":"","sources":["ChangeTypes.ts"],"names":[],"mappings":"AAAA,sEAAsE;;AAEtE,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,SAAS,EAAE,WAAW;IAEtB,aAAa;IAEb,gCAAgC;IAChC,mBAAmB,EAAE,qBAAqB;IAE1C,SAAS;IAET,kBAAkB;IAClB,wBAAwB,EAAE,0BAA0B;IACpD,gBAAgB;IAChB,eAAe,EAAE,iBAAiB;IAClC,kBAAkB;IAClB,gBAAgB,EAAE,kBAAkB;IACpC,mBAAmB;IACnB,eAAe,EAAE,iBAAiB;IAClC,kBAAkB;IAClB,uBAAuB,EAAE,yBAAyB;IAClD,gBAAgB;IAChB,qBAAqB,EAAE,uBAAuB;IAC9C,kBAAkB;IAClB,kBAAkB,EAAE,oBAAoB;IACxC,kBAAkB;IAClB,sBAAsB,EAAE,wBAAwB;IAChD,kBAAkB;IAClB,wBAAwB,EAAE,0BAA0B;IACpD,oBAAoB;IACpB,kCAAkC,EAAE,oCAAoC;IACxE,kBAAkB;IAClB,yBAAyB,EAAE,2BAA2B;IACtD,wBAAwB;IACxB,oBAAoB,EAAE,sBAAsB;IAE5C,sBAAsB;IAEtB,+BAA+B;IAC/B,8BAA8B,EAAE,gCAAgC;IAChE,sDAAsD;IACtD,kBAAkB,EAAE,oBAAoB;IAExC,qBAAqB;IAErB,yBAAyB;IACzB,sBAAsB,EAAE,wBAAwB;IAChD,yBAAyB;IACzB,oBAAoB,EAAE,sBAAsB;IAC5C,wCAAwC;IACxC,kBAAkB,EAAE,oBAAoB;IACxC,4BAA4B;IAC5B,2BAA2B,EAAE,6BAA6B;IAE1D,0BAA0B;IAE1B,4BAA4B;IAC5B,mBAAmB,EAAE,qBAAqB;IAC1C,wCAAwC;IACxC,iBAAiB,EAAE,mBAAmB;IACtC,iCAAiC;IACjC,qBAAqB,EAAE,uBAAuB;IAC9C,wBAAwB;IACxB,yBAAyB,EAAE,2BAA2B;IAEtD,YAAY;IAEZ,8BAA8B;IAC9B,iBAAiB,EAAE,mBAAmB;IACtC,oBAAoB;IACpB,cAAc,EAAE,gBAAgB;IAChC,iBAAiB;IACjB,YAAY,EAAE,cAAc;IAC5B,kBAAkB;IAClB,iBAAiB,EAAE,mBAAmB;IACtC,oBAAoB;IACpB,cAAc,EAAE,gBAAgB;IAEhC,mBAAmB;IAEnB,wBAAwB;IACxB,aAAa,EAAE,eAAe;IAC9B,wBAAwB;IACxB,cAAc,EAAE,gBAAgB;IAChC,eAAe;IACf,kBAAkB,EAAE,oBAAoB;IACxC,8CAA8C;IAC9C,kBAAkB,EAAE,oBAAoB;IACxC,2CAA2C;IAC3C,2BAA2B,EAAE,6BAA6B;IAC1D,8BAA8B;IAC9B,4BAA4B,EAAE,8BAA8B;IAC5D,wDAAwD;IACxD,qBAAqB,EAAE,uBAAuB;IAC9C,0CAA0C;IAC1C,mBAAmB,EAAE,qBAAqB;IAE1C,wBAAwB;IAExB,wBAAwB;IACxB,kBAAkB,EAAE,oBAAoB;IAExC,WAAW;IAEX,wBAAwB;IACxB,iBAAiB,EAAE,mBAAmB;IACtC,0BAA0B;IAC1B,mBAAmB,EAAE,qBAAqB;IAE1C,eAAe;IAEf,2BAA2B;IAC3B,UAAU,EAAE,YAAY;IACxB,0BAA0B;IAC1B,uBAAuB,EAAE,yBAAyB;IAClD,0DAA0D;IAC1D,cAAc,EAAE,gBAAgB;IAEhC,WAAW;IACX,iBAAiB;IACjB,cAAc,EAAE,gBAAgB;IAEhC,QAAQ;IACR,0CAA0C;IAC1C,eAAe,EAAE,iBAAiB;IAClC,8BAA8B;IAC9B,wBAAwB,EAAE,0BAA0B;IACpD,kCAAkC;IAClC,WAAW,EAAE,aAAa;IAC1B,0DAA0D;IAC1D,kBAAkB,EAAE,oBAAoB;IACxC,0BAA0B;IAC1B,kCAAkC,EAAE,oCAAoC;IACxE,iDAAiD;IACjD,mBAAmB,EAAE,qBAAqB;IAC1C,0CAA0C;IAC1C,6BAA6B,EAAE,+BAA+B;IAC9D,uBAAuB;IACvB,kBAAkB,EAAE,oBAAoB;IACxC,qDAAqD;IACrD,mBAAmB,EAAE,qBAAqB;IAC1C,uBAAuB;IACvB,cAAc,EAAE,gBAAgB;IAEhC,yBAAyB;IAEzB,sCAAsC;IACtC,iBAAiB,EAAE,mBAAmB;IACtC,8BAA8B;IAC9B,sBAAsB,EAAE,wBAAwB;IAChD,gDAAgD;IAChD,uCAAuC,EAAE,yCAAyC;IAClF,kCAAkC;IAClC,mCAAmC,EAAE,qCAAqC;IAC1E,oCAAoC;IACpC,sBAAsB,EAAE,wBAAwB;IAChD,kCAAkC;IAClC,kBAAkB,EAAE,oBAAoB;IACxC,0BAA0B;IAC1B,mBAAmB,EAAE,qBAAqB;IAC1C,sCAAsC;IACtC,wBAAwB,EAAE,0BAA0B;IACpD,sBAAsB;IACtB,UAAU,EAAE,YAAY;IAExB,oBAAoB;IAEpB,aAAa;IACb,iBAAiB,EAAE,mBAAmB;IACtC,aAAa;IACb,kBAAkB,EAAE,oBAAoB;IAExC,YAAY;IAEZ,4BAA4B;IAC5B,aAAa,EAAE,eAAe;IAC9B,iCAAiC;IACjC,4BAA4B,EAAE,8BAA8B;IAC5D,iCAAiC;IACjC,qBAAqB,EAAE,uBAAuB;IAC9C,sCAAsC;IACtC,uBAAuB,EAAE,yBAAyB;CACrD,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/ChangeTypes.ts b/lib/ChangeTypes.ts deleted file mode 100644 index c90e6510..00000000 --- a/lib/ChangeTypes.ts +++ /dev/null @@ -1,186 +0,0 @@ -// The text to identify rules for each possible step that can be taken - -var tmp; -tmp = { - NO_CHANGE: "NO_CHANGE", - - // ARITHMETIC - - // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 - SIMPLIFY_ARITHMETIC: "SIMPLIFY_ARITHMETIC", - - // BASICS - - // e.g. 2/-1 -> -2 - DIVISION_BY_NEGATIVE_ONE: "DIVISION_BY_NEGATIVE_ONE", - // e.g. 2/1 -> 2 - DIVISION_BY_ONE: "DIVISION_BY_ONE", - // e.g. x * 0 -> 0 - MULTIPLY_BY_ZERO: "MULTIPLY_BY_ZERO", - // e.g. x * 2 -> 2x - REARRANGE_COEFF: "REARRANGE_COEFF", - // e.g. x ^ 0 -> 1 - REDUCE_EXPONENT_BY_ZERO: "REDUCE_EXPONENT_BY_ZERO", - // e.g. 0/1 -> 0 - REDUCE_ZERO_NUMERATOR: "REDUCE_ZERO_NUMERATOR", - // e.g. 2 + 0 -> 2 - REMOVE_ADDING_ZERO: "REMOVE_ADDING_ZERO", - // e.g. x ^ 1 -> x - REMOVE_EXPONENT_BY_ONE: "REMOVE_EXPONENT_BY_ONE", - // e.g. 1 ^ x -> 1 - REMOVE_EXPONENT_BASE_ONE: "REMOVE_EXPONENT_BASE_ONE", - // e.g. x * -1 -> -x - REMOVE_MULTIPLYING_BY_NEGATIVE_ONE: "REMOVE_MULTIPLYING_BY_NEGATIVE_ONE", - // e.g. x * 1 -> x - REMOVE_MULTIPLYING_BY_ONE: "REMOVE_MULTIPLYING_BY_ONE", - // e.g. 2 - - 3 -> 2 + 3 - RESOLVE_DOUBLE_MINUS: "RESOLVE_DOUBLE_MINUS", - - // COLLECT AND COMBINE - - // e.g. 2 + x + 3 + x -> 5 + 2x - COLLECT_AND_COMBINE_LIKE_TERMS: "COLLECT_AND_COMBINE_LIKE_TERMS", - // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) - COLLECT_LIKE_TERMS: "COLLECT_LIKE_TERMS", - - // ADDING POLYNOMIALS - - // e.g. 2x + x -> 2x + 1x - ADD_COEFFICIENT_OF_ONE: "ADD_COEFFICIENT_OF_ONE", - // e.g. x^2 + x^2 -> 2x^2 - ADD_POLYNOMIAL_TERMS: "ADD_POLYNOMIAL_TERMS", - // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 - GROUP_COEFFICIENTS: "GROUP_COEFFICIENTS", - // e.g. -x + 2x => -1*x + 2x - UNARY_MINUS_TO_NEGATIVE_ONE: "UNARY_MINUS_TO_NEGATIVE_ONE", - - // MULTIPLYING POLYNOMIALS - - // e.g. x^2 * x -> x^2 * x^1 - ADD_EXPONENT_OF_ONE: "ADD_EXPONENT_OF_ONE", - // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) - COLLECT_EXPONENTS: "COLLECT_EXPONENTS", - // e.g. 2x * 3x -> (2 * 3)(x * x) - MULTIPLY_COEFFICIENTS: "MULTIPLY_COEFFICIENTS", - // e.g. 2x * x -> 2x ^ 2 - MULTIPLY_POLYNOMIAL_TERMS: "MULTIPLY_POLYNOMIAL_TERMS", - - // FRACTIONS - - // e.g. (x + 2)/2 -> x/2 + 2/2 - BREAK_UP_FRACTION: "BREAK_UP_FRACTION", - // e.g. -2/-3 => 2/3 - CANCEL_MINUSES: "CANCEL_MINUSES", - // e.g. 2x/2 -> x - CANCEL_TERMS: "CANCEL_TERMS", - // e.g. 2/6 -> 1/3 - SIMPLIFY_FRACTION: "SIMPLIFY_FRACTION", - // e.g. 2/-3 -> -2/3 - SIMPLIFY_SIGNS: "SIMPLIFY_SIGNS", - - // ADDING FRACTIONS - - // e.g. 1/2 + 1/3 -> 5/6 - ADD_FRACTIONS: "ADD_FRACTIONS", - // e.g. (1 + 2)/3 -> 3/3 - ADD_NUMERATORS: "ADD_NUMERATORS", - // e.g. (2+1)/5 - COMBINE_NUMERATORS: "COMBINE_NUMERATORS", - // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) - COMMON_DENOMINATOR: "COMMON_DENOMINATOR", - // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) - CONVERT_INTEGER_TO_FRACTION: "CONVERT_INTEGER_TO_FRACTION", - // e.g. 1.2 + 1/2 -> 1.2 + 0.5 - DIVIDE_FRACTION_FOR_ADDITION: "DIVIDE_FRACTION_FOR_ADDITION", - // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 - MULTIPLY_DENOMINATORS: "MULTIPLY_DENOMINATORS", - // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 - MULTIPLY_NUMERATORS: "MULTIPLY_NUMERATORS", - - // MULTIPLYING FRACTIONS - - // e.g. 1/2 * 2/3 -> 2/6 - MULTIPLY_FRACTIONS: "MULTIPLY_FRACTIONS", - - // DIVISION - - // e.g. 2/3/4 -> 2/(3*4) - SIMPLIFY_DIVISION: "SIMPLIFY_DIVISION", - // e.g. x/(2/3) -> x * 3/2 - MULTIPLY_BY_INVERSE: "MULTIPLY_BY_INVERSE", - - // DISTRIBUTION - - // e.g. 2(x + y) -> 2x + 2y - DISTRIBUTE: "DISTRIBUTE", - // e.g. -(2 + x) -> -2 - x - DISTRIBUTE_NEGATIVE_ONE: "DISTRIBUTE_NEGATIVE_ONE", - // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) - SIMPLIFY_TERMS: "SIMPLIFY_TERMS", - - // ABSOLUTE - // e.g. |-3| -> 3 - ABSOLUTE_VALUE: "ABSOLUTE_VALUE", - - // ROOTS - // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) - CANCEL_EXPONENT: "CANCEL_EXPONENT", - // e.g. nthRoot(x ^ 2, 2) -> x - CANCEL_EXPONENT_AND_ROOT: "CANCEL_EXPONENT_AND_ROOT", - // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 - CANCEL_ROOT: "CANCEL_ROOT", - // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) - COMBINE_UNDER_ROOT: "COMBINE_UNDER_ROOT", - // e.g. 2 * 2 * 2 -> 2 ^ 3 - CONVERT_MULTIPLICATION_TO_EXPONENT: "CONVERT_MULTIPLICATION_TO_EXPONENT", - // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) - DISTRIBUTE_NTH_ROOT: "DISTRIBUTE_NTH_ROOT", - // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x - EVALUATE_DISTRIBUTED_NTH_ROOT: "EVALUATE_DISTRIBUTED_NTH_ROOT", - // e.g. 12 -> 2 * 2 * 3 - FACTOR_INTO_PRIMES: "FACTOR_INTO_PRIMES", - // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) - GROUP_TERMS_BY_ROOT: "GROUP_TERMS_BY_ROOT", - // e.g. nthRoot(4) -> 2 - NTH_ROOT_VALUE: "NTH_ROOT_VALUE", - - // SOLVING FOR A VARIABLE - - // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 - ADD_TO_BOTH_SIDES: "ADD_TO_BOTH_SIDES", - // e.g. 2x = 1 -> (2x)/2 = 1/2 - DIVIDE_FROM_BOTH_SIDES: "DIVIDE_FROM_BOTH_SIDES", - // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) - MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION: "MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION", - // e.g. -x = 2 -> -1 * -x = -1 * 2 - MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE: "MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE", - // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 - MULTIPLY_TO_BOTH_SIDES: "MULTIPLY_TO_BOTH_SIDES", - // e.g. x + 2 - 1 = 3 -> x + 1 = 3 - SIMPLIFY_LEFT_SIDE: "SIMPLIFY_LEFT_SIDE", - // e.g. x = 3 - 1 -> x = 2 - SIMPLIFY_RIGHT_SIDE: "SIMPLIFY_RIGHT_SIDE", - // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 - SUBTRACT_FROM_BOTH_SIDES: "SUBTRACT_FROM_BOTH_SIDES", - // e.g. 2 = x -> x = 2 - SWAP_SIDES: "SWAP_SIDES", - - // CONSTANT EQUATION - - // e.g. 2 = 2 - STATEMENT_IS_TRUE: "STATEMENT_IS_TRUE", - // e.g. 2 = 3 - STATEMENT_IS_FALSE: "STATEMENT_IS_FALSE", - - // FACTORING - - // e.g. x^2 - 4x -> x(x - 4) - FACTOR_SYMBOL: "FACTOR_SYMBOL", - // e.g. x^2 - 4 -> (x - 2)(x + 2) - FACTOR_DIFFERENCE_OF_SQUARES: "FACTOR_DIFFERENCE_OF_SQUARES", - // e.g. x^2 + 2x + 1 -> (x + 1)^2 - FACTOR_PERFECT_SQUARE: "FACTOR_PERFECT_SQUARE", - // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) - FACTOR_SUM_PRODUCT_RULE: "FACTOR_SUM_PRODUCT_RULE", -}; -export = tmp; diff --git a/lib/Negative.js b/lib/Negative.js deleted file mode 100644 index 9ad59ce0..00000000 --- a/lib/Negative.js +++ /dev/null @@ -1,93 +0,0 @@ -"use strict"; -var mathNode = require("./mathNode"); -var Negative = (function () { - function Negative() { - } - // Returns if the given node is negative. Treats a unary minus as a negative, - // as well as a negative constant value or a constant fraction that would - // evaluate to a negative number - Negative.isNegative = function (node) { - if (mathNode.Type.isUnaryMinus(node)) { - return !Negative.isNegative(node.args[0]); - } - else if (mathNode.Type.isConstant(node)) { - return parseFloat(node.value) < 0; - } - else if (mathNode.Type.isConstantFraction(node)) { - var numeratorValue = parseFloat(node.args[0].value); - var denominatorValue = parseFloat(node.args[1].value); - if (numeratorValue < 0 || denominatorValue < 0) { - return !(numeratorValue < 0 && denominatorValue < 0); - } - } - else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - var polyNode = new mathNode.PolynomialTerm(node); - return Negative.isNegative(polyNode.getCoeffNode(true)); - } - return false; - }; - // Given a node, returns the negated node - // If naive is true, then we just add an extra unary minus to the expression - // otherwise, we do the actual negation - // E.g. - // not naive: -3 -> 3, x -> -x - // naive: -3 -> --3, x -> -x - Negative.negate = function (node, naive) { - if (naive === void 0) { naive = false; } - if (mathNode.Type.isConstantFraction(node)) { - node.args[0] = Negative.negate(node.args[0], naive); - return node; - } - else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - return Negative.negatePolynomialTerm(node, naive); - } - else if (!naive) { - if (mathNode.Type.isUnaryMinus(node)) { - return node.args[0]; - } - else if (mathNode.Type.isConstant(node)) { - return mathNode.Creator.constant(0 - parseFloat(node.value)); - } - } - return mathNode.Creator.unaryMinus(node); - }; - // Multiplies a polynomial term by -1 and returns the new node - // If naive is true, then we just add an extra unary minus to the expression - // otherwise, we do the actual negation - // E.g. - // not naive: -3x -> 3x, x -> -x - // naive: -3x -> --3x, x -> -x - Negative.negatePolynomialTerm = function (node, naive) { - if (naive === void 0) { naive = false; } - if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { - throw Error("node is not a polynomial term"); - } - var polyNode = new mathNode.PolynomialTerm(node); - var newCoeff; - if (!polyNode.hasCoeff()) { - newCoeff = mathNode.Creator.constant(-1); - } - else { - var oldCoeff = polyNode.getCoeffNode(); - if (oldCoeff.value === "-1") { - newCoeff = null; - } - else if (polyNode.hasFractionCoeff()) { - var numerator = oldCoeff.args[0]; - numerator = Negative.negate(numerator, naive); - var denominator = oldCoeff.args[1]; - newCoeff = mathNode.Creator.operator("/", [numerator, denominator]); - } - else { - newCoeff = Negative.negate(oldCoeff, naive); - if (newCoeff.value === "1") { - newCoeff = null; - } - } - } - return mathNode.Creator.polynomialTerm(polyNode.getSymbolNode(), polyNode.getExponentNode(), newCoeff); - }; - return Negative; -}()); -module.exports = Negative; -//# sourceMappingURL=Negative.js.map \ No newline at end of file diff --git a/lib/Negative.js.map b/lib/Negative.js.map deleted file mode 100644 index b82cc6b8..00000000 --- a/lib/Negative.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Negative.js","sourceRoot":"","sources":["Negative.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Negative.ts b/lib/Negative.ts deleted file mode 100644 index dbb23e53..00000000 --- a/lib/Negative.ts +++ /dev/null @@ -1,87 +0,0 @@ -import mathNode = require("./mathNode"); - -class Negative { -// Returns if the given node is negative. Treats a unary minus as a negative, -// as well as a negative constant value or a constant fraction that would -// evaluate to a negative number - static isNegative(node: mathjs.MathNode) { - if (mathNode.Type.isUnaryMinus(node)) { - return !Negative.isNegative(node.args[0]); - } else if (mathNode.Type.isConstant(node)) { - return parseFloat(node.value) < 0; - } else if (mathNode.Type.isConstantFraction(node)) { - const numeratorValue = parseFloat(node.args[0].value); - const denominatorValue = parseFloat(node.args[1].value); - if (numeratorValue < 0 || denominatorValue < 0) { - return !(numeratorValue < 0 && denominatorValue < 0); - } - } else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - const polyNode = new mathNode.PolynomialTerm(node); - return Negative.isNegative(polyNode.getCoeffNode(true)); - } - - return false; - } - -// Given a node, returns the negated node -// If naive is true, then we just add an extra unary minus to the expression -// otherwise, we do the actual negation -// E.g. -// not naive: -3 -> 3, x -> -x -// naive: -3 -> --3, x -> -x - static negate(node: mathjs.MathNode, naive: boolean=false) { - if (mathNode.Type.isConstantFraction(node)) { - node.args[0] = Negative.negate(node.args[0], naive); - return node; - } else if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - return Negative.negatePolynomialTerm(node, naive); - } else if (!naive) { - if (mathNode.Type.isUnaryMinus(node)) { - return node.args[0]; - } else if (mathNode.Type.isConstant(node)) { - return mathNode.Creator.constant(0 - parseFloat(node.value)); - } - } - return mathNode.Creator.unaryMinus(node); - } - -// Multiplies a polynomial term by -1 and returns the new node -// If naive is true, then we just add an extra unary minus to the expression -// otherwise, we do the actual negation -// E.g. -// not naive: -3x -> 3x, x -> -x -// naive: -3x -> --3x, x -> -x - static negatePolynomialTerm(node: mathjs.MathNode, naive: boolean = false) { - if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { - throw Error("node is not a polynomial term"); - } - const polyNode = new mathNode.PolynomialTerm(node); - - let newCoeff; - if (!polyNode.hasCoeff()) { - newCoeff = mathNode.Creator.constant(-1); - } else { - const oldCoeff = polyNode.getCoeffNode(); - if (oldCoeff.value === "-1") { - newCoeff = null; - } else if (polyNode.hasFractionCoeff()) { - let numerator = oldCoeff.args[0]; - numerator = Negative.negate(numerator, naive); - - const denominator = oldCoeff.args[1]; - newCoeff = mathNode.Creator.operator("/", [numerator, denominator]); - } else { - newCoeff = Negative.negate(oldCoeff, naive); - if (newCoeff.value === "1") { - newCoeff = null; - } - } - } - return mathNode.Creator.polynomialTerm( - polyNode.getSymbolNode(), - polyNode.getExponentNode(), - newCoeff); - } -} - -export = Negative; diff --git a/lib/Symbols.ts b/lib/Symbols.ts deleted file mode 100644 index 1a6ea217..00000000 --- a/lib/Symbols.ts +++ /dev/null @@ -1,75 +0,0 @@ -import mathNode = require("./mathNode"); - -class Symbols { - // returns the set of all the symbols in an equation - static getSymbolsInEquation(equation) { - const leftSymbols = Symbols.getSymbolsInExpression(equation.leftNode); - const rightSymbols = Symbols.getSymbolsInExpression(equation.rightNode); - const symbols = new Set([...leftSymbols, ...rightSymbols]); - return symbols; - }; - - -// return the set of symbols in the expression tree - static getSymbolsInExpression = expression => { - const symbolNodes = expression.filter(node => node.isSymbolNode); // all the symbol nodes - const symbols = symbolNodes.map(node => node.name); // all the symbol nodes' names - const symbolSet = new Set(symbols); // to get rid of duplicates - return symbolSet; - }; - -// Iterates through a node and returns the polynomial term with the symbol name -// Returns null if no terms with the symbol name are in the node. -// e.g. 4x^2 + 2x + y + 2 with `symbolName=x` would return 2x - static getLastSymbolTerm = (node, symbolName) => { - // First check if the node itself is a polyomial term with symbolName - if (Symbols.isSymbolTerm(node, symbolName)) { - return node; - } - // Otherwise, it's a sum of terms. Look through the operands for a term - // with `symbolName` - else if (mathNode.Type.isOperator(node, "+")) { - for (let i = node.args.length - 1; i >= 0; i--) { - const child = node.args[i]; - if (Symbols.isSymbolTerm(child, symbolName)) { - return child; - } - } - } - return null; - }; - -// Iterates through a node and returns the last term that does not have the -// symbolName including other polynomial terms, and constants or constant -// fractions -// e.g. 4x^2 with `symbolName=x` would return 4 -// e.g. 4x^2 + 2x + 2/4 with `symbolName=x` would return 2/4 -// e.g. 4x^2 + 2x + y with `symbolName=x` would return y - static getLastNonSymbolTerm = (node, symbolName) => { - if (Symbols.isSymbolTerm(node, symbolName)) { - return new mathNode.PolynomialTerm(node).getCoeffNode(); - } else if (mathNode.Type.isOperator(node)) { - for (let i = node.args.length - 1; i >= 0; i--) { - const child = node.args[i]; - if (!Symbols.isSymbolTerm(child, symbolName)) { - return child; - } - } - } - - return null; - }; - -// Returns if `node` is a polynomial term with symbol `symbolName` - static isSymbolTerm(node: mathjs.MathNode, symbolName) { - if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - const polyTerm = new mathNode.PolynomialTerm(node); - if (polyTerm.getSymbolName() === symbolName) { - return true; - } - } - return false; - } -} - -export = Symbols; diff --git a/lib/TreeSearch.js b/lib/TreeSearch.js deleted file mode 100644 index 1c3d400b..00000000 --- a/lib/TreeSearch.js +++ /dev/null @@ -1,59 +0,0 @@ -"use strict"; -var mathNode = require("./mathNode"); -var TreeSearch = (function () { - function TreeSearch() { - var _this = this; - // Returns a function that performs a preorder search on the tree for the given - // simplifcation function - this.preOrder = function (simplificationFunction) { return function (node) { return _this.search(simplificationFunction, node, true); }; }; - // Returns a function that performs a postorder search on the tree for the given - // simplifcation function - this.postOrder = function (simplificationFunction) { return function (node) { return _this.search(simplificationFunction, node, false); }; }; - } - // A helper function for performing a tree search with a function - TreeSearch.prototype.search = function (simplificationFunction, node, preOrder) { - var status; - if (preOrder) { - status = simplificationFunction(node); - if (status.hasChanged()) { - return status; - } - } - if (mathNode.Type.isConstant(node) || mathNode.Type.isSymbol(node)) { - return mathNode.Status.noChange(node); - } - else if (mathNode.Type.isUnaryMinus(node)) { - status = this.search(simplificationFunction, node.args[0], preOrder); - if (status.hasChanged()) { - return mathNode.Status.childChanged(node, status); - } - } - else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { - for (var i = 0; i < node.args.length; i++) { - var child = node.args[i]; - var childNodeStatus = this.search(simplificationFunction, child, preOrder); - if (childNodeStatus.hasChanged()) { - return mathNode.Status.childChanged(node, childNodeStatus, i); - } - } - } - else if (mathNode.Type.isParenthesis(node)) { - status = this.search(simplificationFunction, node.content, preOrder); - if (status.hasChanged()) { - return mathNode.Status.childChanged(node, status); - } - } - else { - throw Error('Unsupported node type: ' + node); - } - if (!preOrder) { - return simplificationFunction(node); - } - else { - return mathNode.Status.noChange(node); - } - }; - return TreeSearch; -}()); -module.exports = TreeSearch; -//# sourceMappingURL=TreeSearch.js.map \ No newline at end of file diff --git a/lib/TreeSearch.js.map b/lib/TreeSearch.js.map deleted file mode 100644 index 319c9ec7..00000000 --- a/lib/TreeSearch.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"TreeSearch.js","sourceRoot":"","sources":["TreeSearch.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/TreeSearch.ts b/lib/TreeSearch.ts deleted file mode 100644 index e7643b8d..00000000 --- a/lib/TreeSearch.ts +++ /dev/null @@ -1,57 +0,0 @@ -/// -import mathNode = require("./mathNode"); -class TreeSearch { - -// Returns a function that performs a preorder search on the tree for the given -// simplifcation function - static preOrder = simplificationFunction => node => TreeSearch.search(simplificationFunction, node, true); - -// Returns a function that performs a postorder search on the tree for the given -// simplifcation function - static postOrder = simplificationFunction => node => TreeSearch.search(simplificationFunction, node, false); - -// A helper function for performing a tree search with a function - - static search(simplificationFunction, node: mathjs.MathNode, preOrder) { - let status; - - if (preOrder) { - status = simplificationFunction(node); - if (status.hasChanged()) { - return status; - } - } - - if (mathNode.Type.isConstant(node) || mathNode.Type.isSymbol(node)) { - return mathNode.Status.noChange(node); - } else if (mathNode.Type.isUnaryMinus(node)) { - status = this.search(simplificationFunction, node.args[0], preOrder); - if (status.hasChanged()) { - return mathNode.Status.childChanged(node, status); - } - } else if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { - for (let i = 0; i < node.args.length; i++) { - const child = node.args[i]; - const childNodeStatus = this.search(simplificationFunction, child, preOrder); - if (childNodeStatus.hasChanged()) { - return mathNode.Status.childChanged(node, childNodeStatus, i); - } - } - } else if (mathNode.Type.isParenthesis(node)) { - status = this.search(simplificationFunction, node.content, preOrder); - if (status.hasChanged()) { - return mathNode.Status.childChanged(node, status); - } - } else { - throw Error("Unsupported node type: " + node); - } - - if (!preOrder) { - return simplificationFunction(node); - } else { - return mathNode.Status.noChange(node); - } - } -} - -export = TreeSearch; diff --git a/lib/checks/canAddLikeTermPolynomialNodes.js b/lib/checks/canAddLikeTermPolynomialNodes.js deleted file mode 100644 index c64d4384..00000000 --- a/lib/checks/canAddLikeTermPolynomialNodes.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -var mathNode = require("../mathnode"); -// Returns true if the nodes are polynomial terms that can be added together. -function canAddLikeTermPolynomialNodes(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "+") { - return false; - } - var args = node.args; - if (!args.every(function (n) { return mathNode.PolynomialTerm.isPolynomialTerm(n); })) { - return false; - } - if (args.length === 1) { - return false; - } - var polynomialTermList = args.map(function (n) { return new mathNode.PolynomialTerm(n); }); - // to add terms, they must have the same symbol name *and* exponent - var firstTerm = polynomialTermList[0]; - var sharedSymbol = firstTerm.getSymbolName(); - var sharedExponentNode = firstTerm.getExponentNode(true); - var restTerms = polynomialTermList.slice(1); - return restTerms.every(function (term) { - var haveSameSymbol = sharedSymbol === term.getSymbolName(); - var exponentNode = term.getExponentNode(true); - var haveSameExponent = exponentNode.equals(sharedExponentNode); - return haveSameSymbol && haveSameExponent; - }); -} -module.exports = canAddLikeTermPolynomialNodes; -//# sourceMappingURL=canAddLikeTermPolynomialNodes.js.map \ No newline at end of file diff --git a/lib/checks/canAddLikeTermPolynomialNodes.js.map b/lib/checks/canAddLikeTermPolynomialNodes.js.map deleted file mode 100644 index 47da1209..00000000 --- a/lib/checks/canAddLikeTermPolynomialNodes.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"canAddLikeTermPolynomialNodes.js","sourceRoot":"","sources":["canAddLikeTermPolynomialNodes.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAEzC,6EAA6E;AAC7E,uCAAuC,IAAqB;IAC1D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAA,CAAC,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAA3C,CAA2C,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAA9B,CAA8B,CAAC,CAAC;IAEzE,mEAAmE;IACnE,IAAM,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACxC,IAAM,YAAY,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;IAC/C,IAAM,kBAAkB,GAAG,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3D,IAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,UAAA,IAAI;QACzB,IAAM,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7D,IAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAChD,IAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACjE,MAAM,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iBAAS,6BAA6B,CAAC"} \ No newline at end of file diff --git a/lib/checks/canAddLikeTermPolynomialNodes.ts b/lib/checks/canAddLikeTermPolynomialNodes.ts deleted file mode 100644 index fe82272c..00000000 --- a/lib/checks/canAddLikeTermPolynomialNodes.ts +++ /dev/null @@ -1,32 +0,0 @@ -import mathNode = require("../mathnode"); - -// Returns true if the nodes are polynomial terms that can be added together. -function canAddLikeTermPolynomialNodes(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "+") { - return false; - } - const args = node.args; - if (!args.every(n => mathNode.PolynomialTerm.isPolynomialTerm(n))) { - return false; - } - if (args.length === 1) { - return false; - } - - const polynomialTermList = args.map(n => new mathNode.PolynomialTerm(n)); - - // to add terms, they must have the same symbol name *and* exponent - const firstTerm = polynomialTermList[0]; - const sharedSymbol = firstTerm.getSymbolName(); - const sharedExponentNode = firstTerm.getExponentNode(true); - - const restTerms = polynomialTermList.slice(1); - return restTerms.every(term => { - const haveSameSymbol = sharedSymbol === term.getSymbolName(); - const exponentNode = term.getExponentNode(true); - const haveSameExponent = exponentNode.equals(sharedExponentNode); - return haveSameSymbol && haveSameExponent; - }); -} - -export = canAddLikeTermPolynomialNodes; diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.js b/lib/checks/canMultiplyLikeTermPolynomialNodes.js deleted file mode 100644 index 7e1b5f8f..00000000 --- a/lib/checks/canMultiplyLikeTermPolynomialNodes.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -var mathNode = require("../mathnode"); -// Returns true if the nodes are symbolic terms with the same symbol and no -// coefficients. -function canMultiplyLikeTermPolynomialNodes(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return false; - } - var args = node.args; - if (!args.every(function (n) { return mathNode.PolynomialTerm.isPolynomialTerm(n); })) { - return false; - } - if (args.length === 1) { - return false; - } - var polynomialTermList = node.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); - if (!polynomialTermList.every(function (polyTerm) { return !polyTerm.hasCoeff(); })) { - return false; - } - var firstTerm = polynomialTermList[0]; - var restTerms = polynomialTermList.slice(1); - // they're considered like terms if they have the same symbol name - return restTerms.every(function (term) { return firstTerm.getSymbolName() === term.getSymbolName(); }); -} -module.exports = canMultiplyLikeTermPolynomialNodes; -//# sourceMappingURL=canMultiplyLikeTermPolynomialNodes.js.map \ No newline at end of file diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.js.map b/lib/checks/canMultiplyLikeTermPolynomialNodes.js.map deleted file mode 100644 index 578b5d6a..00000000 --- a/lib/checks/canMultiplyLikeTermPolynomialNodes.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"canMultiplyLikeTermPolynomialNodes.js","sourceRoot":"","sources":["canMultiplyLikeTermPolynomialNodes.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAGzC,2EAA2E;AAC3E,gBAAgB;AAChB,4CAA4C,IAAqB;IAC/D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAA,CAAC,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAA3C,CAA2C,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAA9B,CAA8B,CAAC,CAAC;IAC9E,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,UAAA,QAAQ,IAAI,OAAA,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAApB,CAAoB,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACxC,IAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9C,kEAAkE;IAClE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,UAAA,IAAI,IAAI,OAAA,SAAS,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,aAAa,EAAE,EAAlD,CAAkD,CAAC,CAAC;AACrF,CAAC;AAED,iBAAS,kCAAkC,CAAC"} \ No newline at end of file diff --git a/lib/checks/canMultiplyLikeTermPolynomialNodes.ts b/lib/checks/canMultiplyLikeTermPolynomialNodes.ts deleted file mode 100644 index 8caed1a6..00000000 --- a/lib/checks/canMultiplyLikeTermPolynomialNodes.ts +++ /dev/null @@ -1,29 +0,0 @@ -import mathNode = require("../mathnode"); - - -// Returns true if the nodes are symbolic terms with the same symbol and no -// coefficients. -function canMultiplyLikeTermPolynomialNodes(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return false; - } - const args = node.args; - if (!args.every(n => mathNode.PolynomialTerm.isPolynomialTerm(n))) { - return false; - } - if (args.length === 1) { - return false; - } - - const polynomialTermList = node.args.map(n => new mathNode.PolynomialTerm(n)); - if (!polynomialTermList.every(polyTerm => !polyTerm.hasCoeff())) { - return false; - } - - const firstTerm = polynomialTermList[0]; - const restTerms = polynomialTermList.slice(1); - // they're considered like terms if they have the same symbol name - return restTerms.every(term => firstTerm.getSymbolName() === term.getSymbolName()); -} - -export = canMultiplyLikeTermPolynomialNodes; diff --git a/lib/checks/canRearrangeCoefficient.js b/lib/checks/canRearrangeCoefficient.js deleted file mode 100644 index 83028413..00000000 --- a/lib/checks/canRearrangeCoefficient.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -var mathNode = require("../mathnode"); -function canRearrangeCoefficient(node) { - // implicit multiplication doesn't count as multiplication here, since it - // represents a single term. - if (node.op !== "*" || node.implicit) { - return false; - } - if (node.args.length !== 2) { - return false; - } - if (!mathNode.Type.isConstantOrConstantFraction(node.args[1])) { - return false; - } - if (!mathNode.PolynomialTerm.isPolynomialTerm(node.args[0])) { - return false; - } - var polyNode = new mathNode.PolynomialTerm(node.args[0]); - return !polyNode.hasCoeff(); -} -module.exports = canRearrangeCoefficient; -//# sourceMappingURL=canRearrangeCoefficient.js.map \ No newline at end of file diff --git a/lib/checks/canRearrangeCoefficient.js.map b/lib/checks/canRearrangeCoefficient.js.map deleted file mode 100644 index e4ed75cb..00000000 --- a/lib/checks/canRearrangeCoefficient.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"canRearrangeCoefficient.js","sourceRoot":"","sources":["canRearrangeCoefficient.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAMzC,iCAAiC,IAAI;IACnC,yEAAyE;IACzE,4BAA4B;IAC5B,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED,iBAAS,uBAAuB,CAAC"} \ No newline at end of file diff --git a/lib/checks/canRearrangeCoefficient.ts b/lib/checks/canRearrangeCoefficient.ts deleted file mode 100644 index dcfd0c96..00000000 --- a/lib/checks/canRearrangeCoefficient.ts +++ /dev/null @@ -1,26 +0,0 @@ -import mathNode = require("../mathnode"); - - -// Returns true if the expression is a multiplication between a constant -// and polynomial without a coefficient. -function canRearrangeCoefficient(node: mathjs.MathNode) { - // implicit multiplication doesn't count as multiplication here, since it - // represents a single term. - if (node.op !== "*" || node.implicit) { - return false; - } - if (node.args.length !== 2) { - return false; - } - if (!mathNode.Type.isConstantOrConstantFraction(node.args[1])) { - return false; - } - if (!mathNode.PolynomialTerm.isPolynomialTerm(node.args[0])) { - return false; - } - - const polyNode = new mathNode.PolynomialTerm(node.args[0]); - return !polyNode.hasCoeff(); -} - -export = canRearrangeCoefficient; diff --git a/lib/checks/canSimplifyPolynomialTerms.js b/lib/checks/canSimplifyPolynomialTerms.js deleted file mode 100644 index 14680ce1..00000000 --- a/lib/checks/canSimplifyPolynomialTerms.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -var canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); -var canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); -var canRearrangeCoefficient = require("./canRearrangeCoefficient"); -// Returns true if the node is an operation node with parameters that are -// polynomial terms that can be combined in some way. -function canSimplifyPolynomialTerms(node) { - return (canAddLikeTermPolynomialNodes(node) || - canMultiplyLikeTermPolynomialNodes(node) || - canRearrangeCoefficient(node)); -} -module.exports = canSimplifyPolynomialTerms; -//# sourceMappingURL=canSimplifyPolynomialTerms.js.map \ No newline at end of file diff --git a/lib/checks/canSimplifyPolynomialTerms.js.map b/lib/checks/canSimplifyPolynomialTerms.js.map deleted file mode 100644 index 7a2c6ed1..00000000 --- a/lib/checks/canSimplifyPolynomialTerms.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"canSimplifyPolynomialTerms.js","sourceRoot":"","sources":["canSimplifyPolynomialTerms.ts"],"names":[],"mappings":";AAAA,+EAAkF;AAClF,yFAA4F;AAC5F,mEAAsE;AAEtE,yEAAyE;AACzE,qDAAqD;AACrD,oCAAoC,IAAqB;IACvD,MAAM,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC;QACnC,kCAAkC,CAAC,IAAI,CAAC;QACxC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/checks/canSimplifyPolynomialTerms.ts b/lib/checks/canSimplifyPolynomialTerms.ts deleted file mode 100644 index 0d2ff413..00000000 --- a/lib/checks/canSimplifyPolynomialTerms.ts +++ /dev/null @@ -1,13 +0,0 @@ -import canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); -import canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); -import canRearrangeCoefficient = require("./canRearrangeCoefficient"); - -// Returns true if the node is an operation node with parameters that are -// polynomial terms that can be combined in some way. -function canSimplifyPolynomialTerms(node: mathjs.MathNode) { - return (canAddLikeTermPolynomialNodes(node) || - canMultiplyLikeTermPolynomialNodes(node) || - canRearrangeCoefficient(node)); -} - -export = canSimplifyPolynomialTerms; diff --git a/lib/checks/hasUnsupportedNodes.js b/lib/checks/hasUnsupportedNodes.js deleted file mode 100644 index 78e19f8d..00000000 --- a/lib/checks/hasUnsupportedNodes.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -var mathNode = require("../mathnode"); -var resolvesToConstant = require("./resolvesToConstant"); -function hasUnsupportedNodes(node) { - if (mathNode.Type.isParenthesis(node)) { - return hasUnsupportedNodes(node.content); - } - else if (mathNode.Type.isUnaryMinus(node)) { - return hasUnsupportedNodes(node.args[0]); - } - else if (mathNode.Type.isOperator(node)) { - return node.args.some(hasUnsupportedNodes); - } - else if (mathNode.Type.isSymbol(node) || mathNode.Type.isConstant(node)) { - return false; - } - else if (mathNode.Type.isFunction(node, "abs")) { - if (node.args.length !== 1) { - return true; - } - if (node.args.some(hasUnsupportedNodes)) { - return true; - } - return !resolvesToConstant(node.args[0]); - } - else if (mathNode.Type.isFunction(node, "nthRoot")) { - return node.args.some(hasUnsupportedNodes) || node.args.length < 1; - } - else { - return true; - } -} -module.exports = hasUnsupportedNodes; -//# sourceMappingURL=hasUnsupportedNodes.js.map \ No newline at end of file diff --git a/lib/checks/hasUnsupportedNodes.js.map b/lib/checks/hasUnsupportedNodes.js.map deleted file mode 100644 index b2d2f030..00000000 --- a/lib/checks/hasUnsupportedNodes.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"hasUnsupportedNodes.js","sourceRoot":"","sources":["hasUnsupportedNodes.ts"],"names":[],"mappings":";AAAA,sCAAyC;AACzC,yDAA4D;AAG5D,6BAA6B,IAAI;IAC/B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/C,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/checks/hasUnsupportedNodes.ts b/lib/checks/hasUnsupportedNodes.ts deleted file mode 100644 index e38dad45..00000000 --- a/lib/checks/hasUnsupportedNodes.ts +++ /dev/null @@ -1,34 +0,0 @@ -import mathNode = require("../mathnode"); -import resolvesToConstant = require("./resolvesToConstant"); - -function hasUnsupportedNodes(node: mathjs.MathNode) { - if (mathNode.Type.isParenthesis(node)) { - return hasUnsupportedNodes(node.content); - } - else if (mathNode.Type.isUnaryMinus(node)) { - return hasUnsupportedNodes(node.args[0]); - } - else if (mathNode.Type.isOperator(node)) { - return node.args.some(hasUnsupportedNodes); - } - else if (mathNode.Type.isSymbol(node) || mathNode.Type.isConstant(node)) { - return false; - } - else if (mathNode.Type.isFunction(node, "abs")) { - if (node.args.length !== 1) { - return true; - } - if (node.args.some(hasUnsupportedNodes)) { - return true; - } - return !resolvesToConstant(node.args[0]); - } - else if (mathNode.Type.isFunction(node, "nthRoot")) { - return node.args.some(hasUnsupportedNodes) || node.args.length < 1; - } - else { - return true; - } -} - -export = hasUnsupportedNodes; diff --git a/lib/checks/index.js b/lib/checks/index.js deleted file mode 100644 index 414e8a91..00000000 --- a/lib/checks/index.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -var canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); -var canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); -var canRearrangeCoefficient = require("./canRearrangeCoefficient"); -var canSimplifyPolynomialTerms = require("./canSimplifyPolynomialTerms"); -var hasUnsupportedNodes = require("./hasUnsupportedNodes"); -var isQuadratic = require("./isQuadratic"); -var resolvesToConstant = require("./resolvesToConstant"); -var tmp; -tmp = { - canAddLikeTermPolynomialNodes: canAddLikeTermPolynomialNodes, - canMultiplyLikeTermPolynomialNodes: canMultiplyLikeTermPolynomialNodes, - canRearrangeCoefficient: canRearrangeCoefficient, - canSimplifyPolynomialTerms: canSimplifyPolynomialTerms, - hasUnsupportedNodes: hasUnsupportedNodes, - isQuadratic: isQuadratic, - resolvesToConstant: resolvesToConstant, -}; -module.exports = tmp; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/checks/index.js.map b/lib/checks/index.js.map deleted file mode 100644 index 2c6ec142..00000000 --- a/lib/checks/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+EAAkF;AAClF,yFAA4F;AAC5F,mEAAsE;AACtE,yEAA4E;AAC5E,2DAA8D;AAC9D,2CAA8C;AAC9C,yDAA4D;AAC5D,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,6BAA6B,+BAAA;IAC7B,kCAAkC,oCAAA;IAClC,uBAAuB,yBAAA;IACvB,0BAA0B,4BAAA;IAC1B,mBAAmB,qBAAA;IACnB,WAAW,aAAA;IACX,kBAAkB,oBAAA;CACrB,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/checks/index.ts b/lib/checks/index.ts deleted file mode 100644 index 6db90d19..00000000 --- a/lib/checks/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import canAddLikeTermPolynomialNodes = require("./canAddLikeTermPolynomialNodes"); -import canMultiplyLikeTermPolynomialNodes = require("./canMultiplyLikeTermPolynomialNodes"); -import canRearrangeCoefficient = require("./canRearrangeCoefficient"); -import canSimplifyPolynomialTerms = require("./canSimplifyPolynomialTerms"); -import hasUnsupportedNodes = require("./hasUnsupportedNodes"); -import isQuadratic = require("./isQuadratic"); -import resolvesToConstant = require("./resolvesToConstant"); -var tmp; -tmp = { - canAddLikeTermPolynomialNodes, - canMultiplyLikeTermPolynomialNodes, - canRearrangeCoefficient, - canSimplifyPolynomialTerms, - hasUnsupportedNodes, - isQuadratic, - resolvesToConstant, -}; -export = tmp; diff --git a/lib/checks/isQuadratic.js b/lib/checks/isQuadratic.js deleted file mode 100644 index 6d75149c..00000000 --- a/lib/checks/isQuadratic.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; -var mathNode = require("../mathnode"); -var Symbols = require("../Symbols"); -// Given a node, will determine if the expression is in the form of a quadratic -// e.g. `x^2 + 2x + 1` OR `x^2 - 1` but not `x^3 + x^2 + x + 1` -function isQuadratic(node) { - if (!mathNode.Type.isOperator(node, "+")) { - return false; - } - if (node.args.length > 3) { - return false; - } - // make sure only one symbol appears in the expression - var symbolSet = Symbols.getSymbolsInExpression(node); - if (symbolSet.size !== 1) { - return false; - } - var secondDegreeTerms = node.args.filter(isPolynomialTermOfDegree(2)); - var firstDegreeTerms = node.args.filter(isPolynomialTermOfDegree(1)); - var constantTerms = node.args.filter(mathNode.Type.isConstant); - // Check that there is one second degree term and at most one first degree - // term and at most one constant term - if (secondDegreeTerms.length !== 1 || firstDegreeTerms.length > 1 || - constantTerms.length > 1) { - return false; - } - // check that there are no terms that don't fall into these groups - if ((secondDegreeTerms.length + firstDegreeTerms.length + - constantTerms.length) !== node.args.length) { - return false; - } - return true; -} -// Given a degree, returns a function that checks if a node -// is a polynomial term of the given degree. -function isPolynomialTermOfDegree(degree) { - return function (node) { - if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - var polyTerm = new mathNode.PolynomialTerm(node); - var exponent = polyTerm.getExponentNode(true); - return exponent && parseFloat(exponent.value) === degree; - } - return false; - }; -} -module.exports = isQuadratic; -//# sourceMappingURL=isQuadratic.js.map \ No newline at end of file diff --git a/lib/checks/isQuadratic.js.map b/lib/checks/isQuadratic.js.map deleted file mode 100644 index 3f0d8433..00000000 --- a/lib/checks/isQuadratic.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"isQuadratic.js","sourceRoot":"","sources":["isQuadratic.ts"],"names":[],"mappings":";AAAA,sCAAyC;AACzC,oCAAuC;AAEvC,+EAA+E;AAC/E,+DAA+D;AAC/D,qBAAqB,IAAqB;IACxC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,sDAAsD;IACtD,IAAM,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACvD,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,IAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,IAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEjE,0EAA0E;IAC1E,qCAAqC;IACrC,EAAE,CAAC,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAC/D,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,kEAAkE;IAClE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM;QACnD,aAAa,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,IAAI,CAAC;AACd,CAAC;AAED,2DAA2D;AAC3D,4CAA4C;AAC5C,kCAAkC,MAAM;IACtC,MAAM,CAAC,UAAA,IAAI;QACP,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACnD,IAAM,QAAQ,GAAG,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;QAC7D,CAAC;QACD,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC,CAAC;AACJ,CAAC;AAED,iBAAS,WAAW,CAAC"} \ No newline at end of file diff --git a/lib/checks/isQuadratic.ts b/lib/checks/isQuadratic.ts deleted file mode 100644 index 5931035b..00000000 --- a/lib/checks/isQuadratic.ts +++ /dev/null @@ -1,54 +0,0 @@ -import mathNode = require("../mathnode"); -import Symbols = require("../Symbols"); - -// Given a node, will determine if the expression is in the form of a quadratic -// e.g. `x^2 + 2x + 1` OR `x^2 - 1` but not `x^3 + x^2 + x + 1` -function isQuadratic(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node, "+")) { - return false; - } - - if (node.args.length > 3) { - return false; - } - - // make sure only one symbol appears in the expression - const symbolSet = Symbols.getSymbolsInExpression(node); - if (symbolSet.size !== 1) { - return false; - } - - const secondDegreeTerms = node.args.filter(isPolynomialTermOfDegree(2)); - const firstDegreeTerms = node.args.filter(isPolynomialTermOfDegree(1)); - const constantTerms = node.args.filter(mathNode.Type.isConstant); - - // Check that there is one second degree term and at most one first degree - // term and at most one constant term - if (secondDegreeTerms.length !== 1 || firstDegreeTerms.length > 1 || - constantTerms.length > 1) { - return false; - } - - // check that there are no terms that don't fall into these groups - if ((secondDegreeTerms.length + firstDegreeTerms.length + - constantTerms.length) !== node.args.length) { - return false; - } - - return true; -} - -// Given a degree, returns a function that checks if a node -// is a polynomial term of the given degree. -function isPolynomialTermOfDegree(degree) { - return node => { - if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - const polyTerm = new mathNode.PolynomialTerm(node); - const exponent = polyTerm.getExponentNode(true); - return exponent && parseFloat(exponent.value) === degree; - } - return false; - }; -} - -export = isQuadratic; diff --git a/lib/checks/resolvesToConstant.js b/lib/checks/resolvesToConstant.js deleted file mode 100644 index 152f42e3..00000000 --- a/lib/checks/resolvesToConstant.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; -var mathNode = require("../mathnode"); -function resolvesToConstant(node) { - if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { - return node.args.every(function (child) { return resolvesToConstant(child); }); - } - else if (mathNode.Type.isParenthesis(node)) { - return resolvesToConstant(node.content); - } - else if (mathNode.Type.isConstant(node, true)) { - return true; - } - else if (mathNode.Type.isSymbol(node)) { - return false; - } - else if (mathNode.Type.isUnaryMinus(node)) { - return resolvesToConstant(node.args[0]); - } - else { - throw Error("Unsupported node type: " + node.type); - } -} -module.exports = resolvesToConstant; -//# sourceMappingURL=resolvesToConstant.js.map \ No newline at end of file diff --git a/lib/checks/resolvesToConstant.js.map b/lib/checks/resolvesToConstant.js.map deleted file mode 100644 index 60090ef3..00000000 --- a/lib/checks/resolvesToConstant.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"resolvesToConstant.js","sourceRoot":"","sources":["resolvesToConstant.ts"],"names":[],"mappings":";AAAA,sCAAyC;AAOzC,4BAA4B,IAAI;IAC9B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CACpB,UAAC,KAAK,IAAK,OAAA,kBAAkB,CAAC,KAAK,CAAC,EAAzB,CAAyB,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,iBAAS,kBAAkB,CAAC"} \ No newline at end of file diff --git a/lib/checks/resolvesToConstant.ts b/lib/checks/resolvesToConstant.ts deleted file mode 100644 index a5254335..00000000 --- a/lib/checks/resolvesToConstant.ts +++ /dev/null @@ -1,29 +0,0 @@ -import mathNode = require("../mathnode"); - - -// Returns true if the node is a constant or can eventually be resolved to -// a constant. -// e.g. 2, 2+4, (2+4)^2 would all return true. x + 4 would return false -function resolvesToConstant(node: mathjs.MathNode) { - if (mathNode.Type.isOperator(node) || mathNode.Type.isFunction(node)) { - return node.args.every( - (child) => resolvesToConstant(child)); - } - else if (mathNode.Type.isParenthesis(node)) { - return resolvesToConstant(node.content); - } - else if (mathNode.Type.isConstant(node, true)) { - return true; - } - else if (mathNode.Type.isSymbol(node)) { - return false; - } - else if (mathNode.Type.isUnaryMinus(node)) { - return resolvesToConstant(node.args[0]); - } - else { - throw Error("Unsupported node type: " + node.type); - } -} - -export = resolvesToConstant; diff --git a/lib/equation/Equation.js b/lib/equation/Equation.js deleted file mode 100644 index 1ad13fdf..00000000 --- a/lib/equation/Equation.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -/// -var math = require("mathjs"); -var clone = require("../util/clone"); -var printNode = require("../util/print"); -// This represents an equation, made up of the leftNode (LHS), the -// rightNode (RHS) and a comparator (=, <, >, <=, or >=) -var Equation = (function () { - function Equation(leftNode, rightNode, comparator) { - this.leftNode = leftNode; - this.rightNode = rightNode; - this.comparator = comparator; - } - // Prints an Equation properly using the print module - Equation.prototype.print = function (showPlusMinus) { - if (showPlusMinus === void 0) { showPlusMinus = false; } - var leftSide = printNode(this.leftNode, showPlusMinus); - var rightSide = printNode(this.rightNode, showPlusMinus); - var comparator = this.comparator; - return leftSide + " " + comparator + " " + rightSide; - }; - Equation.prototype.clone = function () { - var newLeft = clone(this.leftNode); - var newRight = clone(this.rightNode); - return new Equation(newLeft, newRight, this.comparator); - }; - return Equation; -}()); -// Splits a string on the given comparator and returns a new Equation object -// from the left and right hand sides -Equation.createEquationFromString = function (str, comparator) { - var sides = str.split(comparator); - if (sides.length !== 2) { - throw Error("Expected two sides of an equation using comparator: " + - comparator); - } - var leftNode = math.parse(sides[0]); - var rightNode = math.parse(sides[1]); - return new Equation(leftNode, rightNode, comparator); -}; -module.exports = Equation; -//# sourceMappingURL=Equation.js.map \ No newline at end of file diff --git a/lib/equation/Equation.js.map b/lib/equation/Equation.js.map deleted file mode 100644 index e403cc39..00000000 --- a/lib/equation/Equation.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Equation.js","sourceRoot":"","sources":["Equation.ts"],"names":[],"mappings":";AAAA,mEAAmE;AACnE,6BAAgC;AAChC,qCAAwC;AACxC,yCAA4C;AAE5C,kEAAkE;AAClE,wDAAwD;AACxD;IACI,kBAAY,QAAyB,EAAE,SAA0B,EAAE,UAAU;QAC7E,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,qDAAqD;IACrD,wBAAK,GAAL,UAAM,aAAmB;QAAnB,8BAAA,EAAA,qBAAmB;QACvB,IAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACzD,IAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC3D,IAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,MAAM,CAAI,QAAQ,SAAI,UAAU,SAAI,SAAW,CAAC;IAClD,CAAC;IAED,wBAAK,GAAL;QACE,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC;IAkBH,eAAC;AAAD,CAAC,AArCD;AAqBE,4EAA4E;AAC5E,qCAAqC;AAC9B,iCAAwB,GAAG,UAAC,GAAG,EAAE,UAAU;IAC9C,IAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC,sDAAsD;YAC9D,UAAU,CAAC,CAAC;IACpB,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC,CAAC;AAMJ,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/equation/Equation.ts b/lib/equation/Equation.ts deleted file mode 100644 index 4b818015..00000000 --- a/lib/equation/Equation.ts +++ /dev/null @@ -1,47 +0,0 @@ -/// -import math = require("mathjs"); -import clone = require("../util/clone"); -import printNode = require("../util/print"); - -// This represents an equation, made up of the leftNode (LHS), the -// rightNode (RHS) and a comparator (=, <, >, <=, or >=) -class Equation { - constructor(leftNode: mathjs.MathNode, rightNode: mathjs.MathNode, comparator) { - this.leftNode = leftNode; - this.rightNode = rightNode; - this.comparator = comparator; - } - - // Prints an Equation properly using the print module - print(showPlusMinus=false) { - const leftSide = printNode(this.leftNode, showPlusMinus); - const rightSide = printNode(this.rightNode, showPlusMinus); - const comparator = this.comparator; - return `${leftSide} ${comparator} ${rightSide}`; - } - - clone() { - const newLeft = clone(this.leftNode); - const newRight = clone(this.rightNode); - return new Equation(newLeft, newRight, this.comparator); - } - - // Splits a string on the given comparator and returns a new Equation object - // from the left and right hand sides - static createEquationFromString = (str, comparator) => { - const sides = str.split(comparator); - if (sides.length !== 2) { - throw Error("Expected two sides of an equation using comparator: " + - comparator); - } - const leftNode = math.parse(sides[0]); - const rightNode = math.parse(sides[1]); - - return new Equation(leftNode, rightNode, comparator); - }; - leftNode: mathjs.MathNode; - rightNode: mathjs.MathNode; - comparator; -} - -export = Equation; diff --git a/lib/equation/Status.js b/lib/equation/Status.js deleted file mode 100644 index b79f4dff..00000000 --- a/lib/equation/Status.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; -var ChangeTypes = require("../ChangeTypes"); -var Equation = require("./Equation"); -var mathNode = require("../mathNode"); -// This represents the current equation we're solving. -// As we move step by step, an equation might be updated. Functions return this -// status object to pass on the updated equation and information on if/how it was -// changed. -var Status = (function () { - function Status(changeType, oldEquation, newEquation, substeps) { - if (substeps === void 0) { substeps = []; } - if (!newEquation) { - throw Error("new equation isn't defined"); - } - if (changeType === undefined || typeof (changeType) !== "string") { - throw Error("changetype isn't valid"); - } - this.changeType = changeType; - this.oldEquation = oldEquation; - this.newEquation = newEquation; - this.substeps = substeps; - } - Status.prototype.hasChanged = function () { - return this.changeType !== ChangeTypes.NO_CHANGE; - }; - return Status; -}()); -// A wrapper around the Status constructor for the case where equation -// hasn't been changed. -Status.noChange = function (equation) { return new Status(ChangeTypes.NO_CHANGE, null, equation); }; -Status.addLeftStep = function (equation, leftStep) { - var substeps = []; - leftStep.substeps.forEach(function (substep) { - substeps.push(Status.addLeftStep(equation, substep)); - }); - var oldEquation = null; - if (leftStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.leftNode = leftStep.oldNode; - } - var newEquation = equation.clone(); - newEquation.leftNode = leftStep.newNode; - return new Status(leftStep.changeType, oldEquation, newEquation, substeps); -}; -Status.addRightStep = function (equation, rightStep) { - var substeps = []; - rightStep.substeps.forEach(function (substep) { - substeps.push(Status.addRightStep(equation, substep)); - }); - var oldEquation = null; - if (rightStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.rightNode = rightStep.oldNode; - } - var newEquation = equation.clone(); - newEquation.rightNode = rightStep.newNode; - return new Status(rightStep.changeType, oldEquation, newEquation, substeps); -}; -Status.resetChangeGroups = function (equation) { - var leftNode = mathNode.Status.resetChangeGroups(equation.leftNode); - var rightNode = mathNode.Status.resetChangeGroups(equation.rightNode); - return new Equation(leftNode, rightNode, equation.comparator); -}; -module.exports = Status; -//# sourceMappingURL=Status.js.map \ No newline at end of file diff --git a/lib/equation/Status.js.map b/lib/equation/Status.js.map deleted file mode 100644 index 6916524f..00000000 --- a/lib/equation/Status.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Status.js","sourceRoot":"","sources":["Status.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/equation/Status.ts b/lib/equation/Status.ts deleted file mode 100644 index dc786c63..00000000 --- a/lib/equation/Status.ts +++ /dev/null @@ -1,80 +0,0 @@ -import ChangeTypes = require("../ChangeTypes"); -import Equation = require("./Equation"); -import mathNode = require("../mathNode"); - -// This represents the current equation we're solving. -// As we move step by step, an equation might be updated. Functions return this -// status object to pass on the updated equation and information on if/how it was -// changed. -class Status { - constructor(changeType, oldEquation: Equation, newEquation: Equation, substeps=[]) { - if (!newEquation) { - throw Error("new equation isn't defined"); - } - if (changeType === undefined || typeof(changeType) !== "string") { - throw Error("changetype isn't valid"); - } - - this.changeType = changeType; - this.oldEquation = oldEquation; - this.newEquation = newEquation; - this.substeps = substeps; - } - - hasChanged() { - return this.changeType !== ChangeTypes.NO_CHANGE; - } - -// A wrapper around the Status constructor for the case where equation -// hasn't been changed. - static noChange = equation => new Status(ChangeTypes.NO_CHANGE, null, equation); - static addLeftStep = (equation, leftStep) => { - const substeps = []; - leftStep.substeps.forEach(substep => { - substeps.push(Status.addLeftStep(equation, substep)); - }); - let oldEquation = null; - if (leftStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.leftNode = leftStep.oldNode; - } - const newEquation = equation.clone(); - newEquation.leftNode = leftStep.newNode; - return new Status( - leftStep.changeType, - oldEquation, - newEquation, - substeps); - }; - - static addRightStep = (equation, rightStep) => { - const substeps = []; - rightStep.substeps.forEach(substep => { - substeps.push(Status.addRightStep(equation, substep)); - }); - let oldEquation = null; - if (rightStep.oldNode) { - oldEquation = equation.clone(); - oldEquation.rightNode = rightStep.oldNode; - } - const newEquation = equation.clone(); - newEquation.rightNode = rightStep.newNode; - return new Status( - rightStep.changeType, - oldEquation, - newEquation, - substeps); - }; - - static resetChangeGroups = equation => { - const leftNode = mathNode.Status.resetChangeGroups(equation.leftNode); - const rightNode = mathNode.Status.resetChangeGroups(equation.rightNode); - return new Equation(leftNode, rightNode, equation.comparator); - }; - changeType; - oldEquation: Equation; - newEquation: Equation; - substeps: typeof undefined[]; -} - -export = Status; diff --git a/lib/equation/index.js b/lib/equation/index.js deleted file mode 100644 index d6e213da..00000000 --- a/lib/equation/index.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; -var Equation = require("./Equation"); -var Status = require("./Status"); -var tmp; -tmp = { - Equation: Equation, - Status: Status, -}; -module.exports = tmp; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/equation/index.js.map b/lib/equation/index.js.map deleted file mode 100644 index 42d9b0fb..00000000 --- a/lib/equation/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,qCAAwC;AACxC,iCAAoC;AACpC,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,QAAQ,UAAA;IACR,MAAM,QAAA;CACT,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/equation/index.ts b/lib/equation/index.ts deleted file mode 100644 index 504bb3e3..00000000 --- a/lib/equation/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import Equation = require("./Equation"); -import Status = require("./Status"); -var tmp; -tmp = { - Equation, - Status, -}; -export = tmp; diff --git a/lib/factor/ConstantFactors.js b/lib/factor/ConstantFactors.js deleted file mode 100644 index 01b4b0a4..00000000 --- a/lib/factor/ConstantFactors.js +++ /dev/null @@ -1,55 +0,0 @@ -// This module deals with getting constant factors, including prime factors -// and factor pairs of a number -"use strict"; -var ConstantFactors = (function () { - function ConstantFactors() { - } - // Given a number, will return all the prime factors of that number as a list - // sorted from smallest to largest - ConstantFactors.getPrimeFactors = function (number) { - var factors = []; - if (number < 0) { - factors = [-1]; - factors = factors.concat(this.getPrimeFactors(-1 * number)); - return factors; - } - var root = Math.sqrt(number); - var candidate = 2; - if (number % 2) { - candidate = 3; // assign first odd - while (number % candidate && candidate <= root) { - candidate = candidate + 2; - } - } - // if no factor found then the number is prime - if (candidate > root) { - factors.push(number); - } - else { - factors.push(candidate); - factors = factors.concat(this.getPrimeFactors(number / candidate)); - } - return factors; - }; - ; - // Given a number, will return all the factor pairs for that number as a list - // of 2-item lists - ConstantFactors.getFactorPairs = function (number) { - var factors = []; - var bound = Math.floor(Math.sqrt(Math.abs(number))); - for (var divisor = -bound; divisor <= bound; divisor++) { - if (divisor === 0) { - continue; - } - if (number % divisor === 0) { - var quotient = number / divisor; - factors.push([divisor, quotient]); - } - } - return factors; - }; - ; - return ConstantFactors; -}()); -module.exports = ConstantFactors; -//# sourceMappingURL=ConstantFactors.js.map \ No newline at end of file diff --git a/lib/factor/ConstantFactors.js.map b/lib/factor/ConstantFactors.js.map deleted file mode 100644 index 6a7163b4..00000000 --- a/lib/factor/ConstantFactors.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ConstantFactors.js","sourceRoot":"","sources":["ConstantFactors.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,+BAA+B;;AAE/B;IAAA;IAqDA,CAAC;IAnDD,6EAA6E;IAC7E,kCAAkC;IACvB,+BAAe,GAAtB,UAAuB,MAAa;QAChC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACf,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;YAC5D,MAAM,CAAC,OAAO,CAAC;QACnB,CAAC;QAED,IAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACb,SAAS,GAAG,CAAC,CAAC,CAAC,mBAAmB;YAClC,OAAO,MAAM,GAAG,SAAS,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC7C,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC;QAED,8CAA8C;QAC9C,EAAE,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAGD,IAAI,CAAC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IAEN,6EAA6E;IAC7E,kBAAkB;IACP,8BAAc,GAArB,UAAsB,MAAa;QAC/B,IAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,IAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YACrD,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBAChB,QAAQ,CAAC;YACb,CAAC;YACD,EAAE,CAAC,CAAC,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,OAAO,CAAC;IACnB,CAAC;IAAA,CAAC;IACN,sBAAC;AAAD,CAAC,AArDD,IAqDC;AAED,iBAAS,eAAe,CAAC"} \ No newline at end of file diff --git a/lib/factor/ConstantFactors.ts b/lib/factor/ConstantFactors.ts deleted file mode 100644 index 6b5c4af8..00000000 --- a/lib/factor/ConstantFactors.ts +++ /dev/null @@ -1,59 +0,0 @@ -// This module deals with getting constant factors, including prime factors -// and factor pairs of a number - -class ConstantFactors { - -// Given a number, will return all the prime factors of that number as a list -// sorted from smallest to largest - static getPrimeFactors(number:number) { - let factors = []; - if (number < 0) { - factors = [-1]; - factors = factors.concat(this.getPrimeFactors(-1 * number)); - return factors; - } - - const root = Math.sqrt(number); - let candidate = 2; - if (number % 2) { - candidate = 3; // assign first odd - while (number % candidate && candidate <= root) { - candidate = candidate + 2; - } - } - - // if no factor found then the number is prime - if (candidate > root) { - factors.push(number); - } - // if we find a factor, make a recursive call on the quotient of the number and - // our newly found prime factor in order to find more factors - else { - factors.push(candidate); - factors = factors.concat(this.getPrimeFactors(number / candidate)); - } - - return factors; - }; - -// Given a number, will return all the factor pairs for that number as a list -// of 2-item lists - static getFactorPairs(number:number) { - const factors = []; - - const bound = Math.floor(Math.sqrt(Math.abs(number))); - for (var divisor = -bound; divisor <= bound; divisor++) { - if (divisor === 0) { - continue; - } - if (number % divisor === 0) { - const quotient = number / divisor; - factors.push([divisor, quotient]); - } - } - - return factors; - }; -} - -export = ConstantFactors; diff --git a/lib/factor/factorQuadratic.js b/lib/factor/factorQuadratic.js deleted file mode 100644 index 556b5c2a..00000000 --- a/lib/factor/factorQuadratic.js +++ /dev/null @@ -1,184 +0,0 @@ -"use strict"; -/// -var math = require("mathjs"); -var ConstantFactors = require("./ConstantFactors"); -var ChangeTypes = require("../ChangeTypes"); -var checks = require("../checks"); -var evaluate = require("../util/evaluate"); -var flatten = require("../util/flattenOperands"); -var Negative = require("../Negative"); -var mathNode = require("../mathNode"); -var factorFunctions = [ - // factor just the symbol e.g. x^2 + 2x -> x(x + 2) - factorSymbol, - // factor difference of squares e.g. x^2 - 4 - factorDifferenceOfSquares, - // factor perfect square e.g. x^2 + 2x + 1 - factorPerfectSquare, - // factor sum product rule e.g. x^2 + 3x + 2 - factorSumProductRule -]; -// Given a node, will check if it's in the form of a quadratic equation -// `ax^2 + bx + c`, and -// if it is, will factor it using one of the following rules: -// - Factor out the symbol e.g. x^2 + 2x -> x(x + 2) -// - Difference of squares e.g. x^2 - 4 -> (x+2)(x-2) -// - Perfect square e.g. x^2 + 2x + 1 -> (x+1)^2 -// - Sum/product rule e.g. x^2 + 3x + 2 -> (x+1)(x+2) -// - TODO: quadratic formula -// requires us simplify the following only within the parens: -// a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a) -function factorQuadratic(node) { - node = flatten(node); - if (!checks.isQuadratic(node)) { - return mathNode.Status.noChange(node); - } - // get a, b and c - var symbol, aValue = 0, bValue = 0, cValue = 0; - for (var _i = 0, _a = node.args; _i < _a.length; _i++) { - var term = _a[_i]; - if (mathNode.Type.isConstant(term)) { - cValue = evaluate(term); - } - else if (mathNode.PolynomialTerm.isPolynomialTerm(term)) { - var polyTerm = new mathNode.PolynomialTerm(term); - var exponent = polyTerm.getExponentNode(true); - if (exponent.value === "2") { - symbol = polyTerm.getSymbolNode(); - aValue = polyTerm.getCoeffValue(); - } - else if (exponent.value === "1") { - bValue = polyTerm.getCoeffValue(); - } - else { - return mathNode.Status.noChange(node); - } - } - else { - return mathNode.Status.noChange(node); - } - } - if (!symbol || !aValue) { - return mathNode.Status.noChange(node); - } - var negate = false; - if (aValue < 0) { - negate = true; - aValue = -aValue; - bValue = -bValue; - cValue = -cValue; - } - for (var i = 0; i < factorFunctions.length; i++) { - var nodeStatus = factorFunctions[i](node, symbol, aValue, bValue, cValue, negate); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - } - return mathNode.Status.noChange(node); -} -// Will factor the node if it's in the form of ax^2 + bx -function factorSymbol(node, symbol, aValue, bValue, cValue, negate) { - if (!bValue || cValue) { - return mathNode.Status.noChange(node); - } - var gcd = math.gcd(aValue, bValue); - var gcdNode = mathNode.Creator.constant(gcd); - var aNode = mathNode.Creator.constant(aValue / gcd); - var bNode = mathNode.Creator.constant(bValue / gcd); - var factoredNode = mathNode.Creator.polynomialTerm(symbol, null, gcdNode); - var polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aNode); - var paren = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [polyTerm, bNode])); - var newNode = mathNode.Creator.operator("*", [factoredNode, paren], true); - if (negate) { - newNode = Negative.negate(newNode); - } - return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_SYMBOL, node, newNode); -} -// Will factor the node if it's in the form of ax^2 - c, and the aValue -// and cValue are perfect squares -// e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) -function factorDifferenceOfSquares(node, symbol, aValue, bValue, cValue, negate) { - // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, - // (iii) c is negative - if (bValue || !cValue) { - return mathNode.Status.noChange(node); - } - var aRootValue = Math.sqrt(Math.abs(aValue)); - var cRootValue = Math.sqrt(Math.abs(cValue)); - // must be a difference of squares - if ((aRootValue % 1 === 0) && - (cRootValue % 1 === 0) && - cValue < 0) { - var aRootNode = mathNode.Creator.constant(aRootValue); - var cRootNode = mathNode.Creator.constant(cRootValue); - var polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); - var firstParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [polyTerm, cRootNode])); - var secondParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("-", [polyTerm, cRootNode])); - // create node in difference of squares form - var newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); - if (negate) { - newNode = Negative.negate(newNode); - } - return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_DIFFERENCE_OF_SQUARES, node, newNode); - } - return mathNode.Status.noChange(node); -} -// Will factor the node if it's in the form of ax^2 + bx + c, where a and c -// are perfect squares and b = 2*sqrt(a)*sqrt(c) -// e.g. x^2 + 2x + 1 -> (x + 1)^2 -function factorPerfectSquare(node, symbol, aValue, bValue, cValue, negate) { - // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) - if (!bValue || !cValue) { - return mathNode.Status.noChange(node); - } - var aRootValue = Math.sqrt(Math.abs(aValue)); - var cRootValue = Math.sqrt(Math.abs(cValue)); - // if the second term is negative, then the constant in the parens is - // subtracted: e.g. x^2 - 2x + 1 -> (x - 1)^2 - if (bValue < 0) { - cRootValue = cRootValue * -1; - } - // apply the perfect square test - var perfectProduct = 2 * aRootValue * cRootValue; - if ((aRootValue % 1 === 0) && - (cRootValue % 1 === 0) && - bValue === perfectProduct) { - var aRootNode = mathNode.Creator.constant(aRootValue); - var cRootNode = mathNode.Creator.constant(cRootValue); - var polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); - var paren = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [polyTerm, cRootNode])); - var exponent = mathNode.Creator.constant(2); - // create node in perfect square form - var newNode = mathNode.Creator.operator("^", [paren, exponent]); - if (negate) { - newNode = Negative.negate(newNode); - } - return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_PERFECT_SQUARE, node, newNode); - } - return mathNode.Status.noChange(node); -} -// Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by -// applying the sum product rule: finding factors of c that add up to b. -// e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) -function factorSumProductRule(node, symbol, aValue, bValue, cValue, negate) { - if (aValue === 1 && bValue && cValue) { - // try sum/product rule: find a factor pair of c that adds up to b - var factorPairs = ConstantFactors.getFactorPairs(cValue); - for (var _i = 0, factorPairs_1 = factorPairs; _i < factorPairs_1.length; _i++) { - var pair = factorPairs_1[_i]; - if (pair[0] + pair[1] === bValue) { - var firstParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[0])])); - var secondParen = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[1])])); - // create a node in the general factored form for expression - var newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); - if (negate) { - newNode = Negative.negate(newNode); - } - return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_SUM_PRODUCT_RULE, node, newNode); - } - } - } - return mathNode.Status.noChange(node); -} -module.exports = factorQuadratic; -//# sourceMappingURL=factorQuadratic.js.map \ No newline at end of file diff --git a/lib/factor/factorQuadratic.js.map b/lib/factor/factorQuadratic.js.map deleted file mode 100644 index e4de1172..00000000 --- a/lib/factor/factorQuadratic.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"factorQuadratic.js","sourceRoot":"","sources":["factorQuadratic.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/factor/factorQuadratic.ts b/lib/factor/factorQuadratic.ts deleted file mode 100644 index 7a34a05e..00000000 --- a/lib/factor/factorQuadratic.ts +++ /dev/null @@ -1,222 +0,0 @@ -/// -import math = require("mathjs"); -import ConstantFactors = require("./ConstantFactors"); -import ChangeTypes = require("../ChangeTypes"); -import checks = require("../checks"); -import evaluate = require("../util/evaluate"); -import flatten = require("../util/flattenOperands"); -import Negative = require("../Negative"); -import mathNode = require("../mathNode"); -const factorFunctions = [ - // factor just the symbol e.g. x^2 + 2x -> x(x + 2) - factorSymbol, - // factor difference of squares e.g. x^2 - 4 - factorDifferenceOfSquares, - // factor perfect square e.g. x^2 + 2x + 1 - factorPerfectSquare, - // factor sum product rule e.g. x^2 + 3x + 2 - factorSumProductRule -]; - -// Given a node, will check if it's in the form of a quadratic equation -// `ax^2 + bx + c`, and -// if it is, will factor it using one of the following rules: -// - Factor out the symbol e.g. x^2 + 2x -> x(x + 2) -// - Difference of squares e.g. x^2 - 4 -> (x+2)(x-2) -// - Perfect square e.g. x^2 + 2x + 1 -> (x+1)^2 -// - Sum/product rule e.g. x^2 + 3x + 2 -> (x+1)(x+2) -// - TODO: quadratic formula -// requires us simplify the following only within the parens: -// a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a) -function factorQuadratic(node: mathjs.MathNode) { - node = flatten(node); - if (!checks.isQuadratic(node)) { - return mathNode.Status.noChange(node); - } - - // get a, b and c - let symbol, aValue = 0, bValue = 0, cValue = 0; - for (const term of node.args) { - if (mathNode.Type.isConstant(term)) { - cValue = evaluate(term); - } - else if (mathNode.PolynomialTerm.isPolynomialTerm(term)) { - const polyTerm = new mathNode.PolynomialTerm(term); - const exponent = polyTerm.getExponentNode(true); - if (exponent.value === "2") { - symbol = polyTerm.getSymbolNode(); - aValue = polyTerm.getCoeffValue(); - } - else if (exponent.value === "1") { - bValue = polyTerm.getCoeffValue(); - } - else { - return mathNode.Status.noChange(node); - } - } - else { - return mathNode.Status.noChange(node); - } - } - - if (!symbol || !aValue) { - return mathNode.Status.noChange(node); - } - - let negate = false; - if (aValue < 0) { - negate = true; - aValue = -aValue; - bValue = -bValue; - cValue = -cValue; - } - - for (let i = 0; i < factorFunctions.length; i++) { - const nodeStatus = factorFunctions[i](node, symbol, aValue, bValue, cValue, negate); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - } - - return mathNode.Status.noChange(node); -} - -// Will factor the node if it's in the form of ax^2 + bx -function factorSymbol(node: mathjs.MathNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { - if (!bValue || cValue) { - return mathNode.Status.noChange(node); - } - - const gcd = math.gcd(aValue, bValue); - const gcdNode = mathNode.Creator.constant(gcd); - const aNode = mathNode.Creator.constant(aValue/gcd); - const bNode = mathNode.Creator.constant(bValue/gcd); - - const factoredNode = mathNode.Creator.polynomialTerm(symbol, null, gcdNode); - const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aNode); - const paren = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", [polyTerm, bNode])); - - let newNode = mathNode.Creator.operator("*", [factoredNode, paren], true); - if (negate) { - newNode = Negative.negate(newNode); - } - - return mathNode.Status.nodeChanged(ChangeTypes.FACTOR_SYMBOL, node, newNode); -} - -// Will factor the node if it's in the form of ax^2 - c, and the aValue -// and cValue are perfect squares -// e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) -function factorDifferenceOfSquares(node: mathjs.MathNode, symbol, aValue: number, bValue?: number, cValue?: number, negate?: boolean) { - // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, - // (iii) c is negative - if (bValue || !cValue) { - return mathNode.Status.noChange(node); - } - - const aRootValue = Math.sqrt(Math.abs(aValue)); - const cRootValue = Math.sqrt(Math.abs(cValue)); - - // must be a difference of squares - if ((aRootValue%1 === 0) && - (cRootValue % 1 === 0) && - cValue < 0) { - - const aRootNode = mathNode.Creator.constant(aRootValue); - const cRootNode = mathNode.Creator.constant(cRootValue); - - const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); - const firstParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", [polyTerm, cRootNode])); - const secondParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator("-", [polyTerm, cRootNode])); - - // create node in difference of squares form - let newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); - if (negate) { - newNode = Negative.negate(newNode); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.FACTOR_DIFFERENCE_OF_SQUARES, node, newNode); - } - - return mathNode.Status.noChange(node); -} - -// Will factor the node if it's in the form of ax^2 + bx + c, where a and c -// are perfect squares and b = 2*sqrt(a)*sqrt(c) -// e.g. x^2 + 2x + 1 -> (x + 1)^2 -function factorPerfectSquare(node: mathjs.MathNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { - // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) - if (!bValue || !cValue) { - return mathNode.Status.noChange(node); - } - - const aRootValue = Math.sqrt(Math.abs(aValue)); - let cRootValue = Math.sqrt(Math.abs(cValue)); - - // if the second term is negative, then the constant in the parens is - // subtracted: e.g. x^2 - 2x + 1 -> (x - 1)^2 - if (bValue < 0) { - cRootValue = cRootValue * -1; - } - - // apply the perfect square test - const perfectProduct = 2 * aRootValue * cRootValue; - if ((aRootValue%1 === 0) && - (cRootValue %1 === 0) && - bValue === perfectProduct) { - - const aRootNode = mathNode.Creator.constant(aRootValue); - const cRootNode = mathNode.Creator.constant(cRootValue); - - const polyTerm = mathNode.Creator.polynomialTerm(symbol, null, aRootNode); - const paren = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", [polyTerm, cRootNode])); - const exponent = mathNode.Creator.constant(2); - - // create node in perfect square form - let newNode = mathNode.Creator.operator("^", [paren, exponent]); - if (negate) { - newNode = Negative.negate(newNode); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.FACTOR_PERFECT_SQUARE, node, newNode); - } - - return mathNode.Status.noChange(node); -} - -// Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by -// applying the sum product rule: finding factors of c that add up to b. -// e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) -function factorSumProductRule(node: mathjs.MathNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { - if (aValue === 1 && bValue && cValue) { - // try sum/product rule: find a factor pair of c that adds up to b - const factorPairs = ConstantFactors.getFactorPairs(cValue); - for (const pair of factorPairs) { - if (pair[0] + pair[1] === bValue) { - const firstParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[0])])); - const secondParen = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", [symbol, mathNode.Creator.constant(pair[1])])); - - // create a node in the general factored form for expression - let newNode = mathNode.Creator.operator("*", [firstParen, secondParen], true); - if (negate) { - newNode = Negative.negate(newNode); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.FACTOR_SUM_PRODUCT_RULE, node, newNode); - } - } - } - - return mathNode.Status.noChange(node); -} - -export = factorQuadratic; diff --git a/lib/mathNode/Creator.ts b/lib/mathNode/Creator.ts deleted file mode 100644 index d38b4a79..00000000 --- a/lib/mathNode/Creator.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - Functions to generate any mathJS node supported by the stepper - see http://mathjs.org/docs/expressions/expression_trees.html#nodes for more - information on nodes in mathJS -*/ -/// -import math = require("mathjs"); -import NodeType = require("./Type"); -const nodeCreator = { - operator (op, args, implicit=false) { - switch (op) { - case "+": - return new math.expression.OperatorNode("+", "add", args); - case "-": - return new math.expression.OperatorNode("-", "subtract", args); - case "/": - return new math.expression.node.OperatorNode("/", "divide", args); - case "*": - return new math.expression.node.OperatorNode( - "*", "multiply", args, implicit); - case "^": - return new math.expression.node.OperatorNode("^", "pow", args); - default: - throw Error("Unsupported operation: " + op); - } - }, - - // In almost all cases, use Negative.negate (with naive = true) to add a - // unary minus to your node, rather than calling this constructor directly - unaryMinus (content) { - return new math.expression.node.OperatorNode( - "-", "unaryMinus", [content]); - }, - - constant (val) { - return new math.expression.node.ConstantNode(val); - }, - - symbol (name) { - return new math.expression.node.SymbolNode(name); - }, - - parenthesis (content) { - return new math.expression.node.ParenthesisNode(content); - }, - - // exponent might be null, which means there's no exponent node. - // similarly, coefficient might be null, which means there's no coefficient - // the symbol node can never be null. - polynomialTerm (symbol, exponent, coeff, explicitCoeff=false) { - let polyTerm = symbol; - if (exponent) { - polyTerm = this.operator("^", [polyTerm, exponent]); - } - if (coeff && (explicitCoeff || parseFloat(coeff.value) !== 1)) { - if (NodeType.isConstant(coeff) && - parseFloat(coeff.value) === -1 && - !explicitCoeff) { - // if you actually want -1 as the coefficient, set explicitCoeff to true - polyTerm = this.unaryMinus(polyTerm); - } - else { - polyTerm = this.operator("*", [coeff, polyTerm], true); - } - } - return polyTerm; - }, - - // Given a root value and a radicand (what is under the radical) - nthRoot (radicandNode, rootNode) { - const symbol = nodeCreator.symbol("nthRoot"); - return new math.expression.node.FunctionNode(symbol, [radicandNode, rootNode]); - } -}; -export = nodeCreator; diff --git a/lib/mathNode/PolynomialTerm.js b/lib/mathNode/PolynomialTerm.js deleted file mode 100644 index 0263e8bf..00000000 --- a/lib/mathNode/PolynomialTerm.js +++ /dev/null @@ -1,171 +0,0 @@ -"use strict"; -var NodeCreator = require("./Creator"); -var NodeType = require("./Type"); -var evaluate = require("../util/evaluate"); -// For storing polynomial terms. -// Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. -// These expressions are of the form of a PolynomialTerm: x^2, 2y, z, 3x/5 -// These expressions are not: 4, x^(3+4), 2+x, 3*7, x-z -/* Fields: - - coeff: either a constant node or a fraction of two constant nodes - (might be null if no coefficient) - - symbol: the node with the symbol (e.g. in x^2, the node x) - - exponent: a node that can take any form, e.g. x^(2+x^2) - (might be null if no exponent) -*/ -var PolynomialTerm = (function () { - // if onlyImplicitMultiplication is true, an error will be thrown if `node` - // is a polynomial term without implicit multiplication - // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. - function PolynomialTerm(node, onlyImplicitMultiplication) { - if (onlyImplicitMultiplication === void 0) { onlyImplicitMultiplication = false; } - // Returns if the node represents an expression that can be considered a term. - // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. - // See the tests for some more thorough examples of exactly what counts and - // what does not. - this.isPolynomialTerm = function (node, onlyImplicitMultiplication) { - if (onlyImplicitMultiplication === void 0) { onlyImplicitMultiplication = false; } - try { - // will throw error if node isn't poly term - new PolynomialTerm(node, onlyImplicitMultiplication); - return true; - } - catch (err) { - return false; - } - }; - if (NodeType.isOperator(node)) { - if (node.op === "^") { - var symbolNode = node.args[0]; - if (!NodeType.isSymbol(symbolNode)) { - throw Error("Expected symbol term, got " + symbolNode); - } - this.symbol = symbolNode; - this.exponent = node.args[1]; - } - else if (node.op === "*") { - if (onlyImplicitMultiplication && !node.implicit) { - throw Error("Expected implicit multiplication"); - } - if (node.args.length !== 2) { - throw Error("Expected two arguments to *"); - } - var coeffNode = node.args[0]; - if (!NodeType.isConstantOrConstantFraction(coeffNode)) { - throw Error("Expected coefficient to be constant or fraction of " + - "constants term, got " + - coeffNode); - } - this.coeff = coeffNode; - var nonCoefficientTerm = new PolynomialTerm(node.args[1], onlyImplicitMultiplication); - if (nonCoefficientTerm.hasCoeff()) { - throw Error("Cannot have two coefficients " + - coeffNode + - " and " + - nonCoefficientTerm.getCoeffNode()); - } - this.symbol = nonCoefficientTerm.getSymbolNode(); - this.exponent = nonCoefficientTerm.getExponentNode(); - } - else if (node.op === "/") { - var denominatorNode = node.args[1]; - if (!NodeType.isConstant(denominatorNode)) { - throw Error("denominator must be constant node, instead of " + - denominatorNode); - } - var numeratorNode = new PolynomialTerm(node.args[0], onlyImplicitMultiplication); - if (numeratorNode.hasFractionCoeff()) { - throw Error("Polynomial terms cannot have nested fractions"); - } - this.exponent = numeratorNode.getExponentNode(); - this.symbol = numeratorNode.getSymbolNode(); - var numeratorConstantNode = numeratorNode.getCoeffNode(true); - this.coeff = NodeCreator.operator("/", [numeratorConstantNode, denominatorNode]); - } - else { - throw Error("Unsupported operatation for polynomial node: " + node.op); - } - } - else if (NodeType.isUnaryMinus(node)) { - var arg = node.args[0]; - if (NodeType.isParenthesis(arg)) { - arg = arg.content; - } - var polyNode = new PolynomialTerm(arg, onlyImplicitMultiplication); - this.exponent = polyNode.getExponentNode(); - this.symbol = polyNode.getSymbolNode(); - if (!polyNode.hasCoeff()) { - this.coeff = NodeCreator.constant(-1); - } - else { - this.coeff = this.negativeCoefficient(polyNode.getCoeffNode()); - } - } - else if (NodeType.isSymbol(node)) { - this.symbol = node; - } - else { - throw Error("Unsupported node type: " + node.type); - } - } - /* GETTER FUNCTIONS */ - PolynomialTerm.prototype.getSymbolNode = function () { - return this.symbol; - }; - PolynomialTerm.prototype.getSymbolName = function () { - return this.symbol.name; - }; - PolynomialTerm.prototype.getCoeffNode = function (defaultOne) { - if (defaultOne === void 0) { defaultOne = false; } - if (!this.coeff && defaultOne) { - return NodeCreator.constant(1); - } - else { - return this.coeff; - } - }; - PolynomialTerm.prototype.getCoeffValue = function () { - if (this.coeff) { - return evaluate(this.coeff); - } - else { - return 1; // no coefficient is like a coeff of 1 - } - }; - PolynomialTerm.prototype.getExponentNode = function (defaultOne) { - if (defaultOne === void 0) { defaultOne = false; } - if (!this.exponent && defaultOne) { - return NodeCreator.constant(1); - } - else { - return this.exponent; - } - }; - PolynomialTerm.prototype.getRootNode = function () { - return NodeCreator.polynomialTerm(this.symbol, this.exponent, this.coeff); - }; - // note: there is no exponent value getter function because the exponent - // can be any expresion and not necessarily a number. - /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ - // Returns true if the coefficient is a fraction - PolynomialTerm.prototype.hasFractionCoeff = function () { - // coeffNode is either a constant or a division operation. - return this.coeff && NodeType.isOperator(this.coeff); - }; - PolynomialTerm.prototype.hasCoeff = function () { - return !!this.coeff; - }; - PolynomialTerm.prototype.negativeCoefficient = function (node) { - if (NodeType.isConstant(node)) { - node = NodeCreator.constant(0 - parseFloat(node.value)); - } - else { - var numeratorValue = 0 - parseFloat(node.args[0].value); - node.args[0] = NodeCreator.constant(numeratorValue); - } - return node; - }; - return PolynomialTerm; -}()); -module.exports = PolynomialTerm; -//# sourceMappingURL=PolynomialTerm.js.map \ No newline at end of file diff --git a/lib/mathNode/PolynomialTerm.js.map b/lib/mathNode/PolynomialTerm.js.map deleted file mode 100644 index cd740944..00000000 --- a/lib/mathNode/PolynomialTerm.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"PolynomialTerm.js","sourceRoot":"","sources":["PolynomialTerm.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/mathNode/PolynomialTerm.ts b/lib/mathNode/PolynomialTerm.ts deleted file mode 100644 index 6fd3decb..00000000 --- a/lib/mathNode/PolynomialTerm.ts +++ /dev/null @@ -1,188 +0,0 @@ -/// -import NodeCreator = require("./Creator"); -import NodeType = require("./Type"); -import evaluate = require("../util/evaluate"); - -// For storing polynomial terms. -// Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. -// These expressions are of the form of a PolynomialTerm: x^2, 2y, z, 3x/5 -// These expressions are not: 4, x^(3+4), 2+x, 3*7, x-z -/* Fields: - - coeff: either a constant node or a fraction of two constant nodes - (might be null if no coefficient) - - symbol: the node with the symbol (e.g. in x^2, the node x) - - exponent: a node that can take any form, e.g. x^(2+x^2) - (might be null if no exponent) -*/ -class PolynomialTerm { - exponent; - symbol; - coeff; - - // if onlyImplicitMultiplication is true, an error will be thrown if `node` - // is a polynomial term without implicit multiplication - // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. - constructor(node: mathjs.MathNode, onlyImplicitMultiplication=false) { - if (NodeType.isOperator(node)) { - if (node.op === "^") { - const symbolNode = node.args[0]; - if (!NodeType.isSymbol(symbolNode)) { - throw Error("Expected symbol term, got " + symbolNode); - } - this.symbol = symbolNode; - this.exponent = node.args[1]; - } - // it's '*' ie it has a coefficient - else if (node.op === "*") { - if (onlyImplicitMultiplication && !node.implicit) { - throw Error("Expected implicit multiplication"); - } - if (node.args.length !== 2) { - throw Error("Expected two arguments to *"); - } - const coeffNode = node.args[0]; - if (!NodeType.isConstantOrConstantFraction(coeffNode)) { - throw Error("Expected coefficient to be constant or fraction of " + - "constants term, got " + - coeffNode); - } - this.coeff = coeffNode; - const nonCoefficientTerm = new PolynomialTerm( - node.args[1], - onlyImplicitMultiplication); - if (nonCoefficientTerm.hasCoeff()) { - throw Error("Cannot have two coefficients " + - coeffNode + - " and " + - nonCoefficientTerm.getCoeffNode()); - } - this.symbol = nonCoefficientTerm.getSymbolNode(); - this.exponent = nonCoefficientTerm.getExponentNode(); - } - // this means there's a fraction coefficient - else if (node.op === "/") { - const denominatorNode = node.args[1]; - if (!NodeType.isConstant(denominatorNode)) { - throw Error("denominator must be constant node, instead of " + - denominatorNode); - } - const numeratorNode = new PolynomialTerm( - node.args[0], - onlyImplicitMultiplication); - if (numeratorNode.hasFractionCoeff()) { - throw Error("Polynomial terms cannot have nested fractions"); - } - this.exponent = numeratorNode.getExponentNode(); - this.symbol = numeratorNode.getSymbolNode(); - const numeratorConstantNode = numeratorNode.getCoeffNode(true); - this.coeff = NodeCreator.operator( - "/", - [numeratorConstantNode, denominatorNode]); - } else { - throw Error("Unsupported operatation for polynomial node: " + node.op); - } - } else if (NodeType.isUnaryMinus(node)) { - var arg = node.args[0]; - if (NodeType.isParenthesis(arg)) { - arg = arg.content; - } - const polyNode = new PolynomialTerm( - arg, - onlyImplicitMultiplication); - this.exponent = polyNode.getExponentNode(); - this.symbol = polyNode.getSymbolNode(); - if (!polyNode.hasCoeff()) { - this.coeff = NodeCreator.constant(-1); - } else { - this.coeff = this.negativeCoefficient(polyNode.getCoeffNode()); - } - } else if (NodeType.isSymbol(node)) { - this.symbol = node; - } else { - throw Error("Unsupported node type: " + node.type); - } - } - - /* GETTER FUNCTIONS */ - getSymbolNode() { - return this.symbol; - } - - getSymbolName() { - return this.symbol.name; - } - - getCoeffNode(defaultOne=false) { - if (!this.coeff && defaultOne) { - return NodeCreator.constant(1); - } else { - return this.coeff; - } - } - - getCoeffValue() { - if (this.coeff) { - return evaluate(this.coeff); - } else { - return 1; // no coefficient is like a coeff of 1 - } - } - - getExponentNode(defaultOne=false) { - if (!this.exponent && defaultOne) { - return NodeCreator.constant(1); - } else { - return this.exponent; - } - } - - getRootNode() { - return NodeCreator.polynomialTerm( - this.symbol, - this.exponent, - this.coeff); - } - - // note: there is no exponent value getter function because the exponent - // can be any expresion and not necessarily a number. - - /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ - - // Returns true if the coefficient is a fraction - hasFractionCoeff() { - // coeffNode is either a constant or a division operation. - return this.coeff && NodeType.isOperator(this.coeff); - } - - hasCoeff() { - return !!this.coeff; - } - - // Returns if the node represents an expression that can be considered a term. - // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. - // See the tests for some more thorough examples of exactly what counts and - // what does not. - isPolynomialTerm = (node: mathjs.MathNode, onlyImplicitMultiplication = false) => { - try { - // will throw error if node isn't poly term - const temp = new PolynomialTerm(node, onlyImplicitMultiplication); - return true; - } catch (err) { - return false; - } - }; - -// Multiplies `node`, a constant or fraction of two constant nodes, by -1 -// Returns a node - negativeCoefficient(node: mathjs.MathNode) { - if (NodeType.isConstant(node)) { - node = NodeCreator.constant(0 - parseFloat(node.value)); - } else { - const numeratorValue = 0 - parseFloat(node.args[0].value); - node.args[0] = NodeCreator.constant(numeratorValue); - } - return node; - } -} - -export = PolynomialTerm; diff --git a/lib/mathNode/Status.ts b/lib/mathNode/Status.ts deleted file mode 100644 index aee097b6..00000000 --- a/lib/mathNode/Status.ts +++ /dev/null @@ -1,122 +0,0 @@ -/// -import clone = require("../util/clone"); -import ChangeTypes = require("../ChangeTypes"); -import Type = require("./Type"); - -// This represents the current (sub)exp+ ression we're simplifying. -// As we move step by step, a node might be updated. Functions return this -// status object to pass on the updated node and information on if/how it was -// changed. -// Status(node) creates a Status object that signals no change -class Status { - constructor(changeType, oldNode: mathjs.MathNode, newNode: mathjs.MathNode, substeps=[]) { - if (!newNode) { - throw Error("node is not defined"); - } - if (changeType === undefined || typeof(changeType) !== "string") { - throw Error("changetype isn't valid"); - } - - this.changeType = changeType; - this.oldNode = oldNode; - this.newNode = newNode; - this.substeps = substeps; - } - - hasChanged() { - return this.changeType !== ChangeTypes.NO_CHANGE; - } - static resetChangeGroups(node: mathjs.MathNode) { - node = clone(node); - node.filter(node => node.changeGroup).forEach(change => { - delete change.changeGroup; - }); - return node; - }; - // A wrapper around the Status constructor for the case where node hasn't - // been changed. - noChange(node: mathjs.MathNode) { - return new Status(ChangeTypes.NO_CHANGE, null, node); - }; - // A wrapper around the Status constructor for the case of a change - // that is happening at the level of oldNode + newNode - // e.g. 2 + 2 --> 4 (an addition node becomes a constant node) - nodeChanged(changeType, oldNode: mathjs.MathNode, newNode: mathjs.MathNode, defaultChangeGroup = true, steps = []) { - if (defaultChangeGroup) { - oldNode.changeGroup = 1; - newNode.changeGroup = 1; - } - - return new Status(changeType, oldNode, newNode, steps); - }; - // A wrapper around the Status constructor for the case where there was - // a change that happened deeper `node`'s tree, and `node`'s children must be - // updated to have the newNode/oldNode metadata (changeGroups) - // e.g. (2 + 2) + x --> 4 + x has to update the left argument - childChanged(node: mathjs.MathNode, childStatus, childArgIndex = null) { - const oldNode = clone(node); - const newNode = clone(node); - let substeps = childStatus.substeps; - - if (!childStatus.oldNode) { - throw Error(`Expected old node for changeType: ${childStatus.changeType}`); - } - - function updateSubsteps(substeps, fn) { - substeps.map((step) => { - step = fn(step); - step.substeps = updateSubsteps(step.substeps, fn); - }); - return substeps; - } - - if (Type.isParenthesis(node)) { - oldNode.content = childStatus.oldNode; - newNode.content = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.content = step.oldNode; - newNode.content = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else if ((Type.isOperator(node) || Type.isFunction(node) && - childArgIndex !== null)) { - oldNode.args[childArgIndex] = childStatus.oldNode; - newNode.args[childArgIndex] = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.args[childArgIndex] = step.oldNode; - newNode.args[childArgIndex] = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else if (Type.isUnaryMinus(node)) { - oldNode.args[0] = childStatus.oldNode; - newNode.args[0] = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.args[0] = step.oldNode; - newNode.args[0] = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else { - throw Error("Unexpected node type: " + node.type); - } - - return new Status(childStatus.changeType, oldNode, newNode, substeps); - }; - changeType; - substeps; -} -export = Status; diff --git a/lib/mathNode/Type.js b/lib/mathNode/Type.js deleted file mode 100644 index e5b5f74b..00000000 --- a/lib/mathNode/Type.js +++ /dev/null @@ -1,110 +0,0 @@ -/// -/* - For determining the type of a mathJS node. - */ -"use strict"; -var NodeType = (function () { - function NodeType() { - } - NodeType.isOperator = function (node, operator) { - if (operator === void 0) { operator = null; } - return node.type === "OperatorNode" && - node.fn !== "unaryMinus" && - ("*+-/^".lastIndexOf(node.op) !== -1) && - (operator ? node.op === operator : true); - }; - ; - NodeType.isParenthesis = function (node) { - return node.type === "ParenthesisNode"; - }; - ; - NodeType.isUnaryMinus = function (node) { - return node.type === "OperatorNode" && node.fn === "unaryMinus"; - }; - ; - NodeType.isFunction = function (node, functionName) { - if (functionName === void 0) { functionName = null; } - if (node.type !== "FunctionNode") { - return false; - } - if (functionName && node.fn !== functionName) { - return false; - } - return true; - }; - ; - NodeType.isSymbol = function (node, allowUnaryMinus) { - if (allowUnaryMinus === void 0) { allowUnaryMinus = true; } - if (node.type === "SymbolNode") { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - return NodeType.isSymbol(node.args[0], false); - } - else { - return false; - } - }; - ; - NodeType.isConstant = function (node, allowUnaryMinus) { - if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } - if (node.type === "ConstantNode") { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - if (NodeType.isConstant(node.args[0], false)) { - var value = parseFloat(node.args[0].value); - return value >= 0; - } - else { - return false; - } - } - else { - return false; - } - }; - ; - NodeType.isConstantFraction = function (node, allowUnaryMinus) { - if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } - if (NodeType.isOperator(node, '/')) { - return node.args.every(function (n) { return NodeType.isConstant(n, allowUnaryMinus); }); - } - else { - return false; - } - }; - ; - NodeType.isConstantOrConstantFraction = function (node, allowUnaryMinus) { - if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } - if (NodeType.isConstant(node, allowUnaryMinus) || - NodeType.isConstantFraction(node, allowUnaryMinus)) { - return true; - } - else { - return false; - } - }; - ; - NodeType.prototype.isIntegerFraction = function (node, allowUnaryMinus) { - if (allowUnaryMinus === void 0) { allowUnaryMinus = false; } - if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { - return false; - } - var _a = node.args, numerator = _a[0], denominator = _a[1]; - if (allowUnaryMinus) { - if (NodeType.isUnaryMinus(numerator)) { - numerator = numerator.args[0]; - } - if (NodeType.isUnaryMinus(denominator)) { - denominator = denominator.args[0]; - } - } - return ((parseFloat(numerator.value) % 1 === 0) && - (parseFloat(denominator.value) % 1 === 0)); - }; - ; - return NodeType; -}()); -module.exports = NodeType; -//# sourceMappingURL=Type.js.map \ No newline at end of file diff --git a/lib/mathNode/Type.js.map b/lib/mathNode/Type.js.map deleted file mode 100644 index 641ce358..00000000 --- a/lib/mathNode/Type.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Type.js","sourceRoot":"","sources":["Type.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/mathNode/Type.ts b/lib/mathNode/Type.ts deleted file mode 100644 index 42a5b624..00000000 --- a/lib/mathNode/Type.ts +++ /dev/null @@ -1,91 +0,0 @@ -/// -/* - For determining the type of a mathJS node. - */ - -class NodeType { - static isOperator(node: mathjs.MathNode, operator = null) { - return node.type === "OperatorNode" && - node.fn !== "unaryMinus" && - ("*+-/^".lastIndexOf(node.op) !== -1) && - (operator ? node.op === operator : true); - }; - static isParenthesis(node: mathjs.MathNode) { - return node.type === "ParenthesisNode"; - }; - static isUnaryMinus(node: mathjs.MathNode) { - return node.type === "OperatorNode" && node.fn === "unaryMinus"; - }; - static isFunction(node: mathjs.MathNode, functionName = null) { - if (node.type !== "FunctionNode") { - return false; - } - if (functionName && node.fn !== functionName) { - return false; - } - return true; - }; - static isSymbol(node: mathjs.MathNode, allowUnaryMinus = true) { - if (node.type === "SymbolNode") { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - return NodeType.isSymbol(node.args[0], false); - } - else { - return false; - } - }; - static isConstant(node: mathjs.MathNode, allowUnaryMinus = false) { - if (node.type === "ConstantNode") { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - if (NodeType.isConstant(node.args[0], false)) { - const value = parseFloat(node.args[0].value); - return value >= 0; - } - else { - return false; - } - } - else { - return false; - } - }; - static isConstantFraction(node: mathjs.MathNode, allowUnaryMinus = false) { - if (NodeType.isOperator(node, '/')) { - return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); - } - else { - return false; - } - }; - static isConstantOrConstantFraction(node: mathjs.MathNode, allowUnaryMinus = false) { - if (NodeType.isConstant(node, allowUnaryMinus) || - NodeType.isConstantFraction(node, allowUnaryMinus)) { - return true; - } - else { - return false; - } - }; - isIntegerFraction(node: mathjs.MathNode, allowUnaryMinus = false) { - if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { - return false; - } - let [numerator, denominator] = node.args; - if (allowUnaryMinus) { - if (NodeType.isUnaryMinus(numerator)) { - numerator = numerator.args[0]; - } - if (NodeType.isUnaryMinus(denominator)) { - denominator = denominator.args[0]; - } - } - return ((parseFloat(numerator.value)% 1 ===0) && - (parseFloat(denominator.value)%1 === 0)); - }; -} - -export = NodeType; diff --git a/lib/mathNode/index.js b/lib/mathNode/index.js deleted file mode 100644 index f37372df..00000000 --- a/lib/mathNode/index.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -var Creator = require("./Creator"); -var PolynomialTerm = require("./PolynomialTerm"); -var Status = require("./Status"); -var Type = require("./Type"); -var tmp; -tmp = { - Creator: Creator, - PolynomialTerm: PolynomialTerm, - Status: Status, - Type: Type -}; -module.exports = tmp; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/mathNode/index.js.map b/lib/mathNode/index.js.map deleted file mode 100644 index dbeaf38c..00000000 --- a/lib/mathNode/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,mCAAsC;AACtC,iDAAoD;AACpD,iCAAoC;AACpC,6BAAgC;AAChC,IAAI,GAAG,CAAC;AACR,GAAG,GAAG;IACF,OAAO,SAAA;IACP,cAAc,gBAAA;IACd,MAAM,QAAA;IACN,IAAI,MAAA;CACP,CAAC;AACF,iBAAS,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/mathNode/index.ts b/lib/mathNode/index.ts deleted file mode 100644 index 5ef72d2a..00000000 --- a/lib/mathNode/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Creator = require("./Creator"); -import PolynomialTerm = require("./PolynomialTerm"); -import Status = require("./Status"); -import Type = require("./Type"); -var tmp; -tmp = { - Creator, - PolynomialTerm, - Status, - Type -}; -export = tmp; diff --git a/lib/simplifyExpression/arithmeticSearch/index.js b/lib/simplifyExpression/arithmeticSearch/index.js deleted file mode 100644 index d11ddc90..00000000 --- a/lib/simplifyExpression/arithmeticSearch/index.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var evaluate = require("../../util/evaluate"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -// Searches through the tree, prioritizing deeper nodes, and evaluates -// arithmetic (e.g. 2+2 or 3*5*2) on an operation node if possible. -// Returns a mathNode.Status object. -var search = TreeSearch.postOrder(arithmetic); -// evaluates arithmetic (e.g. 2+2 or 3*5*2) on an operation node. -// Returns a mathNode.Status object. -function arithmetic(node) { - if (!mathNode.Type.isOperator(node)) { - return mathNode.Status.noChange(node); - } - if (!node.args.every(function (child) { return mathNode.Type.isConstant(child, true); })) { - return mathNode.Status.noChange(node); - } - // we want to eval each arg so unary minuses around constant nodes become - // constant nodes with negative values - node.args.forEach(function (arg, i) { - node.args[i] = mathNode.Creator.constant(evaluate(arg)); - }); - // Only resolve division of integers if we get an integer result. - // Note that a fraction of decimals will be divided out. - if (mathNode.Type.isIntegerFraction(node)) { - var numeratorValue = parseInt(node.args[0]); - var denominatorValue = parseInt(node.args[1]); - if (numeratorValue % denominatorValue === 0) { - var newNode = mathNode.Creator.constant(numeratorValue / denominatorValue); - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } - } - else { - var evaluatedValue = evaluateAndRound(node); - var newNode = mathNode.Creator.constant(evaluatedValue); - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); - } -} -// Evaluates a math expression to a constant, e.g. 3+4 -> 7 and rounds if -// necessary -function evaluateAndRound(node) { - var result = evaluate(node); - if (result < 1) { - result = parseFloat(result.toPrecision(4)); - } - else { - result = parseFloat(result.toFixed(4)); - } - return result; -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/arithmeticSearch/index.js.map b/lib/simplifyExpression/arithmeticSearch/index.js.map deleted file mode 100644 index aecc8952..00000000 --- a/lib/simplifyExpression/arithmeticSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,8CAAiD;AACjD,yCAA4C;AAC5C,6CAAgD;AAEhD,sEAAsE;AACtE,mEAAmE;AACnE,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAEhD,iEAAiE;AACjE,oCAAoC;AACpC,oBAAoB,IAAI;IACtB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAA,KAAK,IAAI,OAAA,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,EAArC,CAAqC,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,yEAAyE;IACzE,sCAAsC;IACtC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,iEAAiE;IACjE,wDAAwD;IACxD,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAM,gBAAgB,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,EAAE,CAAC,CAAC,cAAc,GAAG,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5C,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,GAAC,gBAAgB,CAAC,CAAC;YAC3E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,IAAM,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,YAAY;AACZ,0BAA0B,IAAI;IAC5B,IAAI,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,GAAI,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,GAAI,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,CAAC,MAAM,CAAC;AAChB,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/arithmeticSearch/index.ts b/lib/simplifyExpression/arithmeticSearch/index.ts deleted file mode 100644 index bb2fce50..00000000 --- a/lib/simplifyExpression/arithmeticSearch/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import evaluate = require("../../util/evaluate"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); - -// Searches through the tree, prioritizing deeper nodes, and evaluates -// arithmetic (e.g. 2+2 or 3*5*2) on an operation node if possible. -// Returns a mathNode.Status object. -const search = TreeSearch.postOrder(arithmetic); - -// evaluates arithmetic (e.g. 2+2 or 3*5*2) on an operation node. -// Returns a mathNode.Status object. -function arithmetic(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node)) { - return mathNode.Status.noChange(node); - } - if (!node.args.every(child => mathNode.Type.isConstant(child, true))) { - return mathNode.Status.noChange(node); - } - - // we want to eval each arg so unary minuses around constant nodes become - // constant nodes with negative values - node.args.forEach((arg, i) => { - node.args[i] = mathNode.Creator.constant(evaluate(arg)); - }); - - // Only resolve division of integers if we get an integer result. - // Note that a fraction of decimals will be divided out. - if (mathNode.Type.isIntegerFraction(node)) { - const numeratorValue = parseInt(node.args[0]); - const denominatorValue = parseInt(node.args[1]); - if (numeratorValue % denominatorValue === 0) { - const newNode = mathNode.Creator.constant(numeratorValue/denominatorValue); - return mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } - } - else { - const evaluatedValue = evaluateAndRound(node); - const newNode = mathNode.Creator.constant(evaluatedValue); - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode); - } -} - -// Evaluates a math expression to a constant, e.g. 3+4 -> 7 and rounds if -// necessary -function evaluateAndRound(node: mathjs.MathNode) { - let result = evaluate(node); - if (result < 1) { - result = parseFloat(result.toPrecision(4)); - } - else { - result = parseFloat(result.toFixed(4)); - } - return result; -} - -export = search; diff --git a/lib/simplifyExpression/basicsSearch/index.js b/lib/simplifyExpression/basicsSearch/index.js deleted file mode 100644 index 055d0989..00000000 --- a/lib/simplifyExpression/basicsSearch/index.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Performs simpifications that are more basic and overaching like (...)^0 => 1 - * These are always the first simplifications that are attempted. - */ -"use strict"; -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -var rearrangeCoefficient = require("./rearrangeCoefficient"); -var reduceExponentByZero = require("./reduceExponentByZero"); -var reduceMultiplicationByZero = require("./reduceMultiplicationByZero"); -var reduceZeroDividedByAnything = require("./reduceZeroDividedByAnything"); -var removeAdditionOfZero = require("./removeAdditionOfZero"); -var removeDivisionByOne = require("./removeDivisionByOne"); -var removeExponentBaseOne = require("./removeExponentBaseOne"); -var removeExponentByOne = require("./removeExponentByOne"); -var removeMultiplicationByNegativeOne = require("./removeMultiplicationByNegativeOne"); -var removeMultiplicationByOne = require("./removeMultiplicationByOne"); -var simplifyDoubleUnaryMinus = require("./simplifyDoubleUnaryMinus"); -var simplificationFunctions = [ - // multiplication by 0 yields 0 - reduceMultiplicationByZero, - // division of 0 by something yields 0 - reduceZeroDividedByAnything, - // ____^0 --> 1 - reduceExponentByZero, - // Check for x^1 which should be reduced to x - removeExponentByOne, - // Check for 1^x which should be reduced to 1 - // if x can be simplified to a constant - removeExponentBaseOne, - // - - becomes + - simplifyDoubleUnaryMinus, - // If this is a + node and one of the operands is 0, get rid of the 0 - removeAdditionOfZero, - // If this is a * node and one of the operands is 1, get rid of the 1 - removeMultiplicationByOne, - // In some cases, remove multiplying by -1 - removeMultiplicationByNegativeOne, - // If this is a / node and the denominator is 1 or -1, get rid of it - removeDivisionByOne, - // e.g. x*5 -> 5x - rearrangeCoefficient, -]; -var search = TreeSearch.preOrder(basics); -// Look for basic step(s) to perform on a node. Returns a mathNode.Status object. -function basics(node) { - for (var i = 0; i < simplificationFunctions.length; i++) { - var nodeStatus = simplificationFunctions[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - else { - node = nodeStatus.newNode; - } - } - return mathNode.Status.noChange(node); -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/index.js.map b/lib/simplifyExpression/basicsSearch/index.js.map deleted file mode 100644 index d03848f0..00000000 --- a/lib/simplifyExpression/basicsSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,yCAA4C;AAC5C,6CAAgD;AAChD,6DAAgE;AAChE,6DAAgE;AAChE,yEAA4E;AAC5E,2EAA8E;AAC9E,6DAAgE;AAChE,2DAA8D;AAC9D,+DAAkE;AAClE,2DAA8D;AAC9D,uFAA0F;AAC1F,uEAA0E;AAC1E,qEAAwE;AACxE,IAAM,uBAAuB,GAAG;IAC9B,+BAA+B;IAC/B,0BAA0B;IAC1B,sCAAsC;IACtC,2BAA2B;IAC3B,eAAe;IACf,oBAAoB;IACpB,6CAA6C;IAC7C,mBAAmB;IACnB,6CAA6C;IAC7C,uCAAuC;IACvC,qBAAqB;IACrB,gBAAgB;IAChB,wBAAwB;IACxB,qEAAqE;IACrE,oBAAoB;IACpB,qEAAqE;IACrE,yBAAyB;IACzB,0CAA0C;IAC1C,iCAAiC;IACjC,oEAAoE;IACpE,mBAAmB;IACnB,iBAAiB;IACjB,oBAAoB;CACrB,CAAC;AAEF,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAE3C,iFAAiF;AACjF,gBAAgB,IAAqB;IACnC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,IAAM,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/index.ts b/lib/simplifyExpression/basicsSearch/index.ts deleted file mode 100644 index 1c6dc2ca..00000000 --- a/lib/simplifyExpression/basicsSearch/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Performs simpifications that are more basic and overaching like (...)^0 => 1 - * These are always the first simplifications that are attempted. - */ - -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); -import rearrangeCoefficient = require("./rearrangeCoefficient"); -import reduceExponentByZero = require("./reduceExponentByZero"); -import reduceMultiplicationByZero = require("./reduceMultiplicationByZero"); -import reduceZeroDividedByAnything = require("./reduceZeroDividedByAnything"); -import removeAdditionOfZero = require("./removeAdditionOfZero"); -import removeDivisionByOne = require("./removeDivisionByOne"); -import removeExponentBaseOne = require("./removeExponentBaseOne"); -import removeExponentByOne = require("./removeExponentByOne"); -import removeMultiplicationByNegativeOne = require("./removeMultiplicationByNegativeOne"); -import removeMultiplicationByOne = require("./removeMultiplicationByOne"); -import simplifyDoubleUnaryMinus = require("./simplifyDoubleUnaryMinus"); -const simplificationFunctions = [ - // multiplication by 0 yields 0 - reduceMultiplicationByZero, - // division of 0 by something yields 0 - reduceZeroDividedByAnything, - // ____^0 --> 1 - reduceExponentByZero, - // Check for x^1 which should be reduced to x - removeExponentByOne, - // Check for 1^x which should be reduced to 1 - // if x can be simplified to a constant - removeExponentBaseOne, - // - - becomes + - simplifyDoubleUnaryMinus, - // If this is a + node and one of the operands is 0, get rid of the 0 - removeAdditionOfZero, - // If this is a * node and one of the operands is 1, get rid of the 1 - removeMultiplicationByOne, - // In some cases, remove multiplying by -1 - removeMultiplicationByNegativeOne, - // If this is a / node and the denominator is 1 or -1, get rid of it - removeDivisionByOne, - // e.g. x*5 -> 5x - rearrangeCoefficient, -]; - -const search = TreeSearch.preOrder(basics); - -// Look for basic step(s) to perform on a node. Returns a mathNode.Status object. -function basics(node: mathjs.MathNode) { - for (let i = 0; i < simplificationFunctions.length; i++) { - const nodeStatus = simplificationFunctions[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - else { - node = nodeStatus.newNode; - } - } - return mathNode.Status.noChange(node); -} - -export = search; diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js deleted file mode 100644 index 32219a55..00000000 --- a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -var checks = require("../../checks"); -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// Rearranges something of the form x * 5 to be 5x, ie putting the coefficient -// in the right place. -// Returns a mathNode.Status object -function rearrangeCoefficient(node) { - if (!checks.canRearrangeCoefficient(node)) { - return mathNode.Status.noChange(node); - } - var newNode = clone(node); - var polyNode = new mathNode.PolynomialTerm(newNode.args[0]); - var constNode = newNode.args[1]; - var exponentNode = polyNode.getExponentNode(); - newNode = mathNode.Creator.polynomialTerm(polyNode.getSymbolNode(), exponentNode, constNode); - return mathNode.Status.nodeChanged(ChangeTypes.REARRANGE_COEFF, node, newNode); -} -module.exports = rearrangeCoefficient; -//# sourceMappingURL=rearrangeCoefficient.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map deleted file mode 100644 index 0f28b645..00000000 --- a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"rearrangeCoefficient.js","sourceRoot":"","sources":["rearrangeCoefficient.ts"],"names":[],"mappings":";AAAA,qCAAwC;AACxC,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,8EAA8E;AAC9E,sBAAsB;AACtB,mCAAmC;AACnC,8BAA8B,IAAqB;IACjD,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAE1B,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,IAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC;IAChD,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CACvC,QAAQ,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;IAErD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,eAAe,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,iBAAS,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts b/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts deleted file mode 100644 index de74dd3d..00000000 --- a/lib/simplifyExpression/basicsSearch/rearrangeCoefficient.ts +++ /dev/null @@ -1,26 +0,0 @@ -import checks = require("../../checks"); -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// Rearranges something of the form x * 5 to be 5x, ie putting the coefficient -// in the right place. -// Returns a mathNode.Status object -function rearrangeCoefficient(node: mathjs.MathNode) { - if (!checks.canRearrangeCoefficient(node)) { - return mathNode.Status.noChange(node); - } - - let newNode = clone(node); - - const polyNode = new mathNode.PolynomialTerm(newNode.args[0]); - const constNode = newNode.args[1]; - const exponentNode = polyNode.getExponentNode(); - newNode = mathNode.Creator.polynomialTerm( - polyNode.getSymbolNode(), exponentNode, constNode); - - return mathNode.Status.nodeChanged( - ChangeTypes.REARRANGE_COEFF, node, newNode); -} - -export = rearrangeCoefficient; diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js deleted file mode 100644 index 2829d560..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// If `node` is an exponent of something to 0, we can reduce that to just 1. -// Returns a mathNode.Status object. -function reduceExponentByZero(node) { - if (node.op !== "^") { - return mathNode.Status.noChange(node); - } - var exponent = node.args[1]; - if (mathNode.Type.isConstant(exponent) && exponent.value === "0") { - var newNode = mathNode.Creator.constant(1); - return mathNode.Status.nodeChanged(ChangeTypes.REDUCE_EXPONENT_BY_ZERO, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} -module.exports = reduceExponentByZero; -//# sourceMappingURL=reduceExponentByZero.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map deleted file mode 100644 index f51f9869..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"reduceExponentByZero.js","sourceRoot":"","sources":["reduceExponentByZero.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAE5C,4EAA4E;AAC5E,oCAAoC;AACpC,8BAA8B,IAAqB;IACjD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QACjE,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,uBAAuB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts b/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts deleted file mode 100644 index d7151113..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceExponentByZero.ts +++ /dev/null @@ -1,21 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is an exponent of something to 0, we can reduce that to just 1. -// Returns a mathNode.Status object. -function reduceExponentByZero(node: mathjs.MathNode) { - if (node.op !== "^") { - return mathNode.Status.noChange(node); - } - const exponent = node.args[1]; - if (mathNode.Type.isConstant(exponent) && exponent.value === "0") { - const newNode = mathNode.Creator.constant(1); - return mathNode.Status.nodeChanged( - ChangeTypes.REDUCE_EXPONENT_BY_ZERO, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} - -export = reduceExponentByZero; diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js deleted file mode 100644 index 7c7f6ef3..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -function reduceMultiplicationByZero(node) { - if (node.op !== "*") { - return mathNode.Status.noChange(node); - } - var zeroIndex = node.args.findIndex(function (arg) { - if (mathNode.Type.isConstant(arg) && arg.value === "0") { - return true; - } - if (mathNode.PolynomialTerm.isPolynomialTerm(arg)) { - var polyTerm = new mathNode.PolynomialTerm(arg); - return polyTerm.getCoeffValue() === 0; - } - return false; - }); - if (zeroIndex >= 0) { - // reduce to just the 0 node - var newNode = mathNode.Creator.constant(0); - return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_BY_ZERO, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} -module.exports = reduceMultiplicationByZero; -//# sourceMappingURL=reduceMultiplicationByZero.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map deleted file mode 100644 index 963c1406..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"reduceMultiplicationByZero.js","sourceRoot":"","sources":["reduceMultiplicationByZero.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAK5C,oCAAoC,IAAI;IACtC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QACvC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAClD,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,CAAC,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,4BAA4B;QAC5B,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,gBAAgB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts b/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts deleted file mode 100644 index 6ba40faf..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero.ts +++ /dev/null @@ -1,31 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is a multiplication node with 0 as one of its operands, -// reduce the node to 0. Returns a mathNode.Status object. -function reduceMultiplicationByZero(node: mathjs.MathNode) { - if (node.op !== "*") { - return mathNode.Status.noChange(node); - } - const zeroIndex = node.args.findIndex(arg => { - if (mathNode.Type.isConstant(arg) && arg.value === "0") { - return true; - } - if (mathNode.PolynomialTerm.isPolynomialTerm(arg)) { - const polyTerm = new mathNode.PolynomialTerm(arg); - return polyTerm.getCoeffValue() === 0; - } - return false; - }); - if (zeroIndex >= 0) { - // reduce to just the 0 node - const newNode = mathNode.Creator.constant(0); - return mathNode.Status.nodeChanged( - ChangeTypes.MULTIPLY_BY_ZERO, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} - -export = reduceMultiplicationByZero; diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js deleted file mode 100644 index b55b65e3..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// If `node` is a fraction with 0 as the numerator, reduce the node to 0. -// Returns a mathNode.Status object. -function reduceZeroDividedByAnything(node) { - if (node.op !== "/") { - return mathNode.Status.noChange(node); - } - if (node.args[0].value === "0") { - var newNode = mathNode.Creator.constant(0); - return mathNode.Status.nodeChanged(ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} -module.exports = reduceZeroDividedByAnything; -//# sourceMappingURL=reduceZeroDividedByAnything.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map deleted file mode 100644 index 21ebde07..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"reduceZeroDividedByAnything.js","sourceRoot":"","sources":["reduceZeroDividedByAnything.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAE5C,yEAAyE;AACzE,oCAAoC;AACpC,qCAAqC,IAAqB;IACxD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,qBAAqB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,2BAA2B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts b/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts deleted file mode 100644 index 0d657c83..00000000 --- a/lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.ts +++ /dev/null @@ -1,20 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is a fraction with 0 as the numerator, reduce the node to 0. -// Returns a mathNode.Status object. -function reduceZeroDividedByAnything(node: mathjs.MathNode) { - if (node.op !== "/") { - return mathNode.Status.noChange(node); - } - if (node.args[0].value === "0") { - const newNode = mathNode.Creator.constant(0); - return mathNode.Status.nodeChanged( - ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} - -export = reduceZeroDividedByAnything; diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js deleted file mode 100644 index ac9ea30e..00000000 --- a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -function removeAdditionOfZero(node) { - if (node.op !== "+") { - return mathNode.Status.noChange(node); - } - var zeroIndex = node.args.findIndex(function (arg) { - return mathNode.Type.isConstant(arg) && arg.value === "0"; - }); - var newNode = clone(node); - if (zeroIndex >= 0) { - // remove the 0 node - newNode.args.splice(zeroIndex, 1); - // if there's only one operand left, there's nothing left to add it to, - // so move it up the tree - if (newNode.args.length === 1) { - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_ADDING_ZERO, node, newNode); - } - return mathNode.Status.noChange(node); -} -module.exports = removeAdditionOfZero; -//# sourceMappingURL=removeAdditionOfZero.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map deleted file mode 100644 index 9ed4afe6..00000000 --- a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeAdditionOfZero.js","sourceRoot":"","sources":["removeAdditionOfZero.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAK5C,8BAA8B,IAAI;IAChC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QACvC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC;IAC5D,CAAC,CAAC,CAAC;IACH,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,oBAAoB;QACpB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAClC,uEAAuE;QACvE,yBAAyB;QACzB,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts b/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts deleted file mode 100644 index 9fa8a1b2..00000000 --- a/lib/simplifyExpression/basicsSearch/removeAdditionOfZero.ts +++ /dev/null @@ -1,29 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is an addition node with 0 as one of its operands, -// remove 0 from the operands list. Returns a mathNode.Status object. -function removeAdditionOfZero(node: mathjs.MathNode) { - if (node.op !== "+") { - return mathNode.Status.noChange(node); - } - const zeroIndex = node.args.findIndex(arg => { - return mathNode.Type.isConstant(arg) && arg.value === "0"; - }); - let newNode = clone(node); - if (zeroIndex >= 0) { - // remove the 0 node - newNode.args.splice(zeroIndex, 1); - // if there's only one operand left, there's nothing left to add it to, - // so move it up the tree - if (newNode.args.length === 1) { - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged( - ChangeTypes.REMOVE_ADDING_ZERO, node, newNode); - } - return mathNode.Status.noChange(node); -} - -export = removeAdditionOfZero; diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js deleted file mode 100644 index dc487f1e..00000000 --- a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var Negative = require("../../Negative"); -var mathNode = require("../../mathnode"); -// If `node` is a division operation of something by 1 or -1, we can remove the -// denominator. Returns a mathNode.Status object. -function removeDivisionByOne(node) { - if (node.op !== "/") { - return mathNode.Status.noChange(node); - } - var denominator = node.args[1]; - if (!mathNode.Type.isConstant(denominator)) { - return mathNode.Status.noChange(node); - } - var numerator = clone(node.args[0]); - // if denominator is -1, we make the numerator negative - if (parseFloat(denominator.value) === -1) { - // If the numerator was an operation, wrap it in parens before adding - - // to the front. - // e.g. 2+3 / -1 ---> -(2+3) - if (mathNode.Type.isOperator(numerator)) { - numerator = mathNode.Creator.parenthesis(numerator); - } - var changeType = Negative.isNegative(numerator) ? - ChangeTypes.RESOLVE_DOUBLE_MINUS : - ChangeTypes.DIVISION_BY_NEGATIVE_ONE; - numerator = Negative.negate(numerator); - return mathNode.Status.nodeChanged(changeType, node, numerator); - } - else if (parseFloat(denominator.value) === 1) { - return mathNode.Status.nodeChanged(ChangeTypes.DIVISION_BY_ONE, node, numerator); - } - else { - return mathNode.Status.noChange(node); - } -} -module.exports = removeDivisionByOne; -//# sourceMappingURL=removeDivisionByOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map deleted file mode 100644 index 29121f74..00000000 --- a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeDivisionByOne.js","sourceRoot":"","sources":["removeDivisionByOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAC5C,yCAA4C;AAE5C,+EAA+E;AAC/E,iDAAiD;AACjD,6BAA6B,IAAqB;IAChD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpC,uDAAuD;IACvD,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,uEAAuE;QACvE,gBAAgB;QAChB,4BAA4B;QAC5B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACxC,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACtD,CAAC;QACD,IAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;YAC/C,WAAW,CAAC,oBAAoB;YAChC,WAAW,CAAC,wBAAwB,CAAC;QACvC,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,eAAe,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts b/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts deleted file mode 100644 index c889b825..00000000 --- a/lib/simplifyExpression/basicsSearch/removeDivisionByOne.ts +++ /dev/null @@ -1,41 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import Negative = require("../../Negative"); -import mathNode = require("../../mathnode"); - -// If `node` is a division operation of something by 1 or -1, we can remove the -// denominator. Returns a mathNode.Status object. -function removeDivisionByOne(node: mathjs.MathNode) { - if (node.op !== "/") { - return mathNode.Status.noChange(node); - } - const denominator = node.args[1]; - if (!mathNode.Type.isConstant(denominator)) { - return mathNode.Status.noChange(node); - } - let numerator = clone(node.args[0]); - - // if denominator is -1, we make the numerator negative - if (parseFloat(denominator.value) === -1) { - // If the numerator was an operation, wrap it in parens before adding - - // to the front. - // e.g. 2+3 / -1 ---> -(2+3) - if (mathNode.Type.isOperator(numerator)) { - numerator = mathNode.Creator.parenthesis(numerator); - } - const changeType = Negative.isNegative(numerator) ? - ChangeTypes.RESOLVE_DOUBLE_MINUS : - ChangeTypes.DIVISION_BY_NEGATIVE_ONE; - numerator = Negative.negate(numerator); - return mathNode.Status.nodeChanged(changeType, node, numerator); - } - else if (parseFloat(denominator.value) === 1) { - return mathNode.Status.nodeChanged( - ChangeTypes.DIVISION_BY_ONE, node, numerator); - } - else { - return mathNode.Status.noChange(node); - } -} - -export = removeDivisionByOne; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js deleted file mode 100644 index b252c58a..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -var checks = require("../../checks"); -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// If `node` is of the form 1^x, reduces it to a node of the form 1. -// Returns a mathNode.Status object. -function removeExponentBaseOne(node) { - if (node.op === "^" && - checks.resolvesToConstant(node.args[1]) && - mathNode.Type.isConstant(node.args[0]) && - node.args[0].value === "1") { - var newNode = clone(node.args[0]); - return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_EXPONENT_BASE_ONE, node, newNode); - } - return mathNode.Status.noChange(node); -} -module.exports = removeExponentBaseOne; -//# sourceMappingURL=removeExponentBaseOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map deleted file mode 100644 index d68ed4b5..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeExponentBaseOne.js","sourceRoot":"","sources":["removeExponentBaseOne.ts"],"names":[],"mappings":";AAAA,qCAAwC;AACxC,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,oEAAoE;AACpE,oCAAoC;AACpC,+BAA+B,IAAqB;IAClD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG;QACf,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,wBAAwB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,qBAAqB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts deleted file mode 100644 index 7a34e018..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentBaseOne.ts +++ /dev/null @@ -1,20 +0,0 @@ -import checks = require("../../checks"); -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is of the form 1^x, reduces it to a node of the form 1. -// Returns a mathNode.Status object. -function removeExponentBaseOne(node: mathjs.MathNode) { - if (node.op === "^" && // an exponent with - checks.resolvesToConstant(node.args[1]) && // a power not a symbol and - mathNode.Type.isConstant(node.args[0]) && // a constant base - node.args[0].value === "1") { // of value 1 - const newNode = clone(node.args[0]); - return mathNode.Status.nodeChanged( - ChangeTypes.REMOVE_EXPONENT_BASE_ONE, node, newNode); - } - return mathNode.Status.noChange(node); -} - -export = removeExponentBaseOne; diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js deleted file mode 100644 index 6b3bc6e3..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// If `node` is of the form x^1, reduces it to a node of the form x. -// Returns a mathNode.Status object. -function removeExponentByOne(node) { - if (node.op === "^" && - mathNode.Type.isConstant(node.args[1]) && - node.args[1].value === "1") { - var newNode = clone(node.args[0]); - return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_EXPONENT_BY_ONE, node, newNode); - } - return mathNode.Status.noChange(node); -} -module.exports = removeExponentByOne; -//# sourceMappingURL=removeExponentByOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map b/lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map deleted file mode 100644 index da09389d..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentByOne.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeExponentByOne.js","sourceRoot":"","sources":["removeExponentByOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,oEAAoE;AACpE,oCAAoC;AACpC,6BAA6B,IAAqB;IAChD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG;QACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,sBAAsB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts b/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts deleted file mode 100644 index a5a1dd89..00000000 --- a/lib/simplifyExpression/basicsSearch/removeExponentByOne.ts +++ /dev/null @@ -1,18 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is of the form x^1, reduces it to a node of the form x. -// Returns a mathNode.Status object. -function removeExponentByOne(node: mathjs.MathNode) { - if (node.op === "^" && // exponent of anything - mathNode.Type.isConstant(node.args[1]) && // to a constant - node.args[1].value === "1") { // of value 1 - const newNode = clone(node.args[0]); - return mathNode.Status.nodeChanged( - ChangeTypes.REMOVE_EXPONENT_BY_ONE, node, newNode); - } - return mathNode.Status.noChange(node); -} - -export = removeExponentByOne; diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js deleted file mode 100644 index 63ae4cb2..00000000 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js +++ /dev/null @@ -1,44 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var Negative = require("../../Negative"); -var mathNode = require("../../mathnode"); -function removeMultiplicationByNegativeOne(node) { - if (node.op !== "*") { - return mathNode.Status.noChange(node); - } - var minusOneIndex = node.args.findIndex(function (arg) { - return mathNode.Type.isConstant(arg) && arg.value === "-1"; - }); - if (minusOneIndex < 0) { - return mathNode.Status.noChange(node); - } - // We might merge/combine the negative one into another node. This stores - // the index of that other node in the arg list. - var nodeToCombineIndex; - // If minus one is the last term, maybe combine with the term before - if (minusOneIndex + 1 === node.args.length) { - nodeToCombineIndex = minusOneIndex - 1; - } - else { - nodeToCombineIndex = minusOneIndex + 1; - } - var nodeToCombine = node.args[nodeToCombineIndex]; - // If it's a constant, the combining of those terms is handled elsewhere. - if (mathNode.Type.isConstant(nodeToCombine)) { - return mathNode.Status.noChange(node); - } - var newNode = clone(node); - // Get rid of the -1 - nodeToCombine = Negative.negate(clone(nodeToCombine)); - // replace the node next to -1 and remove -1 - newNode.args[nodeToCombineIndex] = nodeToCombine; - newNode.args.splice(minusOneIndex, 1); - // if there's only one operand left, move it up the tree - if (newNode.args.length === 1) { - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_MULTIPLYING_BY_NEGATIVE_ONE, node, newNode); -} -module.exports = removeMultiplicationByNegativeOne; -//# sourceMappingURL=removeMultiplicationByNegativeOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map deleted file mode 100644 index 124b0d76..00000000 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeMultiplicationByNegativeOne.js","sourceRoot":"","sources":["removeMultiplicationByNegativeOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAC5C,yCAA4C;AAO5C,2CAA2C,IAAI;IAC7C,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QAC3C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC;IAC7D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,yEAAyE;IACzE,gDAAgD;IAChD,IAAI,kBAAkB,CAAC;IACvB,oEAAoE;IACpE,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3C,kBAAkB,GAAG,aAAa,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,kBAAkB,GAAG,aAAa,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClD,yEAAyE;IACzE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAE1B,oBAAoB;IACpB,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IAEtD,4CAA4C;IAC5C,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,aAAa,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAEtC,wDAAwD;IACxD,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kCAAkC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,iBAAS,iCAAiC,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts b/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts deleted file mode 100644 index 9f037d0f..00000000 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.ts +++ /dev/null @@ -1,55 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import Negative = require("../../Negative"); -import mathNode = require("../../mathnode"); - -// If `node` is a multiplication node with -1 as one of its operands, -// and a non constant as the next operand, remove -1 from the operands -// list and make the next term have a unary minus. -// Returns a mathNode.Status object. -function removeMultiplicationByNegativeOne(node: mathjs.MathNode) { - if (node.op !== "*") { - return mathNode.Status.noChange(node); - } - const minusOneIndex = node.args.findIndex(arg => { - return mathNode.Type.isConstant(arg) && arg.value === "-1"; - }); - if (minusOneIndex < 0) { - return mathNode.Status.noChange(node); - } - - // We might merge/combine the negative one into another node. This stores - // the index of that other node in the arg list. - let nodeToCombineIndex; - // If minus one is the last term, maybe combine with the term before - if (minusOneIndex + 1 === node.args.length) { - nodeToCombineIndex = minusOneIndex - 1; - } - else { - nodeToCombineIndex = minusOneIndex + 1; - } - - let nodeToCombine = node.args[nodeToCombineIndex]; - // If it's a constant, the combining of those terms is handled elsewhere. - if (mathNode.Type.isConstant(nodeToCombine)) { - return mathNode.Status.noChange(node); - } - - let newNode = clone(node); - - // Get rid of the -1 - nodeToCombine = Negative.negate(clone(nodeToCombine)); - - // replace the node next to -1 and remove -1 - newNode.args[nodeToCombineIndex] = nodeToCombine; - newNode.args.splice(minusOneIndex, 1); - - // if there's only one operand left, move it up the tree - if (newNode.args.length === 1) { - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged( - ChangeTypes.REMOVE_MULTIPLYING_BY_NEGATIVE_ONE, node, newNode); -} - -export = removeMultiplicationByNegativeOne; diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js deleted file mode 100644 index 8fa3527b..00000000 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// If `node` is a multiplication node with 1 as one of its operands, -// remove 1 from the operands list. Returns a mathNode.Status object. -function removeMultiplicationByOne(node) { - if (node.op !== "*") { - return mathNode.Status.noChange(node); - } - var oneIndex = node.args.findIndex(function (arg) { - return mathNode.Type.isConstant(arg) && arg.value === "1"; - }); - if (oneIndex >= 0) { - var newNode = clone(node); - // remove the 1 node - newNode.args.splice(oneIndex, 1); - // if there's only one operand left, there's nothing left to multiply it - // to, so move it up the tree - if (newNode.args.length === 1) { - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged(ChangeTypes.REMOVE_MULTIPLYING_BY_ONE, node, newNode); - } - return mathNode.Status.noChange(node); -} -module.exports = removeMultiplicationByOne; -//# sourceMappingURL=removeMultiplicationByOne.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map deleted file mode 100644 index 5df017b6..00000000 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeMultiplicationByOne.js","sourceRoot":"","sources":["removeMultiplicationByOne.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,oEAAoE;AACpE,qEAAqE;AACrE,mCAAmC,IAAI;IACrC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAA,GAAG;QACtC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC;IAC5D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,oBAAoB;QACpB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACjC,wEAAwE;QACxE,6BAA6B;QAC7B,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,yBAAyB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,yBAAyB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts b/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts deleted file mode 100644 index 84c1f7bd..00000000 --- a/lib/simplifyExpression/basicsSearch/removeMultiplicationByOne.ts +++ /dev/null @@ -1,29 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// If `node` is a multiplication node with 1 as one of its operands, -// remove 1 from the operands list. Returns a mathNode.Status object. -function removeMultiplicationByOne(node: mathjs.MathNode) { - if (node.op !== "*") { - return mathNode.Status.noChange(node); - } - const oneIndex = node.args.findIndex(arg => { - return mathNode.Type.isConstant(arg) && arg.value === "1"; - }); - if (oneIndex >= 0) { - let newNode = clone(node); - // remove the 1 node - newNode.args.splice(oneIndex, 1); - // if there's only one operand left, there's nothing left to multiply it - // to, so move it up the tree - if (newNode.args.length === 1) { - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged( - ChangeTypes.REMOVE_MULTIPLYING_BY_ONE, node, newNode); - } - return mathNode.Status.noChange(node); -} - -export = removeMultiplicationByOne; diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js deleted file mode 100644 index 0d943a7c..00000000 --- a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js +++ /dev/null @@ -1,32 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// Simplifies two unary minuses in a row by removing both of them. -// e.g. -(- 4) --> 4 -function simplifyDoubleUnaryMinus(node) { - if (!mathNode.Type.isUnaryMinus(node)) { - return mathNode.Status.noChange(node); - } - var unaryArg = node.args[0]; - // e.g. in - -x, -x is the unary arg, and we'd want to reduce to just x - if (mathNode.Type.isUnaryMinus(unaryArg)) { - var newNode = clone(unaryArg.args[0]); - return mathNode.Status.nodeChanged(ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - else if (mathNode.Type.isConstant(unaryArg) && parseFloat(unaryArg.value) < 0) { - var newNode = mathNode.Creator.constant(parseFloat(unaryArg.value) * -1); - return mathNode.Status.nodeChanged(ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - else if (mathNode.Type.isParenthesis(unaryArg)) { - var parenthesisNode = unaryArg; - var parenthesisContent = parenthesisNode; - if (mathNode.Type.isUnaryMinus(parenthesisContent)) { - var newNode = mathNode.Creator.parenthesis(parenthesisContent.args[0]); - return mathNode.Status.nodeChanged(ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - } - return mathNode.Status.noChange(node); -} -module.exports = simplifyDoubleUnaryMinus; -//# sourceMappingURL=simplifyDoubleUnaryMinus.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map deleted file mode 100644 index e174a1c7..00000000 --- a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"simplifyDoubleUnaryMinus.js","sourceRoot":"","sources":["simplifyDoubleUnaryMinus.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAE5C,kEAAkE;AAClE,oBAAoB;AACpB,kCAAkC,IAAqB;IACrD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,uEAAuE;IACvE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACzC,IAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9E,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAM,eAAe,GAAG,QAAQ,CAAC;QACjC,IAAM,kBAAkB,GAAG,eAAe,CAAC;QAC3C,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;YACnD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,wBAAwB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts b/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts deleted file mode 100644 index 8a6efd16..00000000 --- a/lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.ts +++ /dev/null @@ -1,37 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// Simplifies two unary minuses in a row by removing both of them. -// e.g. -(- 4) --> 4 -function simplifyDoubleUnaryMinus(node: mathjs.MathNode) { - if (!mathNode.Type.isUnaryMinus(node)) { - return mathNode.Status.noChange(node); - } - const unaryArg = node.args[0]; - // e.g. in - -x, -x is the unary arg, and we'd want to reduce to just x - if (mathNode.Type.isUnaryMinus(unaryArg)) { - const newNode = clone(unaryArg.args[0]); - return mathNode.Status.nodeChanged( - ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - // e.g. - -4, -4 could be a constant with negative value - else if (mathNode.Type.isConstant(unaryArg) && parseFloat(unaryArg.value) < 0) { - const newNode = mathNode.Creator.constant(parseFloat(unaryArg.value) * -1); - return mathNode.Status.nodeChanged( - ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - // e.g. -(-(5+2)) - else if (mathNode.Type.isParenthesis(unaryArg)) { - const parenthesisNode = unaryArg; - const parenthesisContent = parenthesisNode; - if (mathNode.Type.isUnaryMinus(parenthesisContent)) { - const newNode = mathNode.Creator.parenthesis(parenthesisContent.args[0]); - return mathNode.Status.nodeChanged( - ChangeTypes.RESOLVE_DOUBLE_MINUS, node, newNode); - } - } - return mathNode.Status.noChange(node); -} - -export = simplifyDoubleUnaryMinus; diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.js b/lib/simplifyExpression/breakUpNumeratorSearch/index.js deleted file mode 100644 index 36f0e233..00000000 --- a/lib/simplifyExpression/breakUpNumeratorSearch/index.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -// Breaks up any fraction (deeper nodes getting priority) that has a numerator -// that is a sum. e.g. (2+x)/5 -> (2/5 + x/5) -// This step must happen after things have been collected and combined, or -// else things will infinite loop, so it's a tree search of its own. -// Returns a mathNode.Status object -var search = TreeSearch.postOrder(breakUpNumerator); -function breakUpNumerator(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "/") { - return mathNode.Status.noChange(node); - } - var numerator = node.args[0]; - if (mathNode.Type.isParenthesis(numerator)) { - numerator = numerator.content; - } - if (!mathNode.Type.isOperator(numerator) || numerator.op !== "+") { - return mathNode.Status.noChange(node); - } - // At this point, we know that node is a fraction and its numerator is a sum - // of terms that can't be collected or combined, so we should break it up. - var fractionList = []; - var denominator = node.args[1]; - numerator.args.forEach(function (arg) { - var newFraction = mathNode.Creator.operator("/", [arg, denominator]); - newFraction.changeGroup = 1; - fractionList.push(newFraction); - }); - var newNode = mathNode.Creator.operator("+", fractionList); - // Wrap in parens for cases like 2*(2+3)/5 => 2*(2/5 + 3/5) - newNode = mathNode.Creator.parenthesis(newNode); - node.changeGroup = 1; - return mathNode.Status.nodeChanged(ChangeTypes.BREAK_UP_FRACTION, node, newNode, false); -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.js.map b/lib/simplifyExpression/breakUpNumeratorSearch/index.js.map deleted file mode 100644 index 13853c0a..00000000 --- a/lib/simplifyExpression/breakUpNumeratorSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,8EAA8E;AAC9E,6CAA6C;AAC7C,0EAA0E;AAC1E,oEAAoE;AACpE,mCAAmC;AACnC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAMtD,0BAA0B,IAAI;IAC5B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3C,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC;IAChC,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,4EAA4E;IAC5E,0EAA0E;IAC1E,IAAM,YAAY,GAAG,EAAE,CAAC;IACxB,IAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAA,GAAG;QACxB,IAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;QACvE,WAAW,CAAC,WAAW,GAAG,CAAC,CAAC;QAC5B,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC3D,2DAA2D;IAC3D,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACrB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/breakUpNumeratorSearch/index.ts b/lib/simplifyExpression/breakUpNumeratorSearch/index.ts deleted file mode 100644 index a2a37e89..00000000 --- a/lib/simplifyExpression/breakUpNumeratorSearch/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); - -// Breaks up any fraction (deeper nodes getting priority) that has a numerator -// that is a sum. e.g. (2+x)/5 -> (2/5 + x/5) -// This step must happen after things have been collected and combined, or -// else things will infinite loop, so it's a tree search of its own. -// Returns a mathNode.Status object -const search = TreeSearch.postOrder(breakUpNumerator); - -// If `node` is a fraction with a numerator that is a sum, breaks up the -// fraction e.g. (2+x)/5 -> (2/5 + x/5) -// Returns a mathNode.Status object -function breakUpNumerator(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "/") { - return mathNode.Status.noChange(node); - } - let numerator = node.args[0]; - if (mathNode.Type.isParenthesis(numerator)) { - numerator = numerator.content; - } - if (!mathNode.Type.isOperator(numerator) || numerator.op !== "+") { - return mathNode.Status.noChange(node); - } - - // At this point, we know that node is a fraction and its numerator is a sum - // of terms that can't be collected or combined, so we should break it up. - const fractionList = []; - const denominator = node.args[1]; - numerator.args.forEach(arg => { - const newFraction = mathNode.Creator.operator("/", [arg, denominator]); - newFraction.changeGroup = 1; - fractionList.push(newFraction); - }); - - let newNode = mathNode.Creator.operator("+", fractionList); - // Wrap in parens for cases like 2*(2+3)/5 => 2*(2/5 + 3/5) - newNode = mathNode.Creator.parenthesis(newNode); - node.changeGroup = 1; - return mathNode.Status.nodeChanged( - ChangeTypes.BREAK_UP_FRACTION, node, newNode, false); -} - -export = search; diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js deleted file mode 100644 index d48fa5cc..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js +++ /dev/null @@ -1,236 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var print = require("../../util/print"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -var Util = require("../../util/Util"); -var CONSTANT = 'constant'; -var CONSTANT_FRACTION = 'constantFraction'; -var OTHER = 'other'; -var LikeTermCollector = (function () { - function LikeTermCollector() { - // Collects like terms for an operation node and returns a mathNode.Status object. - this.collectLikeTerms = function (node) { - if (!LikeTermCollector.canCollectLikeTerms(node)) { - return mathNode.Status.noChange(node); - } - var op = node.op; - var terms; - if (op === '+') { - terms = getTermsForCollectingAddition(node); - } - else if (op === '*') { - terms = getTermsForCollectingMultiplication(node); - } - else { - throw Error('Operation not supported: ' + op); - } - // List the symbols alphabetically - var termTypesSorted = Object.keys(terms) - .filter(function (x) { return (x !== CONSTANT && x !== CONSTANT_FRACTION && x !== OTHER); }) - .sort(sortTerms); - // Then add const - if (terms[CONSTANT]) { - // at the end for addition (since we'd expect x^2 + (x + x) + 4) - if (op === '+') { - termTypesSorted.push(CONSTANT); - } - // for multipliation it should be at the front (e.g. (3*4) * x^2) - if (op === '*') { - termTypesSorted.unshift(CONSTANT); - } - } - if (terms[CONSTANT_FRACTION]) { - termTypesSorted.push(CONSTANT_FRACTION); - } - // Collect the new operands under op. - var newOperands = []; - var changeGroup = 1; - termTypesSorted.forEach(function (termType) { - var termsOfType = terms[termType]; - if (termsOfType.length === 1) { - var singleTerm = clone(termsOfType[0]); - singleTerm.changeGroup = changeGroup; - newOperands.push(singleTerm); - } - else { - var termList = clone(mathNode.Creator.parenthesis(mathNode.Creator.operator(op, termsOfType))); - termList.changeGroup = changeGroup; - newOperands.push(termList); - } - termsOfType.forEach(function (term) { - term.changeGroup = changeGroup; - }); - changeGroup++; - }); - // then stick anything else (paren nodes, operator nodes) at the end - if (terms[OTHER]) { - newOperands = newOperands.concat(terms[OTHER]); - } - var newNode = clone(node); - newNode.args = newOperands; - return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_LIKE_TERMS, node, newNode, false); - }; - } - return LikeTermCollector; -}()); -// Given an expression tree, returns true if there are terms that can be -// collected -LikeTermCollector.canCollectLikeTerms = function (node) { - // We can collect like terms through + or through * - // Note that we never collect like terms with - or /, those expressions will - // always be manipulated in flattenOperands so that the top level operation is - // + or *. - if (!(mathNode.Type.isOperator(node, '+') || mathNode.Type.isOperator(node, '*'))) { - return false; - } - var terms; - if (node.op === '+') { - terms = getTermsForCollectingAddition(node); - } - else if (node.op === '*') { - terms = getTermsForCollectingMultiplication(node); - } - else { - throw Error('Operation not supported: ' + node.op); - } - // Conditions we need to meet to decide to to reorganize (collect) the terms: - // - more than 1 term type - // - more than 1 of at least one type (not including other) - // (note that this means x^2 + x + x + 2 -> x^2 + (x + x) + 2, - // which will be recorded as a step, but doesn't change the order of terms) - var termTypes = Object.keys(terms); - var filteredTermTypes = termTypes.filter(function (x) { return x !== OTHER; }); - return (termTypes.length > 1 && - filteredTermTypes.some(function (x) { return terms[x].length > 1; })); -}; -// Polyonomial terms are collected by categorizing them by their 'name' -// which is used to separate them into groups that can be combined. getTermName -// returns this group 'name' -function getTermName(node, op) { - var polyNode = new mathNode.PolynomialTerm(node); - // we 'name' polynomial terms by their symbol name - var termName = polyNode.getSymbolName(); - // when adding terms, the exponent matters too (e.g. 2x^2 + 5x^3 can't be combined) - if (op === '+') { - var exponent = print(polyNode.getExponentNode(true)); - termName += '^' + exponent; - } - return termName; -} -// Collects like terms in an addition expression tree into categories. -// Returns a dictionary of termname to lists of nodes with that name -// e.g. 2x + 4 + 5x would return {'x': [2x, 5x], CONSTANT: [4]} -// (where 2x, 5x, and 4 would actually be expression trees) -function getTermsForCollectingAddition(node) { - var terms = {}; - for (var i = 0; i < node.args.length; i++) { - var child = node.args[i]; - if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { - var termName = getTermName(child, '+'); - terms = Util.appendToArrayInObject(terms, termName, child); - } - else if (mathNode.Type.isIntegerFraction(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT_FRACTION, child); - } - else if (mathNode.Type.isConstant(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, child); - } - else if (mathNode.Type.isOperator(node) || - mathNode.Type.isFunction(node) || - mathNode.Type.isParenthesis(node) || - mathNode.Type.isUnaryMinus(node)) { - terms = Util.appendToArrayInObject(terms, OTHER, child); - } - else { - // Note that we shouldn't get any symbol nodes in the switch statement - // since they would have been handled by isPolynomialTerm - throw Error('Unsupported node type: ' + child.type); - } - } - // If there's exactly one constant and one fraction, we collect them - // to add them together. - // e.g. 2 + 1/3 + 5 would collect the constants (2+5) + 1/3 - // but 2 + 1/3 + x would collect (2 + 1/3) + x so we can add them together - if (terms[CONSTANT] && terms[CONSTANT].length === 1 && - terms[CONSTANT_FRACTION] && terms[CONSTANT_FRACTION].length === 1) { - var fraction = terms[CONSTANT_FRACTION][0]; - terms = Util.appendToArrayInObject(terms, CONSTANT, fraction); - delete terms[CONSTANT_FRACTION]; - } - return terms; -} -function getTermsForCollectingMultiplication(node) { - var terms = {}; - for (var i = 0; i < node.args.length; i++) { - var child = node.args[i]; - if (mathNode.Type.isUnaryMinus(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, mathNode.Creator.constant(-1)); - child = child.args[0]; - } - if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { - terms = addToTermsforPolynomialMultiplication(terms, child); - } - else if (mathNode.Type.isIntegerFraction(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, child); - } - else if (mathNode.Type.isConstant(child)) { - terms = Util.appendToArrayInObject(terms, CONSTANT, child); - } - else if (mathNode.Type.isOperator(node) || - mathNode.Type.isFunction(node) || - mathNode.Type.isParenthesis(node) || - mathNode.Type.isUnaryMinus(node)) { - terms = Util.appendToArrayInObject(terms, OTHER, child); - } - else { - // Note that we shouldn't get any symbol nodes in the switch statement - // since they would have been handled by isPolynomialTerm - throw Error('Unsupported node type: ' + child.type); - } - } - return terms; -} -function addToTermsforPolynomialMultiplication(terms, node) { - var polyNode = new mathNode.PolynomialTerm(node); - var termName; - if (!polyNode.hasCoeff()) { - termName = getTermName(node, '*'); - terms = Util.appendToArrayInObject(terms, termName, node); - } - else { - var coefficient = polyNode.getCoeffNode(); - var termWithoutCoefficient = polyNode.getSymbolNode(); - if (polyNode.getExponentNode()) { - termWithoutCoefficient = mathNode.Creator.operator('^', [termWithoutCoefficient, polyNode.getExponentNode()]); - } - terms = Util.appendToArrayInObject(terms, CONSTANT, coefficient); - termName = getTermName(termWithoutCoefficient, '*'); - terms = Util.appendToArrayInObject(terms, termName, termWithoutCoefficient); - } - return terms; -} -// Sort function for termnames. Sort first by symbol name, and then by exponent. -function sortTerms(a, b) { - if (a === b) { - return 0; - } - // if no exponent, sort alphabetically - if (a.indexOf('^') === -1) { - return a < b ? -1 : 1; - } - else { - var symbA = a.split('^')[0]; - var expA = a.split('^')[1]; - var symbB = b.split('^')[0]; - var expB = b.split('^')[1]; - if (symbA !== symbB) { - return symbA < symbB ? -1 : 1; - } - else { - return expA > expB ? -1 : 1; - } - } -} -module.exports = LikeTermCollector; -//# sourceMappingURL=LikeTermCollector.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map deleted file mode 100644 index 4584c1b7..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"LikeTermCollector.js","sourceRoot":"","sources":["LikeTermCollector.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts b/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts deleted file mode 100644 index 7affb9d0..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector.ts +++ /dev/null @@ -1,274 +0,0 @@ -import clone = require("../../util/clone"); -import print = require("../../util/print"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); -import Util = require("../../util/Util"); -const constant = "constant"; -const constantFraction = "constantFraction"; -const other = "other"; - -class LikeTermCollector{ - -// Given an expression tree, returns true if there are terms that can be -// collected - static canCollectLikeTerms = node => { - // We can collect like terms through + or through * - // Note that we never collect like terms with - or /, those expressions will - // always be manipulated in flattenOperands so that the top level operation is - // + or *. - if (!(mathNode.Type.isOperator(node, "+") || mathNode.Type.isOperator(node, "*"))) { - return false; - } - - let terms; - if (node.op === "+") { - terms = getTermsForCollectingAddition(node); - } - else if (node.op === "*") { - terms = getTermsForCollectingMultiplication(node); - } - else { - throw Error("Operation not supported: " + node.op); - } - - // Conditions we need to meet to decide to to reorganize (collect) the terms: - // - more than 1 term type - // - more than 1 of at least one type (not including other) - // (note that this means x^2 + x + x + 2 -> x^2 + (x + x) + 2, - // which will be recorded as a step, but doesn't change the order of terms) - const termTypes = Object.keys(terms); - const filteredTermTypes = termTypes.filter(x => x !== other); - return (termTypes.length > 1 && - filteredTermTypes.some(x => terms[x].length > 1)); -}; - -// Collects like terms for an operation node and returns a mathNode.Status object. -collectLikeTerms = node => { - if (!LikeTermCollector.canCollectLikeTerms(node)) { - return mathNode.Status.noChange(node); - } - - const op = node.op; - let terms: {}; - if (op === "+") { - terms = getTermsForCollectingAddition(node); - } - else if (op === "*") { - terms = getTermsForCollectingMultiplication(node); - } - else { - throw Error("Operation not supported: " + op); - } - - // List the symbols alphabetically - const termTypesSorted = Object.keys(terms) - .filter(x => (x !== constant && x !== constantFraction && x !== other)) - .sort(sortTerms); - - - // Then add const - if (terms[constant]) { - // at the end for addition (since we'd expect x^2 + (x + x) + 4) - if (op === "+") { - termTypesSorted.push(constant); - } - // for multipliation it should be at the front (e.g. (3*4) * x^2) - if (op === "*") { - termTypesSorted.unshift(constant); - } - } - if (terms[constantFraction]) { - termTypesSorted.push(constantFraction); - } - - // Collect the new operands under op. - let newOperands = []; - let changeGroup = 1; - termTypesSorted.forEach(termType => { - const termsOfType = terms[termType]; - if (termsOfType.length === 1) { - const singleTerm = clone(termsOfType[0]); - singleTerm.changeGroup = changeGroup; - newOperands.push(singleTerm); - } - // Any like terms should be wrapped in parens. - else { - const termList = clone(mathNode.Creator.parenthesis( - mathNode.Creator.operator(op, termsOfType))); - termList.changeGroup = changeGroup; - newOperands.push(termList); - } - termsOfType.forEach(term => { - term.changeGroup = changeGroup; - }); - changeGroup++; - }); - - // then stick anything else (paren nodes, operator nodes) at the end - if (terms[other]) { - newOperands = newOperands.concat(terms[other]); - } - - const newNode = clone(node); - newNode.args = newOperands; - return mathNode.Status.nodeChanged( - ChangeTypes.COLLECT_LIKE_TERMS, node, newNode, false); -}; -} -// Polyonomial terms are collected by categorizing them by their 'name' -// which is used to separate them into groups that can be combined. getTermName -// returns this group 'name' -function getTermName(node, op) { - const polyNode = new mathNode.PolynomialTerm(node); - // we 'name' polynomial terms by their symbol name - let termName = polyNode.getSymbolName(); - // when adding terms, the exponent matters too (e.g. 2x^2 + 5x^3 can't be combined) - if (op === "+") { - const exponent = print(polyNode.getExponentNode(true)); - termName += "^" + exponent; - } - return termName; -} - -// Collects like terms in an addition expression tree into categories. -// Returns a dictionary of termname to lists of nodes with that name -// e.g. 2x + 4 + 5x would return {'x': [2x, 5x], CONSTANT: [4]} -// (where 2x, 5x, and 4 would actually be expression trees) -function getTermsForCollectingAddition(node) { - let terms = {}; - - for (let i = 0; i < node.args.length; i++) { - const child = node.args[i]; - - if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { - const termName = getTermName(child, "+"); - terms = Util.appendToArrayInObject(terms, termName, child); - } - else if (mathNode.Type.isIntegerFraction(child)) { - terms = Util.appendToArrayInObject(terms, constantFraction, child); - } - else if (mathNode.Type.isConstant(child)) { - terms = Util.appendToArrayInObject(terms, constant, child); - } - else if (mathNode.Type.isOperator(node) || - mathNode.Type.isFunction(node) || - mathNode.Type.isParenthesis(node) || - mathNode.Type.isUnaryMinus(node)) { - terms = Util.appendToArrayInObject(terms, other, child); - } - else { - // Note that we shouldn't get any symbol nodes in the switch statement - // since they would have been handled by isPolynomialTerm - throw Error("Unsupported node type: " + child.type); - } - } - // If there's exactly one constant and one fraction, we collect them - // to add them together. - // e.g. 2 + 1/3 + 5 would collect the constants (2+5) + 1/3 - // but 2 + 1/3 + x would collect (2 + 1/3) + x so we can add them together - if (terms[constant] && terms[constant].length === 1 && - terms[constantFraction] && terms[constantFraction].length === 1) { - const fraction = terms[constantFraction][0]; - terms = Util.appendToArrayInObject(terms, constant, fraction); - delete terms[constantFraction]; - } - - return terms; -} - -// Collects like terms in a multiplication expression tree into categories. -// For multiplication, polynomial terms with constants are separated into -// a symbolic term and a constant term. -// Returns a dictionary of termname to lists of nodes with that name -// e.g. 2x + 4 + 5x^2 would return {'x': [x, x^2], CONSTANT: [2, 4, 5]} -// (where x, x^2, 2, 4, and 5 would actually be expression trees) -function getTermsForCollectingMultiplication(node: any); -function getTermsForCollectingMultiplication(node) { - let terms = {}; - - for (let i = 0; i < node.args.length; i++) { - let child = node.args[i]; - - if (mathNode.Type.isUnaryMinus(child)) { - terms = Util.appendToArrayInObject( - terms, constant, mathNode.Creator.constant(-1)); - child = child.args[0]; - } - if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { - terms = addToTermsforPolynomialMultiplication(terms, child); - } - else if (mathNode.Type.isIntegerFraction(child)) { - terms = Util.appendToArrayInObject(terms, constant, child); - } - else if (mathNode.Type.isConstant(child)) { - terms = Util.appendToArrayInObject(terms, constant, child); - } - else if (mathNode.Type.isOperator(node) || - mathNode.Type.isFunction(node) || - mathNode.Type.isParenthesis(node) || - mathNode.Type.isUnaryMinus(node)) { - terms = Util.appendToArrayInObject(terms, other, child); - } - else { - // Note that we shouldn't get any symbol nodes in the switch statement - // since they would have been handled by isPolynomialTerm - throw Error("Unsupported node type: " + child.type); - } - } - return terms; -} - -// A helper function for getTermsForCollectingMultiplication -// Polynomial terms need to be divided into their coefficient + symbolic parts. -// e.g. 2x^4 -> 2 (coeffient) and x^4 (symbolic, named after the symbol node) -// Takes the terms list and the polynomial term node, and returns an updated -// terms list. -function addToTermsforPolynomialMultiplication(terms: any, node: any); -function addToTermsforPolynomialMultiplication(terms, node) { - const polyNode = new mathNode.PolynomialTerm(node); - let termName; - - if (!polyNode.hasCoeff()) { - termName = getTermName(node, "*"); - terms = Util.appendToArrayInObject(terms, termName, node); - } - else { - const coefficient = polyNode.getCoeffNode(); - let termWithoutCoefficient = polyNode.getSymbolNode(); - if (polyNode.getExponentNode()) { - termWithoutCoefficient = mathNode.Creator.operator( - "^", [termWithoutCoefficient, polyNode.getExponentNode()]); - } - - terms = Util.appendToArrayInObject(terms, constant, coefficient); - termName = getTermName(termWithoutCoefficient, "*"); - terms = Util.appendToArrayInObject(terms, termName, termWithoutCoefficient); - } - return terms; -} - -// Sort function for termnames. Sort first by symbol name, and then by exponent. -function sortTerms(a, b) { - if (a === b) { - return 0; - } - // if no exponent, sort alphabetically - if (a.indexOf("^") === -1) { - return a < b ? -1 : 1; - } - // if exponent: sort by symbol, but then exponent decreasing - else { - const symbA = a.split("^")[0]; - const expA = a.split("^")[1]; - const symbB = b.split("^")[0]; - const expB = b.split("^")[1]; - if (symbA !== symbB) { - return symbA < symbB ? -1 : 1; - } - else { - return expA > expB ? -1 : 1; - } - } -} - -export = LikeTermCollector; diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js deleted file mode 100644 index bf92d636..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js +++ /dev/null @@ -1,126 +0,0 @@ -"use strict"; -var checks = require("../../checks"); -var clone = require("../../util/clone"); -var evaluateConstantSum = require("./evaluateConstantSum"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// Adds a list of nodes that are polynomial terms. Returns a mathNode.Status object. -function addLikeTerms(node, polynomialOnly) { - if (polynomialOnly === void 0) { polynomialOnly = false; } - if (!mathNode.Type.isOperator(node)) { - return mathNode.Status.noChange(node); - } - var status; - if (!polynomialOnly) { - status = evaluateConstantSum(node); - if (status.hasChanged()) { - return status; - } - } - status = addLikePolynomialTerms(node); - if (status.hasChanged()) { - return status; - } - return mathNode.Status.noChange(node); -} -function addLikePolynomialTerms(node) { - if (!checks.canAddLikeTermPolynomialNodes(node)) { - return mathNode.Status.noChange(node); - } - var substeps = []; - var newNode = clone(node); - // STEP 1: If any nodes have no coefficient, make it have coefficient 1 - // (this step only happens under certain conditions and later steps might - // happen even if step 1 does not) - var status = addPositiveOneCoefficient(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - // STEP 2: If any nodes have a unary minus, make it have coefficient -1 - // (this step only happens under certain conditions and later steps might - // happen even if step 2 does not) - status = addNegativeOneCoefficient(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - // STEP 3: group the coefficients in a sum - status = groupCoefficientsForAdding(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - // STEP 4: evaluate the sum (could include fractions) - status = evaluateCoefficientSum(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - return mathNode.Status.nodeChanged(ChangeTypes.ADD_POLYNOMIAL_TERMS, node, newNode, true, substeps); -} -function addPositiveOneCoefficient(node) { - var newNode = clone(node); - var change = false; - var changeGroup = 1; - newNode.args.forEach(function (child, i) { - var polyTerm = new mathNode.PolynomialTerm(child); - if (polyTerm.getCoeffValue() === 1) { - newNode.args[i] = mathNode.Creator.polynomialTerm(polyTerm.getSymbolNode(), polyTerm.getExponentNode(), mathNode.Creator.constant(1), true /* explicit coefficient */); - newNode.args[i].changeGroup = changeGroup; - node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" - change = true; - changeGroup++; - } - }); - if (change) { - return mathNode.Status.nodeChanged(ChangeTypes.ADD_COEFFICIENT_OF_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} -function addNegativeOneCoefficient(node) { - var newNode = clone(node); - var change = false; - var changeGroup = 1; - newNode.args.forEach(function (child, i) { - var polyTerm = new mathNode.PolynomialTerm(child); - if (polyTerm.getCoeffValue() === -1) { - newNode.args[i] = mathNode.Creator.polynomialTerm(polyTerm.getSymbolNode(), polyTerm.getExponentNode(), polyTerm.getCoeffNode(), true /* explicit -1 coefficient */); - node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" - newNode.args[i].changeGroup = changeGroup; - change = true; - changeGroup++; - } - }); - if (change) { - return mathNode.Status.nodeChanged(ChangeTypes.UNARY_MINUS_TO_NEGATIVE_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} -function groupCoefficientsForAdding(node) { - var newNode = clone(node); - var polynomialTermList = newNode.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); - var coefficientList = polynomialTermList.map(function (p) { return p.getCoeffNode(true); }); - var sumOfCoefficents = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", coefficientList)); - // TODO: changegroups should also be on the before node, on all the - // coefficients, but changegroups with polyTerm gets messy so let's tackle - // that later. - sumOfCoefficents.changeGroup = 1; - // Polynomial terms that can be added together must share the same symbol - // name and exponent. Get that name and exponent from the first term - var firstTerm = polynomialTermList[0]; - var exponentNode = firstTerm.getExponentNode(); - var symbolNode = firstTerm.getSymbolNode(); - newNode = mathNode.Creator.polynomialTerm(symbolNode, exponentNode, sumOfCoefficents); - return mathNode.Status.nodeChanged(ChangeTypes.GROUP_COEFFICIENTS, node, newNode); -} -function evaluateCoefficientSum(node) { - // the node is now always a * node with the left child the coefficent sum - // e.g. (2 + 4 + 5) and the right node the symbol part e.g. x or y^2 - // so we want to evaluate args[0] - var coefficientSum = clone(node).args[0]; - var childStatus = evaluateConstantSum(coefficientSum); - return mathNode.Status.childChanged(node, childStatus, 0); -} -module.exports = addLikeTerms; -//# sourceMappingURL=addLikeTerms.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map deleted file mode 100644 index b1b0f3e8..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"addLikeTerms.js","sourceRoot":"","sources":["addLikeTerms.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts b/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts deleted file mode 100644 index 7f2b7cf9..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/addLikeTerms.ts +++ /dev/null @@ -1,183 +0,0 @@ -import checks = require("../../checks"); -import clone = require("../../util/clone"); -import evaluateConstantSum = require("./evaluateConstantSum"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// Adds a list of nodes that are polynomial terms. Returns a mathNode.Status object. -function addLikeTerms(node: mathjs.MathNode, polynomialOnly=false) { - if (!mathNode.Type.isOperator(node)) { - return mathNode.Status.noChange(node); - } - let status; - - if (!polynomialOnly) { - status = evaluateConstantSum(node); - if (status.hasChanged()) { - return status; - } - } - - status = addLikePolynomialTerms(node); - if (status.hasChanged()) { - return status; - } - - return mathNode.Status.noChange(node); -} - -function addLikePolynomialTerms(node: mathjs.MathNode) { - if (!checks.canAddLikeTermPolynomialNodes(node)) { - return mathNode.Status.noChange(node); - } - - const substeps = []; - let newNode = clone(node); - - // STEP 1: If any nodes have no coefficient, make it have coefficient 1 - // (this step only happens under certain conditions and later steps might - // happen even if step 1 does not) - let status = addPositiveOneCoefficient(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // STEP 2: If any nodes have a unary minus, make it have coefficient -1 - // (this step only happens under certain conditions and later steps might - // happen even if step 2 does not) - status = addNegativeOneCoefficient(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // STEP 3: group the coefficients in a sum - status = groupCoefficientsForAdding(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // STEP 4: evaluate the sum (could include fractions) - status = evaluateCoefficientSum(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - return mathNode.Status.nodeChanged( - ChangeTypes.ADD_POLYNOMIAL_TERMS, - node, newNode, true, substeps); -} - -// Given a sum of like polynomial terms, changes any term with no coefficient -// into a term with an explicit coefficient of 1. This is for pedagogy, and -// makes the adding coefficients step clearer. -// e.g. 2x + x -> 2x + 1x -// Returns a mathNode.Status object. -function addPositiveOneCoefficient(node: mathjs.MathNode) { - const newNode = clone(node); - let change = false; - - let changeGroup = 1; - newNode.args.forEach((child, i) => { - const polyTerm = new mathNode.PolynomialTerm(child); - if (polyTerm.getCoeffValue() === 1) { - newNode.args[i] = mathNode.Creator.polynomialTerm( - polyTerm.getSymbolNode(), - polyTerm.getExponentNode(), - mathNode.Creator.constant(1), - true /* explicit coefficient */); - - newNode.args[i].changeGroup = changeGroup; - node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" - - change = true; - changeGroup++; - } - }); - - if (change) { - return mathNode.Status.nodeChanged( - ChangeTypes.ADD_COEFFICIENT_OF_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Given a sum of like polynomial terms, changes any term with a unary minus -// coefficient into a term with an explicit coefficient of -1. This is for -// pedagogy, and makes the adding coefficients step clearer. -// e.g. 2x - x -> 2x - 1x -// Returns a mathNode.Status object. -function addNegativeOneCoefficient(node: mathjs.MathNode) { - const newNode = clone(node); - let change = false; - - let changeGroup = 1; - newNode.args.forEach((child, i) => { - const polyTerm = new mathNode.PolynomialTerm(child); - if (polyTerm.getCoeffValue() === -1) { - newNode.args[i] = mathNode.Creator.polynomialTerm( - polyTerm.getSymbolNode(), - polyTerm.getExponentNode(), - polyTerm.getCoeffNode(), - true /* explicit -1 coefficient */); - - node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" - newNode.args[i].changeGroup = changeGroup; - - change = true; - changeGroup++; - } - }); - - if (change) { - return mathNode.Status.nodeChanged( - ChangeTypes.UNARY_MINUS_TO_NEGATIVE_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Given a sum of like polynomial terms, groups the coefficients -// e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 -// Returns a mathNode.Status object. -function groupCoefficientsForAdding(node: any); -function groupCoefficientsForAdding(node) { - let newNode = clone(node); - - const polynomialTermList = newNode.args.map(n => new mathNode.PolynomialTerm(n)); - const coefficientList = polynomialTermList.map(p => p.getCoeffNode(true)); - const sumOfCoefficents = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", coefficientList)); - // TODO: changegroups should also be on the before node, on all the - // coefficients, but changegroups with polyTerm gets messy so let's tackle - // that later. - sumOfCoefficents.changeGroup = 1; - - // Polynomial terms that can be added together must share the same symbol - // name and exponent. Get that name and exponent from the first term - const firstTerm = polynomialTermList[0]; - const exponentNode = firstTerm.getExponentNode(); - const symbolNode = firstTerm.getSymbolNode(); - newNode = mathNode.Creator.polynomialTerm( - symbolNode, exponentNode, sumOfCoefficents); - - return mathNode.Status.nodeChanged( - ChangeTypes.GROUP_COEFFICIENTS, node, newNode); -} - -// Given a node of the form (2 + 4 + 5)x -- ie the coefficients have been -// grouped for adding -- add the coefficients together to make a new coeffient -// that is a constant or constant fraction. -function evaluateCoefficientSum(node: any); -function evaluateCoefficientSum(node) { - // the node is now always a * node with the left child the coefficent sum - // e.g. (2 + 4 + 5) and the right node the symbol part e.g. x or y^2 - // so we want to evaluate args[0] - const coefficientSum = clone(node).args[0]; - const childStatus = evaluateConstantSum(coefficientSum); - return mathNode.Status.childChanged(node, childStatus, 0); -} - -export = addLikeTerms; diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js deleted file mode 100644 index 53247734..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js +++ /dev/null @@ -1,106 +0,0 @@ -"use strict"; -var addConstantAndFraction = require("../fractionsSearch/addConstantAndFraction"); -var addConstantFractions = require("../fractionsSearch/addConstantFractions"); -var arithmeticSearch = require("../arithmeticSearch"); -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -function evaluateConstantSum(node) { - if (mathNode.Type.isParenthesis(node)) { - node = node.content; - } - if (!mathNode.Type.isOperator(node) || node.op !== "+") { - return mathNode.Status.noChange(node); - } - if (node.args.some(function (node) { return !mathNode.Type.isConstantOrConstantFraction(node); })) { - return mathNode.Status.noChange(node); - } - // functions needed to evaluate the sum - var summingFunctions = [ - arithmeticSearch, - addConstantFractions, - addConstantAndFraction, - ]; - for (var i = 0; i < summingFunctions.length; i++) { - var status_1 = summingFunctions[i](node); - if (status_1.hasChanged()) { - if (mathNode.Type.isConstantOrConstantFraction(status_1.newNode)) { - return status_1; - } - } - } - var newNode = clone(node); - var substeps = []; - var status; - // STEP 1: group fractions and constants separately - status = groupConstantsAndFractions(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - var constants = newNode.args[0]; - var fractions = newNode.args[1]; - // STEP 2A: evaluate arithmetic IF there's > 1 constant - // (which is the case if it's a list surrounded by parenthesis) - if (mathNode.Type.isParenthesis(constants)) { - var constantList = constants.content; - var evaluateStatus = arithmeticSearch(constantList); - status = mathNode.Status.childChanged(newNode, evaluateStatus, 0); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - // STEP 2B: add fractions IF there's > 1 fraction - // (which is the case if it's a list surrounded by parenthesis) - if (mathNode.Type.isParenthesis(fractions)) { - var fractionList = fractions.content; - var evaluateStatus = addConstantFractions(fractionList); - status = mathNode.Status.childChanged(newNode, evaluateStatus, 1); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - // STEP 3: combine the evaluated constant and fraction - // the fraction might have simplified to a constant (e.g. 1/3 + 2/3 -> 2) - // so we just call evaluateConstantSum again to cycle through - status = evaluateConstantSum(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); -} -function groupConstantsAndFractions(node) { - var fractions = node.args.filter(mathNode.Type.isIntegerFraction); - var constants = node.args.filter(mathNode.Type.isConstant); - if (fractions.length === 0 || constants.length === 0) { - throw Error("expected both integer fractions and constants, got " + node); - } - if (fractions.length + constants.length !== node.args.length) { - throw Error("can only evaluate integer fractions and constants"); - } - constants = constants.map(function (node) { - // set the changeGroup - this affects both the old and new node - node.changeGroup = 1; - // clone so that node and newNode aren't stored in the same memory - return clone(node); - }); - // wrap in parenthesis if there's more than one, to group them - if (constants.length > 1) { - constants = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", constants)); - } - else { - constants = constants[0]; - } - fractions = fractions.map(function (node) { - // set the changeGroup - this affects both the old and new node - node.changeGroup = 2; - // clone so that node and newNode aren't stored in the same memory - return clone(node); - }); - // wrap in parenthesis if there's more than one, to group them - if (fractions.length > 1) { - fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", fractions)); - } - else { - fractions = fractions[0]; - } - var newNode = mathNode.Creator.operator("+", [constants, fractions]); - return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_LIKE_TERMS, node, newNode); -} -module.exports = evaluateConstantSum; -//# sourceMappingURL=evaluateConstantSum.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map deleted file mode 100644 index d00eda76..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"evaluateConstantSum.js","sourceRoot":"","sources":["evaluateConstantSum.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts b/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts deleted file mode 100644 index eb8e9768..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.ts +++ /dev/null @@ -1,133 +0,0 @@ -import addConstantAndFraction = require("../fractionsSearch/addConstantAndFraction"); -import addConstantFractions = require("../fractionsSearch/addConstantFractions"); -import arithmeticSearch = require("../arithmeticSearch"); -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// Evaluates a sum of constant numbers and integer fractions to a single -// constant number or integer fraction. e.g. e.g. 2/3 + 5 + 5/2 => 49/6 -// Returns a mathNode.Status object. -function evaluateConstantSum(node: any); -function evaluateConstantSum(node) { - if (mathNode.Type.isParenthesis(node)) { - node = node.content; - } - if (!mathNode.Type.isOperator(node) || node.op !== "+") { - return mathNode.Status.noChange(node); - } - if (node.args.some(node => !mathNode.Type.isConstantOrConstantFraction(node))) { - return mathNode.Status.noChange(node); - } - - // functions needed to evaluate the sum - const summingFunctions = [ - arithmeticSearch, - addConstantFractions, - addConstantAndFraction, - ]; - for (let i = 0; i < summingFunctions.length; i++) { - const status = summingFunctions[i](node); - if (status.hasChanged()) { - if (mathNode.Type.isConstantOrConstantFraction(status.newNode)) { - return status; - } - } - } - - let newNode = clone(node); - const substeps = []; - let status; - - // STEP 1: group fractions and constants separately - status = groupConstantsAndFractions(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - const constants = newNode.args[0]; - const fractions = newNode.args[1]; - - // STEP 2A: evaluate arithmetic IF there's > 1 constant - // (which is the case if it's a list surrounded by parenthesis) - if (mathNode.Type.isParenthesis(constants)) { - const constantList = constants.content; - const evaluateStatus = arithmeticSearch(constantList); - status = mathNode.Status.childChanged(newNode, evaluateStatus, 0); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // STEP 2B: add fractions IF there's > 1 fraction - // (which is the case if it's a list surrounded by parenthesis) - if (mathNode.Type.isParenthesis(fractions)) { - const fractionList = fractions.content; - const evaluateStatus = addConstantFractions(fractionList); - status = mathNode.Status.childChanged(newNode, evaluateStatus, 1); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // STEP 3: combine the evaluated constant and fraction - // the fraction might have simplified to a constant (e.g. 1/3 + 2/3 -> 2) - // so we just call evaluateConstantSum again to cycle through - status = evaluateConstantSum(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - return mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); -} - -// If we can't combine using one of those functions, there's a mix of > 2 -// fractions and constants. So we need to group them together so we can later -// add them. -// Expects a node that is a sum of integer fractions and constants. -// Returns a mathNode.Status object. -// e.g. 2/3 + 5 + 5/2 => (2/3 + 5/2) + 5 -function groupConstantsAndFractions(node: any); -function groupConstantsAndFractions(node) { - let fractions = node.args.filter(mathNode.Type.isIntegerFraction); - let constants = node.args.filter(mathNode.Type.isConstant); - - if (fractions.length === 0 || constants.length === 0) { - throw Error("expected both integer fractions and constants, got " + node); - } - - if (fractions.length + constants.length !== node.args.length) { - throw Error("can only evaluate integer fractions and constants"); - } - - constants = constants.map(node => { - // set the changeGroup - this affects both the old and new node - node.changeGroup = 1; - // clone so that node and newNode aren't stored in the same memory - return clone(node); - }); - // wrap in parenthesis if there's more than one, to group them - if (constants.length > 1) { - constants = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", constants)); - } - else { - constants = constants[0]; - } - - fractions = fractions.map(node => { - // set the changeGroup - this affects both the old and new node - node.changeGroup = 2; - // clone so that node and newNode aren't stored in the same memory - return clone(node); - }); - // wrap in parenthesis if there's more than one, to group them - if (fractions.length > 1) { - fractions = mathNode.Creator.parenthesis(mathNode.Creator.operator("+", fractions)); - } - else { - fractions = fractions[0]; - } - - const newNode = mathNode.Creator.operator("+", [constants, fractions]); - return mathNode.Status.nodeChanged( - ChangeTypes.COLLECT_LIKE_TERMS, node, newNode); -} - -export = evaluateConstantSum; diff --git a/lib/simplifyExpression/collectAndCombineSearch/index.ts b/lib/simplifyExpression/collectAndCombineSearch/index.ts deleted file mode 100644 index bcd7ad4d..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/index.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Collects and combines like terms - -import addLikeTerms = require("./addLikeTerms"); -import clone = require("../../util/clone"); -import multiplyLikeTerms = require("./multiplyLikeTerms"); -import ChangeTypes = require("../../ChangeTypes"); -import LikeTermCollector = require("./LikeTermCollector"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); -const termCollectorFunctions = { - '+': addLikeTerms, - '*': multiplyLikeTerms -}; - -// Iterates through the tree looking for like terms to collect and combine. -// Will prioritize deeper expressions. Returns a mathNode.Status object. -const search = TreeSearch.postOrder(collectAndCombineLikeTerms); - -// Given an operator node, maybe collects and then combines if possible -// e.g. 2x + 4x + y => 6x + y -// e.g. 2x * x^2 * 5x => 10 x^4 -function collectAndCombineLikeTerms(node) { - if (node.op === "+") { - const status = collectAndCombineOperation(node); - if (status.hasChanged()) { - return status; - } - // we might also be able to just combine if they're all the same term - // e.g. 2x + 4x + x (doesn't need collecting) - return addLikeTerms(node, true); - } - else if (node.op === "*") { - // collect and combine involves there being coefficients pulled the front - // e.g. 2x * x^2 * 5x => (2*5) * (x * x^2 * x) => ... => 10 x^4 - const status = collectAndCombineOperation(node); - if (status.hasChanged()) { - // make sure there's no * between the coefficient and the symbol part - status.newNode.implicit = true; - return status; - } - // we might also be able to just combine polynomial terms - // e.g. x * x^2 * x => ... => x^4 - return multiplyLikeTerms(node, true); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Collects and combines (if possible) the arguments of an addition or -// multiplication -function collectAndCombineOperation(node: any); -function collectAndCombineOperation(node) { - let substeps = []; - - const status = LikeTermCollector.collectLikeTerms(clone(node)); - if (!status.hasChanged()) { - return status; - } - - // STEP 1: collect like terms, e.g. 2x + 4x^2 + 5x => 4x^2 + (2x + 5x) - substeps.push(status); - let newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // STEP 2 onwards: combine like terms for each group that can be combined - // e.g. (x + 3x) + (2 + 2) has two groups - const combineSteps = combineLikeTerms(newNode); - if (combineSteps.length > 0) { - substeps = substeps.concat(combineSteps); - const lastStep = combineSteps[combineSteps.length - 1]; - newNode = mathNode.Status.resetChangeGroups(lastStep.newNode); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.COLLECT_AND_COMBINE_LIKE_TERMS, - node, newNode, true, substeps); -} - -// step 2 onwards for collectAndCombineOperation -// combine like terms for each group that can be combined -// e.g. (x + 3x) + (2 + 2) has two groups -// returns a list of combine steps -function combineLikeTerms(node) { - const steps = []; - let newNode = clone(node); - - for (let i = 0; i < node.args.length; i++) { - let child = node.args[i]; - // All groups of terms will be surrounded by parenthesis - if (!mathNode.Type.isParenthesis(child)) { - continue; - } - child = child.content; - const childStatus = termCollectorFunctions[newNode.op](child); - if (childStatus.hasChanged()) { - const status = mathNode.Status.childChanged(newNode, childStatus, i); - steps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - } - - return steps; -} - -export = search; diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js deleted file mode 100644 index 901d2565..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js +++ /dev/null @@ -1,109 +0,0 @@ -"use strict"; -var arithmeticSearch = require("../arithmeticSearch"); -var checks = require("../../checks"); -var clone = require("../../util/clone"); -var multiplyFractionsSearch = require("../multiplyFractionsSearch"); -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -// Multiplies a list of nodes that are polynomial like terms. Returns a node. -// The polynomial nodes should *not* have coefficients. (multiplying -// coefficients is handled in collecting like terms for multiplication) -function multiplyLikeTerms(node, polynomialOnly) { - if (polynomialOnly === void 0) { polynomialOnly = false; } - if (!mathNode.Type.isOperator(node)) { - return mathNode.Status.noChange(node); - } - var status; - if (!polynomialOnly) { - status = arithmeticSearch(node); - if (status.hasChanged()) { - status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; - return status; - } - status = multiplyFractionsSearch(node); - if (status.hasChanged()) { - status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; - return status; - } - } - status = multiplyPolynomialTerms(node); - if (status.hasChanged()) { - status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; - return status; - } - return mathNode.Status.noChange(node); -} -function multiplyPolynomialTerms(node) { - if (!checks.canMultiplyLikeTermPolynomialNodes(node)) { - return mathNode.Status.noChange(node); - } - var substeps = []; - var newNode = clone(node); - // STEP 1: If any term has no exponent, make it have exponent 1 - // e.g. x -> x^1 (this is for pedagogy reasons) - // (this step only happens under certain conditions and later steps might - // happen even if step 1 does not) - var status = addOneExponent(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - // STEP 2: collect exponents to a single exponent sum - // e.g. x^1 * x^3 -> x^(1+3) - status = collectExponents(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - // STEP 3: add exponents together. - // NOTE: This might not be a step if the exponents aren't all constants, - // but this case isn't that common and can be caught in other steps. - // e.g. x^(2+4+z) - // TODO: handle fractions, combining and collecting like terms, etc, here - var exponentSum = newNode.args[1].content; - var sumStatus = arithmeticSearch(exponentSum); - if (sumStatus.hasChanged()) { - status = mathNode.Status.childChanged(newNode, sumStatus, 1); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - if (substeps.length === 1) { - return substeps[0]; - } - else { - return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_POLYNOMIAL_TERMS, node, newNode, true, substeps); - } -} -function addOneExponent(node) { - var newNode = clone(node); - var change = false; - var changeGroup = 1; - newNode.args.forEach(function (child, i) { - var polyTerm = new mathNode.PolynomialTerm(child); - if (!polyTerm.getExponentNode()) { - newNode.args[i] = mathNode.Creator.polynomialTerm(polyTerm.getSymbolNode(), mathNode.Creator.constant(1), polyTerm.getCoeffNode()); - newNode.args[i].changeGroup = changeGroup; - node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" - change = true; - changeGroup++; - } - }); - if (change) { - return mathNode.Status.nodeChanged(ChangeTypes.ADD_EXPONENT_OF_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} -function collectExponents(node) { - var polynomialTermList = node.args.map(function (n) { return new mathNode.PolynomialTerm(n); }); - // If we're multiplying polynomial nodes together, they all share the same - // symbol. Get that from the first node. - var symbolNode = polynomialTermList[0].getSymbolNode(); - // The new exponent will be a sum of exponents (an operation, wrapped in - // parens) e.g. x^(3+4+5) - var exponentNodeList = polynomialTermList.map(function (p) { return p.getExponentNode(true); }); - var newExponent = mathNode.Creator.parenthesis(mathNode.Creator.operator('+', exponentNodeList)); - var newNode = mathNode.Creator.polynomialTerm(symbolNode, newExponent, null); - return mathNode.Status.nodeChanged(ChangeTypes.COLLECT_EXPONENTS, node, newNode); -} -module.exports = multiplyLikeTerms; -//# sourceMappingURL=multiplyLikeTerms.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map deleted file mode 100644 index 1f98974b..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"multiplyLikeTerms.js","sourceRoot":"","sources":["multiplyLikeTerms.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts b/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts deleted file mode 100644 index 68f1a090..00000000 --- a/lib/simplifyExpression/collectAndCombineSearch/multiplyLikeTerms.ts +++ /dev/null @@ -1,145 +0,0 @@ -import arithmeticSearch = require("../arithmeticSearch"); -import checks = require("../../checks"); -import clone = require("../../util/clone"); -import multiplyFractionsSearch = require("../multiplyFractionsSearch"); -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); - -// Multiplies a list of nodes that are polynomial like terms. Returns a node. -// The polynomial nodes should *not* have coefficients. (multiplying -// coefficients is handled in collecting like terms for multiplication) -function multiplyLikeTerms(node, polynomialOnly=false) { - if (!mathNode.Type.isOperator(node)) { - return mathNode.Status.noChange(node); - } - let status; - - if (!polynomialOnly) { - status = arithmeticSearch(node); - if (status.hasChanged()) { - status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; - return status; - } - - status = multiplyFractionsSearch(node); - if (status.hasChanged()) { - status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; - return status; - } - } - - status = multiplyPolynomialTerms(node); - if (status.hasChanged()) { - status.changeType = ChangeTypes.MULTIPLY_COEFFICIENTS; - return status; - } - - return mathNode.Status.noChange(node); -} - -function multiplyPolynomialTerms(node: any); -function multiplyPolynomialTerms(node) { - if (!checks.canMultiplyLikeTermPolynomialNodes(node)) { - return mathNode.Status.noChange(node); - } - - const substeps = []; - let newNode = clone(node); - - // STEP 1: If any term has no exponent, make it have exponent 1 - // e.g. x -> x^1 (this is for pedagogy reasons) - // (this step only happens under certain conditions and later steps might - // happen even if step 1 does not) - let status = addOneExponent(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // STEP 2: collect exponents to a single exponent sum - // e.g. x^1 * x^3 -> x^(1+3) - status = collectExponents(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // STEP 3: add exponents together. - // NOTE: This might not be a step if the exponents aren't all constants, - // but this case isn't that common and can be caught in other steps. - // e.g. x^(2+4+z) - // TODO: handle fractions, combining and collecting like terms, etc, here - const exponentSum = newNode.args[1].content; - const sumStatus = arithmeticSearch(exponentSum); - if (sumStatus.hasChanged()) { - status = mathNode.Status.childChanged(newNode, sumStatus, 1); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - if (substeps.length === 1) { // possible if only step 2 happens - return substeps[0]; - } - else { - return mathNode.Status.nodeChanged( - ChangeTypes.MULTIPLY_POLYNOMIAL_TERMS, - node, newNode, true, substeps); - } -} - -// Given a product of polynomial terms, changes any term with no exponent -// into a term with an explicit exponent of 1. This is for pedagogy, and -// makes the adding coefficients step clearer. -// e.g. x^2 * x -> x^2 * x^1 -// Returns a mathNode.Status object. -function addOneExponent(node: any); -function addOneExponent(node) { - const newNode = clone(node); - let change = false; - - let changeGroup = 1; - newNode.args.forEach((child, i) => { - const polyTerm = new mathNode.PolynomialTerm(child); - if (!polyTerm.getExponentNode()) { - newNode.args[i] = mathNode.Creator.polynomialTerm( - polyTerm.getSymbolNode(), - mathNode.Creator.constant(1), - polyTerm.getCoeffNode()); - - newNode.args[i].changeGroup = changeGroup; - node.args[i].changeGroup = changeGroup; // note that this is the "oldNode" - - change = true; - changeGroup++; - } - }); - - if (change) { - return mathNode.Status.nodeChanged( - ChangeTypes.ADD_EXPONENT_OF_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Given a product of polynomial terms, groups the exponents into a sum -// e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) -// Returns a mathNode.Status object. -function collectExponents(node: any); -function collectExponents(node) { - const polynomialTermList = node.args.map(n => new mathNode.PolynomialTerm(n)); - - // If we're multiplying polynomial nodes together, they all share the same - // symbol. Get that from the first node. - const symbolNode = polynomialTermList[0].getSymbolNode(); - - // The new exponent will be a sum of exponents (an operation, wrapped in - // parens) e.g. x^(3+4+5) - const exponentNodeList = polynomialTermList.map(p => p.getExponentNode(true)); - const newExponent = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", exponentNodeList)); - const newNode = mathNode.Creator.polynomialTerm(symbolNode, newExponent, null); - return mathNode.Status.nodeChanged( - ChangeTypes.COLLECT_EXPONENTS, node, newNode); -} - -export = multiplyLikeTerms; diff --git a/lib/simplifyExpression/distributeSearch/index.js b/lib/simplifyExpression/distributeSearch/index.js deleted file mode 100644 index 3a7c600f..00000000 --- a/lib/simplifyExpression/distributeSearch/index.js +++ /dev/null @@ -1,231 +0,0 @@ -"use strict"; -var arithmeticSearch = require("../arithmeticSearch"); -var clone = require("../../util/clone"); -var collectAndCombineSearch = require("../collectAndCombineSearch"); -var rearrangeCoefficient = require("../basicsSearch/rearrangeCoefficient"); -var ChangeTypes = require("../../ChangeTypes"); -var Negative = require("../../Negative"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -var search = TreeSearch.postOrder(distribute); -function distribute(node) { - if (mathNode.Type.isUnaryMinus(node)) { - return distributeUnaryMinus(node); - } - else if (mathNode.Type.isOperator(node)) { - return distributeAndSimplifyOperationNode(node); - } - else { - return mathNode.Status.noChange(node); - } -} -function distributeUnaryMinus(node) { - if (!mathNode.Type.isUnaryMinus(node)) { - return mathNode.Status.noChange(node); - } - var unaryContent = node.args[0]; - if (!mathNode.Type.isParenthesis(unaryContent)) { - return mathNode.Status.noChange(node); - } - var content = unaryContent.content; - if (!mathNode.Type.isOperator(content)) { - return mathNode.Status.noChange(node); - } - var newContent = clone(content); - node.changeGroup = 1; - // For multiplication and division, we can push the unary minus in to - // the first argument. - // e.g. -(2/3) -> (-2/3) -(4*9*x^2) --> (-4 * 9 * x^2) - if (content.op === "*" || content.op === "/") { - newContent.args[0] = Negative.negate(newContent.args[0]); - newContent.args[0].changeGroup = 1; - var newNode = mathNode.Creator.parenthesis(newContent); - return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); - } - else if (content.op === "+") { - // Now we know `node` is of the form -(x + y + ...). - // We want to now return (-x + -y + ....) - // If any term is negative, we make it positive it right away - // e.g. -(2-4) => -2 + 4 - var newArgs = newContent.args.map(function (arg) { - var newArg = Negative.negate(arg); - newArg.changeGroup = 1; - return newArg; - }); - newContent.args = newArgs; - var newNode = mathNode.Creator.parenthesis(newContent); - return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} -function distributeAndSimplifyOperationNode(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return mathNode.Status.noChange(node); - } - // STEP 1: distribute with `distributeTwoNodes` - // e.g. x*(2+x) -> x*2 + x*x - // STEP 2: simplifications of each operand in the new sum with `simplify` - // e.g. x*2 + x*x -> ... -> 2x + x^2 - for (var i = 0; i + 1 < node.args.length; i++) { - if (!isParenthesisOfAddition(node.args[i]) && - !isParenthesisOfAddition(node.args[i + 1])) { - continue; - } - var newNode = clone(node); - var substeps = []; - var status_1 = void 0; - var combinedNode = distributeTwoNodes(newNode.args[i], newNode.args[i + 1]); - node.args[i].changeGroup = 1; - node.args[i + 1].changeGroup = 1; - combinedNode.changeGroup = 1; - if (newNode.args.length > 2) { - newNode.args.splice(i, 2, combinedNode); - newNode.args[i].changeGroup = 1; - } - else { - newNode = combinedNode; - newNode.changeGroup = 1; - } - status_1 = mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE, node, newNode, false); - substeps.push(status_1); - newNode = mathNode.Status.resetChangeGroups(status_1.newNode); - // case 1: there were more than two operands in this multiplication - // e.g. 3*7*(2+x)*(3+x)*(4+x) is a multiplication node with 5 children - // and the new node will be 3*(14+7x)*(3+x)*(4+x) with 4 children. - if (mathNode.Type.isOperator(newNode, "*")) { - var childStatus = simplifyWithParens(newNode.args[i]); - if (childStatus.hasChanged()) { - status_1 = mathNode.Status.childChanged(newNode, childStatus, i); - substeps.push(status_1); - newNode = mathNode.Status.resetChangeGroups(status_1.newNode); - } - } - else if (mathNode.Type.isParenthesis(newNode)) { - status_1 = simplifyWithParens(newNode); - if (status_1.hasChanged()) { - substeps.push(status_1); - newNode = mathNode.Status.resetChangeGroups(status_1.newNode); - } - } - else { - throw Error("Unsupported node type for distribution: " + node); - } - if (substeps.length === 1) { - return substeps[0]; - } - return mathNode.Status.nodeChanged(ChangeTypes.DISTRIBUTE, node, newNode, false, substeps); - } - return mathNode.Status.noChange(node); -} -function distributeTwoNodes(firstNode, secondNode) { - // lists of terms we'll be multiplying together from each node - var firstArgs, secondArgs; - if (isParenthesisOfAddition(firstNode)) { - firstArgs = firstNode.content.args; - } - else { - firstArgs = [firstNode]; - } - if (isParenthesisOfAddition(secondNode)) { - secondArgs = secondNode.content.args; - } - else { - secondArgs = [secondNode]; - } - // the new operands under addition, now products of terms - var newArgs = []; - // if exactly one group contains at least one fraction, multiply the - // non-fraction group into the numerators of the fraction group - if ([firstArgs, secondArgs].filter(hasFraction).length === 1) { - var firstArgsHasFraction = hasFraction(firstArgs); - var fractionNodes = firstArgsHasFraction ? firstArgs : secondArgs; - var nonFractionTerm_1 = firstArgsHasFraction ? secondNode : firstNode; - fractionNodes.forEach(function (node) { - var arg; - if (isFraction(node)) { - var numerator = mathNode.Creator.operator("*", [node.args[0], nonFractionTerm_1]); - numerator = mathNode.Creator.parenthesis(numerator); - arg = mathNode.Creator.operator("/", [numerator, node.args[1]]); - } - else { - arg = mathNode.Creator.operator("*", [node, nonFractionTerm_1]); - } - arg.changeGroup = 1; - newArgs.push(arg); - }); - } - else if (firstArgs.length > 1 && secondArgs.length > 1) { - firstArgs.forEach(function (leftArg) { - var arg = mathNode.Creator.operator("*", [leftArg, secondNode]); - arg.changeGroup = 1; - newArgs.push(arg); - }); - } - else { - // a list of all pairs of nodes between the two arg lists - firstArgs.forEach(function (leftArg) { - secondArgs.forEach(function (rightArg) { - var arg = mathNode.Creator.operator("*", [leftArg, rightArg]); - arg.changeGroup = 1; - newArgs.push(arg); - }); - }); - } - return mathNode.Creator.parenthesis(mathNode.Creator.operator("+", newArgs)); -} -function hasFraction(args) { - return args.filter(isFraction).length > 0; -} -function isFraction(node) { - return mathNode.Type.isOperator(node, "/"); -} -function simplifyWithParens(node) { - if (!mathNode.Type.isParenthesis(node)) { - throw Error("expected " + node + " to be a parenthesis node"); - } - var status = simplify(node.content); - if (status.hasChanged()) { - return mathNode.Status.childChanged(node, status); - } - else { - return mathNode.Status.noChange(node); - } -} -function simplify(node) { - var substeps = []; - var simplifyFunctions = [ - arithmeticSearch, - rearrangeCoefficient, - collectAndCombineSearch, - distributeAndSimplifyOperationNode, - ]; - var newNode = clone(node); - for (var i = 0; i < newNode.args.length; i++) { - for (var j = 0; j < simplifyFunctions.length; j++) { - var childStatus = simplifyFunctions[j](newNode.args[i]); - if (childStatus.hasChanged()) { - var status_2 = mathNode.Status.childChanged(newNode, childStatus, i); - substeps.push(status_2); - newNode = mathNode.Status.resetChangeGroups(status_2.newNode); - } - } - } - // possible in cases like 2(x + y) -> 2x + 2y -> doesn't need simplifying - if (substeps.length === 0) { - return mathNode.Status.noChange(node); - } - else { - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_TERMS, node, newNode, false, substeps); - } -} -function isParenthesisOfAddition(node) { - if (!mathNode.Type.isParenthesis(node)) { - return false; - } - var content = node.content; - return mathNode.Type.isOperator(content, "+"); -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/distributeSearch/index.js.map b/lib/simplifyExpression/distributeSearch/index.js.map deleted file mode 100644 index 537e8900..00000000 --- a/lib/simplifyExpression/distributeSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/distributeSearch/index.ts b/lib/simplifyExpression/distributeSearch/index.ts deleted file mode 100644 index e62e1f4b..00000000 --- a/lib/simplifyExpression/distributeSearch/index.ts +++ /dev/null @@ -1,291 +0,0 @@ -import arithmeticSearch = require("../arithmeticSearch"); -import clone = require("../../util/clone"); -import collectAndCombineSearch = require("../collectAndCombineSearch"); -import rearrangeCoefficient = require("../basicsSearch/rearrangeCoefficient"); -import ChangeTypes = require("../../ChangeTypes"); -import Negative = require("../../Negative"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); -const search = TreeSearch.postOrder(distribute); - -// Distributes through parenthesis. -// e.g. 2(x+3) -> (2*x + 2*3) -// e.g. -(x+5) -> (-x + -5) -// Returns a mathNode.Status object. -function distribute(node: mathjs.MathNode) { - if (mathNode.Type.isUnaryMinus(node)) { - return distributeUnaryMinus(node); - } - else if (mathNode.Type.isOperator(node)) { - return distributeAndSimplifyOperationNode(node); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Distributes unary minus into a parenthesis node. -// e.g. -(4*9*x^2) --> (-4 * 9 * x^2) -// e.g. -(x + y - 5) --> (-x + -y + 5) -// Returns a mathNode.Status object. -function distributeUnaryMinus(node: mathjs.MathNode) { - if (!mathNode.Type.isUnaryMinus(node)) { - return mathNode.Status.noChange(node); - } - const unaryContent = node.args[0]; - if (!mathNode.Type.isParenthesis(unaryContent)) { - return mathNode.Status.noChange(node); - } - const content = unaryContent; - if (!mathNode.Type.isOperator(content)) { - return mathNode.Status.noChange(node); - } - const newContent = clone(content); - node.changeGroup = 1; - // For multiplication and division, we can push the unary minus in to - // the first argument. - // e.g. -(2/3) -> (-2/3) -(4*9*x^2) --> (-4 * 9 * x^2) - if (content.op === "*" || content.op === "/") { - newContent.args[0] = Negative.negate(newContent.args[0]); - newContent.args[0].changeGroup = 1; - const newNode = mathNode.Creator.parenthesis(newContent); - return mathNode.Status.nodeChanged( - ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); - } - else if (content.op === "+") { - // Now we know `node` is of the form -(x + y + ...). - // We want to now return (-x + -y + ....) - // If any term is negative, we make it positive it right away - // e.g. -(2-4) => -2 + 4 - const newArgs = newContent.args.map(arg => { - const newArg = Negative.negate(arg); - newArg.changeGroup = 1; - return newArg; - }); - newContent.args = newArgs; - const newNode = mathNode.Creator.parenthesis(newContent); - return mathNode.Status.nodeChanged( - ChangeTypes.DISTRIBUTE_NEGATIVE_ONE, node, newNode, false); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Distributes a pair of terms in a multiplication operation, if a pair -// can be distributed. To be distributed, there must be two terms beside -// each other, and at least one of them must be a parenthesis node. -// e.g. 2*(3+x) or (4+x^2+x^3)*(x+3) -// Returns a mathNode.Status object with substeps -function distributeAndSimplifyOperationNode(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return mathNode.Status.noChange(node); - } - - // STEP 1: distribute with `distributeTwoNodes` - // e.g. x*(2+x) -> x*2 + x*x - // STEP 2: simplifications of each operand in the new sum with `simplify` - // e.g. x*2 + x*x -> ... -> 2x + x^2 - for (let i = 0; i+1 < node.args.length; i++) { - if (!isParenthesisOfAddition(node.args[i]) && - !isParenthesisOfAddition(node.args[i+1])) { - continue; - } - - let newNode = clone(node); - const substeps = []; - let status; - - const combinedNode = distributeTwoNodes(newNode.args[i], newNode.args[i+1]); - node.args[i].changeGroup = 1; - node.args[i+1].changeGroup = 1; - combinedNode.changeGroup = 1; - - if (newNode.args.length > 2) { - newNode.args.splice(i, 2, combinedNode); - newNode.args[i].changeGroup = 1; - } - else { - newNode = combinedNode; - newNode.changeGroup = 1; - } - - status = mathNode.Status.nodeChanged( - ChangeTypes.DISTRIBUTE, node, newNode, false); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // case 1: there were more than two operands in this multiplication - // e.g. 3*7*(2+x)*(3+x)*(4+x) is a multiplication node with 5 children - // and the new node will be 3*(14+7x)*(3+x)*(4+x) with 4 children. - if (mathNode.Type.isOperator(newNode, "*")) { - const childStatus = simplifyWithParens(newNode.args[i]); - if (childStatus.hasChanged()) { - status = mathNode.Status.childChanged(newNode, childStatus, i); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - } - // case 2: there were only two operands and we multiplied them together. - // e.g. 7*(2+x) -> (7*2 + 7*x) - // Now we can just simplify it. - else if (mathNode.Type.isParenthesis(newNode)){ - status = simplifyWithParens(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - } - else { - throw Error("Unsupported node type for distribution: " + node); - } - - if (substeps.length === 1) { - return substeps[0]; - } - - return mathNode.Status.nodeChanged( - ChangeTypes.DISTRIBUTE, node, newNode, false, substeps); - } - return mathNode.Status.noChange(node); -} - -// Distributes two nodes together. At least one node must be parenthesis node -// e.g. 2*(x+3) -> (2*x + 2*3) (5+x)*x -> 5*x + x*x -// e.g. (5+x)*(x+3) -> (5*x + 5*3 + x*x + x*3) -// Returns a node. -function distributeTwoNodes(firstNode: mathjs.MathNode, secondNode: mathjs.MathNode) { - // lists of terms we'll be multiplying together from each node - let firstArgs, secondArgs; - if (isParenthesisOfAddition(firstNode)) { - firstArgs = firstNode.args; - } - else { - firstArgs = [firstNode]; - } - - if (isParenthesisOfAddition(secondNode)) { - secondArgs = secondNode.args; - } - else { - secondArgs = [secondNode]; - } - // the new operands under addition, now products of terms - const newArgs = []; - - // if exactly one group contains at least one fraction, multiply the - // non-fraction group into the numerators of the fraction group - if ([firstArgs, secondArgs].filter(hasFraction).length === 1) { - const firstArgsHasFraction = hasFraction(firstArgs); - const fractionNodes = firstArgsHasFraction ? firstArgs : secondArgs; - const nonFractionTerm = firstArgsHasFraction ? secondNode : firstNode; - fractionNodes.forEach((node) => { - let arg; - if (isFraction(node)) { - let numerator = mathNode.Creator.operator("*", [node.args[0], nonFractionTerm]); - numerator = mathNode.Creator.parenthesis(numerator); - arg = mathNode.Creator.operator("/", [numerator, node.args[1]]); - } - else { - arg = mathNode.Creator.operator("*", [node, nonFractionTerm]); - } - arg.changeGroup = 1; - newArgs.push(arg); - }); - } - // e.g. (4+x)(x+y+z) will become 4(x+y+z) + x(x+y+z) as an intermediate - // step. - else if (firstArgs.length > 1 && secondArgs.length > 1) { - firstArgs.forEach(leftArg => { - const arg = mathNode.Creator.operator("*", [leftArg, secondNode]); - arg.changeGroup = 1; - newArgs.push(arg); - }); - } - else { - // a list of all pairs of nodes between the two arg lists - firstArgs.forEach(leftArg => { - secondArgs.forEach(rightArg => { - const arg = mathNode.Creator.operator("*", [leftArg, rightArg]); - arg.changeGroup = 1; - newArgs.push(arg); - }); - }); - } - return mathNode.Creator.parenthesis(mathNode.Creator.operator("+", newArgs)); -} - -function hasFraction(args) { - return args.filter(isFraction).length > 0; -} - -function isFraction(node: mathjs.MathNode) { - return mathNode.Type.isOperator(node, "/"); -} - -// Simplifies a sum of terms (a result of distribution) that's in parens -// (note that all results of distribution are in parens) -// e.g. 2x*(4 + x) distributes to (2x*4 + 2x*x) -// This is a separate function from simplify to make the flow more readable, -// but this is literally just a wrapper around 'simplify'. -// Returns a mathNode.Status object -function simplifyWithParens(node: any); -function simplifyWithParens(node) { - if (!mathNode.Type.isParenthesis(node)) { - throw Error(`expected ${node} to be a parenthesis node`); - } - - const status = simplify(node.content); - if (status.hasChanged()) { - return mathNode.Status.childChanged(node, status); - } - else { - return mathNode.Status.noChange(node); - } -} - -// Simplifies a sum of terms that are a result of distribution. -// e.g. (2x+3)*(4x+5) -distribute-> 2x*(4x+5) + 3*(4x+5) <- 2 terms to simplify -// e.g. 2x*(4x+5) --distribute--> 2x*4x + 2x*5 --simplify--> 8x^2 + 10x -// Returns a mathNode.Status object. -function simplify(node: mathjs.MathNode) { - const substeps = []; - const simplifyFunctions = [ - arithmeticSearch, // e.g. 2*9 -> 18 - rearrangeCoefficient, // e.g. x*5 -> 5x - collectAndCombineSearch, // e.g 2x*4x -> 8x^2 - distributeAndSimplifyOperationNode, // e.g. (2+x)(3+x) -> 2*(3+x) recurses - ]; - - let newNode = clone(node); - for (let i = 0; i < newNode.args.length; i++) { - for (let j = 0; j < simplifyFunctions.length; j++) { - const childStatus = simplifyFunctions[j](newNode.args[i]); - if (childStatus.hasChanged()) { - const status = mathNode.Status.childChanged(newNode, childStatus, i); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - } - } - - // possible in cases like 2(x + y) -> 2x + 2y -> doesn't need simplifying - if (substeps.length === 0) { - return mathNode.Status.noChange(node); - } - else { - return mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_TERMS, node, newNode, false, substeps); - } -} - -// returns true if `node` is of the type (node + node + ...) -function isParenthesisOfAddition(node: mathjs.MathNode) { - if (!mathNode.Type.isParenthesis(node)) { - return false; - } - const content = node.content; - return mathNode.Type.isOperator(content, "+"); -} - -export = search; diff --git a/lib/simplifyExpression/divisionSearch/index.js b/lib/simplifyExpression/divisionSearch/index.js deleted file mode 100644 index a1881d90..00000000 --- a/lib/simplifyExpression/divisionSearch/index.js +++ /dev/null @@ -1,68 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -// Searches for and simplifies any chains of division or nested division. -// Returns a mathNode.Status object -var search = TreeSearch.preOrder(division); -function division(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "/") { - return mathNode.Status.noChange(node); - } - // e.g. 2/(x/6) => 2 * 6/x - var nodeStatus = multiplyByInverse(node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - // e.g. 2/x/6 -> 2/(x*6) - nodeStatus = simplifyDivisionChain(node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - return mathNode.Status.noChange(node); -} -function multiplyByInverse(node) { - var denominator = node.args[1]; - if (mathNode.Type.isParenthesis(denominator)) { - denominator = denominator.content; - } - if (!mathNode.Type.isOperator(denominator) || denominator.op !== "/") { - return mathNode.Status.noChange(node); - } - // At this point, we know that node is a fraction and denonimator is the - // fraction we need to inverse. - var inverseNumerator = denominator.args[1]; - var inverseDenominator = denominator.args[0]; - var inverseFraction = mathNode.Creator.operator("/", [inverseNumerator, inverseDenominator]); - var newNode = mathNode.Creator.operator("*", [node.args[0], inverseFraction]); - return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_BY_INVERSE, node, newNode); -} -function simplifyDivisionChain(node) { - // check for a chain of division - var denominatorList = getDenominatorList(node); - // one for the numerator, and at least two terms in the denominator - if (denominatorList.length > 2) { - var numerator = denominatorList.shift(); - // the new single denominator is all the chained denominators - // multiplied together, in parentheses. - var denominator = mathNode.Creator.parenthesis(mathNode.Creator.operator("*", denominatorList)); - var newNode = mathNode.Creator.operator("/", [numerator, denominator]); - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_DIVISION, node, newNode); - } - return mathNode.Status.noChange(node); -} -function getDenominatorList(denominator) { - var node = denominator; - var denominatorList = []; - while (node.op === "/") { - // unshift the denominator to the front of the list, and recurse on - // the numerator - denominatorList.unshift(node.args[1]); - node = node.args[0]; - } - // unshift the final node, which wasn't a / node - denominatorList.unshift(node); - return denominatorList; -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/divisionSearch/index.js.map b/lib/simplifyExpression/divisionSearch/index.js.map deleted file mode 100644 index 0477903b..00000000 --- a/lib/simplifyExpression/divisionSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/divisionSearch/index.ts b/lib/simplifyExpression/divisionSearch/index.ts deleted file mode 100644 index 370b1d00..00000000 --- a/lib/simplifyExpression/divisionSearch/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); - -// Searches for and simplifies any chains of division or nested division. -// Returns a mathNode.Status object -const search = TreeSearch.preOrder(division); - -function division(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "/") { - return mathNode.Status.noChange(node); - } - // e.g. 2/(x/6) => 2 * 6/x - let nodeStatus = multiplyByInverse(node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - // e.g. 2/x/6 -> 2/(x*6) - nodeStatus = simplifyDivisionChain(node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - return mathNode.Status.noChange(node); -} - -// If `node` is a fraction with a denominator that is also a fraction, multiply -// by the inverse. -// e.g. x/(2/3) -> x * 3/2 - -function multiplyByInverse(node: mathjs.MathNode) { - let denominator = node.args[1]; - if (mathNode.Type.isParenthesis(denominator)) { - denominator = denominator.content; - } - if (!mathNode.Type.isOperator(denominator) || denominator.op !== "/") { - return mathNode.Status.noChange(node); - } - // At this point, we know that node is a fraction and denonimator is the - // fraction we need to inverse. - const inverseNumerator = denominator.args[1]; - const inverseDenominator = denominator.args[0]; - const inverseFraction = mathNode.Creator.operator( - "/", [inverseNumerator, inverseDenominator]); - - const newNode = mathNode.Creator.operator("*", [node.args[0], inverseFraction]); - return mathNode.Status.nodeChanged( - ChangeTypes.MULTIPLY_BY_INVERSE, node, newNode); -} - -// Simplifies any chains of division into a single division operation. -// e.g. 2/x/6 -> 2/(x*6) -// Returns a mathNode.Status object -function simplifyDivisionChain(node: mathjs.MathNode) { - // check for a chain of division - const denominatorList = getDenominatorList(node); - // one for the numerator, and at least two terms in the denominator - if (denominatorList.length > 2) { - const numerator = denominatorList.shift(); - // the new single denominator is all the chained denominators - // multiplied together, in parentheses. - const denominator = mathNode.Creator.parenthesis( - mathNode.Creator.operator("*", denominatorList)); - const newNode = mathNode.Creator.operator("/", [numerator, denominator]); - return mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_DIVISION, node, newNode); - } - return mathNode.Status.noChange(node); -} - -// Given a the denominator of a division node, returns all the nested -// denominator nodess. e.g. 2/3/4/5 would return [2,3,4,5] -// (note: all the numbers in the example are actually constant nodes) - -function getDenominatorList(denominator) { - let node = denominator; - const denominatorList = []; - while (node.op === "/") { - // unshift the denominator to the front of the list, and recurse on - // the numerator - denominatorList.unshift(node.args[1]); - node = node.args[0]; - } - // unshift the final node, which wasn't a / node - denominatorList.unshift(node); - return denominatorList; -} - -export = search; diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js deleted file mode 100644 index c4724ded..00000000 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js +++ /dev/null @@ -1,93 +0,0 @@ -"use strict"; -var addConstantFractions = require("./addConstantFractions"); -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var evaluate = require("../../util/evaluate"); -var mathNode = require("../../mathnode"); -// Adds a constant to a fraction by: -// - collapsing the fraction to decimal if the constant is not an integer -// e.g. 5.3 + 1/2 -> 5.3 + 0.2 -// - turning the constant into a fraction with the same denominator if it is -// an integer, e.g. 5 + 1/2 -> 10/2 + 1/2 -function addConstantAndFraction(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "+" || node.args.length !== 2) { - return mathNode.Status.noChange(node); - } - var _a = node.args, firstArg = _a[0], secondArg = _a[1]; - var constNode, fractionNode; - if (mathNode.Type.isConstant(firstArg)) { - if (mathNode.Type.isIntegerFraction(secondArg)) { - constNode = firstArg; - fractionNode = secondArg; - } - else { - return mathNode.Status.noChange(node); - } - } - else if (mathNode.Type.isConstant(secondArg)) { - if (mathNode.Type.isIntegerFraction(firstArg)) { - constNode = secondArg; - fractionNode = firstArg; - } - else { - return mathNode.Status.noChange(node); - } - } - else { - return mathNode.Status.noChange(node); - } - var newNode = clone(node); - var substeps = []; - // newConstNode and newFractionNode will end up both constants, or both - // fractions. I'm naming them based on their original form so we can keep - // track of which is which. - var newConstNode, newFractionNode; - var changeType; - if (parseFloat(constNode.value) % 1 === 0) { - var denominatorNode = fractionNode.args[1]; - var denominatorValue = parseInt(denominatorNode); - var constNodeValue = parseInt(constNode.value); - var newNumeratorNode = mathNode.Creator.constant(constNodeValue * denominatorValue); - newConstNode = mathNode.Creator.operator("/", [newNumeratorNode, denominatorNode]); - newFractionNode = fractionNode; - changeType = ChangeTypes.CONVERT_INTEGER_TO_FRACTION; - } - else { - // round to 4 decimal places - var dividedValue = evaluate(fractionNode); - if (dividedValue < 1) { - dividedValue = parseFloat(dividedValue.toPrecision(4)); - } - else { - dividedValue = parseFloat(dividedValue.toFixed(4)); - } - newFractionNode = mathNode.Creator.constant(dividedValue); - newConstNode = constNode; - changeType = ChangeTypes.DIVIDE_FRACTION_FOR_ADDITION; - } - if (mathNode.Type.isConstant(firstArg)) { - newNode.args[0] = newConstNode; - newNode.args[1] = newFractionNode; - } - else { - newNode.args[0] = newFractionNode; - newNode.args[1] = newConstNode; - } - substeps.push(mathNode.Status.nodeChanged(changeType, node, newNode)); - newNode = mathNode.Status.resetChangeGroups(newNode); - // If we changed an integer to a fraction, we need to add the steps for - // adding the fractions. - if (changeType === ChangeTypes.CONVERT_INTEGER_TO_FRACTION) { - var addFractionStatus = addConstantFractions(newNode); - substeps = substeps.concat(addFractionStatus.substeps); - } - else { - var evalNode = mathNode.Creator.constant(evaluate(newNode)); - substeps.push(mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, newNode, evalNode)); - } - var lastStep = substeps[substeps.length - 1]; - newNode = mathNode.Status.resetChangeGroups(lastStep.newNode); - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); -} -module.exports = addConstantAndFraction; -//# sourceMappingURL=addConstantAndFraction.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map deleted file mode 100644 index f75ad718..00000000 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"addConstantAndFraction.js","sourceRoot":"","sources":["addConstantAndFraction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts b/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts deleted file mode 100644 index de81aba4..00000000 --- a/lib/simplifyExpression/fractionsSearch/addConstantAndFraction.ts +++ /dev/null @@ -1,104 +0,0 @@ -import addConstantFractions = require("./addConstantFractions"); -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import evaluate = require("../../util/evaluate"); -import mathNode = require("../../mathnode"); - -// Adds a constant to a fraction by: -// - collapsing the fraction to decimal if the constant is not an integer -// e.g. 5.3 + 1/2 -> 5.3 + 0.2 -// - turning the constant into a fraction with the same denominator if it is -// an integer, e.g. 5 + 1/2 -> 10/2 + 1/2 -function addConstantAndFraction(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "+" || node.args.length !== 2) { - return mathNode.Status.noChange(node); - } - const [firstArg, secondArg] = node.args; - let constNode, fractionNode; - if (mathNode.Type.isConstant(firstArg)) { - if (mathNode.Type.isIntegerFraction(secondArg)) { - constNode = firstArg; - fractionNode = secondArg; - } - else { - return mathNode.Status.noChange(node); - } - } - else if (mathNode.Type.isConstant(secondArg)) { - if (mathNode.Type.isIntegerFraction(firstArg)) { - constNode = secondArg; - fractionNode = firstArg; - } - else { - return mathNode.Status.noChange(node); - } - } - else { - return mathNode.Status.noChange(node); - } - - let newNode = clone(node); - let substeps = []; - // newConstNode and newFractionNode will end up both constants, or both - // fractions. I'm naming them based on their original form so we can keep - // track of which is which. - let newConstNode, newFractionNode; - let changeType; - if (parseFloat(constNode.value) % 1 === 0) { - const denominatorNode = fractionNode.args[1]; - const denominatorValue = parseInt(denominatorNode); - const constNodeValue = parseInt(constNode.value); - const newNumeratorNode = mathNode.Creator.constant( - constNodeValue * denominatorValue); - newConstNode = mathNode.Creator.operator( - "/", [newNumeratorNode, denominatorNode]); - newFractionNode = fractionNode; - changeType = ChangeTypes.CONVERT_INTEGER_TO_FRACTION; - } - else { - // round to 4 decimal places - let dividedValue = evaluate(fractionNode); - if (dividedValue < 1) { - dividedValue = parseFloat(dividedValue.toPrecision(4)); - } - else { - dividedValue = parseFloat(dividedValue.toFixed(4)); - } - newFractionNode = mathNode.Creator.constant(dividedValue); - newConstNode = constNode; - changeType = ChangeTypes.DIVIDE_FRACTION_FOR_ADDITION; - } - - if (mathNode.Type.isConstant(firstArg)) { - newNode.args[0] = newConstNode; - newNode.args[1] = newFractionNode; - } - else { - newNode.args[0] = newFractionNode; - newNode.args[1] = newConstNode; - } - - substeps.push(mathNode.Status.nodeChanged(changeType, node, newNode)); - newNode = mathNode.Status.resetChangeGroups(newNode); - - // If we changed an integer to a fraction, we need to add the steps for - // adding the fractions. - if (changeType === ChangeTypes.CONVERT_INTEGER_TO_FRACTION) { - const addFractionStatus = addConstantFractions(newNode); - substeps = substeps.concat(addFractionStatus.substeps); - } - // Otherwise, add the two constants - else { - const evalNode = mathNode.Creator.constant(evaluate(newNode)); - substeps.push(mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_ARITHMETIC, newNode, evalNode)); - } - - const lastStep = substeps[substeps.length - 1]; - newNode = mathNode.Status.resetChangeGroups(lastStep.newNode); - - return mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_ARITHMETIC, node, newNode, true, substeps); -} - -export = addConstantAndFraction; diff --git a/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts b/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts deleted file mode 100644 index 009e23c9..00000000 --- a/lib/simplifyExpression/fractionsSearch/addConstantFractions.ts +++ /dev/null @@ -1,172 +0,0 @@ -import clone = require("../../util/clone"); -import divideByGCD = require("./divideByGCD"); -import math = require("mathjs"); -import ChangeTypes = require("../../ChangeTypes"); -import evaluate = require("../../util/evaluate"); -import mathNode = require("../../mathnode"); - -// Adds constant fractions -- can start from either step 1 or 2 -// 1A. Find the LCD if denominators are different and multiplies to make -// denominators equal, e.g. 2/3 + 4/6 --> (2*2)/(3*2) + 4/6 -// 1B. Multiplies out to make constant fractions again -// e.g. (2*2)/(3*2) + 4/6 -> 4/6 + 4/6 -// 2A. Combines numerators, e.g. 4/6 + 4/6 -> e.g. 2/5 + 4/5 --> (2+4)/5 -// 2B. Adds numerators together, e.g. (2+4)/5 -> 6/5 -// Returns a mathNode.Status object with substeps -function addConstantFractions(node: mathjs.MathNode) { - let newNode = clone(node); - - if (!mathNode.Type.isOperator(node) || node.op !== "+") { - return mathNode.Status.noChange(node); - } - if (!node.args.every(n => mathNode.Type.isIntegerFraction(n, true))) { - return mathNode.Status.noChange(node); - } - const denominators = node.args.map(fraction => { - return parseFloat(evaluate(fraction.args[1])); - }); - - const substeps = []; - let status; - - // 1A. First create the common denominator if needed - // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) - if (!denominators.every(denominator => denominator === denominators[0])) { - status = makeCommonDenominator(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // 1B. Multiply out the denominators - status = evaluateDenominators(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // 1B. Multiply out the numerators - status = evaluateNumerators(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // 2A. Now that they all have the same denominator, combine the numerators - // e.g. 2/3 + 5/3 -> (2+5)/3 - status = combineNumeratorsAboveCommonDenominator(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // 2B. Finally, add the numerators together - status = addNumeratorsTogether(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // 2C. If the numerator is 0, simplify to just 0 - status = reduceNumerator(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // 2D. If we can simplify the fraction, do so - status = divideByGCD(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.ADD_FRACTIONS, node, newNode, true, substeps); -} - -// Given a + operation node with a list of fraction nodes as args that all have -// the same denominator, add them together. e.g. 2/3 + 5/3 -> (2+5)/3 -// Returns the new node. -function combineNumeratorsAboveCommonDenominator(node: mathjs.MathNode) { - let newNode = clone(node); - - const commonDenominator = newNode.args[0].args[1]; - const numeratorArgs = []; - newNode.args.forEach(fraction => { - numeratorArgs.push(fraction.args[0]); - }); - const newNumerator = mathNode.Creator.parenthesis( - mathNode.Creator.operator("+", numeratorArgs)); - - newNode = mathNode.Creator.operator("/", [newNumerator, commonDenominator]); - return mathNode.Status.nodeChanged( - ChangeTypes.COMBINE_NUMERATORS, node, newNode); -} - -// Given a node with a numerator that is an addition node, will add -// all the numerators and return the result -function addNumeratorsTogether(node: mathjs.MathNode) { - const newNode = clone(node); - - newNode.args[0] = mathNode.Creator.constant(evaluate(newNode.args[0])); - return mathNode.Status.nodeChanged( - ChangeTypes.ADD_NUMERATORS, node, newNode); -} - -function reduceNumerator(node: mathjs.MathNode) { - let newNode = clone(node); - - if (newNode.args[0].value === "0") { - newNode = mathNode.Creator.constant(0); - return mathNode.Status.nodeChanged( - ChangeTypes.REDUCE_ZERO_NUMERATOR, node, newNode); - } - - return mathNode.Status.noChange(node); -} - -// Takes `node`, a sum of fractions, and returns a node that's a sum of -// fractions with denominators that evaluate to the same common denominator -// e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) -// Returns the new node. -function makeCommonDenominator(node: mathjs.MathNode) { - const newNode = clone(node); - - const denominators = newNode.args.map(fraction => { - return parseFloat(fraction.args[1].value); - }); - const commonDenominator = math.lcm(.denominators); - - newNode.args.forEach((child, i) => { - // missingFactor is what we need to multiply the top and bottom by - // so that the denominator is the LCD - const missingFactor = commonDenominator / denominators[i]; - if (missingFactor !== 1) { - const missingFactorNode = mathNode.Creator.constant(missingFactor); - const newNumerator = mathNode.Creator.parenthesis( - mathNode.Creator.operator("*", [child.args[0], missingFactorNode])); - const newDeominator = mathNode.Creator.parenthesis( - mathNode.Creator.operator("*", [child.args[1], missingFactorNode])); - newNode.args[i] = mathNode.Creator.operator("/", [newNumerator, newDeominator]); - } - }); - - return mathNode.Status.nodeChanged( - ChangeTypes.COMMON_DENOMINATOR, node, newNode); -} - -function evaluateDenominators(node: mathjs.MathNode) { - const newNode = clone(node); - - newNode.args.map(fraction => { - fraction.args[1] = mathNode.Creator.constant(evaluate(fraction.args[1])); - }); - - return mathNode.Status.nodeChanged( - ChangeTypes.MULTIPLY_DENOMINATORS, node, newNode); -} - -function evaluateNumerators(node: mathjs.MathNode) { - const newNode = clone(node); - - newNode.args.map(fraction => { - fraction.args[0] = mathNode.Creator.constant(evaluate(fraction.args[0])); - }); - - return mathNode.Status.nodeChanged( - ChangeTypes.MULTIPLY_NUMERATORS, node, newNode); -} - -export = addConstantFractions; diff --git a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts b/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts deleted file mode 100644 index 985ae224..00000000 --- a/lib/simplifyExpression/fractionsSearch/cancelLikeTerms.ts +++ /dev/null @@ -1,309 +0,0 @@ -import clone = require("../../util/clone"); -import print = require("../../util/print"); -import ChangeTypes = require("../../ChangeTypes"); -import Negative = require("../../Negative"); -import mathNode = require("../../mathnode"); - -// Used for cancelTerms to return a (possibly updated) numerator and denominator -class CancelOutStatus { - constructor(numerator, denominator, hasChanged=false) { - this.numerator = numerator; - this.denominator = denominator; - this.hasChanged = hasChanged; - } - - numerator; - denominator; - hasChanged: boolean; -} - -// Cancels like terms in a fraction node -// e.g. (2x^2 * 5) / 2x^2 => 5 / 1 -// Returns a mathNode.Status object -function cancelLikeTerms(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "/") { - return mathNode.Status.noChange(node); - } - let newNode = clone(node); - const numerator = newNode.args[0]; - const denominator = newNode.args[1]; - - // case 1: neither the numerator or denominator is a multiplication of terms - if (!isMultiplicationOfTerms(numerator) && - !isMultiplicationOfTerms(denominator)) { - const cancelStatus = cancelTerms(numerator, denominator); - if (cancelStatus.hasChanged) { - newNode.args[0] = cancelStatus.numerator || mathNode.Creator.constant(1); - if (cancelStatus.denominator) { - newNode.args[1] = cancelStatus.denominator; - } - else { - // If we cancelled out the denominator, the node is now its numerator - // e.g. (2x*y) / 2x => y (note y isn't a fraction) - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_TERMS, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } - } - - // case 2: numerator is a multiplication of terms and denominator is not - // e.g. (2x^2 * 5) / 2x^2 => 5 / 1 - // e.g. (x^2*y) / x => x^(2 - 1) * y (<-- note that the denominator goes - // away because we always adjust the exponent in the numerator) - else if (isMultiplicationOfTerms(numerator) && - !isMultiplicationOfTerms(denominator)) { - const numeratorArgs = mathNode.Type.isParenthesis(numerator) ? - numerator.content.args : numerator.args; - for (let i = 0; i < numeratorArgs.length; i++) { - const cancelStatus = cancelTerms(numeratorArgs[i], denominator); - if (cancelStatus.hasChanged) { - if (cancelStatus.numerator) { - numeratorArgs[i] = cancelStatus.numerator; - } - // if the cancelling out got rid of the numerator node, we remove it from - // the list - else { - numeratorArgs.splice(i, 1); - // if the numerator is now a "multiplication" of only one term, - // change it to just that term - if (numeratorArgs.length === 1) { - newNode.args[0] = numeratorArgs[0]; - } - } - if (cancelStatus.denominator) { - newNode.args[1] = cancelStatus.denominator; - } - else { - // If we cancelled out the denominator, the node is now its numerator - // e.g. (2x*y) / 2x => y (note y isn't a fraction) - newNode = newNode.args[0]; - } - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_TERMS, node, newNode); - } - } - return mathNode.Status.noChange(node); - } - - // case 3: denominator is a multiplication of terms and numerator is not - // e.g. 2x^2 / (2x^2 * 5) => 1 / 5 - // e.g. x / (x^2*y) => x^(1-2) / y - else if (isMultiplicationOfTerms(denominator) && - !isMultiplicationOfTerms(numerator)) { - const denominatorArgs = mathNode.Type.isParenthesis(denominator) ? - denominator.content.args : denominator.args; - for (let i = 0; i < denominatorArgs.length; i++) { - const cancelStatus = cancelTerms(numerator, denominatorArgs[i]); - if (cancelStatus.hasChanged) { - newNode.args[0] = cancelStatus.numerator || mathNode.Creator.constant(1); - if (cancelStatus.denominator) { - denominatorArgs[i] = cancelStatus.denominator; - } - // if the cancelling out got rid of the denominator node, we remove it - // from the list - else { - denominatorArgs.splice(i, 1); - // if the denominator is now a "multiplication" of only one term, - // change it to just that term - if (denominatorArgs.length === 1) { - newNode.args[1] = denominatorArgs[0]; - } - } - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_TERMS, node, newNode); - } - } - return mathNode.Status.noChange(node); - } - - // case 4: the numerator and denominator are both multiplications of terms - else { - const numeratorArgs = mathNode.Type.isParenthesis(numerator) ? - numerator.content.args : numerator.args; - const denominatorArgs = mathNode.Type.isParenthesis(denominator) ? - denominator.content.args : denominator.args; - for (let i = 0; i < numeratorArgs.length; i++) { - for (let j = 0; j < denominatorArgs.length; j++) { - const cancelStatus = cancelTerms(numeratorArgs[i], denominatorArgs[j]); - if (cancelStatus.hasChanged) { - if (cancelStatus.numerator) { - numeratorArgs[i] = cancelStatus.numerator; - } - // if the cancelling out got rid of the numerator node, we remove it - // from the list - else { - numeratorArgs.splice(i, 1); - // if the numerator is now a "multiplication" of only one term, - // change it to just that term - if (numeratorArgs.length === 1) { - newNode.args[0] = numeratorArgs[0]; - } - } - if (cancelStatus.denominator) { - denominatorArgs[j] = cancelStatus.denominator; - } - // if the cancelling out got rid of the denominator node, we remove it - // from the list - else { - denominatorArgs.splice(j, 1); - // if the denominator is now a "multiplication" of only one term, - // change it to just that term - if (denominatorArgs.length === 1) { - newNode.args[1] = denominatorArgs[0]; - } - } - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_TERMS, node, newNode); - } - } - } - return mathNode.Status.noChange(node); - } -} - -// Given a term in the numerator and a term in the denominator, cancels out -// like terms if possible. See the cases below for possible things that can -// be cancelled out and how they are cancelled out. -// Returns the new nodes for numerator and denominator with the common terms -// removed. If the entire numerator or denominator is cancelled out, it is -// returned as null. e.g. 4, 4x => null, x -function cancelTerms(numerator, denominator) { - // Deal with unary minuses by recursing on the argument - if (mathNode.Type.isUnaryMinus(numerator)) { - const cancelStatus = cancelTerms(numerator.args[0], denominator); - if (!cancelStatus.numerator) { - numerator = mathNode.Creator.constant(-1); - } - else if (Negative.isNegative(cancelStatus.numerator)) { - numerator = Negative.negate(cancelStatus.numerator); - } - else { - numerator.args[0] = cancelStatus.numerator; - } - denominator = cancelTerms.denominator; - return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); - } - if (mathNode.Type.isUnaryMinus(denominator)) { - const cancelStatus = cancelTerms(numerator, denominator.args[0]); - numerator = cancelStatus.numerator; - if (cancelStatus.denominator) { - denominator.args[0] = cancelStatus.denominator; - } - else { - denominator = cancelStatus.denominator; - if (numerator) { - numerator = Negative.negate(numerator); - } - else { - numerator = mathNode.Creator.constant(-1); - } - } - return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); - } - - // Deal with parens similarily - if (mathNode.Type.isParenthesis(numerator)) { - const cancelStatus = cancelTerms(numerator.content, denominator); - if (cancelStatus.numerator) { - numerator.content = cancelStatus.numerator; - } - else { - // if the numerator was cancelled out, the numerator should be null - // and not null in parens. - numerator = cancelStatus.numerator; - } - denominator = cancelStatus.denominator; - return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); - } - if (mathNode.Type.isParenthesis(denominator)) { - const cancelStatus = cancelTerms(numerator, denominator.content); - if (cancelStatus.denominator) { - denominator.content = cancelStatus.denominator; - } - else { - // if the denominator was cancelled out, the denominator should be null - // and not null in parens. - denominator = cancelStatus.denominator; - } - numerator = cancelStatus.numerator; - return new CancelOutStatus(numerator, denominator, cancelStatus.hasChanged); - } - - // Now for the term cancelling ---- - - // case 1: the numerator term and denominator term are the same, so we cancel - // them out. e.g. (x+5)^100 / (x+5)^100 => null / null - if (print(numerator) === print(denominator)) { - return new CancelOutStatus(null, null, true); - } - - // case 2: they're both exponent nodes with the same base - // e.g. (2x+5)^8 and (2x+5)^2 - if (mathNode.Type.isOperator(numerator, "^") && - mathNode.Type.isOperator(denominator, "^") && - print(numerator.args[0]) === print(denominator.args[0])) { - const numeratorExponent = numerator.args[1]; - let denominatorExponent = denominator.args[1]; - // wrap the denominatorExponent in parens, in case it's complicated. - // If the parens aren't needed, they'll be removed with - // removeUnnecessaryParens at the end of this step. - denominatorExponent = mathNode.Creator.parenthesis(denominatorExponent); - const newExponent = mathNode.Creator.parenthesis( - mathNode.Creator.operator("-", [numeratorExponent, denominatorExponent])); - numerator.args[1] = newExponent; - return new CancelOutStatus(numerator, null, true); - } - - // case 3: they're both polynomial terms, check if they have the same symbol - // e.g. 4x^2 / 5x^2 => 4 / 5 - // e.g. 4x^3 / 5x^2 => 4x^(3-2) / 5 - if (mathNode.PolynomialTerm.isPolynomialTerm(numerator) && - mathNode.PolynomialTerm.isPolynomialTerm(denominator)) { - const numeratorTerm = new mathNode.PolynomialTerm(numerator); - const denominatorTerm = new mathNode.PolynomialTerm(denominator); - if (numeratorTerm.getSymbolName() !== denominatorTerm.getSymbolName()) { - return new CancelOutStatus(numerator, denominator); - } - const numeratorExponent = numeratorTerm.getExponentNode(true); - let denominatorExponent = denominatorTerm.getExponentNode(true); - if (print(numeratorExponent) === print(denominatorExponent)) { - // note this returns null if there's no coefficient (ie it's 1) - numerator = numeratorTerm.getCoeffNode(); - } - else { - // wrap the denominatorExponent in parens, in case it's complicated. - // If the parens aren't needed, they'll be removed with - // removeUnnecessaryParens at the end of this step. - denominatorExponent = mathNode.Creator.parenthesis(denominatorExponent); - const newExponent = mathNode.Creator.parenthesis( - mathNode.Creator.operator("-", [numeratorExponent, denominatorExponent])); - numerator = mathNode.Creator.polynomialTerm( - numeratorTerm.getSymbolNode(), - newExponent, - numeratorTerm.getCoeffNode()); - } - denominator = denominatorTerm.getCoeffNode(); - return new CancelOutStatus(numerator, denominator, true); - } - - return new CancelOutStatus(numerator, denominator); -} - -// Returns true if node is a multiplication of terms that can be cancelled out -// e.g. 2 * 6^y => true -// e.g. 2 + 6 => false -// e.g. (2 * 6^y) => true -// e.g. 2x^2 => false (polynomial terms are considered as one single term) -function isMultiplicationOfTerms(node: mathjs.MathNode) { - if (mathNode.Type.isParenthesis(node)) { - return isMultiplicationOfTerms(node); - } - return (mathNode.Type.isOperator(node, "*") && - !mathNode.PolynomialTerm.isPolynomialTerm(node)); -} - -export = cancelLikeTerms; diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.js b/lib/simplifyExpression/fractionsSearch/divideByGCD.js deleted file mode 100644 index 7d92f70a..00000000 --- a/lib/simplifyExpression/fractionsSearch/divideByGCD.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; -var math = require("mathjs"); -var ChangeTypes = require("../../ChangeTypes"); -var evaluate = require("../../util/evaluate"); -var mathNode = require("../../mathnode"); -// Simplifies a fraction (with constant numerator and denominator) by dividing -// the top and bottom by the GCD, if possible. -// e.g. 2/4 --> 1/2 10/5 --> 2x -// Also simplified negative signs -// e.g. -1/-3 --> 1/3 4/-5 --> -4/5 -// Note that -4/5 doesn't need to be simplified. -// Note that our goal is for the denominator to always be positive. If it -// isn't, we can simplify signs. -// Returns a mathNode.Status object -function divideByGcd(fraction) { - if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { - return mathNode.Status.noChange(fraction); - } - // If it's not an integer fraction, all we can do is simplify signs - if (!mathNode.Type.isIntegerFraction(fraction, true)) { - return mathNode.Status.noChange(fraction); - } - var numeratorValue = parseInt(evaluate(fraction.args[0])); - var denominatorValue = parseInt(evaluate(fraction.args[1])); - // The gcd is what we're dividing the numerator and denominator by. - var gcd = math.gcd(numeratorValue, denominatorValue); - // A greatest common denominator is technically defined as always positive, - // but since our goal is to reduce negative signs or move them to the - // numerator, a negative denominator always means we want to flip signs - // of both numerator and denominator. - // e.g. -1/-3 --> 1/3 4/-5 --> -4/5 - if (denominatorValue < 0) { - gcd *= -1; - } - if (gcd === 1) { - return mathNode.Status.noChange(fraction); - } - var newNumeratorNode = mathNode.Creator.constant(numeratorValue / gcd); - var newDenominatorNode = mathNode.Creator.constant(denominatorValue / gcd); - var newFraction; - if (parseFloat(newDenominatorNode.value) === 1) { - newFraction = newNumeratorNode; - } - else { - newFraction = mathNode.Creator.operator("/", [newNumeratorNode, newDenominatorNode]); - } - return mathNode.Status.nodeChanged(ChangeTypes.SIMPLIFY_FRACTION, fraction, newFraction); -} -module.exports = divideByGcd; -//# sourceMappingURL=divideByGCD.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.js.map b/lib/simplifyExpression/fractionsSearch/divideByGCD.js.map deleted file mode 100644 index 92d36304..00000000 --- a/lib/simplifyExpression/fractionsSearch/divideByGCD.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"divideByGCD.js","sourceRoot":"","sources":["divideByGCD.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,+CAAkD;AAClD,8CAAiD;AACjD,yCAA4C;AAE5C,8EAA8E;AAC9E,8CAA8C;AAC9C,kCAAkC;AAClC,iCAAiC;AACjC,qCAAqC;AACrC,gDAAgD;AAChD,yEAAyE;AACzE,gCAAgC;AAChC,mCAAmC;AACnC,qBAAqB,QAAQ;IAC3B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IACD,mEAAmE;IACnE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,IAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9D,mEAAmE;IACnE,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IACrD,2EAA2E;IAC3E,qEAAqE;IACrE,uEAAuE;IACvE,qCAAqC;IACrC,qCAAqC;IACrC,EAAE,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,GAAG,IAAI,CAAC,CAAC,CAAC;IACZ,CAAC;IAED,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,IAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,GAAC,GAAG,CAAC,CAAC;IACvE,IAAM,kBAAkB,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,GAAC,GAAG,CAAC,CAAC;IAC3E,IAAI,WAAW,CAAC;IAChB,EAAE,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/C,WAAW,GAAG,gBAAgB,CAAC;IACjC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CACrC,GAAG,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,iBAAiB,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AAC1D,CAAC;AAED,iBAAS,WAAW,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/divideByGCD.ts b/lib/simplifyExpression/fractionsSearch/divideByGCD.ts deleted file mode 100644 index 8f0e5f46..00000000 --- a/lib/simplifyExpression/fractionsSearch/divideByGCD.ts +++ /dev/null @@ -1,57 +0,0 @@ -import math = require("mathjs"); -import ChangeTypes = require("../../ChangeTypes"); -import evaluate = require("../../util/evaluate"); -import mathNode = require("../../mathnode"); - -// Simplifies a fraction (with constant numerator and denominator) by dividing -// the top and bottom by the GCD, if possible. -// e.g. 2/4 --> 1/2 10/5 --> 2x -// Also simplified negative signs -// e.g. -1/-3 --> 1/3 4/-5 --> -4/5 -// Note that -4/5 doesn't need to be simplified. -// Note that our goal is for the denominator to always be positive. If it -// isn't, we can simplify signs. -// Returns a mathNode.Status object -function divideByGcd(fraction) { - if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { - return mathNode.Status.noChange(fraction); - } - // If it's not an integer fraction, all we can do is simplify signs - if (!mathNode.Type.isIntegerFraction(fraction, true)) { - return mathNode.Status.noChange(fraction); - } - - const numeratorValue = parseInt(evaluate(fraction.args[0])); - const denominatorValue = parseInt(evaluate(fraction.args[1])); - - // The gcd is what we're dividing the numerator and denominator by. - let gcd = math.gcd(numeratorValue, denominatorValue); - // A greatest common denominator is technically defined as always positive, - // but since our goal is to reduce negative signs or move them to the - // numerator, a negative denominator always means we want to flip signs - // of both numerator and denominator. - // e.g. -1/-3 --> 1/3 4/-5 --> -4/5 - if (denominatorValue < 0) { - gcd *= -1; - } - - if (gcd === 1) { - return mathNode.Status.noChange(fraction); - } - - const newNumeratorNode = mathNode.Creator.constant(numeratorValue/gcd); - const newDenominatorNode = mathNode.Creator.constant(denominatorValue/gcd); - let newFraction; - if (parseFloat(newDenominatorNode.value) === 1) { - newFraction = newNumeratorNode; - } - else { - newFraction = mathNode.Creator.operator( - "/", [newNumeratorNode, newDenominatorNode]); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.SIMPLIFY_FRACTION, fraction, newFraction); -} - -export = divideByGcd; diff --git a/lib/simplifyExpression/fractionsSearch/index.js b/lib/simplifyExpression/fractionsSearch/index.js deleted file mode 100644 index 88e9b28e..00000000 --- a/lib/simplifyExpression/fractionsSearch/index.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Performs simpifications on fractions: adding and cancelling out. - * - * Note: division is represented in mathjs as an operator node with op '/' - * and two args, where arg[0] is the numerator and arg[1] is the denominator - -// This module manipulates fractions with constants in the numerator and -// denominator. For more complex/general fractions, see Fraction.js - - */ -"use strict"; -var addConstantAndFraction = require("./addConstantAndFraction"); -var addConstantFractions = require("./addConstantFractions"); -var cancelLikeTerms = require("./cancelLikeTerms"); -var divideByGCD = require("./divideByGCD"); -var simplifyFractionSigns = require("./simplifyFractionSigns"); -var simplifyPolynomialFraction = require("./simplifyPolynomialFraction"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -var simplificationFunctions = [ - // e.g. 2/3 + 5/6 - addConstantFractions, - // e.g. 4 + 5/6 or 4.5 + 6/8 - addConstantAndFraction, - // e.g. 2/-9 -> -2/9 e.g. -2/-9 -> 2/9 - simplifyFractionSigns, - // e.g. 8/12 -> 2/3 (divide by GCD 4) - divideByGCD, - // e.g. 2x/4 -> x/2 (divideByGCD but for coefficients of polynomial terms) - simplifyPolynomialFraction, - // e.g. (2x * 5) / 2x -> 5 - cancelLikeTerms, -]; -var search = TreeSearch.preOrder(simplifyFractions); -function simplifyFractions(node) { - for (var i = 0; i < simplificationFunctions.length; i++) { - var nodeStatus = simplificationFunctions[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - else { - node = nodeStatus.newNode; - } - } - return mathNode.Status.noChange(node); -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/index.js.map b/lib/simplifyExpression/fractionsSearch/index.js.map deleted file mode 100644 index 4e2ce522..00000000 --- a/lib/simplifyExpression/fractionsSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;AAEH,iEAAoE;AACpE,6DAAgE;AAChE,mDAAsD;AACtD,2CAA8C;AAC9C,+DAAkE;AAClE,yEAA4E;AAC5E,yCAA4C;AAC5C,6CAAgD;AAChD,IAAM,uBAAuB,GAAe;IAC1C,iBAAiB;IACjB,oBAAoB;IACpB,4BAA4B;IAC5B,sBAAsB;IACtB,+CAA+C;IAC/C,qBAAqB;IACrB,uCAAuC;IACvC,WAAW;IACX,0EAA0E;IAC1E,0BAA0B;IAC1B,4BAA4B;IAC5B,eAAe;CAChB,CAAC;AAEF,IAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAItD,2BAA2B,IAAI;IAC7B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,IAAM,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpD,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/index.ts b/lib/simplifyExpression/fractionsSearch/index.ts deleted file mode 100644 index e960db7f..00000000 --- a/lib/simplifyExpression/fractionsSearch/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Performs simpifications on fractions: adding and cancelling out. - * - * Note: division is represented in mathjs as an operator node with op '/' - * and two args, where arg[0] is the numerator and arg[1] is the denominator - -// This module manipulates fractions with constants in the numerator and -// denominator. For more complex/general fractions, see Fraction.js - - */ - -import addConstantAndFraction = require("./addConstantAndFraction"); -import addConstantFractions = require("./addConstantFractions"); -import cancelLikeTerms = require("./cancelLikeTerms"); -import divideByGCD = require("./divideByGCD"); -import simplifyFractionSigns = require("./simplifyFractionSigns"); -import simplifyPolynomialFraction = require("./simplifyPolynomialFraction"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); -const simplificationFunctions: Array = [ - // e.g. 2/3 + 5/6 - addConstantFractions, - // e.g. 4 + 5/6 or 4.5 + 6/8 - addConstantAndFraction, - // e.g. 2/-9 -> -2/9 e.g. -2/-9 -> 2/9 - simplifyFractionSigns, - // e.g. 8/12 -> 2/3 (divide by GCD 4) - divideByGCD, - // e.g. 2x/4 -> x/2 (divideByGCD but for coefficients of polynomial terms) - simplifyPolynomialFraction, - // e.g. (2x * 5) / 2x -> 5 - cancelLikeTerms, -]; - -const search = TreeSearch.preOrder(simplifyFractions); - -// Look for step(s) to perform on a node. Returns a mathNode.Status object. -function simplifyFractions(node: any); -function simplifyFractions(node) { - for (let i = 0; i < simplificationFunctions.length; i++) { - const nodeStatus = simplificationFunctions[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - else { - node = nodeStatus.newNode; - } - } - return mathNode.Status.noChange(node); -} - -export = search; diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js deleted file mode 100644 index 184aa5af..00000000 --- a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var ChangeTypes = require("../../ChangeTypes"); -var Negative = require("../../Negative"); -var mathNode = require("../../mathnode"); -// Simplifies negative signs if possible -// e.g. -1/-3 --> 1/3 4/-5 --> -4/5 -// Note that -4/5 doesn't need to be simplified. -// Note that our goal is for the denominator to always be positive. If it -// isn't, we can simplify signs. -// Returns a mathNode.Status object -function simplifySigns(fraction) { - if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { - return mathNode.Status.noChange(fraction); - } - var oldFraction = clone(fraction); - var numerator = fraction.args[0]; - var denominator = fraction.args[1]; - // The denominator should never be negative. - if (Negative.isNegative(denominator)) { - denominator = Negative.negate(denominator); - var changeType = Negative.isNegative(numerator) ? - ChangeTypes.CANCEL_MINUSES : - ChangeTypes.SIMPLIFY_SIGNS; - numerator = Negative.negate(numerator); - var newFraction = mathNode.Creator.operator("/", [numerator, denominator]); - return mathNode.Status.nodeChanged(changeType, oldFraction, newFraction); - } - else { - return mathNode.Status.noChange(fraction); - } -} -module.exports = simplifySigns; -//# sourceMappingURL=simplifyFractionSigns.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map deleted file mode 100644 index 8ae3a150..00000000 --- a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"simplifyFractionSigns.js","sourceRoot":"","sources":["simplifyFractionSigns.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,+CAAkD;AAClD,yCAA4C;AAC5C,yCAA4C;AAE5C,wCAAwC;AACxC,qCAAqC;AACrC,gDAAgD;AAChD,yEAAyE;AACzE,gCAAgC;AAChC,mCAAmC;AAEnC,uBAAuB,QAAQ;IAC7B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IACD,IAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,4CAA4C;IAC5C,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACrC,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;YAC/C,WAAW,CAAC,cAAc;YAC1B,WAAW,CAAC,cAAc,CAAC;QAC7B,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvC,IAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,iBAAS,aAAa,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts b/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts deleted file mode 100644 index ab3c8b0f..00000000 --- a/lib/simplifyExpression/fractionsSearch/simplifyFractionSigns.ts +++ /dev/null @@ -1,35 +0,0 @@ -import clone = require("../../util/clone"); -import ChangeTypes = require("../../ChangeTypes"); -import Negative = require("../../Negative"); -import mathNode = require("../../mathnode"); - -// Simplifies negative signs if possible -// e.g. -1/-3 --> 1/3 4/-5 --> -4/5 -// Note that -4/5 doesn't need to be simplified. -// Note that our goal is for the denominator to always be positive. If it -// isn't, we can simplify signs. -// Returns a mathNode.Status object - -function simplifySigns(fraction) { - if (!mathNode.Type.isOperator(fraction) || fraction.op !== "/") { - return mathNode.Status.noChange(fraction); - } - const oldFraction = clone(fraction); - let numerator = fraction.args[0]; - let denominator = fraction.args[1]; - // The denominator should never be negative. - if (Negative.isNegative(denominator)) { - denominator = Negative.negate(denominator); - const changeType = Negative.isNegative(numerator) ? - ChangeTypes.CANCEL_MINUSES : - ChangeTypes.SIMPLIFY_SIGNS; - numerator = Negative.negate(numerator); - const newFraction = mathNode.Creator.operator("/", [numerator, denominator]); - return mathNode.Status.nodeChanged(changeType, oldFraction, newFraction); - } - else { - return mathNode.Status.noChange(fraction); - } -} - -export = simplifySigns; diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js deleted file mode 100644 index 00c0c88a..00000000 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -var arithmeticSearch = require("../arithmeticSearch"); -var clone = require("../../util/clone"); -var divideByGCD = require("./divideByGCD"); -var mathNode = require("../../mathnode"); -// Simplifies a polynomial term with a fraction as its coefficients. -// e.g. 2x/4 --> x/2 10x/5 --> 2x -// Also simplified negative signs -// e.g. -y/-3 --> y/3 4x/-5 --> -4x/5 -// returns the new simplified node in a mathNode.Status object -function simplifyPolynomialFraction(node) { - if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { - return mathNode.Status.noChange(node); - } - var polyNode = new mathNode.PolynomialTerm(clone(node)); - if (!polyNode.hasFractionCoeff()) { - return mathNode.Status.noChange(node); - } - var coefficientSimplifications = [ - divideByGCD, - arithmeticSearch, - ]; - for (var i = 0; i < coefficientSimplifications.length; i++) { - var coefficientFraction = polyNode.getCoeffNode(); // a division node - var newCoeffStatus = coefficientSimplifications[i](coefficientFraction); - if (newCoeffStatus.hasChanged()) { - var newCoeff = newCoeffStatus.newNode; - if (newCoeff.value === "1") { - newCoeff = null; - } - var exponentNode = polyNode.getExponentNode(); - var newNode = mathNode.Creator.polynomialTerm(polyNode.getSymbolNode(), exponentNode, newCoeff); - return mathNode.Status.nodeChanged(newCoeffStatus.changeType, node, newNode); - } - } - return mathNode.Status.noChange(node); -} -module.exports = simplifyPolynomialFraction; -//# sourceMappingURL=simplifyPolynomialFraction.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map deleted file mode 100644 index 3ec6f21b..00000000 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"simplifyPolynomialFraction.js","sourceRoot":"","sources":["simplifyPolynomialFraction.ts"],"names":[],"mappings":";AAAA,sDAAyD;AACzD,wCAA2C;AAC3C,2CAA8C;AAC9C,yCAA4C;AAE5C,oEAAoE;AACpE,oCAAoC;AACpC,iCAAiC;AACjC,uCAAuC;AACvC,8DAA8D;AAC9D,oCAAoC,IAAqB;IACvD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,0BAA0B,GAAG;QACjC,WAAW;QACX,gBAAgB;KACjB,CAAC;IAEF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,0BAA0B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,IAAM,mBAAmB,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,kBAAkB;QACvE,IAAM,cAAc,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC1E,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;YACtC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;gBAC3B,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;YACD,IAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC;YAChD,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,CAC3C,QAAQ,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;YACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,0BAA0B,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts b/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts deleted file mode 100644 index 48e7d5ad..00000000 --- a/lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.ts +++ /dev/null @@ -1,44 +0,0 @@ -import arithmeticSearch = require("../arithmeticSearch"); -import clone = require("../../util/clone"); -import divideByGCD = require("./divideByGCD"); -import mathNode = require("../../mathnode"); - -// Simplifies a polynomial term with a fraction as its coefficients. -// e.g. 2x/4 --> x/2 10x/5 --> 2x -// Also simplified negative signs -// e.g. -y/-3 --> y/3 4x/-5 --> -4x/5 -// returns the new simplified node in a mathNode.Status object -function simplifyPolynomialFraction(node: mathjs.MathNode) { - if (!mathNode.PolynomialTerm.isPolynomialTerm(node)) { - return mathNode.Status.noChange(node); - } - - const polyNode = new mathNode.PolynomialTerm(clone(node)); - if (!polyNode.hasFractionCoeff()) { - return mathNode.Status.noChange(node); - } - - const coefficientSimplifications = [ - divideByGCD, // for integer fractions - arithmeticSearch, // for decimal fractions - ]; - - for (let i = 0; i < coefficientSimplifications.length; i++) { - const coefficientFraction = polyNode.getCoeffNode(); // a division node - const newCoeffStatus = coefficientSimplifications[i](coefficientFraction); - if (newCoeffStatus.hasChanged()) { - let newCoeff = newCoeffStatus.newNode; - if (newCoeff.value === "1") { - newCoeff = null; - } - const exponentNode = polyNode.getExponentNode(); - const newNode = mathNode.Creator.polynomialTerm( - polyNode.getSymbolNode(), exponentNode, newCoeff); - return mathNode.Status.nodeChanged(newCoeffStatus.changeType, node, newNode); - } - } - - return mathNode.Status.noChange(node); -} - -export = simplifyPolynomialFraction; diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.js b/lib/simplifyExpression/functionsSearch/absoluteValue.js deleted file mode 100644 index 8249c390..00000000 --- a/lib/simplifyExpression/functionsSearch/absoluteValue.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -var clone = require("../../util/clone"); -var math = require("mathjs"); -var ChangeTypes = require("../../ChangeTypes"); -var evaluate = require("../../util/evaluate"); -var mathNode = require("../../mathnode"); -// Evaluates abs() function if it's on a single constant value. -// Returns a mathNode.Status object. -function absoluteValue(node) { - if (!mathNode.Type.isFunction(node, "abs")) { - return mathNode.Status.noChange(node); - } - if (node.args.length > 1) { - return mathNode.Status.noChange(node); - } - var newNode = clone(node); - var argument = newNode.args[0]; - if (mathNode.Type.isConstant(argument, true)) { - newNode = mathNode.Creator.constant(math.abs(evaluate(argument))); - return mathNode.Status.nodeChanged(ChangeTypes.ABSOLUTE_VALUE, node, newNode); - } - else if (mathNode.Type.isConstantFraction(argument, true)) { - var newNumerator = mathNode.Creator.constant(math.abs(evaluate(argument.args[0]))); - var newDenominator = mathNode.Creator.constant(math.abs(evaluate(argument.args[1]))); - newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); - return mathNode.Status.nodeChanged(ChangeTypes.ABSOLUTE_VALUE, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} -module.exports = absoluteValue; -//# sourceMappingURL=absoluteValue.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.js.map b/lib/simplifyExpression/functionsSearch/absoluteValue.js.map deleted file mode 100644 index d795a3b8..00000000 --- a/lib/simplifyExpression/functionsSearch/absoluteValue.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"absoluteValue.js","sourceRoot":"","sources":["absoluteValue.ts"],"names":[],"mappings":";AAAA,wCAA2C;AAC3C,6BAAgC;AAChC,+CAAkD;AAClD,8CAAiD;AACjD,yCAA6C;AAE7C,+DAA+D;AAC/D,oCAAoC;AACpC,uBAAuB,IAAqB;IAC1C,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAC5C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,IAAM,cAAc,GAAI,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAC/C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;QACzE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,iBAAS,aAAa,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/absoluteValue.ts b/lib/simplifyExpression/functionsSearch/absoluteValue.ts deleted file mode 100644 index 1864394e..00000000 --- a/lib/simplifyExpression/functionsSearch/absoluteValue.ts +++ /dev/null @@ -1,37 +0,0 @@ -import clone = require("../../util/clone"); -import math = require("mathjs"); -import ChangeTypes = require("../../ChangeTypes"); -import evaluate = require("../../util/evaluate"); -import mathNode = require("../../mathnode"); - -// Evaluates abs() function if it's on a single constant value. -// Returns a mathNode.Status object. -function absoluteValue(node: mathjs.MathNode) { - if (!mathNode.Type.isFunction(node, "abs")) { - return mathNode.Status.noChange(node); - } - if (node.args.length > 1) { - return mathNode.Status.noChange(node); - } - let newNode = clone(node); - const argument = newNode.args[0]; - if (mathNode.Type.isConstant(argument, true)) { - newNode = mathNode.Creator.constant(math.abs(evaluate(argument))); - return mathNode.Status.nodeChanged( - ChangeTypes.ABSOLUTE_VALUE, node, newNode); - } - else if (mathNode.Type.isConstantFraction(argument, true)) { - const newNumerator = mathNode.Creator.constant( - math.abs(evaluate(argument.args[0]))); - const newDenominator = mathNode.Creator.constant( - math.abs(evaluate(argument.args[1]))); - newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); - return mathNode.Status.nodeChanged( - ChangeTypes.ABSOLUTE_VALUE, node, newNode); - } - else { - return mathNode.Status.noChange(node); - } -} - -export = absoluteValue; diff --git a/lib/simplifyExpression/functionsSearch/index.js b/lib/simplifyExpression/functionsSearch/index.js deleted file mode 100644 index 562743d5..00000000 --- a/lib/simplifyExpression/functionsSearch/index.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -var absoluteValue = require("./absoluteValue"); -var nthRoot = require("./nthRoot"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -var FUNCTIONS = [ - nthRoot, - absoluteValue -]; -// Searches through the tree, prioritizing deeper nodes, and evaluates -// functions (e.g. abs(-4)) if possible. -// Returns a mathNode.Status object. -var search = TreeSearch.postOrder(functions); -// Evaluates a function call if possible. Returns a mathNode.Status object. -function functions(node) { - if (!mathNode.Type.isFunction(node)) { - return mathNode.Status.noChange(node); - } - for (var i = 0; i < FUNCTIONS.length; i++) { - var nodeStatus = FUNCTIONS[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - } - return mathNode.Status.noChange(node); -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/index.js.map b/lib/simplifyExpression/functionsSearch/index.js.map deleted file mode 100644 index b3c405bd..00000000 --- a/lib/simplifyExpression/functionsSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,mCAAsC;AACtC,yCAA4C;AAC5C,6CAAgD;AAChD,IAAM,SAAS,GAAG;IAChB,OAAO;IACP,aAAa;CACd,CAAC;AAEF,sEAAsE;AACtE,wCAAwC;AACxC,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAE/C,2EAA2E;AAC3E,mBAAmB,IAAqB;IACtC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,IAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/functionsSearch/index.ts b/lib/simplifyExpression/functionsSearch/index.ts deleted file mode 100644 index a412a5be..00000000 --- a/lib/simplifyExpression/functionsSearch/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import absoluteValue = require("./absoluteValue"); -import nthRoot = require("./nthRoot"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); -const FUNCTIONS = [ - nthRoot, - absoluteValue -]; - -// Searches through the tree, prioritizing deeper nodes, and evaluates -// functions (e.g. abs(-4)) if possible. -// Returns a mathNode.Status object. -const search = TreeSearch.postOrder(functions); - -// Evaluates a function call if possible. Returns a mathNode.Status object. -function functions(node: mathjs.MathNode) { - if (!mathNode.Type.isFunction(node)) { - return mathNode.Status.noChange(node); - } - - for (let i = 0; i < FUNCTIONS.length; i++) { - const nodeStatus = FUNCTIONS[i](node); - if (nodeStatus.hasChanged()) { - return nodeStatus; - } - } - return mathNode.Status.noChange(node); -} - -export = search; diff --git a/lib/simplifyExpression/functionsSearch/nthRoot.ts b/lib/simplifyExpression/functionsSearch/nthRoot.ts deleted file mode 100644 index 19102b37..00000000 --- a/lib/simplifyExpression/functionsSearch/nthRoot.ts +++ /dev/null @@ -1,474 +0,0 @@ -import clone = require("../../util/clone"); -import math = require("mathjs"); -import ChangeTypes = require("../../ChangeTypes"); -import ConstantFactors = require("../../factor/ConstantFactors"); -import Negative = require("../../Negative"); -import mathNode = require("../../mathnode"); - -// Evaluate nthRoot() function. -// Returns a mathNode.Status object. -function nthRoot(node: mathjs.MathNode) { - if (!mathNode.Type.isFunction(node, "nthRoot")) { - return mathNode.Status.noChange(node); - } - - const radicandNode = getRadicandNode(node); - if (mathNode.Type.isOperator(radicandNode)) { - if (radicandNode.op === "^") { - return nthRootExponent(node); - } - else if (radicandNode.op === "*") { - return nthRootMultiplication(node); - } - } - else if (mathNode.Type.isConstant(radicandNode)) { - return nthRootConstant(node); - } - - return mathNode.Status.noChange(node); -} - -// Returns the nthRoot evaluated for an exponent node. Expects an exponent under -// the radicand. Cancels the root and the exponent if possible. Three cases: -// equal: nthRoot(2^x, x) = 2 -// root > exponent: nthRoot(x^2, 4) = nthRoot(x, 2) -// exponent > root: nthRoot(x^4, 2) = x^2 -function nthRootExponent(node: mathjs.MathNode) { - // is this used anywhere? - let newNode = clone(node); - - const radicandNode = getRadicandNode(node); - const rootNode = getRootNode(node); - const baseNode = radicandNode.args[0]; - const exponentNode = mathNode.Type.isParenthesis(radicandNode.args[1]) ? - radicandNode.args[1].content : radicandNode.args[1]; - if (rootNode.equals(exponentNode)) { - newNode = baseNode; - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_EXPONENT_AND_ROOT, node, newNode); - } - else if (mathNode.Type.isConstant(rootNode) && mathNode.Type.isConstant(exponentNode)) { - const rootValue = parseFloat(rootNode.value); - const exponentValue = parseFloat(exponentNode.value); - if (rootValue % exponentValue === 0) { - const newRootValue = rootValue/exponentValue; - const newRootNode = mathNode.Creator.constant(newRootValue); - - newNode = mathNode.Creator.nthRoot(baseNode, newRootNode); - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_EXPONENT, node, newNode); - } - else if (exponentValue % rootValue === 0) { - const newExponentValue = exponentValue/rootValue; - const newExponentNode = mathNode.Creator.constant(newExponentValue); - - newNode = mathNode.Creator.operator("^", [baseNode, newExponentNode]); - return mathNode.Status.nodeChanged( - ChangeTypes.CANCEL_ROOT, node, newNode); - } - } - - return mathNode.Status.noChange(node); -} - -// Returns the nthRoot evaluated for a multiplication node. -// Expects a multiplication node uder the radicand. -// If the root is a positive constant, it: -// 1A: factors the multiplicands -// 1B: groups them into groups whose length is the root value -// 1C: converts the multiplications into exponents. -// If it's possible to simplify further, it: -// 2A: Distributes the nthRoot into the children nodes, -// 2B: evaluates those nthRoots -// 2C: combines them -function nthRootMultiplication(node: mathjs.MathNode) { - let newNode = clone(node); - const rootNode = getRootNode(node); - - const substeps = []; - let status; - if (mathNode.Type.isConstant(rootNode) && !Negative.isNegative(rootNode)) { - // Step 1A - status = factorMultiplicands(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // Step 1B - status = groupTermsByRoot(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - // Step 1C - status = convertMultiplicationToExponent(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - if (newNode.args[0].op === "^") { - status = nthRootExponent(newNode); - substeps.push(status); - return mathNode.Status.nodeChanged( - ChangeTypes.NTH_ROOT_VALUE, node, status.newNode, true, substeps); - } - } - } - - // Step 2A - status = distributeNthRoot(newNode); - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // Step 2B - status = evaluateNthRootForChildren(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - - // Step 2C - status = combineRoots(newNode); - if (status.hasChanged()) { - substeps.push(status); - newNode = mathNode.Status.resetChangeGroups(status.newNode); - } - - return mathNode.Status.nodeChanged( - ChangeTypes.NTH_ROOT_VALUE, node, newNode, true, substeps); - } - - return mathNode.Status.noChange(node); -} - -// Given an nthRoot node with a constant positive root, will do the step of -// factoring all the multiplicands under the radicand -// e.g. nthRoot(2 * 9 * 5 * 12) = nthRoot(2 * 3 * 3 * 5 * 2 * 2 * 3) -function factorMultiplicands(node: mathjs.MathNode) { - const newNode = clone(node); - const radicandNode = getRadicandNode(node); - - let children = []; - let factored = false; - radicandNode.args.forEach(child => { - if (mathNode.PolynomialTerm.isPolynomialTerm(child)) { - const polyTerm = new mathNode.PolynomialTerm(child); - const coeffNode = polyTerm.getCoeffNode(); - const polyTermNoCoeff = mathNode.Creator.polynomialTerm( - polyTerm.getSymbolNode(), polyTerm.getExponentNode(), null); - if (coeffNode) { - const factorNodes = getFactorNodes(coeffNode); - if (factorNodes.length > 1) { - factored = true; - } - children = children.concat(factorNodes); - } - children.push(polyTermNoCoeff); - } - else { - const factorNodes = getFactorNodes(child); - if (factorNodes.length > 1) { - factored = true; - } - children = children.concat(factorNodes); - } - }); - - if (factored) { - newNode.args[0] = mathNode.Creator.operator("*", children); - return mathNode.Status.nodeChanged( - ChangeTypes.FACTOR_INTO_PRIMES, node, newNode); - } - - return mathNode.Status.noChange(node); -} - -function getFactorNodes(node: mathjs.MathNode): any { - if (mathNode.Type.isConstant(node) && !Negative.isNegative(node)) { - const value = parseFloat(node.value); - const factors = ConstantFactors.getPrimeFactors(value); - const factorNodes = factors.map(mathNode.Creator.constant); - return factorNodes; - } - return [node]; -} - -// Given an nthRoot node with a constant positive root, will group the arguments -// into groups of the root as a step -// e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2, 2) -function groupTermsByRoot(node: mathjs.MathNode) { - const newNode = clone(node); - const radicandNode = getRadicandNode(node); - const rootNode = getRootNode(node); - const rootValue = parseFloat(rootNode.value); - - radicandNode.args.sort(sortNodes); - - // We want to go through the sorted nodes, and try to find any groups of the - // same node that are the size of the root value - let children = [], hasGroups = false; - for (let i = 0; i < radicandNode.args.length;) { - let j = i; - const initialNode = radicandNode.args[i]; - while (j < radicandNode.args.length && j - i < rootValue) { - const siblingNode = radicandNode.args[j]; - if (!initialNode.equals(siblingNode)) { - break; - } - j++; - } - if (j - i === rootValue) { - hasGroups = true; - const groupedNode = mathNode.Creator.parenthesis( - mathNode.Creator.operator("*", radicandNode.args.slice(i, j))); - children.push(groupedNode); - } - else { - children = children.concat(radicandNode.args.slice(i, j)); - } - i = j; - } - - if (hasGroups) { - newNode.args[0] = children.length === 1 ? - children[0] : mathNode.Creator.operator("*", children); - return mathNode.Status.nodeChanged( - ChangeTypes.GROUP_TERMS_BY_ROOT, node, newNode); - } - // if we don't group any factors, then we can't simplify it any more - return mathNode.Status.noChange(node); -} - -// Given an nthRoot node with a constant positive root, -// will convert any grouped factors into exponent nodes as a step -// e.g. nthRoot((2 * 2) * 2, 2) -> nthRoot(2^2 * 2, 2) -function convertMultiplicationToExponent(node: mathjs.MathNode) { - const newNode = clone(node); - - const radicandNode = getRadicandNode(node); - - if (mathNode.Type.isParenthesis(radicandNode)) { - const child = radicandNode.content; - if (isMultiplicationOfEqualNodes(child)) { - const baseNode = child.args[0]; - const exponentNode = mathNode.Creator.constant(child.args.length); - newNode.args[0] = mathNode.Creator.operator("^", [baseNode, exponentNode]); - return mathNode.Status.nodeChanged( - ChangeTypes.CONVERT_MULTIPLICATION_TO_EXPONENT, node, newNode); - } - } - else if (mathNode.Type.isOperator(radicandNode, "*")) { - const children = []; - radicandNode.args.forEach(child => { - if (mathNode.Type.isParenthesis(child)) { - const grandChild = child.content; - if (isMultiplicationOfEqualNodes(grandChild)) { - const baseNode = grandChild.args[0]; - const exponentNode = mathNode.Creator.constant(grandChild.args.length); - children.push(mathNode.Creator.operator("^", [baseNode, exponentNode])); - return; - } - } - children.push(child); - }); - - newNode.args[0] = mathNode.Creator.operator("*", children); - return mathNode.Status.nodeChanged( - ChangeTypes.CONVERT_MULTIPLICATION_TO_EXPONENT, node, newNode); - } - - return mathNode.Status.noChange(node); -} - -// Given an nthRoot node with a multiplication under the radicand, will -// distribute the nthRoot to all the arguments under the radicand as a step -// e.g. nthRoot(2 * x^2, 2) -> nthRoot(2) * nthRoot(x^2) -function distributeNthRoot(node: mathjs.MathNode) { - //is this used anywhere? - let newNode = clone(node); - const radicandNode = getRadicandNode(node); - const rootNode = getRootNode(node); - - const children = []; - for (let i = 0; i < radicandNode.args.length; i++) { - const child = radicandNode.args[i]; - children.push(mathNode.Creator.nthRoot(child, rootNode)); - } - - newNode = mathNode.Creator.operator("*", children); - return mathNode.Status.nodeChanged( - ChangeTypes.DISTRIBUTE_NTH_ROOT, node, newNode); -} - -// Given a multiplication node of nthRoots (with the same root) -// will evaluate the nthRoot of each child as a substep -// e.g. nthRoot(2) * nthRoot(x^2) -> nthRoot(2) * x -function evaluateNthRootForChildren(node: mathjs.MathNode) { - const newNode = clone(node); - - const substeps = []; - for (let i = 0; i < newNode.args.length; i++) { - const child = newNode.args[i]; - const childNodeStatus = nthRoot(child); - if (childNodeStatus.hasChanged()) { - newNode.args[i] = childNodeStatus.newNode; - substeps.push(mathNode.Status.childChanged(newNode, childNodeStatus, i)); - } - } - - if (substeps.length === 0) { - return mathNode.Status.noChange(node); - } - else if (substeps.length === 1) { - return substeps[0]; - } - else { - return mathNode.Status.nodeChanged( - ChangeTypes.EVALUATE_DISTRIBUTED_NTH_ROOT, node, newNode, true, substeps); - } -} - -// Given a multiplication node, with children including nthRoots, will combine -// the nodes with the same radicand as a step -// e.g. 2 * nthRoot(2) * nthRoot(x) -> 2 * nthRoot(2 * x) -// Assumes that all the roots are the same (that this is occuring right -// after distributeNthRoot and evaluateNthRootForChildren) -function combineRoots(node: mathjs.MathNode) { - let newNode = clone(node); - - let rootNode; - const children = []; - const radicandArgs = []; - for (let i = 0; i < newNode.args.length; i++) { - const child = newNode.args[i]; - if (mathNode.Type.isFunction(child, "nthRoot")) { - radicandArgs.push(child.args[0]); - rootNode = getRootNode(child); - } - else { - children.push(child); - } - } - - if (children.length > 0) { - if (radicandArgs.length > 0) { - const radicandNode = radicandArgs.length === 1 ? - radicandArgs[0] : mathNode.Creator.operator("*", radicandArgs); - children.push(mathNode.Creator.nthRoot(radicandNode, rootNode)); - } - - newNode = mathNode.Creator.operator("*", children); - if (!newNode.equals(node)) { - return mathNode.Status.nodeChanged( - ChangeTypes.COMBINE_UNDER_ROOT, node, newNode); - } - } - - // if there are no items moved out of the root, then nothing has changed - return mathNode.Status.noChange(node); -} - -// Returns the nthRoot evaluated on a constant node -// Potentially factors the constant node into primes, and calls -// nthRootMultiplication on the new nthRoot -function nthRootConstant(node: mathjs.MathNode) { - let newNode = clone(node); - const radicandNode = getRadicandNode(node); - const rootNode = getRootNode(node); - - if (Negative.isNegative(radicandNode)) { - return mathNode.Status.noChange(node); - } - else if (!mathNode.Type.isConstant(rootNode) || Negative.isNegative(rootNode)) { - return mathNode.Status.noChange(node); - } - - const radicandValue: number = parseFloat(radicandNode.value); - const rootValue: number = parseFloat(rootNode.value); - const nthRootValue: any = math.nthRoot(radicandValue, rootValue); - // Perfect root e.g. nthRoot(4, 2) = 2 - if (nthRootValue % 1 === 0) { - newNode = mathNode.Creator.constant(nthRootValue); - return mathNode.Status.nodeChanged( - ChangeTypes.NTH_ROOT_VALUE, node, newNode); - } - // Try to find if we can simplify by finding factors that can be - // pulled out of the radical - else { - // convert the number into the product of its prime factors - const factors = ConstantFactors.getPrimeFactors(radicandValue); - if (factors.length > 1) { - let substeps = []; - const factorNodes = factors.map(mathNode.Creator.constant); - - newNode.args[0] = mathNode.Creator.operator("*", factorNodes); - substeps.push(mathNode.Status.nodeChanged( - ChangeTypes.FACTOR_INTO_PRIMES, node, newNode)); - - // run nthRoot on the new node - const nodeStatus = nthRootMultiplication(newNode); - if (nodeStatus.hasChanged()) { - substeps = substeps.concat(nodeStatus.substeps); - newNode = nodeStatus.newNode; - - return mathNode.Status.nodeChanged( - ChangeTypes.NTH_ROOT_VALUE, node, newNode, true, substeps); - } - } - } - - return mathNode.Status.noChange(node); -} - -// Helpers - -// Given an nthRoot node, will return the root node. -// The root node is the second child of the nthRoot node, but if one doesn't -// exist, we assume it's a square root and return 2. -function getRootNode(node: mathjs.MathNode) { - if (!mathNode.Type.isFunction(node, "nthRoot")) { - throw Error("Expected nthRoot"); - } - - return node.args.length === 2 ? node.args[1] : mathNode.Creator.constant(2); -} - -// Given an nthRoot node, will return the radicand node. -function getRadicandNode(node: mathjs.MathNode) { - if (!mathNode.Type.isFunction(node, "nthRoot")) { - throw Error("Expected nthRoot"); - } - - return node.args[0]; -} - -// Sorts nodes, ordering constants nodes from smallest to largest and symbol -// nodes after -function sortNodes(a: mathjs.MathNode, b: mathjs.MathNode) { - if (mathNode.Type.isConstant(a) && mathNode.Type.isConstant(b)) { - return parseFloat(a.value) - parseFloat(b.value); - } - else if (mathNode.Type.isConstant(a)) { - return -1; - } - else if (mathNode.Type.isConstant(b)) { - return 1; - } - return 0; -} - -// Simple helper function which determines a node is a multiplication node -// of all equal nodes -function isMultiplicationOfEqualNodes(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return false; - } - - // return if they are all equal nodes - return node.args.reduce((a, b) => { - return a.equals(b); - }); - -} - -export = nthRoot; diff --git a/lib/simplifyExpression/index.js b/lib/simplifyExpression/index.js deleted file mode 100644 index 32d58611..00000000 --- a/lib/simplifyExpression/index.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -var math = require("mathjs"); -var stepThrough = require("./stepThrough"); -function simplifyExpressionString(expressionString, debug) { - if (debug === void 0) { debug = false; } - var exprNode; - try { - exprNode = math.parse(expressionString); - } - catch (err) { - return []; - } - if (exprNode) { - return stepThrough(exprNode, debug); - } - return []; -} -module.exports = simplifyExpressionString; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/index.js.map b/lib/simplifyExpression/index.js.map deleted file mode 100644 index c6f6837c..00000000 --- a/lib/simplifyExpression/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,2CAA8C;AAE9C,kCAAkC,gBAAgB,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IAC7D,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC1C,CAAC;IACD,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACX,MAAM,CAAC,EAAE,CAAC;IACZ,CAAC;IACD,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACb,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,CAAC,EAAE,CAAC;AACZ,CAAC;AAED,iBAAS,wBAAwB,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/index.ts b/lib/simplifyExpression/index.ts deleted file mode 100644 index d5b586a4..00000000 --- a/lib/simplifyExpression/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import math = require("mathjs"); -import stepThrough = require("./stepThrough"); - -function simplifyExpressionString(expressionString, debug=false) { - let exprNode; - try { - exprNode = math.parse(expressionString); - } - catch (err) { - return []; - } - if (exprNode) { - return stepThrough(exprNode, debug); - } - return []; -} - -export = simplifyExpressionString; diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js b/lib/simplifyExpression/multiplyFractionsSearch/index.js deleted file mode 100644 index 4924acca..00000000 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.js +++ /dev/null @@ -1,48 +0,0 @@ -"use strict"; -var ChangeTypes = require("../../ChangeTypes"); -var mathNode = require("../../mathnode"); -var TreeSearch = require("../../TreeSearch"); -// If `node` is a product of terms where some are fractions (but none are -// polynomial terms), multiplies them together. -// e.g. 2 * 5/x -> (2*5)/x -// e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) -// TODO: add a step somewhere to remove common terms in numerator and -// denominator (so the 5s would cancel out on the next step after this) -// This step must happen after things have been distributed, or else the answer -// will be formatted badly, so it's a tree search of its own. -// Returns a mathNode.Status object. -var search = TreeSearch.postOrder(multiplyFractions); -// If `node` is a product of terms where some are fractions (but none are -// polynomial terms), multiplies them together. -// e.g. 2 * 5/x -> (2*5)/x -// e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) -// Returns a mathNode.Status object. -function multiplyFractions(node) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return mathNode.Status.noChange(node); - } - var atLeastOneFraction = node.args.some(function (arg) { return mathNode.Type.isOperator(arg, "/"); }); - var hasPolynomialTerms = node.args.some(function (arg) { return mathNode.PolynomialTerm.isPolynomialTerm(arg); }); - if (!atLeastOneFraction || hasPolynomialTerms) { - return mathNode.Status.noChange(node); - } - var numeratorArgs = []; - var denominatorArgs = []; - node.args.forEach(function (operand) { - if (mathNode.Type.isOperator(operand, "/")) { - numeratorArgs.push(operand.args[0]); - denominatorArgs.push(operand.args[1]); - } - else { - numeratorArgs.push(operand); - } - }); - var newNumerator = mathNode.Creator.parenthesis(mathNode.Creator.operator("*", numeratorArgs)); - var newDenominator = denominatorArgs.length === 1 - ? denominatorArgs[0] - : mathNode.Creator.parenthesis(mathNode.Creator.operator("*", denominatorArgs)); - var newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); - return mathNode.Status.nodeChanged(ChangeTypes.MULTIPLY_FRACTIONS, node, newNode); -} -module.exports = search; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.js.map b/lib/simplifyExpression/multiplyFractionsSearch/index.js.map deleted file mode 100644 index 477a5727..00000000 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+CAAkD;AAClD,yCAA4C;AAC5C,6CAAgD;AAEhD,yEAAyE;AACzE,+CAA+C;AAC/C,0BAA0B;AAC1B,qCAAqC;AACrC,qEAAqE;AACrE,uEAAuE;AACvE,+EAA+E;AAC/E,6DAA6D;AAC7D,oCAAoC;AACpC,IAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;AAEvD,yEAAyE;AACzE,+CAA+C;AAC/C,0BAA0B;AAC1B,qCAAqC;AACrC,oCAAoC;AACpC,2BAA2B,IAAqB;IAC9C,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAlC,CAAkC,CAAC,CAAC;IAC7C,IAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACvC,UAAA,GAAG,IAAI,OAAA,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAA7C,CAA6C,CAAC,CAAC;IACxD,EAAE,CAAC,CAAC,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAM,aAAa,GAAG,EAAE,CAAC;IACzB,IAAM,eAAe,GAAG,EAAE,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAA,OAAO;QACvB,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,CAAC;YACJ,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAC/C,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC;IACjD,IAAM,cAAc,GAAG,eAAe,CAAC,MAAM,KAAK,CAAC;UAC/C,eAAe,CAAC,CAAC,CAAC;UAClB,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;IAElF,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IAC/E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAChC,WAAW,CAAC,kBAAkB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,iBAAS,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/multiplyFractionsSearch/index.ts b/lib/simplifyExpression/multiplyFractionsSearch/index.ts deleted file mode 100644 index 22feff3c..00000000 --- a/lib/simplifyExpression/multiplyFractionsSearch/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import ChangeTypes = require("../../ChangeTypes"); -import mathNode = require("../../mathnode"); -import TreeSearch = require("../../TreeSearch"); - -// If `node` is a product of terms where some are fractions (but none are -// polynomial terms), multiplies them together. -// e.g. 2 * 5/x -> (2*5)/x -// e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) -// TODO: add a step somewhere to remove common terms in numerator and -// denominator (so the 5s would cancel out on the next step after this) -// This step must happen after things have been distributed, or else the answer -// will be formatted badly, so it's a tree search of its own. -// Returns a mathNode.Status object. -const search = TreeSearch.postOrder(multiplyFractions); - -// If `node` is a product of terms where some are fractions (but none are -// polynomial terms), multiplies them together. -// e.g. 2 * 5/x -> (2*5)/x -// e.g. 3 * 1/5 * 5/9 = (3*1*5)/(5*9) -// Returns a mathNode.Status object. -function multiplyFractions(node: mathjs.MathNode) { - if (!mathNode.Type.isOperator(node) || node.op !== "*") { - return mathNode.Status.noChange(node); - } - const atLeastOneFraction = node.args.some( - arg => mathNode.Type.isOperator(arg, "/")); - const hasPolynomialTerms = node.args.some( - arg => mathNode.PolynomialTerm.isPolynomialTerm(arg)); - if (!atLeastOneFraction || hasPolynomialTerms) { - return mathNode.Status.noChange(node); - } - - const numeratorArgs = []; - const denominatorArgs = []; - node.args.forEach(operand => { - if (mathNode.Type.isOperator(operand, "/")) { - numeratorArgs.push(operand.args[0]); - denominatorArgs.push(operand.args[1]); - } - else { - numeratorArgs.push(operand); - } - }); - - const newNumerator = mathNode.Creator.parenthesis( - mathNode.Creator.operator("*", numeratorArgs)); - const newDenominator = denominatorArgs.length === 1 - ? denominatorArgs[0] - : mathNode.Creator.parenthesis(mathNode.Creator.operator("*", denominatorArgs)); - - const newNode = mathNode.Creator.operator("/", [newNumerator, newDenominator]); - return mathNode.Status.nodeChanged( - ChangeTypes.MULTIPLY_FRACTIONS, node, newNode); -} - -export = search; diff --git a/lib/simplifyExpression/simplify.js b/lib/simplifyExpression/simplify.js deleted file mode 100644 index 67440b6b..00000000 --- a/lib/simplifyExpression/simplify.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -var math = require("mathjs"); -var checks = require("../checks"); -var flattenOperands = require("../util/flattenOperands"); -var print = require("../util/print"); -var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); -var stepThrough = require("./stepThrough"); -// Given a mathjs expression node, steps through simplifying the expression. -// Returns the simplified expression node. -function simplify(node, debug) { - if (debug === void 0) { debug = false; } - if (checks.hasUnsupportedNodes(node)) { - return node; - } - var steps = stepThrough(node, debug); - var simplifiedNode; - if (steps.length > 0) { - simplifiedNode = steps.pop().newNode; - } - else { - // removing parens isn't counted as a step, so try it here - simplifiedNode = removeUnnecessaryParens(flattenOperands(node), true); - } - // unflatten the node. - return unflatten(simplifiedNode); -} -// Unflattens a node so it is in the math.js style, by printing and parsing it -// again -function unflatten(node) { - return math.parse(print(node)); -} -module.exports = simplify; -//# sourceMappingURL=simplify.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/simplify.js.map b/lib/simplifyExpression/simplify.js.map deleted file mode 100644 index 64c6227f..00000000 --- a/lib/simplifyExpression/simplify.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"simplify.js","sourceRoot":"","sources":["simplify.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,kCAAqC;AACrC,yDAA4D;AAC5D,qCAAwC;AACxC,yEAA4E;AAC5E,2CAA8C;AAG9C,4EAA4E;AAC5E,0CAA0C;AAC1C,kBAAkB,IAAqB,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IAClD,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IAED,IAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvC,IAAI,cAAc,CAAC;IACnB,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,cAAc,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;IACvC,CAAC;IACD,IAAI,CAAC,CAAC;QACJ,0DAA0D;QAC1D,cAAc,GAAG,uBAAuB,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;IACD,sBAAsB;IACtB,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AACnC,CAAC;AAED,8EAA8E;AAC9E,QAAQ;AACR,mBAAmB,IAAqB;IACtC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/simplifyExpression/simplify.ts b/lib/simplifyExpression/simplify.ts deleted file mode 100644 index cbcc3360..00000000 --- a/lib/simplifyExpression/simplify.ts +++ /dev/null @@ -1,35 +0,0 @@ -import math = require("mathjs"); -import checks = require("../checks"); -import flattenOperands = require("../util/flattenOperands"); -import print = require("../util/print"); -import removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); -import stepThrough = require("./stepThrough"); - - -// Given a mathjs expression node, steps through simplifying the expression. -// Returns the simplified expression node. -function simplify(node: mathjs.MathNode, debug=false) { - if (checks.hasUnsupportedNodes(node)) { - return node; - } - - const steps = stepThrough(node, debug); - let simplifiedNode; - if (steps.length > 0) { - simplifiedNode = steps.pop().newNode; - } - else { - // removing parens isn't counted as a step, so try it here - simplifiedNode = removeUnnecessaryParens(flattenOperands(node), true); - } - // unflatten the node. - return unflatten(simplifiedNode); -} - -// Unflattens a node so it is in the math.js style, by printing and parsing it -// again -function unflatten(node: mathjs.MathNode) { - return math.parse(print(node)); -} - -export = simplify; diff --git a/lib/simplifyExpression/stepThrough.js b/lib/simplifyExpression/stepThrough.js deleted file mode 100644 index 93396eaf..00000000 --- a/lib/simplifyExpression/stepThrough.js +++ /dev/null @@ -1,120 +0,0 @@ -"use strict"; -var checks = require("../checks"); -var mathNode = require("../mathNode"); -var Status = require("../mathnode/Status"); -var arithmeticSearch = require("./arithmeticSearch"); -var basicsSearch = require("./basicsSearch"); -var breakUpNumeratorSearch = require("./breakUpNumeratorSearch"); -var collectAndCombineSearch = require("./collectAndCombineSearch"); -var distributeSearch = require("./distributeSearch"); -var divisionSearch = require("./divisionSearch"); -var fractionsSearch = require("./fractionsSearch"); -var functionsSearch = require("./functionsSearch"); -var multiplyFractionsSearch = require("./multiplyFractionsSearch"); -var clone = require("../util/clone"); -var flattenOperands = require("../util/flattenOperands"); -var print = require("../util/print"); -var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); -// Given a mathjs expression node, steps through simplifying the expression. -// Returns a list of details about each step. -function stepThrough(node, debug) { - if (debug === void 0) { debug = false; } - if (debug) { - // eslint-disable-next-line - // again, unsure whether or not there should be a ternary argument - console.log("\n\nSimplifying: " + print(node, false)); - } - if (checks.hasUnsupportedNodes(node)) { - return []; - } - var nodeStatus; - var steps = []; - var originalExpressionStr = print(node); - var maxStepCount = 20; - var iters = 0; - // Now, step through the math expression until nothing changes - nodeStatus = step(node); - while (nodeStatus.hasChanged()) { - if (debug) { - logSteps(nodeStatus); - } - steps.push(removeUnnecessaryParensInStep(nodeStatus)); - var nextNode = Status.resetChangeGroups(nodeStatus.newNode); - nodeStatus = step(nextNode); - if (iters++ === maxStepCount) { - // eslint-disable-next-line - console.error("Math error: Potential infinite loop for expression: " + - originalExpressionStr + ", returning no steps"); - return []; - } - } - return steps; -} -// Given a mathjs expression node, performs a single step to simplify the -// expression. Returns a mathNode.Status object. -function step(node) { - var nodeStatus; - node = flattenOperands(node); - node = removeUnnecessaryParens(node, true); - var simplificationTreeSearches = [ - // Basic simplifications that we always try first e.g. (...)^0 => 1 - basicsSearch, - // Simplify any division chains so there's at most one division operation. - // e.g. 2/x/6 -> 2/(x*6) e.g. 2/(x/6) => 2 * 6/x - divisionSearch, - // Adding fractions, cancelling out things in fractions - fractionsSearch, - // e.g. 2 + 2 => 4 - arithmeticSearch, - // e.g. addition: 2x + 4x^2 + x => 4x^2 + 3x - // e.g. multiplication: 2x * x * x^2 => 2x^3 - collectAndCombineSearch, - // e.g. (2 + x) / 4 => 2/4 + x/4 - breakUpNumeratorSearch, - // e.g. 3/x * 2x/5 => (3 * 2x) / (x * 5) - multiplyFractionsSearch, - // e.g. (2x + 3)(x + 4) => 2x^2 + 11x + 12 - distributeSearch, - // e.g. abs(-4) => 4 - functionsSearch, - ]; - for (var i = 0; i < simplificationTreeSearches.length; i++) { - nodeStatus = simplificationTreeSearches[i](node); - // Always update node, since there might be changes that didn't count as - // a step. Remove unnecessary parens, in case one a step results in more - // parens than needed. - node = removeUnnecessaryParens(nodeStatus.newNode, true); - if (nodeStatus.hasChanged()) { - node = flattenOperands(node); - nodeStatus.newNode = clone(node); - return nodeStatus; - } - else { - node = flattenOperands(node); - } - } - return mathNode.Status.noChange(node); -} -// Removes unnecessary parens throughout the steps. -// TODO: Ideally this would happen in NodeStatus instead. -function removeUnnecessaryParensInStep(nodeStatus) { - if (nodeStatus.substeps.length > 0) { - nodeStatus.substeps.map(removeUnnecessaryParensInStep); - } - nodeStatus.oldNode = removeUnnecessaryParens(nodeStatus.oldNode, true); - nodeStatus.newNode = removeUnnecessaryParens(nodeStatus.newNode, true); - return nodeStatus; -} -function logSteps(nodeStatus) { - // eslint-disable-next-line - console.log(nodeStatus.changeType); - // eslint-disable-next-line - console.log(print(nodeStatus.newNode) + "\n"); - if (nodeStatus.substeps.length > 0) { - // eslint-disable-next-line - console.log("\nsubsteps: "); - nodeStatus.substeps.forEach(function (substep) { return substep; }); - } -} -module.exports = stepThrough; -//# sourceMappingURL=stepThrough.js.map \ No newline at end of file diff --git a/lib/simplifyExpression/stepThrough.js.map b/lib/simplifyExpression/stepThrough.js.map deleted file mode 100644 index 34358d2f..00000000 --- a/lib/simplifyExpression/stepThrough.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/simplifyExpression/stepThrough.ts b/lib/simplifyExpression/stepThrough.ts deleted file mode 100644 index f8b9f1e4..00000000 --- a/lib/simplifyExpression/stepThrough.ts +++ /dev/null @@ -1,132 +0,0 @@ -import checks = require("../checks"); -import mathNode = require("../mathNode"); -import Status = require("../mathnode/Status"); -import arithmeticSearch = require("./arithmeticSearch"); -import basicsSearch = require("./basicsSearch"); -import breakUpNumeratorSearch = require("./breakUpNumeratorSearch"); -import collectAndCombineSearch = require("./collectAndCombineSearch"); -import distributeSearch = require("./distributeSearch"); -import divisionSearch = require("./divisionSearch"); -import fractionsSearch = require("./fractionsSearch"); -import functionsSearch = require("./functionsSearch"); -import multiplyFractionsSearch = require("./multiplyFractionsSearch"); -import clone = require("../util/clone"); -import flattenOperands = require("../util/flattenOperands"); -import print = require("../util/print"); -import removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); - -// Given a mathjs expression node, steps through simplifying the expression. -// Returns a list of details about each step. -function stepThrough(node: mathjs.MathNode, debug=false) { - if (debug) { - // eslint-disable-next-line - // again, unsure whether or not there should be a ternary argument - console.log("\n\nSimplifying: " + print(node, false)); - } - - if (checks.hasUnsupportedNodes(node)) { - return []; - } - - let nodeStatus; - const steps = []; - - const originalExpressionStr = print(node); - const maxStepCount = 20; - let iters = 0; - - // Now, step through the math expression until nothing changes - nodeStatus = step(node); - while (nodeStatus.hasChanged()) { - if (debug) { - logSteps(nodeStatus); - } - steps.push(removeUnnecessaryParensInStep(nodeStatus)); - const nextNode = Status.resetChangeGroups(nodeStatus.newNode); - nodeStatus = step(nextNode); - if (iters++ === maxStepCount) { - // eslint-disable-next-line - console.error("Math error: Potential infinite loop for expression: " + - originalExpressionStr + ", returning no steps"); - return []; - } - } - - return steps; -} - -// Given a mathjs expression node, performs a single step to simplify the -// expression. Returns a mathNode.Status object. -function step(node: mathjs.MathNode) { - let nodeStatus; - - node = flattenOperands(node); - node = removeUnnecessaryParens(node, true); - - const simplificationTreeSearches = [ - // Basic simplifications that we always try first e.g. (...)^0 => 1 - basicsSearch, - // Simplify any division chains so there's at most one division operation. - // e.g. 2/x/6 -> 2/(x*6) e.g. 2/(x/6) => 2 * 6/x - divisionSearch, - // Adding fractions, cancelling out things in fractions - fractionsSearch, - // e.g. 2 + 2 => 4 - arithmeticSearch, - // e.g. addition: 2x + 4x^2 + x => 4x^2 + 3x - // e.g. multiplication: 2x * x * x^2 => 2x^3 - collectAndCombineSearch, - // e.g. (2 + x) / 4 => 2/4 + x/4 - breakUpNumeratorSearch, - // e.g. 3/x * 2x/5 => (3 * 2x) / (x * 5) - multiplyFractionsSearch, - // e.g. (2x + 3)(x + 4) => 2x^2 + 11x + 12 - distributeSearch, - // e.g. abs(-4) => 4 - functionsSearch, - ]; - - for (let i = 0; i < simplificationTreeSearches.length; i++) { - nodeStatus = simplificationTreeSearches[i](node); - // Always update node, since there might be changes that didn't count as - // a step. Remove unnecessary parens, in case one a step results in more - // parens than needed. - node = removeUnnecessaryParens(nodeStatus.newNode, true); - if (nodeStatus.hasChanged()) { - node = flattenOperands(node); - nodeStatus.newNode = clone(node); - return nodeStatus; - } - else { - node = flattenOperands(node); - } - } - return mathNode.Status.noChange(node); -} - -// Removes unnecessary parens throughout the steps. -// TODO: Ideally this would happen in NodeStatus instead. -function removeUnnecessaryParensInStep(nodeStatus) { - if (nodeStatus.substeps.length > 0) { - nodeStatus.substeps.map(removeUnnecessaryParensInStep); - } - - nodeStatus.oldNode = removeUnnecessaryParens(nodeStatus.oldNode, true); - nodeStatus.newNode = removeUnnecessaryParens(nodeStatus.newNode, true); - return nodeStatus; -} - -function logSteps(nodeStatus) { - // eslint-disable-next-line - console.log(nodeStatus.changeType); - // eslint-disable-next-line - console.log(print(nodeStatus.newNode) + "\n"); - - if (nodeStatus.substeps.length > 0) { - // eslint-disable-next-line - console.log("\nsubsteps: "); - nodeStatus.substeps.forEach(substep => substep); - } -} - -export = stepThrough; diff --git a/lib/solveEquation/EquationOperations.js b/lib/solveEquation/EquationOperations.js deleted file mode 100644 index 882ff1f8..00000000 --- a/lib/solveEquation/EquationOperations.js +++ /dev/null @@ -1,202 +0,0 @@ -// Operations on equation nodes -"use strict"; -var ChangeTypes = require("../ChangeTypes"); -var clone = require("../util/clone"); -var Equation = require("../equation/Equation"); -var EquationStatus = require("../equation/Status"); -var Negative = require("../Negative"); -var mathNode = require("../mathNode"); -var Symbols = require("../Symbols"); -var comparatorToInverse = { - '>': "<", - '>=': "<=", - '<': ">", - '<=': ">=", - '=': "=" -}; -var EquationOperations = (function () { - function EquationOperations() { - } - return EquationOperations; -}()); -// Ensures that the given equation has the given symbolName on the left side, -// by swapping the right and left sides if it is only in the right side. -// So 3 = x would become x = 3. -EquationOperations.ensureSymbolInLeftNode = function (equation, symbolName) { - var leftSideSymbolTerm = Symbols.getLastSymbolTerm(equation.leftNode, symbolName); - var rightSideSymbolTerm = Symbols.getLastSymbolTerm(equation.rightNode, symbolName); - if (!leftSideSymbolTerm) { - if (rightSideSymbolTerm) { - var comparator = comparatorToInverse[equation.comparator]; - var oldEquation = equation; - var newEquation = new Equation(equation.rightNode, equation.leftNode, comparator); - // no change groups are set for this step because everything changes, so - // they wouldn't be pedagogically helpful. - return new EquationStatus(ChangeTypes.SWAP_SIDES, oldEquation, newEquation); - } - else { - throw Error("No term with symbol: " + symbolName); - } - } - return EquationStatus.noChange(equation); -}; -// TODO: Ensures that a symbol is not in the denominator by multiplying -// both sides by the whatever order of the symbol necessary. -// This is blocked on the simplifying functionality of canceling symbols in -// fractions (needs factoring for full canceling support) -EquationOperations.removeSymbolFromDenominator = function (equation) { return EquationStatus.noChange(equation); }; -// Removes the given symbolName from the right side by adding or subtracting -// it from both sides as appropriate. -// e.g. 2x = 3x + 5 --> 2x - 3x = 5 -// There are actually no cases where we'd remove symbols from the right side -// by multiplying or dividing by a symbol term. -// TODO: support inverting functions e.g. sqrt, ^, log etc. -EquationOperations.removeSymbolFromRightSide = function (equation, symbolName) { - var rightNode = equation.rightNode; - var symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); - var inverseOp, inverseTerm, changeType; - if (!symbolTerm) { - return EquationStatus.noChange(equation); - } - // Clone it so that any operations on it don't affect the node already - // in the equation - symbolTerm = clone(symbolTerm); - if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { - if (Negative.isNegative(symbolTerm)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } - else { - inverseOp = "-"; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } - else if (mathNode.Type.isOperator(rightNode)) { - if (rightNode.op === "+") { - if (Negative.isNegative(symbolTerm)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } - else { - inverseOp = "-"; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } - else { - // Note that operator '-' won't show up here because subtraction is - // flattened into adding the negative. See 'TRICKY catch' in the README - // for more details. - throw Error("Unsupported operation: " + symbolTerm.op); - } - } - else if (mathNode.Type.isUnaryMinus(rightNode)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = symbolTerm.args[0]; - } - else { - throw Error("Unsupported node type: " + rightNode.type); - } - return performTermOperationOnEquation(equation, inverseOp, inverseTerm, changeType); -}; -// Isolates the given symbolName to the left side by adding, multiplying, subtracting -// or dividing all other symbols and constants from both sides appropriately -// TODO: support inverting functions e.g. sqrt, ^, log etc. -EquationOperations.isolateSymbolOnLeftSide = function (equation, symbolName) { - var leftNode = equation.leftNode; - var nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); - var inverseOp, inverseTerm, changeType; - if (!nonSymbolTerm) { - return EquationStatus.noChange(equation); - } - // Clone it so that any operations on it don't affect the node already - // in the equation - nonSymbolTerm = clone(nonSymbolTerm); - if (mathNode.Type.isOperator(leftNode)) { - if (leftNode.op === "+") { - if (Negative.isNegative(nonSymbolTerm)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(nonSymbolTerm); - } - else { - inverseOp = "-"; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } - else if (leftNode.op === "*") { - if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator("/", [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - else { - inverseOp = "/"; - changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } - else if (leftNode.op === "/") { - // The non symbol term is always a fraction because it's the - // coefficient of our symbol term. - // If the numerator is 1, we multiply both sides by the denominator, - // otherwise we multiply by the inverse - if (["1", "-1"].indexOf(nonSymbolTerm.args[0].value) !== -1) { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; - inverseTerm = nonSymbolTerm.args[1]; - } - else { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator("/", [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - } - else if (leftNode.op === "^") { - // TODO: support roots - return EquationStatus.noChange(equation); - } - else { - throw Error("Unsupported operation: " + leftNode.op); - } - } - else if (mathNode.Type.isUnaryMinus(leftNode)) { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; - inverseTerm = mathNode.Creator.constant(-1); - } - else { - throw Error("Unsupported node type: " + leftNode.type); - } - return performTermOperationOnEquation(equation, inverseOp, inverseTerm, changeType); -}; -// Modifies the left and right sides of an equation by `op`-ing `term` -// to both sides. Returns an Status object. -function performTermOperationOnEquation(equation, op, term, changeType) { - var oldEquation = equation.clone(); - var leftTerm = clone(term); - var rightTerm = clone(term); - var leftNode = performTermOperationOnExpression(equation.leftNode, op, leftTerm); - var rightNode = performTermOperationOnExpression(equation.rightNode, op, rightTerm); - var comparator = equation.comparator; - if (Negative.isNegative(term) && (op === "*" || op === "/")) { - comparator = comparatorToInverse[comparator]; - } - var newEquation = new Equation(leftNode, rightNode, comparator); - return new EquationStatus(changeType, oldEquation, newEquation); -} -// Performs an operation of a term on an entire given expression -function performTermOperationOnExpression(expression, op, term) { - var node = (mathNode.Type.isOperator(expression) ? - mathNode.Creator.parenthesis(expression) : expression); - term.changeGroup = 1; - var newNode = mathNode.Creator.operator(op, [node, term]); - return newNode; -} -module.exports = EquationOperations; -//# sourceMappingURL=EquationOperations.js.map \ No newline at end of file diff --git a/lib/solveEquation/EquationOperations.js.map b/lib/solveEquation/EquationOperations.js.map deleted file mode 100644 index 22ea3649..00000000 --- a/lib/solveEquation/EquationOperations.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"EquationOperations.js","sourceRoot":"","sources":["EquationOperations.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/solveEquation/EquationOperations.ts b/lib/solveEquation/EquationOperations.ts deleted file mode 100644 index a4acbd44..00000000 --- a/lib/solveEquation/EquationOperations.ts +++ /dev/null @@ -1,227 +0,0 @@ -// Operations on equation nodes - -import ChangeTypes = require("../ChangeTypes"); -import clone = require("../util/clone"); -import Equation = require("../equation/Equation"); -import EquationStatus = require("../equation/Status"); -import Negative = require("../Negative"); -import mathNode = require("../mathNode"); -import Symbols = require("../Symbols"); -const comparatorToInverse = { - '>': "<", - '>=': "<=", - '<': ">", - '<=': ">=", - '=': "=" -}; - -class EquationOperations { - -// Ensures that the given equation has the given symbolName on the left side, -// by swapping the right and left sides if it is only in the right side. -// So 3 = x would become x = 3. - static ensureSymbolInLeftNode = (equation, symbolName) => { - const leftSideSymbolTerm = Symbols.getLastSymbolTerm( - equation.leftNode, - symbolName); - const rightSideSymbolTerm = Symbols.getLastSymbolTerm( - equation.rightNode, - symbolName); - - if (!leftSideSymbolTerm) { - if (rightSideSymbolTerm) { - const comparator = comparatorToInverse[equation.comparator]; - const oldEquation = equation; - const newEquation = new Equation( - equation.rightNode, - equation.leftNode, - comparator); - // no change groups are set for this step because everything changes, so - // they wouldn't be pedagogically helpful. - return new EquationStatus( - ChangeTypes.SWAP_SIDES, - oldEquation, - newEquation); - } else { - throw Error("No term with symbol: " + symbolName); - } - } - return EquationStatus.noChange(equation); - }; - -// TODO: Ensures that a symbol is not in the denominator by multiplying -// both sides by the whatever order of the symbol necessary. -// This is blocked on the simplifying functionality of canceling symbols in -// fractions (needs factoring for full canceling support) - static removeSymbolFromDenominator = equation => EquationStatus.noChange(equation); - -// Removes the given symbolName from the right side by adding or subtracting -// it from both sides as appropriate. -// e.g. 2x = 3x + 5 --> 2x - 3x = 5 -// There are actually no cases where we'd remove symbols from the right side -// by multiplying or dividing by a symbol term. -// TODO: support inverting functions e.g. sqrt, ^, log etc. - static removeSymbolFromRightSide = (equation: Equation, symbolName) => { - const rightNode = equation.rightNode; - let symbolTerm = Symbols.getLastSymbolTerm(rightNode, symbolName); - - let inverseOp, inverseTerm, changeType; - if (!symbolTerm) { - return EquationStatus.noChange(equation); - } - - // Clone it so that any operations on it don't affect the node already - // in the equation - symbolTerm = clone(symbolTerm); - - if (mathNode.PolynomialTerm.isPolynomialTerm(rightNode)) { - if (Negative.isNegative(symbolTerm)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } else { - inverseOp = "-"; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } else if (mathNode.Type.isOperator(rightNode)) { - if (rightNode.op === "+") { - if (Negative.isNegative(symbolTerm)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(symbolTerm); - } else { - inverseOp = "-"; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = symbolTerm; - } - } else { - // Note that operator '-' won't show up here because subtraction is - // flattened into adding the negative. See 'TRICKY catch' in the README - // for more details. - throw Error("Unsupported operation: " + symbolTerm.op); - } - } else if (mathNode.Type.isUnaryMinus(rightNode)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = symbolTerm.args[0]; - } else { - throw Error("Unsupported node type: " + rightNode.type); - } - return performTermOperationOnEquation( - equation, - inverseOp, - inverseTerm, - changeType); - }; - -// Isolates the given symbolName to the left side by adding, multiplying, subtracting -// or dividing all other symbols and constants from both sides appropriately -// TODO: support inverting functions e.g. sqrt, ^, log etc. - static isolateSymbolOnLeftSide = (equation: Equation, symbolName) => { - const leftNode = equation.leftNode; - let nonSymbolTerm = Symbols.getLastNonSymbolTerm(leftNode, symbolName); - - let inverseOp, inverseTerm, changeType; - if (!nonSymbolTerm) { - return EquationStatus.noChange(equation); - } - - // Clone it so that any operations on it don't affect the node already - // in the equation - nonSymbolTerm = clone(nonSymbolTerm); - - if (mathNode.Type.isOperator(leftNode)) { - if (leftNode.op === "+") { - if (Negative.isNegative(nonSymbolTerm)) { - inverseOp = "+"; - changeType = ChangeTypes.ADD_TO_BOTH_SIDES; - inverseTerm = Negative.negate(nonSymbolTerm); - } else { - inverseOp = "-"; - changeType = ChangeTypes.SUBTRACT_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } else if (leftNode.op === "*") { - if (mathNode.Type.isConstantFraction(nonSymbolTerm)) { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator( - "/", - [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } else { - inverseOp = "/"; - changeType = ChangeTypes.DIVIDE_FROM_BOTH_SIDES; - inverseTerm = nonSymbolTerm; - } - } else if (leftNode.op === "/") { - // The non symbol term is always a fraction because it's the - // coefficient of our symbol term. - // If the numerator is 1, we multiply both sides by the denominator, - // otherwise we multiply by the inverse - if (["1", "-1"].indexOf(nonSymbolTerm.args[0].value) !== -1) { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_TO_BOTH_SIDES; - inverseTerm = nonSymbolTerm.args[1]; - } else { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION; - inverseTerm = mathNode.Creator.operator( - "/", - [nonSymbolTerm.args[1], nonSymbolTerm.args[0]]); - } - } else if (leftNode.op === "^") { - // TODO: support roots - return EquationStatus.noChange(equation); - } else { - throw Error("Unsupported operation: " + leftNode.op); - } - } else if (mathNode.Type.isUnaryMinus(leftNode)) { - inverseOp = "*"; - changeType = ChangeTypes.MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE; - inverseTerm = mathNode.Creator.constant(-1); - } else { - throw Error("Unsupported node type: " + leftNode.type); - } - - return performTermOperationOnEquation( - equation, - inverseOp, - inverseTerm, - changeType); - }; -} - -// Modifies the left and right sides of an equation by `op`-ing `term` -// to both sides. Returns an Status object. -function performTermOperationOnEquation(equation: Equation, op, term, changeType) { - const oldEquation = equation.clone(); - - const leftTerm = clone(term); - const rightTerm = clone(term); - const leftNode = performTermOperationOnExpression( - equation.leftNode, op, leftTerm); - const rightNode = performTermOperationOnExpression( - equation.rightNode, op, rightTerm); - - let comparator = equation.comparator; - if (Negative.isNegative(term) && (op === "*" || op === "/")) { - comparator = comparatorToInverse[comparator]; - } - - const newEquation = new Equation(leftNode, rightNode, comparator); - return new EquationStatus(changeType, oldEquation, newEquation); -} - -// Performs an operation of a term on an entire given expression -function performTermOperationOnExpression(expression, op, term) { - const node = (mathNode.Type.isOperator(expression) ? - mathNode.Creator.parenthesis(expression) : expression); - - term.changeGroup = 1; - const newNode = mathNode.Creator.operator(op, [node, term]); - - return newNode; -} - -export = EquationOperations; diff --git a/lib/solveEquation/index.js b/lib/solveEquation/index.js deleted file mode 100644 index 782a38ed..00000000 --- a/lib/solveEquation/index.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -var math = require("mathjs"); -var stepThrough = require("./stepThrough"); -function solveEquationString(equationString, debug) { - if (debug === void 0) { debug = false; } - var comparators = ["<=", ">=", "=", "<", ">"]; - for (var i = 0; i < comparators.length; i++) { - var comparator = comparators[i]; - var sides = equationString.split(comparator); - if (sides.length !== 2) { - continue; - } - var leftNode = void 0, rightNode = void 0; - var leftSide = sides[0].trim(); - var rightSide = sides[1].trim(); - if (!leftSide || !rightSide) { - return []; - } - try { - leftNode = math.parse(leftSide); - rightNode = math.parse(rightSide); - } - catch (err) { - return []; - } - if (leftNode && rightNode) { - return stepThrough(leftNode, rightNode, comparator, debug); - } - } - return []; -} -module.exports = solveEquationString; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/solveEquation/index.js.map b/lib/solveEquation/index.js.map deleted file mode 100644 index 724dec0a..00000000 --- a/lib/solveEquation/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,6BAAgC;AAChC,2CAA8C;AAE9C,6BAA6B,cAAc,EAAE,KAAW;IAAX,sBAAA,EAAA,aAAW;IACtD,IAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAEhD,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAClC,IAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/C,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,QAAQ,CAAC;QACX,CAAC;QACD,IAAI,QAAQ,SAAA,EAAE,SAAS,SAAA,CAAC;QACxB,IAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjC,IAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAElC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAChC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACX,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC;QACD,EAAE,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC;YAC1B,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,CAAC,EAAE,CAAC;AACZ,CAAC;AAED,iBAAS,mBAAmB,CAAC"} \ No newline at end of file diff --git a/lib/solveEquation/index.ts b/lib/solveEquation/index.ts deleted file mode 100644 index a81a0b7a..00000000 --- a/lib/solveEquation/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import math = require("mathjs"); -import stepThrough = require("./stepThrough"); - -function solveEquationString(equationString, debug=false) { - const comparators = ["<=", ">=", "=", "<", ">"]; - - for (let i = 0; i < comparators.length; i++) { - const comparator = comparators[i]; - const sides = equationString.split(comparator); - if (sides.length !== 2) { - continue; - } - let leftNode, rightNode; - const leftSide = sides[0].trim(); - const rightSide = sides[1].trim(); - - if (!leftSide || !rightSide) { - return []; - } - - try { - leftNode = math.parse(leftSide); - rightNode = math.parse(rightSide); - } - catch (err) { - return []; - } - if (leftNode && rightNode) { - return stepThrough(leftNode, rightNode, comparator, debug); - } - } - - return []; -} - -export = solveEquationString; diff --git a/lib/solveEquation/stepThrough.js b/lib/solveEquation/stepThrough.js deleted file mode 100644 index da916e86..00000000 --- a/lib/solveEquation/stepThrough.js +++ /dev/null @@ -1,228 +0,0 @@ -"use strict"; -var ChangeTypes = require("../ChangeTypes"); -var checks = require("../checks"); -var Equation = require("../equation/Equation"); -var EquationOperations = require("./EquationOperations"); -var EquationStatus = require("../equation/Status"); -var evaluate = require("../util/evaluate"); -var flattenOperands = require("../util/flattenOperands"); -var mathNode = require("../mathnode"); -var removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); -var simplifyExpressionNode = require("../simplifyExpression/stepThrough"); -var Symbols = require("../Symbols"); -var comparatorToFunction = { - '=': function (left, right) { return left === right; }, - '>': function (left, right) { return left > right; }, - '>=': function (left, right) { return left >= right; }, - '<': function (left, right) { return left < right; }, - '<=': function (left, right) { return left <= right; }, -}; -// Given a leftNode, rightNode and a comparator, will return the steps to get -// the solution. Possible solutions include: -// - solving for a variable (e.g. 'x=3' for '3x=4+5') -// - the result of comparing values (e.g. 'true' for 3 = 3, 'false' for 3 < 2) -function stepThrough(leftNode, rightNode, comparator, debug) { - if (debug === void 0) { debug = false; } - var equation = new Equation(leftNode, rightNode, comparator); - if (debug) { - // eslint-disable-next-line - // unsure whether or not the second paramter should be a thing? - console.log("\n\nSolving: " + equation.print(false)); - } - // we can't solve/find steps if there are any unsupported nodes - if (checks.hasUnsupportedNodes(equation.leftNode) || - checks.hasUnsupportedNodes(equation.rightNode)) { - return []; - } - var symbolSet = Symbols.getSymbolsInEquation(equation); - if (symbolSet.size === 0) { - return solveConstantEquation(equation, debug); - } - var symbolName = symbolSet.values().next().value; - var equationStatus; - var steps = []; - var originalEquationStr = equation.print(); - var maxStepCount = 20; - var iters = 0; - // Step through the math equation until nothing changes - do { - steps = addSimplificationSteps(steps, equation, debug); - if (steps.length > 0) { - var lastStep = steps[steps.length - 1]; - equation = Equation.createEquationFromString(lastStep.newEquation.print(), equation.comparator); - } - equation.leftNode = flattenOperands(equation.leftNode); - equation.rightNode = flattenOperands(equation.rightNode); - // at this point, the symbols might have cancelled out. - if (Symbols.getSymbolsInEquation(equation).size === 0) { - return solveConstantEquation(equation, debug, steps); - } - try { - equationStatus = step(equation, symbolName); - } - catch (e) { - // This error happens for some math that we don't support - if (e.message.startsWith("No term with symbol: ")) { - // eslint-disable-next-line - console.error("Math error: " + e.message + ", returning no steps"); - return []; - } - else { - throw e; // bubble up - } - } - if (equationStatus.hasChanged()) { - if (equationStatus.newEquation.print().length > 300) { - // eslint-disable-next-line - throw Error("Math error: Potential infinite loop for equation " + - originalEquationStr + ". It reached over 300 characters " + - " long, so returning no steps"); - } - if (debug) { - logSteps(equationStatus); - } - steps.push(equationStatus); - } - equation = EquationStatus.resetChangeGroups(equationStatus.newEquation); - if (iters++ === maxStepCount) { - // eslint-disable-next-line - console.error("Math error: Potential infinite loop for equation: " + - originalEquationStr + ", returning no steps"); - return []; - } - } while (equationStatus.hasChanged()); - return steps; -} -// Given an equation of constants, will simplify both sides, returning -// the steps and the result of the equation e.g. 'True' or 'False' -function solveConstantEquation(equation, debug, steps) { - if (steps === void 0) { steps = []; } - var compareFunction = comparatorToFunction[equation.comparator]; - if (!compareFunction) { - throw Error("Unexpected comparator"); - } - steps = addSimplificationSteps(steps, equation, debug); - if (steps.length > 0) { - var lastStep = steps[steps.length - 1]; - equation = Equation.createEquationFromString(lastStep.newEquation.print(), equation.comparator); - } - // 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); - if (!mathNode.Type.isConstantOrConstantFraction(equation.leftNode, true) || - !mathNode.Type.isConstantOrConstantFraction(equation.rightNode, true)) { - throw Error("Expected both nodes to be constants, instead got: " + - equation.print()); - } - var leftValue = evaluate(equation.leftNode); - var rightValue = evaluate(equation.rightNode); - var changeType; - if (compareFunction(leftValue, rightValue)) { - changeType = ChangeTypes.STATEMENT_IS_TRUE; - } - else { - changeType = ChangeTypes.STATEMENT_IS_FALSE; - } - // there's no oldEquation or change groups because nothing actually changes - // here, it's just a final step that states the solution - var equationStatus = new EquationStatus(changeType, null, equation); - if (debug) { - logSteps(equationStatus); - } - steps.push((equationStatus)); - return steps; -} -// Given a symbol and an equation, performs a single step to -// solve for the symbol. Returns an Status object. -function step(equation, symbolName) { - var solveFunctions = [ - // ensure the symbol is always on the left node - EquationOperations.ensureSymbolInLeftNode, - // get rid of denominators that have the symbol - EquationOperations.removeSymbolFromDenominator, - // remove the symbol from the right side - EquationOperations.removeSymbolFromRightSide, - // isolate the symbol on the left side - EquationOperations.isolateSymbolOnLeftSide, - ]; - for (var i = 0; i < solveFunctions.length; i++) { - var equationStatus = solveFunctions[i](equation, symbolName); - if (equationStatus.hasChanged()) { - return equationStatus; - } - } - return EquationStatus.noChange(equation); -} -// Simplifies the equation and returns the simplification steps -function addSimplificationSteps(steps, equation, debug) { - if (debug === void 0) { debug = false; } - var oldEquation = equation.clone(); - var leftSteps = simplifyExpressionNode(equation.leftNode, false); - var leftSubSteps = []; - for (var i = 0; i < leftSteps.length; i++) { - var step_1 = leftSteps[i]; - leftSubSteps.push(EquationStatus.addLeftStep(equation, step_1)); - } - if (leftSubSteps.length === 1) { - var step_2 = leftSubSteps[0]; - if (debug) { - logSteps(step_2); - } - steps.push(step_2); - } - else if (leftSubSteps.length > 1) { - var lastStep = leftSubSteps[leftSubSteps.length - 1]; - var finalEquation = EquationStatus.resetChangeGroups(lastStep.newEquation); - // no change groups are set here - too much is changing for it to be useful - var simplifyStatus = new EquationStatus(ChangeTypes.SIMPLIFY_LEFT_SIDE, oldEquation, finalEquation, leftSubSteps); - if (debug) { - logSteps(simplifyStatus); - } - steps.push(simplifyStatus); - } - // update `equation` to have the new simplified left node - if (steps.length > 0) { - equation = EquationStatus.resetChangeGroups(steps[steps.length - 1].newEquation); - } - // the updated equation from simplifing the left side is the old equation - // (ie the "before" of the before and after) for simplifying the right side. - oldEquation = equation.clone(); - var rightSteps = simplifyExpressionNode(equation.rightNode, false); - var rightSubSteps = []; - for (var i = 0; i < rightSteps.length; i++) { - var step_3 = rightSteps[i]; - rightSubSteps.push(EquationStatus.addRightStep(equation, step_3)); - } - if (rightSubSteps.length === 1) { - var step_4 = rightSubSteps[0]; - if (debug) { - logSteps(step_4); - } - steps.push(step_4); - } - else if (rightSubSteps.length > 1) { - var lastStep = rightSubSteps[rightSubSteps.length - 1]; - var finalEquation = EquationStatus.resetChangeGroups(lastStep.newEquation); - // no change groups are set here - too much is changing for it to be useful - var simplifyStatus = new EquationStatus(ChangeTypes.SIMPLIFY_RIGHT_SIDE, oldEquation, finalEquation, rightSubSteps); - if (debug) { - logSteps(simplifyStatus); - } - steps.push(simplifyStatus); - } - return steps; -} -function logSteps(equationStatus) { - // eslint-disable-next-line - console.log("\n" + equationStatus.changeType); - // eslint-disable-next-line - console.log(equationStatus.newEquation.print()); - if (equationStatus.substeps.length > 0) { - // eslint-disable-next-line - console.log("\n substeps: "); - equationStatus.substeps.forEach(logSteps); - } -} -module.exports = stepThrough; -//# sourceMappingURL=stepThrough.js.map \ No newline at end of file diff --git a/lib/solveEquation/stepThrough.js.map b/lib/solveEquation/stepThrough.js.map deleted file mode 100644 index 29777e79..00000000 --- a/lib/solveEquation/stepThrough.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"stepThrough.js","sourceRoot":"","sources":["stepThrough.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/solveEquation/stepThrough.ts b/lib/solveEquation/stepThrough.ts deleted file mode 100644 index 1fe10d02..00000000 --- a/lib/solveEquation/stepThrough.ts +++ /dev/null @@ -1,262 +0,0 @@ -import ChangeTypes = require("../ChangeTypes"); -import checks = require("../checks"); -import Equation = require("../equation/Equation"); -import EquationOperations = require("./EquationOperations"); -import EquationStatus = require("../equation/Status"); -import evaluate = require("../util/evaluate"); -import flattenOperands = require("../util/flattenOperands"); -import mathNode = require("../mathnode"); -import removeUnnecessaryParens = require("../util/removeUnnecessaryParens"); -import simplifyExpressionNode = require("../simplifyExpression/stepThrough"); -import Symbols = require("../Symbols"); -const comparatorToFunction = { - '='(left, right) { return left === right; }, - '>'(left, right) { return left > right; }, - '>='(left, right) { return left >= right; }, - '<'(left, right) { return left < right; }, - '<='(left, right) { return left <= right; }, -}; - -// Given a leftNode, rightNode and a comparator, will return the steps to get -// the solution. Possible solutions include: -// - solving for a variable (e.g. 'x=3' for '3x=4+5') -// - the result of comparing values (e.g. 'true' for 3 = 3, 'false' for 3 < 2) -function stepThrough(leftNode: mathjs.MathNode, rightNode: mathjs.MathNode, comparator, debug=false) { - let equation = new Equation(leftNode, rightNode, comparator); - - if (debug) { - // eslint-disable-next-line - // unsure whether or not the second paramter should be a thing? - console.log("\n\nSolving: " + equation.print(false)); - } - - // we can't solve/find steps if there are any unsupported nodes - if (checks.hasUnsupportedNodes(equation.leftNode) || - checks.hasUnsupportedNodes(equation.rightNode)) { - return []; - } - - const symbolSet = Symbols.getSymbolsInEquation(equation); - - if (symbolSet.size === 0) { - return solveConstantEquation(equation, debug); - } - const symbolName = symbolSet.values().next().value; - - let equationStatus; - let steps = []; - - const originalEquationStr = equation.print(); - const maxStepCount = 20; - let iters = 0; - - // Step through the math equation until nothing changes - do { - steps = addSimplificationSteps(steps, equation, debug); - if (steps.length > 0) { - const lastStep = steps[steps.length - 1]; - equation = Equation.createEquationFromString( - lastStep.newEquation.print(), equation.comparator); - } - - equation.leftNode = flattenOperands(equation.leftNode); - equation.rightNode = flattenOperands(equation.rightNode); - - // at this point, the symbols might have cancelled out. - if (Symbols.getSymbolsInEquation(equation).size === 0) { - return solveConstantEquation(equation, debug, steps); - } - - try { - equationStatus = step(equation, symbolName); - } - catch (e) { - // This error happens for some math that we don't support - if (e.message.startsWith("No term with symbol: ")) { - // eslint-disable-next-line - console.error("Math error: " + e.message + ", returning no steps"); - return []; - } - else { - throw e; // bubble up - } - } - - if (equationStatus.hasChanged()) { - if (equationStatus.newEquation.print().length > 300) { - // eslint-disable-next-line - throw Error("Math error: Potential infinite loop for equation " + - originalEquationStr + ". It reached over 300 characters "+ - " long, so returning no steps"); - } - if (debug) { - logSteps(equationStatus); - } - steps.push(equationStatus); - } - - equation = EquationStatus.resetChangeGroups(equationStatus.newEquation); - if (iters++ === maxStepCount) { - // eslint-disable-next-line - console.error("Math error: Potential infinite loop for equation: " + - originalEquationStr + ", returning no steps"); - return []; - } - } while (equationStatus.hasChanged()); - - return steps; -} - -// Given an equation of constants, will simplify both sides, returning -// the steps and the result of the equation e.g. 'True' or 'False' -function solveConstantEquation(equation: Equation, debug, steps=[]) { - const compareFunction = comparatorToFunction[equation.comparator]; - - if (!compareFunction) { - throw Error("Unexpected comparator"); - } - - steps = addSimplificationSteps(steps, equation, debug); - if (steps.length > 0) { - const lastStep = steps[steps.length - 1]; - equation = Equation.createEquationFromString( - lastStep.newEquation.print(), equation.comparator); - } - - // 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); - - if (!mathNode.Type.isConstantOrConstantFraction(equation.leftNode, true) || - !mathNode.Type.isConstantOrConstantFraction(equation.rightNode, true)) { - throw Error("Expected both nodes to be constants, instead got: " + - equation.print()); - } - - const leftValue = evaluate(equation.leftNode); - const rightValue = evaluate(equation.rightNode); - let changeType; - if (compareFunction(leftValue, rightValue)) { - changeType = ChangeTypes.STATEMENT_IS_TRUE; - } - else { - changeType = ChangeTypes.STATEMENT_IS_FALSE; - } - - // there's no oldEquation or change groups because nothing actually changes - // here, it's just a final step that states the solution - const equationStatus = new EquationStatus(changeType, null, equation); - if (debug) { - logSteps(equationStatus); - } - steps.push((equationStatus) as any); - return steps; -} - -// Given a symbol and an equation, performs a single step to -// solve for the symbol. Returns an Status object. -function step(equation, symbolName) { - const solveFunctions = [ - // ensure the symbol is always on the left node - EquationOperations.ensureSymbolInLeftNode, - // get rid of denominators that have the symbol - EquationOperations.removeSymbolFromDenominator, - // remove the symbol from the right side - EquationOperations.removeSymbolFromRightSide, - // isolate the symbol on the left side - EquationOperations.isolateSymbolOnLeftSide, - ]; - - for (let i = 0; i < solveFunctions.length; i++) { - const equationStatus = solveFunctions[i](equation, symbolName); - - if (equationStatus.hasChanged()) { - return equationStatus; - } - } - return EquationStatus.noChange(equation); -} - -// Simplifies the equation and returns the simplification steps -function addSimplificationSteps(steps, equation: Equation, debug=false) { - let oldEquation = equation.clone(); - - const leftSteps = simplifyExpressionNode(equation.leftNode, false); - const leftSubSteps = []; - for (let i = 0; i < leftSteps.length; i++) { - const step = leftSteps[i]; - leftSubSteps.push(EquationStatus.addLeftStep(equation, step)); - } - if (leftSubSteps.length === 1) { - const step = leftSubSteps[0]; - if (debug) { - logSteps(step); - } - steps.push(step); - } - else if (leftSubSteps.length > 1) { - const lastStep = leftSubSteps[leftSubSteps.length - 1]; - const finalEquation = EquationStatus.resetChangeGroups(lastStep.newEquation); - // no change groups are set here - too much is changing for it to be useful - const simplifyStatus = new EquationStatus( - ChangeTypes.SIMPLIFY_LEFT_SIDE, - oldEquation, finalEquation, leftSubSteps); - if (debug) { - logSteps(simplifyStatus); - } - steps.push(simplifyStatus); - } - - // update `equation` to have the new simplified left node - if (steps.length > 0) { - equation = EquationStatus.resetChangeGroups( - steps[steps.length - 1 ].newEquation); - } - - // the updated equation from simplifing the left side is the old equation - // (ie the "before" of the before and after) for simplifying the right side. - oldEquation = equation.clone(); - - const rightSteps = simplifyExpressionNode(equation.rightNode, false); - const rightSubSteps = []; - for (let i = 0; i < rightSteps.length; i++) { - const step = rightSteps[i]; - rightSubSteps.push(EquationStatus.addRightStep(equation, step)); - } - if (rightSubSteps.length === 1) { - const step = rightSubSteps[0]; - if (debug) { - logSteps(step); - } - steps.push(step); - } - else if (rightSubSteps.length > 1) { - const lastStep = rightSubSteps[rightSubSteps.length - 1]; - const finalEquation = EquationStatus.resetChangeGroups(lastStep.newEquation); - // no change groups are set here - too much is changing for it to be useful - const simplifyStatus = new EquationStatus( - ChangeTypes.SIMPLIFY_RIGHT_SIDE, - oldEquation, finalEquation, rightSubSteps); - if (debug) { - logSteps(simplifyStatus); - } - steps.push(simplifyStatus); - } - - return steps; -} - -function logSteps(equationStatus: EquationStatus) { - // eslint-disable-next-line - console.log("\n" + equationStatus.changeType); - // eslint-disable-next-line - console.log(equationStatus.newEquation.print()); - if (equationStatus.substeps.length > 0) { - // eslint-disable-next-line - console.log("\n substeps: "); - equationStatus.substeps.forEach(logSteps); - } -} - -export = stepThrough; diff --git a/lib/util/Util.js b/lib/util/Util.js deleted file mode 100644 index ef5b4cc2..00000000 --- a/lib/util/Util.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -/* - Various utility functions used in the math stepper - */ -var Util = (function () { - function Util() { - } - return Util; -}()); -// Adds `value` to a list in `dict`, creating a new list if the key isn't in -// the dictionary yet. Returns the updated dictionary. -Util.appendToArrayInObject = function (dict, key, value) { - if (dict[key]) { - dict[key].push(value); - } - else { - dict[key] = [value]; - } - return dict; -}; -module.exports = Util; -//# sourceMappingURL=Util.js.map \ No newline at end of file diff --git a/lib/util/Util.js.map b/lib/util/Util.js.map deleted file mode 100644 index f72d0420..00000000 --- a/lib/util/Util.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Util.js","sourceRoot":"","sources":["Util.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH;IAAA;IAYA,CAAC;IAAD,WAAC;AAAD,CAAC,AAZD;AAEA,4EAA4E;AAC5E,sDAAsD;AAC3C,0BAAqB,GAAG,UAAC,IAAI,EAAE,GAAG,EAAE,KAAK;IAC5C,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC,CAAC;AAGN,iBAAS,IAAI,CAAC"} \ No newline at end of file diff --git a/lib/util/Util.ts b/lib/util/Util.ts deleted file mode 100644 index d0832197..00000000 --- a/lib/util/Util.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - Various utility functions used in the math stepper - */ -class Util { - -// Adds `value` to a list in `dict`, creating a new list if the key isn't in -// the dictionary yet. Returns the updated dictionary. - static appendToArrayInObject = (dict, key, value) => { - if (dict[key]) { - dict[key].push(value); - } else { - dict[key] = [value]; - } - return dict; - }; -} - -export = Util; diff --git a/lib/util/clone.js b/lib/util/clone.js deleted file mode 100644 index 74e0e3d4..00000000 --- a/lib/util/clone.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -// Simple clone function, which creates a deep copy of the given node -// And recurses on the children (due to the shallow nature of the mathjs node -// clone) -function clone(node) { - var copy = node.clone(); - copy.changeGroup = node.changeGroup; - if (node.args) { - node.args.forEach(function (child, i) { - copy.args[i] = clone(child); - }); - } - else if (node.content) { - copy.content = clone(node.content); - } - return copy; -} -module.exports = clone; -//# sourceMappingURL=clone.js.map \ No newline at end of file diff --git a/lib/util/clone.js.map b/lib/util/clone.js.map deleted file mode 100644 index 724d088f..00000000 --- a/lib/util/clone.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"clone.js","sourceRoot":"","sources":["clone.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,6EAA6E;AAC7E,SAAS;AACT,eAAe,IAAI;IACjB,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AACd,CAAC;AAED,iBAAS,KAAK,CAAC"} \ No newline at end of file diff --git a/lib/util/clone.ts b/lib/util/clone.ts deleted file mode 100644 index 5c51688e..00000000 --- a/lib/util/clone.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Simple clone function, which creates a deep copy of the given node -// And recurses on the children (due to the shallow nature of the mathjs node -// clone) -function clone(node) { - const copy = node.clone(); - copy.changeGroup = node.changeGroup; - if (node.args) { - node.args.forEach((child, i) => { - copy.args[i] = clone(child); - }); - } - else if (node.content) { - copy.content = clone(node.content); - } - return copy; -} - -export = clone; diff --git a/lib/util/evaluate.js b/lib/util/evaluate.js deleted file mode 100644 index 995216fd..00000000 --- a/lib/util/evaluate.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; -// Evaluates a node to a numerical value -// e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 -// it's important that `node` does not contain any symbol nodes -function evaluate(node) { - // TODO: once we swap in math-parser, call its evaluate function instead - return node.eval(); -} -module.exports = evaluate; -//# sourceMappingURL=evaluate.js.map \ No newline at end of file diff --git a/lib/util/evaluate.js.map b/lib/util/evaluate.js.map deleted file mode 100644 index 45d425a8..00000000 --- a/lib/util/evaluate.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["evaluate.ts"],"names":[],"mappings":";AAAA,wCAAwC;AACxC,6EAA6E;AAC7E,+DAA+D;AAC/D,kBAAkB,IAAI;IACpB,wEAAwE;IACxE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,iBAAS,QAAQ,CAAC"} \ No newline at end of file diff --git a/lib/util/evaluate.ts b/lib/util/evaluate.ts deleted file mode 100644 index c71181b1..00000000 --- a/lib/util/evaluate.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Evaluates a node to a numerical value -// e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 -// it's important that `node` does not contain any symbol nodes -function evaluate(node) { - // TODO: once we swap in math-parser, call its evaluate function instead - return node.eval(); -} - -export = evaluate; diff --git a/lib/util/flattenOperands.ts b/lib/util/flattenOperands.ts deleted file mode 100644 index c3b14017..00000000 --- a/lib/util/flattenOperands.ts +++ /dev/null @@ -1,333 +0,0 @@ -import evaluate = require("./evaluate"); -import Negative = require("../Negative"); -import mathNode = require("../mathNode"); - -/* -Background: - -Expression trees are commonly parsed as binary trees, and mathjs does this too. -That means that a mathjs expression tree likely looks like: -http://collegelabs.co/clabs/nld/images/524px-Expression_Tree.svg.png - -e.g. 2+2+2 is parsed by mathjs as 2 + 2+2 (a plus node with children 2 and 2+2) -However... -1. This is more complicated than needed. 2+2+2 is the same as 2+(2+2) -2. To collect like terms, we actually *need* it to be flat. e.g. with 2x+(2+2x), - there's no easy way to know that there are two 2x's to collect without - running up and down the tree. If we flatten to 2x+2+2x, it becomes a lot - easier to collect like terms to (2x+2x) + 2, which would then be combined to - 4x + 2 -The purpose of flatteOperands is to flatten the tree in this way. - -e.g. an expression that is grouped in the tree like -(2 + ((4 * ((1 + 2) + (3 + 4))) * 8)) -should be flattened to look like: -(2 + (4 * (1 + 2 + 3 + 4) * 8)) - -Subtraction and division are also flattened, though that gets a bit more -complicated and you may as well start reading through the code if you're -interested in how that works -*/ - -// Flattens the tree accross the same operation (just + and * for now) -// e.g. 2+2+2 is parsed by mathjs as 2+(2+2), but this would change that to -// 2+2+2, ie one + node that has three children. -// Input: an expression tree -// Output: the expression tree updated with flattened operations -function flattenOperands(node) { - if (Node.Type.isConstant(node, true)) { - // the evaluate() changes unary minuses around constant nodes to constant nodes - // with negative values. - const constNode = Node.Creator.constant(evaluate(node)); - if (node.changeGroup) { - constNode.changeGroup = node.changeGroup; - } - return constNode; - } - else if (Node.Type.isOperator(node)) { - if ("+-/*".includes(node.op)) { - let parentOp; - if (node.op === "/") { - // Division is flattened in partner with multiplication. This means - // that after collecting the operands, they'll be children args of * - parentOp = "*"; - } - else if (node.op === "-") { - // Subtraction is flattened in partner with addition, This means that - // after collecting the operands, they'll be children args of + - parentOp = "+"; - } - else { - parentOp = node.op; - } - return flattenSupportedOperation(node, parentOp); - } - // If the operation is not supported, just recurse on the children - else { - node.args.forEach((child, i) => { - node.args[i] = flattenOperands(child); - }); - } - return node; - } - else if (Node.Type.isParenthesis(node)) { - node.content = flattenOperands(node.content); - return node; - } - else if (Node.Type.isUnaryMinus(node)) { - const arg = flattenOperands(node.args[0]); - const flattenedNode = Negative.negate(arg, true); - if (node.changeGroup) { - flattenedNode.changeGroup = node.changeGroup; - } - return flattenedNode; - } - else if (Node.Type.isFunction(node, "abs")) { - node.args[0] = flattenOperands(node.args[0]); - return node; - } - else if (Node.Type.isFunction(node, "nthRoot")) { - node.args[0] = flattenOperands(node.args[0]); - if (node.args[1]) { - node.args[1] = flattenOperands(node.args[1]); - } - return node; - } - else { - return node; - } -} - -// Flattens operations (see flattenOperands docstring) for an operator node -// with an operation type that can be flattened. Currently * + / are supported. -// Returns the updated, flattened node. -// NOTE: the returned node will be of operation type `parentOp`, regardless of -// the operation type of `node`, unless `node` wasn't changed -// e.g. 2 * 3 / 4 would be * of 2 and 3/4, but 2/3 would stay 2/3 and division -function flattenSupportedOperation(node: any, parentOp: any); -function flattenSupportedOperation(node, parentOp) { - // First get the list of operands that this operator operates on. - // e.g. 2 + 3 + 4 + 5 is stored as (((2 + 3) + 4) + 5) in the tree and we - // want to get the list [2, 3, 4, 5] - const operands = getOperands(node, parentOp); - - // If there's only one operand (possible if 2*x was flattened to 2x) - // then it's no longer an operation, so we should replace the node - // with the one operand. - if (operands.length === 1) { - node = operands[0]; - } - else { - // When we are dealing with flattening division, and there's also - // multiplication involved, we might end up with a top level * instead. - // e.g. 2*4/5 is parsed with / at the top, but in the end we want 2 * (4/5) - // Check for this by first checking if we have more than two operands - // (which is impossible for division), then by recursing through the - // original tree for any multiplication node - if there was one, it would - // have ended up at the root. - if (node.op === "/" && (operands.length > 2 || - hasMultiplicationBesideDivision(node))) { - node = Node.Creator.operator("*", operands); - } - // similarily, - will become + always - else if (node.op === "-") { - node = Node.Creator.operator("+", operands); - } - // otherwise keep the operator, replace operands - else { - node.args = operands; - } - // When we collect operands to flatten multiplication, the - // multiplication of those operands should never be implicit - if (node.op === "*") { - node.implicit = false; - } - } - return node; -} - -// Recursively finds the operands under `parentOp` in the input tree `node`. -// The input tree `node` will always have a parent that is an operation -// of type `op`. -// Op is a string e.g. '+' or '*' -// returns the list of all the node operated on by `parentOp` -function getOperands(node: any, parentOp: "*"); -function getOperands(node: any, parentOp: "+"); -function getOperands(node: any, parentOp: any); -function getOperands(node, parentOp) { - // We can only recurse on operations of type op. - // If the node is not an operator node or of the right operation type, - // we can't break up or flatten this tree any further, so we return just - // the current node, and recurse on it to flatten its ops. - if (!Node.Type.isOperator(node)) { - return [flattenOperands(node)]; - } - switch (node.op) { - // division is part of flattening multiplication - case "*": - case "/": - if (parentOp !== "*") { - return [flattenOperands(node)]; - } - break; - case "+": - case "-": - if (parentOp !== "+") { - return [flattenOperands(node)]; - } - break; - default: - return [flattenOperands(node)]; - } - if (Node.PolynomialTerm.isPolynomialTerm(node, true)) { - node.args.forEach((arg, i) => { - node.args[i] = flattenOperands(node.args[i]); - }); - return [node]; - } - - // If we're flattening over *, check for a polynomial term (ie a - // coefficient multiplied by a symbol such as 2x^2 or 3y) - // This is true if there's an implicit multiplication and the right operand - // is a symbol or a symbol to an exponent. - else if (parentOp === "*" && isPolynomialTermMultiplication(node)) { - return maybeFlattenPolynomialTerm(node); - } - else if (parentOp === "*" && node.op === "/") { - return flattenDivision(node); - } - else if (node.op === "-") { - // this operation will become addition e.g. 2 - 3 -> 2 + -(-3) - const secondOperand = node.args[1]; - const negativeSecondOperand = Negative.negate(secondOperand, true); - const operands = [ - getOperands(node.args[0], parentOp), - getOperands(negativeSecondOperand, parentOp) - ]; - return [].concat.apply([], operands); - } - else { - const operands = []; - node.args.forEach((child) => { - // This will make an array of arrays - operands.push(getOperands(child, parentOp)); - }); - return [].concat.apply([], operands); - } -} - -// Return true iff node is a candidate for simplifying to a polynomial -// term. This function is a helper function for getOperands. -// Context: Usually we'd flatten 2*2*x to a multiplication node with 3 children -// (2, 2, and x) but if we got 2*2x, we want to keep 2x together. -// 2*2*x (a tree stored in two levels because initially nodes only have two -// children) in the flattening process should be turned into 2*2x instead of -// 2*2*x (which has three children). -// So this function would return true for the input 2*2x, if it was stored as -// an expression tree with root node * and children 2*2 and x -function isPolynomialTermMultiplication(node) { - // This concept only applies when we're flattening multiplication operations - if (node.op !== "*") { - return false; - } - // This only makes sense when we're flattening two arguments - if (node.args.length !== 2) { - return false; - } - // The second node should be for the form x or x^2 (ie a polynomial term - // with no coefficient) - const secondOperand = node.args[1]; - if (mathNode.PolynomialTerm.isPolynomialTerm(secondOperand)) { - const polyNode = new mathNode.PolynomialTerm(secondOperand); - return !polyNode.hasCoeff(); - } - else { - return false; - } -} - -// Takes a node that might represent a multiplication with a polynomial term -// and flattens it appropriately so the coefficient and symbol are grouped -// together. Returns a new list of operands from this node that should be -// multiplied together. -function maybeFlattenPolynomialTerm(node: any); -function maybeFlattenPolynomialTerm(node) { - // We recurse on the left side of the tree to find operands so far - const operands = getOperands(node.args[0], "*"); - - // If the last operand (so far) under * was a constant, then it's a - // polynomial term. - // e.g. 2*5*6x creates a tree where the top node is implicit multiplcation - // and the left branch goes to the tree with 2*5*6, and the right operand - // is the symbol x. We want to check that the last argument on the left (in - // this example 6) is a constant. - const lastOperand = operands.pop(); - - // in the above example, node.args[1] would be the symbol x - const nextOperand = flattenOperands(node.args[1]); - - // a coefficient can be constant or a fraction of constants - if (mathNode.Type.isConstantOrConstantFraction(lastOperand)) { - // we replace the constant (which we popped) with constant*symbol - operands.push( - mathNode.Creator.operator("*", [lastOperand, nextOperand], true)); - } - // Now we know it isn't a polynomial term, it's just another seperate operand - else { - operands.push(lastOperand); - operands.push(nextOperand); - } - return operands; -} - -// Takes a division node and returns a list of operands -// If there is multiplication in the numerator, the operands returned -// are to be multiplied together. Otherwise, a list of length one with -// just the division node is returned. getOperands might change the -// operator accordingly. -function flattenDivision(node: any); -function flattenDivision(node) { - // We recurse on the left side of the tree to find operands so far - // Flattening division is always considered part of a bigger picture - // of multiplication, so we get operands with '*' - let operands = getOperands(node.args[0], "*"); - - if (operands.length === 1) { - node.args[0] = operands.pop(); - node.args[1] = flattenOperands(node.args[1]); - operands = [node]; - } - else { - // This is the last operand, the term we'll want to add our division to - const numerator = operands.pop(); - // This is the denominator of the current division node we're recursing on - const denominator = flattenOperands(node.args[1]); - // Note that this means 2 * 3 * 4 / 5 / 6 * 7 will flatten but keep the 4/5/6 - // as an operand - in simplifyDivision.js this is changed to 4/(5*6) - const divisionNode = mathNode.Creator.operator("/", [numerator, denominator]); - operands.push(divisionNode); - } - - return operands; -} - -// Returns true if there is a * node nested in some division, with no other -// operators or parentheses between them. -// e.g. returns true: 2*3/4, 2 / 5 / 6 * 7 / 8 -// e.g. returns false: 3/4/5, ((3*2) - 5) / 7, (2*5)/6 -function hasMultiplicationBesideDivision(node: any); -function hasMultiplicationBesideDivision(node) { - if (!mathNode.Type.isOperator(node)) { - return false; - } - if (node.op === "*") { - return true; - } - // we ony recurse through division - if (node.op !== "/") { - return false; - } - return node.args.some(hasMultiplicationBesideDivision); -} - -export = flattenOperands; diff --git a/lib/util/print.js b/lib/util/print.js deleted file mode 100644 index 8d5b93e5..00000000 --- a/lib/util/print.js +++ /dev/null @@ -1,98 +0,0 @@ -"use strict"; -var clone = require("./clone"); -var flatten = require("./flattenOperands"); -var mathNode = require("../mathNode"); -// Prints an expression node in asciimath -// If showPlusMinus is true, print + - (e.g. 2 + -3) -// If it's false (the default) 2 + -3 would print as 2 - 3 -// (The + - is needed to support the conversion of subtraction to addition of -// negative terms. See flattenOperands for more details if you're curious.) -function print(node, showPlusMinus) { - if (showPlusMinus === void 0) { showPlusMinus = false; } - node = flatten(clone(node)); - var string = printTreeTraversal(node); - if (!showPlusMinus) { - string = string.replace(/\s*?\+\s*?\-\s*?/g, " - "); - } - return string; -} -function printTreeTraversal(node, parentNode) { - if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - var polyTerm = new mathNode.PolynomialTerm(node); - // This is so we don't print 2/3 x^2 as 2 / 3x^2 - // Still print x/2 as x/2 and not 1/2 x though - if (polyTerm.hasFractionCoeff() && node.op !== "/") { - var coeffTerm = polyTerm.getCoeffNode(); - var coeffStr = printTreeTraversal(coeffTerm); - var nonCoeffTerm = mathNode.Creator.polynomialTerm(polyTerm.symbol, polyTerm.exponent, null); - var nonCoeffStr = printTreeTraversal(nonCoeffTerm); - return coeffStr + " " + nonCoeffStr; - } - } - if (mathNode.Type.isIntegerFraction(node)) { - return node.args[0] + "/" + node.args[1]; - } - if (mathNode.Type.isOperator(node)) { - if (node.op === "/" && mathNode.Type.isOperator(node.args[1])) { - return printTreeTraversal(node.args[0]) + " / (" + printTreeTraversal(node.args[1]) + ")"; - } - var opString = ""; - switch (node.op) { - case "+": - case "-": - // add space between operator and operands - opString = " " + node.op + " "; - break; - case "*": - if (node.implicit) { - break; - } - opString = " " + node.op + " "; - break; - case "/": - // no space for constant fraction divisions (slightly easier to read) - if (mathNode.Type.isConstantFraction(node, true)) { - opString = "" + node.op; - } - else { - opString = " " + node.op + " "; - } - break; - case "^": - // no space for exponents - opString = "" + node.op; - break; - } - var str = node.args.map(function (arg) { return printTreeTraversal(arg, node); }).join(opString); - // Need to add parens around any [+, -] operation - // nested in [/, *, ^] operation - // Check #120, #126 issues for more details. - // { "/" [{ "+" ["x", "2"] }, "2"] } -> (x + 2) / 2. - if (parentNode && - mathNode.Type.isOperator(parentNode) && - node.op && parentNode.op && - "*/^".indexOf(parentNode.op) >= 0 && - "+-".indexOf(node.op) >= 0) { - str = "(" + str + ")"; - } - return str; - } - else if (mathNode.Type.isParenthesis(node)) { - return "(" + printTreeTraversal(node.content) + ")"; - } - else if (mathNode.Type.isUnaryMinus(node)) { - if (mathNode.Type.isOperator(node.args[0]) && - "*/^".indexOf(node.args[0].op) === -1 && - !mathNode.PolynomialTerm.isPolynomialTerm(node)) { - return "-(" + printTreeTraversal(node.args[0]) + ")"; - } - else { - return "-" + printTreeTraversal(node.args[0]); - } - } - else { - return node.toString(); - } -} -module.exports = print; -//# sourceMappingURL=print.js.map \ No newline at end of file diff --git a/lib/util/print.js.map b/lib/util/print.js.map deleted file mode 100644 index 04410637..00000000 --- a/lib/util/print.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"print.js","sourceRoot":"","sources":["print.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/util/print.ts b/lib/util/print.ts deleted file mode 100644 index 745cfc49..00000000 --- a/lib/util/print.ts +++ /dev/null @@ -1,108 +0,0 @@ -import clone = require("./clone"); -import flatten = require("./flattenOperands"); -import mathNode = require("../mathNode"); - -// Prints an expression node in asciimath -// If showPlusMinus is true, print + - (e.g. 2 + -3) -// If it's false (the default) 2 + -3 would print as 2 - 3 -// (The + - is needed to support the conversion of subtraction to addition of -// negative terms. See flattenOperands for more details if you're curious.) -function print(node, showPlusMinus=false) { - node = flatten(clone(node)); - - let string = printTreeTraversal(node); - if (!showPlusMinus) { - string = string.replace(/\s*?\+\s*?\-\s*?/g, " - "); - } - return string; -} -function printTreeTraversal(node, parentNode?) { - if (mathNode.PolynomialTerm.isPolynomialTerm(node)) { - const polyTerm = new mathNode.PolynomialTerm(node); - // This is so we don't print 2/3 x^2 as 2 / 3x^2 - // Still print x/2 as x/2 and not 1/2 x though - if (polyTerm.hasFractionCoeff() && node.op !== "/") { - const coeffTerm = polyTerm.getCoeffNode(); - const coeffStr = printTreeTraversal(coeffTerm); - - const nonCoeffTerm = mathNode.Creator.polynomialTerm( - polyTerm.symbol, polyTerm.exponent, null); - const nonCoeffStr = printTreeTraversal(nonCoeffTerm); - - return `${coeffStr} ${nonCoeffStr}`; - } - } - - if (mathNode.Type.isIntegerFraction(node)) { - return `${node.args[0]}/${node.args[1]}`; - } - - if (mathNode.Type.isOperator(node)) { - if (node.op === "/" && mathNode.Type.isOperator(node.args[1])) { - return `${printTreeTraversal(node.args[0])} / (${printTreeTraversal(node.args[1])})`; - } - - let opString = ""; - - switch (node.op) { - case "+": - case "-": - // add space between operator and operands - opString = ` ${node.op} `; - break; - case "*": - if (node.implicit) { - break; - } - opString = ` ${node.op} `; - break; - case "/": - // no space for constant fraction divisions (slightly easier to read) - if (mathNode.Type.isConstantFraction(node, true)) { - opString = `${node.op}`; - } - else { - opString = ` ${node.op} `; - } - break; - case "^": - // no space for exponents - opString = `${node.op}`; - break; - } - - let str = node.args.map(arg => printTreeTraversal(arg, node)).join(opString); - - // Need to add parens around any [+, -] operation - // nested in [/, *, ^] operation - // Check #120, #126 issues for more details. - // { "/" [{ "+" ["x", "2"] }, "2"] } -> (x + 2) / 2. - if (parentNode && - mathNode.Type.isOperator(parentNode) && - node.op && parentNode.op && - "*/^".indexOf(parentNode.op) >= 0 && - "+-".indexOf(node.op) >= 0) { - str = `(${str})`; - } - - return str; - } - else if (mathNode.Type.isParenthesis(node)) { - return `(${printTreeTraversal(node.content)})`; - } - else if (mathNode.Type.isUnaryMinus(node)) { - if (mathNode.Type.isOperator(node.args[0]) && - "*/^".indexOf(node.args[0].op) === -1 && - !mathNode.PolynomialTerm.isPolynomialTerm(node)) { - return `-(${printTreeTraversal(node.args[0])})`; - } - else { - return `-${printTreeTraversal(node.args[0])}`; - } - } - else { - return node.toString(); - } -} - -export = print; diff --git a/lib/util/removeUnnecessaryParens.js b/lib/util/removeUnnecessaryParens.js deleted file mode 100644 index d19e2223..00000000 --- a/lib/util/removeUnnecessaryParens.js +++ /dev/null @@ -1,142 +0,0 @@ -"use strict"; -var checks = require("../checks"); -var LikeTermCollector = require("../simplifyExpression/collectAndCombineSearch/LikeTermCollector"); -var mathNode = require("../mathNode"); -// Removes any parenthesis around nodes that can't be resolved further. -// Input must be a top level expression. -// Returns a node. -function removeUnnecessaryParens(node, rootNode) { - if (rootNode === void 0) { rootNode = false; } - // Parens that wrap everything are redundant. - // NOTE: removeUnnecessaryParensSearch recursively removes parens that aren't - // needed, while this step only applies to the very top level expression. - // e.g. (2 + 3) * 4 can't become 2 + 3 * 4, but if (2 + 3) as a top level - // expression can become 2 + 3 - if (rootNode) { - while (mathNode.Type.isParenthesis(node)) { - node = node.content; - } - } - return removeUnnecessaryParensSearch(node); -} -// Recursively moves parenthesis around nodes that can't be resolved further if -// it doesn't change the value of the expression. Returns a node. -// NOTE: after this function is called, every parenthesis node in the -// tree should always have an operator node or unary minus as its child. -function removeUnnecessaryParensSearch(node) { - if (mathNode.Type.isOperator(node)) { - return removeUnnecessaryParensInOperatorNode(node); - } - else if (mathNode.Type.isFunction(node)) { - return removeUnnecessaryParensInFunctionNode(node); - } - else if (mathNode.Type.isParenthesis(node)) { - return removeUnnecessaryParensInParenthesisNode(node); - } - else if (mathNode.Type.isConstant(node, true) || mathNode.Type.isSymbol(node)) { - return node; - } - else if (mathNode.Type.isUnaryMinus(node)) { - var content = node.args[0]; - node.args[0] = removeUnnecessaryParensSearch(content); - return node; - } - else { - throw Error('Unsupported node type: ' + node.type); - } -} -function removeUnnecessaryParensInOperatorNode(node) { - // Special case: if the node is an exponent node and the base - // is an operator, we should keep the parentheses for the base. - // e.g. (2x)^2 -> (2x)^2 instead of 2x^2 - if (node.op === '^' && mathNode.Type.isParenthesis(node.args[0])) { - var base = node.args[0]; - if (mathNode.Type.isOperator(base.content)) { - base.content = removeUnnecessaryParensSearch(base.content); - node.args[1] = removeUnnecessaryParensSearch(node.args[1]); - return node; - } - } - node.args.forEach(function (child, i) { - node.args[i] = removeUnnecessaryParensSearch(child); - }); - // Sometimes, parens are around expressions that have been simplified - // all they can be. If that expression is part of an addition or subtraction - // operation, we can remove the parenthesis. - // e.g. (x+4) + 12 -> x+4 + 12 - if (node.op === '+') { - node.args.forEach(function (child, i) { - if (mathNode.Type.isParenthesis(child) && - !canCollectOrCombine(child.content)) { - // remove the parens by replacing the child node (in its args list) - // with its content - node.args[i] = child.content; - } - }); - } - else if (node.op === '-') { - if (mathNode.Type.isParenthesis(node.args[0]) && - !canCollectOrCombine(node.args[0].content)) { - node.args[0] = node.args[0].content; - } - } - return node; -} -function removeUnnecessaryParensInFunctionNode(node) { - node.args.forEach(function (child, i) { - if (mathNode.Type.isParenthesis(child)) { - child = child.content; - } - node.args[i] = removeUnnecessaryParensSearch(child); - }); - return node; -} -function removeUnnecessaryParensInParenthesisNode(node) { - // polynomials terms can be complex trees (e.g. 3x^2/5) but don't need parens - // around them - if (mathNode.PolynomialTerm.isPolynomialTerm(node.content)) { - // also recurse to remove any unnecessary parens within the term - // (e.g. the exponent might have parens around it) - if (node.content.args) { - node.content.args.forEach(function (arg, i) { - node.content.args[i] = removeUnnecessaryParensSearch(arg); - }); - } - node = node.content; - } - else if (mathNode.Type.isConstant(node.content, true) || - mathNode.Type.isIntegerFraction(node.content) || - mathNode.Type.isSymbol(node.content)) { - node = node.content; - } - else if (mathNode.Type.isFunction(node.content)) { - node = node.content; - node = removeUnnecessaryParensSearch(node); - } - else if (mathNode.Type.isOperator(node.content)) { - node.content = removeUnnecessaryParensSearch(node.content); - // exponent nodes don't need parens around them - if (node.content.op === '^') { - node = node.content; - } - } - else if (mathNode.Type.isParenthesis(node.content)) { - node = removeUnnecessaryParensSearch(node.content); - } - else if (mathNode.Type.isUnaryMinus(node.content)) { - node.content = removeUnnecessaryParensSearch(node.content); - } - else { - throw Error('Unsupported node type: ' + node.content.type); - } - return node; -} -// Returns true if any of the collect or combine steps can be applied to the -// expression tree `node`. -function canCollectOrCombine(node) { - return LikeTermCollector.canCollectLikeTerms(node) || - checks.resolvesToConstant(node) || - checks.canSimplifyPolynomialTerms(node); -} -module.exports = removeUnnecessaryParens; -//# sourceMappingURL=removeUnnecessaryParens.js.map \ No newline at end of file diff --git a/lib/util/removeUnnecessaryParens.js.map b/lib/util/removeUnnecessaryParens.js.map deleted file mode 100644 index 74b8d5a7..00000000 --- a/lib/util/removeUnnecessaryParens.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"removeUnnecessaryParens.js","sourceRoot":"","sources":["removeUnnecessaryParens.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/util/removeUnnecessaryParens.ts b/lib/util/removeUnnecessaryParens.ts deleted file mode 100644 index 8420b4c7..00000000 --- a/lib/util/removeUnnecessaryParens.ts +++ /dev/null @@ -1,177 +0,0 @@ -import checks = require("../checks"); -import LikeTermCollector = require("../simplifyExpression/collectAndCombineSearch/LikeTermCollector"); -import mathNode = require("../mathNode"); - -// Removes any parenthesis around nodes that can't be resolved further. -// Input must be a top level expression. -// Returns a node. -function removeUnnecessaryParens(node, rootNode=false) { - // Parens that wrap everything are redundant. - // NOTE: removeUnnecessaryParensSearch recursively removes parens that aren't - // needed, while this step only applies to the very top level expression. - // e.g. (2 + 3) * 4 can't become 2 + 3 * 4, but if (2 + 3) as a top level - // expression can become 2 + 3 - if (rootNode) { - while (mathNode.Type.isParenthesis(node)) { - node = node.content; - } - } - return removeUnnecessaryParensSearch(node); -} - -// Recursively moves parenthesis around nodes that can't be resolved further if -// it doesn't change the value of the expression. Returns a node. -// NOTE: after this function is called, every parenthesis node in the -// tree should always have an operator node or unary minus as its child. -function removeUnnecessaryParensSearch(node) { - if (mathNode.Type.isOperator(node)) { - return removeUnnecessaryParensInOperatorNode(node); - } - else if (mathNode.Type.isFunction(node)) { - return removeUnnecessaryParensInFunctionNode(node); - } - else if (mathNode.Type.isParenthesis(node)) { - return removeUnnecessaryParensInParenthesisNode(node); - } - else if (mathNode.Type.isConstant(node, true) || mathNode.Type.isSymbol(node)) { - return node; - } - else if (mathNode.Type.isUnaryMinus(node)) { - const content = node.args[0]; - node.args[0] = removeUnnecessaryParensSearch(content); - return node; - } - else { - throw Error("Unsupported node type: " + node.type); - } -} - -// Removes unncessary parens for each operator in an operator node, and removes -// unncessary parens around operators that can't be simplified further. -// Returns a node. -function removeUnnecessaryParensInOperatorNode(node: any); -function removeUnnecessaryParensInOperatorNode(node) { - // Special case: if the node is an exponent node and the base - // is an operator, we should keep the parentheses for the base. - // e.g. (2x)^2 -> (2x)^2 instead of 2x^2 - if (node.op === "^" && mathNode.Type.isParenthesis(node.args[0])) { - const base = node.args[0]; - if (mathNode.Type.isOperator(base.content)) { - base.content = removeUnnecessaryParensSearch(base.content); - node.args[1] = removeUnnecessaryParensSearch(node.args[1]); - - return node; - } - } - - node.args.forEach((child, i) => { - node.args[i] = removeUnnecessaryParensSearch(child); - }); - - // Sometimes, parens are around expressions that have been simplified - // all they can be. If that expression is part of an addition or subtraction - // operation, we can remove the parenthesis. - // e.g. (x+4) + 12 -> x+4 + 12 - if (node.op === "+") { - node.args.forEach((child, i) => { - if (mathNode.Type.isParenthesis(child) && - !canCollectOrCombine(child.content)) { - // remove the parens by replacing the child node (in its args list) - // with its content - node.args[i] = child.content; - } - }); - } - // This is different from addition because when subtracting a group of terms - //in parenthesis, we want to distribute the subtraction. - // e.g. `(2 + x) - (1 + x)` => `2 + x - (1 + x)` not `2 + x - 1 + x` - else if (node.op === "-") { - if (mathNode.Type.isParenthesis(node.args[0]) && - !canCollectOrCombine(node.args[0].content)) { - node.args[0] = node.args[0].content; - } - } - - return node; -} - -// Removes unncessary parens for each argument in a function node. -// Returns a node. -function removeUnnecessaryParensInFunctionNode(node: any); -function removeUnnecessaryParensInFunctionNode(node) { - node.args.forEach((child, i) => { - if (mathNode.Type.isParenthesis(child)) { - child = child.content; - } - node.args[i] = removeUnnecessaryParensSearch(child); - }); - - return node; -} - - -// Parentheses are unnecessary when their content is a constant e.g. (2) -// or also a parenthesis node, e.g. ((2+3)) - this removes those parentheses. -// Note that this means that the type of the content of a ParenthesisNode after -// this step should now always be an OperatorNode (including unary minus). -// Returns a node. -function removeUnnecessaryParensInParenthesisNode(node: any); -function removeUnnecessaryParensInParenthesisNode(node) { - // polynomials terms can be complex trees (e.g. 3x^2/5) but don't need parens - // around them - if (mathNode.PolynomialTerm.isPolynomialTerm(node.content)) { - // also recurse to remove any unnecessary parens within the term - // (e.g. the exponent might have parens around it) - if (node.content.args) { - node.content.args.forEach((arg, i) => { - node.content.args[i] = removeUnnecessaryParensSearch(arg); - }); - } - node = node.content; - } - // If the content is just one symbol or constant, the parens are not - // needed. - else if (mathNode.Type.isConstant(node.content, true) || - mathNode.Type.isIntegerFraction(node.content) || - mathNode.Type.isSymbol(node.content)) { - node = node.content; - } - // If the content is just one function call, the parens are not needed. - else if (mathNode.Type.isFunction(node.content)) { - node = node.content; - node = removeUnnecessaryParensSearch(node); - } - // If there is an operation within the parens, then the parens are - // likely needed. So, recurse. - else if (mathNode.Type.isOperator(node.content)) { - node.content = removeUnnecessaryParensSearch(node.content); - // exponent nodes don't need parens around them - if (node.content.op === "^") { - node = node.content; - } - } - // If the content is also parens, we have doubly nested parens. First - // recurse on the child node, then set the current node equal to its child - // to get rid of the extra parens. - else if (mathNode.Type.isParenthesis(node.content)) { - node = removeUnnecessaryParensSearch(node.content); - } - else if (mathNode.Type.isUnaryMinus(node.content)) { - node.content = removeUnnecessaryParensSearch(node.content); - } - else { - throw Error("Unsupported node type: " + node.content.type); - } - - return node; -} - -// Returns true if any of the collect or combine steps can be applied to the -// expression tree `node`. -function canCollectOrCombine(node) { - return LikeTermCollector.canCollectLikeTerms(node) || - checks.resolvesToConstant(node) || - checks.canSimplifyPolynomialTerms(node); -} - -export = removeUnnecessaryParens; diff --git a/package.json b/package.json index d503fd33..494a4256 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "eslint": "^3.10.2", "eslint-config-google": "^0.7.0", "eslint-plugin-sort-requires": "^2.1.0", - "mocha": "2.4.5" + "mocha": "2.4.5", + "typescript": "^2.2.2" }, "scripts": { "lint": "node_modules/.bin/eslint .", diff --git a/test/Negative.test.ts b/test/Negative.test.ts deleted file mode 100644 index 49700f13..00000000 --- a/test/Negative.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import math = require("mathjs"); -import flatten = require("../lib/util/flattenOperands"); -import print = require("../lib/util/print"); -import Negative = require("../lib/Negative"); -import TestUtil = require("./TestUtil"); - -function testNegate(exprString: any, outputStr: any); -function testNegate(exprString, outputStr) { - const inputStr = Negative.negate(flatten(math.parse(exprString))); - TestUtil.testFunctionOutput(print, inputStr, outputStr); -} - -describe("negate", () => { - const tests = [ - ["1", "-1"], - ["-1", "1"], - ["1/2", "-1/2"], - ["(x+2)", "-(x + 2)"], - ["x", "-x"], - ["x^2", "-x^2"], - ["-y^3", "y^3"], - ["2/3 x", "-2/3 x"], - ["-5/6 z", "5/6 z"], - ]; - tests.forEach(t => testNegate(t[0], t[1])); -}); diff --git a/test/Node/PolynomialTerm.test.ts b/test/Node/PolynomialTerm.test.ts deleted file mode 100644 index 14006755..00000000 --- a/test/Node/PolynomialTerm.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -const polynomialTerm = require("../../lib/node/PolynomialTerm"); -import TestUtil = require("../TestUtil"); - -function testIsPolynomialTerm(exprStr: any, isTerm: any); -function testIsPolynomialTerm(exprStr, isTerm) { - TestUtil.testBooleanFunction(polynomialTerm.isPolynomialTerm, exprStr, isTerm); -} - -describe("classifies symbol terms correctly", () => { - const tests = [ - ["x", true], - ["x", true], - ["x^2", true], - ["y^55", true], - ["y^4/4", true], - ["5y/3", true], - ["x^y", true], - ["3", false], - ["2^5", false], - ["x*y^5", false], - ["-12y^5/-3", true], - ]; - tests.forEach(t => testIsPolynomialTerm(t[0], t[1])); -}); diff --git a/test/Node/Type.test.ts b/test/Node/Type.test.ts deleted file mode 100644 index 9f0f0946..00000000 --- a/test/Node/Type.test.ts +++ /dev/null @@ -1,109 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -const mathNode = require("../../lib/node"); - -const constNode = mathNode.Creator.constant; - -describe("mathNode.Type works", () => { - it("(2+2) parenthesis", () => { - assert.deepEqual( - mathNode.Type.isParenthesis(math.parse("(2+2)")), - true); - }); - it("10 constant", () => { - assert.deepEqual( - mathNode.Type.isConstant(math.parse(10)), - true); - }); - it("-2 constant", () => { - assert.deepEqual( - mathNode.Type.isConstant(constNode(-2)), - true); - }); - it("2+2 operator without operator param", () => { - assert.deepEqual( - mathNode.Type.isOperator(math.parse("2+2")), - true); - }); - it("2+2 operator with correct operator param", () => { - assert.deepEqual( - mathNode.Type.isOperator(math.parse("2+2"), "+"), - true); - }); - it("2+2 operator with incorrect operator param", () => { - assert.deepEqual( - mathNode.Type.isOperator(math.parse("2+2"), "-"), - false); - }); - it("-x not operator", () => { - assert.deepEqual( - mathNode.Type.isOperator(math.parse("-x")), - false); - }); - it("-x symbol", () => { - assert.deepEqual( - mathNode.Type.isSymbol(math.parse("-x")), - true); - }); - it("y symbol", () => { - assert.deepEqual( - mathNode.Type.isSymbol(math.parse("y")), - true); - }); - it("abs(5) is abs function", () => { - assert.deepEqual( - mathNode.Type.isFunction(math.parse("abs(5)"), "abs"), - true); - }); - it("sqrt(5) is not abs function", () => { - assert.deepEqual( - mathNode.Type.isFunction(math.parse("sqrt(5)"), "abs"), - false); - }); - // it('nthRoot(4) is an nthRoot function', function () { - // assert.deepEqual( - // mathNode.Type.isFunction(math.parse('nthRoot(5)'), 'nthRoot'), - // true); - // }); -}); - -describe("isConstantOrConstantFraction", () => { - it("2 true", () => { - assert.deepEqual( - mathNode.Type.isConstantOrConstantFraction(math.parse("2")), - true); - }); - it("2/9 true", () => { - assert.deepEqual( - mathNode.Type.isConstantOrConstantFraction(math.parse("4/9")), - true); - }); - it("x/2 false", () => { - assert.deepEqual( - mathNode.Type.isConstantOrConstantFraction(math.parse("x/2")), - false); - }); -}); - -describe("isIntegerFraction", () => { - it("4/5 true", () => { - assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse("4/5")), - true); - }); - it("4.3/5 false", () => { - assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse("4.3/5")), - false); - }); - it("4x/5 false", () => { - assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse("4x/5")), - false); - }); - it("5 false", () => { - assert.deepEqual( - mathNode.Type.isIntegerFraction(math.parse("5")), - false); - }); -}); diff --git a/test/TestUtil.ts b/test/TestUtil.ts deleted file mode 100644 index cee19205..00000000 --- a/test/TestUtil.ts +++ /dev/null @@ -1,52 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import flatten = require("../lib/util/flattenOperands"); -import print = require("../lib/util/print"); - -// TestUtil contains helper methods to share code across tests -const testUtil = {}; - -// Tests a function that takes an input string and check its output -testUtil.testFunctionOutput = (fn, input, output) => { - it(input + " -> " + output, () => { - assert.deepEqual(fn(input),output); - }); -}; - -// tests a function that takes in a node and returns a boolean value -testUtil.testBooleanFunction = (simplifier, exprString, expectedBooleanValue) => { - it(exprString + " " + expectedBooleanValue, () => { - const inputNode = flatten(math.parse(exprString)); - assert.equal(simplifier(inputNode),expectedBooleanValue); - }); -}; - -// Tests a simplification function -testUtil.testSimplification = (simplifyingFunction, exprString, expectedOutputString) => { - it (exprString + " -> " + expectedOutputString, () => { - assert.deepEqual( - print(simplifyingFunction(flatten(math.parse(exprString))).newNode), - expectedOutputString); - }); -}; - -// Test the substeps in the expression -testUtil.testSubsteps = (fn, exprString, outputList, outputStr) => { - it(exprString + " -> " + outputStr, () => { - const status = fn(flatten(math.parse(exprString))); - const substeps = status.substeps; - - assert.deepEqual(substeps.length, outputList.length); - substeps.forEach((step, i) => { - assert.deepEqual( - print(step.newNode), - outputList[i]); - }); - if (outputStr) { - assert.deepEqual( - print(status.newNode), - outputStr); - } - }); -}; -export = testUtil; diff --git a/test/canAddLikeTermPolynomialNodes.test.ts b/test/canAddLikeTermPolynomialNodes.test.ts deleted file mode 100644 index 8ad3ae0a..00000000 --- a/test/canAddLikeTermPolynomialNodes.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import canAddLikeTermPolynomialNodes = require("../lib/checks/canAddLikeTermPolynomialNodes"); -import TestUtil = require("./TestUtil"); - -function testCanBeAdded(expr: any, addable: any); -function testCanBeAdded(expr, addable) { - TestUtil.testBooleanFunction(canAddLikeTermPolynomialNodes, expr, addable); -} - -describe("can add like term polynomials", () => { - const tests = [ - ["x^2 + x^2", true], - ["x + x", true], - ["x^3 + x", false], - ]; - tests.forEach(t => testCanBeAdded(t[0], t[1])); -}); diff --git a/test/canMultiplyLikeTermPolynomialNodes.test.ts b/test/canMultiplyLikeTermPolynomialNodes.test.ts deleted file mode 100644 index 9e1704fa..00000000 --- a/test/canMultiplyLikeTermPolynomialNodes.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import canMultiplyLikeTermPolynomialNodes = require("../lib/checks/canMultiplyLikeTermPolynomialNodes"); -import TestUtil = require("./TestUtil"); - -function testCanBeMultiplied(expr: any, multipliable: any); -function testCanBeMultiplied(expr, multipliable) { - TestUtil.testBooleanFunction(canMultiplyLikeTermPolynomialNodes, expr, multipliable); -} - -describe("can multiply like term polynomials", () => { - const tests = [ - ["x^2 * x * x", true], - ["x^2 * 3x * x", false], - ["y * y^3", true] - ]; - tests.forEach(t => testCanBeMultiplied(t[0], t[1])); -}); diff --git a/test/canRearrangeCoefficient.test.ts b/test/canRearrangeCoefficient.test.ts deleted file mode 100644 index 275ca1e5..00000000 --- a/test/canRearrangeCoefficient.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import canRearrangeCoefficient = require("../lib/checks/canRearrangeCoefficient"); -import TestUtil = require("./TestUtil"); - -function testCanBeRearranged(expr: any, arrangeable: any); -function testCanBeRearranged(expr, arrangeable) { - TestUtil.testBooleanFunction(canRearrangeCoefficient, expr, arrangeable); -} - -describe("can rearrange coefficient", () => { - const tests = [ - ["x*2", true], - ["y^3 * 7", true] - ]; - tests.forEach(t => testCanBeRearranged(t[0], t[1])); -}); diff --git a/test/checks/checks.test.ts b/test/checks/checks.test.ts deleted file mode 100644 index b81a99de..00000000 --- a/test/checks/checks.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import checks = require("../../lib/checks"); -import TestUtil = require("../TestUtil"); - -function testCanCombine(exprStr: any, canCombine: any); -function testCanCombine(exprStr, canCombine) { - TestUtil.testBooleanFunction(checks.canSimplifyPolynomialTerms, exprStr, canCombine); -} - -describe("canSimplifyPolynomialTerms multiplication", () => { - const tests = [ - ["x^2 * x * x", true], - // false b/c coefficient - ["x^2 * 3x * x", false], - ["y * y^3", true], - ["5 * y^3", false], // just needs flattening - ["5/7 * x", false], // just needs flattening - ["5/7 * 9 * x", false], - ]; - tests.forEach(t => testCanCombine(t[0], t[1])); -}); - - -describe("canSimplifyPolynomialTerms addition", () => { - const tests = [ - ["x + x", true], - ["4y^2 + 7y^2 + y^2", true], - ["4y^2 + 7y^2 + y^2 + y", false], - ["y", false], - ]; - tests.forEach(t => testCanCombine(t[0], t[1])); -}); diff --git a/test/checks/hasUnsupportedNodes.test.ts b/test/checks/hasUnsupportedNodes.test.ts deleted file mode 100644 index 7641ad34..00000000 --- a/test/checks/hasUnsupportedNodes.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import checks = require("../../lib/checks"); -describe("arithmetic stepping", () => { - it("4 + sqrt(16) no support for sqrt", () => { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse("4 + sqrt(4)")), - true); - }); - - it("x = 5 no support for assignment", () => { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse("x = 5")), - true); - }); - - it("x + (-5)^2 - 8*y/2 is fine", () => { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse("x + (-5)^2 - 8*y/2")), - false); - }); - - it("nthRoot() with no args has no support", () => { - assert.deepEqual( - checks.hasUnsupportedNodes(math.parse("nthRoot()")), - true); - }); -}); diff --git a/test/checks/isQuadratic.test.ts b/test/checks/isQuadratic.test.ts deleted file mode 100644 index 91bc0f93..00000000 --- a/test/checks/isQuadratic.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import checks = require("../../lib/checks"); -import TestUtil = require("../TestUtil"); - -function testIsQuadratic(input: any, output: any); -function testIsQuadratic(input, output) { - TestUtil.testBooleanFunction(checks.isQuadratic, input, output); -} - -describe("isQuadratic", () => { - const tests = [ - ["2 + 2", false], - ["x", false], - ["x^2 - 4", true], - ["x^2 + 2x + 1", true], - ["x^2 - 2x + 1", true], - ["x^2 + 3x + 2", true], - ["x^2 - 3x + 2", true], - ["x^2 + x - 2", true], - ["x^2 + x", true], - ["x^2 + 4", true], - ["x^2 + 4x + 1", true], - ["x^2", false], - ["x^3 + x^2 + x + 1", false], - ["x^2 + 4 + 2^x", false], - ["x^2 + 4 + 2y", false], - ["y^2 + 4 + 2x", false], - ]; - tests.forEach(t => testIsQuadratic(t[0], t[1])); -}); diff --git a/test/checks/resolvesToConstant.test.ts b/test/checks/resolvesToConstant.test.ts deleted file mode 100644 index 1e54c751..00000000 --- a/test/checks/resolvesToConstant.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import checks = require("../../lib/checks"); -import TestUtil = require("../TestUtil"); - -function testResolvesToConstant(exprString: any, resolves: any); -function testResolvesToConstant(exprString, resolves) { - TestUtil.testBooleanFunction(checks.resolvesToConstant, exprString, resolves); -} - -describe("resolvesToConstant", () => { - const tests = [ - ["(2+2)", true], - ["10", true], - ["((2^2 + 4)) * 7 / 8", true], - ["2 * 3^x", false], - ["-(2) * -3", true], - ]; - tests.forEach(t => testResolvesToConstant(t[0], t[1])); -}); diff --git a/test/equation.test.ts b/test/equation.test.ts deleted file mode 100644 index eb517807..00000000 --- a/test/equation.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import Equation = require("../lib/equation/Equation"); - -function constructAndPrintEquation(left: any, right: any, comp: any); -function constructAndPrintEquation(left, right, comp) { - const leftNode = math.parse(left); - const rightNode = math.parse(right); - const equation = new Equation(leftNode, rightNode, comp); - return equation.print(); -} - -function testEquationConstructor(left: any, right: any, comp: any, output: any); -function testEquationConstructor(left, right, comp, output) { - it (output, () => { - assert.equal( - constructAndPrintEquation(left, right, comp), output - ); - }); -} - -describe("Equation constructor", () => { - const tests = [ - ["2*x^2 + x", "4", "=", "2x^2 + x = 4"], - ["x^2 + 2*x + 2", "0", ">=", "x^2 + 2x + 2 >= 0"], - ["2*x - 1", "0", "<=", "2x - 1 <= 0"] - ]; - tests.forEach(t => testEquationConstructor(t[0], t[1], t[2], t[3])); -}); diff --git a/test/factor/ConstantFactors.test.ts b/test/factor/ConstantFactors.test.ts deleted file mode 100644 index adb5dcf5..00000000 --- a/test/factor/ConstantFactors.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import ConstantFactors = require("../../lib/factor/ConstantFactors"); -import TestUtil = require("../TestUtil"); - -function testPrimeFactors(input: any, output: any); -function testPrimeFactors(input, output) { - TestUtil.testFunctionOutput(ConstantFactors.getPrimeFactors, input, output); -} - -describe("prime factors", () => { - const tests = [ - [1, [1]], - [-1, [-1, 1]], - [-2, [-1, 2]], - [5, [5]], - [12, [2, 2, 3]], - [15, [3, 5]], - [36, [2, 2, 3, 3]], - [49, [7, 7]], - [1260, [2, 2, 3, 3, 5, 7]], - [13195, [5, 7, 13, 29]], - [1234567891, [1234567891]] - ]; - tests.forEach(t => testPrimeFactors(t[0], t[1])); -}); - -function testFactorPairs(input: any, output: any); -function testFactorPairs(input, output) { - TestUtil.testFunctionOutput(ConstantFactors.getFactorPairs, input, output); -} - -describe("factor pairs", () => { - const tests = [ - [1, [[-1, -1], [1, 1]]], - [5, [[-1, -5], [1, 5]]], - [12, [[-3, -4], [-2, -6], [-1, -12], [1, 12], [2, 6], [3, 4]]], - [-12, [[-3, 4], [-2, 6], [-1, 12], [1, -12], [2, -6], [3, -4]]], - [15, [[-3, -5], [-1, -15], [1, 15], [3, 5]]], - [36, [[-6, -6], [-4, -9], [-3, -12], [-2, -18], [-1, -36], [1, 36], [2, 18], [3, 12], [4, 9], [6, 6,]]], - [49, [[-7, -7], [-1, -49], [1, 49], [7, 7]]], - [1260, [[-35, -36], [-30, -42], [-28, -45], [-21, -60], [-20, -63], [-18, -70], [-15, -84], [-14, -90], [-12, -105], [-10, -126], [-9, -140], [-7, -180], [-6, -210], [-5, -252], [-4, -315], [-3, -420], [-2, -630], [-1, -1260], [1, 1260], [2, 630], [3, 420], [4, 315], [5, 252], [6, 210], [7, 180], [9, 140], [10, 126], [12, 105], [14, 90], [15, 84], [18, 70], [20, 63], [21, 60], [28, 45], [30, 42], [35, 36]]], - [13195, [[-91, -145], [-65, -203], [-35, -377], [-29, -455], [-13, -1015], [-7, -1885], [-5, -2639], [-1, -13195], [1, 13195], [5, 2639], [7, 1885], [13, 1015], [29, 455], [35, 377], [65, 203], [91, 145]]], - [1234567891, [[-1, -1234567891], [1, 1234567891]]] - ]; - tests.forEach(t => testFactorPairs(t[0], t[1])); -}); diff --git a/test/factor/factorQuadratic.test.ts b/test/factor/factorQuadratic.test.ts deleted file mode 100644 index 19ca4b1e..00000000 --- a/test/factor/factorQuadratic.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import factorQuadratic = require("../../lib/factor/factorQuadratic"); -import TestUtil = require("../TestUtil"); - -function testFactorQuadratic(input: any, output: any); -function testFactorQuadratic(input, output) { - TestUtil.testSimplification(factorQuadratic, input, output); -} - -describe("factorQuadratic", () => { - const tests = [ - ["x^2", "x^2"], - ["x^2 + x^2", "x^2 + x^2"], - ["x^2 + 2 - 3", "x^2 + 2 - 3"], - ["x^2 + 2y + 2x + 3", "x^2 + 2y + 2x + 3"], - ["x^2 + 2x", "x * (x + 2)"], - ["-x^2 - 2x", "-x * (x + 2)"], - ["x^2 - 3x", "x * (x - 3)"], - ["2x^2 + 2x", "2x * (x + 1)"], - ["x^2 - 4", "(x + 2) * (x - 2)"], - ["x^2 + 4", "x^2 + 4"], - ["x^2 + 2x + 1", "(x + 1)^2"], - ["x^2 - 2x + 1", "(x - 1)^2"], - ["x^2 + 3x + 2", "(x + 1) * (x + 2)"], - ["x^2 - 3x + 2", "(x - 1) * (x - 2)"], - ["x^2 + x - 2", "(x - 1) * (x + 2)"], - ["x^2 + 4x + 1", "x^2 + 4x + 1"], - ["x^2 - 3x + 1", "x^2 - 3x + 1"], - ["x^2 + 4 + 2^x", "x^2 + 4 + 2^x"], - ["-x^2 - 2x - 1", "-(x + 1)^2"], - ["-x^2 - 3x - 2", "-(x + 1) * (x + 2)"], - ["-x^2 + 1", "-(x + 1) * (x - 1)"], - ["-x^2 - 1", "-x^2 - 1"], - ]; - tests.forEach(t => testFactorQuadratic(t[0], t[1])); -}); diff --git a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts deleted file mode 100644 index 487dd7fb..00000000 --- a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import arithmeticSearch = require("../../../lib/simplifyExpression/arithmeticSearch"); -import TestUtil = require("../../TestUtil"); - -function testArithmeticSearch(exprStr: any, outputStr: any); -function testArithmeticSearch(exprStr, outputStr) { - TestUtil.testSimplification(arithmeticSearch, exprStr, outputStr); -} - -describe("evaluate arithmeticSearch", () => { - const tests = [ - ["2+2", "4"], - ["2*3*5", "30"], - ["9/4", "9/4"], // does not divide - ]; - tests.forEach(t => testArithmeticSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts deleted file mode 100644 index 19632507..00000000 --- a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import rearrangeCoefficient = require("../../../lib/simplifyExpression/basicsSearch/rearrangeCoefficient"); -import testSimplify = require("./testSimplify"); -describe("rearrangeCoefficient", () => { - const tests = [ - ["2 * x^2", "2x^2"], - ["y^3 * 5", "5y^3"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], rearrangeCoefficient)); -}); diff --git a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts deleted file mode 100644 index 78beb915..00000000 --- a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import reduceExponentByZero = require("../../../lib/simplifyExpression/basicsSearch/reduceExponentByZero"); -import testSimplify = require("./testSimplify"); -describe("reduceExponentByZero", () => { - testSimplify("(x+3)^0", "1", reduceExponentByZero); -}); diff --git a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts deleted file mode 100644 index 2c2f3a28..00000000 --- a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import reduceMultiplicationByZero = require("../../../lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero"); -import testSimplify = require("./testSimplify"); -describe("reduce multiplication by 0", () => { - const tests = [ - ["0x", "0"], - ["2*0*z^2","0"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], reduceMultiplicationByZero)); -}); diff --git a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts deleted file mode 100644 index ee9f1baf..00000000 --- a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import reduceZeroDividedByAnything = require("../../../lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything"); -import testSimplify = require("./testSimplify"); -describe("simplify basics", () => { - const tests = [ - ["0/5", "0"], - ["0/(x+6+7+x^2+2^y)", "0"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], reduceZeroDividedByAnything)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts deleted file mode 100644 index cd8416cc..00000000 --- a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import removeAdditionOfZero = require("../../../lib/simplifyExpression/basicsSearch/removeAdditionOfZero"); -import testSimplify = require("./testSimplify"); -describe("removeAdditionOfZero", () => { - var tests = [ - ["2+0+x", "2 + x"], - ["2+x+0", "2 + x"], - ["0+2+x", "2 + x"] - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeAdditionOfZero)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts deleted file mode 100644 index e86cf27e..00000000 --- a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import removeDivisionByOne = require("../../../lib/simplifyExpression/basicsSearch/removeDivisionByOne"); -import testSimplify = require("./testSimplify"); -describe("removeDivisionByOne", () => { - testSimplify("x/1", "x", removeDivisionByOne); -}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts deleted file mode 100644 index 09fed31a..00000000 --- a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import removeExponentBaseOne = require("../../../lib/simplifyExpression/basicsSearch/removeExponentBaseOne"); -import testSimplify = require("./testSimplify"); -describe("removeExponentBaseOne", () => { - const tests = [ - ["1^3", "1"], - ["1^x", "1^x"], - ["1^(2 + 3 + 5/4 + 7 - 6/7)", "1"] - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeExponentBaseOne)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts deleted file mode 100644 index 8680afed..00000000 --- a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import removeExponentByOne = require("../../../lib/simplifyExpression/basicsSearch/removeExponentByOne"); -import testSimplify = require("./testSimplify"); -describe("removeExponentByOne", () => { - testSimplify("x^1", "x", removeExponentByOne); -}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts deleted file mode 100644 index 0e0e5fff..00000000 --- a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import removeMultiplicationByNegativeOne = require("../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne"); -import testSimplify = require("./testSimplify"); -describe("removeMultiplicationByNegativeOne", () => { - const tests = [ - ["-1*x", "-x"], - ["x^2*-1", "-x^2"], - ["2x*2*-1", "2x * 2 * -1"], // does not remove multiplication by -1 - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByNegativeOne)); -}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts deleted file mode 100644 index 8f1e38a3..00000000 --- a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import removeMultiplicationByOne = require("../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByOne"); -import testSimplify = require("./testSimplify"); -describe("removeMultiplicationByOne", () => { - const tests = [ - ["x*1", "x"], - ["1x", "x"], - ["1*z^2", "z^2"], - ["2*1*z^2", "2 * 1z^2"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByOne)); -}); diff --git a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts deleted file mode 100644 index 5e2da1b5..00000000 --- a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import simplifyDoubleUnaryMinus = require("../../../lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus"); -import testSimplify = require("./testSimplify"); -describe("simplifyDoubleUnaryMinus", () => { - var tests = [ - ["--5", "5"], - ["--x", "x"] - ]; - tests.forEach(t => testSimplify(t[0], t[1], simplifyDoubleUnaryMinus)); -}); diff --git a/test/simplifyExpression/basicsSearch/testSimplify.ts b/test/simplifyExpression/basicsSearch/testSimplify.ts deleted file mode 100644 index efee4364..00000000 --- a/test/simplifyExpression/basicsSearch/testSimplify.ts +++ /dev/null @@ -1,17 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import flatten = require("../../../lib/util/flattenOperands"); -import print = require("../../../lib/util/print"); - -function testSimplify(exprStr: any, outputStr: any, simplifyOperation: any); -function testSimplify(exprStr, outputStr, simplifyOperation) { - it(exprStr + " -> " + outputStr, () => { - const inputNode = flatten(math.parse(exprStr)); - const newNode = simplifyOperation(inputNode).newNode; - assert.equal( - print(newNode), - outputStr); - }); -} - -export = testSimplify; diff --git a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts deleted file mode 100644 index 643dab7f..00000000 --- a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import breakUpNumeratorSearch = require("../../../lib/simplifyExpression/breakUpNumeratorSearch"); -import TestUtil = require("../../TestUtil"); - -function testBreakUpNumeratorSearch(exprStr: any, outputStr: any); -function testBreakUpNumeratorSearch(exprStr, outputStr) { - TestUtil.testSimplification(breakUpNumeratorSearch, exprStr, outputStr); -} - -describe("breakUpNumerator", () => { - const tests = [ - ["(x+3+y)/3", "(x / 3 + 3/3 + y / 3)"], - ["(2+x)/4", "(2/4 + x / 4)"], - ["2(x+3)/3", "2 * (x / 3 + 3/3)"], - ]; - tests.forEach(t => testBreakUpNumeratorSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts deleted file mode 100644 index 2ed30322..00000000 --- a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import flatten = require("../../../lib/util/flattenOperands"); -import print = require("../../../lib/util/print"); -import LikeTermCollector = require("../../../lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector"); - -function testCollectLikeTerms(exprStr, outputStr, explanation="", debug=false) { - let description = `${exprStr} -> ${outputStr}`; - - if (explanation) { - description += ` (${explanation})`; - } - - it(description, () => { - const exprTree = flatten(math.parse(exprStr)); - const collected = print(LikeTermCollector.collectLikeTerms(exprTree).newNode); - if (debug) { - // eslint-disable-next-line - console.log(collected); - } - assert.equal(collected, outputStr); - }); -} - -function testCanCollectLikeTerms(exprStr: any, canCollect: any, explanation: any); -function testCanCollectLikeTerms(exprStr, canCollect, explanation) { - let description = `${exprStr} -> ${canCollect}`; - - if (explanation) { - description += ` (${explanation})`; - } - - it(description , () => { - const exprTree = flatten(math.parse(exprStr)); - assert.equal( - LikeTermCollector.canCollectLikeTerms(exprTree), - canCollect); - }); -} - -describe("can collect like terms for addition", () => { - const tests = [ - ["2+2", false, "because only one type"], - ["x^2+x^2", false, "because only one type"], - ["x+2", false, "because all types have only one"], - ["(x+2+x)", false, "because in parenthesis, need to be collected first"], - ["x+2+x", true], - ["x^2 + 5 + x + x^2", true], - ]; - tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe("can collect like terms for multiplication", () => { - const tests = [ - ["2*2", false, "because only one type"], - ["x^2 * 2x^2", true], - ["x * 2", false, "because all types have only one"], - ["((2x^2)) * y * x * y^3", true], - ]; - tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe("basic addition collect like terms, no exponents or coefficients", () => { - const tests = [ - ["2+x+7", "x + (2 + 7)"], - ["x + 4 + x + 5", "(x + x) + (4 + 5)"], - ["x + 4 + y", "x + 4 + y"], - ["x + 4 + x + 4/9 + y + 5/7", "(x + x) + y + 4 + (4/9 + 5/7)"], - ["x + 4 + x + 2^x + 5", "(x + x) + (4 + 5) + 2^x", - "because 2^x is an 'other'"], - ["z + 2*(y + x) + 4 + z", "(z + z) + 4 + 2 * (y + x)", - "2*(y + x) is an 'other' cause it has parens"], - ]; - tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe("collect like terms with exponents and coefficients", () => { - const tests = [ - ["x^2 + x + x^2 + x", "(x^2 + x^2) + (x + x)"], - ["y^2 + 5 + y^2 + 5", "(y^2 + y^2) + (5 + 5)"], - ["y + 5 + z^2", "y + 5 + z^2"], - ["2x^2 + x + x^2 + 3x", "(2x^2 + x^2) + (x + 3x)"], - ]; - tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); -}); - -describe("collect like terms for multiplication", () => { - const tests = [ - ["2x^2 * y * x * y^3", "2 * (x^2 * x) * (y * y^3)"], - ["y^2 * 5 * y * 9", "(5 * 9) * (y^2 * y)"], - ["5y^2 * -4y * 9", "(5 * -4 * 9) * (y^2 * y)"], - ["5y^2 * -y * 9", "(5 * -1 * 9) * (y^2 * y)"], - ["y * 5 * (2+x) * y^2 * 1/3", "(5 * 1/3) * (y * y^2) * (2 + x)"], - ]; - tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); -}); diff --git a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts deleted file mode 100644 index 626042fb..00000000 --- a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import collectAndCombineSearch = require("../../../lib/simplifyExpression/collectAndCombineSearch"); -import TestUtil = require("../../TestUtil"); - -function testCollectAndCombineSubsteps(exprString: any, outputList: any, outputStr: any); -function testCollectAndCombineSubsteps(exprString, outputList, outputStr) { - TestUtil.testSubsteps(collectAndCombineSearch, exprString, outputList, outputStr); -} - -function testSimpleCollectAndCombineSearch(exprString: any, outputStr: any); -function testSimpleCollectAndCombineSearch(exprString, outputStr) { - TestUtil.testSimplification(collectAndCombineSearch, exprString, outputStr); -} - -describe("combinePolynomialTerms multiplication", () => { - const tests = [ - ["x^2 * x * x", - ["x^2 * x^1 * x^1", - "x^(2 + 1 + 1)", - "x^4"], - ], - ["y * y^3", - ["y^1 * y^3", - "y^(1 + 3)", - "y^4"], - ], - ["2x * x^2 * 5x", - ["(2 * 5) * (x * x^2 * x)", - "10 * (x * x^2 * x)", - "10x^4"], - "10x^4" - ], - ]; - tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1], t[2])); -}); - -describe("combinePolynomialTerms addition", () => { - const tests = [ - ["x+x", - ["1x + 1x", - "(1 + 1) * x", - "2x"] - ], - ["4y^2 + 7y^2 + y^2", - ["4y^2 + 7y^2 + 1y^2", - "(4 + 7 + 1) * y^2", - "12y^2"] - ], - ["2x + 4x + y", - ["(2x + 4x) + y", - "6x + y"], - "6x + y" - ], - ]; - tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1])); -}); - -describe("collectAndCombineSearch with no substeps", () => { - const tests = [ - ["2x + 4x + x", "7x"], - ["x * x^2 * x", "x^4"] - ]; - tests.forEach(t => testSimpleCollectAndCombineSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts deleted file mode 100644 index 43505736..00000000 --- a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import evaluateConstantSum = require("../../../lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum"); -import TestUtil = require("../../TestUtil"); - -function testEvaluateConstantSum(exprString: any, outputList: any); -function testEvaluateConstantSum(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(evaluateConstantSum, exprString, outputList, lastString); -} - -describe("evaluateConstantSum", () => { - const tests = [ - ["4/10 + 3/5", - ["4/10 + (3 * 2) / (5 * 2)", - "4/10 + (3 * 2) / 10", - "4/10 + 6/10", - "(4 + 6) / 10", - "10/10", - "1"] - ], - ["4/5 + 3/5 + 2", - ["2 + (4/5 + 3/5)", - "2 + 7/5", - "17/5"] - ], - ["9 + 4/5 + 1/5 + 2", - ["(9 + 2) + (4/5 + 1/5)", - "11 + (4/5 + 1/5)", - "11 + 1", - "12"] - ], - ]; - tests.forEach(t => testEvaluateConstantSum(t[0], t[1])); -}); diff --git a/test/simplifyExpression/distributeSearch/distributeSearch.test.ts b/test/simplifyExpression/distributeSearch/distributeSearch.test.ts deleted file mode 100644 index 20d9e65c..00000000 --- a/test/simplifyExpression/distributeSearch/distributeSearch.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import distributeSearch = require("../../../lib/simplifyExpression/distributeSearch"); -import TestUtil = require("../../TestUtil"); - -function testDistribute(exprStr: any, outputStr: any); -function testDistribute(exprStr, outputStr) { - TestUtil.testSimplification(distributeSearch, exprStr, outputStr); -} - -describe("distribute - into paren with addition", () => { - const tests = [ - ["-(x+3)", "(-x - 3)"], - ["-(x - 3)", "(-x + 3)"], - ["-(-x^2 + 3y^6)" , "(x^2 - 3y^6)"], - ]; - tests.forEach(t => testDistribute(t[0], t[1])); -}); - -describe("distribute - into paren with multiplication/division", () => { - const tests = [ - ["-(x*3)", "(-x * 3)"], - ["-(-x * 3)", "(x * 3)"], - ["-(-x^2 * 3y^6)", "(x^2 * 3y^6)"], - ]; - tests.forEach(t => testDistribute(t[0], t[1])); -}); - -function testDistributeSteps(exprString: any, outputList: any); -function testDistributeSteps(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(distributeSearch, exprString, outputList, lastString); -} - -describe("distribute", () => { - const tests = [ - ["x*(x+2+y)", - ["(x * x + x * 2 + x * y)", - "(x^2 + 2x + x * y)"] - ], - ["(x+2+y)*x*7", - ["(x * x + 2x + y * x) * 7", - "(x^2 + 2x + y * x) * 7"] - ], - ["(5+x)*(x+3)", - ["(5 * (x + 3) + x * (x + 3))", - "((5x + 15) + (x^2 + 3x))"] - ], - ["-2x^2 * (3x - 4)", - ["(-2x^2 * 3x - 2x^2 * -4)", - "(-6x^3 + 8x^2)"] - ], - ]; - tests.forEach(t => testDistributeSteps(t[0], t[1])); -}); - -describe("distribute with fractions", () => { - const tests = [ - // distribute the non-fraction term into the numerator(s) - ["(3 / x^2 + x / (x^2 + 3)) * (x^2 + 3)", - "((3 * (x^2 + 3)) / (x^2) + (x * (x^2 + 3)) / (x^2 + 3))", - ], - - // if both groupings have fraction, the rule does not apply - ["(3 / x^2 + x / (x^2 + 3)) * (5 / x + x^5)", - "((3 / (x^2) * 5 / x + 3 / (x^2) * x^5) + (x / (x^2 + 3) * 5 / x + x / (x^2 + 3) * x^5))", - ], - ]; - - const multiStepTests = [ - - ["(2 / x + 3x^2) * (x^3 + 1)", - ["((2 * (x^3 + 1)) / x + 3x^2 * (x^3 + 1))", - "((2 * (x^3 + 1)) / x + (3x^5 + 3x^2))"] - ], - - ["(2x + x^2) * (1 / (x^2 -4) + 4x^2)", - ["((1 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))", - "((1 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))"] - ], - - ["(2x + x^2) * (3x^2 / (x^2 -4) + 4x^2)", - ["((3x^2 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))", - "((3x^2 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))"] - ], - - ]; - - tests.forEach(t => testDistribute(t[0], t[1])); - - multiStepTests.forEach(t => testDistributeSteps(t[0], t[1])); -}); diff --git a/test/simplifyExpression/divisionSearch/divisionSearch.test.ts b/test/simplifyExpression/divisionSearch/divisionSearch.test.ts deleted file mode 100644 index e5916155..00000000 --- a/test/simplifyExpression/divisionSearch/divisionSearch.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import divisionSearch = require("../../../lib/simplifyExpression/divisionSearch"); -import TestUtil = require("../../TestUtil"); - -function testSimplifyDivision(exprStr: any, outputStr: any); -function testSimplifyDivision(exprStr, outputStr) { - TestUtil.testSimplification(divisionSearch, exprStr, outputStr); -} - -describe("simplifyDivision", () => { - const tests = [ - ["6/x/5", "6 / (x * 5)"], - ["-(6/x/5)", "-(6 / (x * 5))"], - ["-6/x/5", "-6 / (x * 5)"], - ["(2+2)/x/6/(y-z)","(2 + 2) / (x * 6 * (y - z))"], - ["2/x", "2 / x"], - ["x/(2/3)", "x * 3/2"], - ["x / (y/(z+a))", "x * (z + a) / y"], - ["x/((2+z)/(3/y))", "x * (3 / y) / (2 + z)"], - ]; - tests.forEach(t => testSimplifyDivision(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts deleted file mode 100644 index 013c92a2..00000000 --- a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import addConstantAndFraction = require("../../../lib/simplifyExpression/fractionsSearch/addConstantAndFraction"); -import TestUtil = require("../../TestUtil"); - -function testAddConstantAndFraction(exprString: any, outputList: any); -function testAddConstantAndFraction(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(addConstantAndFraction, exprString, outputList, lastString); -} - -describe("addConstantAndFraction", () => { - const tests = [ - ["7 + 1/2", - ["14/2 + 1/2", - "(14 + 1) / 2", - "15/2"] - ], - ["5/6 + 3", - ["5/6 + 18/6", - "(5 + 18) / 6", - "23/6"], - ], - ["1/2 + 5.8", - ["0.5 + 5.8", - "6.3"], - ], - ["1/3 + 5.8", - ["0.3333 + 5.8", - "6.1333"] - ], - ]; - tests.forEach(t => testAddConstantAndFraction(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts deleted file mode 100644 index 75ae3531..00000000 --- a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import addConstantFractions = require("../../../lib/simplifyExpression/fractionsSearch/addConstantFractions"); -import TestUtil = require("../../TestUtil"); - -function testAddConstantFractions(exprString: any, outputList: any); -function testAddConstantFractions(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(addConstantFractions, exprString, outputList, lastString); -} - -describe("addConstantFractions", () => { - const tests = [ - ["4/5 + 3/5", - ["(4 + 3) / 5", - "7/5"] - ], - ["4/10 + 3/5", - ["4/10 + (3 * 2) / (5 * 2)", - "4/10 + (3 * 2) / 10", - "4/10 + 6/10", - "(4 + 6) / 10", - "10/10", - "1"] - ], - ["4/9 + 3/5", - ["(4 * 5) / (9 * 5) + (3 * 9) / (5 * 9)", - "(4 * 5) / 45 + (3 * 9) / 45", - "20/45 + 27/45", - "(20 + 27) / 45", - "47/45"] - ], - ["4/5 - 4/5", - ["(4 - 4) / 5", - "0/5", - "0"] - ], - ]; - tests.forEach(t => testAddConstantFractions(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts deleted file mode 100644 index a55650c4..00000000 --- a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import cancelLikeTerms = require("../../../lib/simplifyExpression/fractionsSearch/cancelLikeTerms"); -import TestUtil = require("../../TestUtil"); - -function testCancelLikeTerms(exprStr: any, expectedStr: any); -function testCancelLikeTerms(exprStr, expectedStr) { - TestUtil.testSimplification(cancelLikeTerms, exprStr, expectedStr); -} - -describe("cancel like terms", () => { - const tests = [ - ["2/2", "1"], - ["x^2/x^2", "1"], - ["x^3/x^2", "x^(3 - (2))"], // parens will be removed at end of step - ["(x^3*y)/x^2", "(x^(3 - (2)) * y)"], - ["-(7+x)^8/(7+x)^2", "-((7 + x)^(8 - (2)))"], - ["(2x^2 * 5) / (2x^2)", "5"], // these parens have to stay around 2x^2 to be parsed correctly. - ["(x^2 * y) / x", "(x^(2 - (1)) * y)"], - ["2x^2 / (2x^2 * 5)", "1/5"], - ["x / (x^2*y)", "x^(1 - (2)) / y"], - ["(4x^2) / (5x^2)", "(4) / (5)"], - ["(2x+5)^8 / (2x+5)^2", "(2x + 5)^(8 - (2))"], - ["(4x^3) / (5x^2)", "(4x^(3 - (2))) / (5)"], - ["-x / -x", "1"], - ]; - - tests.forEach(t => { - const before = t[0]; - const after = t[1]; - it(before + " -> " + after, () => { - testCancelLikeTerms(before, after); - }); - }); -}); diff --git a/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts b/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts deleted file mode 100644 index 2a6f3ace..00000000 --- a/test/simplifyExpression/fractionsSearch/divideByGCD.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import divideByGCD = require("../../../lib/simplifyExpression/fractionsSearch/divideByGCD"); -import TestUtil = require("../../TestUtil"); - -function testdivideByGcd(exprStr: any, outputStr: any); -function testdivideByGcd(exprStr, outputStr) { - TestUtil.testSimplification(divideByGCD, exprStr, outputStr); -} - -describe("simplifyFraction", () => { - const tests = [ - ["2/4", "1/2"], - ["9/3", "3"], - ["12/27", "4/9"], - ["1/-3", "-1/3"], - ["-3/-2", "3/2"], - ["-1/-1", "1"], - ]; - tests.forEach(t => testdivideByGcd(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts deleted file mode 100644 index 845dfe08..00000000 --- a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import simplifyFractionSigns = require("../../../lib/simplifyExpression/fractionsSearch/simplifyFractionSigns"); -import TestUtil = require("../../TestUtil"); - -function testSimplifyFractionSigns(exprStr: any, outputStr: any); -function testSimplifyFractionSigns(exprStr, outputStr) { - TestUtil.testSimplification(simplifyFractionSigns, exprStr, outputStr); -} - -describe("simplify signs", () => { - const tests = [ - ["-12x / -27", "12x / 27"], - ["x / -y", "-x / y"], - ]; - tests.forEach(t => testSimplifyFractionSigns(t[0], t[1])); -}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts deleted file mode 100644 index 5d7e5581..00000000 --- a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import simplifyPolynomialFraction = require("../../../lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction"); -import TestUtil = require("../../TestUtil"); - -function testSimplifyPolynomialFraction(exprStr: any, outputStr: any); -function testSimplifyPolynomialFraction(exprStr, outputStr) { - TestUtil.testSimplification(simplifyPolynomialFraction, exprStr, outputStr); -} - -describe("simplifyPolynomialFraction", () => { - const tests = [ - ["2x/4", "1/2 x"], - ["9y/3", "3y"], - ["y/-3", "-1/3 y"], - ["-3y/-2", "3/2 y"], - ["-y/-1", "y"], - ["12z^2/27", "4/9 z^2"], - ["1.6x / 1.6", "x"], - ]; - tests.forEach(t => testSimplifyPolynomialFraction(t[0], t[1])); -}); diff --git a/test/simplifyExpression/functionsSearch/absoluteValue.test.ts b/test/simplifyExpression/functionsSearch/absoluteValue.test.ts deleted file mode 100644 index b62cc5dd..00000000 --- a/test/simplifyExpression/functionsSearch/absoluteValue.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import absoluteValue = require("../../../lib/simplifyExpression/functionsSearch/absoluteValue"); -import TestUtil = require("../../TestUtil"); - -function testAbsoluteValue(exprString: any, outputStr: any); -function testAbsoluteValue(exprString, outputStr) { - TestUtil.testSimplification(absoluteValue, exprString, outputStr); -} - -describe("abs", () => { - const tests = [ - ["abs(4)", "4"], - ["abs(-5)", "5"], - ]; - tests.forEach(t => testAbsoluteValue(t[0], t[1])); -}); diff --git a/test/simplifyExpression/functionsSearch/nthRoot.test.ts b/test/simplifyExpression/functionsSearch/nthRoot.test.ts deleted file mode 100644 index d0c2766f..00000000 --- a/test/simplifyExpression/functionsSearch/nthRoot.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import nthRoot = require("../../../lib/simplifyExpression/functionsSearch/nthRoot"); -import TestUtil = require("../../TestUtil"); - -function testNthRoot(exprString: any, outputStr: any); -function testNthRoot(exprString, outputStr) { - TestUtil.testSimplification(nthRoot, exprString, outputStr); -} - -describe("simplify nthRoot", () => { - const tests = [ - ["nthRoot(4)", "2"], - ["nthRoot(8, 3)", "2"], - ["nthRoot(5 * 7)", "nthRoot(5 * 7)"], - ["nthRoot(4, 3)", "nthRoot(4, 3)"], - ["nthRoot(12)", "2 * nthRoot(3, 2)"], - ["nthRoot(36)", "6"], - ["nthRoot(72)", "2 * 3 * nthRoot(2, 2)"], - ["nthRoot(x^2)", "x"], - ["nthRoot(x ^ 3)", "nthRoot(x ^ 3)"], - ["nthRoot(x^3, 3)", "x"], - ["nthRoot(-2)", "nthRoot(-2)"], - ["nthRoot(2 ^ x, x)", "2"], - ["nthRoot(x ^ (1/2), 1/2)", "x"], - ["nthRoot(2 * 2, 2)", "2"], - ["nthRoot(3 * 2 * 3 * 2, 2)", "2 * 3"], - ["nthRoot(36*x)", "2 * 3 * nthRoot(x, 2)"], - ["nthRoot(2 * 18 * x ^ 2, 2)", "2 * 3 * x"], - ["nthRoot(x * x, 2)", "x"], - ["nthRoot(x * x * (2 + 3), 2)", "x * nthRoot((2 + 3), 2)"], - ]; - tests.forEach(t => testNthRoot(t[0], t[1])); -}); - -function testNthRootSteps(exprString: any, outputList: any); -function testNthRootSteps(exprString, outputList) { - const lastString = outputList[outputList.length - 1]; - TestUtil.testSubsteps(nthRoot, exprString, outputList, lastString); -} - -describe("nthRoot steps", () => { - const tests = [ - ["nthRoot(12)", - ["nthRoot(2 * 2 * 3)", - "nthRoot((2 * 2) * 3)", - "nthRoot(2 ^ 2 * 3)", - "nthRoot(2 ^ 2, 2) * nthRoot(3, 2)", - "2 * nthRoot(3, 2)"] - ], - ["nthRoot(72)", - ["nthRoot(2 * 2 * 2 * 3 * 3)", - "nthRoot((2 * 2) * 2 * (3 * 3))", - "nthRoot(2 ^ 2 * 2 * 3 ^ 2)", - "nthRoot(2 ^ 2, 2) * nthRoot(2, 2) * nthRoot(3 ^ 2, 2)", - "2 * nthRoot(2, 2) * 3", - "2 * 3 * nthRoot(2, 2)"] - ], - ["nthRoot(36*x)", - ["nthRoot(2 * 2 * 3 * 3 * x)", - "nthRoot((2 * 2) * (3 * 3) * x)", - "nthRoot(2 ^ 2 * 3 ^ 2 * x)", - "nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x, 2)", - "2 * 3 * nthRoot(x, 2)"] - ], - ["nthRoot(2 * 18 * x ^ 2, 2)", - ["nthRoot(2 * 2 * 3 * 3 * x ^ 2, 2)", - "nthRoot((2 * 2) * (3 * 3) * x ^ 2, 2)", - "nthRoot(2 ^ 2 * 3 ^ 2 * x ^ 2, 2)", - "nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x ^ 2, 2)", - "2 * 3 * x"] - ] - ]; - tests.forEach(t => testNthRootSteps(t[0], t[1])); -}); diff --git a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts deleted file mode 100644 index b44f8d8e..00000000 --- a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import multiplyFractionsSearch = require("../../../lib/simplifyExpression//multiplyFractionsSearch"); -import TestUtil = require("../../TestUtil"); - -function testMultiplyFractionsSearch(exprString: any, outputStr: any); -function testMultiplyFractionsSearch(exprString, outputStr) { - TestUtil.testSimplification(multiplyFractionsSearch, exprString, outputStr); -} - -describe("multiplyFractions", () => { - const tests = [ - ["3 * 1/5 * 5/9", "(3 * 1 * 5) / (5 * 9)"], - ["3/7 * 10/11", "(3 * 10) / (7 * 11)"], - ["2 * 5/x", "(2 * 5) / x"] - ]; - tests.forEach(t => testMultiplyFractionsSearch(t[0], t[1])); -}); diff --git a/test/simplifyExpression/oneStep.test.ts b/test/simplifyExpression/oneStep.test.ts deleted file mode 100644 index 4e00c1bc..00000000 --- a/test/simplifyExpression/oneStep.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -const assert = require("assert"); -import print = require("../../lib/util/print"); -import ChangeTypes = require("../../lib/ChangeTypes"); -import simplifyExpression = require("../../lib/simplifyExpression"); - -function testOneStep(exprStr, outputStr, debug=false) { - const steps = simplifyExpression(exprStr); - if (!steps.length) { - return exprStr; - } - const nodeStatus = steps[0]; - if (debug) { - if (!nodeStatus.changeType) { - throw Error("missing or bad change type"); - } - // eslint-disable-next-line - console.log(nodeStatus.changeType); - // eslint-disable-next-line - console.log(print(nodeStatus.newNode)); - } - it(exprStr + " -> " + outputStr, () => { - assert.deepEqual( - print(nodeStatus.newNode), - outputStr); - }); -} - -describe("arithmetic stepping", () => { - const tests = [ - ["(2+2)", "4"], - ["(2+2)*5", "4 * 5"], - ["5*(2+2)", "5 * 4"], - ["2*(2+2) + 2^3", "2 * 4 + 2^3"], - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe("adding symbols without breaking things", () => { - // nothing old breaks - const tests = [ - ["2+x", "2 + x"], - ["(2+2)*x", "4x"], - ["(2+2)*x+3", "4x + 3"], - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe("collecting like terms within the context of the stepper", () => { - const tests = [ - ["2+x+7", "x + 9"], // substeps not tested here -// ['2x^2 * y * x * y^3', '2 * x^3 * y^4'], // substeps not tested here - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe("collects and combines like terms", () => { - const tests = [ - ["(x + x) + (x^2 + x^2)", "2x + (x^2 + x^2)"], // substeps not tested here - ["10 + (y^2 + y^2)", "10 + 2y^2"], // substeps not tested here - ["10y^2 + 1/2 y^2 + 3/2 y^2", "12y^2"], // substeps not tested here - ["x + y + y^2", "x + y + y^2"], - ["2x^(2+1)", "2x^3"], - ]; - tests.forEach(t => testOneStep(t[0], t[1])); -}); - -describe("stepThrough returning no steps", () => { - it("12x^2 already simplified", () => { - assert.deepEqual( - simplifyExpression("12x^2"), - []); - }); - it("2*5x^2 + sqrt(5) has unsupported sqrt", () => { - assert.deepEqual( - simplifyExpression("2*5x^2 + sqrt(5)"), - []); - }); -}); - -describe("keeping parens in important places, on printing", () => { - testOneStep("5 + (3*6) + 2 / (x / y)", "5 + (3 * 6) + 2 * y / x"); - testOneStep("-(x + y) + 5+3", "8 - (x + y)"); -}); - -describe("fractions", () => { - testOneStep("2 + 5/2 + 3", "5 + 5/2"); // collect and combine without substeps -}); - -describe("simplifyDoubleUnaryMinus step actually happens", () => { - it("22 - (-7) -> 22 + 7", () => { - const steps = simplifyExpression("22 - (-7)"); - assert.equal(steps[0].changeType, ChangeTypes.RESOLVE_DOUBLE_MINUS); - }); -}); diff --git a/test/simplifyExpression/simplify.test.ts b/test/simplifyExpression/simplify.test.ts deleted file mode 100644 index 3e60d869..00000000 --- a/test/simplifyExpression/simplify.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import print = require("../../lib/util/print"); -import simplify = require("../../lib/simplifyExpression/simplify"); - -function testSimplify(exprStr, outputStr, debug=false) { - it(exprStr + " -> " + outputStr, () => { - assert.deepEqual( - print(simplify(math.parse(exprStr), debug)), - outputStr); - }); -} - -describe("simplify (arithmetic)", () => { - const tests = [ - ["(2+2)*5", "20"], - ["(8+(-4))*5", "20"], - ["5*(2+2)*10", "200"], - ["(2+(2)+7)", "11"], - ["(8-2) * 2^2 * (1+1) / (4 /2) / 5", "24/5"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("collects and combines like terms", () => { - const tests = [ - ["x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6", "5x^3 - 8x^2 + 6"], - ["2x^2 * y * x * y^3", "2x^3 * y^4"], - ["4y*3*5", "60y"], - ["(2x^2 - 4) + (4x^2 + 3)", "6x^2 - 1"], - ["(2x^1 + 4) + (4x^2 + 3)", "4x^2 + 2x + 7"], - ["y * 2x * 10", "20x * y"], - ["x^y * x^z", "x^(y + z)"], - ["x^(3+y) + x^(3+y)+ 4", "2x^(3 + y) + 4"], - ["x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6", "5x^3 - 8x^2 + 6"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - - -describe("can simplify with division", () => { - const tests = [ - ["2 * 4 / 5 * 10 + 3", "19"], - ["2x * 5x / 2", "5x^2"], - ["2x * 4x / 5 * 10 + 3", "16x^2 + 3"], - ["2x * 4x / 2 / 4", "x^2"], - ["2x * y / z * 10", "20x * y / z"], - ["2x * 4x / 5 * 10 + 3", "16x^2 + 3"], - ["2x/x", "2"], - ["2x/4/3", "1/6 x"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); - // TODO: factor the numerator to cancel out with denominator - // e.g. (x^2 - 3 + 2)/(x-2) -> (x-1) -}); - -describe("subtraction support", () => { - const tests = [ - ["-(-(2+3))", "5"], - ["-(-5)", "5"], - ["-(-(2+x))", "2 + x"], - ["-------5", "-5"], - ["--(-----5) + 6", "1"], - ["x^2 + 3 - x*x", "3"], - ["-(2*x) * -(2 + 2)", "8x"], - ["(x-4)-5", "x - 9"], - ["5-x-4", "-x + 1"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("support for more * and ( that come from latex conversion", () => { - const tests = [ - ["(3*x)*(4*x)", "12x^2"], - ["(12*z^(2))/27", "4/9 z^2"], - ["x^2 - 12x^2 + 5x^2 - 7", "-6x^2 - 7"], - ["-(12 x ^ 2)", "-12x^2"] - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("distribution", () => { - const tests = [ - ["(3*x)*(4*x)", "12x^2"], - ["(3+x)*(4+x)*(x+5)", "x^3 + 12x^2 + 47x + 60"], - ["-2x^2 * (3x - 4)", "-6x^3 + 8x^2"], - ["x^2 - x^2*(12 + 5x) - 7", "-5x^3 - 11x^2 - 7"], - ["(5+x)*(x+3)", "x^2 + 8x + 15"], - ["(x-2)(x-4)", "x^2 - 6x + 8"], - ["- x*y^4 (6x * y^2 + 5x*y - 3x)", - "-6x^2 * y^6 - 5x^2 * y^5 + 3x^2 * y^4"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("fractions", () => { - const tests = [ - ["5x + (1/2)x", "11/2 x"], - ["x + x/2", "3/2 x"], - ["1 + 1/2", "3/2"], - ["2 + 5/2 + 3", "15/2"], - ["9/18-5/18", "2/9"], - ["2(x+3)/3", "2x / 3 + 2"], - ["5/18 - 9/18", "-2/9"], - ["9/18", "1/2"], - ["x/(2/3) + 5", "3/2 x + 5"], - ["(2+x)/6", "1/3 + x / 6"] - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("floating point", () => { - testSimplify("1.983*10", "19.83"); -}); - -describe("cancelling out", () => { - const tests = [ - ["(x^3*y)/x^2 + 5", "x * y + 5"], - ["(x^(2)+y^(2))/(5x-6x) + 5", "-x - y^2 / x + 5"], - ["( p ^ ( 2) + 1)/( p ^ ( 2) + 1)", "1"], - ["(-x)/(x)", "-1"], - ["(x)/(-x)", "-1"], - ["((2x^3 y^2)/(-x^2 y^5))^(-2)", "(-2x * y^-3)^-2"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("absolute value support", () => { - const tests = [ - ["(x^3*y)/x^2 + abs(-5)", "x * y + 5"], - ["-6 + -5 - abs(-4) + -10 - 3 abs(-4)", "-37"], - ["5*abs((2+2))*10", "200"], - ["5x + (1/abs(-2))x", "11/2 x"], - ["abs(5/18-abs(9/-18))", "2/9"], - // handle parens around abs() - ["( abs( -3) )/(3)", "1"], - ["- abs( -40)", "-40"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("nthRoot support", () => { - const tests = [ - ["nthRoot(4x, 2)", "2 * nthRoot(x, 2)"], - ["2 * nthRoot(4x, 2)", "4 * nthRoot(x, 2)"], - ["(x^3*y)/x^2 + nthRoot(4x, 2)", "x * y + 2 * nthRoot(x, 2)"], - ["2 + nthRoot(4)", "4"], - ["x * nthRoot(x^4, 2)", "x^3"], - ["x * nthRoot(2 + 2, 3)", "x * nthRoot(4, 3)"], - ["x * nthRoot((2 + 2) * 2, 3)", "2x"], - ["nthRoot(x * (2 + 3) * x, 2)", "x * nthRoot(5, 2)"] - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("handles unnecessary parens at root level", () => { - const tests = [ - ["(x+(y))", "x + y"], - ["((x+y) + ((z^3)))", "x + y + z^3"], - ]; - tests.forEach(t => testSimplify(t[0], t[1], t[2])); -}); - -describe("keeping parens in important places, on printing", () => { - testSimplify("2 / (2x^2) + 5", "2 / (2x^2) + 5"); -}); diff --git a/test/solveEquation/solveEquation.test.ts b/test/solveEquation/solveEquation.test.ts deleted file mode 100644 index 1964ed32..00000000 --- a/test/solveEquation/solveEquation.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -const assert = require("assert"); -import ChangeTypes = require("../../lib/ChangeTypes"); -import solveEquation = require("../../lib/solveEquation"); -const noSteps = "no-steps"; - -function testSolve(equationString, outputStr, debug=false) { - const steps = solveEquation(equationString, debug); - let lastStep; - if (steps.length === 0) { - lastStep = noSteps; - } - else { - lastStep = steps[steps.length -1].newEquation.print(); - } - it(equationString + " -> " + outputStr, (done) => { - assert.equal(lastStep, outputStr); - done(); - }); -} - -describe("solveEquation for =", () => { - const tests = [ - // can't solve this because two symbols: g and x -- so there's no steps - ["g *( x ) = ( x - 4) ^ ( 2) - 3", noSteps], - // can't solve this because we don't deal with the complicated fraction yet - ["( x )/( 2x + 7) >= 4", noSteps], - ["y - x - 2 = 3*2", "y = 8 + x"], - ["2y - x - 2 = x", "y = x + 1"], - ["x = 1", noSteps], - ["2 = x", "x = 2"], - ["2 + -3 = x", "x = -1"], - ["x + 3 = 4", "x = 1"], - ["2x - 3 = 0", "x = 3/2"], - ["x/3 - 2 = -1", "x = 3"], - ["5x/2 + 2 = 3x/2 + 10", "x = 8"], - ["2x - 1 = -x", "x = 1/3"], - ["2 - x = -4 + x", "x = 3"], - ["2x/3 = 2", "x = 3"], - ["2x - 3 = x", "x = 3"], - ["8 - 2a = a + 3 - 1", "a = 2"], - ["2 - x = 4", "x = -2"], - ["2 - 4x = x", "x = 2/5"], - ["9x + 4 - 3 = 2x", "x = -1/7"], - ["9x + 4 - 3 = -2x", "x = -1/11"], - ["(2x^2 - 1)(x^2 - 5)(x^2 + 5) = 0", "2x^6 - x^4 - 50x^2 = -25"], - ["(-x ^ 2 - 4x + 2)(-3x^2 - 6x + 3) = 0", "3x^4 + 18x^3 + 15x^2 - 24x = -6"], - ["5x + (1/2)x = 27 ", "x = 54/11"], - ["2x/3 = 2x - 4 ", "x = 3"], - ["(-2/3)x + 3/7 = 1/2", "x = -3/28"], - ["-9/4v + 4/5 = 7/8 ", "v = -1/30"], - // TODO: update test once we have root support - ["x^2 - 2 = 0", "x^2 = 2"], - ["x/(2/3) = 1", "x = 2/3"], - ["(x+1)/3 = 4", "x = 11"], - ["2(x+3)/3 = 2", "x = 0"], - ["( u )/( 0.3) = 4u + 6.28", "u = -9.42"], - ["- q - 4.36= ( 2.2q )/( 1.8)", "q = -1.962"], - // TODO: figure out what to do about errors from rounding midway through - // this gives us 6.3995 when it should actually be 6.4 :( - // ['x - 3.4= ( x - 2.5)/( 1.3)', 'x = 6.4'] - ]; - tests.forEach(t => testSolve(t[0], t[1], t[2])); -}); - -describe("solveEquation for non = comparators", () => { - const tests = [ - ["x + 2 > 3", "x > 1"], - ["2x < 6", "x < 3"], - ["-x > 1", "x < -1"], - ["2 - x < 3", "x > -1"], - ["9.5j / 6+ 5.5j >= 3( 5j - 2)", "j <= 0.7579"] - ]; - tests.forEach(t => testSolve(t[0], t[1], t[2])); -}); - -function testSolveConstantEquation(equationString, expectedChange, debug=false) { - const steps = solveEquation(equationString, debug); - const actualChange = steps[steps.length -1].changeType; - it(equationString + " -> " + expectedChange, (done) => { - assert.equal(actualChange, expectedChange); - done(); - }); -} - -describe("constant comparison support", () => { - const tests = [ - ["1 = 2", ChangeTypes.STATEMENT_IS_FALSE], - ["3 + 5 = 8", ChangeTypes.STATEMENT_IS_TRUE], - ["1 = 2", ChangeTypes.STATEMENT_IS_FALSE], - ["2 - 3 = 5", ChangeTypes.STATEMENT_IS_FALSE], - ["2 > 1", ChangeTypes.STATEMENT_IS_TRUE], - ["2/3 > 1/3", ChangeTypes.STATEMENT_IS_TRUE], - ["1 > 2", ChangeTypes.STATEMENT_IS_FALSE], - ["1/3 > 2/3", ChangeTypes.STATEMENT_IS_FALSE], - ["1 >= 1", ChangeTypes.STATEMENT_IS_TRUE], - ["2 >= 1", ChangeTypes.STATEMENT_IS_TRUE], - ["1 >= 2", ChangeTypes.STATEMENT_IS_FALSE], - ["2 < 1", ChangeTypes.STATEMENT_IS_FALSE], - ["2/3 < 1/3", ChangeTypes.STATEMENT_IS_FALSE], - ["1 < 2", ChangeTypes.STATEMENT_IS_TRUE], - ["1/3 < 2/3", ChangeTypes.STATEMENT_IS_TRUE], - ["1 <= 1", ChangeTypes.STATEMENT_IS_TRUE], - ["2 <= 1", ChangeTypes.STATEMENT_IS_FALSE], - ["1 <= 2", ChangeTypes.STATEMENT_IS_TRUE], - ["( 1) = ( 14)", ChangeTypes.STATEMENT_IS_FALSE], - // TODO: when we support fancy exponent and sqrt things - // ['(1/64)^(-5/6) = 32', ChangeTypes.STATEMENT_IS_TRUE], - // With variables that cancel - ["( r )/( ( r ) ) = ( 1)/( 10)", ChangeTypes.STATEMENT_IS_FALSE], - ["5 + (x - 5) = x", ChangeTypes.STATEMENT_IS_TRUE], - ["4x - 4= 4x", ChangeTypes.STATEMENT_IS_FALSE], - ]; - tests.forEach(t => testSolveConstantEquation(t[0], t[1], t[2])); -}); - -function testEquationError(equationString, debug=false) { - it(equationString + " throws error", (done) => { - assert.throws(() => solveEquation(equationString, debug),Error); - done(); - }); -} - -describe("solveEquation errors", () => { - const tests = [ - ["( x + 2) ^ ( 2) - x ^ ( 2) = 4( x + 1)"] - ]; - tests.forEach(t => testEquationError(t[0], t[1])); -}); diff --git a/test/util/Util.test.ts b/test/util/Util.test.ts deleted file mode 100644 index 2d0ae8f1..00000000 --- a/test/util/Util.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -const assert = require("assert"); -import Util = require("../../lib/util/Util"); -describe("appendToArrayInObject", () => { - it("creates empty array", () => { - const object = {}; - Util.appendToArrayInObject(object, "key", "value"); - assert.deepEqual( - object, - {'key': ["value"]} - ); - }); - it("appends to array if it exists", () => { - const object = {'key': ["old_value"]}; - Util.appendToArrayInObject(object, "key", "new_value"); - assert.deepEqual( - object, - {'key': ["old_value", "new_value"]} - ); - }); -}); diff --git a/test/util/flattenOperands.test.ts b/test/util/flattenOperands.test.ts deleted file mode 100644 index 0fd1545b..00000000 --- a/test/util/flattenOperands.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -const assert = require("assert"); -import math = require("mathjs"); -import flattenOperands = require("../../lib/util/flattenOperands"); -import print = require("../../lib/util/print"); -const mathNode = require("../../lib/node"); - -function testFlatten(exprStr, afterNode, debug=false) { - const flattened = flattenOperands(math.parse(exprStr)); - if (debug) { - // eslint-disable-next-line - console.log(print(flattened)); - } - removeComments(flattened); - removeComments(afterNode); - it(print(flattened), () => { - assert.deepEqual(flattened, afterNode); - }); -} - -// to create nodes, for testing -const opNode = mathNode.Creator.operator; -const constNode = mathNode.Creator.constant; -const symbolNode = mathNode.Creator.symbol; -const parenNode = mathNode.Creator.parenthesis; - -describe("flattens + and *", () => { - const tests = [ - ["2+2", math.parse("2+2")], - ["2+2+7", opNode("+", [constNode(2), constNode(2), constNode(7)])], - ["9*8*6+3+4", - opNode("+", [ - opNode("*", [constNode(9), constNode(8), constNode(6)]), - constNode(3), - constNode(4)])], - ["5*(2+3+2)*10", - opNode("*", [ - constNode(5), - parenNode(opNode("+", [constNode(2), constNode(3),constNode(2)])), - constNode(10)])], - // keeps the polynomial term - ["9x*8*6+3+4", - opNode("+", [ - opNode("*", [math.parse("9x"), constNode(8), constNode(6)]), - constNode(3), - constNode(4)])], - ["9x*8*6+3y^2+4", - opNode("+", [ - opNode("*", [math.parse("9x"), constNode(8), constNode(6)]), - math.parse("3y^2"), - constNode(4)])], - // doesn't flatten - ["2 x ^ (2 + 1) * y", math.parse("2 x ^ (2 + 1) * y")], - ["2 x ^ (2 + 1 + 2) * y", - opNode("*", [ - opNode("*", [constNode(2), - opNode("^", [symbolNode("x"), parenNode( - opNode("+", [constNode(2), constNode(1), constNode(2)]))]), - ], true), symbolNode("y")]) - ], - ["3x*4x", opNode("*", [math.parse("3x"), math.parse("4x")])] - ]; - tests.forEach(t => testFlatten(t[0], t[1])); -}); - -describe("flattens division", () => { - const tests = [ - // groups x/4 and continues to flatten * - ["2 * x / 4 * 6 ", - opNode("*", [opNode("/", [ - math.parse("2x"), math.parse("4")]), constNode(6)])], - ["2*3/4/5*6", - opNode("*", [constNode(2), math.parse("3/4/5"), constNode(6)])], - // combines coefficient with x - ["x / (4 * x) / 8", - math.parse("x / (4x) / 8")], - ["2 x * 4 x / 8", - opNode("*", [math.parse("2x"), opNode( - "/", [math.parse("4x"), constNode(8)])])], - ]; - tests.forEach(t => testFlatten(t[0], t[1])); -}); - -describe("subtraction", () => { - const tests = [ - ["1 + 2 - 3 - 4 + 5", - opNode("+", [ - constNode(1), constNode(2), constNode(-3), constNode(-4), constNode(5)])], - ["x - 3", opNode("+", [symbolNode("x"), constNode(-3)])], - ["x + 4 - (y+4)", - opNode("+", [symbolNode("x"), constNode(4), math.parse("-(y+4)")])], - ]; - tests.forEach(t => testFlatten(t[0], t[1])); -}); - - -// Remove some property used in mathjs that we don't need and prevents node -// equality checks from passing -function removeComments(node: any); -function removeComments(node) { - node.filter(node => node.comment !== undefined).forEach( - node => delete node.comment); -} diff --git a/test/util/print.test.ts b/test/util/print.test.ts deleted file mode 100644 index 20a36cdc..00000000 --- a/test/util/print.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import math = require("mathjs"); -const mathNode = require("../../lib/node"); -import print = require("../../lib/util/print"); -import TestUtil = require("../TestUtil"); - -// to create nodes, for testing -const opNode = mathNode.Creator.operator; -const constNode = mathNode.Creator.constant; -const symbolNode = mathNode.Creator.symbol; - -function testPrintStr(exprStr: any, outputStr: any); -function testPrintStr(exprStr, outputStr) { - const input = math.parse(exprStr); - TestUtil.testFunctionOutput(print, input, outputStr); -} - -function testPrintNode(node: any, outputStr: any); -function testPrintNode(node, outputStr) { - TestUtil.testFunctionOutput(print, node, outputStr); -} - -describe("print asciimath", () => { - const tests = [ - ["2+3+4", "2 + 3 + 4"], - ["2 + (4 - x) + - 4", "2 + (4 - x) - 4"], - ["2/3 x^2", "2/3 x^2"], - ["-2/3", "-2/3"], - ]; - tests.forEach(t => testPrintStr(t[0], t[1])); -}); - -describe("print with parenthesis", () => { - const tests = [ - [opNode("*", [ - opNode("+", [constNode(2), constNode(3)]), - symbolNode("x") - ]), "(2 + 3) * x"], - [opNode("^", [ - opNode("-", [constNode(7), constNode(4)]), - symbolNode("x") - ]), "(7 - 4)^x"], - [opNode("/", [ - opNode("+", [constNode(9), constNode(2)]), - symbolNode("x") - ]), "(9 + 2) / x"], - ]; - tests.forEach(t => testPrintNode(t[0], t[1])); -}); diff --git a/test/util/removeUnnecessaryParens.test.ts b/test/util/removeUnnecessaryParens.test.ts deleted file mode 100644 index 22920f21..00000000 --- a/test/util/removeUnnecessaryParens.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import math = require("mathjs"); -import print = require("../../lib/util/print"); -import removeUnnecessaryParens = require("../../lib/util/removeUnnecessaryParens"); -import TestUtil = require("../TestUtil"); - -function testRemoveUnnecessaryParens(exprStr: any, outputStr: any); -function testRemoveUnnecessaryParens(exprStr, outputStr) { - const input = removeUnnecessaryParens(math.parse(exprStr)); - TestUtil.testFunctionOutput(print, input, outputStr); -} - -describe("removeUnnecessaryParens", () => { - const tests = [ - ["(x+4) + 12", "x + 4 + 12"], - ["-(x+4x) + 12", "-(x + 4x) + 12"], - ["x + (12)", "x + 12"], - ["x + (y)", "x + y"], - ["x + -(y)", "x - y"], - ["((3 - 5)) * x", "(3 - 5) * x"], - ["((3 - 5)) * x", "(3 - 5) * x"], - ["(((-5)))", "-5"], - ["((4+5)) + ((2^3))", "(4 + 5) + 2^3"], - ["(2x^6 + -50 x^2) - (x^4)", "2x^6 - 50x^2 - x^4"], - ["(x+4) - (12 + x)", "x + 4 - (12 + x)"], - ["(2x)^2", "(2x)^2"], - ["((4+x)-5)^(2)", "(4 + x - 5)^2"], - ]; - tests.forEach(t => testRemoveUnnecessaryParens(t[0], t[1])); -}); From fcc1578d83cb9a88ad19d0db8496b61ec894a603 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 13:17:36 -0700 Subject: [PATCH 05/12] Refactor 1 --- test/Negative.test.js | 28 +++ test/Node/PolynomialTerm.test.js | 24 +++ test/Node/Type.test.js | 110 ++++++++++++ test/TestUtil.js | 56 ++++++ test/canAddLikeTermPolynomialNodes.test.js | 16 ++ ...canMultiplyLikeTermPolynomialNodes.test.js | 16 ++ test/canRearrangeCoefficient.test.js | 15 ++ test/checks/checks.test.js | 31 ++++ test/checks/hasUnsupportedNodes.test.js | 30 ++++ test/checks/isQuadratic.test.js | 28 +++ test/checks/resolvesToConstant.test.js | 18 ++ test/equation.test.js | 28 +++ test/factor/ConstantFactors.test.js | 44 +++++ test/factor/factorQuadratic.test.js | 34 ++++ .../arithmeticSearch/arithmeticSearch.test.js | 16 ++ .../basicsSearch/rearrangeCoefficient.test.js | 11 ++ .../basicsSearch/reduceExponentByZero.test.js | 7 + .../reduceMutliplicationByZero.test.js | 11 ++ .../reduceZeroDividedByAnything.test.js | 11 ++ .../basicsSearch/removeAdditionOfZero.test.js | 12 ++ .../basicsSearch/removeDivisionByOne.test.js | 7 + .../removeExponentBaseOne.test.js | 12 ++ .../basicsSearch/removeExponentByOne.test.js | 7 + .../removeMultiplicationByNegativeOne.test.js | 12 ++ .../removeMultiplicationByOne.test.js | 13 ++ .../simplifyDoubleUnaryMinus.test.js | 12 ++ .../basicsSearch/testSimplify.js | 18 ++ .../breakUpNumeratorSearch.test.js | 16 ++ .../LikeTermCollector.test.js | 97 ++++++++++ .../collectAndCombineSearch.test.js | 62 +++++++ .../evaluateConstantSum.test.js | 33 ++++ .../distributeSearch/distributeSearch.test.js | 89 ++++++++++ .../divisionSearch/divisionSearch.test.js | 21 +++ .../addConstantAndFraction.test.js | 32 ++++ .../addConstantFractions.test.js | 38 ++++ .../fractionsSearch/cancelLikeTerms.test.js | 33 ++++ .../fractionsSearch/divideByGCD.test.js | 19 ++ .../simplifyFractionSigns.test.js | 15 ++ .../simplifyPolynomialFraction.test.js | 20 +++ .../functionsSearch/absoluteValue.test.js | 15 ++ .../functionsSearch/nthRoot.test.js | 72 ++++++++ .../multiplyFractionsSearch.test.js | 16 ++ test/simplifyExpression/oneStep.test.js | 96 ++++++++++ test/simplifyExpression/simplify.test.js | 168 ++++++++++++++++++ test/solveEquation/solveEquation.test.js | 130 ++++++++++++++ test/util/Util.test.js | 22 +++ test/util/flattenOperands.test.js | 103 +++++++++++ test/util/print.test.js | 48 +++++ test/util/removeUnnecessaryParens.test.js | 30 ++++ tsconfig.json | 16 ++ 50 files changed, 1818 insertions(+) create mode 100644 test/Negative.test.js create mode 100644 test/Node/PolynomialTerm.test.js create mode 100644 test/Node/Type.test.js create mode 100644 test/TestUtil.js create mode 100644 test/canAddLikeTermPolynomialNodes.test.js create mode 100644 test/canMultiplyLikeTermPolynomialNodes.test.js create mode 100644 test/canRearrangeCoefficient.test.js create mode 100644 test/checks/checks.test.js create mode 100644 test/checks/hasUnsupportedNodes.test.js create mode 100644 test/checks/isQuadratic.test.js create mode 100644 test/checks/resolvesToConstant.test.js create mode 100644 test/equation.test.js create mode 100644 test/factor/ConstantFactors.test.js create mode 100644 test/factor/factorQuadratic.test.js create mode 100644 test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js create mode 100644 test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js create mode 100644 test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js create mode 100644 test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js create mode 100644 test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeExponentByOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js create mode 100644 test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js create mode 100644 test/simplifyExpression/basicsSearch/testSimplify.js create mode 100644 test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js create mode 100644 test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js create mode 100644 test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js create mode 100644 test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js create mode 100644 test/simplifyExpression/distributeSearch/distributeSearch.test.js create mode 100644 test/simplifyExpression/divisionSearch/divisionSearch.test.js create mode 100644 test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js create mode 100644 test/simplifyExpression/fractionsSearch/addConstantFractions.test.js create mode 100644 test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js create mode 100644 test/simplifyExpression/fractionsSearch/divideByGCD.test.js create mode 100644 test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js create mode 100644 test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js create mode 100644 test/simplifyExpression/functionsSearch/absoluteValue.test.js create mode 100644 test/simplifyExpression/functionsSearch/nthRoot.test.js create mode 100644 test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js create mode 100644 test/simplifyExpression/oneStep.test.js create mode 100644 test/simplifyExpression/simplify.test.js create mode 100644 test/solveEquation/solveEquation.test.js create mode 100644 test/util/Util.test.js create mode 100644 test/util/flattenOperands.test.js create mode 100644 test/util/print.test.js create mode 100644 test/util/removeUnnecessaryParens.test.js create mode 100644 tsconfig.json diff --git a/test/Negative.test.js b/test/Negative.test.js new file mode 100644 index 00000000..a20cf1af --- /dev/null +++ b/test/Negative.test.js @@ -0,0 +1,28 @@ +const math = require('mathjs'); + +const flatten = require('../lib/util/flattenOperands'); +const print = require('../lib/util/print'); + +const Negative = require('../lib/Negative'); + +const TestUtil = require('./TestUtil'); + +function testNegate(exprString, outputStr) { + const inputStr = Negative.negate(flatten(math.parse(exprString))); + TestUtil.testFunctionOutput(print, inputStr, outputStr); +} + +describe('negate', function() { + const tests = [ + ['1', '-1'], + ['-1', '1'], + ['1/2', '-1/2'], + ['(x+2)', '-(x + 2)'], + ['x', '-x'], + ['x^2', '-x^2'], + ['-y^3', 'y^3'], + ['2/3 x', '-2/3 x'], + ['-5/6 z', '5/6 z'], + ]; + tests.forEach(t => testNegate(t[0], t[1])); +}); diff --git a/test/Node/PolynomialTerm.test.js b/test/Node/PolynomialTerm.test.js new file mode 100644 index 00000000..30489e62 --- /dev/null +++ b/test/Node/PolynomialTerm.test.js @@ -0,0 +1,24 @@ +const PolynomialTerm = require('../../lib/node/PolynomialTerm'); + +const TestUtil = require('../TestUtil'); + +function testIsPolynomialTerm(exprStr, isTerm) { + TestUtil.testBooleanFunction(PolynomialTerm.isPolynomialTerm, exprStr, isTerm); +} + +describe('classifies symbol terms correctly', function() { + const tests = [ + ['x', true], + ['x', true], + ['x^2', true], + ['y^55', true], + ['y^4/4', true], + ['5y/3', true], + ['x^y', true], + ['3', false], + ['2^5', false], + ['x*y^5', false], + ['-12y^5/-3', true], + ]; + tests.forEach(t => testIsPolynomialTerm(t[0], t[1])); +}); diff --git a/test/Node/Type.test.js b/test/Node/Type.test.js new file mode 100644 index 00000000..82407533 --- /dev/null +++ b/test/Node/Type.test.js @@ -0,0 +1,110 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const Node = require('../../lib/node'); + +const constNode = Node.Creator.constant; + +describe('Node.Type works', function () { + it('(2+2) parenthesis', function () { + assert.deepEqual( + Node.Type.isParenthesis(math.parse('(2+2)')), + true); + }); + it('10 constant', function () { + assert.deepEqual( + Node.Type.isConstant(math.parse(10)), + true); + }); + it('-2 constant', function () { + assert.deepEqual( + Node.Type.isConstant(constNode(-2)), + true); + }); + it('2+2 operator without operator param', function () { + assert.deepEqual( + Node.Type.isOperator(math.parse('2+2')), + true); + }); + it('2+2 operator with correct operator param', function () { + assert.deepEqual( + Node.Type.isOperator(math.parse('2+2'), '+'), + true); + }); + it('2+2 operator with incorrect operator param', function () { + assert.deepEqual( + Node.Type.isOperator(math.parse('2+2'), '-'), + false); + }); + it('-x not operator', function () { + assert.deepEqual( + Node.Type.isOperator(math.parse('-x')), + false); + }); + it('-x symbol', function () { + assert.deepEqual( + Node.Type.isSymbol(math.parse('-x')), + true); + }); + it('y symbol', function () { + assert.deepEqual( + Node.Type.isSymbol(math.parse('y')), + true); + }); + it('abs(5) is abs function', function () { + assert.deepEqual( + Node.Type.isFunction(math.parse('abs(5)'), 'abs'), + true); + }); + it('sqrt(5) is not abs function', function () { + assert.deepEqual( + Node.Type.isFunction(math.parse('sqrt(5)'), 'abs'), + false); + }); + // it('nthRoot(4) is an nthRoot function', function () { + // assert.deepEqual( + // Node.Type.isFunction(math.parse('nthRoot(5)'), 'nthRoot'), + // true); + // }); +}); + +describe('isConstantOrConstantFraction', function () { + it('2 true', function () { + assert.deepEqual( + Node.Type.isConstantOrConstantFraction(math.parse('2')), + true); + }); + it('2/9 true', function () { + assert.deepEqual( + Node.Type.isConstantOrConstantFraction(math.parse('4/9')), + true); + }); + it('x/2 false', function () { + assert.deepEqual( + Node.Type.isConstantOrConstantFraction(math.parse('x/2')), + false); + }); +}); + +describe('isIntegerFraction', function () { + it('4/5 true', function () { + assert.deepEqual( + Node.Type.isIntegerFraction(math.parse('4/5')), + true); + }); + it('4.3/5 false', function () { + assert.deepEqual( + Node.Type.isIntegerFraction(math.parse('4.3/5')), + false); + }); + it('4x/5 false', function () { + assert.deepEqual( + Node.Type.isIntegerFraction(math.parse('4x/5')), + false); + }); + it('5 false', function () { + assert.deepEqual( + Node.Type.isIntegerFraction(math.parse('5')), + false); + }); +}); diff --git a/test/TestUtil.js b/test/TestUtil.js new file mode 100644 index 00000000..246d889b --- /dev/null +++ b/test/TestUtil.js @@ -0,0 +1,56 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const flatten = require('../lib/util/flattenOperands'); +const print = require('../lib/util/print'); + +// TestUtil contains helper methods to share code across tests +const TestUtil = {}; + +// Tests a function that takes an input string and check its output +TestUtil.testFunctionOutput = function (fn, input, output) { + it(input + ' -> ' + output, () => { + assert.deepEqual(fn(input),output); + }); +}; + +// tests a function that takes in a node and returns a boolean value +TestUtil.testBooleanFunction = function (simplifier, exprString, expectedBooleanValue) { + it(exprString + ' ' + expectedBooleanValue, () => { + const inputNode = flatten(math.parse(exprString)); + assert.equal(simplifier(inputNode),expectedBooleanValue); + }); +}; + +// Tests a simplification function +TestUtil.testSimplification = function (simplifyingFunction, exprString, + expectedOutputString) { + it (exprString + ' -> ' + expectedOutputString, () => { + assert.deepEqual( + print(simplifyingFunction(flatten(math.parse(exprString))).newNode), + expectedOutputString); + }); +}; + +// Test the substeps in the expression +TestUtil.testSubsteps = function (fn, exprString, outputList, + outputStr) { + it(exprString + ' -> ' + outputStr, () => { + const status = fn(flatten(math.parse(exprString))); + const substeps = status.substeps; + + assert.deepEqual(substeps.length, outputList.length); + substeps.forEach((step, i) => { + assert.deepEqual( + print(step.newNode), + outputList[i]); + }); + if (outputStr) { + assert.deepEqual( + print(status.newNode), + outputStr); + } + }); +}; + +module.exports = TestUtil; diff --git a/test/canAddLikeTermPolynomialNodes.test.js b/test/canAddLikeTermPolynomialNodes.test.js new file mode 100644 index 00000000..cc5ca4f2 --- /dev/null +++ b/test/canAddLikeTermPolynomialNodes.test.js @@ -0,0 +1,16 @@ +const canAddLikeTermPolynomialNodes = require('../lib/checks/canAddLikeTermPolynomialNodes'); + +const TestUtil = require('./TestUtil'); + +function testCanBeAdded(expr, addable) { + TestUtil.testBooleanFunction(canAddLikeTermPolynomialNodes, expr, addable); +} + +describe('can add like term polynomials', () => { + const tests = [ + ['x^2 + x^2', true], + ['x + x', true], + ['x^3 + x', false], + ]; + tests.forEach(t => testCanBeAdded(t[0], t[1])); +}); diff --git a/test/canMultiplyLikeTermPolynomialNodes.test.js b/test/canMultiplyLikeTermPolynomialNodes.test.js new file mode 100644 index 00000000..d176dc4d --- /dev/null +++ b/test/canMultiplyLikeTermPolynomialNodes.test.js @@ -0,0 +1,16 @@ +const canMultiplyLikeTermPolynomialNodes = require('../lib/checks/canMultiplyLikeTermPolynomialNodes'); + +const TestUtil = require('./TestUtil'); + +function testCanBeMultiplied(expr, multipliable) { + TestUtil.testBooleanFunction(canMultiplyLikeTermPolynomialNodes, expr, multipliable); +} + +describe('can multiply like term polynomials', () => { + const tests = [ + ['x^2 * x * x', true], + ['x^2 * 3x * x', false], + ['y * y^3', true] + ]; + tests.forEach(t => testCanBeMultiplied(t[0], t[1])); +}); diff --git a/test/canRearrangeCoefficient.test.js b/test/canRearrangeCoefficient.test.js new file mode 100644 index 00000000..09d7f1e1 --- /dev/null +++ b/test/canRearrangeCoefficient.test.js @@ -0,0 +1,15 @@ +const canRearrangeCoefficient = require('../lib/checks/canRearrangeCoefficient'); + +const TestUtil = require('./TestUtil'); + +function testCanBeRearranged(expr, arrangeable) { + TestUtil.testBooleanFunction(canRearrangeCoefficient, expr, arrangeable); +} + +describe('can rearrange coefficient', () => { + const tests = [ + ['x*2', true], + ['y^3 * 7', true] + ]; + tests.forEach(t => testCanBeRearranged(t[0], t[1])); +}); diff --git a/test/checks/checks.test.js b/test/checks/checks.test.js new file mode 100644 index 00000000..4df3005f --- /dev/null +++ b/test/checks/checks.test.js @@ -0,0 +1,31 @@ +const checks = require('../../lib/checks'); + +const TestUtil = require('../TestUtil'); + +function testCanCombine(exprStr, canCombine) { + TestUtil.testBooleanFunction(checks.canSimplifyPolynomialTerms, exprStr, canCombine); +} + +describe('canSimplifyPolynomialTerms multiplication', function() { + const tests = [ + ['x^2 * x * x', true], + // false b/c coefficient + ['x^2 * 3x * x', false], + ['y * y^3', true], + ['5 * y^3', false], // just needs flattening + ['5/7 * x', false], // just needs flattening + ['5/7 * 9 * x', false], + ]; + tests.forEach(t => testCanCombine(t[0], t[1])); +}); + + +describe('canSimplifyPolynomialTerms addition', function() { + const tests = [ + ['x + x', true], + ['4y^2 + 7y^2 + y^2', true], + ['4y^2 + 7y^2 + y^2 + y', false], + ['y', false], + ]; + tests.forEach(t => testCanCombine(t[0], t[1])); +}); diff --git a/test/checks/hasUnsupportedNodes.test.js b/test/checks/hasUnsupportedNodes.test.js new file mode 100644 index 00000000..7b71a5f5 --- /dev/null +++ b/test/checks/hasUnsupportedNodes.test.js @@ -0,0 +1,30 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const checks = require('../../lib/checks'); + +describe('arithmetic stepping', function () { + it('4 + sqrt(16) no support for sqrt', function () { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('4 + sqrt(4)')), + true); + }); + + it('x = 5 no support for assignment', function () { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('x = 5')), + true); + }); + + it('x + (-5)^2 - 8*y/2 is fine', function () { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('x + (-5)^2 - 8*y/2')), + false); + }); + + it('nthRoot() with no args has no support', function () { + assert.deepEqual( + checks.hasUnsupportedNodes(math.parse('nthRoot()')), + true); + }); +}); diff --git a/test/checks/isQuadratic.test.js b/test/checks/isQuadratic.test.js new file mode 100644 index 00000000..d5c98d01 --- /dev/null +++ b/test/checks/isQuadratic.test.js @@ -0,0 +1,28 @@ +const checks = require('../../lib/checks'); +const TestUtil = require('../TestUtil'); + +function testIsQuadratic(input, output) { + TestUtil.testBooleanFunction(checks.isQuadratic, input, output); +} + +describe('isQuadratic', function () { + const tests = [ + ['2 + 2', false], + ['x', false], + ['x^2 - 4', true], + ['x^2 + 2x + 1', true], + ['x^2 - 2x + 1', true], + ['x^2 + 3x + 2', true], + ['x^2 - 3x + 2', true], + ['x^2 + x - 2', true], + ['x^2 + x', true], + ['x^2 + 4', true], + ['x^2 + 4x + 1', true], + ['x^2', false], + ['x^3 + x^2 + x + 1', false], + ['x^2 + 4 + 2^x', false], + ['x^2 + 4 + 2y', false], + ['y^2 + 4 + 2x', false], + ]; + tests.forEach(t => testIsQuadratic(t[0], t[1])); +}); diff --git a/test/checks/resolvesToConstant.test.js b/test/checks/resolvesToConstant.test.js new file mode 100644 index 00000000..8d08d296 --- /dev/null +++ b/test/checks/resolvesToConstant.test.js @@ -0,0 +1,18 @@ +const checks = require('../../lib/checks'); + +const TestUtil = require('../TestUtil'); + +function testResolvesToConstant(exprString, resolves) { + TestUtil.testBooleanFunction(checks.resolvesToConstant, exprString, resolves); +} + +describe('resolvesToConstant', function () { + const tests = [ + ['(2+2)', true], + ['10', true], + ['((2^2 + 4)) * 7 / 8', true], + ['2 * 3^x', false], + ['-(2) * -3', true], + ]; + tests.forEach(t => testResolvesToConstant(t[0], t[1])); +}); diff --git a/test/equation.test.js b/test/equation.test.js new file mode 100644 index 00000000..3cecd055 --- /dev/null +++ b/test/equation.test.js @@ -0,0 +1,28 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const Equation = require('../lib/equation/Equation'); + +function constructAndPrintEquation(left, right, comp) { + const leftNode = math.parse(left); + const rightNode = math.parse(right); + const equation = new Equation(leftNode, rightNode, comp); + return equation.print(); +} + +function testEquationConstructor(left, right, comp, output) { + it (output, () => { + assert.equal( + constructAndPrintEquation(left, right, comp), output + ); + }); +} + +describe('Equation constructor', () => { + const tests = [ + ['2*x^2 + x', '4', '=', '2x^2 + x = 4'], + ['x^2 + 2*x + 2', '0', '>=', 'x^2 + 2x + 2 >= 0'], + ['2*x - 1', '0', '<=', '2x - 1 <= 0'] + ]; + tests.forEach(t => testEquationConstructor(t[0], t[1], t[2], t[3])); +}); diff --git a/test/factor/ConstantFactors.test.js b/test/factor/ConstantFactors.test.js new file mode 100644 index 00000000..9fb102fa --- /dev/null +++ b/test/factor/ConstantFactors.test.js @@ -0,0 +1,44 @@ +const ConstantFactors = require('../../lib/factor/ConstantFactors'); + +const TestUtil = require('../TestUtil'); + +function testPrimeFactors(input, output) { + TestUtil.testFunctionOutput(ConstantFactors.getPrimeFactors, input, output); +} + +describe('prime factors', function() { + const tests = [ + [1, [1]], + [-1, [-1, 1]], + [-2, [-1, 2]], + [5, [5]], + [12, [2, 2, 3]], + [15, [3, 5]], + [36, [2, 2, 3, 3]], + [49, [7, 7]], + [1260, [2, 2, 3, 3, 5, 7]], + [13195, [5, 7, 13, 29]], + [1234567891, [1234567891]] + ]; + tests.forEach(t => testPrimeFactors(t[0], t[1])); +}); + +function testFactorPairs(input, output) { + TestUtil.testFunctionOutput(ConstantFactors.getFactorPairs, input, output); +} + +describe('factor pairs', function() { + const tests = [ + [1, [[-1, -1], [1, 1]]], + [5, [[-1, -5], [1, 5]]], + [12, [[-3, -4], [-2, -6], [-1, -12], [1, 12], [2, 6], [3, 4]]], + [-12, [[-3, 4], [-2, 6], [-1, 12], [1, -12], [2, -6], [3, -4]]], + [15, [[-3, -5], [-1, -15], [1, 15], [3, 5]]], + [36, [[-6, -6], [-4, -9], [-3, -12], [-2, -18], [-1, -36], [1, 36], [2, 18], [3, 12], [4, 9], [6, 6,]]], + [49, [[-7, -7], [-1, -49], [1, 49], [7, 7]]], + [1260, [[-35, -36], [-30, -42], [-28, -45], [-21, -60], [-20, -63], [-18, -70], [-15, -84], [-14, -90], [-12, -105], [-10, -126], [-9, -140], [-7, -180], [-6, -210], [-5, -252], [-4, -315], [-3, -420], [-2, -630], [-1, -1260], [1, 1260], [2, 630], [3, 420], [4, 315], [5, 252], [6, 210], [7, 180], [9, 140], [10, 126], [12, 105], [14, 90], [15, 84], [18, 70], [20, 63], [21, 60], [28, 45], [30, 42], [35, 36]]], + [13195, [[-91, -145], [-65, -203], [-35, -377], [-29, -455], [-13, -1015], [-7, -1885], [-5, -2639], [-1, -13195], [1, 13195], [5, 2639], [7, 1885], [13, 1015], [29, 455], [35, 377], [65, 203], [91, 145]]], + [1234567891, [[-1, -1234567891], [1, 1234567891]]] + ]; + tests.forEach(t => testFactorPairs(t[0], t[1])); +}); diff --git a/test/factor/factorQuadratic.test.js b/test/factor/factorQuadratic.test.js new file mode 100644 index 00000000..ec8e46b5 --- /dev/null +++ b/test/factor/factorQuadratic.test.js @@ -0,0 +1,34 @@ +const factorQuadratic = require('../../lib/factor/factorQuadratic'); +const TestUtil = require('../TestUtil'); + +function testFactorQuadratic(input, output) { + TestUtil.testSimplification(factorQuadratic, input, output); +} + +describe('factorQuadratic', function () { + const tests = [ + ['x^2', 'x^2'], + ['x^2 + x^2', 'x^2 + x^2'], + ['x^2 + 2 - 3', 'x^2 + 2 - 3'], + ['x^2 + 2y + 2x + 3', 'x^2 + 2y + 2x + 3'], + ['x^2 + 2x', 'x * (x + 2)'], + ['-x^2 - 2x', '-x * (x + 2)'], + ['x^2 - 3x', 'x * (x - 3)'], + ['2x^2 + 2x', '2x * (x + 1)'], + ['x^2 - 4', '(x + 2) * (x - 2)'], + ['x^2 + 4', 'x^2 + 4'], + ['x^2 + 2x + 1', '(x + 1)^2'], + ['x^2 - 2x + 1', '(x - 1)^2'], + ['x^2 + 3x + 2', '(x + 1) * (x + 2)'], + ['x^2 - 3x + 2', '(x - 1) * (x - 2)'], + ['x^2 + x - 2', '(x - 1) * (x + 2)'], + ['x^2 + 4x + 1', 'x^2 + 4x + 1'], + ['x^2 - 3x + 1', 'x^2 - 3x + 1'], + ['x^2 + 4 + 2^x', 'x^2 + 4 + 2^x'], + ['-x^2 - 2x - 1', '-(x + 1)^2'], + ['-x^2 - 3x - 2', '-(x + 1) * (x + 2)'], + ['-x^2 + 1', '-(x + 1) * (x - 1)'], + ['-x^2 - 1', '-x^2 - 1'], + ]; + tests.forEach(t => testFactorQuadratic(t[0], t[1])); +}); diff --git a/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js new file mode 100644 index 00000000..0503b586 --- /dev/null +++ b/test/simplifyExpression/arithmeticSearch/arithmeticSearch.test.js @@ -0,0 +1,16 @@ +const arithmeticSearch = require('../../../lib/simplifyExpression/arithmeticSearch'); + +const TestUtil = require('../../TestUtil'); + +function testArithmeticSearch(exprStr, outputStr) { + TestUtil.testSimplification(arithmeticSearch, exprStr, outputStr); +} + +describe('evaluate arithmeticSearch', function () { + const tests = [ + ['2+2', '4'], + ['2*3*5', '30'], + ['9/4', '9/4'], // does not divide + ]; + tests.forEach(t => testArithmeticSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js new file mode 100644 index 00000000..d163dd7e --- /dev/null +++ b/test/simplifyExpression/basicsSearch/rearrangeCoefficient.test.js @@ -0,0 +1,11 @@ +const rearrangeCoefficient = require('../../../lib/simplifyExpression/basicsSearch/rearrangeCoefficient'); + +const testSimplify = require('./testSimplify'); + +describe('rearrangeCoefficient', function() { + const tests = [ + ['2 * x^2', '2x^2'], + ['y^3 * 5', '5y^3'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], rearrangeCoefficient)); +}); diff --git a/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js new file mode 100644 index 00000000..506728f8 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/reduceExponentByZero.test.js @@ -0,0 +1,7 @@ +const reduceExponentByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceExponentByZero'); + +const testSimplify = require('./testSimplify'); + +describe('reduceExponentByZero', function() { + testSimplify('(x+3)^0', '1', reduceExponentByZero); +}); diff --git a/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js new file mode 100644 index 00000000..490a6f91 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/reduceMutliplicationByZero.test.js @@ -0,0 +1,11 @@ +const reduceMultiplicationByZero = require('../../../lib/simplifyExpression/basicsSearch/reduceMultiplicationByZero'); + +const testSimplify = require('./testSimplify'); + +describe('reduce multiplication by 0', function () { + const tests = [ + ['0x', '0'], + ['2*0*z^2','0'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], reduceMultiplicationByZero)); +}); diff --git a/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js new file mode 100644 index 00000000..2c24f182 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/reduceZeroDividedByAnything.test.js @@ -0,0 +1,11 @@ +const reduceZeroDividedByAnything = require('../../../lib/simplifyExpression/basicsSearch/reduceZeroDividedByAnything'); + +const testSimplify = require('./testSimplify'); + +describe('simplify basics', function () { + const tests = [ + ['0/5', '0'], + ['0/(x+6+7+x^2+2^y)', '0'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], reduceZeroDividedByAnything)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js new file mode 100644 index 00000000..1d288236 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeAdditionOfZero.test.js @@ -0,0 +1,12 @@ +const removeAdditionOfZero = require('../../../lib/simplifyExpression/basicsSearch/removeAdditionOfZero'); + +const testSimplify = require('./testSimplify'); + +describe('removeAdditionOfZero', function() { + var tests = [ + ['2+0+x', '2 + x'], + ['2+x+0', '2 + x'], + ['0+2+x', '2 + x'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeAdditionOfZero)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js new file mode 100644 index 00000000..acee1f9f --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeDivisionByOne.test.js @@ -0,0 +1,7 @@ +const removeDivisionByOne = require('../../../lib/simplifyExpression/basicsSearch/removeDivisionByOne'); + +const testSimplify = require('./testSimplify'); + +describe('removeDivisionByOne', function() { + testSimplify('x/1', 'x', removeDivisionByOne); +}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js new file mode 100644 index 00000000..5aac993f --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeExponentBaseOne.test.js @@ -0,0 +1,12 @@ +const removeExponentBaseOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentBaseOne'); + +const testSimplify = require('./testSimplify'); + +describe('removeExponentBaseOne', function() { + const tests = [ + ['1^3', '1'], + ['1^x', '1^x'], + ['1^(2 + 3 + 5/4 + 7 - 6/7)', '1'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeExponentBaseOne)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeExponentByOne.test.js b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.js new file mode 100644 index 00000000..047d1de4 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeExponentByOne.test.js @@ -0,0 +1,7 @@ +const removeExponentByOne = require('../../../lib/simplifyExpression/basicsSearch/removeExponentByOne'); + +const testSimplify = require('./testSimplify'); + +describe('removeExponentByOne', function() { + testSimplify('x^1', 'x', removeExponentByOne); +}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js new file mode 100644 index 00000000..e701c1f1 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne.test.js @@ -0,0 +1,12 @@ +const removeMultiplicationByNegativeOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByNegativeOne'); + +const testSimplify = require('./testSimplify'); + +describe('removeMultiplicationByNegativeOne', function() { + const tests = [ + ['-1*x', '-x'], + ['x^2*-1', '-x^2'], + ['2x*2*-1', '2x * 2 * -1'], // does not remove multiplication by -1 + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByNegativeOne)); +}); diff --git a/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js new file mode 100644 index 00000000..0e554444 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/removeMultiplicationByOne.test.js @@ -0,0 +1,13 @@ +const removeMultiplicationByOne = require('../../../lib/simplifyExpression/basicsSearch/removeMultiplicationByOne'); + +const testSimplify = require('./testSimplify'); + +describe('removeMultiplicationByOne', function() { + const tests = [ + ['x*1', 'x'], + ['1x', 'x'], + ['1*z^2', 'z^2'], + ['2*1*z^2', '2 * 1z^2'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], removeMultiplicationByOne)); +}); diff --git a/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js new file mode 100644 index 00000000..33c13a44 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus.test.js @@ -0,0 +1,12 @@ +const simplifyDoubleUnaryMinus = require('../../../lib/simplifyExpression/basicsSearch/simplifyDoubleUnaryMinus'); + +const testSimplify = require('./testSimplify'); + + +describe('simplifyDoubleUnaryMinus', function() { + var tests = [ + ['--5', '5'], + ['--x', 'x'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], simplifyDoubleUnaryMinus)); +}); diff --git a/test/simplifyExpression/basicsSearch/testSimplify.js b/test/simplifyExpression/basicsSearch/testSimplify.js new file mode 100644 index 00000000..fdf6be37 --- /dev/null +++ b/test/simplifyExpression/basicsSearch/testSimplify.js @@ -0,0 +1,18 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const flatten = require('../../../lib/util/flattenOperands'); +const print = require('../../../lib/util/print'); + + +function testSimplify(exprStr, outputStr, simplifyOperation) { + it(exprStr + ' -> ' + outputStr, function () { + const inputNode = flatten(math.parse(exprStr)); + const newNode = simplifyOperation(inputNode).newNode; + assert.equal( + print(newNode), + outputStr); + }); +} + +module.exports = testSimplify; diff --git a/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js new file mode 100644 index 00000000..73aef5c1 --- /dev/null +++ b/test/simplifyExpression/breakUpNumeratorSearch/breakUpNumeratorSearch.test.js @@ -0,0 +1,16 @@ +const breakUpNumeratorSearch = require('../../../lib/simplifyExpression/breakUpNumeratorSearch'); + +const TestUtil = require('../../TestUtil'); + +function testBreakUpNumeratorSearch(exprStr, outputStr) { + TestUtil.testSimplification(breakUpNumeratorSearch, exprStr, outputStr); +} + +describe('breakUpNumerator', function() { + const tests = [ + ['(x+3+y)/3', '(x / 3 + 3/3 + y / 3)'], + ['(2+x)/4', '(2/4 + x / 4)'], + ['2(x+3)/3', '2 * (x / 3 + 3/3)'], + ]; + tests.forEach(t => testBreakUpNumeratorSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js new file mode 100644 index 00000000..baad5b9d --- /dev/null +++ b/test/simplifyExpression/collectAndCombineSearch/LikeTermCollector.test.js @@ -0,0 +1,97 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const flatten = require('../../../lib/util/flattenOperands'); +const print = require('../../../lib/util/print'); + +const LikeTermCollector = require('../../../lib/simplifyExpression/collectAndCombineSearch/LikeTermCollector'); + +function testCollectLikeTerms(exprStr, outputStr, explanation='', debug=false) { + let description = `${exprStr} -> ${outputStr}`; + + if (explanation) { + description += ` (${explanation})`; + } + + it(description, () => { + const exprTree = flatten(math.parse(exprStr)); + const collected = print(LikeTermCollector.collectLikeTerms(exprTree).newNode); + if (debug) { + // eslint-disable-next-line + console.log(collected); + } + assert.equal(collected, outputStr); + }); +} + +function testCanCollectLikeTerms(exprStr, canCollect, explanation) { + let description = `${exprStr} -> ${canCollect}`; + + if (explanation) { + description += ` (${explanation})`; + } + + it(description , () => { + const exprTree = flatten(math.parse(exprStr)); + assert.equal( + LikeTermCollector.canCollectLikeTerms(exprTree), + canCollect); + }); +} + +describe('can collect like terms for addition', function () { + const tests = [ + ['2+2', false, 'because only one type'], + ['x^2+x^2', false, 'because only one type'], + ['x+2', false, 'because all types have only one'], + ['(x+2+x)', false, 'because in parenthesis, need to be collected first'], + ['x+2+x', true], + ['x^2 + 5 + x + x^2', true], + ]; + tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('can collect like terms for multiplication', function () { + const tests = [ + ['2*2', false, 'because only one type'], + ['x^2 * 2x^2', true], + ['x * 2', false, 'because all types have only one'], + ['((2x^2)) * y * x * y^3', true], + ]; + tests.forEach(t => testCanCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('basic addition collect like terms, no exponents or coefficients', function() { + const tests = [ + ['2+x+7', 'x + (2 + 7)'], + ['x + 4 + x + 5', '(x + x) + (4 + 5)'], + ['x + 4 + y', 'x + 4 + y'], + ['x + 4 + x + 4/9 + y + 5/7', '(x + x) + y + 4 + (4/9 + 5/7)'], + ['x + 4 + x + 2^x + 5', '(x + x) + (4 + 5) + 2^x', + 'because 2^x is an \'other\''], + ['z + 2*(y + x) + 4 + z', '(z + z) + 4 + 2 * (y + x)', + '2*(y + x) is an \'other\' cause it has parens'], + ]; + tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('collect like terms with exponents and coefficients', function() { + const tests = [ + ['x^2 + x + x^2 + x', '(x^2 + x^2) + (x + x)'], + ['y^2 + 5 + y^2 + 5', '(y^2 + y^2) + (5 + 5)'], + ['y + 5 + z^2', 'y + 5 + z^2'], + ['2x^2 + x + x^2 + 3x', '(2x^2 + x^2) + (x + 3x)'], + ]; + tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); +}); + +describe('collect like terms for multiplication', function() { + const tests = [ + ['2x^2 * y * x * y^3', '2 * (x^2 * x) * (y * y^3)'], + ['y^2 * 5 * y * 9', '(5 * 9) * (y^2 * y)'], + ['5y^2 * -4y * 9', '(5 * -4 * 9) * (y^2 * y)'], + ['5y^2 * -y * 9', '(5 * -1 * 9) * (y^2 * y)'], + ['y * 5 * (2+x) * y^2 * 1/3', '(5 * 1/3) * (y * y^2) * (2 + x)'], + ]; + tests.forEach(t => testCollectLikeTerms(t[0], t[1], t[2])); +}); diff --git a/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js new file mode 100644 index 00000000..b2335179 --- /dev/null +++ b/test/simplifyExpression/collectAndCombineSearch/collectAndCombineSearch.test.js @@ -0,0 +1,62 @@ +const collectAndCombineSearch = require('../../../lib/simplifyExpression/collectAndCombineSearch'); + +const TestUtil = require('../../TestUtil'); + +function testCollectAndCombineSubsteps(exprString, outputList, outputStr) { + TestUtil.testSubsteps(collectAndCombineSearch, exprString, outputList, outputStr); +} + +function testSimpleCollectAndCombineSearch(exprString, outputStr) { + TestUtil.testSimplification(collectAndCombineSearch, exprString, outputStr); +} + +describe('combinePolynomialTerms multiplication', function() { + const tests = [ + ['x^2 * x * x', + ['x^2 * x^1 * x^1', + 'x^(2 + 1 + 1)', + 'x^4'], + ], + ['y * y^3', + ['y^1 * y^3', + 'y^(1 + 3)', + 'y^4'], + ], + ['2x * x^2 * 5x', + ['(2 * 5) * (x * x^2 * x)', + '10 * (x * x^2 * x)', + '10x^4'], + '10x^4' + ], + ]; + tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1], t[2])); +}); + +describe('combinePolynomialTerms addition', function() { + const tests = [ + ['x+x', + ['1x + 1x', + '(1 + 1) * x', + '2x'] + ], + ['4y^2 + 7y^2 + y^2', + ['4y^2 + 7y^2 + 1y^2', + '(4 + 7 + 1) * y^2', + '12y^2'] + ], + ['2x + 4x + y', + ['(2x + 4x) + y', + '6x + y'], + '6x + y' + ], + ]; + tests.forEach(t => testCollectAndCombineSubsteps(t[0], t[1])); +}); + +describe('collectAndCombineSearch with no substeps', function () { + const tests = [ + ['2x + 4x + x', '7x'], + ['x * x^2 * x', 'x^4'] + ]; + tests.forEach(t => testSimpleCollectAndCombineSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js new file mode 100644 index 00000000..972c2f57 --- /dev/null +++ b/test/simplifyExpression/collectAndCombineSearch/evaluateConstantSum.test.js @@ -0,0 +1,33 @@ +const evaluateConstantSum = require('../../../lib/simplifyExpression/collectAndCombineSearch/evaluateConstantSum'); + +const TestUtil = require('../../TestUtil'); + +function testEvaluateConstantSum(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(evaluateConstantSum, exprString, outputList, lastString); +} + +describe('evaluateConstantSum', function () { + const tests = [ + ['4/10 + 3/5', + ['4/10 + (3 * 2) / (5 * 2)', + '4/10 + (3 * 2) / 10', + '4/10 + 6/10', + '(4 + 6) / 10', + '10/10', + '1'] + ], + ['4/5 + 3/5 + 2', + ['2 + (4/5 + 3/5)', + '2 + 7/5', + '17/5'] + ], + ['9 + 4/5 + 1/5 + 2', + ['(9 + 2) + (4/5 + 1/5)', + '11 + (4/5 + 1/5)', + '11 + 1', + '12'] + ], + ]; + tests.forEach(t => testEvaluateConstantSum(t[0], t[1])); +}); diff --git a/test/simplifyExpression/distributeSearch/distributeSearch.test.js b/test/simplifyExpression/distributeSearch/distributeSearch.test.js new file mode 100644 index 00000000..0aa38c6c --- /dev/null +++ b/test/simplifyExpression/distributeSearch/distributeSearch.test.js @@ -0,0 +1,89 @@ +const distributeSearch = require('../../../lib/simplifyExpression/distributeSearch'); + +const TestUtil = require('../../TestUtil'); + +function testDistribute(exprStr, outputStr) { + TestUtil.testSimplification(distributeSearch, exprStr, outputStr); +} + +describe('distribute - into paren with addition', function () { + const tests = [ + ['-(x+3)', '(-x - 3)'], + ['-(x - 3)', '(-x + 3)'], + ['-(-x^2 + 3y^6)' , '(x^2 - 3y^6)'], + ]; + tests.forEach(t => testDistribute(t[0], t[1])); +}); + +describe('distribute - into paren with multiplication/division', function () { + const tests = [ + ['-(x*3)', '(-x * 3)'], + ['-(-x * 3)', '(x * 3)'], + ['-(-x^2 * 3y^6)', '(x^2 * 3y^6)'], + ]; + tests.forEach(t => testDistribute(t[0], t[1])); +}); + +function testDistributeSteps(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(distributeSearch, exprString, outputList, lastString); +} + +describe('distribute', function () { + const tests = [ + ['x*(x+2+y)', + ['(x * x + x * 2 + x * y)', + '(x^2 + 2x + x * y)'] + ], + ['(x+2+y)*x*7', + ['(x * x + 2x + y * x) * 7', + '(x^2 + 2x + y * x) * 7'] + ], + ['(5+x)*(x+3)', + ['(5 * (x + 3) + x * (x + 3))', + '((5x + 15) + (x^2 + 3x))'] + ], + ['-2x^2 * (3x - 4)', + ['(-2x^2 * 3x - 2x^2 * -4)', + '(-6x^3 + 8x^2)'] + ], + ]; + tests.forEach(t => testDistributeSteps(t[0], t[1])); +}); + +describe('distribute with fractions', function () { + const tests = [ + // distribute the non-fraction term into the numerator(s) + ['(3 / x^2 + x / (x^2 + 3)) * (x^2 + 3)', + '((3 * (x^2 + 3)) / (x^2) + (x * (x^2 + 3)) / (x^2 + 3))', + ], + + // if both groupings have fraction, the rule does not apply + ['(3 / x^2 + x / (x^2 + 3)) * (5 / x + x^5)', + '((3 / (x^2) * 5 / x + 3 / (x^2) * x^5) + (x / (x^2 + 3) * 5 / x + x / (x^2 + 3) * x^5))', + ], + ]; + + const multiStepTests = [ + + ['(2 / x + 3x^2) * (x^3 + 1)', + ['((2 * (x^3 + 1)) / x + 3x^2 * (x^3 + 1))', + '((2 * (x^3 + 1)) / x + (3x^5 + 3x^2))'] + ], + + ['(2x + x^2) * (1 / (x^2 -4) + 4x^2)', + ['((1 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', + '((1 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] + ], + + ['(2x + x^2) * (3x^2 / (x^2 -4) + 4x^2)', + ['((3x^2 * (2x + x^2)) / (x^2 - 4) + 4x^2 * (2x + x^2))', + '((3x^2 * (2x + x^2)) / (x^2 - 4) + (8x^3 + 4x^4))'] + ], + + ]; + + tests.forEach(t => testDistribute(t[0], t[1])); + + multiStepTests.forEach(t => testDistributeSteps(t[0], t[1])); +}); diff --git a/test/simplifyExpression/divisionSearch/divisionSearch.test.js b/test/simplifyExpression/divisionSearch/divisionSearch.test.js new file mode 100644 index 00000000..2d4a3a5b --- /dev/null +++ b/test/simplifyExpression/divisionSearch/divisionSearch.test.js @@ -0,0 +1,21 @@ +const divisionSearch = require('../../../lib/simplifyExpression/divisionSearch'); + +const TestUtil = require('../../TestUtil'); + +function testSimplifyDivision(exprStr, outputStr) { + TestUtil.testSimplification(divisionSearch, exprStr, outputStr); +} + +describe('simplifyDivision', function () { + const tests = [ + ['6/x/5', '6 / (x * 5)'], + ['-(6/x/5)', '-(6 / (x * 5))'], + ['-6/x/5', '-6 / (x * 5)'], + ['(2+2)/x/6/(y-z)','(2 + 2) / (x * 6 * (y - z))'], + ['2/x', '2 / x'], + ['x/(2/3)', 'x * 3/2'], + ['x / (y/(z+a))', 'x * (z + a) / y'], + ['x/((2+z)/(3/y))', 'x * (3 / y) / (2 + z)'], + ]; + tests.forEach(t => testSimplifyDivision(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js new file mode 100644 index 00000000..0219bb8b --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/addConstantAndFraction.test.js @@ -0,0 +1,32 @@ +const addConstantAndFraction = require('../../../lib/simplifyExpression/fractionsSearch/addConstantAndFraction'); + +const TestUtil = require('../../TestUtil'); + +function testAddConstantAndFraction(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(addConstantAndFraction, exprString, outputList, lastString); +} + +describe('addConstantAndFraction', function () { + const tests = [ + ['7 + 1/2', + ['14/2 + 1/2', + '(14 + 1) / 2', + '15/2'] + ], + ['5/6 + 3', + ['5/6 + 18/6', + '(5 + 18) / 6', + '23/6'], + ], + ['1/2 + 5.8', + ['0.5 + 5.8', + '6.3'], + ], + ['1/3 + 5.8', + ['0.3333 + 5.8', + '6.1333'] + ], + ]; + tests.forEach(t => testAddConstantAndFraction(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/addConstantFractions.test.js b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.js new file mode 100644 index 00000000..c023d94c --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/addConstantFractions.test.js @@ -0,0 +1,38 @@ +const addConstantFractions = require('../../../lib/simplifyExpression/fractionsSearch/addConstantFractions'); + +const TestUtil = require('../../TestUtil'); + +function testAddConstantFractions(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(addConstantFractions, exprString, outputList, lastString); +} + +describe('addConstantFractions', function () { + const tests = [ + ['4/5 + 3/5', + ['(4 + 3) / 5', + '7/5'] + ], + ['4/10 + 3/5', + ['4/10 + (3 * 2) / (5 * 2)', + '4/10 + (3 * 2) / 10', + '4/10 + 6/10', + '(4 + 6) / 10', + '10/10', + '1'] + ], + ['4/9 + 3/5', + ['(4 * 5) / (9 * 5) + (3 * 9) / (5 * 9)', + '(4 * 5) / 45 + (3 * 9) / 45', + '20/45 + 27/45', + '(20 + 27) / 45', + '47/45'] + ], + ['4/5 - 4/5', + ['(4 - 4) / 5', + '0/5', + '0'] + ], + ]; + tests.forEach(t => testAddConstantFractions(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js new file mode 100644 index 00000000..936d6ffe --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/cancelLikeTerms.test.js @@ -0,0 +1,33 @@ +const cancelLikeTerms = require('../../../lib/simplifyExpression/fractionsSearch/cancelLikeTerms'); + +const TestUtil = require('../../TestUtil'); + +function testCancelLikeTerms(exprStr, expectedStr) { + TestUtil.testSimplification(cancelLikeTerms, exprStr, expectedStr); +} + +describe('cancel like terms', function () { + const tests = [ + ['2/2', '1'], + ['x^2/x^2', '1'], + ['x^3/x^2', 'x^(3 - (2))'], // parens will be removed at end of step + ['(x^3*y)/x^2', '(x^(3 - (2)) * y)'], + ['-(7+x)^8/(7+x)^2', '-((7 + x)^(8 - (2)))'], + ['(2x^2 * 5) / (2x^2)', '5'], // these parens have to stay around 2x^2 to be parsed correctly. + ['(x^2 * y) / x', '(x^(2 - (1)) * y)'], + ['2x^2 / (2x^2 * 5)', '1/5'], + ['x / (x^2*y)', 'x^(1 - (2)) / y'], + ['(4x^2) / (5x^2)', '(4) / (5)'], + ['(2x+5)^8 / (2x+5)^2', '(2x + 5)^(8 - (2))'], + ['(4x^3) / (5x^2)', '(4x^(3 - (2))) / (5)'], + ['-x / -x', '1'], + ]; + + tests.forEach(t => { + const before = t[0]; + const after = t[1]; + it(before + ' -> ' + after, function () { + testCancelLikeTerms(before, after); + }); + }); +}); diff --git a/test/simplifyExpression/fractionsSearch/divideByGCD.test.js b/test/simplifyExpression/fractionsSearch/divideByGCD.test.js new file mode 100644 index 00000000..73a4d090 --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/divideByGCD.test.js @@ -0,0 +1,19 @@ +const divideByGCD = require('../../../lib/simplifyExpression/fractionsSearch/divideByGCD'); + +const TestUtil = require('../../TestUtil'); + +function testdivideByGCD(exprStr, outputStr) { + TestUtil.testSimplification(divideByGCD, exprStr, outputStr); +} + +describe('simplifyFraction', function() { + const tests = [ + ['2/4', '1/2'], + ['9/3', '3'], + ['12/27', '4/9'], + ['1/-3', '-1/3'], + ['-3/-2', '3/2'], + ['-1/-1', '1'], + ]; + tests.forEach(t => testdivideByGCD(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js new file mode 100644 index 00000000..c4aa000a --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/simplifyFractionSigns.test.js @@ -0,0 +1,15 @@ +const simplifyFractionSigns = require('../../../lib/simplifyExpression/fractionsSearch/simplifyFractionSigns'); + +const TestUtil = require('../../TestUtil'); + +function testSimplifyFractionSigns(exprStr, outputStr) { + TestUtil.testSimplification(simplifyFractionSigns, exprStr, outputStr); +} + +describe('simplify signs', function() { + const tests = [ + ['-12x / -27', '12x / 27'], + ['x / -y', '-x / y'], + ]; + tests.forEach(t => testSimplifyFractionSigns(t[0], t[1])); +}); diff --git a/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js new file mode 100644 index 00000000..1d16748d --- /dev/null +++ b/test/simplifyExpression/fractionsSearch/simplifyPolynomialFraction.test.js @@ -0,0 +1,20 @@ +const simplifyPolynomialFraction = require('../../../lib/simplifyExpression/fractionsSearch/simplifyPolynomialFraction'); + +const TestUtil = require('../../TestUtil'); + +function testSimplifyPolynomialFraction(exprStr, outputStr) { + TestUtil.testSimplification(simplifyPolynomialFraction, exprStr, outputStr); +} + +describe('simplifyPolynomialFraction', function() { + const tests = [ + ['2x/4', '1/2 x'], + ['9y/3', '3y'], + ['y/-3', '-1/3 y'], + ['-3y/-2', '3/2 y'], + ['-y/-1', 'y'], + ['12z^2/27', '4/9 z^2'], + ['1.6x / 1.6', 'x'], + ]; + tests.forEach(t => testSimplifyPolynomialFraction(t[0], t[1])); +}); diff --git a/test/simplifyExpression/functionsSearch/absoluteValue.test.js b/test/simplifyExpression/functionsSearch/absoluteValue.test.js new file mode 100644 index 00000000..923c6561 --- /dev/null +++ b/test/simplifyExpression/functionsSearch/absoluteValue.test.js @@ -0,0 +1,15 @@ +const absoluteValue = require('../../../lib/simplifyExpression/functionsSearch/absoluteValue'); + +const TestUtil = require('../../TestUtil'); + +function testAbsoluteValue(exprString, outputStr) { + TestUtil.testSimplification(absoluteValue, exprString, outputStr); +} + +describe('abs', function () { + const tests = [ + ['abs(4)', '4'], + ['abs(-5)', '5'], + ]; + tests.forEach(t => testAbsoluteValue(t[0], t[1])); +}); diff --git a/test/simplifyExpression/functionsSearch/nthRoot.test.js b/test/simplifyExpression/functionsSearch/nthRoot.test.js new file mode 100644 index 00000000..21352c5b --- /dev/null +++ b/test/simplifyExpression/functionsSearch/nthRoot.test.js @@ -0,0 +1,72 @@ +const nthRoot = require('../../../lib/simplifyExpression/functionsSearch/nthRoot'); + +const TestUtil = require('../../TestUtil'); + +function testNthRoot(exprString, outputStr) { + TestUtil.testSimplification(nthRoot, exprString, outputStr); +} + +describe('simplify nthRoot', function () { + const tests = [ + ['nthRoot(4)', '2'], + ['nthRoot(8, 3)', '2'], + ['nthRoot(5 * 7)', 'nthRoot(5 * 7)'], + ['nthRoot(4, 3)', 'nthRoot(4, 3)'], + ['nthRoot(12)', '2 * nthRoot(3, 2)'], + ['nthRoot(36)', '6'], + ['nthRoot(72)', '2 * 3 * nthRoot(2, 2)'], + ['nthRoot(x^2)', 'x'], + ['nthRoot(x ^ 3)', 'nthRoot(x ^ 3)'], + ['nthRoot(x^3, 3)', 'x'], + ['nthRoot(-2)', 'nthRoot(-2)'], + ['nthRoot(2 ^ x, x)', '2'], + ['nthRoot(x ^ (1/2), 1/2)', 'x'], + ['nthRoot(2 * 2, 2)', '2'], + ['nthRoot(3 * 2 * 3 * 2, 2)', '2 * 3'], + ['nthRoot(36*x)', '2 * 3 * nthRoot(x, 2)'], + ['nthRoot(2 * 18 * x ^ 2, 2)', '2 * 3 * x'], + ['nthRoot(x * x, 2)', 'x'], + ['nthRoot(x * x * (2 + 3), 2)', 'x * nthRoot((2 + 3), 2)'], + ]; + tests.forEach(t => testNthRoot(t[0], t[1])); +}); + +function testNthRootSteps(exprString, outputList) { + const lastString = outputList[outputList.length - 1]; + TestUtil.testSubsteps(nthRoot, exprString, outputList, lastString); +} + +describe('nthRoot steps', function () { + const tests = [ + ['nthRoot(12)', + ['nthRoot(2 * 2 * 3)', + 'nthRoot((2 * 2) * 3)', + 'nthRoot(2 ^ 2 * 3)', + 'nthRoot(2 ^ 2, 2) * nthRoot(3, 2)', + '2 * nthRoot(3, 2)'] + ], + ['nthRoot(72)', + ['nthRoot(2 * 2 * 2 * 3 * 3)', + 'nthRoot((2 * 2) * 2 * (3 * 3))', + 'nthRoot(2 ^ 2 * 2 * 3 ^ 2)', + 'nthRoot(2 ^ 2, 2) * nthRoot(2, 2) * nthRoot(3 ^ 2, 2)', + '2 * nthRoot(2, 2) * 3', + '2 * 3 * nthRoot(2, 2)'] + ], + ['nthRoot(36*x)', + ['nthRoot(2 * 2 * 3 * 3 * x)', + 'nthRoot((2 * 2) * (3 * 3) * x)', + 'nthRoot(2 ^ 2 * 3 ^ 2 * x)', + 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x, 2)', + '2 * 3 * nthRoot(x, 2)'] + ], + ['nthRoot(2 * 18 * x ^ 2, 2)', + ['nthRoot(2 * 2 * 3 * 3 * x ^ 2, 2)', + 'nthRoot((2 * 2) * (3 * 3) * x ^ 2, 2)', + 'nthRoot(2 ^ 2 * 3 ^ 2 * x ^ 2, 2)', + 'nthRoot(2 ^ 2, 2) * nthRoot(3 ^ 2, 2) * nthRoot(x ^ 2, 2)', + '2 * 3 * x'] + ] + ]; + tests.forEach(t => testNthRootSteps(t[0], t[1])); +}); diff --git a/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js new file mode 100644 index 00000000..0e319d8b --- /dev/null +++ b/test/simplifyExpression/multiplyFractionsSearch/multiplyFractionsSearch.test.js @@ -0,0 +1,16 @@ +const multiplyFractionsSearch = require('../../../lib/simplifyExpression//multiplyFractionsSearch'); + +const TestUtil = require('../../TestUtil'); + +function testMultiplyFractionsSearch(exprString, outputStr) { + TestUtil.testSimplification(multiplyFractionsSearch, exprString, outputStr); +} + +describe('multiplyFractions', function () { + const tests = [ + ['3 * 1/5 * 5/9', '(3 * 1 * 5) / (5 * 9)'], + ['3/7 * 10/11', '(3 * 10) / (7 * 11)'], + ['2 * 5/x', '(2 * 5) / x'] + ]; + tests.forEach(t => testMultiplyFractionsSearch(t[0], t[1])); +}); diff --git a/test/simplifyExpression/oneStep.test.js b/test/simplifyExpression/oneStep.test.js new file mode 100644 index 00000000..ead906be --- /dev/null +++ b/test/simplifyExpression/oneStep.test.js @@ -0,0 +1,96 @@ +const assert = require('assert'); + +const print = require('../../lib/util/print'); + +const ChangeTypes = require('../../lib/ChangeTypes'); +const simplifyExpression = require('../../lib/simplifyExpression'); + +function testOneStep(exprStr, outputStr, debug=false) { + const steps = simplifyExpression(exprStr); + if (!steps.length) { + return exprStr; + } + const nodeStatus = steps[0]; + if (debug) { + if (!nodeStatus.changeType) { + throw Error('missing or bad change type'); + } + // eslint-disable-next-line + console.log(nodeStatus.changeType); + // eslint-disable-next-line + console.log(print(nodeStatus.newNode)); + } + it(exprStr + ' -> ' + outputStr, function () { + assert.deepEqual( + print(nodeStatus.newNode), + outputStr); + }); +} + +describe('arithmetic stepping', function() { + const tests = [ + ['(2+2)', '4'], + ['(2+2)*5', '4 * 5'], + ['5*(2+2)', '5 * 4'], + ['2*(2+2) + 2^3', '2 * 4 + 2^3'], + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('adding symbols without breaking things', function() { + // nothing old breaks + const tests = [ + ['2+x', '2 + x'], + ['(2+2)*x', '4x'], + ['(2+2)*x+3', '4x + 3'], + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('collecting like terms within the context of the stepper', function() { + const tests = [ + ['2+x+7', 'x + 9'], // substeps not tested here +// ['2x^2 * y * x * y^3', '2 * x^3 * y^4'], // substeps not tested here + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('collects and combines like terms', function() { + const tests = [ + ['(x + x) + (x^2 + x^2)', '2x + (x^2 + x^2)'], // substeps not tested here + ['10 + (y^2 + y^2)', '10 + 2y^2'], // substeps not tested here + ['10y^2 + 1/2 y^2 + 3/2 y^2', '12y^2'], // substeps not tested here + ['x + y + y^2', 'x + y + y^2'], + ['2x^(2+1)', '2x^3'], + ]; + tests.forEach(t => testOneStep(t[0], t[1])); +}); + +describe('stepThrough returning no steps', function() { + it('12x^2 already simplified', function () { + assert.deepEqual( + simplifyExpression('12x^2'), + []); + }); + it('2*5x^2 + sqrt(5) has unsupported sqrt', function () { + assert.deepEqual( + simplifyExpression('2*5x^2 + sqrt(5)'), + []); + }); +}); + +describe('keeping parens in important places, on printing', function() { + testOneStep('5 + (3*6) + 2 / (x / y)', '5 + (3 * 6) + 2 * y / x'); + testOneStep('-(x + y) + 5+3', '8 - (x + y)'); +}); + +describe('fractions', function() { + testOneStep('2 + 5/2 + 3', '5 + 5/2'); // collect and combine without substeps +}); + +describe('simplifyDoubleUnaryMinus step actually happens', function () { + it('22 - (-7) -> 22 + 7', function() { + const steps = simplifyExpression('22 - (-7)'); + assert.equal(steps[0].changeType, ChangeTypes.RESOLVE_DOUBLE_MINUS); + }); +}); diff --git a/test/simplifyExpression/simplify.test.js b/test/simplifyExpression/simplify.test.js new file mode 100644 index 00000000..1cefba3b --- /dev/null +++ b/test/simplifyExpression/simplify.test.js @@ -0,0 +1,168 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const print = require('../../lib/util/print'); + +const simplify = require('../../lib/simplifyExpression/simplify'); + +function testSimplify(exprStr, outputStr, debug=false) { + it(exprStr + ' -> ' + outputStr, function () { + assert.deepEqual( + print(simplify(math.parse(exprStr), debug)), + outputStr); + }); +} + +describe('simplify (arithmetic)', function () { + const tests = [ + ['(2+2)*5', '20'], + ['(8+(-4))*5', '20'], + ['5*(2+2)*10', '200'], + ['(2+(2)+7)', '11'], + ['(8-2) * 2^2 * (1+1) / (4 /2) / 5', '24/5'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('collects and combines like terms', function() { + const tests = [ + ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], + ['2x^2 * y * x * y^3', '2x^3 * y^4'], + ['4y*3*5', '60y'], + ['(2x^2 - 4) + (4x^2 + 3)', '6x^2 - 1'], + ['(2x^1 + 4) + (4x^2 + 3)', '4x^2 + 2x + 7'], + ['y * 2x * 10', '20x * y'], + ['x^y * x^z', 'x^(y + z)'], + ['x^(3+y) + x^(3+y)+ 4', '2x^(3 + y) + 4'], + ['x^2 + 3x*(-4x) + 5x^3 + 3x^2 + 6', '5x^3 - 8x^2 + 6'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + + +describe('can simplify with division', function () { + const tests = [ + ['2 * 4 / 5 * 10 + 3', '19'], + ['2x * 5x / 2', '5x^2'], + ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], + ['2x * 4x / 2 / 4', 'x^2'], + ['2x * y / z * 10', '20x * y / z'], + ['2x * 4x / 5 * 10 + 3', '16x^2 + 3'], + ['2x/x', '2'], + ['2x/4/3', '1/6 x'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); + // TODO: factor the numerator to cancel out with denominator + // e.g. (x^2 - 3 + 2)/(x-2) -> (x-1) +}); + +describe('subtraction support', function() { + const tests = [ + ['-(-(2+3))', '5'], + ['-(-5)', '5'], + ['-(-(2+x))', '2 + x'], + ['-------5', '-5'], + ['--(-----5) + 6', '1'], + ['x^2 + 3 - x*x', '3'], + ['-(2*x) * -(2 + 2)', '8x'], + ['(x-4)-5', 'x - 9'], + ['5-x-4', '-x + 1'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('support for more * and ( that come from latex conversion', function () { + const tests = [ + ['(3*x)*(4*x)', '12x^2'], + ['(12*z^(2))/27', '4/9 z^2'], + ['x^2 - 12x^2 + 5x^2 - 7', '-6x^2 - 7'], + ['-(12 x ^ 2)', '-12x^2'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('distribution', function () { + const tests = [ + ['(3*x)*(4*x)', '12x^2'], + ['(3+x)*(4+x)*(x+5)', 'x^3 + 12x^2 + 47x + 60'], + ['-2x^2 * (3x - 4)', '-6x^3 + 8x^2'], + ['x^2 - x^2*(12 + 5x) - 7', '-5x^3 - 11x^2 - 7'], + ['(5+x)*(x+3)', 'x^2 + 8x + 15'], + ['(x-2)(x-4)', 'x^2 - 6x + 8'], + ['- x*y^4 (6x * y^2 + 5x*y - 3x)', + '-6x^2 * y^6 - 5x^2 * y^5 + 3x^2 * y^4'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('fractions', function() { + const tests = [ + ['5x + (1/2)x', '11/2 x'], + ['x + x/2', '3/2 x'], + ['1 + 1/2', '3/2'], + ['2 + 5/2 + 3', '15/2'], + ['9/18-5/18', '2/9'], + ['2(x+3)/3', '2x / 3 + 2'], + ['5/18 - 9/18', '-2/9'], + ['9/18', '1/2'], + ['x/(2/3) + 5', '3/2 x + 5'], + ['(2+x)/6', '1/3 + x / 6'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('floating point', function() { + testSimplify('1.983*10', '19.83'); +}); + +describe('cancelling out', function() { + const tests = [ + ['(x^3*y)/x^2 + 5', 'x * y + 5'], + ['(x^(2)+y^(2))/(5x-6x) + 5', '-x - y^2 / x + 5'], + ['( p ^ ( 2) + 1)/( p ^ ( 2) + 1)', '1'], + ['(-x)/(x)', '-1'], + ['(x)/(-x)', '-1'], + ['((2x^3 y^2)/(-x^2 y^5))^(-2)', '(-2x * y^-3)^-2'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('absolute value support', function() { + const tests = [ + ['(x^3*y)/x^2 + abs(-5)', 'x * y + 5'], + ['-6 + -5 - abs(-4) + -10 - 3 abs(-4)', '-37'], + ['5*abs((2+2))*10', '200'], + ['5x + (1/abs(-2))x', '11/2 x'], + ['abs(5/18-abs(9/-18))', '2/9'], + // handle parens around abs() + ['( abs( -3) )/(3)', '1'], + ['- abs( -40)', '-40'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('nthRoot support', function() { + const tests = [ + ['nthRoot(4x, 2)', '2 * nthRoot(x, 2)'], + ['2 * nthRoot(4x, 2)', '4 * nthRoot(x, 2)'], + ['(x^3*y)/x^2 + nthRoot(4x, 2)', 'x * y + 2 * nthRoot(x, 2)'], + ['2 + nthRoot(4)', '4'], + ['x * nthRoot(x^4, 2)', 'x^3'], + ['x * nthRoot(2 + 2, 3)', 'x * nthRoot(4, 3)'], + ['x * nthRoot((2 + 2) * 2, 3)', '2x'], + ['nthRoot(x * (2 + 3) * x, 2)', 'x * nthRoot(5, 2)'] + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('handles unnecessary parens at root level', function() { + const tests = [ + ['(x+(y))', 'x + y'], + ['((x+y) + ((z^3)))', 'x + y + z^3'], + ]; + tests.forEach(t => testSimplify(t[0], t[1], t[2])); +}); + +describe('keeping parens in important places, on printing', function() { + testSimplify('2 / (2x^2) + 5', '2 / (2x^2) + 5'); +}); diff --git a/test/solveEquation/solveEquation.test.js b/test/solveEquation/solveEquation.test.js new file mode 100644 index 00000000..c127674c --- /dev/null +++ b/test/solveEquation/solveEquation.test.js @@ -0,0 +1,130 @@ +const assert = require('assert'); + +const ChangeTypes = require('../../lib/ChangeTypes'); +const solveEquation = require('../../lib/solveEquation'); + +const NO_STEPS = 'no-steps'; + +function testSolve(equationString, outputStr, debug=false) { + const steps = solveEquation(equationString, debug); + let lastStep; + if (steps.length === 0) { + lastStep = NO_STEPS; + } + else { + lastStep = steps[steps.length -1].newEquation.print(); + } + it(equationString + ' -> ' + outputStr, (done) => { + assert.equal(lastStep, outputStr); + done(); + }); +} + +describe('solveEquation for =', function () { + const tests = [ + // can't solve this because two symbols: g and x -- so there's no steps + ['g *( x ) = ( x - 4) ^ ( 2) - 3', NO_STEPS], + // can't solve this because we don't deal with the complicated fraction yet + ['( x )/( 2x + 7) >= 4', NO_STEPS], + ['y - x - 2 = 3*2', 'y = 8 + x'], + ['2y - x - 2 = x', 'y = x + 1'], + ['x = 1', NO_STEPS], + ['2 = x', 'x = 2'], + ['2 + -3 = x', 'x = -1'], + ['x + 3 = 4', 'x = 1'], + ['2x - 3 = 0', 'x = 3/2'], + ['x/3 - 2 = -1', 'x = 3'], + ['5x/2 + 2 = 3x/2 + 10', 'x = 8'], + ['2x - 1 = -x', 'x = 1/3'], + ['2 - x = -4 + x', 'x = 3'], + ['2x/3 = 2', 'x = 3'], + ['2x - 3 = x', 'x = 3'], + ['8 - 2a = a + 3 - 1', 'a = 2'], + ['2 - x = 4', 'x = -2'], + ['2 - 4x = x', 'x = 2/5'], + ['9x + 4 - 3 = 2x', 'x = -1/7'], + ['9x + 4 - 3 = -2x', 'x = -1/11'], + ['(2x^2 - 1)(x^2 - 5)(x^2 + 5) = 0', '2x^6 - x^4 - 50x^2 = -25'], + ['(-x ^ 2 - 4x + 2)(-3x^2 - 6x + 3) = 0', '3x^4 + 18x^3 + 15x^2 - 24x = -6'], + ['5x + (1/2)x = 27 ', 'x = 54/11'], + ['2x/3 = 2x - 4 ', 'x = 3'], + ['(-2/3)x + 3/7 = 1/2', 'x = -3/28'], + ['-9/4v + 4/5 = 7/8 ', 'v = -1/30'], + // TODO: update test once we have root support + ['x^2 - 2 = 0', 'x^2 = 2'], + ['x/(2/3) = 1', 'x = 2/3'], + ['(x+1)/3 = 4', 'x = 11'], + ['2(x+3)/3 = 2', 'x = 0'], + ['( u )/( 0.3) = 4u + 6.28', 'u = -9.42'], + ['- q - 4.36= ( 2.2q )/( 1.8)', 'q = -1.962'], + // TODO: figure out what to do about errors from rounding midway through + // this gives us 6.3995 when it should actually be 6.4 :( + // ['x - 3.4= ( x - 2.5)/( 1.3)', 'x = 6.4'] + ]; + tests.forEach(t => testSolve(t[0], t[1], t[2])); +}); + +describe('solveEquation for non = comparators', function() { + const tests = [ + ['x + 2 > 3', 'x > 1'], + ['2x < 6', 'x < 3'], + ['-x > 1', 'x < -1'], + ['2 - x < 3', 'x > -1'], + ['9.5j / 6+ 5.5j >= 3( 5j - 2)', 'j <= 0.7579'] + ]; + tests.forEach(t => testSolve(t[0], t[1], t[2])); +}); + +function testSolveConstantEquation(equationString, expectedChange, debug=false) { + const steps = solveEquation(equationString, debug); + const actualChange = steps[steps.length -1].changeType; + it(equationString + ' -> ' + expectedChange, (done) => { + assert.equal(actualChange, expectedChange); + done(); + }); +} + +describe('constant comparison support', function () { + const tests = [ + ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], + ['3 + 5 = 8', ChangeTypes.STATEMENT_IS_TRUE], + ['1 = 2', ChangeTypes.STATEMENT_IS_FALSE], + ['2 - 3 = 5', ChangeTypes.STATEMENT_IS_FALSE], + ['2 > 1', ChangeTypes.STATEMENT_IS_TRUE], + ['2/3 > 1/3', ChangeTypes.STATEMENT_IS_TRUE], + ['1 > 2', ChangeTypes.STATEMENT_IS_FALSE], + ['1/3 > 2/3', ChangeTypes.STATEMENT_IS_FALSE], + ['1 >= 1', ChangeTypes.STATEMENT_IS_TRUE], + ['2 >= 1', ChangeTypes.STATEMENT_IS_TRUE], + ['1 >= 2', ChangeTypes.STATEMENT_IS_FALSE], + ['2 < 1', ChangeTypes.STATEMENT_IS_FALSE], + ['2/3 < 1/3', ChangeTypes.STATEMENT_IS_FALSE], + ['1 < 2', ChangeTypes.STATEMENT_IS_TRUE], + ['1/3 < 2/3', ChangeTypes.STATEMENT_IS_TRUE], + ['1 <= 1', ChangeTypes.STATEMENT_IS_TRUE], + ['2 <= 1', ChangeTypes.STATEMENT_IS_FALSE], + ['1 <= 2', ChangeTypes.STATEMENT_IS_TRUE], + ['( 1) = ( 14)', ChangeTypes.STATEMENT_IS_FALSE], + // TODO: when we support fancy exponent and sqrt things + // ['(1/64)^(-5/6) = 32', ChangeTypes.STATEMENT_IS_TRUE], + // With variables that cancel + ['( r )/( ( r ) ) = ( 1)/( 10)', ChangeTypes.STATEMENT_IS_FALSE], + ['5 + (x - 5) = x', ChangeTypes.STATEMENT_IS_TRUE], + ['4x - 4= 4x', ChangeTypes.STATEMENT_IS_FALSE], + ]; + tests.forEach(t => testSolveConstantEquation(t[0], t[1], t[2])); +}); + +function testEquationError(equationString, debug=false) { + it(equationString + ' throws error', (done) => { + assert.throws(() => solveEquation(equationString, debug),Error); + done(); + }); +} + +describe('solveEquation errors', function() { + const tests = [ + ['( x + 2) ^ ( 2) - x ^ ( 2) = 4( x + 1)'] + ]; + tests.forEach(t => testEquationError(t[0], t[1])); +}); diff --git a/test/util/Util.test.js b/test/util/Util.test.js new file mode 100644 index 00000000..a1706f84 --- /dev/null +++ b/test/util/Util.test.js @@ -0,0 +1,22 @@ +const assert = require('assert'); + +const Util = require('../../lib/util/Util'); + +describe('appendToArrayInObject', function () { + it('creates empty array', function () { + const object = {}; + Util.appendToArrayInObject(object, 'key', 'value'); + assert.deepEqual( + object, + {'key': ['value']} + ); + }); + it('appends to array if it exists', function () { + const object = {'key': ['old_value']}; + Util.appendToArrayInObject(object, 'key', 'new_value'); + assert.deepEqual( + object, + {'key': ['old_value', 'new_value']} + ); + }); +}); diff --git a/test/util/flattenOperands.test.js b/test/util/flattenOperands.test.js new file mode 100644 index 00000000..41ce2c67 --- /dev/null +++ b/test/util/flattenOperands.test.js @@ -0,0 +1,103 @@ +const assert = require('assert'); +const math = require('mathjs'); + +const flattenOperands = require('../../lib/util/flattenOperands'); +const print = require('../../lib/util/print'); + +const Node = require('../../lib/node'); + +function testFlatten(exprStr, afterNode, debug=false) { + const flattened = flattenOperands(math.parse(exprStr)); + if (debug) { + // eslint-disable-next-line + console.log(print(flattened)); + } + removeComments(flattened); + removeComments(afterNode); + it(print(flattened), function() { + assert.deepEqual(flattened, afterNode); + }); +} + +// to create nodes, for testing +const opNode = Node.Creator.operator; +const constNode = Node.Creator.constant; +const symbolNode = Node.Creator.symbol; +const parenNode = Node.Creator.parenthesis; + +describe('flattens + and *', function () { + const tests = [ + ['2+2', math.parse('2+2')], + ['2+2+7', opNode('+', [constNode(2), constNode(2), constNode(7)])], + ['9*8*6+3+4', + opNode('+', [ + opNode('*', [constNode(9), constNode(8), constNode(6)]), + constNode(3), + constNode(4)])], + ['5*(2+3+2)*10', + opNode('*', [ + constNode(5), + parenNode(opNode('+', [constNode(2), constNode(3),constNode(2)])), + constNode(10)])], + // keeps the polynomial term + ['9x*8*6+3+4', + opNode('+', [ + opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), + constNode(3), + constNode(4)])], + ['9x*8*6+3y^2+4', + opNode('+', [ + opNode('*', [math.parse('9x'), constNode(8), constNode(6)]), + math.parse('3y^2'), + constNode(4)])], + // doesn't flatten + ['2 x ^ (2 + 1) * y', math.parse('2 x ^ (2 + 1) * y')], + ['2 x ^ (2 + 1 + 2) * y', + opNode('*', [ + opNode('*', [constNode(2), + opNode('^', [symbolNode('x'), parenNode( + opNode('+', [constNode(2), constNode(1), constNode(2)]))]), + ], true), symbolNode('y')]) + ], + ['3x*4x', opNode('*', [math.parse('3x'), math.parse('4x')])] + ]; + tests.forEach(t => testFlatten(t[0], t[1])); +}); + +describe('flattens division', function () { + const tests = [ + // groups x/4 and continues to flatten * + ['2 * x / 4 * 6 ', + opNode('*', [opNode('/', [ + math.parse('2x'), math.parse('4')]), constNode(6)])], + ['2*3/4/5*6', + opNode('*', [constNode(2), math.parse('3/4/5'), constNode(6)])], + // combines coefficient with x + ['x / (4 * x) / 8', + math.parse('x / (4x) / 8')], + ['2 x * 4 x / 8', + opNode('*', [math.parse('2x'), opNode( + '/', [math.parse('4x'), constNode(8)])])], + ]; + tests.forEach(t => testFlatten(t[0], t[1])); +}); + +describe('subtraction', function () { + const tests = [ + ['1 + 2 - 3 - 4 + 5', + opNode('+', [ + constNode(1), constNode(2), constNode(-3), constNode(-4), constNode(5)])], + ['x - 3', opNode('+', [symbolNode('x'), constNode(-3)])], + ['x + 4 - (y+4)', + opNode('+', [symbolNode('x'), constNode(4), math.parse('-(y+4)')])], + ]; + tests.forEach(t => testFlatten(t[0], t[1])); +}); + + +// Remove some property used in mathjs that we don't need and prevents node +// equality checks from passing +function removeComments(node) { + node.filter(node => node.comment !== undefined).forEach( + node => delete node.comment); +} diff --git a/test/util/print.test.js b/test/util/print.test.js new file mode 100644 index 00000000..232e8cc9 --- /dev/null +++ b/test/util/print.test.js @@ -0,0 +1,48 @@ +const math = require('mathjs'); + +const Node = require('../../lib/node'); +const print = require('../../lib/util/print'); + +const TestUtil = require('../TestUtil'); + +// to create nodes, for testing +const opNode = Node.Creator.operator; +const constNode = Node.Creator.constant; +const symbolNode = Node.Creator.symbol; + +function testPrintStr(exprStr, outputStr) { + const input = math.parse(exprStr); + TestUtil.testFunctionOutput(print, input, outputStr); +} + +function testPrintNode(node, outputStr) { + TestUtil.testFunctionOutput(print, node, outputStr); +} + +describe('print asciimath', function () { + const tests = [ + ['2+3+4', '2 + 3 + 4'], + ['2 + (4 - x) + - 4', '2 + (4 - x) - 4'], + ['2/3 x^2', '2/3 x^2'], + ['-2/3', '-2/3'], + ]; + tests.forEach(t => testPrintStr(t[0], t[1])); +}); + +describe('print with parenthesis', function () { + const tests = [ + [opNode('*', [ + opNode('+', [constNode(2), constNode(3)]), + symbolNode('x') + ]), '(2 + 3) * x'], + [opNode('^', [ + opNode('-', [constNode(7), constNode(4)]), + symbolNode('x') + ]), '(7 - 4)^x'], + [opNode('/', [ + opNode('+', [constNode(9), constNode(2)]), + symbolNode('x') + ]), '(9 + 2) / x'], + ]; + tests.forEach(t => testPrintNode(t[0], t[1])); +}); diff --git a/test/util/removeUnnecessaryParens.test.js b/test/util/removeUnnecessaryParens.test.js new file mode 100644 index 00000000..9078cd33 --- /dev/null +++ b/test/util/removeUnnecessaryParens.test.js @@ -0,0 +1,30 @@ +const math = require('mathjs'); + +const print = require('../../lib/util/print'); +const removeUnnecessaryParens = require('../../lib/util/removeUnnecessaryParens'); + +const TestUtil = require('../TestUtil'); + +function testRemoveUnnecessaryParens(exprStr, outputStr) { + const input = removeUnnecessaryParens(math.parse(exprStr)); + TestUtil.testFunctionOutput(print, input, outputStr); +} + +describe('removeUnnecessaryParens', function () { + const tests = [ + ['(x+4) + 12', 'x + 4 + 12'], + ['-(x+4x) + 12', '-(x + 4x) + 12'], + ['x + (12)', 'x + 12'], + ['x + (y)', 'x + y'], + ['x + -(y)', 'x - y'], + ['((3 - 5)) * x', '(3 - 5) * x'], + ['((3 - 5)) * x', '(3 - 5) * x'], + ['(((-5)))', '-5'], + ['((4+5)) + ((2^3))', '(4 + 5) + 2^3'], + ['(2x^6 + -50 x^2) - (x^4)', '2x^6 - 50x^2 - x^4'], + ['(x+4) - (12 + x)', 'x + 4 - (12 + x)'], + ['(2x)^2', '(2x)^2'], + ['((4+x)-5)^(2)', '(4 + x - 5)^2'], + ]; + tests.forEach(t => testRemoveUnnecessaryParens(t[0], t[1])); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..d1395468 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "system", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "outDir": "lib", + "sourceMap": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file From 817568721b6ff17cef5461eee1327a5de4ca216f Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 14:05:13 -0700 Subject: [PATCH 06/12] Some more filestructure --- src/ChangeTypes.ts | 0 src/factor/factor.ts | 0 src/index.d.ts | 0 src/nodeHelper/Creator.ts | 4 + src/nodeHelper/PolynomialTerm.ts | 4 + src/nodeHelper/Status.ts | 4 + src/nodeHelper/Type.ts | 6 ++ src/nodeHelper/nodeHelper.ts | 5 ++ src/simplifyExpression/arithmeticSearch.ts | 0 src/simplifyExpression/basicsSearch.ts | 0 .../breakUpNumeratorSearch.ts | 0 .../collectAndCombineSearch.ts | 0 src/simplifyExpression/distributeSearch.ts | 0 src/simplifyExpression/divisionSearch.ts | 0 src/simplifyExpression/fractionsSearch.ts | 0 src/simplifyExpression/functionsSearch.ts | 0 .../multiplyFractionsSearch.ts | 0 src/solveEquation/EquationOperators.ts | 0 src/solveEquation/solveEquation.ts | 32 +++++++ src/util/Negative.ts | 89 +++++++++++++++++++ src/util/Symbols.ts | 0 src/util/TreeSearch.ts | 45 ++++++++++ tsconfig.json | 2 +- 23 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/ChangeTypes.ts create mode 100644 src/factor/factor.ts create mode 100644 src/index.d.ts create mode 100644 src/nodeHelper/Creator.ts create mode 100644 src/nodeHelper/PolynomialTerm.ts create mode 100644 src/nodeHelper/Status.ts create mode 100644 src/nodeHelper/Type.ts create mode 100644 src/nodeHelper/nodeHelper.ts create mode 100644 src/simplifyExpression/arithmeticSearch.ts create mode 100644 src/simplifyExpression/basicsSearch.ts create mode 100644 src/simplifyExpression/breakUpNumeratorSearch.ts create mode 100644 src/simplifyExpression/collectAndCombineSearch.ts create mode 100644 src/simplifyExpression/distributeSearch.ts create mode 100644 src/simplifyExpression/divisionSearch.ts create mode 100644 src/simplifyExpression/fractionsSearch.ts create mode 100644 src/simplifyExpression/functionsSearch.ts create mode 100644 src/simplifyExpression/multiplyFractionsSearch.ts create mode 100644 src/solveEquation/EquationOperators.ts create mode 100644 src/solveEquation/solveEquation.ts create mode 100644 src/util/Negative.ts create mode 100644 src/util/Symbols.ts create mode 100644 src/util/TreeSearch.ts diff --git a/src/ChangeTypes.ts b/src/ChangeTypes.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/factor/factor.ts b/src/factor/factor.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/nodeHelper/Creator.ts b/src/nodeHelper/Creator.ts new file mode 100644 index 00000000..1bd30d74 --- /dev/null +++ b/src/nodeHelper/Creator.ts @@ -0,0 +1,4 @@ +/// +namespace nodeHelper{ + +} \ No newline at end of file diff --git a/src/nodeHelper/PolynomialTerm.ts b/src/nodeHelper/PolynomialTerm.ts new file mode 100644 index 00000000..1bd30d74 --- /dev/null +++ b/src/nodeHelper/PolynomialTerm.ts @@ -0,0 +1,4 @@ +/// +namespace nodeHelper{ + +} \ No newline at end of file diff --git a/src/nodeHelper/Status.ts b/src/nodeHelper/Status.ts new file mode 100644 index 00000000..1bd30d74 --- /dev/null +++ b/src/nodeHelper/Status.ts @@ -0,0 +1,4 @@ +/// +namespace nodeHelper{ + +} \ No newline at end of file diff --git a/src/nodeHelper/Type.ts b/src/nodeHelper/Type.ts new file mode 100644 index 00000000..466247da --- /dev/null +++ b/src/nodeHelper/Type.ts @@ -0,0 +1,6 @@ +/// +namespace nodeHelper{ + /* + Determines the type of a Math + */ +} \ No newline at end of file diff --git a/src/nodeHelper/nodeHelper.ts b/src/nodeHelper/nodeHelper.ts new file mode 100644 index 00000000..76ae5fcb --- /dev/null +++ b/src/nodeHelper/nodeHelper.ts @@ -0,0 +1,5 @@ +namespace nodeHelper{ + export interface ParenthesisNode extends mathjs.MathNode{ + content?: mathjs.MathNode; + } +} \ No newline at end of file diff --git a/src/simplifyExpression/arithmeticSearch.ts b/src/simplifyExpression/arithmeticSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/basicsSearch.ts b/src/simplifyExpression/basicsSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/breakUpNumeratorSearch.ts b/src/simplifyExpression/breakUpNumeratorSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/collectAndCombineSearch.ts b/src/simplifyExpression/collectAndCombineSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/distributeSearch.ts b/src/simplifyExpression/distributeSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/divisionSearch.ts b/src/simplifyExpression/divisionSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/fractionsSearch.ts b/src/simplifyExpression/fractionsSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/functionsSearch.ts b/src/simplifyExpression/functionsSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/simplifyExpression/multiplyFractionsSearch.ts b/src/simplifyExpression/multiplyFractionsSearch.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/solveEquation/EquationOperators.ts b/src/solveEquation/EquationOperators.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/solveEquation/solveEquation.ts b/src/solveEquation/solveEquation.ts new file mode 100644 index 00000000..6abfa070 --- /dev/null +++ b/src/solveEquation/solveEquation.ts @@ -0,0 +1,32 @@ +module solveEquation{ +export function solveEquationString(equationString: string, debug=false) { + const comparators = ['<=', '>=', '=', '<', '>']; + + for (let i of comparators) { + const sides = equationString.split(i); + if (sides.length !== 2) { + continue; + } + let leftNode: mathjs.MathNode, rightNode: mathjs.MathNode; + const leftSide = sides[0].trim(); + const rightSide = sides[1].trim(); + + if (!leftSide || !rightSide) { + return []; + } + + try { + leftNode = math.parse(leftSide); + rightNode = math.parse(rightSide); + } + catch (err) { + return []; + } + if (leftNode && rightNode) { + return stepThrough(leftNode, rightNode, comparator, debug); + } + } + + return []; +} +} \ No newline at end of file diff --git a/src/util/Negative.ts b/src/util/Negative.ts new file mode 100644 index 00000000..b96b5812 --- /dev/null +++ b/src/util/Negative.ts @@ -0,0 +1,89 @@ + +// Returns if the given node is negative. Treats a unary minus as a negative, +// as well as a negative constant value or a constant fraction that would +// evaluate to a negative number +isNegative(node: mathjs.MathNode) { + if (Node.Type.isUnaryMinus(node)) { + return !Negative.isNegative(node.args[0]); + } + else if (Node.Type.isConstant(node)) { + return parseFloat(node.value) < 0; + } + else if (Node.Type.isConstantFraction(node)) { + const numeratorValue = parseFloat(node.args[0].value); + const denominatorValue = parseFloat(node.args[1].value); + if (numeratorValue < 0 || denominatorValue < 0) { + return !(numeratorValue < 0 && denominatorValue < 0); + } + } + else if (Node.PolynomialTerm.isPolynomialTerm(node)) { + const polyNode = new Node.PolynomialTerm(node); + return Negative.isNegative(polyNode.getCoeffNode(true)); + } + + return false; +}; + +// Given a node, returns the negated node +// If naive is true, then we just add an extra unary minus to the expression +// otherwise, we do the actual negation +// E.g. +// not naive: -3 -> 3, x -> -x +// naive: -3 -> --3, x -> -x +Negative.negate = function(node, naive=false) { + if (Node.Type.isConstantFraction(node)) { + node.args[0] = Negative.negate(node.args[0], naive); + return node; + } + else if (Node.PolynomialTerm.isPolynomialTerm(node)) { + return Negative.negatePolynomialTerm(node, naive); + } + else if (!naive) { + if (Node.Type.isUnaryMinus(node)) { + return node.args[0]; + } + else if (Node.Type.isConstant(node)) { + return Node.Creator.constant(0 - parseFloat(node.value)); + } + } + return Node.Creator.unaryMinus(node); +}; + +// Multiplies a polynomial term by -1 and returns the new node +// If naive is true, then we just add an extra unary minus to the expression +// otherwise, we do the actual negation +// E.g. +// not naive: -3x -> 3x, x -> -x +// naive: -3x -> --3x, x -> -x +Negative.negatePolynomialTerm = function(node, naive=false) { + if (!Node.PolynomialTerm.isPolynomialTerm(node)) { + throw Error('node is not a polynomial term'); + } + const polyNode = new Node.PolynomialTerm(node); + + let newCoeff; + if (!polyNode.hasCoeff()) { + newCoeff = Node.Creator.constant(-1); + } + else { + const oldCoeff = polyNode.getCoeffNode(); + if (oldCoeff.value === '-1') { + newCoeff = null; + } + else if (polyNode.hasFractionCoeff()) { + let numerator = oldCoeff.args[0]; + numerator = Negative.negate(numerator, naive); + + const denominator = oldCoeff.args[1]; + newCoeff = Node.Creator.operator('/', [numerator, denominator]); + } + else { + newCoeff = Negative.negate(oldCoeff, naive); + if (newCoeff.value === '1') { + newCoeff = null; + } + } + } + return Node.Creator.polynomialTerm( + polyNode.getSymbolNode(), polyNode.getExponentNode(), newCoeff); +}; \ No newline at end of file diff --git a/src/util/Symbols.ts b/src/util/Symbols.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/util/TreeSearch.ts b/src/util/TreeSearch.ts new file mode 100644 index 00000000..8ed4889f --- /dev/null +++ b/src/util/TreeSearch.ts @@ -0,0 +1,45 @@ +function search(simplificationFunction: function, node: mathjs.MathNode, preOrder: bool) { + let status; + + if (preOrder) { + status = simplificationFunction(node); + if (status.hasChanged()) { + return status; + } + } + + if (node.isConstantNode || node.isSymbolNode) { + return Node.Status.noChange(node); + } + else if (Node.Type.isUnaryMinus(node)) { + status = search(simplificationFunction, node.args[0], preOrder); + if (status.hasChanged()) { + return Node.Status.childChanged(node, status); + } + } + else if (node.isOperatorNode || Node.Type.isFunction(node)) { + for (let i = 0; i < node.args.length; i++) { + const child = node.args[i]; + const childNodeStatus = search(simplificationFunction, child, preOrder); + if (childNodeStatus.hasChanged()) { + return Node.Status.childChanged(node, childNodeStatus, i); + } + } + } + else if (Node.Type.isParenthesis(node)) { + status = search(simplificationFunction, node.content, preOrder); + if (status.hasChanged()) { + return Node.Status.childChanged(node, status); + } + } + else { + throw Error('Unsupported node type: ' + node); + } + + if (!preOrder) { + return simplificationFunction(node); + } + else { + return Node.Status.noChange(node); + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d1395468..b818afca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "module": "system", + "module": "commonJS", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, From d76fcc20e37abb0e967a4e8dfe4f00d6934e7dad Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 14:09:50 -0700 Subject: [PATCH 07/12] Add some other stuff --- src/factor/factor.ts | 13 +++++++++++++ src/util/util.ts | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/util/util.ts diff --git a/src/factor/factor.ts b/src/factor/factor.ts index e69de29b..29a2bf74 100644 --- a/src/factor/factor.ts +++ b/src/factor/factor.ts @@ -0,0 +1,13 @@ +namespace factor{ + //returns the + export getPrimeFactors(){ + + } + export getFactorPairs(){ + + } + export factorQuadratic{ + + } + +} \ No newline at end of file diff --git a/src/util/util.ts b/src/util/util.ts new file mode 100644 index 00000000..5c7a3d23 --- /dev/null +++ b/src/util/util.ts @@ -0,0 +1,10 @@ + +Util.appendToArrayInObject = function(dict, key, value) { + if (dict[key]) { + dict[key].push(value); + } + else { + dict[key] = [value]; + } + return dict; +}; \ No newline at end of file From 4e63ba06ee90a4933f0e20f65112887c6abf1ed7 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 15:14:26 -0700 Subject: [PATCH 08/12] More changes --- src/ChangeTypes.ts | 0 src/classes.ts | 5 + src/factor/factor.ts | 6 +- src/nodeHelper/Creator.ts | 4 - src/nodeHelper/PolynomialTerm.ts | 4 - src/nodeHelper/Status.ts | 4 - src/nodeHelper/Type.ts | 6 - src/nodeHelper/nodeHelper.ts | 296 ++++++++++++++++++++++++++++++- src/util/ChangeTypes.ts | 184 +++++++++++++++++++ src/util/Negative.ts | 2 +- src/util/TreeSearch.ts | 46 +---- src/util/clone.ts | 18 ++ src/util/util.ts | 7 +- 13 files changed, 510 insertions(+), 72 deletions(-) delete mode 100644 src/ChangeTypes.ts create mode 100644 src/classes.ts delete mode 100644 src/nodeHelper/Creator.ts delete mode 100644 src/nodeHelper/PolynomialTerm.ts delete mode 100644 src/nodeHelper/Status.ts delete mode 100644 src/nodeHelper/Type.ts create mode 100644 src/util/ChangeTypes.ts create mode 100644 src/util/clone.ts diff --git a/src/ChangeTypes.ts b/src/ChangeTypes.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/classes.ts b/src/classes.ts new file mode 100644 index 00000000..dead85db --- /dev/null +++ b/src/classes.ts @@ -0,0 +1,5 @@ + //extend utility for MathNode class + interface mNode extends mathjs.MathNode{ + changeGroup?: number; + content?: mathjs.MathNode; + } \ No newline at end of file diff --git a/src/factor/factor.ts b/src/factor/factor.ts index 29a2bf74..a4a1807a 100644 --- a/src/factor/factor.ts +++ b/src/factor/factor.ts @@ -1,12 +1,12 @@ namespace factor{ //returns the - export getPrimeFactors(){ + export function getPrimeFactors(number: number){ } - export getFactorPairs(){ + export function getFactorPairs(number: number){ } - export factorQuadratic{ + export function factorQuadratic{ } diff --git a/src/nodeHelper/Creator.ts b/src/nodeHelper/Creator.ts deleted file mode 100644 index 1bd30d74..00000000 --- a/src/nodeHelper/Creator.ts +++ /dev/null @@ -1,4 +0,0 @@ -/// -namespace nodeHelper{ - -} \ No newline at end of file diff --git a/src/nodeHelper/PolynomialTerm.ts b/src/nodeHelper/PolynomialTerm.ts deleted file mode 100644 index 1bd30d74..00000000 --- a/src/nodeHelper/PolynomialTerm.ts +++ /dev/null @@ -1,4 +0,0 @@ -/// -namespace nodeHelper{ - -} \ No newline at end of file diff --git a/src/nodeHelper/Status.ts b/src/nodeHelper/Status.ts deleted file mode 100644 index 1bd30d74..00000000 --- a/src/nodeHelper/Status.ts +++ /dev/null @@ -1,4 +0,0 @@ -/// -namespace nodeHelper{ - -} \ No newline at end of file diff --git a/src/nodeHelper/Type.ts b/src/nodeHelper/Type.ts deleted file mode 100644 index 466247da..00000000 --- a/src/nodeHelper/Type.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// -namespace nodeHelper{ - /* - Determines the type of a Math - */ -} \ No newline at end of file diff --git a/src/nodeHelper/nodeHelper.ts b/src/nodeHelper/nodeHelper.ts index 76ae5fcb..52366cda 100644 --- a/src/nodeHelper/nodeHelper.ts +++ b/src/nodeHelper/nodeHelper.ts @@ -1,5 +1,295 @@ -namespace nodeHelper{ - export interface ParenthesisNode extends mathjs.MathNode{ - content?: mathjs.MathNode; +/// +/// + +namespace nodeHelper { + + export class Status { + changeType: ChangeTypes; + oldNode: mNode; + newNode: mNode; + substeps: any; + constructor(changeType: ChangeTypes, oldNode: mNode, newNode: mNode, substeps = []) { + if (!newNode) { + throw Error('node is not defined'); + } + if (changeType === undefined || typeof (changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } + + this.changeType = changeType; + this.oldNode = oldNode; + this.newNode = newNode; + this.substeps = substeps; + } + hasChanged() { + return this.changeType !== ChangeTypes.NO_CHANGE; + } + resetChangeGroups = function (node: mNode) { + node = clone(node); + node.filter(node => node.changeGroup).forEach(change => { + delete change.changeGroup; + }); + return node; + }; + + // A wrapper around the Status constructor for the case where node hasn't + // been changed. + noChange(node: mNode) { + return new Status(ChangeTypes.NO_CHANGE, null, node); + }; + + // A wrapper around the Status constructor for the case of a change + // that is happening at the level of oldNode + newNode + // e.g. 2 + 2 --> 4 (an addition node becomes a constant node) + nodeChanged( + changeType: ChangeTypes, oldNode: mNode, newNode: mNode, defaultChangeGroup = true, steps = []) { + if (defaultChangeGroup) { + oldNode.changeGroup = 1; + newNode.changeGroup = 1; + } + + return new Status(changeType, oldNode, newNode, steps); + }; + + // A wrapper around the Status constructor for the case where there was + // a change that happened deeper `node`'s tree, and `node`'s children must be + // updated to have the newNode/oldNode metadata (changeGroups) + // e.g. (2 + 2) + x --> 4 + x has to update the left argument + childChanged(node: mNode, childStatus, childArgIndex = null) { + const oldNode = clone(node); + const newNode = clone(node); + let substeps = childStatus.substeps; + + if (!childStatus.oldNode) { + throw Error('Expected old node for changeType: ' + childStatus.changeType); + } + + function updateSubsteps(substeps, fn) { + substeps.map((step) => { + step = fn(step); + step.substeps = updateSubsteps(step.substeps, fn); + }); + return substeps; + } + + if (Type.isParenthesis(node)) { + oldNode.content = childStatus.oldNode; + newNode.content = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.content = step.oldNode; + newNode.content = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else if ((Type.isOperator(node) || Type.isFunction(node) && + childArgIndex !== null)) { + oldNode.args[childArgIndex] = childStatus.oldNode; + newNode.args[childArgIndex] = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.args[childArgIndex] = step.oldNode; + newNode.args[childArgIndex] = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else if (Type.isUnaryMinus(node)) { + oldNode.args[0] = childStatus.oldNode; + newNode.args[0] = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.args[0] = step.oldNode; + newNode.args[0] = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else { + throw Error('Unexpected node type: ' + node.type); + } + + return new Status(childStatus.changeType, oldNode, newNode, substeps); + }; } + class Creator { + /* + Functions to generate any mathJS node supported by the stepper + see http://mathjs.org/docs/expressions/expression_trees.html#nodes for more + information on nodes in mathJS +*/ + class NodeCreator { + operator(op, args, implicit = false) { + switch (op) { + case '+': + return new math.expression.node.OperatorNode('+', 'add', args); + case '-': + return new math.expression.node.OperatorNode('-', 'subtract', args); + case '/': + return new math.expression.node.OperatorNode('/', 'divide', args); + case '*': + return new math.expression.node.OperatorNode( + '*', 'multiply', args, implicit); + case '^': + return new math.expression.node.OperatorNode('^', 'pow', args); + default: + throw Error('Unsupported operation: ' + op); + } + } + + // In almost all cases, use Negative.negate (with naive = true) to add a + // unary minus to your node, rather than calling this constructor directly + unaryMinus(content) { + return new math.expression.node.OperatorNode( + '-', 'unaryMinus', [content]); + } + + constant(val) { + return new math.expression.node.ConstantNode(val); + } + + symbol(name) { + return new math.expression.node.SymbolNode(name); + } + + parenthesis(content) { + return new math.expression.node.ParenthesisNode(content); + } + + // exponent might be null, which means there's no exponent node. + // similarly, coefficient might be null, which means there's no coefficient + // the symbol node can never be null. + polynomialTerm(symbol, exponent, coeff, explicitCoeff = false) { + let polyTerm = symbol; + if (exponent) { + polyTerm = this.operator('^', [polyTerm, exponent]); + } + if (coeff && (explicitCoeff || parseFloat(coeff.value) !== 1)) { + if (NodeType.isConstant(coeff) && + parseFloat(coeff.value) === -1 && + !explicitCoeff) { + // if you actually want -1 as the coefficient, set explicitCoeff to true + polyTerm = this.unaryMinus(polyTerm); + } + else { + polyTerm = this.operator('*', [coeff, polyTerm], true); + } + } + return polyTerm; + } + + // Given a root value and a radicand (what is under the radical) + nthRoot(radicandNode, rootNode) { + const symbol = NodeCreator.symbol('nthRoot'); + return new math.expression.node.FunctionNode(symbol, [radicandNode, rootNode]); + } + }; +} + /* +For determining the type of a mathJS node. +*/ + class NodeType { + + static isOperator(node: mNode, operator = null) { + return node.type === 'OperatorNode' && + node.fn !== 'unaryMinus' && + "*+-/^".includes(node.op) && + (operator ? node.op === operator : true); + }; + + static isParenthesis(node: mNode) { + return node.type === 'ParenthesisNode'; + }; + + static isUnaryMinus = function (node: mNode) { + return node.type === 'OperatorNode' && node.fn === 'unaryMinus'; + }; + + static isFunction = function (node: mNode, functionName = null) { + if (node.type !== 'FunctionNode') { + return false; + } + if (functionName && node.fn.name !== functionName) { + return false; + } + return true; + }; + + static isSymbol(node: mNode, allowUnaryMinus = true): boolean { + if (node.type === 'SymbolNode') { + return true; + } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + return NodeType.isSymbol(node.args[0], false); + } + else { + return false; + } + }; + + static isConstant(node: mNode, allowUnaryMinus = false) { + if (node.type === 'ConstantNode') { + return true; + } + else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { + if (NodeType.isConstant(node.args[0], false)) { + const value = parseFloat(node.args[0].value); + return value >= 0; + } + else { + return false; + } + } + else { + return false; + } + }; + + static isConstantFraction(node: mNode, allowUnaryMinus = false) { + if (NodeType.isOperator(node, '/')) { + return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); + } + else { + return false; + } + }; + + static isConstantOrConstantFraction(node: mNode, allowUnaryMinus = false) { + if (NodeType.isConstant(node, allowUnaryMinus) || + NodeType.isConstantFraction(node, allowUnaryMinus)) { + return true; + } + else { + return false; + } + }; + + static isIntegerFraction(node: mNode, allowUnaryMinus = false) { + if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { + return false; + } + let numerator = node.args[0]; + let denominator = node.args[1]; + if (allowUnaryMinus) { + if (NodeType.isUnaryMinus(numerator)) { + numerator = numerator.args[0]; + } + if (NodeType.isUnaryMinus(denominator)) { + denominator = denominator.args[0]; + } + } + return (Number.isInteger(parseFloat(numerator.value)) && + Number.isInteger(parseFloat(denominator.value))); + }; + + } +class PolynomialTerm { + } \ No newline at end of file diff --git a/src/util/ChangeTypes.ts b/src/util/ChangeTypes.ts new file mode 100644 index 00000000..a82a3ea1 --- /dev/null +++ b/src/util/ChangeTypes.ts @@ -0,0 +1,184 @@ +// The text to identify rules for each possible step that can be taken + +enum ChangeTypes{ + NO_CHANGE, + + // ARITHMETIC + + // e.g. 2 + 2 -> 4 or 2 * 2 -> 4 + SIMPLIFY_ARITHMETIC, + + // BASICS + + // e.g. 2/-1 -> -2 + DIVISION_BY_NEGATIVE_ONE, + // e.g. 2/1 -> 2 + DIVISION_BY_ONE, + // e.g. x * 0 -> 0 + MULTIPLY_BY_ZERO, + // e.g. x * 2 -> 2x + REARRANGE_COEFF, + // e.g. x ^ 0 -> 1 + REDUCE_EXPONENT_BY_ZERO, + // e.g. 0/1 -> 0 + REDUCE_ZERO_NUMERATOR, + // e.g. 2 + 0 -> 2 + REMOVE_ADDING_ZERO, + // e.g. x ^ 1 -> x + REMOVE_EXPONENT_BY_ONE, + // e.g. 1 ^ x -> 1 + REMOVE_EXPONENT_BASE_ONE, + // e.g. x * -1 -> -x + REMOVE_MULTIPLYING_BY_NEGATIVE_ONE, + // e.g. x * 1 -> x + REMOVE_MULTIPLYING_BY_ONE, + // e.g. 2 - - 3 -> 2 + 3 + RESOLVE_DOUBLE_MINUS, + + // COLLECT AND COMBINE + + // e.g. 2 + x + 3 + x -> 5 + 2x + COLLECT_AND_COMBINE_LIKE_TERMS, + // e.g. x + 2 + x^2 + x + 4 -> x^2 + (x + x) + (4 + 2) + COLLECT_LIKE_TERMS, + + // ADDING POLYNOMIALS + + // e.g. 2x + x -> 2x + 1x + ADD_COEFFICIENT_OF_ONE, + // e.g. x^2 + x^2 -> 2x^2 + ADD_POLYNOMIAL_TERMS, + // e.g. 2x^2 + 3x^2 + 5x^2 -> (2+3+5)x^2 + GROUP_COEFFICIENTS, + // e.g. -x + 2x => -1*x + 2x + UNARY_MINUS_TO_NEGATIVE_ONE, + + // MULTIPLYING POLYNOMIALS + + // e.g. x^2 * x -> x^2 * x^1 + ADD_EXPONENT_OF_ONE, + // e.g. x^2 * x^3 * x^1 -> x^(2 + 3 + 1) + COLLECT_EXPONENTS, + // e.g. 2x * 3x -> (2 * 3)(x * x) + MULTIPLY_COEFFICIENTS, + // e.g. 2x * x -> 2x ^ 2 + MULTIPLY_POLYNOMIAL_TERMS, + + // FRACTIONS + + // e.g. (x + 2)/2 -> x/2 + 2/2 + BREAK_UP_FRACTION, + // e.g. -2/-3 => 2/3 + CANCEL_MINUSES, + // e.g. 2x/2 -> x + CANCEL_TERMS, + // e.g. 2/6 -> 1/3 + SIMPLIFY_FRACTION, + // e.g. 2/-3 -> -2/3 + SIMPLIFY_SIGNS, + + // ADDING FRACTIONS + + // e.g. 1/2 + 1/3 -> 5/6 + ADD_FRACTIONS, + // e.g. (1 + 2)/3 -> 3/3 + ADD_NUMERATORS, + // e.g. (2+1)/5 + COMBINE_NUMERATORS, + // e.g. 2/6 + 1/4 -> (2*2)/(6*2) + (1*3)/(4*3) + COMMON_DENOMINATOR, + // e.g. 3 + 1/2 -> 6/2 + 1/2 (for addition) + CONVERT_INTEGER_TO_FRACTION, + // e.g. 1.2 + 1/2 -> 1.2 + 0.5 + DIVIDE_FRACTION_FOR_ADDITION, + // e.g. (2*2)/(6*2) + (1*3)/(4*3) -> (2*2)/12 + (1*3)/12 + MULTIPLY_DENOMINATORS, + // e.g. (2*2)/12 + (1*3)/12 -> 4/12 + 3/12 + MULTIPLY_NUMERATORS, + + // MULTIPLYING FRACTIONS + + // e.g. 1/2 * 2/3 -> 2/6 + MULTIPLY_FRACTIONS, + + // DIVISION + + // e.g. 2/3/4 -> 2/(3*4) + SIMPLIFY_DIVISION, + // e.g. x/(2/3) -> x * 3/2 + MULTIPLY_BY_INVERSE, + + // DISTRIBUTION + + // e.g. 2(x + y) -> 2x + 2y + DISTRIBUTE, + // e.g. -(2 + x) -> -2 - x + DISTRIBUTE_NEGATIVE_ONE, + // e.g. 2 * 4x + 2*5 --> 8x + 10 (as part of distribution) + SIMPLIFY_TERMS, + + // ABSOLUTE + // e.g. |-3| -> 3 + ABSOLUTE_VALUE, + + // ROOTS + // e.g. nthRoot(x ^ 2, 4) -> nthRoot(x, 2) + CANCEL_EXPONENT, + // e.g. nthRoot(x ^ 2, 2) -> x + CANCEL_EXPONENT_AND_ROOT, + // e.g. nthRoot(x ^ 4, 2) -> x ^ 2 + CANCEL_ROOT, + // e.g. nthRoot(2, 2) * nthRoot(3, 2) -> nthRoot(2 * 3, 2) + COMBINE_UNDER_ROOT, + // e.g. 2 * 2 * 2 -> 2 ^ 3 + CONVERT_MULTIPLICATION_TO_EXPONENT, + // e.g. nthRoot(2 * x) -> nthRoot(2) * nthRoot(x) + DISTRIBUTE_NTH_ROOT, + // e.g. nthRoot(4) * nthRoot(x^2) -> 2 * x + EVALUATE_DISTRIBUTED_NTH_ROOT, + // e.g. 12 -> 2 * 2 * 3 + FACTOR_INTO_PRIMES, + // e.g. nthRoot(2 * 2 * 2, 2) -> nthRoot((2 * 2) * 2) + GROUP_TERMS_BY_ROOT, + // e.g. nthRoot(4) -> 2 + NTH_ROOT_VALUE, + + // SOLVING FOR A VARIABLE + + // e.g. x - 3 = 2 -> x - 3 + 3 = 2 + 3 + ADD_TO_BOTH_SIDES, + // e.g. 2x = 1 -> (2x)/2 = 1/2 + DIVIDE_FROM_BOTH_SIDES, + // e.g. (2/3)x = 1 -> (2/3)x * (3/2) = 1 * (3/2) + MULTIPLY_BOTH_SIDES_BY_INVERSE_FRACTION, + // e.g. -x = 2 -> -1 * -x = -1 * 2 + MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE, + // e.g. x/2 = 1 -> (x/2) * 2 = 1 * 2 + MULTIPLY_TO_BOTH_SIDES, + // e.g. x + 2 - 1 = 3 -> x + 1 = 3 + SIMPLIFY_LEFT_SIDE, + // e.g. x = 3 - 1 -> x = 2 + SIMPLIFY_RIGHT_SIDE, + // e.g. x + 3 = 2 -> x + 3 - 3 = 2 - 3 + SUBTRACT_FROM_BOTH_SIDES, + // e.g. 2 = x -> x = 2 + SWAP_SIDES, + + // CONSTANT EQUATION + + // e.g. 2 = 2 + STATEMENT_IS_TRUE, + // e.g. 2 = 3 + STATEMENT_IS_FALSE, + + // FACTORING + + // e.g. x^2 - 4x -> x(x - 4) + FACTOR_SYMBOL, + // e.g. x^2 - 4 -> (x - 2)(x + 2) + FACTOR_DIFFERENCE_OF_SQUARES, + // e.g. x^2 + 2x + 1 -> (x + 1)^2 + FACTOR_PERFECT_SQUARE, + // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) + FACTOR_SUM_PRODUCT_RULE, +}; \ No newline at end of file diff --git a/src/util/Negative.ts b/src/util/Negative.ts index b96b5812..6ce91fc0 100644 --- a/src/util/Negative.ts +++ b/src/util/Negative.ts @@ -2,7 +2,7 @@ // Returns if the given node is negative. Treats a unary minus as a negative, // as well as a negative constant value or a constant fraction that would // evaluate to a negative number -isNegative(node: mathjs.MathNode) { +function isNegative(node) { if (Node.Type.isUnaryMinus(node)) { return !Negative.isNegative(node.args[0]); } diff --git a/src/util/TreeSearch.ts b/src/util/TreeSearch.ts index 8ed4889f..45622957 100644 --- a/src/util/TreeSearch.ts +++ b/src/util/TreeSearch.ts @@ -1,45 +1,3 @@ -function search(simplificationFunction: function, node: mathjs.MathNode, preOrder: bool) { - let status; - - if (preOrder) { - status = simplificationFunction(node); - if (status.hasChanged()) { - return status; - } - } - - if (node.isConstantNode || node.isSymbolNode) { - return Node.Status.noChange(node); - } - else if (Node.Type.isUnaryMinus(node)) { - status = search(simplificationFunction, node.args[0], preOrder); - if (status.hasChanged()) { - return Node.Status.childChanged(node, status); - } - } - else if (node.isOperatorNode || Node.Type.isFunction(node)) { - for (let i = 0; i < node.args.length; i++) { - const child = node.args[i]; - const childNodeStatus = search(simplificationFunction, child, preOrder); - if (childNodeStatus.hasChanged()) { - return Node.Status.childChanged(node, childNodeStatus, i); - } - } - } - else if (Node.Type.isParenthesis(node)) { - status = search(simplificationFunction, node.content, preOrder); - if (status.hasChanged()) { - return Node.Status.childChanged(node, status); - } - } - else { - throw Error('Unsupported node type: ' + node); - } - - if (!preOrder) { - return simplificationFunction(node); - } - else { - return Node.Status.noChange(node); - } +function search(simplificationFunction, node: mNode, preOrder: boolean) { + } \ No newline at end of file diff --git a/src/util/clone.ts b/src/util/clone.ts new file mode 100644 index 00000000..29aa3d98 --- /dev/null +++ b/src/util/clone.ts @@ -0,0 +1,18 @@ + +// Simple clone function, which creates a deep copy of the given node +// And recurses on the children (due to the shallow nature of the mathjs node +// clone) +//need to somehow make this actually work in TS +function clone(node: mNode): mNode { + const copy = node.clone(); + copy.changeGroup = node.changeGroup; + if (node.args) { + node.args.forEach((child, i) => { + copy.args[i] = clone(child); + }); + } + else if (node.content) { + copy.content = clone(node.content); + } + return copy; +} \ No newline at end of file diff --git a/src/util/util.ts b/src/util/util.ts index 5c7a3d23..c806fbdd 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,5 +1,5 @@ - -Util.appendToArrayInObject = function(dict, key, value) { +namespace util { +function appendToArrayInObject(dict, key, value) { if (dict[key]) { dict[key].push(value); } @@ -7,4 +7,5 @@ Util.appendToArrayInObject = function(dict, key, value) { dict[key] = [value]; } return dict; -}; \ No newline at end of file +}; +} \ No newline at end of file From aa5632d95854e19bbbeccfd2db98f27f244322f2 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 15:16:39 -0700 Subject: [PATCH 09/12] More stuff --- src/nodeHelper/nodeHelper.ts | 179 ++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/src/nodeHelper/nodeHelper.ts b/src/nodeHelper/nodeHelper.ts index 52366cda..bedb1286 100644 --- a/src/nodeHelper/nodeHelper.ts +++ b/src/nodeHelper/nodeHelper.ts @@ -119,7 +119,6 @@ namespace nodeHelper { return new Status(childStatus.changeType, oldNode, newNode, substeps); }; } - class Creator { /* Functions to generate any mathJS node supported by the stepper see http://mathjs.org/docs/expressions/expression_trees.html#nodes for more @@ -291,5 +290,183 @@ For determining the type of a mathJS node. } class PolynomialTerm { +// For storing polynomial terms. +// Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. +// These expressions are of the form of a PolynomialTerm: x^2, 2y, z, 3x/5 +// These expressions are not: 4, x^(3+4), 2+x, 3*7, x-z +/* Fields: + - coeff: either a constant node or a fraction of two constant nodes + (might be null if no coefficient) + - symbol: the node with the symbol (e.g. in x^2, the node x) + - exponent: a node that can take any form, e.g. x^(2+x^2) + (might be null if no exponent) +*/ +class PolynomialTerm { + // if onlyImplicitMultiplication is true, an error will be thrown if `node` + // is a polynomial term without implicit multiplication + // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. + constructor(node, onlyImplicitMultiplication=false) { + if (NodeType.isOperator(node)) { + if (node.op === '^') { + const symbolNode = node.args[0]; + if (!NodeType.isSymbol(symbolNode)) { + throw Error('Expected symbol term, got ' + symbolNode); + } + this.symbol = symbolNode; + this.exponent = node.args[1]; + } + // it's '*' ie it has a coefficient + else if (node.op === '*') { + if (onlyImplicitMultiplication && !node.implicit) { + throw Error('Expected implicit multiplication'); + } + if (node.args.length !== 2) { + throw Error('Expected two arguments to *'); + } + const coeffNode = node.args[0]; + if (!NodeType.isConstantOrConstantFraction(coeffNode)) { + throw Error('Expected coefficient to be constant or fraction of ' + + 'constants term, got ' + coeffNode); + } + this.coeff = coeffNode; + const nonCoefficientTerm = new PolynomialTerm( + node.args[1], onlyImplicitMultiplication); + if (nonCoefficientTerm.hasCoeff()) { + throw Error('Cannot have two coefficients ' + coeffNode + + ' and ' + nonCoefficientTerm.getCoeffNode()); + } + this.symbol = nonCoefficientTerm.getSymbolNode(); + this.exponent = nonCoefficientTerm.getExponentNode(); + } + // this means there's a fraction coefficient + else if (node.op === '/') { + const denominatorNode = node.args[1]; + if (!NodeType.isConstant(denominatorNode)) { + throw Error('denominator must be constant node, instead of ' + + denominatorNode); + } + const numeratorNode = new PolynomialTerm( + node.args[0], onlyImplicitMultiplication); + if (numeratorNode.hasFractionCoeff()) { + throw Error('Polynomial terms cannot have nested fractions'); + } + this.exponent = numeratorNode.getExponentNode(); + this.symbol = numeratorNode.getSymbolNode(); + const numeratorConstantNode = numeratorNode.getCoeffNode(true); + this.coeff = NodeCreator.operator( + '/', [numeratorConstantNode, denominatorNode]); + } + else { + throw Error('Unsupported operatation for polynomial node: ' + node.op); + } + } + else if (NodeType.isUnaryMinus(node)) { + var arg = node.args[0]; + if (NodeType.isParenthesis(arg)) { + arg = arg.content; + } + const polyNode = new PolynomialTerm( + arg, onlyImplicitMultiplication); + this.exponent = polyNode.getExponentNode(); + this.symbol = polyNode.getSymbolNode(); + if (!polyNode.hasCoeff()) { + this.coeff = NodeCreator.constant(-1); + } + else { + this.coeff = negativeCoefficient(polyNode.getCoeffNode()); + } + } + else if (NodeType.isSymbol(node)) { + this.symbol = node; + } + else { + throw Error('Unsupported node type: ' + node.type); + } + } + + /* GETTER FUNCTIONS */ + getSymbolNode() { + return this.symbol; + } + + getSymbolName() { + return this.symbol.name; + } + + getCoeffNode(defaultOne=false) { + if (!this.coeff && defaultOne) { + return NodeCreator.constant(1); + } + else { + return this.coeff; + } + } + + getCoeffValue() { + if (this.coeff) { + return evaluate(this.coeff); + } + else { + return 1; // no coefficient is like a coeff of 1 + } + } + + getExponentNode(defaultOne=false) { + if (!this.exponent && defaultOne) { + return NodeCreator.constant(1); + } + else { + return this.exponent; + } + } + getRootNode() { + return NodeCreator.polynomialTerm( + this.symbol, this.exponent, this.coeff); + } + + // note: there is no exponent value getter function because the exponent + // can be any expresion and not necessarily a number. + + /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ + + // Returns true if the coefficient is a fraction + hasFractionCoeff() { + // coeffNode is either a constant or a division operation. + return this.coeff && NodeType.isOperator(this.coeff); + } + + hasCoeff() { + return !!this.coeff; + } +} + +// Returns if the node represents an expression that can be considered a term. +// e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. +// See the tests for some more thorough examples of exactly what counts and +// what does not. +PolynomialTerm.isPolynomialTerm = function( + node, onlyImplicitMultiplication=false) { + try { + // will throw error if node isn't poly term + new PolynomialTerm(node, onlyImplicitMultiplication); + return true; + } + catch (err) { + return false; + } +}; + +// Multiplies `node`, a constant or fraction of two constant nodes, by -1 +// Returns a node +function negativeCoefficient(node) { + if (NodeType.isConstant(node)) { + node = NodeCreator.constant(0 - parseFloat(node.value)); + } + else { + const numeratorValue = 0 - parseFloat(node.args[0].value); + node.args[0] = NodeCreator.constant(numeratorValue); + } + return node; +} } \ No newline at end of file From beb20a9242565b18dabf9b7674b7d288c38fba96 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 18:20:04 -0700 Subject: [PATCH 10/12] aaaahhhhh --- src/{util => }/ChangeTypes.ts | 0 src/{util => }/Negative.ts | 2 +- src/{util => }/Symbols.ts | 0 src/TreeSearch.ts | 65 +++++ src/factor/factor.ts | 256 ++++++++++++++++- src/nodeHelper.ts | 499 ++++++++++++++++++++++++++++++++++ src/nodeHelper/nodeHelper.ts | 472 -------------------------------- src/util/TreeSearch.ts | 3 - src/util/util.ts | 2 +- 9 files changed, 814 insertions(+), 485 deletions(-) rename src/{util => }/ChangeTypes.ts (100%) rename src/{util => }/Negative.ts (98%) rename src/{util => }/Symbols.ts (100%) create mode 100644 src/TreeSearch.ts create mode 100644 src/nodeHelper.ts delete mode 100644 src/nodeHelper/nodeHelper.ts delete mode 100644 src/util/TreeSearch.ts diff --git a/src/util/ChangeTypes.ts b/src/ChangeTypes.ts similarity index 100% rename from src/util/ChangeTypes.ts rename to src/ChangeTypes.ts diff --git a/src/util/Negative.ts b/src/Negative.ts similarity index 98% rename from src/util/Negative.ts rename to src/Negative.ts index 6ce91fc0..707f5444 100644 --- a/src/util/Negative.ts +++ b/src/Negative.ts @@ -2,7 +2,7 @@ // Returns if the given node is negative. Treats a unary minus as a negative, // as well as a negative constant value or a constant fraction that would // evaluate to a negative number -function isNegative(node) { +function isNegative(node: mNode) { if (Node.Type.isUnaryMinus(node)) { return !Negative.isNegative(node.args[0]); } diff --git a/src/util/Symbols.ts b/src/Symbols.ts similarity index 100% rename from src/util/Symbols.ts rename to src/Symbols.ts diff --git a/src/TreeSearch.ts b/src/TreeSearch.ts new file mode 100644 index 00000000..6e118989 --- /dev/null +++ b/src/TreeSearch.ts @@ -0,0 +1,65 @@ +class TreeSearch { + +// Returns a function that performs a preorder search on the tree for the given +// simplifcation function +static preOrder(simplificationFunction) { + return function (node) { + return search(simplificationFunction, node, true); + }; +}; + +// Returns a function that performs a postorder search on the tree for the given +// simplifcation function +static postOrder = function(simplificationFunction) { + return function (node) { + return search(simplificationFunction, node, false); + }; +}; + +// A helper function for performing a tree search with a function +static search(simplificationFunction, node, preOrder) { + let status; + + if (preOrder) { + status = simplificationFunction(node); + if (status.hasChanged()) { + return status; + } + } + + if (Node.Type.isConstant(node) || Node.Type.isSymbol(node)) { + return Node.Status.noChange(node); + } + else if (Node.Type.isUnaryMinus(node)) { + status = search(simplificationFunction, node.args[0], preOrder); + if (status.hasChanged()) { + return Node.Status.childChanged(node, status); + } + } + else if (Node.Type.isOperator(node) || Node.Type.isFunction(node)) { + for (let i = 0; i < node.args.length; i++) { + const child = node.args[i]; + const childNodeStatus = search(simplificationFunction, child, preOrder); + if (childNodeStatus.hasChanged()) { + return Node.Status.childChanged(node, childNodeStatus, i); + } + } + } + else if (Node.Type.isParenthesis(node)) { + status = search(simplificationFunction, node.content, preOrder); + if (status.hasChanged()) { + return Node.Status.childChanged(node, status); + } + } + else { + throw Error('Unsupported node type: ' + node); + } + + if (!preOrder) { + return simplificationFunction(node); + } + else { + return Node.Status.noChange(node); + } +} +} \ No newline at end of file diff --git a/src/factor/factor.ts b/src/factor/factor.ts index a4a1807a..4eac8e93 100644 --- a/src/factor/factor.ts +++ b/src/factor/factor.ts @@ -1,13 +1,253 @@ -namespace factor{ - //returns the - export function getPrimeFactors(number: number){ - +import * as nodeHelper from "../nodeHelper"; + //returns all prime factors of a number + export function getPrimeFactors(number: number): number[] { + let factors = []; + if (number < 0) { + factors = [-1]; + factors = factors.concat(getPrimeFactors(-1 * number)); + return factors; + } + + const root = Math.sqrt(number); + let candidate = 2; + if (number % 2) { + candidate = 3; // assign first odd + while (number % candidate && candidate <= root) { + candidate = candidate + 2; + } + } + + // if no factor found then the number is prime + if (candidate > root) { + factors.push(number); + } + // if we find a factor, make a recursive call on the quotient of the number and + // our newly found prime factor in order to find more factors + else { + factors.push(candidate); + factors = factors.concat(getPrimeFactors(number / candidate)); + } + + return factors; + } + // Given a number, will return all the factor pairs for that number as a list + // of 2-item lists + export function getFactorPairs(number: number): number[][] { + const factors = []; + + const bound = Math.floor(Math.sqrt(Math.abs(number))); + for (var divisor = -bound; divisor <= bound; divisor++) { + if (divisor === 0) { + continue; + } + if (number % divisor === 0) { + const quotient = number / divisor; + factors.push([divisor, quotient]); + } + } + + return factors; } - export function getFactorPairs(number: number){ + // functions for factoring quadratic equations + const FACTOR_FUNCTIONS = [ + // factor just the symbol e.g. x^2 + 2x -> x(x + 2) + factorSymbol, + // factor difference of squares e.g. x^2 - 4 + factorDifferenceOfSquares, + // factor perfect square e.g. x^2 + 2x + 1 + factorPerfectSquare, + // factor sum product rule e.g. x^2 + 3x + 2 + factorSumProductRule +]; + export function factorQuadratic(node: mNode) { + node = flatten(node); + if (!checks.isQuadratic(node)) { + return nodeHelper.Status.noChange(node); + } + // get a, b and c + let symbol, aValue = 0, bValue = 0, cValue = 0; + for (const term of node.args) { + if (nodeHelper.Type.isConstant(term)) { + cValue = evaluate(term); + } + else if (nodeHelper.PolynomialTerm.isPolynomialTerm(term)) { + const polyTerm = new nodeHelper.PolynomialTerm(term); + const exponent = polyTerm.getExponentNode(true); + if (exponent.value === '2') { + symbol = polyTerm.getSymbolNode(); + aValue = polyTerm.getCoeffValue(); + } + else if (exponent.value === '1') { + bValue = polyTerm.getCoeffValue(); + } + else { + return nodeHelper.Status.noChange(node); + } + } + else { + return nodeHelper.Status.noChange(node); + } + } + + if (!symbol || !aValue) { + return nodeHelper.Status.noChange(node); + } + + let negate = false; + if (aValue < 0) { + negate = true; + aValue = -aValue; + bValue = -bValue; + cValue = -cValue; + } + for (let i = 0; i < FACTOR_FUNCTIONS.length; i++) { + const nodeStatus = FACTOR_FUNCTIONS[i](node, symbol, aValue, bValue, cValue, negate); + if (nodeStatus.hasChanged()) { + return nodeStatus; + } + } + + return nodeHelper.Status.noChange(node); } - export function factorQuadratic{ + // Will factor the node if it's in the form of ax^2 + bx + function factorSymbol(node: mNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { + if (!bValue || cValue) { + return nodeHelper.Status.noChange(node); + } + + const gcd = math.gcd(aValue, bValue); + const gcdNode = nodeHelper.Creator.constant(gcd); + const aNode = nodeHelper.Creator.constant(aValue / gcd); + const bNode = nodeHelper.Creator.constant(bValue / gcd); + + const factoredNode = nodeHelper.Creator.polynomialTerm(symbol, null, gcdNode); + const polyTerm = nodeHelper.Creator.polynomialTerm(symbol, null, aNode); + const paren = nodeHelper.Creator.parenthesis( + nodeHelper.Creator.operator('+', [polyTerm, bNode])); + + let newNode = nodeHelper.Creator.operator('*', [factoredNode, paren], true); + if (negate) { + newNode = Negative.negate(newNode); + } + + return nodeHelper.Status.nodeChanged(ChangeTypes.FACTOR_SYMBOL, node, newNode); + } + + // Will factor the node if it's in the form of ax^2 - c, and the aValue + // and cValue are perfect squares + // e.g. 4x^2 - 4 -> (2x + 2)(2x - 2) + function factorDifferenceOfSquares(node: mNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { + // check if difference of squares: (i) abs(a) and abs(c) are squares, (ii) b = 0, + // (iii) c is negative + if (bValue || !cValue) { + return nodeHelper.Status.noChange(node); + } + + const aRootValue = Math.sqrt(Math.abs(aValue)); + const cRootValue = Math.sqrt(Math.abs(cValue)); + + // must be a difference of squares + if (isInteger(aRootValue) && + isInteger(cRootValue) && + cValue < 0) { + + const aRootNode = nodeHelper.Creator.constant(aRootValue); + const cRootNode = nodeHelper.Creator.constant(cRootValue); + + const polyTerm = nodeHelper.Creator.polynomialTerm(symbol, null, aRootNode); + const firstParen = nodeHelper.Creator.parenthesis( + nodeHelper.Creator.operator('+', [polyTerm, cRootNode])); + const secondParen = nodeHelper.Creator.parenthesis( + nodeHelper.Creator.operator('-', [polyTerm, cRootNode])); + // create node in difference of squares form + let newNode = nodeHelper.Creator.operator('*', [firstParen, secondParen], true); + if (negate) { + newNode = Negative.negate(newNode); + } + + return nodeHelper.Status.nodeChanged( + ChangeTypes.FACTOR_DIFFERENCE_OF_SQUARES, node, newNode); + } + + return nodeHelper.Status.noChange(node); + } + + // Will factor the node if it's in the form of ax^2 + bx + c, where a and c + // are perfect squares and b = 2*sqrt(a)*sqrt(c) + // e.g. x^2 + 2x + 1 -> (x + 1)^2 + function factorPerfectSquare(node: mNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { + // check if perfect square: (i) a and c squares, (ii) b = 2*sqrt(a)*sqrt(c) + if (!bValue || !cValue) { + return nodeHelper.Status.noChange(node); + } + + const aRootValue = Math.sqrt(Math.abs(aValue)); + let cRootValue = Math.sqrt(Math.abs(cValue)); + + // if the second term is negative, then the constant in the parens is + // subtracted: e.g. x^2 - 2x + 1 -> (x - 1)^2 + if (bValue < 0) { + cRootValue = cRootValue * -1; + } + + // apply the perfect square test + const perfectProduct = 2 * aRootValue * cRootValue; + if (isInteger(aRootValue) && + isInteger(cRootValue) && + bValue === perfectProduct) { + + const aRootNode = nodeHelper.Creator.constant(aRootValue); + const cRootNode = nodeHelper.Creator.constant(cRootValue); + + const polyTerm = nodeHelper.Creator.polynomialTerm(symbol, null, aRootNode); + const paren = nodeHelper.Creator.parenthesis( + nodeHelper.Creator.operator('+', [polyTerm, cRootNode])); + const exponent = nodeHelper.Creator.constant(2); + + // create node in perfect square form + let newNode = nodeHelper.Creator.operator('^', [paren, exponent]); + if (negate) { + newNode = Negative.negate(newNode); + } + + return nodeHelper.Status.nodeChanged( + ChangeTypes.FACTOR_PERFECT_SQUARE, node, newNode); + } + + return nodeHelper.Status.noChange(node); + } + + // Will factor the node if it's in the form of x^2 + bx + c (i.e. a is 1), by + // applying the sum product rule: finding factors of c that add up to b. + // e.g. x^2 + 3x + 2 -> (x + 1)(x + 2) + function factorSumProductRule(node: mNode, symbol, aValue: number, bValue: number, cValue: number, negate: boolean) { + if (aValue === 1 && bValue && cValue) { + // try sum/product rule: find a factor pair of c that adds up to b + const factorPairs = getFactorPairs(cValue); + for (const pair of factorPairs) { + if (pair[0] + pair[1] === bValue) { + const firstParen = nodeHelper.Creator.parenthesis( + nodeHelper.Creator.operator('+', [symbol, nodeHelper.Creator.constant(pair[0])])); + const secondParen = nodeHelper.Creator.parenthesis( + nodeHelper.Creator.operator('+', [symbol, nodeHelper.Creator.constant(pair[1])])); + + // create a node in the general factored form for expression + let newNode = nodeHelper.Creator.operator('*', [firstParen, secondParen], true); + if (negate) { + newNode = Negative.negate(newNode); + } + + return nodeHelper.Status.nodeChanged( + ChangeTypes.FACTOR_SUM_PRODUCT_RULE, node, newNode); + } + } + } + + return nodeHelper.Status.noChange(node); + } + function isInteger(a: number) + { + return a % 1 === 0; } - -} \ No newline at end of file diff --git a/src/nodeHelper.ts b/src/nodeHelper.ts new file mode 100644 index 00000000..e98e093b --- /dev/null +++ b/src/nodeHelper.ts @@ -0,0 +1,499 @@ +/// +/// + +export class Status { + changeType: ChangeTypes; + oldNode: mNode; + newNode: mNode; + substeps: any; + constructor(changeType: ChangeTypes, oldNode: mNode, newNode: mNode, substeps = []) { + if (!newNode) { + throw Error('node is not defined'); + } + if (changeType === undefined || typeof (changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } + + this.changeType = changeType; + this.oldNode = oldNode; + this.newNode = newNode; + this.substeps = substeps; + } + hasChanged() { + return this.changeType !== ChangeTypes.NO_CHANGE; + } + static resetChangeGroups = function (node: mNode) { + node = clone(node); + node.filter(node => node.changeGroup).forEach(change => { + delete change.changeGroup; + }); + return node; + }; + + // A wrapper around the Status constructor for the case where node hasn't + // been changed. + static noChange(node: mNode) { + return new Status(ChangeTypes.NO_CHANGE, null, node); + }; + + // A wrapper around the Status constructor for the case of a change + // that is happening at the level of oldNode + newNode + // e.g. 2 + 2 --> 4 (an addition node becomes a constant node) + static nodeChanged( + changeType: ChangeTypes, oldNode: mNode, newNode: mNode, defaultChangeGroup = true, steps = []) { + if (defaultChangeGroup) { + oldNode.changeGroup = 1; + newNode.changeGroup = 1; + } + + return new Status(changeType, oldNode, newNode, steps); + }; + + // A wrapper around the Status constructor for the case where there was + // a change that happened deeper `node`'s tree, and `node`'s children must be + // updated to have the newNode/oldNode metadata (changeGroups) + // e.g. (2 + 2) + x --> 4 + x has to update the left argument + static childChanged(node: mNode, childStatus, childArgIndex = null) { + const oldNode = clone(node); + const newNode = clone(node); + let substeps = childStatus.substeps; + + if (!childStatus.oldNode) { + throw Error('Expected old node for changeType: ' + childStatus.changeType); + } + + function updateSubsteps(substeps, fn) { + substeps.map((step) => { + step = fn(step); + step.substeps = updateSubsteps(step.substeps, fn); + }); + return substeps; + } + + if (Type.isParenthesis(node)) { + oldNode.content = childStatus.oldNode; + newNode.content = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.content = step.oldNode; + newNode.content = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else if ((Type.isOperator(node) || Type.isFunction(node) && + childArgIndex !== null)) { + oldNode.args[childArgIndex] = childStatus.oldNode; + newNode.args[childArgIndex] = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.args[childArgIndex] = step.oldNode; + newNode.args[childArgIndex] = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else if (Type.isUnaryMinus(node)) { + oldNode.args[0] = childStatus.oldNode; + newNode.args[0] = childStatus.newNode; + substeps = updateSubsteps(substeps, (step) => { + const oldNode = clone(node); + const newNode = clone(node); + oldNode.args[0] = step.oldNode; + newNode.args[0] = step.newNode; + step.oldNode = oldNode; + step.newNode = newNode; + return step; + }); + } + else { + throw Error('Unexpected node type: ' + node.type); + } + + return new Status(childStatus.changeType, oldNode, newNode, substeps); + }; +} +/* +Functions to generate any mathJS node supported by the stepper +see http://mathjs.org/docs/expressions/expression_trees.html#nodes for more +information on nodes in mathJS +*/ +export class Creator { + static operator(op: string, args: mNode[], implicit = false): mNode { + switch (op) { + case '+': + return new math.expression.node.OperatorNode('+', 'add', args); + case '-': + return new math.expression.node.OperatorNode('-', 'subtract', args); + case '/': + return new math.expression.node.OperatorNode('/', 'divide', args); + case '*': + return new math.expression.node.OperatorNode( + '*', 'multiply', args, implicit); + case '^': + return new math.expression.node.OperatorNode('^', 'pow', args); + default: + throw Error('Unsupported operation: ' + op); + } + } + + // In almost all cases, use Negative.negate (with naive = true) to add a + // unary minus to your node, rather than calling this constructor directly + static unaryMinus(content) { + return new math.expression.node.OperatorNode( + '-', 'unaryMinus', [content]); + } + + static constant(val) { + return new math.expression.node.ConstantNode(val); + } + + static symbol(name) { + return new math.expression.node.SymbolNode(name); + } + + static parenthesis(content) { + return new math.expression.node.ParenthesisNode(content); + } + + // exponent might be null, which means there's no exponent node. + // similarly, coefficient might be null, which means there's no coefficient + // the symbol node can never be null. + static polynomialTerm(symbol, exponent, coeff, explicitCoeff = false) { + let polyTerm = symbol; + if (exponent) { + polyTerm = this.operator('^', [polyTerm, exponent]); + } + if (coeff && (explicitCoeff || parseFloat(coeff.value) !== 1)) { + if (Type.isConstant(coeff) && + parseFloat(coeff.value) === -1 && + !explicitCoeff) { + // if you actually want -1 as the coefficient, set explicitCoeff to true + polyTerm = this.unaryMinus(polyTerm); + } + else { + polyTerm = this.operator('*', [coeff, polyTerm], true); + } + } + return polyTerm; + } + + // Given a root value and a radicand (what is under the radical) + static nthRoot(radicandNode: mNode, rootNode: mNode) { + const symbol = Creator.symbol('nthRoot'); + return new math.expression.node.FunctionNode(symbol, [radicandNode, rootNode]); + } +}; +//For determining the type of a mathJS node. +export class Type { + + static isOperator(node: mNode, operator: string = null) { + return node.type === 'OperatorNode' && + node.fn !== 'unaryMinus' && + "*+-/^".indexOf(node.op) >= 0 && + (operator ? node.op === operator : true); + }; + + static isParenthesis(node: mNode) { + return node.type === 'ParenthesisNode'; + }; + + static isUnaryMinus = function (node: mNode) { + return node.type === 'OperatorNode' && node.fn === 'unaryMinus'; + }; + + static isFunction = function (node: mNode, functionName = null) { + if (node.type !== 'FunctionNode') { + return false; + } + if (functionName && node.fn.name !== functionName) { + return false; + } + return true; + }; + + static isSymbol(node: mNode, allowUnaryMinus = true): boolean { + if (node.type === 'SymbolNode') { + return true; + } + else if (allowUnaryMinus && Type.isUnaryMinus(node)) { + return Type.isSymbol(node.args[0], false); + } + else { + return false; + } + }; + + static isConstant(node: mNode, allowUnaryMinus = false) { + if (node.type === 'ConstantNode') { + return true; + } + else if (allowUnaryMinus && Type.isUnaryMinus(node)) { + if (Type.isConstant(node.args[0], false)) { + const value = parseFloat(node.args[0].value); + return value >= 0; + } + else { + return false; + } + } + else { + return false; + } + }; + + static isConstantFraction(node: mNode, allowUnaryMinus = false) { + if (Type.isOperator(node, '/')) { + return node.args.every(n => Type.isConstant(n, allowUnaryMinus)); + } + else { + return false; + } + }; + + static isConstantOrConstantFraction(node: mNode, allowUnaryMinus = false) { + if (Type.isConstant(node, allowUnaryMinus) || + Type.isConstantFraction(node, allowUnaryMinus)) { + return true; + } + else { + return false; + } + }; + + static isIntegerFraction(node: mNode, allowUnaryMinus = false) { + if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { + return false; + } + let numerator = node.args[0]; + let denominator = node.args[1]; + if (allowUnaryMinus) { + if (NodeType.isUnaryMinus(numerator)) { + numerator = numerator.args[0]; + } + if (NodeType.isUnaryMinus(denominator)) { + denominator = denominator.args[0]; + } + } + return (Number.isInteger(parseFloat(numerator.value)) && + Number.isInteger(parseFloat(denominator.value))); + }; + +} +export class PolynomialTerm { + // For storing polynomial terms. + // Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. + // These expressions are of the form of a PolynomialTerm: x^2, 2y, z, 3x/5 + // These expressions are not: 4, x^(3+4), 2+x, 3*7, x-z + /* Fields: + - coeff: either a constant node or a fraction of two constant nodes + (might be null if no coefficient) + - symbol: the node with the symbol (e.g. in x^2, the node x) + - exponent: a node that can take any form, e.g. x^(2+x^2) + (might be null if no exponent) + */ + // if onlyImplicitMultiplication is true, an error will be thrown if `node` + // is a polynomial term without implicit multiplication + // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. + //TODO: Add type annotation + symbol; + exponent; + coeff; + constructor(node: mNode, onlyImplicitMultiplication = false) { + if (NodeType.isOperator(node)) { + if (node.op === '^') { + const symbolNode = node.args[0]; + if (!NodeType.isSymbol(symbolNode)) { + throw Error('Expected symbol term, got ' + symbolNode); + } + this.symbol = symbolNode; + this.exponent = node.args[1]; + } + // it's '*' ie it has a coefficient + else if (node.op === '*') { + if (onlyImplicitMultiplication && !node.implicit) { + throw Error('Expected implicit multiplication'); + } + if (node.args.length !== 2) { + throw Error('Expected two arguments to *'); + } + const coeffNode = node.args[0]; + if (!NodeType.isConstantOrConstantFraction(coeffNode)) { + throw Error('Expected coefficient to be constant or fraction of ' + + 'constants term, got ' + coeffNode); + } + this.coeff = coeffNode; + const nonCoefficientTerm = new PolynomialTerm( + node.args[1], onlyImplicitMultiplication); + if (nonCoefficientTerm.hasCoeff()) { + throw Error('Cannot have two coefficients ' + coeffNode + + ' and ' + nonCoefficientTerm.getCoeffNode()); + } + this.symbol = nonCoefficientTerm.getSymbolNode(); + this.exponent = nonCoefficientTerm.getExponentNode(); + } + // this means there's a fraction coefficient + else if (node.op === '/') { + const denominatorNode = node.args[1]; + if (!NodeType.isConstant(denominatorNode)) { + throw Error('denominator must be constant node, instead of ' + + denominatorNode); + } + const numeratorNode = new PolynomialTerm( + node.args[0], onlyImplicitMultiplication); + if (numeratorNode.hasFractionCoeff()) { + throw Error('Polynomial terms cannot have nested fractions'); + } + this.exponent = numeratorNode.getExponentNode(); + this.symbol = numeratorNode.getSymbolNode(); + const numeratorConstantNode = numeratorNode.getCoeffNode(true); + this.coeff = NodeCreator.operator( + '/', [numeratorConstantNode, denominatorNode]); + } + else { + throw Error('Unsupported operatation for polynomial node: ' + node.op); + } + } + else if (NodeType.isUnaryMinus(node)) { + var arg = node.args[0] as mNode; + if (NodeType.isParenthesis(arg)) { + arg = arg.content; + } + const polyNode = new PolynomialTerm( + arg, onlyImplicitMultiplication); + this.exponent = polyNode.getExponentNode(); + this.symbol = polyNode.getSymbolNode(); + if (!polyNode.hasCoeff()) { + this.coeff = NodeCreator.constant(-1); + } + else { + this.coeff = negativeCoefficient(polyNode.getCoeffNode()); + } + } + else if (NodeType.isSymbol(node)) { + this.symbol = node; + } + else { + throw Error('Unsupported node type: ' + node.type); + } + } + + /* GETTER FUNCTIONS */ + getSymbolNode() { + return this.symbol; + } + + getSymbolName() { + return this.symbol.name; + } + + getCoeffNode(defaultOne = false) { + if (!this.coeff && defaultOne) { + return Creator.constant(1); + } + else { + return this.coeff; + } + } + + getCoeffValue() { + if (this.coeff) { + return evaluate(this.coeff); + } + else { + return 1; // no coefficient is like a coeff of 1 + } + } + + getExponentNode(defaultOne = false) { + if (!this.exponent && defaultOne) { + return Creator.constant(1); + } + else { + return this.exponent; + } + } + + getRootNode() { + return Creator.polynomialTerm( + this.symbol, this.exponent, this.coeff); + } + + // note: there is no exponent value getter function because the exponent + // can be any expresion and not necessarily a number. + + /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ + + // Returns true if the coefficient is a fraction + hasFractionCoeff() { + // coeffNode is either a constant or a division operation. + return this.coeff && Type.isOperator(this.coeff); + } + + hasCoeff() { + return !!this.coeff; + } + + + // Returns if the node represents an expression that can be considered a term. + // e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. + // See the tests for some more thorough examples of exactly what counts and + // what does not. + static isPolynomialTerm(node: mNode, onlyImplicitMultiplication = false) { + try { + // will throw error if node isn't poly term + new PolynomialTerm(node, onlyImplicitMultiplication); + return true; + } + catch (err) { + return false; + } + }; + + // Multiplies `node`, a constant or fraction of two constant nodes, by -1 + // Returns a node + static negativeCoefficient(node: mNode) { + if (Type.isConstant(node)) { + node = Creator.constant(0 - parseFloat(node.value)); + } + else { + const numeratorValue = 0 - parseFloat(node.args[0].value); + node.args[0] = Creator.constant(numeratorValue); + } + return node; + } +} +/* +None of this works :( +// create node constructors because we can't use the ones from mathjs :( +function OperatorNode(op: string, fn: string, args: mNode[]): mNode { + let node: mNode = { + isNode: true, + type: "OperatorNode", + isOperatorNode: true, + op: op, + fn: fn, + args: args as mathjs.MathNode[] || [], + //don't know how to implement the rest of the things + } + return node; +} +function Constant(value: string, valueType:string): mNode { + let node: mNode = { + value: value, + valueType: valueType, + isNode: true, + type: "OperatorNode", + isOperatorNode: true, + op: op, + fn: fn, + args: args as mathjs.MathNode[] || [], + //don't know how to implement the rest of the things + } + return node; +} +*/ \ No newline at end of file diff --git a/src/nodeHelper/nodeHelper.ts b/src/nodeHelper/nodeHelper.ts deleted file mode 100644 index bedb1286..00000000 --- a/src/nodeHelper/nodeHelper.ts +++ /dev/null @@ -1,472 +0,0 @@ -/// -/// - -namespace nodeHelper { - - export class Status { - changeType: ChangeTypes; - oldNode: mNode; - newNode: mNode; - substeps: any; - constructor(changeType: ChangeTypes, oldNode: mNode, newNode: mNode, substeps = []) { - if (!newNode) { - throw Error('node is not defined'); - } - if (changeType === undefined || typeof (changeType) !== 'string') { - throw Error('changetype isn\'t valid'); - } - - this.changeType = changeType; - this.oldNode = oldNode; - this.newNode = newNode; - this.substeps = substeps; - } - hasChanged() { - return this.changeType !== ChangeTypes.NO_CHANGE; - } - resetChangeGroups = function (node: mNode) { - node = clone(node); - node.filter(node => node.changeGroup).forEach(change => { - delete change.changeGroup; - }); - return node; - }; - - // A wrapper around the Status constructor for the case where node hasn't - // been changed. - noChange(node: mNode) { - return new Status(ChangeTypes.NO_CHANGE, null, node); - }; - - // A wrapper around the Status constructor for the case of a change - // that is happening at the level of oldNode + newNode - // e.g. 2 + 2 --> 4 (an addition node becomes a constant node) - nodeChanged( - changeType: ChangeTypes, oldNode: mNode, newNode: mNode, defaultChangeGroup = true, steps = []) { - if (defaultChangeGroup) { - oldNode.changeGroup = 1; - newNode.changeGroup = 1; - } - - return new Status(changeType, oldNode, newNode, steps); - }; - - // A wrapper around the Status constructor for the case where there was - // a change that happened deeper `node`'s tree, and `node`'s children must be - // updated to have the newNode/oldNode metadata (changeGroups) - // e.g. (2 + 2) + x --> 4 + x has to update the left argument - childChanged(node: mNode, childStatus, childArgIndex = null) { - const oldNode = clone(node); - const newNode = clone(node); - let substeps = childStatus.substeps; - - if (!childStatus.oldNode) { - throw Error('Expected old node for changeType: ' + childStatus.changeType); - } - - function updateSubsteps(substeps, fn) { - substeps.map((step) => { - step = fn(step); - step.substeps = updateSubsteps(step.substeps, fn); - }); - return substeps; - } - - if (Type.isParenthesis(node)) { - oldNode.content = childStatus.oldNode; - newNode.content = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.content = step.oldNode; - newNode.content = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else if ((Type.isOperator(node) || Type.isFunction(node) && - childArgIndex !== null)) { - oldNode.args[childArgIndex] = childStatus.oldNode; - newNode.args[childArgIndex] = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.args[childArgIndex] = step.oldNode; - newNode.args[childArgIndex] = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else if (Type.isUnaryMinus(node)) { - oldNode.args[0] = childStatus.oldNode; - newNode.args[0] = childStatus.newNode; - substeps = updateSubsteps(substeps, (step) => { - const oldNode = clone(node); - const newNode = clone(node); - oldNode.args[0] = step.oldNode; - newNode.args[0] = step.newNode; - step.oldNode = oldNode; - step.newNode = newNode; - return step; - }); - } - else { - throw Error('Unexpected node type: ' + node.type); - } - - return new Status(childStatus.changeType, oldNode, newNode, substeps); - }; - } - /* - Functions to generate any mathJS node supported by the stepper - see http://mathjs.org/docs/expressions/expression_trees.html#nodes for more - information on nodes in mathJS -*/ - class NodeCreator { - operator(op, args, implicit = false) { - switch (op) { - case '+': - return new math.expression.node.OperatorNode('+', 'add', args); - case '-': - return new math.expression.node.OperatorNode('-', 'subtract', args); - case '/': - return new math.expression.node.OperatorNode('/', 'divide', args); - case '*': - return new math.expression.node.OperatorNode( - '*', 'multiply', args, implicit); - case '^': - return new math.expression.node.OperatorNode('^', 'pow', args); - default: - throw Error('Unsupported operation: ' + op); - } - } - - // In almost all cases, use Negative.negate (with naive = true) to add a - // unary minus to your node, rather than calling this constructor directly - unaryMinus(content) { - return new math.expression.node.OperatorNode( - '-', 'unaryMinus', [content]); - } - - constant(val) { - return new math.expression.node.ConstantNode(val); - } - - symbol(name) { - return new math.expression.node.SymbolNode(name); - } - - parenthesis(content) { - return new math.expression.node.ParenthesisNode(content); - } - - // exponent might be null, which means there's no exponent node. - // similarly, coefficient might be null, which means there's no coefficient - // the symbol node can never be null. - polynomialTerm(symbol, exponent, coeff, explicitCoeff = false) { - let polyTerm = symbol; - if (exponent) { - polyTerm = this.operator('^', [polyTerm, exponent]); - } - if (coeff && (explicitCoeff || parseFloat(coeff.value) !== 1)) { - if (NodeType.isConstant(coeff) && - parseFloat(coeff.value) === -1 && - !explicitCoeff) { - // if you actually want -1 as the coefficient, set explicitCoeff to true - polyTerm = this.unaryMinus(polyTerm); - } - else { - polyTerm = this.operator('*', [coeff, polyTerm], true); - } - } - return polyTerm; - } - - // Given a root value and a radicand (what is under the radical) - nthRoot(radicandNode, rootNode) { - const symbol = NodeCreator.symbol('nthRoot'); - return new math.expression.node.FunctionNode(symbol, [radicandNode, rootNode]); - } - }; -} - /* -For determining the type of a mathJS node. -*/ - class NodeType { - - static isOperator(node: mNode, operator = null) { - return node.type === 'OperatorNode' && - node.fn !== 'unaryMinus' && - "*+-/^".includes(node.op) && - (operator ? node.op === operator : true); - }; - - static isParenthesis(node: mNode) { - return node.type === 'ParenthesisNode'; - }; - - static isUnaryMinus = function (node: mNode) { - return node.type === 'OperatorNode' && node.fn === 'unaryMinus'; - }; - - static isFunction = function (node: mNode, functionName = null) { - if (node.type !== 'FunctionNode') { - return false; - } - if (functionName && node.fn.name !== functionName) { - return false; - } - return true; - }; - - static isSymbol(node: mNode, allowUnaryMinus = true): boolean { - if (node.type === 'SymbolNode') { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - return NodeType.isSymbol(node.args[0], false); - } - else { - return false; - } - }; - - static isConstant(node: mNode, allowUnaryMinus = false) { - if (node.type === 'ConstantNode') { - return true; - } - else if (allowUnaryMinus && NodeType.isUnaryMinus(node)) { - if (NodeType.isConstant(node.args[0], false)) { - const value = parseFloat(node.args[0].value); - return value >= 0; - } - else { - return false; - } - } - else { - return false; - } - }; - - static isConstantFraction(node: mNode, allowUnaryMinus = false) { - if (NodeType.isOperator(node, '/')) { - return node.args.every(n => NodeType.isConstant(n, allowUnaryMinus)); - } - else { - return false; - } - }; - - static isConstantOrConstantFraction(node: mNode, allowUnaryMinus = false) { - if (NodeType.isConstant(node, allowUnaryMinus) || - NodeType.isConstantFraction(node, allowUnaryMinus)) { - return true; - } - else { - return false; - } - }; - - static isIntegerFraction(node: mNode, allowUnaryMinus = false) { - if (!NodeType.isConstantFraction(node, allowUnaryMinus)) { - return false; - } - let numerator = node.args[0]; - let denominator = node.args[1]; - if (allowUnaryMinus) { - if (NodeType.isUnaryMinus(numerator)) { - numerator = numerator.args[0]; - } - if (NodeType.isUnaryMinus(denominator)) { - denominator = denominator.args[0]; - } - } - return (Number.isInteger(parseFloat(numerator.value)) && - Number.isInteger(parseFloat(denominator.value))); - }; - - } -class PolynomialTerm { -// For storing polynomial terms. -// Has a symbol (e.g. x), maybe an exponent, and maybe a coefficient. -// These expressions are of the form of a PolynomialTerm: x^2, 2y, z, 3x/5 -// These expressions are not: 4, x^(3+4), 2+x, 3*7, x-z -/* Fields: - - coeff: either a constant node or a fraction of two constant nodes - (might be null if no coefficient) - - symbol: the node with the symbol (e.g. in x^2, the node x) - - exponent: a node that can take any form, e.g. x^(2+x^2) - (might be null if no exponent) -*/ -class PolynomialTerm { - // if onlyImplicitMultiplication is true, an error will be thrown if `node` - // is a polynomial term without implicit multiplication - // (i.e. 2*x instead of 2x) and therefore isPolynomialTerm will return false. - constructor(node, onlyImplicitMultiplication=false) { - if (NodeType.isOperator(node)) { - if (node.op === '^') { - const symbolNode = node.args[0]; - if (!NodeType.isSymbol(symbolNode)) { - throw Error('Expected symbol term, got ' + symbolNode); - } - this.symbol = symbolNode; - this.exponent = node.args[1]; - } - // it's '*' ie it has a coefficient - else if (node.op === '*') { - if (onlyImplicitMultiplication && !node.implicit) { - throw Error('Expected implicit multiplication'); - } - if (node.args.length !== 2) { - throw Error('Expected two arguments to *'); - } - const coeffNode = node.args[0]; - if (!NodeType.isConstantOrConstantFraction(coeffNode)) { - throw Error('Expected coefficient to be constant or fraction of ' + - 'constants term, got ' + coeffNode); - } - this.coeff = coeffNode; - const nonCoefficientTerm = new PolynomialTerm( - node.args[1], onlyImplicitMultiplication); - if (nonCoefficientTerm.hasCoeff()) { - throw Error('Cannot have two coefficients ' + coeffNode + - ' and ' + nonCoefficientTerm.getCoeffNode()); - } - this.symbol = nonCoefficientTerm.getSymbolNode(); - this.exponent = nonCoefficientTerm.getExponentNode(); - } - // this means there's a fraction coefficient - else if (node.op === '/') { - const denominatorNode = node.args[1]; - if (!NodeType.isConstant(denominatorNode)) { - throw Error('denominator must be constant node, instead of ' + - denominatorNode); - } - const numeratorNode = new PolynomialTerm( - node.args[0], onlyImplicitMultiplication); - if (numeratorNode.hasFractionCoeff()) { - throw Error('Polynomial terms cannot have nested fractions'); - } - this.exponent = numeratorNode.getExponentNode(); - this.symbol = numeratorNode.getSymbolNode(); - const numeratorConstantNode = numeratorNode.getCoeffNode(true); - this.coeff = NodeCreator.operator( - '/', [numeratorConstantNode, denominatorNode]); - } - else { - throw Error('Unsupported operatation for polynomial node: ' + node.op); - } - } - else if (NodeType.isUnaryMinus(node)) { - var arg = node.args[0]; - if (NodeType.isParenthesis(arg)) { - arg = arg.content; - } - const polyNode = new PolynomialTerm( - arg, onlyImplicitMultiplication); - this.exponent = polyNode.getExponentNode(); - this.symbol = polyNode.getSymbolNode(); - if (!polyNode.hasCoeff()) { - this.coeff = NodeCreator.constant(-1); - } - else { - this.coeff = negativeCoefficient(polyNode.getCoeffNode()); - } - } - else if (NodeType.isSymbol(node)) { - this.symbol = node; - } - else { - throw Error('Unsupported node type: ' + node.type); - } - } - - /* GETTER FUNCTIONS */ - getSymbolNode() { - return this.symbol; - } - - getSymbolName() { - return this.symbol.name; - } - - getCoeffNode(defaultOne=false) { - if (!this.coeff && defaultOne) { - return NodeCreator.constant(1); - } - else { - return this.coeff; - } - } - - getCoeffValue() { - if (this.coeff) { - return evaluate(this.coeff); - } - else { - return 1; // no coefficient is like a coeff of 1 - } - } - - getExponentNode(defaultOne=false) { - if (!this.exponent && defaultOne) { - return NodeCreator.constant(1); - } - else { - return this.exponent; - } - } - - getRootNode() { - return NodeCreator.polynomialTerm( - this.symbol, this.exponent, this.coeff); - } - - // note: there is no exponent value getter function because the exponent - // can be any expresion and not necessarily a number. - - /* CHECKER FUNCTIONS (returns true / false for certain conditions) */ - - // Returns true if the coefficient is a fraction - hasFractionCoeff() { - // coeffNode is either a constant or a division operation. - return this.coeff && NodeType.isOperator(this.coeff); - } - - hasCoeff() { - return !!this.coeff; - } -} - -// Returns if the node represents an expression that can be considered a term. -// e.g. x^2, 2y, z, 3x/5 are all terms. 4, 2+x, 3*7, x-z are all not terms. -// See the tests for some more thorough examples of exactly what counts and -// what does not. -PolynomialTerm.isPolynomialTerm = function( - node, onlyImplicitMultiplication=false) { - try { - // will throw error if node isn't poly term - new PolynomialTerm(node, onlyImplicitMultiplication); - return true; - } - catch (err) { - return false; - } -}; - -// Multiplies `node`, a constant or fraction of two constant nodes, by -1 -// Returns a node -function negativeCoefficient(node) { - if (NodeType.isConstant(node)) { - node = NodeCreator.constant(0 - parseFloat(node.value)); - } - else { - const numeratorValue = 0 - parseFloat(node.args[0].value); - node.args[0] = NodeCreator.constant(numeratorValue); - } - return node; -} -} \ No newline at end of file diff --git a/src/util/TreeSearch.ts b/src/util/TreeSearch.ts deleted file mode 100644 index 45622957..00000000 --- a/src/util/TreeSearch.ts +++ /dev/null @@ -1,3 +0,0 @@ -function search(simplificationFunction, node: mNode, preOrder: boolean) { - -} \ No newline at end of file diff --git a/src/util/util.ts b/src/util/util.ts index c806fbdd..58fe6ceb 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,5 +1,5 @@ namespace util { -function appendToArrayInObject(dict, key, value) { +function appendToArrayInObject(dict: Array, key: number, value: any) { if (dict[key]) { dict[key].push(value); } From 5d09c8fb72db1cf9fc19a2e962b9018f71f88217 Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Fri, 21 Apr 2017 21:48:48 -0700 Subject: [PATCH 11/12] more stuff --- src/Equation.ts | 114 +++++++++++++ src/Negative.ts | 44 ++--- src/Symbols.ts | 95 +++++++++++ src/TreeSearch.ts | 37 +++-- src/{factor => }/factor.ts | 0 src/util/evaluate.ts | 8 + src/util/flattenOperands.ts | 323 ++++++++++++++++++++++++++++++++++++ src/util/util.ts | 11 -- tsconfig.json | 2 +- 9 files changed, 583 insertions(+), 51 deletions(-) create mode 100644 src/Equation.ts rename src/{factor => }/factor.ts (100%) create mode 100644 src/util/evaluate.ts create mode 100644 src/util/flattenOperands.ts delete mode 100644 src/util/util.ts diff --git a/src/Equation.ts b/src/Equation.ts new file mode 100644 index 00000000..8b388bc1 --- /dev/null +++ b/src/Equation.ts @@ -0,0 +1,114 @@ +import * as nodeHelper from "../nodeHelper"; +// This represents an equation, made up of the leftNode (LHS), the +// rightNode (RHS) and a comparator (=, <, >, <=, or >=) +export default class Equation { + leftNode: mNode; + rightNode: mNode; + comparator: string; + constructor(leftNode: mNode, rightNode: mNode, comparator: string) { + this.leftNode = leftNode; + this.rightNode = rightNode; + this.comparator = comparator; + } + + // Prints an Equation properly using the print module + print(showPlusMinus=false) { + const leftSide = printNode(this.leftNode, showPlusMinus); + const rightSide = printNode(this.rightNode, showPlusMinus); + const comparator = this.comparator; + + return `${leftSide} ${comparator} ${rightSide}`; + } + + clone() { + const newLeft = clone(this.leftNode); + const newRight = clone(this.rightNode); + return new Equation(newLeft, newRight, this.comparator); + } + +// Splits a string on the given comparator and returns a new Equation object +// from the left and right hand sides +static createEquationFromString = function(str: string, comparator:string) { + const sides = str.split(comparator); + if (sides.length !== 2) { + throw Error('Expected two sides of an equation using comparator: ' + + comparator); + } + const leftNode = math.parse(sides[0]); + const rightNode = math.parse(sides[1]); + + return new Equation(leftNode, rightNode, comparator); +}; +} + +// This represents the current equation we're solving. +// As we move step by step, an equation might be updated. Functions return this +// status object to pass on the updated equation and information on if/how it was +// changed. +class Status { + changeType; + oldEquation: Equation; + newEquation: Equation; + substeps; + constructor(changeType, oldEquation: Equation, newEquation: Equation, substeps=[]) { + if (!newEquation) { + throw Error('new equation isn\'t defined'); + } + if (changeType === undefined || typeof(changeType) !== 'string') { + throw Error('changetype isn\'t valid'); + } + + this.changeType = changeType; + this.oldEquation = oldEquation; + this.newEquation = newEquation; + this.substeps = substeps; + } + + hasChanged() { + return this.changeType !== ChangeTypes.NO_CHANGE; + } + +// A wrapper around the Status constructor for the case where equation +// hasn't been changed. +noChange(equation) { + return new Status(ChangeTypes.NO_CHANGE, null, equation); +}; + +addLeftStep(equation, leftStep) { + const substeps = []; + leftStep.substeps.forEach(substep => { + substeps.push(Status.addLeftStep(equation, substep)); + }); + let oldEquation = null; + if (leftStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.leftNode = leftStep.oldNode; + } + const newEquation = equation.clone(); + newEquation.leftNode = leftStep.newNode; + return new Status( + leftStep.changeType, oldEquation, newEquation, substeps); +}; + +addRightStep(equation: Equation, rightStep) { + const substeps = []; + rightStep.substeps.forEach(substep => { + substeps.push(Status.addRightStep(equation, substep)); + }); + let oldEquation = null; + if (rightStep.oldNode) { + oldEquation = equation.clone(); + oldEquation.rightNode = rightStep.oldNode; + } + const newEquation = equation.clone(); + newEquation.rightNode = rightStep.newNode; + return new Status( + rightStep.changeType, oldEquation, newEquation, substeps); +}; + +resetChangeGroups(equation) { + const leftNode = nodeHelper.Status.resetChangeGroups(equation.leftNode); + const rightNode = nodeHelper.Status.resetChangeGroups(equation.rightNode); + return new Equation(leftNode, rightNode, equation.comparator); +}; +} diff --git a/src/Negative.ts b/src/Negative.ts index 707f5444..6b4b88cf 100644 --- a/src/Negative.ts +++ b/src/Negative.ts @@ -1,23 +1,24 @@ - +import * as nodeHelper from "./nodeHelper" +export default class Negative{ // Returns if the given node is negative. Treats a unary minus as a negative, // as well as a negative constant value or a constant fraction that would // evaluate to a negative number -function isNegative(node: mNode) { - if (Node.Type.isUnaryMinus(node)) { +static isNegative(node: mNode): boolean { + if (nodeHelper.Type.isUnaryMinus(node)) { return !Negative.isNegative(node.args[0]); } - else if (Node.Type.isConstant(node)) { + else if (nodeHelper.Type.isConstant(node)) { return parseFloat(node.value) < 0; } - else if (Node.Type.isConstantFraction(node)) { + else if (nodeHelper.Type.isConstantFraction(node)) { const numeratorValue = parseFloat(node.args[0].value); const denominatorValue = parseFloat(node.args[1].value); if (numeratorValue < 0 || denominatorValue < 0) { return !(numeratorValue < 0 && denominatorValue < 0); } } - else if (Node.PolynomialTerm.isPolynomialTerm(node)) { - const polyNode = new Node.PolynomialTerm(node); + else if (nodeHelper.PolynomialTerm.isPolynomialTerm(node)) { + const polyNode = new nodeHelper.PolynomialTerm(node); return Negative.isNegative(polyNode.getCoeffNode(true)); } @@ -30,23 +31,23 @@ function isNegative(node: mNode) { // E.g. // not naive: -3 -> 3, x -> -x // naive: -3 -> --3, x -> -x -Negative.negate = function(node, naive=false) { - if (Node.Type.isConstantFraction(node)) { +static negate(node: mNode, naive=false): mNode { + if (nodeHelper.Type.isConstantFraction(node)) { node.args[0] = Negative.negate(node.args[0], naive); return node; } - else if (Node.PolynomialTerm.isPolynomialTerm(node)) { + else if (nodeHelper.PolynomialTerm.isPolynomialTerm(node)) { return Negative.negatePolynomialTerm(node, naive); } else if (!naive) { - if (Node.Type.isUnaryMinus(node)) { + if (nodeHelper.Type.isUnaryMinus(node)) { return node.args[0]; } - else if (Node.Type.isConstant(node)) { - return Node.Creator.constant(0 - parseFloat(node.value)); + else if (nodeHelper.Type.isConstant(node)) { + return nodeHelper.Creator.constant(0 - parseFloat(node.value)); } } - return Node.Creator.unaryMinus(node); + return nodeHelper.Creator.unaryMinus(node); }; // Multiplies a polynomial term by -1 and returns the new node @@ -55,15 +56,15 @@ Negative.negate = function(node, naive=false) { // E.g. // not naive: -3x -> 3x, x -> -x // naive: -3x -> --3x, x -> -x -Negative.negatePolynomialTerm = function(node, naive=false) { - if (!Node.PolynomialTerm.isPolynomialTerm(node)) { +static negatePolynomialTerm(node: mNode, naive=false): mNode { + if (!nodeHelper.PolynomialTerm.isPolynomialTerm(node)) { throw Error('node is not a polynomial term'); } - const polyNode = new Node.PolynomialTerm(node); + const polyNode = new nodeHelper.PolynomialTerm(node); let newCoeff; if (!polyNode.hasCoeff()) { - newCoeff = Node.Creator.constant(-1); + newCoeff = nodeHelper.Creator.constant(-1); } else { const oldCoeff = polyNode.getCoeffNode(); @@ -75,7 +76,7 @@ Negative.negatePolynomialTerm = function(node, naive=false) { numerator = Negative.negate(numerator, naive); const denominator = oldCoeff.args[1]; - newCoeff = Node.Creator.operator('/', [numerator, denominator]); + newCoeff = nodeHelper.Creator.operator('/', [numerator, denominator]); } else { newCoeff = Negative.negate(oldCoeff, naive); @@ -84,6 +85,7 @@ Negative.negatePolynomialTerm = function(node, naive=false) { } } } - return Node.Creator.polynomialTerm( + return nodeHelper.Creator.polynomialTerm( polyNode.getSymbolNode(), polyNode.getExponentNode(), newCoeff); -}; \ No newline at end of file +}; +} \ No newline at end of file diff --git a/src/Symbols.ts b/src/Symbols.ts index e69de29b..edcf215e 100644 --- a/src/Symbols.ts +++ b/src/Symbols.ts @@ -0,0 +1,95 @@ +import * as nodeHelper from "./nodeHelper"; +import Equation from "./Equation"; +class Symbols{ + +// returns the set of all the symbols in an equation +static getSymbolsInEquation(equation: Equation) { + const leftSymbols = Symbols.getSymbolsInExpression(equation.leftNode); + const rightSymbols = Symbols.getSymbolsInExpression(equation.rightNode); + const symbols = new Set([...leftSymbols, ...rightSymbols]); + return symbols; +}; + +// return the set of symbols in the expression tree +static getSymbolsInExpression(expression) { + const symbolNodes = expression.filter(node => node.isSymbolNode); // all the symbol nodes + const symbols = symbolNodes.map(node => node.name); // all the symbol nodes' names + const symbolSet = new Set(symbols); // to get rid of duplicates + return symbolSet; +}; + +// Iterates through a node and returns the polynomial term with the symbol name +// Returns null if no terms with the symbol name are in the node. +// e.g. 4x^2 + 2x + y + 2 with `symbolName=x` would return 2x +static getLastSymbolTerm(node: mNode, symbolName: string) { + // First check if the node itself is a polyomial term with symbolName + if (Symbols.isSymbolTerm(node, symbolName)) { + return node; + } + // Otherwise, it's a sum of terms. Look through the operands for a term + // with `symbolName` + else if (nodeHelper.Type.isOperator(node, '+')) { + for (let i = node.args.length - 1; i >= 0 ; i--) { + const child = node.args[i]; + if (Symbols.isSymbolTerm(child, symbolName)) { + return child; + } + } + } + return null; +}; + +// Iterates through a node and returns the last term that does not have the +// symbolName including other polynomial terms, and constants or constant +// fractions +// e.g. 4x^2 with `symbolName=x` would return 4 +// e.g. 4x^2 + 2x + 2/4 with `symbolName=x` would return 2/4 +// e.g. 4x^2 + 2x + y with `symbolName=x` would return y +static getLastNonSymbolTerm(node: mNode, symbolName: string) { + if (Symbols.isSymbolTerm(node, symbolName)) { + return new nodeHelper.PolynomialTerm(node).getCoeffNode(); + } + else if (nodeHelper.Type.isOperator(node)) { + for (let i = node.args.length - 1; i >= 0 ; i--) { + const child = node.args[i]; + if (!Symbols.isSymbolTerm(child, symbolName)) { + return child; + } + } + } + + return null; +}; + +// Returns if `node` is a polynomial term with symbol `symbolName` +static isSymbolTerm(node: mNode, symbolName: string) { + if (nodeHelper.PolynomialTerm.isPolynomialTerm(node)) { + const polyTerm = new nodeHelper.PolynomialTerm(node); + if (polyTerm.getSymbolName() === symbolName) { + return true; + } + } + return false; +} +} +//Probably shouldn't do this but whatever +interface Set { + add(value: T): Set; + clear(): void; + delete(value: T): boolean; + entries(): IterableIterator<[T, T]>; + forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void; + has(value: T): boolean; + keys(): IterableIterator; + size: number; + values(): IterableIterator; + [Symbol.iterator]():IterableIterator; + [Symbol.toStringTag]: string; +} + +interface SetConstructor { + new (): Set; + new (iterable: Iterable): Set; + prototype: Set; +} +declare var Set: SetConstructor; \ No newline at end of file diff --git a/src/TreeSearch.ts b/src/TreeSearch.ts index 6e118989..0c47f85a 100644 --- a/src/TreeSearch.ts +++ b/src/TreeSearch.ts @@ -1,23 +1,24 @@ +import * as nodeHelper from "./nodeHelper"; class TreeSearch { // Returns a function that performs a preorder search on the tree for the given // simplifcation function static preOrder(simplificationFunction) { - return function (node) { - return search(simplificationFunction, node, true); + return function (node: mNode) { + return TreeSearch.search(simplificationFunction, node, true); }; }; // Returns a function that performs a postorder search on the tree for the given // simplifcation function static postOrder = function(simplificationFunction) { - return function (node) { - return search(simplificationFunction, node, false); + return function (node: mNode) { + return TreeSearch.search(simplificationFunction, node, false); }; }; // A helper function for performing a tree search with a function -static search(simplificationFunction, node, preOrder) { +static search(simplificationFunction, node: mNode, preOrder: boolean) { let status; if (preOrder) { @@ -27,28 +28,28 @@ static search(simplificationFunction, node, preOrder) { } } - if (Node.Type.isConstant(node) || Node.Type.isSymbol(node)) { - return Node.Status.noChange(node); + if (nodeHelper.Type.isConstant(node) || nodeHelper.Type.isSymbol(node)) { + return nodeHelper.Status.noChange(node); } - else if (Node.Type.isUnaryMinus(node)) { - status = search(simplificationFunction, node.args[0], preOrder); + else if (nodeHelper.Type.isUnaryMinus(node)) { + status = TreeSearch.search(simplificationFunction, node.args[0], preOrder); if (status.hasChanged()) { - return Node.Status.childChanged(node, status); + return nodeHelper.Status.childChanged(node, status); } } - else if (Node.Type.isOperator(node) || Node.Type.isFunction(node)) { + else if (nodeHelper.Type.isOperator(node) || nodeHelper.Type.isFunction(node)) { for (let i = 0; i < node.args.length; i++) { const child = node.args[i]; - const childNodeStatus = search(simplificationFunction, child, preOrder); + const childNodeStatus = TreeSearch.search(simplificationFunction, child, preOrder); if (childNodeStatus.hasChanged()) { - return Node.Status.childChanged(node, childNodeStatus, i); + return nodeHelper.Status.childChanged(node, childNodeStatus, i); } } } - else if (Node.Type.isParenthesis(node)) { - status = search(simplificationFunction, node.content, preOrder); + else if (nodeHelper.Type.isParenthesis(node)) { + status = TreeSearch.search(simplificationFunction, node.content, preOrder); if (status.hasChanged()) { - return Node.Status.childChanged(node, status); + return nodeHelper.Status.childChanged(node, status); } } else { @@ -59,7 +60,7 @@ static search(simplificationFunction, node, preOrder) { return simplificationFunction(node); } else { - return Node.Status.noChange(node); + return nodeHelper.Status.noChange(node); } } -} \ No newline at end of file +} diff --git a/src/factor/factor.ts b/src/factor.ts similarity index 100% rename from src/factor/factor.ts rename to src/factor.ts diff --git a/src/util/evaluate.ts b/src/util/evaluate.ts new file mode 100644 index 00000000..18d5a539 --- /dev/null +++ b/src/util/evaluate.ts @@ -0,0 +1,8 @@ +// Evaluates a node to a numerical value +// e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 +// it's important that `node` does not contain any symbol nodes + +function evaluate(node) { + // TODO: once we swap in math-parser, call its evaluate function instead + return node.eval(); +} diff --git a/src/util/flattenOperands.ts b/src/util/flattenOperands.ts new file mode 100644 index 00000000..343ae0bb --- /dev/null +++ b/src/util/flattenOperands.ts @@ -0,0 +1,323 @@ +/* +Background: + +Expression trees are commonly parsed as binary trees, and mathjs does this too. +That means that a mathjs expression tree likely looks like: +http://collegelabs.co/clabs/nld/images/524px-Expression_Tree.svg.png + +e.g. 2+2+2 is parsed by mathjs as 2 + 2+2 (a plus node with children 2 and 2+2) +However... +1. This is more complicated than needed. 2+2+2 is the same as 2+(2+2) +2. To collect like terms, we actually *need* it to be flat. e.g. with 2x+(2+2x), + there's no easy way to know that there are two 2x's to collect without + running up and down the tree. If we flatten to 2x+2+2x, it becomes a lot + easier to collect like terms to (2x+2x) + 2, which would then be combined to + 4x + 2 +The purpose of flatteOperands is to flatten the tree in this way. + +e.g. an expression that is grouped in the tree like +(2 + ((4 * ((1 + 2) + (3 + 4))) * 8)) +should be flattened to look like: +(2 + (4 * (1 + 2 + 3 + 4) * 8)) + +Subtraction and division are also flattened, though that gets a bit more +complicated and you may as well start reading through the code if you're +interested in how that works +*/ + +// Flattens the tree accross the same operation (just + and * for now) +// e.g. 2+2+2 is parsed by mathjs as 2+(2+2), but this would change that to +// 2+2+2, ie one + node that has three children. +// Input: an expression tree +// Output: the expression tree updated with flattened operations +import * as nodeHelper from "../nodeHelper"; +import * as Negative from "../Negative"; + +function flattenOperands(node: mNode): mNode { + if (nodeHelper.Type.isConstant(node, true)) { + // the evaluate() changes unary minuses around constant nodes to constant nodes + // with negative values. + const constNode = nodeHelper.Creator.constant(evaluate(node)); + if (node.changeGroup) { + constNode.changeGroup = node.changeGroup; + } + return constNode; + } + else if (nodeHelper.Type.isOperator(node)) { + if ('+-/*'.indexOf(node.op)>= 0) { + let parentOp; + if (node.op === '/') { + // Division is flattened in partner with multiplication. This means + // that after collecting the operands, they'll be children args of * + parentOp = '*'; + } + else if (node.op === '-') { + // Subtraction is flattened in partner with addition, This means that + // after collecting the operands, they'll be children args of + + parentOp = '+'; + } + else { + parentOp = node.op; + } + return flattenSupportedOperation(node, parentOp); + } + // If the operation is not supported, just recurse on the children + else { + node.args.forEach((child, i) => { + node.args[i] = flattenOperands(child); + }); + } + return node; + } + else if (nodeHelper.Type.isParenthesis(node)) { + node.content = flattenOperands(node.content); + return node; + } + else if (nodeHelper.Type.isUnaryMinus(node)) { + const arg = flattenOperands(node.args[0]); + const flattenedNode = Negative.negate(arg, true); + if (node.changeGroup) { + flattenedNode.changeGroup = node.changeGroup; + } + return flattenedNode; + } + else if (nodeHelper.Type.isFunction(node, 'abs')) { + node.args[0] = flattenOperands(node.args[0]); + return node; + } + else if (nodeHelper.Type.isFunction(node, 'nthRoot')) { + node.args[0] = flattenOperands(node.args[0]); + if (node.args[1]) { + node.args[1] = flattenOperands(node.args[1]); + } + return node; + } + else { + return node; + } +} + +// Flattens operations (see flattenOperands docstring) for an operator node +// with an operation type that can be flattened. Currently * + / are supported. +// Returns the updated, flattened node. +// NOTE: the returned node will be of operation type `parentOp`, regardless of +// the operation type of `node`, unless `node` wasn't changed +// e.g. 2 * 3 / 4 would be * of 2 and 3/4, but 2/3 would stay 2/3 and division +function flattenSupportedOperation(node: mNode, parentOp) { + // First get the list of operands that this operator operates on. + // e.g. 2 + 3 + 4 + 5 is stored as (((2 + 3) + 4) + 5) in the tree and we + // want to get the list [2, 3, 4, 5] + const operands = getOperands(node, parentOp); + + // If there's only one operand (possible if 2*x was flattened to 2x) + // then it's no longer an operation, so we should replace the node + // with the one operand. + if (operands.length === 1) { + node = operands[0]; + } + else { + // When we are dealing with flattening division, and there's also + // multiplication involved, we might end up with a top level * instead. + // e.g. 2*4/5 is parsed with / at the top, but in the end we want 2 * (4/5) + // Check for this by first checking if we have more than two operands + // (which is impossible for division), then by recursing through the + // original tree for any multiplication node - if there was one, it would + // have ended up at the root. + if (node.op === '/' && (operands.length > 2 || + hasMultiplicationBesideDivision(node))) { + node = nodeHelper.Creator.operator('*', operands); + } + // similarily, - will become + always + else if (node.op === '-') { + node = nodeHelper.Creator.operator('+', operands); + } + // otherwise keep the operator, replace operands + else { + node.args = operands; + } + // When we collect operands to flatten multiplication, the + // multiplication of those operands should never be implicit + if (node.op === '*') { + node.implicit = false; + } + } + return node; +} + +// Recursively finds the operands under `parentOp` in the input tree `node`. +// The input tree `node` will always have a parent that is an operation +// of type `op`. +// Op is a string e.g. '+' or '*' +// returns the list of all the node operated on by `parentOp` +function getOperands(node: mNode, parentOp) { + // We can only recurse on operations of type op. + // If the node is not an operator node or of the right operation type, + // we can't break up or flatten this tree any further, so we return just + // the current node, and recurse on it to flatten its ops. + if (!nodeHelper.Type.isOperator(node)) { + return [flattenOperands(node)]; + } + switch (node.op) { + // division is part of flattening multiplication + case '*': + case '/': + if (parentOp !== '*') { + return [flattenOperands(node)]; + } + break; + case '+': + case '-': + if (parentOp !== '+') { + return [flattenOperands(node)]; + } + break; + default: + return [flattenOperands(node)]; + } + if (nodeHelper.PolynomialTerm.isPolynomialTerm(node, true)) { + node.args.forEach((arg, i) => { + node.args[i] = flattenOperands(node.args[i]); + }); + return [node]; + } + + // If we're flattening over *, check for a polynomial term (ie a + // coefficient multiplied by a symbol such as 2x^2 or 3y) + // This is true if there's an implicit multiplication and the right operand + // is a symbol or a symbol to an exponent. + else if (parentOp === '*' && isPolynomialTermMultiplication(node)) { + return maybeFlattenPolynomialTerm(node); + } + else if (parentOp === '*' && node.op === '/') { + return flattenDivision(node); + } + else if (node.op === '-') { + // this operation will become addition e.g. 2 - 3 -> 2 + -(-3) + const secondOperand = node.args[1]; + const negativeSecondOperand = Negative.negate(secondOperand, true); + const operands = [ + getOperands(node.args[0], parentOp), + getOperands(negativeSecondOperand, parentOp) + ]; + return [].concat.apply([], operands); + } + else { + const operands = []; + node.args.forEach((child) => { + // This will make an array of arrays + operands.push(getOperands(child, parentOp)); + }); + return [].concat.apply([], operands); + } +} + +// Return true iff node is a candidate for simplifying to a polynomial +// term. This function is a helper function for getOperands. +// Context: Usually we'd flatten 2*2*x to a multiplication node with 3 children +// (2, 2, and x) but if we got 2*2x, we want to keep 2x together. +// 2*2*x (a tree stored in two levels because initially nodes only have two +// children) in the flattening process should be turned into 2*2x instead of +// 2*2*x (which has three children). +// So this function would return true for the input 2*2x, if it was stored as +// an expression tree with root node * and children 2*2 and x +function isPolynomialTermMultiplication(node: mNode) { + // This concept only applies when we're flattening multiplication operations + if (node.op !== '*') { + return false; + } + // This only makes sense when we're flattening two arguments + if (node.args.length !== 2) { + return false; + } + // The second node should be for the form x or x^2 (ie a polynomial term + // with no coefficient) + const secondOperand = node.args[1]; + if (nodeHelper.PolynomialTerm.isPolynomialTerm(secondOperand)) { + const polyNode = new nodeHelper.PolynomialTerm(secondOperand); + return !polyNode.hasCoeff(); + } + else { + return false; + } +} + +// Takes a node that might represent a multiplication with a polynomial term +// and flattens it appropriately so the coefficient and symbol are grouped +// together. Returns a new list of operands from this node that should be +// multiplied together. +function maybeFlattenPolynomialTerm(node: mNode) { + // We recurse on the left side of the tree to find operands so far + const operands = getOperands(node.args[0], '*'); + + // If the last operand (so far) under * was a constant, then it's a + // polynomial term. + // e.g. 2*5*6x creates a tree where the top node is implicit multiplcation + // and the left branch goes to the tree with 2*5*6, and the right operand + // is the symbol x. We want to check that the last argument on the left (in + // this example 6) is a constant. + const lastOperand = operands.pop(); + + // in the above example, node.args[1] would be the symbol x + const nextOperand = flattenOperands(node.args[1]); + + // a coefficient can be constant or a fraction of constants + if (nodeHelper.Type.isConstantOrConstantFraction(lastOperand)) { + // we replace the constant (which we popped) with constant*symbol + operands.push( + nodeHelper.Creator.operator('*', [lastOperand, nextOperand], true)); + } + // Now we know it isn't a polynomial term, it's just another seperate operand + else { + operands.push(lastOperand); + operands.push(nextOperand); + } + return operands; +} + +// Takes a division node and returns a list of operands +// If there is multiplication in the numerator, the operands returned +// are to be multiplied together. Otherwise, a list of length one with +// just the division node is returned. getOperands might change the +// operator accordingly. +function flattenDivision(node: mNode) { + // We recurse on the left side of the tree to find operands so far + // Flattening division is always considered part of a bigger picture + // of multiplication, so we get operands with '*' + let operands = getOperands(node.args[0], '*'); + + if (operands.length === 1) { + node.args[0] = operands.pop(); + node.args[1] = flattenOperands(node.args[1]); + operands = [node]; + } + else { + // This is the last operand, the term we'll want to add our division to + const numerator = operands.pop(); + // This is the denominator of the current division node we're recursing on + const denominator = flattenOperands(node.args[1]); + // Note that this means 2 * 3 * 4 / 5 / 6 * 7 will flatten but keep the 4/5/6 + // as an operand - in simplifyDivision.js this is changed to 4/(5*6) + const divisionNode = nodeHelper.Creator.operator('/', [numerator, denominator]); + operands.push(divisionNode); + } + + return operands; +} + +// Returns true if there is a * node nested in some division, with no other +// operators or parentheses between them. +// e.g. returns true: 2*3/4, 2 / 5 / 6 * 7 / 8 +// e.g. returns false: 3/4/5, ((3*2) - 5) / 7, (2*5)/6 +function hasMultiplicationBesideDivision(node: mNode) { + if (!nodeHelper.Type.isOperator(node)) { + return false; + } + if (node.op === '*') { + return true; + } + // we ony recurse through division + if (node.op !== '/') { + return false; + } + return node.args.some(hasMultiplicationBesideDivision); +} \ No newline at end of file diff --git a/src/util/util.ts b/src/util/util.ts deleted file mode 100644 index 58fe6ceb..00000000 --- a/src/util/util.ts +++ /dev/null @@ -1,11 +0,0 @@ -namespace util { -function appendToArrayInObject(dict: Array, key: number, value: any) { - if (dict[key]) { - dict[key].push(value); - } - else { - dict[key] = [value]; - } - return dict; -}; -} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b818afca..82e472b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "module": "commonJS", + "module": "commonjs", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, From 4634a2fa9532aca82c59d78fa71879d12abbccbc Mon Sep 17 00:00:00 2001 From: Ethan Lu Date: Wed, 26 Apr 2017 12:11:38 -0700 Subject: [PATCH 12/12] More type annotations/starting to add more simplification functions --- src/ChangeTypes.ts | 2 +- src/Equation.ts | 2 +- src/factor.ts | 3 +- src/simplifyExpression/arithmeticSearch.ts | 2 + src/util/clone.ts | 2 +- src/util/evaluate.ts | 2 +- src/util/printNode.ts | 106 +++++++++++++++++++++ 7 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 src/util/printNode.ts diff --git a/src/ChangeTypes.ts b/src/ChangeTypes.ts index a82a3ea1..20d8bf65 100644 --- a/src/ChangeTypes.ts +++ b/src/ChangeTypes.ts @@ -1,6 +1,6 @@ // The text to identify rules for each possible step that can be taken -enum ChangeTypes{ +export enum ChangeTypes{ NO_CHANGE, // ARITHMETIC diff --git a/src/Equation.ts b/src/Equation.ts index 8b388bc1..79bb21ee 100644 --- a/src/Equation.ts +++ b/src/Equation.ts @@ -1,4 +1,4 @@ -import * as nodeHelper from "../nodeHelper"; +import * as nodeHelper from "./nodeHelper"; // This represents an equation, made up of the leftNode (LHS), the // rightNode (RHS) and a comparator (=, <, >, <=, or >=) export default class Equation { diff --git a/src/factor.ts b/src/factor.ts index 4eac8e93..eda5c639 100644 --- a/src/factor.ts +++ b/src/factor.ts @@ -1,4 +1,5 @@ -import * as nodeHelper from "../nodeHelper"; +import Negative from "./Negative"; +import * as nodeHelper from "./nodeHelper"; //returns all prime factors of a number export function getPrimeFactors(number: number): number[] { let factors = []; diff --git a/src/simplifyExpression/arithmeticSearch.ts b/src/simplifyExpression/arithmeticSearch.ts index e69de29b..2b9c4f46 100644 --- a/src/simplifyExpression/arithmeticSearch.ts +++ b/src/simplifyExpression/arithmeticSearch.ts @@ -0,0 +1,2 @@ +import * as ChangeTypes from "../ChangeTypes"; +import * as evaluate from "../util/evaluate"; \ No newline at end of file diff --git a/src/util/clone.ts b/src/util/clone.ts index 29aa3d98..a3c50e62 100644 --- a/src/util/clone.ts +++ b/src/util/clone.ts @@ -3,7 +3,7 @@ // And recurses on the children (due to the shallow nature of the mathjs node // clone) //need to somehow make this actually work in TS -function clone(node: mNode): mNode { +export default function clone(node: mNode): mNode { const copy = node.clone(); copy.changeGroup = node.changeGroup; if (node.args) { diff --git a/src/util/evaluate.ts b/src/util/evaluate.ts index 18d5a539..e5828556 100644 --- a/src/util/evaluate.ts +++ b/src/util/evaluate.ts @@ -2,7 +2,7 @@ // e.g. the tree representing (2 + 2) * 5 would be evaluated to the number 20 // it's important that `node` does not contain any symbol nodes -function evaluate(node) { +export function evaluate(node: mNode) { // TODO: once we swap in math-parser, call its evaluate function instead return node.eval(); } diff --git a/src/util/printNode.ts b/src/util/printNode.ts new file mode 100644 index 00000000..34d0ea88 --- /dev/null +++ b/src/util/printNode.ts @@ -0,0 +1,106 @@ +import clone from "./clone"; +import * as flatten from "./flattenOperands"; +import * as nodeHelper from "../nodeHelper"; +// Prints an expression node in asciimath +// If showPlusMinus is true, print + - (e.g. 2 + -3) +// If it's false (the default) 2 + -3 would print as 2 - 3 +// (The + - is needed to support the conversion of subtraction to addition of +// negative terms. See flattenOperands for more details if you're curious.) +export function print(node: mNode, showPlusMinus=false) { + node = flatten(clone(node)); + + let string = printTreeTraversal(node); + if (!showPlusMinus) { + string = string.replace(/\s*?\+\s*?\-\s*?/g, ' - '); + } + return string; +} + +function printTreeTraversal(node: mNode, parentNode?: mNode): string { + if (nodeHelper.PolynomialTerm.isPolynomialTerm(node)) { + const polyTerm = new nodeHelper.PolynomialTerm(node); + // This is so we don't print 2/3 x^2 as 2 / 3x^2 + // Still print x/2 as x/2 and not 1/2 x though + if (polyTerm.hasFractionCoeff() && node.op !== '/') { + const coeffTerm = polyTerm.getCoeffNode(); + const coeffStr = printTreeTraversal(coeffTerm); + + const nonCoeffTerm = Node.Creator.polynomialTerm( + polyTerm.symbol, polyTerm.exponent, null); + const nonCoeffStr = printTreeTraversal(nonCoeffTerm); + + return `${coeffStr} ${nonCoeffStr}`; + } + } + + if (nodeHelper.Type.isIntegerFraction(node)) { + return `${node.args[0]}/${node.args[1]}`; + } + + if (nodeHelper.Type.isOperator(node)) { + if (node.op === '/' && nodeHelper.Type.isOperator(node.args[1])) { + return `${printTreeTraversal(node.args[0])} / (${printTreeTraversal(node.args[1])})`; + } + + let opString = ''; + + switch (node.op) { + case '+': + case '-': + // add space between operator and operands + opString = ` ${node.op} `; + break; + case '*': + if (node.implicit) { + break; + } + opString = ` ${node.op} `; + break; + case '/': + // no space for constant fraction divisions (slightly easier to read) + if (nodeHelper.Type.isConstantFraction(node, true)) { + opString = `${node.op}`; + } + else { + opString = ` ${node.op} `; + } + break; + case '^': + // no space for exponents + opString = `${node.op}`; + break; + } + + let str = node.args.map(arg => printTreeTraversal(arg, node)).join(opString); + + // Need to add parens around any [+, -] operation + // nested in [/, *, ^] operation + // Check #120, #126 issues for more details. + // { "/" [{ "+" ["x", "2"] }, "2"] } -> (x + 2) / 2. + if (parentNode && + nodeHelper.Type.isOperator(parentNode) && + node.op && parentNode.op && + '*/^'.indexOf(parentNode.op) >= 0 && + '+-'.indexOf(node.op) >= 0) { + str = `(${str})`; + } + + return str; + } + else if (nodeHelper.Type.isParenthesis(node)) { + return `(${printTreeTraversal(node.content)})`; + } + else if (nodeHelper.Type.isUnaryMinus(node)) { + if (nodeHelper.Type.isOperator(node.args[0]) && + '*/^'.indexOf(node.args[0].op) === -1 && + !nodeHelper.PolynomialTerm.isPolynomialTerm(node)) { + return `-(${printTreeTraversal(node.args[0])})`; + } + else { + return `-${printTreeTraversal(node.args[0])}`; + } + } + else { + return node.toString(); + } +}