From 48bb64af4e3c756ad91f76f4866b4298439ee5ea Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Sat, 19 Sep 2015 21:24:56 -0700 Subject: [PATCH] Added some comments to the derivative file. Added some test cases as well (explicitly test partial derivatives and pure JS usage). --- lib/function/algebra/derivative.js | 11 ++++-- test/function/algebra/derivative.test.js | 48 +++++++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/function/algebra/derivative.js b/lib/function/algebra/derivative.js index e37ad1fa7..a5e3e1c51 100644 --- a/lib/function/algebra/derivative.js +++ b/lib/function/algebra/derivative.js @@ -52,6 +52,8 @@ function factory (type, config, load, typed) { }, 'Object, SymbolNode, string': function (constNodes, node, varName) { + // Treat other variables like constants. For reasoning, see: + // https://en.wikipedia.org/wiki/Partial_derivative if (node.name != varName) { return constNodes[node] = true; } @@ -126,8 +128,8 @@ function factory (type, config, load, typed) { var arg1 = node.args[0]; var arg2; - var div = false; - var negative = false; + var div = false; // is output a fraction? + var negative = false; // is output negative? var funcDerivative; switch (node.name) { @@ -589,7 +591,10 @@ function factory (type, config, load, typed) { return; } - // Avoids unidentified symbol error + // There should be an incorrect number of arguments if we reach here + + // Change all args to constants to avoid unidentified + // symbol error when compiling function for (var i = 0; i < node.args.length; ++i) { node.args[i] = new ConstantNode(0); } diff --git a/test/function/algebra/derivative.test.js b/test/function/algebra/derivative.test.js index 63b59b6a0..2e919c5f6 100644 --- a/test/function/algebra/derivative.test.js +++ b/test/function/algebra/derivative.test.js @@ -16,7 +16,6 @@ describe('derivative', function() { it('should take the derivative of a SymbolNodes', function() { assert.deepEqual(math.eval('derivative(x, x)'), new ConstantNode(1)); - assert.deepEqual(math.eval('derivative(C, x)'), new ConstantNode(0)); }); it('should maintain parenthesis of ParenthesisNodes', function() { @@ -281,6 +280,53 @@ describe('derivative', function() { ])); }); + it('should take the partial derivative of an expression', function() { + assert.deepEqual(math.eval('derivative(x + y, x)'), math.parse('1 + 0')); + assert.deepEqual(math.eval('derivative(x + log(y)*y, x)'), math.parse('1 + 0')); + + assert.deepEqual(math.eval('derivative(x + y + z, x)'), math.parse('1 + 0 + 0')); + assert.deepEqual(math.eval('derivative(x + log(y)*z, x)'), math.parse('1 + 0')); + + assert.deepEqual(math.eval('derivative(x + log(y)*x, x)'), math.parse('1 + log(y)*1')); + + // 2 * 1 * x ^ (2 - 1) + y * 1 + 0 = 2x + y + assert.deepEqual(math.eval('derivative(x^2 + x*y + y^2, x)'), new OperatorNode('+', 'add', [ + new OperatorNode('+', 'add', [ + new OperatorNode('*', 'multiply', [ + new ConstantNode(2), + new OperatorNode('*', 'multiply', [ + new ConstantNode(1), + new OperatorNode('^', 'pow', [ + new SymbolNode('x'), + math.parse('2 - 1') + ]) + ]) + ]), + math.parse('y * 1') + ]), + new ConstantNode(0) + ])); + }); + + it('should function properly even without being called within an eval', function() { + var f = math.parse('2x^3'); + + // 2*3*1*x^(3-1) = 6x^2 + assert.deepEqual(math.derivative(f, new SymbolNode('x')), new OperatorNode('*', 'multiply', [ + new ConstantNode(2), + new OperatorNode('*', 'multiply', [ + new ConstantNode(3), + new OperatorNode('*', 'multiply', [ + new ConstantNode(1), + new OperatorNode('^', 'pow', [ + new SymbolNode('x'), + math.parse('3 - 1') + ]) + ]) + ]) + ])); + }); + it('should throw error if expressions contain unsupported operators or functions', function() { assert.throws(function () { math.eval('derivative(x << 2, x)'); }, /Error: Operator "<<" not supported by derivative/); assert.throws(function () { math.eval('derivative(subset(x), x)'); }, /Error: Function "subset" not supported by derivative/);