From a2b31e4d02cbc480e8003380798d024b43ba458f Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 25 Aug 2015 00:58:45 +0000 Subject: [PATCH 1/5] First commit --- lib/function/algebra/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/function/algebra/index.js b/lib/function/algebra/index.js index 0a1920744..f500f5589 100644 --- a/lib/function/algebra/index.js +++ b/lib/function/algebra/index.js @@ -1,6 +1,10 @@ module.exports = [ require('./derivative'), require('./derivative.transform'), + + // simplify + require('./simplify'), + require('./simplify.transform'), // decomposition require('./decomposition/lup'), From 3b8ad55fba24184a4ff52ef8202cf4d747a3e589 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 25 Aug 2015 00:59:42 +0000 Subject: [PATCH 2/5] Added new files --- lib/function/algebra/simplify.js | 196 +++++++++++++++++++++ lib/function/algebra/simplify.transform.js | 28 +++ 2 files changed, 224 insertions(+) create mode 100644 lib/function/algebra/simplify.js create mode 100644 lib/function/algebra/simplify.transform.js diff --git a/lib/function/algebra/simplify.js b/lib/function/algebra/simplify.js new file mode 100644 index 000000000..b7b0f3766 --- /dev/null +++ b/lib/function/algebra/simplify.js @@ -0,0 +1,196 @@ +'use strict'; + +function factory (type, config, load, typed) { + var parse = load(require('../../expression/parse')); + var ConstantNode = load(require('../../expression/node/ConstantNode')); + var FunctionNode = load(require('../../expression/node/FunctionNode')); + var OperatorNode = load(require('../../expression/node/OperatorNode')); + var ParenthesisNode = load(require('../../expression/node/ParenthesisNode')); + var SymbolNode = load(require('../../expression/node/SymbolNode')); + + /** + * Returns a simplified expression tree. The parameter passed to the function is cloned + * before simplifying. + * See this for more details on the theory: + * http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions + * https://en.wikipedia.org/wiki/Symbolic_computation#Simplification + * + * Syntax: + * + * simplify(expr) + * + * Usage: + * + * math.eval('simplify(2 * 1 * x ^ (2 - 1))') + * + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} expr + * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The simplified form of `expr` + */ + var simplify = typed('simplify', { + 'Node': function (expr) { + var res = expr.clone(); + _simplify(res); + return res; + } + }); + + // Array of rules to be used to simplify expressions + var ruleSet = []; + + // Array of strings, used to build the ruleSet. + // Each l (left side) and r (right side) are parsed by + // the expression parser into a node tree. + // Left hand sides are matched to subtrees within the + // expression to be parsed and replaced with the right + // hand side. + var rules = [ + { l: "0*n1", r: "0" } + ]; + + + /** + * Parse the string array of rules into nodes + * + * Example syntax for rules: + * + * Position constants to the left in a product: + * { l: "n1 * c1", r: "c1 * n1" } + * n1 is any Node, and c1 is a ConstantNode. + * + * Apply difference of squares formula: + * { l: "(n1 - n2) * (n1 + n2)", r: "n1^2 - n2^2" } + * n1, n2 mean any Node. + */ + function _buildRules() { + for(var i=0; i} args + * Expects the following arguments: [f, x] + * @param {Object} math + * @param {Object} [scope] + */ + var simplifyTransform = typed('simplify', { + 'Array, Object, Object': function (args) { + return simplify.apply(null, args); + } + }); + + simplifyTransform.rawArgs = true; + + return simplifyTransform; +} + +exports.name = 'simplify'; +exports.path = 'expression.transform'; +exports.factory = factory; From 2434ed3b90c92ddc3b1375656444af5c4d5d6704 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 25 Aug 2015 19:42:04 +0000 Subject: [PATCH 3/5] _simplify, _ruleMatch, _exactMatch --- lib/function/algebra/simplify.js | 169 +++++++++++++++++++++++++++---- 1 file changed, 151 insertions(+), 18 deletions(-) diff --git a/lib/function/algebra/simplify.js b/lib/function/algebra/simplify.js index b7b0f3766..b675ade6b 100644 --- a/lib/function/algebra/simplify.js +++ b/lib/function/algebra/simplify.js @@ -29,6 +29,10 @@ function factory (type, config, load, typed) { var simplify = typed('simplify', { 'Node': function (expr) { var res = expr.clone(); + + // TODO: Remove all ParenthesisNodes + + // TODO: Make _simplify return a new node (since head node may change while simplifying) _simplify(res); return res; } @@ -43,8 +47,10 @@ function factory (type, config, load, typed) { // Left hand sides are matched to subtrees within the // expression to be parsed and replaced with the right // hand side. + // TODO: Add support for constraints on constants (either in the form of a '=' expression or a callback [callback allows things like comparing symbols alphabetically]) + // TODO: Add support for calculation of rhs constants, such as: { l: "c1+c2", r: "c3", calculations: ["c3 = c1 + c2"] } var rules = [ - { l: "0*n1", r: "0" } + { l: "0*n1", r: "0" }, ]; @@ -81,13 +87,21 @@ function factory (type, config, load, typed) { */ var _simplify = typed('_simplify', { 'Node': function (node) { + + console.log('Entering _simplify(' + node.toString() + ')'); // Try to match a rule against this node for (var i=0; i Date: Wed, 26 Aug 2015 04:50:52 +0000 Subject: [PATCH 4/5] Basic functionality of simplify function --- lib/function/algebra/simplify.js | 169 +++++++++++++++++++++++-------- 1 file changed, 127 insertions(+), 42 deletions(-) diff --git a/lib/function/algebra/simplify.js b/lib/function/algebra/simplify.js index b675ade6b..29c762aeb 100644 --- a/lib/function/algebra/simplify.js +++ b/lib/function/algebra/simplify.js @@ -9,9 +9,9 @@ function factory (type, config, load, typed) { var SymbolNode = load(require('../../expression/node/SymbolNode')); /** - * Returns a simplified expression tree. The parameter passed to the function is cloned - * before simplifying. - * See this for more details on the theory: + * Returns a simplified expression tree. + * + * For more details on the theory: * http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions * https://en.wikipedia.org/wiki/Symbolic_computation#Simplification * @@ -28,16 +28,33 @@ function factory (type, config, load, typed) { */ var simplify = typed('simplify', { 'Node': function (expr) { - var res = expr.clone(); - // TODO: Remove all ParenthesisNodes + var res = removeParens(expr); + var after = 'foo'; + var before = 'bar'; + while(before != after) { + var before = after; + res = _simplify(res); + var after = res.toString({paranthesis: 'all'}); + } - // TODO: Make _simplify return a new node (since head node may change while simplifying) - _simplify(res); + console.log("Returning " + after + " from simplify"); return res; } }); + function removeParens(node) { + return node.transform(function(node, path, parent) { + if(node.isParenthesisNode) { + return node.content; + } + else { + return node; + } + }); + } + + // Array of rules to be used to simplify expressions var ruleSet = []; @@ -48,9 +65,24 @@ function factory (type, config, load, typed) { // expression to be parsed and replaced with the right // hand side. // TODO: Add support for constraints on constants (either in the form of a '=' expression or a callback [callback allows things like comparing symbols alphabetically]) - // TODO: Add support for calculation of rhs constants, such as: { l: "c1+c2", r: "c3", calculations: ["c3 = c1 + c2"] } + // To evaluate lhs constants for rhs constants, use: { l: "c1+c2", r: "c3", evaluate: "c3 = c1 + c2" }. Multiple assignments are separated by ';' in block format. var rules = [ - { l: "0*n1", r: "0" }, + { l: "v*c", r: "c*v" }, + { l: "0*n", r: "0" }, + { l: "c1+c2", r: "c3", evaluate: "c3 = c1 + c2" }, + { l: "c1-c2", r: "c3", evaluate: "c3 = c1 - c2" }, + { l: "c1*c2", r: "c3", evaluate: "c3 = c1 * c2" }, + { l: "n^1", r: "n"}, + { l: "c1*(c2*n3)", r: "(c1*c2)*n3" }, + { l: "(c1*n2)*n3", r: "c1*(n2*n3)" }, + { l: "1*n", r: "n" }, + { l: "n/n", r: "1" }, + { l: "n+n", r: "2*n" }, + { l: "n*n", r: "n^2" }, + { l: "n1*n2 + n2", r: "(n1+1)*n2" }, + { l: "n^n1 * n^n2", r: "n^(n1+n2)" }, + { l: "n^n1 * n", r: "n^(n1+1)" }, + { l: "n * n^n1", r: "n^(n1+1)" }, ]; @@ -70,56 +102,95 @@ function factory (type, config, load, typed) { function _buildRules() { for(var i=0; i Date: Wed, 26 Aug 2015 04:53:50 +0000 Subject: [PATCH 5/5] Fixed tabs --- lib/function/algebra/index.js | 4 +- lib/function/algebra/simplify.js | 624 +++++++++++++++---------------- 2 files changed, 314 insertions(+), 314 deletions(-) diff --git a/lib/function/algebra/index.js b/lib/function/algebra/index.js index f500f5589..342845ba8 100644 --- a/lib/function/algebra/index.js +++ b/lib/function/algebra/index.js @@ -1,8 +1,8 @@ module.exports = [ require('./derivative'), require('./derivative.transform'), - - // simplify + + // simplify require('./simplify'), require('./simplify.transform'), diff --git a/lib/function/algebra/simplify.js b/lib/function/algebra/simplify.js index 29c762aeb..4e8aaecb4 100644 --- a/lib/function/algebra/simplify.js +++ b/lib/function/algebra/simplify.js @@ -1,7 +1,7 @@ 'use strict'; function factory (type, config, load, typed) { - var parse = load(require('../../expression/parse')); + var parse = load(require('../../expression/parse')); var ConstantNode = load(require('../../expression/node/ConstantNode')); var FunctionNode = load(require('../../expression/node/FunctionNode')); var OperatorNode = load(require('../../expression/node/OperatorNode')); @@ -10,9 +10,9 @@ function factory (type, config, load, typed) { /** * Returns a simplified expression tree. - * + * * For more details on the theory: - * http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions + * http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions * https://en.wikipedia.org/wiki/Symbolic_computation#Simplification * * Syntax: @@ -29,90 +29,90 @@ function factory (type, config, load, typed) { var simplify = typed('simplify', { 'Node': function (expr) { - var res = removeParens(expr); - var after = 'foo'; - var before = 'bar'; - while(before != after) { - var before = after; - res = _simplify(res); - var after = res.toString({paranthesis: 'all'}); - } + var res = removeParens(expr); + var after = 'foo'; + var before = 'bar'; + while(before != after) { + var before = after; + res = _simplify(res); + var after = res.toString({paranthesis: 'all'}); + } - console.log("Returning " + after + " from simplify"); - return res; + console.log("Returning " + after + " from simplify"); + return res; } }); - function removeParens(node) { - return node.transform(function(node, path, parent) { - if(node.isParenthesisNode) { - return node.content; - } - else { - return node; - } - }); - } - + function removeParens(node) { + return node.transform(function(node, path, parent) { + if(node.isParenthesisNode) { + return node.content; + } + else { + return node; + } + }); + } + - // Array of rules to be used to simplify expressions - var ruleSet = []; + // Array of rules to be used to simplify expressions + var ruleSet = []; - // Array of strings, used to build the ruleSet. + // Array of strings, used to build the ruleSet. // Each l (left side) and r (right side) are parsed by - // the expression parser into a node tree. - // Left hand sides are matched to subtrees within the - // expression to be parsed and replaced with the right - // hand side. - // TODO: Add support for constraints on constants (either in the form of a '=' expression or a callback [callback allows things like comparing symbols alphabetically]) - // To evaluate lhs constants for rhs constants, use: { l: "c1+c2", r: "c3", evaluate: "c3 = c1 + c2" }. Multiple assignments are separated by ';' in block format. - var rules = [ - { l: "v*c", r: "c*v" }, - { l: "0*n", r: "0" }, - { l: "c1+c2", r: "c3", evaluate: "c3 = c1 + c2" }, - { l: "c1-c2", r: "c3", evaluate: "c3 = c1 - c2" }, - { l: "c1*c2", r: "c3", evaluate: "c3 = c1 * c2" }, - { l: "n^1", r: "n"}, - { l: "c1*(c2*n3)", r: "(c1*c2)*n3" }, - { l: "(c1*n2)*n3", r: "c1*(n2*n3)" }, - { l: "1*n", r: "n" }, - { l: "n/n", r: "1" }, - { l: "n+n", r: "2*n" }, - { l: "n*n", r: "n^2" }, - { l: "n1*n2 + n2", r: "(n1+1)*n2" }, - { l: "n^n1 * n^n2", r: "n^(n1+n2)" }, - { l: "n^n1 * n", r: "n^(n1+1)" }, - { l: "n * n^n1", r: "n^(n1+1)" }, - ]; + // the expression parser into a node tree. + // Left hand sides are matched to subtrees within the + // expression to be parsed and replaced with the right + // hand side. + // TODO: Add support for constraints on constants (either in the form of a '=' expression or a callback [callback allows things like comparing symbols alphabetically]) + // To evaluate lhs constants for rhs constants, use: { l: "c1+c2", r: "c3", evaluate: "c3 = c1 + c2" }. Multiple assignments are separated by ';' in block format. + var rules = [ + { l: "v*c", r: "c*v" }, + { l: "0*n", r: "0" }, + { l: "c1+c2", r: "c3", evaluate: "c3 = c1 + c2" }, + { l: "c1-c2", r: "c3", evaluate: "c3 = c1 - c2" }, + { l: "c1*c2", r: "c3", evaluate: "c3 = c1 * c2" }, + { l: "n^1", r: "n"}, + { l: "c1*(c2*n3)", r: "(c1*c2)*n3" }, + { l: "(c1*n2)*n3", r: "c1*(n2*n3)" }, + { l: "1*n", r: "n" }, + { l: "n/n", r: "1" }, + { l: "n+n", r: "2*n" }, + { l: "n*n", r: "n^2" }, + { l: "n1*n2 + n2", r: "(n1+1)*n2" }, + { l: "n^n1 * n^n2", r: "n^(n1+n2)" }, + { l: "n^n1 * n", r: "n^(n1+1)" }, + { l: "n * n^n1", r: "n^(n1+1)" }, + ]; - /** - * Parse the string array of rules into nodes - * - * Example syntax for rules: + /** + * Parse the string array of rules into nodes + * + * Example syntax for rules: * - * Position constants to the left in a product: - * { l: "n1 * c1", r: "c1 * n1" } - * n1 is any Node, and c1 is a ConstantNode. - * - * Apply difference of squares formula: - * { l: "(n1 - n2) * (n1 + n2)", r: "n1^2 - n2^2" } - * n1, n2 mean any Node. - */ - function _buildRules() { - for(var i=0; i