UNPKG

24.9 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.createDerivative = void 0;
7
8var _is = require("../../utils/is.js");
9
10var _factory = require("../../utils/factory.js");
11
12var name = 'derivative';
13var dependencies = ['typed', 'config', 'parse', 'simplify', 'equal', 'isZero', 'numeric', 'ConstantNode', 'FunctionNode', 'OperatorNode', 'ParenthesisNode', 'SymbolNode'];
14var createDerivative = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
15 var typed = _ref.typed,
16 config = _ref.config,
17 parse = _ref.parse,
18 simplify = _ref.simplify,
19 equal = _ref.equal,
20 isZero = _ref.isZero,
21 numeric = _ref.numeric,
22 ConstantNode = _ref.ConstantNode,
23 FunctionNode = _ref.FunctionNode,
24 OperatorNode = _ref.OperatorNode,
25 ParenthesisNode = _ref.ParenthesisNode,
26 SymbolNode = _ref.SymbolNode;
27
28 /**
29 * Takes the derivative of an expression expressed in parser Nodes.
30 * The derivative will be taken over the supplied variable in the
31 * second parameter. If there are multiple variables in the expression,
32 * it will return a partial derivative.
33 *
34 * This uses rules of differentiation which can be found here:
35 *
36 * - [Differentiation rules (Wikipedia)](https://en.wikipedia.org/wiki/Differentiation_rules)
37 *
38 * Syntax:
39 *
40 * derivative(expr, variable)
41 * derivative(expr, variable, options)
42 *
43 * Examples:
44 *
45 * math.derivative('x^2', 'x') // Node {2 * x}
46 * math.derivative('x^2', 'x', {simplify: false}) // Node {2 * 1 * x ^ (2 - 1)
47 * math.derivative('sin(2x)', 'x')) // Node {2 * cos(2 * x)}
48 * math.derivative('2*x', 'x').evaluate() // number 2
49 * math.derivative('x^2', 'x').evaluate({x: 4}) // number 8
50 * const f = math.parse('x^2')
51 * const x = math.parse('x')
52 * math.derivative(f, x) // Node {2 * x}
53 *
54 * See also:
55 *
56 * simplify, parse, evaluate
57 *
58 * @param {Node | string} expr The expression to differentiate
59 * @param {SymbolNode | string} variable The variable over which to differentiate
60 * @param {{simplify: boolean}} [options]
61 * There is one option available, `simplify`, which
62 * is true by default. When false, output will not
63 * be simplified.
64 * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr`
65 */
66 var derivative = typed('derivative', {
67 'Node, SymbolNode, Object': function NodeSymbolNodeObject(expr, variable, options) {
68 var constNodes = {};
69 constTag(constNodes, expr, variable.name);
70
71 var res = _derivative(expr, constNodes);
72
73 return options.simplify ? simplify(res) : res;
74 },
75 'Node, SymbolNode': function NodeSymbolNode(expr, variable) {
76 return this(expr, variable, {
77 simplify: true
78 });
79 },
80 'string, SymbolNode': function stringSymbolNode(expr, variable) {
81 return this(parse(expr), variable);
82 },
83 'string, SymbolNode, Object': function stringSymbolNodeObject(expr, variable, options) {
84 return this(parse(expr), variable, options);
85 },
86 'string, string': function stringString(expr, variable) {
87 return this(parse(expr), parse(variable));
88 },
89 'string, string, Object': function stringStringObject(expr, variable, options) {
90 return this(parse(expr), parse(variable), options);
91 },
92 'Node, string': function NodeString(expr, variable) {
93 return this(expr, parse(variable));
94 },
95 'Node, string, Object': function NodeStringObject(expr, variable, options) {
96 return this(expr, parse(variable), options);
97 } // TODO: replace the 8 signatures above with 4 as soon as typed-function supports optional arguments
98
99 /* TODO: implement and test syntax with order of derivatives -> implement as an option {order: number}
100 'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) {
101 let res = expr
102 for (let i = 0; i < order; i++) {
103 let constNodes = {}
104 constTag(constNodes, expr, variable.name)
105 res = _derivative(res, constNodes)
106 }
107 return res
108 }
109 */
110
111 });
112 derivative._simplify = true;
113
114 derivative.toTex = function (deriv) {
115 return _derivTex.apply(null, deriv.args);
116 }; // FIXME: move the toTex method of derivative to latex.js. Difficulty is that it relies on parse.
117 // NOTE: the optional "order" parameter here is currently unused
118
119
120 var _derivTex = typed('_derivTex', {
121 'Node, SymbolNode': function NodeSymbolNode(expr, x) {
122 if ((0, _is.isConstantNode)(expr) && (0, _is.typeOf)(expr.value) === 'string') {
123 return _derivTex(parse(expr.value).toString(), x.toString(), 1);
124 } else {
125 return _derivTex(expr.toString(), x.toString(), 1);
126 }
127 },
128 'Node, ConstantNode': function NodeConstantNode(expr, x) {
129 if ((0, _is.typeOf)(x.value) === 'string') {
130 return _derivTex(expr, parse(x.value));
131 } else {
132 throw new Error("The second parameter to 'derivative' is a non-string constant");
133 }
134 },
135 'Node, SymbolNode, ConstantNode': function NodeSymbolNodeConstantNode(expr, x, order) {
136 return _derivTex(expr.toString(), x.name, order.value);
137 },
138 'string, string, number': function stringStringNumber(expr, x, order) {
139 var d;
140
141 if (order === 1) {
142 d = '{d\\over d' + x + '}';
143 } else {
144 d = '{d^{' + order + '}\\over d' + x + '^{' + order + '}}';
145 }
146
147 return d + "\\left[".concat(expr, "\\right]");
148 }
149 });
150 /**
151 * Does a depth-first search on the expression tree to identify what Nodes
152 * are constants (e.g. 2 + 2), and stores the ones that are constants in
153 * constNodes. Classification is done as follows:
154 *
155 * 1. ConstantNodes are constants.
156 * 2. If there exists a SymbolNode, of which we are differentiating over,
157 * in the subtree it is not constant.
158 *
159 * @param {Object} constNodes Holds the nodes that are constant
160 * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
161 * @param {string} varName Variable that we are differentiating
162 * @return {boolean} if node is constant
163 */
164 // TODO: can we rewrite constTag into a pure function?
165
166
167 var constTag = typed('constTag', {
168 'Object, ConstantNode, string': function ObjectConstantNodeString(constNodes, node) {
169 constNodes[node] = true;
170 return true;
171 },
172 'Object, SymbolNode, string': function ObjectSymbolNodeString(constNodes, node, varName) {
173 // Treat other variables like constants. For reasoning, see:
174 // https://en.wikipedia.org/wiki/Partial_derivative
175 if (node.name !== varName) {
176 constNodes[node] = true;
177 return true;
178 }
179
180 return false;
181 },
182 'Object, ParenthesisNode, string': function ObjectParenthesisNodeString(constNodes, node, varName) {
183 return constTag(constNodes, node.content, varName);
184 },
185 'Object, FunctionAssignmentNode, string': function ObjectFunctionAssignmentNodeString(constNodes, node, varName) {
186 if (node.params.indexOf(varName) === -1) {
187 constNodes[node] = true;
188 return true;
189 }
190
191 return constTag(constNodes, node.expr, varName);
192 },
193 'Object, FunctionNode | OperatorNode, string': function ObjectFunctionNodeOperatorNodeString(constNodes, node, varName) {
194 if (node.args.length > 0) {
195 var isConst = constTag(constNodes, node.args[0], varName);
196
197 for (var i = 1; i < node.args.length; ++i) {
198 isConst = constTag(constNodes, node.args[i], varName) && isConst;
199 }
200
201 if (isConst) {
202 constNodes[node] = true;
203 return true;
204 }
205 }
206
207 return false;
208 }
209 });
210 /**
211 * Applies differentiation rules.
212 *
213 * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
214 * @param {Object} constNodes Holds the nodes that are constant
215 * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr`
216 */
217
218 var _derivative = typed('_derivative', {
219 'ConstantNode, Object': function ConstantNodeObject(node) {
220 return createConstantNode(0);
221 },
222 'SymbolNode, Object': function SymbolNodeObject(node, constNodes) {
223 if (constNodes[node] !== undefined) {
224 return createConstantNode(0);
225 }
226
227 return createConstantNode(1);
228 },
229 'ParenthesisNode, Object': function ParenthesisNodeObject(node, constNodes) {
230 return new ParenthesisNode(_derivative(node.content, constNodes));
231 },
232 'FunctionAssignmentNode, Object': function FunctionAssignmentNodeObject(node, constNodes) {
233 if (constNodes[node] !== undefined) {
234 return createConstantNode(0);
235 }
236
237 return _derivative(node.expr, constNodes);
238 },
239 'FunctionNode, Object': function FunctionNodeObject(node, constNodes) {
240 if (node.args.length !== 1) {
241 funcArgsCheck(node);
242 }
243
244 if (constNodes[node] !== undefined) {
245 return createConstantNode(0);
246 }
247
248 var arg0 = node.args[0];
249 var arg1;
250 var div = false; // is output a fraction?
251
252 var negative = false; // is output negative?
253
254 var funcDerivative;
255
256 switch (node.name) {
257 case 'cbrt':
258 // d/dx(cbrt(x)) = 1 / (3x^(2/3))
259 div = true;
260 funcDerivative = new OperatorNode('*', 'multiply', [createConstantNode(3), new OperatorNode('^', 'pow', [arg0, new OperatorNode('/', 'divide', [createConstantNode(2), createConstantNode(3)])])]);
261 break;
262
263 case 'sqrt':
264 case 'nthRoot':
265 // d/dx(sqrt(x)) = 1 / (2*sqrt(x))
266 if (node.args.length === 1) {
267 div = true;
268 funcDerivative = new OperatorNode('*', 'multiply', [createConstantNode(2), new FunctionNode('sqrt', [arg0])]);
269 } else if (node.args.length === 2) {
270 // Rearrange from nthRoot(x, a) -> x^(1/a)
271 arg1 = new OperatorNode('/', 'divide', [createConstantNode(1), node.args[1]]); // Is a variable?
272
273 constNodes[arg1] = constNodes[node.args[1]];
274 return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), constNodes);
275 }
276
277 break;
278
279 case 'log10':
280 arg1 = createConstantNode(10);
281
282 /* fall through! */
283
284 case 'log':
285 if (!arg1 && node.args.length === 1) {
286 // d/dx(log(x)) = 1 / x
287 funcDerivative = arg0.clone();
288 div = true;
289 } else if (node.args.length === 1 && arg1 || node.args.length === 2 && constNodes[node.args[1]] !== undefined) {
290 // d/dx(log(x, c)) = 1 / (x*ln(c))
291 funcDerivative = new OperatorNode('*', 'multiply', [arg0.clone(), new FunctionNode('log', [arg1 || node.args[1]])]);
292 div = true;
293 } else if (node.args.length === 2) {
294 // d/dx(log(f(x), g(x))) = d/dx(log(f(x)) / log(g(x)))
295 return _derivative(new OperatorNode('/', 'divide', [new FunctionNode('log', [arg0]), new FunctionNode('log', [node.args[1]])]), constNodes);
296 }
297
298 break;
299
300 case 'pow':
301 constNodes[arg1] = constNodes[node.args[1]]; // Pass to pow operator node parser
302
303 return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), constNodes);
304
305 case 'exp':
306 // d/dx(e^x) = e^x
307 funcDerivative = new FunctionNode('exp', [arg0.clone()]);
308 break;
309
310 case 'sin':
311 // d/dx(sin(x)) = cos(x)
312 funcDerivative = new FunctionNode('cos', [arg0.clone()]);
313 break;
314
315 case 'cos':
316 // d/dx(cos(x)) = -sin(x)
317 funcDerivative = new OperatorNode('-', 'unaryMinus', [new FunctionNode('sin', [arg0.clone()])]);
318 break;
319
320 case 'tan':
321 // d/dx(tan(x)) = sec(x)^2
322 funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('sec', [arg0.clone()]), createConstantNode(2)]);
323 break;
324
325 case 'sec':
326 // d/dx(sec(x)) = sec(x)tan(x)
327 funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('tan', [arg0.clone()])]);
328 break;
329
330 case 'csc':
331 // d/dx(csc(x)) = -csc(x)cot(x)
332 negative = true;
333 funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('cot', [arg0.clone()])]);
334 break;
335
336 case 'cot':
337 // d/dx(cot(x)) = -csc(x)^2
338 negative = true;
339 funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('csc', [arg0.clone()]), createConstantNode(2)]);
340 break;
341
342 case 'asin':
343 // d/dx(asin(x)) = 1 / sqrt(1 - x^2)
344 div = true;
345 funcDerivative = new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])])]);
346 break;
347
348 case 'acos':
349 // d/dx(acos(x)) = -1 / sqrt(1 - x^2)
350 div = true;
351 negative = true;
352 funcDerivative = new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])])]);
353 break;
354
355 case 'atan':
356 // d/dx(atan(x)) = 1 / (x^2 + 1)
357 div = true;
358 funcDerivative = new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)]);
359 break;
360
361 case 'asec':
362 // d/dx(asec(x)) = 1 / (|x|*sqrt(x^2 - 1))
363 div = true;
364 funcDerivative = new OperatorNode('*', 'multiply', [new FunctionNode('abs', [arg0.clone()]), new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])])]);
365 break;
366
367 case 'acsc':
368 // d/dx(acsc(x)) = -1 / (|x|*sqrt(x^2 - 1))
369 div = true;
370 negative = true;
371 funcDerivative = new OperatorNode('*', 'multiply', [new FunctionNode('abs', [arg0.clone()]), new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])])]);
372 break;
373
374 case 'acot':
375 // d/dx(acot(x)) = -1 / (x^2 + 1)
376 div = true;
377 negative = true;
378 funcDerivative = new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)]);
379 break;
380
381 case 'sinh':
382 // d/dx(sinh(x)) = cosh(x)
383 funcDerivative = new FunctionNode('cosh', [arg0.clone()]);
384 break;
385
386 case 'cosh':
387 // d/dx(cosh(x)) = sinh(x)
388 funcDerivative = new FunctionNode('sinh', [arg0.clone()]);
389 break;
390
391 case 'tanh':
392 // d/dx(tanh(x)) = sech(x)^2
393 funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('sech', [arg0.clone()]), createConstantNode(2)]);
394 break;
395
396 case 'sech':
397 // d/dx(sech(x)) = -sech(x)tanh(x)
398 negative = true;
399 funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('tanh', [arg0.clone()])]);
400 break;
401
402 case 'csch':
403 // d/dx(csch(x)) = -csch(x)coth(x)
404 negative = true;
405 funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('coth', [arg0.clone()])]);
406 break;
407
408 case 'coth':
409 // d/dx(coth(x)) = -csch(x)^2
410 negative = true;
411 funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('csch', [arg0.clone()]), createConstantNode(2)]);
412 break;
413
414 case 'asinh':
415 // d/dx(asinh(x)) = 1 / sqrt(x^2 + 1)
416 div = true;
417 funcDerivative = new FunctionNode('sqrt', [new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])]);
418 break;
419
420 case 'acosh':
421 // d/dx(acosh(x)) = 1 / sqrt(x^2 - 1); XXX potentially only for x >= 1 (the real spectrum)
422 div = true;
423 funcDerivative = new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])]);
424 break;
425
426 case 'atanh':
427 // d/dx(atanh(x)) = 1 / (1 - x^2)
428 div = true;
429 funcDerivative = new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])]);
430 break;
431
432 case 'asech':
433 // d/dx(asech(x)) = -1 / (x*sqrt(1 - x^2))
434 div = true;
435 negative = true;
436 funcDerivative = new OperatorNode('*', 'multiply', [arg0.clone(), new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])])])]);
437 break;
438
439 case 'acsch':
440 // d/dx(acsch(x)) = -1 / (|x|*sqrt(x^2 + 1))
441 div = true;
442 negative = true;
443 funcDerivative = new OperatorNode('*', 'multiply', [new FunctionNode('abs', [arg0.clone()]), new FunctionNode('sqrt', [new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])])]);
444 break;
445
446 case 'acoth':
447 // d/dx(acoth(x)) = -1 / (1 - x^2)
448 div = true;
449 negative = true;
450 funcDerivative = new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])]);
451 break;
452
453 case 'abs':
454 // d/dx(abs(x)) = abs(x)/x
455 funcDerivative = new OperatorNode('/', 'divide', [new FunctionNode(new SymbolNode('abs'), [arg0.clone()]), arg0.clone()]);
456 break;
457
458 case 'gamma': // Needs digamma function, d/dx(gamma(x)) = gamma(x)digamma(x)
459
460 default:
461 throw new Error('Function "' + node.name + '" is not supported by derivative, or a wrong number of arguments is passed');
462 }
463
464 var op, func;
465
466 if (div) {
467 op = '/';
468 func = 'divide';
469 } else {
470 op = '*';
471 func = 'multiply';
472 }
473 /* Apply chain rule to all functions:
474 F(x) = f(g(x))
475 F'(x) = g'(x)*f'(g(x)) */
476
477
478 var chainDerivative = _derivative(arg0, constNodes);
479
480 if (negative) {
481 chainDerivative = new OperatorNode('-', 'unaryMinus', [chainDerivative]);
482 }
483
484 return new OperatorNode(op, func, [chainDerivative, funcDerivative]);
485 },
486 'OperatorNode, Object': function OperatorNodeObject(node, constNodes) {
487 if (constNodes[node] !== undefined) {
488 return createConstantNode(0);
489 }
490
491 if (node.op === '+') {
492 // d/dx(sum(f(x)) = sum(f'(x))
493 return new OperatorNode(node.op, node.fn, node.args.map(function (arg) {
494 return _derivative(arg, constNodes);
495 }));
496 }
497
498 if (node.op === '-') {
499 // d/dx(+/-f(x)) = +/-f'(x)
500 if (node.isUnary()) {
501 return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes)]);
502 } // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x)
503
504
505 if (node.isBinary()) {
506 return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes), _derivative(node.args[1], constNodes)]);
507 }
508 }
509
510 if (node.op === '*') {
511 // d/dx(c*f(x)) = c*f'(x)
512 var constantTerms = node.args.filter(function (arg) {
513 return constNodes[arg] !== undefined;
514 });
515
516 if (constantTerms.length > 0) {
517 var nonConstantTerms = node.args.filter(function (arg) {
518 return constNodes[arg] === undefined;
519 });
520 var nonConstantNode = nonConstantTerms.length === 1 ? nonConstantTerms[0] : new OperatorNode('*', 'multiply', nonConstantTerms);
521 var newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes));
522 return new OperatorNode('*', 'multiply', newArgs);
523 } // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x)
524
525
526 return new OperatorNode('+', 'add', node.args.map(function (argOuter) {
527 return new OperatorNode('*', 'multiply', node.args.map(function (argInner) {
528 return argInner === argOuter ? _derivative(argInner, constNodes) : argInner.clone();
529 }));
530 }));
531 }
532
533 if (node.op === '/' && node.isBinary()) {
534 var arg0 = node.args[0];
535 var arg1 = node.args[1]; // d/dx(f(x) / c) = f'(x) / c
536
537 if (constNodes[arg1] !== undefined) {
538 return new OperatorNode('/', 'divide', [_derivative(arg0, constNodes), arg1]);
539 } // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2)
540
541
542 if (constNodes[arg0] !== undefined) {
543 return new OperatorNode('*', 'multiply', [new OperatorNode('-', 'unaryMinus', [arg0]), new OperatorNode('/', 'divide', [_derivative(arg1, constNodes), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])])]);
544 } // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2
545
546
547 return new OperatorNode('/', 'divide', [new OperatorNode('-', 'subtract', [new OperatorNode('*', 'multiply', [_derivative(arg0, constNodes), arg1.clone()]), new OperatorNode('*', 'multiply', [arg0.clone(), _derivative(arg1, constNodes)])]), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])]);
548 }
549
550 if (node.op === '^' && node.isBinary()) {
551 var _arg = node.args[0];
552 var _arg2 = node.args[1];
553
554 if (constNodes[_arg] !== undefined) {
555 // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1
556 if ((0, _is.isConstantNode)(_arg) && (isZero(_arg.value) || equal(_arg.value, 1))) {
557 return createConstantNode(0);
558 } // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x)
559
560
561 return new OperatorNode('*', 'multiply', [node, new OperatorNode('*', 'multiply', [new FunctionNode('log', [_arg.clone()]), _derivative(_arg2.clone(), constNodes)])]);
562 }
563
564 if (constNodes[_arg2] !== undefined) {
565 if ((0, _is.isConstantNode)(_arg2)) {
566 // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0
567 if (isZero(_arg2.value)) {
568 return createConstantNode(0);
569 } // Ignore exponent; f(x)^1 = f(x)
570
571
572 if (equal(_arg2.value, 1)) {
573 return _derivative(_arg, constNodes);
574 }
575 } // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1)
576
577
578 var powMinusOne = new OperatorNode('^', 'pow', [_arg.clone(), new OperatorNode('-', 'subtract', [_arg2, createConstantNode(1)])]);
579 return new OperatorNode('*', 'multiply', [_arg2.clone(), new OperatorNode('*', 'multiply', [_derivative(_arg, constNodes), powMinusOne])]);
580 } // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)]
581
582
583 return new OperatorNode('*', 'multiply', [new OperatorNode('^', 'pow', [_arg.clone(), _arg2.clone()]), new OperatorNode('+', 'add', [new OperatorNode('*', 'multiply', [_derivative(_arg, constNodes), new OperatorNode('/', 'divide', [_arg2.clone(), _arg.clone()])]), new OperatorNode('*', 'multiply', [_derivative(_arg2, constNodes), new FunctionNode('log', [_arg.clone()])])])]);
584 }
585
586 throw new Error('Operator "' + node.op + '" is not supported by derivative, or a wrong number of arguments is passed');
587 }
588 });
589 /**
590 * Ensures the number of arguments for a function are correct,
591 * and will throw an error otherwise.
592 *
593 * @param {FunctionNode} node
594 */
595
596
597 function funcArgsCheck(node) {
598 // TODO add min, max etc
599 if ((node.name === 'log' || node.name === 'nthRoot' || node.name === 'pow') && node.args.length === 2) {
600 return;
601 } // There should be an incorrect number of arguments if we reach here
602 // Change all args to constants to avoid unidentified
603 // symbol error when compiling function
604
605
606 for (var i = 0; i < node.args.length; ++i) {
607 node.args[i] = createConstantNode(0);
608 }
609
610 node.compile().evaluate();
611 throw new Error('Expected TypeError, but none found');
612 }
613 /**
614 * Helper function to create a constant node with a specific type
615 * (number, BigNumber, Fraction)
616 * @param {number} value
617 * @param {string} [valueType]
618 * @return {ConstantNode}
619 */
620
621
622 function createConstantNode(value, valueType) {
623 return new ConstantNode(numeric(value, valueType || config.number));
624 }
625
626 return derivative;
627});
628exports.createDerivative = createDerivative;
\No newline at end of file