UNPKG

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