Repository: josdejong/mathjs
Pull request #780 (2017-01-22 14:36:30)

Fixed derivative of exp(x)


Patch:
diff --git a/HISTORY.md b/HISTORY.md
index 1c877f206..6996b4f38 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -3,8 +3,6 @@
 
 ## not yet released, version 3.9.0
 
-- Implemented support for algebra: powerful new functions `simplify` and
-  `derivative`. Thanks @ericman314, @tetslee, and @BigFav.
 - Reverted `FunctionNode` not accepting a string as function name anymore.
 - Fixed #765: `FunctionAssignmentNode.toString()` returning a string
   incompatible with the function assignment syntax.
diff --git a/docs/expressions/algebra.md b/docs/expressions/algebra.md
deleted file mode 100644
index bab972ff7..000000000
--- a/docs/expressions/algebra.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Algebra (symbolic computation)
-
-math.js has built-in support for symbolic computation ([CAS](https://www.wikiwand.com/en/Computer_algebra_system)). It can parse expressions into an expression tree and do algebraic operations like simplification and derivation on the tree.
-
-> It's worth mentioning an excellent extension on math.js here: the step-by-step solver [mathsteps](https://github.com/socraticorg/mathsteps).
-> The goal of [mathsteps](https://github.com/socraticorg/mathsteps) is to offer a math solver library that is focused on pedagogy (how best to teach). The math problems it focuses on are pre-algebra and algebra problems involving simplifying expressions.
-
-
-## Simplify
-
-The function [`math.simplify`](../reference/functions/simplify.md) simplifies an expression tree:
-
-```js
-// simplify an expression
-console.log(math.simplify('3 + 2 / 4').toString());             // '7 / 2'
-console.log(math.simplify('2x + 3x').toString());               // '5 * x'
-console.log(math.simplify('x^2 + x + 3 + x^2').toString());     // '2 * x ^ 2 + x + 3'
-console.log(math.simplify('x * y * -x / (x ^ 2)').toString());  // '-y'
-```
-
-The function accepts either a string or an expression tree (`Node`) as input, and outputs a simplified expression tree (`Node`). This node tree can be transformed and evaluated as described in detail on the page [Expression trees]('./expression_trees.md').
-
-```js
-// work with an expression tree, evaluate results
-var f = math.parse('2x + x');
-var simplified = math.simplify(f);
-console.log(simplified.toString());    // '3 * x'
-console.log(simplified.eval({x: 4}));  // 12
-```
-
-For more details on the theory of expression simplification, see:
-
-- http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions
-- https://en.wikipedia.org/wiki/Symbolic_computation#Simplification
-
-
-## Derivative
-
-The function [`math.derivative`](../reference/functions/derivative.md) finds the symbolic derivative of an expression:
-
-```js
-// calculate a derivative
-console.log(math.derivative('2x^2 + 3x + 4', 'x').toString());  // '4 * x + 3'
-console.log(math.derivative('sin(2x)', 'x').toString());        // '2 * cos(2 * x)'
-```
-
-Similar to the function `math.simplify`, `math.derivative` accepts either a string or an expression tree (`Node`) as input, and outputs a simplified expression tree (`Node`).
-
-```js
-// work with an expression tree, evaluate results
-var h = math.parse('x^2 + x');
-var x = math.parse('x');
-var dh = math.derivative(h, x);
-console.log(dh.toString());       // '2 * x + 1'
-console.log(dh.eval({x: 3}));     // '7'
-```
-
-The rules used by `math.derivative` can be found on Wikipedia:
-
-- http://en.wikipedia.org/wiki/Differentiation_rules
diff --git a/docs/expressions/expression_trees.md b/docs/expressions/expression_trees.md
index 1be3392e2..f0dfe579e 100644
--- a/docs/expressions/expression_trees.md
+++ b/docs/expressions/expression_trees.md
@@ -140,6 +140,11 @@ All nodes have the following methods:
 
     Information about the options in [Customization](customization.md#custom-latex-and-string-output).
 
+-   `simplify([rules: Array]): Node`
+
+    Simplify the expression tree. Optionally, a custom set with rules can be
+    passed. See function `math.simplify` for more details.
+
 -   `toTex(options: object): string`
 
     Get a [LaTeX](http://en.wikipedia.org/wiki/LaTeX) representation of the
diff --git a/docs/expressions/index.md b/docs/expressions/index.md
index a3f4c9464..61674fd3c 100644
--- a/docs/expressions/index.md
+++ b/docs/expressions/index.md
@@ -15,6 +15,5 @@ This section is divided in the following pages:
 - [Syntax](syntax.md) describes how to write expressions.
 - [Expression trees](expression_trees.md) explains how to parse an expression into an
   expression tree, and use this to analyse and manipulate the expression.
-- [Algebra](algebra.md) describing symbolic computation in math.js.
 - [Customization](customization.md) describes how to customize processing and
   evaluation of expressions.
diff --git a/docs/index.md b/docs/index.md
index f9ab1c0ab..c300a1a3f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,6 +1,9 @@
 # Documentation
 
-[Math.js](http://mathjs.org) is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with different data types like numbers, big numbers, complex numbers, units, and matrices.
+[Math.js](http://mathjs.org) is an extensive math library for JavaScript and Node.js.
+It features a flexible expression parser, a large set of built-in functions and constants,
+and offers an integrated solution to work with different data types like numbers,
+big numbers, complex numbers, units, and matrices.
 
 Math.js can be used in the browser, in node.js and in any JavaScript engine. Installation and download instructions are available on the [Download page](http://mathjs.org/download.html) of the website.
 
@@ -20,7 +23,6 @@ Math.js can be used in the browser, in node.js and in any JavaScript engine. Ins
   - [Parsing and evaluation](expressions/parsing.md)
   - [Syntax](expressions/syntax.md)
   - [Expression trees](expressions/expression_trees.md)
-  - [Algebra](expressions/algebra.md)
   - [Customization](expressions/customization.md)
 - **[Data Types](datatypes/index.md)**
   - [Numbers](datatypes/numbers.md)
diff --git a/examples/algebra.js b/examples/algebra.js
deleted file mode 100644
index 9e7182083..000000000
--- a/examples/algebra.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// algebra
-//
-// math.js has support for symbolic computation (CAS). It can parse
-// expressions in an expression tree and do algebraic operations like
-// simplification and derivation on this tree.
-
-// load math.js (using node.js)
-var math = require('../index');
-
-// simplify an expression
-console.log('simplify expressions');
-console.log(math.simplify('3 + 2 / 4').toString());             // '7 / 2'
-console.log(math.simplify('2x + 3x').toString());               // '5 * x'
-console.log(math.simplify('x^2 + x + 3 + x^2').toString());     // '2 * x ^ 2 + x + 3'
-console.log(math.simplify('x * y * -x / (x ^ 2)').toString());  // '-y'
-
-// work with an expression tree, evaluate results
-var f = math.parse('2x + x');
-var simplified = math.simplify(f);
-console.log(simplified.toString());    // '3 * x'
-console.log(simplified.eval({x: 4}));  // 12
-console.log()
-
-// calculate a derivative
-console.log('calculate derivatives');
-console.log(math.derivative('2x^2 + 3x + 4', 'x').toString());  // '4 * x + 3'
-console.log(math.derivative('sin(2x)', 'x').toString());        // '2 * cos(2 * x)'
-
-// work with an expression tree, evaluate results
-var h = math.parse('x^2 + x');
-var dh = math.derivative(h, 'x');
-console.log(dh.toString());       // '2 * x + 1'
-console.log(dh.eval({x: 3}));     // '7'
diff --git a/lib/expression/docs/function/algebra/derivative.js b/lib/expression/docs/function/algebra/derivative.js
deleted file mode 100644
index a3dce7e43..000000000
--- a/lib/expression/docs/function/algebra/derivative.js
+++ /dev/null
@@ -1,22 +0,0 @@
-module.exports = {
-  'name': 'derivative',
-  'category': 'Algebra',
-  'syntax': [
-    'derivative(expr)',
-    'derivative(expr, {simplify: boolean})'
-  ],
-  'description': 'Takes the derivative of an expression expressed in parser Nodes. The derivative will be taken over the supplied variable in the second parameter. If there are multiple variables in the expression, it will return a partial derivative.',
-  'examples': [
-    'derivative("2x^3", "x")',
-    'derivative("2x^3", "x", {simplify: false})',
-    'derivative("2x^2 + 3x + 4", "x")',
-    'derivative("sin(2x)", "x")',
-    'f = parse("x^2 + x")',
-    'x = parse("x")',
-    'df = derivative(f, x)',
-    'df.eval({x: 3})'
-  ],
-  'seealso': [
-    'simplify', 'parse', 'eval'
-  ]
-};
diff --git a/lib/expression/docs/function/algebra/simplify.js b/lib/expression/docs/function/algebra/simplify.js
deleted file mode 100644
index 78c50a677..000000000
--- a/lib/expression/docs/function/algebra/simplify.js
+++ /dev/null
@@ -1,19 +0,0 @@
-module.exports = {
-  'name': 'simplify',
-  'category': 'Algebra',
-  'syntax': [
-    'simplify(expr)',
-    'simplify(expr, rules)'
-  ],
-  'description': 'Simplify an expression tree.',
-  'examples': [
-    'simplify("3 + 2 / 4")',
-    'simplify("x^2 + x + 3 + x^2")',
-    'f = parse("x^2 + x")',
-    'simplified = simplify(f)',
-    'simplified.eval({x: 4})'
-  ],
-  'seealso': [
-    'derivative', 'parse', 'eval'
-  ]
-};
diff --git a/lib/expression/docs/index.js b/lib/expression/docs/index.js
index 77b433b0d..39f759e6f 100644
--- a/lib/expression/docs/index.js
+++ b/lib/expression/docs/index.js
@@ -98,11 +98,9 @@ function factory (construction, config, load, typed) {
   docs.planckTemperature = {description: 'Planck temperature', examples: ['planckTemperature']};
 
   // functions - algebra
-  docs.derivative = require('./function/algebra/derivative');
   docs.lsolve = require('./function/algebra/lsolve');
   docs.lup = require('./function/algebra/lup');
   docs.lusolve = require('./function/algebra/lusolve');
-  docs.simplify = require('./function/algebra/simplify');
   docs.slu = require('./function/algebra/slu');
   docs.usolve = require('./function/algebra/usolve');
 
diff --git a/lib/expression/node/Node.js b/lib/expression/node/Node.js
index bfdf04e34..be88a5280 100644
--- a/lib/expression/node/Node.js
+++ b/lib/expression/node/Node.js
@@ -72,6 +72,20 @@ function factory (type, config, load, typed, math) {
     return factory(defs);
   };
 
+  /**
+   * Simplify the expression tree.
+   * @param {Array<{l:string, r: string} | string | function>} [rules]
+   *            Optional list with custom rules
+   * @return {Node}
+   *            Returns the simplified expression tree.
+   */
+  Node.prototype.simplify = function (rules) {
+    if (typeof rules !== 'undefined') {
+      return math.simplify(this, rules);
+    }
+    return math.simplify(this);
+  };
+
   /**
    * Compile the node to javascript code
    * @param {Object} defs     Object which can be used to define functions
diff --git a/lib/function/algebra/derivative.js b/lib/function/algebra/derivative.js
index 5141b9dd1..a5c1a125f 100644
--- a/lib/function/algebra/derivative.js
+++ b/lib/function/algebra/derivative.js
@@ -27,7 +27,6 @@ function factory (type, config, load, typed) {
    *
    *     math.derivative('x^2', 'x');                     // Node {2 * x}
    *     math.derivative('x^2', 'x', {simplify: false});  // Node {2 * 1 * x ^ (2 - 1)
-   *     math.derivative('sin(2x)', 'x'));                // Node {2 * cos(2 * x)}
    *     math.derivative('2*x', 'x').eval();              // number 2
    *     math.derivative('x^2', 'x').eval({x: 4});        // number 8
    *     var f = math.parse('x^2');
@@ -280,7 +279,7 @@ function factory (type, config, load, typed) {
           break;
         case 'exp':
           // d/dx(e^x) = e^x
-          funcDerivative = arg1.clone();
+          funcDerivative = new FunctionNode('exp', [arg1.clone()]);
           break;
         case 'sin':
           // d/dx(sin(x)) = cos(x)
diff --git a/lib/function/algebra/simplify.js b/lib/function/algebra/simplify.js
index 9ab45fc69..78570d4ac 100644
--- a/lib/function/algebra/simplify.js
+++ b/lib/function/algebra/simplify.js
@@ -66,11 +66,11 @@ function factory (type, config, load, typed) {
    */
   var simplify = typed('simplify', {
     'string': function (expr) {
-      return simplify(parse(expr), simplify.rules);
+      return parse(expr).simplify(simplify.rules);
     },
 
     'string, Array': function (expr, rules) {
-      return simplify(parse(expr), rules);
+      return parse(expr).simplify(rules);
     },
 
     'Node': function (expr) {
diff --git a/lib/function/algebra/simplify/util.js b/lib/function/algebra/simplify/util.js
index dfa3693b4..3074c3fb1 100644
--- a/lib/function/algebra/simplify/util.js
+++ b/lib/function/algebra/simplify/util.js
@@ -3,7 +3,6 @@
 function factory(type, config, load, typed, math) {
   var FunctionNode = math.expression.node.FunctionNode;
   var OperatorNode = math.expression.node.OperatorNode;
-  var SymbolNode = math.expression.node.SymbolNode;
 
   // TODO commutative/associative properties rely on the arguments
   // e.g. multiply is not commutative for matrices
@@ -139,7 +138,7 @@ function factory(type, config, load, typed, math) {
     }
     else {
       return function(args){
-        return new FunctionNode(new SymbolNode(node.name), args);
+        return new FunctionNode(new Symbol(node.name), args);
       };
     }
   }


Test patch:
diff --git a/test/function/algebra/derivative.test.js b/test/function/algebra/derivative.test.js
index d04686eae..b61cc7d80 100644
--- a/test/function/algebra/derivative.test.js
+++ b/test/function/algebra/derivative.test.js
@@ -25,10 +25,6 @@ describe('derivative', function() {
     compareString(derivative('2x', 'x', {simplify: false}), '2 * 1');
   });
 
-  it('should create a function node', function() {
-    compareString(derivative('sin(2x)', 'x'), '2 * cos(2 * x)');
-  });
-
   it('should take the derivative of a SymbolNodes', function() {
     compareString(derivativeWithoutSimplify('x', 'x'), '1');
   });
@@ -143,6 +139,8 @@ describe('derivative', function() {
     compareString(derivativeWithoutSimplify('asech((2x))', 'x'), '-(2 * 1) / ((2 x) * sqrt(1 - (2 x) ^ 2))');
     compareString(derivativeWithoutSimplify('acsch((2x))', 'x'), '-(2 * 1) / (abs((2 x)) * sqrt((2 x) ^ 2 + 1))');
     compareString(derivativeWithoutSimplify('acoth((2x))', 'x'), '-(2 * 1) / (1 - (2 x) ^ 2)');
+    
+    compareString(derivativeWithoutSimplify('exp(2x)', 'x'), '2 * 1 * exp(2 x)');
   });
 
   it('should take the partial derivative of an expression', function() {
@@ -179,14 +177,14 @@ describe('derivative', function() {
       var res = math.eval('derivative("x^2", "x")');
       assert.ok(res && res.isNode)
 
-      assert.equal(res.toString(), '2 * x');
+      assert.equal(res.simplify().toString(), '2 * x');
     });
 
     it('should evaluate a derivative containing nodes', function() {
       var res = math.eval('derivative(parse("x^2"), parse("x"))');
       assert.ok(res && res.isNode)
 
-      assert.equal(res.toString(), '2 * x');
+      assert.equal(res.simplify().toString(), '2 * x');
     });
 
   });
diff --git a/test/function/algebra/simplify.test.js b/test/function/algebra/simplify.test.js
index 278ba9bac..ad490d449 100644
--- a/test/function/algebra/simplify.test.js
+++ b/test/function/algebra/simplify.test.js
@@ -14,7 +14,7 @@ describe('simplify', function() {
   }
 
   it('should not change the value of the function', function() {
-    simplifyAndCompareEval('3+2/4+2*8', '39/2');
+    simplifyAndCompareEval('3+2/4+2*8', '7/2+16');
     simplifyAndCompareEval('x+1+x', '2x+1', {x:7});
     simplifyAndCompareEval('x+1+2x', '3x+1', {x:7});
     simplifyAndCompareEval('x^2+x-3+x^2', '2x^2+x-3', {x:7});
@@ -65,7 +65,7 @@ describe('simplify', function() {
     });
 
     it('should compute and simplify derivatives', function() {
-      var res = math.eval('derivative("5x*3x", "x")');
+      var res = math.eval('simplify(derivative("5x*3x", "x"))');
       assert.ok(res && res.isNode)
       assert.equal(res.toString(), '30 * x');
     });