diff --git a/lib/function/algebra/index.js b/lib/function/algebra/index.js index 0a1920744..342845ba8 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'), diff --git a/lib/function/algebra/simplify.js b/lib/function/algebra/simplify.js new file mode 100644 index 000000000..4e8aaecb4 --- /dev/null +++ b/lib/function/algebra/simplify.js @@ -0,0 +1,414 @@ +'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. + * + * 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 = 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; + } + }); + + 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 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)" }, + ]; + + + /** + * 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;