1 | import { isConstantNode, typeOf } from '../../utils/is'
|
2 | import { factory } from '../../utils/factory'
|
3 |
|
4 | const name = 'derivative'
|
5 | const dependencies = [
|
6 | 'typed',
|
7 | 'config',
|
8 | 'parse',
|
9 | 'simplify',
|
10 | 'equal',
|
11 | 'isZero',
|
12 | 'numeric',
|
13 | 'ConstantNode',
|
14 | 'FunctionNode',
|
15 | 'OperatorNode',
|
16 | 'ParenthesisNode',
|
17 | 'SymbolNode'
|
18 | ]
|
19 |
|
20 | export const createDerivative = factory(name, dependencies, ({
|
21 | typed,
|
22 | config,
|
23 | parse,
|
24 | simplify,
|
25 | equal,
|
26 | isZero,
|
27 | numeric,
|
28 | ConstantNode,
|
29 | FunctionNode,
|
30 | OperatorNode,
|
31 | ParenthesisNode,
|
32 | SymbolNode
|
33 | }) => {
|
34 | |
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | const derivative = typed('derivative', {
|
73 | 'Node, SymbolNode, Object': function (expr, variable, options) {
|
74 | const constNodes = {}
|
75 | constTag(constNodes, expr, variable.name)
|
76 | const res = _derivative(expr, constNodes)
|
77 | return options.simplify ? simplify(res) : res
|
78 | },
|
79 | 'Node, SymbolNode': function (expr, variable) {
|
80 | return derivative(expr, variable, { simplify: true })
|
81 | },
|
82 |
|
83 | 'string, SymbolNode': function (expr, variable) {
|
84 | return derivative(parse(expr), variable)
|
85 | },
|
86 | 'string, SymbolNode, Object': function (expr, variable, options) {
|
87 | return derivative(parse(expr), variable, options)
|
88 | },
|
89 |
|
90 | 'string, string': function (expr, variable) {
|
91 | return derivative(parse(expr), parse(variable))
|
92 | },
|
93 | 'string, string, Object': function (expr, variable, options) {
|
94 | return derivative(parse(expr), parse(variable), options)
|
95 | },
|
96 |
|
97 | 'Node, string': function (expr, variable) {
|
98 | return derivative(expr, parse(variable))
|
99 | },
|
100 | 'Node, string, Object': function (expr, variable, options) {
|
101 | return derivative(expr, parse(variable), options)
|
102 | }
|
103 |
|
104 |
|
105 |
|
106 | |
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | })
|
118 |
|
119 | derivative._simplify = true
|
120 |
|
121 | derivative.toTex = function (deriv) {
|
122 | return _derivTex.apply(null, deriv.args)
|
123 | }
|
124 |
|
125 |
|
126 |
|
127 | const _derivTex = typed('_derivTex', {
|
128 | 'Node, SymbolNode': function (expr, x) {
|
129 | if (isConstantNode(expr) && typeOf(expr.value) === 'string') {
|
130 | return _derivTex(parse(expr.value).toString(), x.toString(), 1)
|
131 | } else {
|
132 | return _derivTex(expr.toString(), x.toString(), 1)
|
133 | }
|
134 | },
|
135 | 'Node, ConstantNode': function (expr, x) {
|
136 | if (typeOf(x.value) === 'string') {
|
137 | return _derivTex(expr, parse(x.value))
|
138 | } else {
|
139 | throw new Error("The second parameter to 'derivative' is a non-string constant")
|
140 | }
|
141 | },
|
142 | 'Node, SymbolNode, ConstantNode': function (expr, x, order) {
|
143 | return _derivTex(expr.toString(), x.name, order.value)
|
144 | },
|
145 | 'string, string, number': function (expr, x, order) {
|
146 | let d
|
147 | if (order === 1) {
|
148 | d = '{d\\over d' + x + '}'
|
149 | } else {
|
150 | d = '{d^{' + order + '}\\over d' + x + '^{' + order + '}}'
|
151 | }
|
152 | return d + `\\left[${expr}\\right]`
|
153 | }
|
154 | })
|
155 |
|
156 | |
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 | const constTag = typed('constTag', {
|
172 | 'Object, ConstantNode, string': function (constNodes, node) {
|
173 | constNodes[node] = true
|
174 | return true
|
175 | },
|
176 |
|
177 | 'Object, SymbolNode, string': function (constNodes, node, varName) {
|
178 |
|
179 |
|
180 | if (node.name !== varName) {
|
181 | constNodes[node] = true
|
182 | return true
|
183 | }
|
184 | return false
|
185 | },
|
186 |
|
187 | 'Object, ParenthesisNode, string': function (constNodes, node, varName) {
|
188 | return constTag(constNodes, node.content, varName)
|
189 | },
|
190 |
|
191 | 'Object, FunctionAssignmentNode, string': function (constNodes, node, varName) {
|
192 | if (node.params.indexOf(varName) === -1) {
|
193 | constNodes[node] = true
|
194 | return true
|
195 | }
|
196 | return constTag(constNodes, node.expr, varName)
|
197 | },
|
198 |
|
199 | 'Object, FunctionNode | OperatorNode, string': function (constNodes, node, varName) {
|
200 | if (node.args.length > 0) {
|
201 | let isConst = constTag(constNodes, node.args[0], varName)
|
202 | for (let i = 1; i < node.args.length; ++i) {
|
203 | isConst = constTag(constNodes, node.args[i], varName) && isConst
|
204 | }
|
205 |
|
206 | if (isConst) {
|
207 | constNodes[node] = true
|
208 | return true
|
209 | }
|
210 | }
|
211 | return false
|
212 | }
|
213 | })
|
214 |
|
215 | |
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 | const _derivative = typed('_derivative', {
|
223 | 'ConstantNode, Object': function (node) {
|
224 | return createConstantNode(0)
|
225 | },
|
226 |
|
227 | 'SymbolNode, Object': function (node, constNodes) {
|
228 | if (constNodes[node] !== undefined) {
|
229 | return createConstantNode(0)
|
230 | }
|
231 | return createConstantNode(1)
|
232 | },
|
233 |
|
234 | 'ParenthesisNode, Object': function (node, constNodes) {
|
235 | return new ParenthesisNode(_derivative(node.content, constNodes))
|
236 | },
|
237 |
|
238 | 'FunctionAssignmentNode, Object': function (node, constNodes) {
|
239 | if (constNodes[node] !== undefined) {
|
240 | return createConstantNode(0)
|
241 | }
|
242 | return _derivative(node.expr, constNodes)
|
243 | },
|
244 |
|
245 | 'FunctionNode, Object': function (node, constNodes) {
|
246 | if (node.args.length !== 1) {
|
247 | funcArgsCheck(node)
|
248 | }
|
249 |
|
250 | if (constNodes[node] !== undefined) {
|
251 | return createConstantNode(0)
|
252 | }
|
253 |
|
254 | const arg0 = node.args[0]
|
255 | let arg1
|
256 |
|
257 | let div = false
|
258 | let negative = false
|
259 |
|
260 | let funcDerivative
|
261 | switch (node.name) {
|
262 | case 'cbrt':
|
263 |
|
264 | div = true
|
265 | funcDerivative = new OperatorNode('*', 'multiply', [
|
266 | createConstantNode(3),
|
267 | new OperatorNode('^', 'pow', [
|
268 | arg0,
|
269 | new OperatorNode('/', 'divide', [
|
270 | createConstantNode(2),
|
271 | createConstantNode(3)
|
272 | ])
|
273 | ])
|
274 | ])
|
275 | break
|
276 | case 'sqrt':
|
277 | case 'nthRoot':
|
278 |
|
279 | if (node.args.length === 1) {
|
280 | div = true
|
281 | funcDerivative = new OperatorNode('*', 'multiply', [
|
282 | createConstantNode(2),
|
283 | new FunctionNode('sqrt', [arg0])
|
284 | ])
|
285 | } else if (node.args.length === 2) {
|
286 |
|
287 | arg1 = new OperatorNode('/', 'divide', [
|
288 | createConstantNode(1),
|
289 | node.args[1]
|
290 | ])
|
291 |
|
292 |
|
293 | constNodes[arg1] = constNodes[node.args[1]]
|
294 |
|
295 | return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), constNodes)
|
296 | }
|
297 | break
|
298 | case 'log10':
|
299 | arg1 = createConstantNode(10)
|
300 |
|
301 | case 'log':
|
302 | if (!arg1 && node.args.length === 1) {
|
303 |
|
304 | funcDerivative = arg0.clone()
|
305 | div = true
|
306 | } else if ((node.args.length === 1 && arg1) ||
|
307 | (node.args.length === 2 && constNodes[node.args[1]] !== undefined)) {
|
308 |
|
309 | funcDerivative = new OperatorNode('*', 'multiply', [
|
310 | arg0.clone(),
|
311 | new FunctionNode('log', [arg1 || node.args[1]])
|
312 | ])
|
313 | div = true
|
314 | } else if (node.args.length === 2) {
|
315 |
|
316 | return _derivative(new OperatorNode('/', 'divide', [
|
317 | new FunctionNode('log', [arg0]),
|
318 | new FunctionNode('log', [node.args[1]])
|
319 | ]), constNodes)
|
320 | }
|
321 | break
|
322 | case 'pow':
|
323 | constNodes[arg1] = constNodes[node.args[1]]
|
324 |
|
325 | return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), constNodes)
|
326 | case 'exp':
|
327 |
|
328 | funcDerivative = new FunctionNode('exp', [arg0.clone()])
|
329 | break
|
330 | case 'sin':
|
331 |
|
332 | funcDerivative = new FunctionNode('cos', [arg0.clone()])
|
333 | break
|
334 | case 'cos':
|
335 |
|
336 | funcDerivative = new OperatorNode('-', 'unaryMinus', [
|
337 | new FunctionNode('sin', [arg0.clone()])
|
338 | ])
|
339 | break
|
340 | case 'tan':
|
341 |
|
342 | funcDerivative = new OperatorNode('^', 'pow', [
|
343 | new FunctionNode('sec', [arg0.clone()]),
|
344 | createConstantNode(2)
|
345 | ])
|
346 | break
|
347 | case 'sec':
|
348 |
|
349 | funcDerivative = new OperatorNode('*', 'multiply', [
|
350 | node,
|
351 | new FunctionNode('tan', [arg0.clone()])
|
352 | ])
|
353 | break
|
354 | case 'csc':
|
355 |
|
356 | negative = true
|
357 | funcDerivative = new OperatorNode('*', 'multiply', [
|
358 | node,
|
359 | new FunctionNode('cot', [arg0.clone()])
|
360 | ])
|
361 | break
|
362 | case 'cot':
|
363 |
|
364 | negative = true
|
365 | funcDerivative = new OperatorNode('^', 'pow', [
|
366 | new FunctionNode('csc', [arg0.clone()]),
|
367 | createConstantNode(2)
|
368 | ])
|
369 | break
|
370 | case 'asin':
|
371 |
|
372 | div = true
|
373 | funcDerivative = new FunctionNode('sqrt', [
|
374 | new OperatorNode('-', 'subtract', [
|
375 | createConstantNode(1),
|
376 | new OperatorNode('^', 'pow', [
|
377 | arg0.clone(),
|
378 | createConstantNode(2)
|
379 | ])
|
380 | ])
|
381 | ])
|
382 | break
|
383 | case 'acos':
|
384 |
|
385 | div = true
|
386 | negative = true
|
387 | funcDerivative = new FunctionNode('sqrt', [
|
388 | new OperatorNode('-', 'subtract', [
|
389 | createConstantNode(1),
|
390 | new OperatorNode('^', 'pow', [
|
391 | arg0.clone(),
|
392 | createConstantNode(2)
|
393 | ])
|
394 | ])
|
395 | ])
|
396 | break
|
397 | case 'atan':
|
398 |
|
399 | div = true
|
400 | funcDerivative = new OperatorNode('+', 'add', [
|
401 | new OperatorNode('^', 'pow', [
|
402 | arg0.clone(),
|
403 | createConstantNode(2)
|
404 | ]),
|
405 | createConstantNode(1)
|
406 | ])
|
407 | break
|
408 | case 'asec':
|
409 |
|
410 | div = true
|
411 | funcDerivative = new OperatorNode('*', 'multiply', [
|
412 | new FunctionNode('abs', [arg0.clone()]),
|
413 | new FunctionNode('sqrt', [
|
414 | new OperatorNode('-', 'subtract', [
|
415 | new OperatorNode('^', 'pow', [
|
416 | arg0.clone(),
|
417 | createConstantNode(2)
|
418 | ]),
|
419 | createConstantNode(1)
|
420 | ])
|
421 | ])
|
422 | ])
|
423 | break
|
424 | case 'acsc':
|
425 |
|
426 | div = true
|
427 | negative = true
|
428 | funcDerivative = new OperatorNode('*', 'multiply', [
|
429 | new FunctionNode('abs', [arg0.clone()]),
|
430 | new FunctionNode('sqrt', [
|
431 | new OperatorNode('-', 'subtract', [
|
432 | new OperatorNode('^', 'pow', [
|
433 | arg0.clone(),
|
434 | createConstantNode(2)
|
435 | ]),
|
436 | createConstantNode(1)
|
437 | ])
|
438 | ])
|
439 | ])
|
440 | break
|
441 | case 'acot':
|
442 |
|
443 | div = true
|
444 | negative = true
|
445 | funcDerivative = new OperatorNode('+', 'add', [
|
446 | new OperatorNode('^', 'pow', [
|
447 | arg0.clone(),
|
448 | createConstantNode(2)
|
449 | ]),
|
450 | createConstantNode(1)
|
451 | ])
|
452 | break
|
453 | case 'sinh':
|
454 |
|
455 | funcDerivative = new FunctionNode('cosh', [arg0.clone()])
|
456 | break
|
457 | case 'cosh':
|
458 |
|
459 | funcDerivative = new FunctionNode('sinh', [arg0.clone()])
|
460 | break
|
461 | case 'tanh':
|
462 |
|
463 | funcDerivative = new OperatorNode('^', 'pow', [
|
464 | new FunctionNode('sech', [arg0.clone()]),
|
465 | createConstantNode(2)
|
466 | ])
|
467 | break
|
468 | case 'sech':
|
469 |
|
470 | negative = true
|
471 | funcDerivative = new OperatorNode('*', 'multiply', [
|
472 | node,
|
473 | new FunctionNode('tanh', [arg0.clone()])
|
474 | ])
|
475 | break
|
476 | case 'csch':
|
477 |
|
478 | negative = true
|
479 | funcDerivative = new OperatorNode('*', 'multiply', [
|
480 | node,
|
481 | new FunctionNode('coth', [arg0.clone()])
|
482 | ])
|
483 | break
|
484 | case 'coth':
|
485 |
|
486 | negative = true
|
487 | funcDerivative = new OperatorNode('^', 'pow', [
|
488 | new FunctionNode('csch', [arg0.clone()]),
|
489 | createConstantNode(2)
|
490 | ])
|
491 | break
|
492 | case 'asinh':
|
493 |
|
494 | div = true
|
495 | funcDerivative = new FunctionNode('sqrt', [
|
496 | new OperatorNode('+', 'add', [
|
497 | new OperatorNode('^', 'pow', [
|
498 | arg0.clone(),
|
499 | createConstantNode(2)
|
500 | ]),
|
501 | createConstantNode(1)
|
502 | ])
|
503 | ])
|
504 | break
|
505 | case 'acosh':
|
506 |
|
507 | div = true
|
508 | funcDerivative = new FunctionNode('sqrt', [
|
509 | new OperatorNode('-', 'subtract', [
|
510 | new OperatorNode('^', 'pow', [
|
511 | arg0.clone(),
|
512 | createConstantNode(2)
|
513 | ]),
|
514 | createConstantNode(1)
|
515 | ])
|
516 | ])
|
517 | break
|
518 | case 'atanh':
|
519 |
|
520 | div = true
|
521 | funcDerivative = new OperatorNode('-', 'subtract', [
|
522 | createConstantNode(1),
|
523 | new OperatorNode('^', 'pow', [
|
524 | arg0.clone(),
|
525 | createConstantNode(2)
|
526 | ])
|
527 | ])
|
528 | break
|
529 | case 'asech':
|
530 |
|
531 | div = true
|
532 | negative = true
|
533 | funcDerivative = new OperatorNode('*', 'multiply', [
|
534 | arg0.clone(),
|
535 | new FunctionNode('sqrt', [
|
536 | new OperatorNode('-', 'subtract', [
|
537 | createConstantNode(1),
|
538 | new OperatorNode('^', 'pow', [
|
539 | arg0.clone(),
|
540 | createConstantNode(2)
|
541 | ])
|
542 | ])
|
543 | ])
|
544 | ])
|
545 | break
|
546 | case 'acsch':
|
547 |
|
548 | div = true
|
549 | negative = true
|
550 | funcDerivative = new OperatorNode('*', 'multiply', [
|
551 | new FunctionNode('abs', [arg0.clone()]),
|
552 | new FunctionNode('sqrt', [
|
553 | new OperatorNode('+', 'add', [
|
554 | new OperatorNode('^', 'pow', [
|
555 | arg0.clone(),
|
556 | createConstantNode(2)
|
557 | ]),
|
558 | createConstantNode(1)
|
559 | ])
|
560 | ])
|
561 | ])
|
562 | break
|
563 | case 'acoth':
|
564 |
|
565 | div = true
|
566 | negative = true
|
567 | funcDerivative = new OperatorNode('-', 'subtract', [
|
568 | createConstantNode(1),
|
569 | new OperatorNode('^', 'pow', [
|
570 | arg0.clone(),
|
571 | createConstantNode(2)
|
572 | ])
|
573 | ])
|
574 | break
|
575 | case 'abs':
|
576 |
|
577 | funcDerivative = new OperatorNode('/', 'divide', [
|
578 | new FunctionNode(new SymbolNode('abs'), [arg0.clone()]),
|
579 | arg0.clone()
|
580 | ])
|
581 | break
|
582 | case 'gamma':
|
583 | default: throw new Error('Function "' + node.name + '" is not supported by derivative, or a wrong number of arguments is passed')
|
584 | }
|
585 |
|
586 | let op, func
|
587 | if (div) {
|
588 | op = '/'
|
589 | func = 'divide'
|
590 | } else {
|
591 | op = '*'
|
592 | func = 'multiply'
|
593 | }
|
594 |
|
595 | |
596 |
|
597 |
|
598 | let chainDerivative = _derivative(arg0, constNodes)
|
599 | if (negative) {
|
600 | chainDerivative = new OperatorNode('-', 'unaryMinus', [chainDerivative])
|
601 | }
|
602 | return new OperatorNode(op, func, [chainDerivative, funcDerivative])
|
603 | },
|
604 |
|
605 | 'OperatorNode, Object': function (node, constNodes) {
|
606 | if (constNodes[node] !== undefined) {
|
607 | return createConstantNode(0)
|
608 | }
|
609 |
|
610 | if (node.op === '+') {
|
611 |
|
612 | return new OperatorNode(node.op, node.fn, node.args.map(function (arg) {
|
613 | return _derivative(arg, constNodes)
|
614 | }))
|
615 | }
|
616 |
|
617 | if (node.op === '-') {
|
618 |
|
619 | if (node.isUnary()) {
|
620 | return new OperatorNode(node.op, node.fn, [
|
621 | _derivative(node.args[0], constNodes)
|
622 | ])
|
623 | }
|
624 |
|
625 |
|
626 | if (node.isBinary()) {
|
627 | return new OperatorNode(node.op, node.fn, [
|
628 | _derivative(node.args[0], constNodes),
|
629 | _derivative(node.args[1], constNodes)
|
630 | ])
|
631 | }
|
632 | }
|
633 |
|
634 | if (node.op === '*') {
|
635 |
|
636 | const constantTerms = node.args.filter(function (arg) {
|
637 | return constNodes[arg] !== undefined
|
638 | })
|
639 |
|
640 | if (constantTerms.length > 0) {
|
641 | const nonConstantTerms = node.args.filter(function (arg) {
|
642 | return constNodes[arg] === undefined
|
643 | })
|
644 |
|
645 | const nonConstantNode = nonConstantTerms.length === 1
|
646 | ? nonConstantTerms[0]
|
647 | : new OperatorNode('*', 'multiply', nonConstantTerms)
|
648 |
|
649 | const newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes))
|
650 |
|
651 | return new OperatorNode('*', 'multiply', newArgs)
|
652 | }
|
653 |
|
654 |
|
655 | return new OperatorNode('+', 'add', node.args.map(function (argOuter) {
|
656 | return new OperatorNode('*', 'multiply', node.args.map(function (argInner) {
|
657 | return (argInner === argOuter)
|
658 | ? _derivative(argInner, constNodes)
|
659 | : argInner.clone()
|
660 | }))
|
661 | }))
|
662 | }
|
663 |
|
664 | if (node.op === '/' && node.isBinary()) {
|
665 | const arg0 = node.args[0]
|
666 | const arg1 = node.args[1]
|
667 |
|
668 |
|
669 | if (constNodes[arg1] !== undefined) {
|
670 | return new OperatorNode('/', 'divide', [_derivative(arg0, constNodes), arg1])
|
671 | }
|
672 |
|
673 |
|
674 | if (constNodes[arg0] !== undefined) {
|
675 | return new OperatorNode('*', 'multiply', [
|
676 | new OperatorNode('-', 'unaryMinus', [arg0]),
|
677 | new OperatorNode('/', 'divide', [
|
678 | _derivative(arg1, constNodes),
|
679 | new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])
|
680 | ])
|
681 | ])
|
682 | }
|
683 |
|
684 |
|
685 | return new OperatorNode('/', 'divide', [
|
686 | new OperatorNode('-', 'subtract', [
|
687 | new OperatorNode('*', 'multiply', [_derivative(arg0, constNodes), arg1.clone()]),
|
688 | new OperatorNode('*', 'multiply', [arg0.clone(), _derivative(arg1, constNodes)])
|
689 | ]),
|
690 | new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])
|
691 | ])
|
692 | }
|
693 |
|
694 | if (node.op === '^' && node.isBinary()) {
|
695 | const arg0 = node.args[0]
|
696 | const arg1 = node.args[1]
|
697 |
|
698 | if (constNodes[arg0] !== undefined) {
|
699 |
|
700 | if (isConstantNode(arg0) && (isZero(arg0.value) || equal(arg0.value, 1))) {
|
701 | return createConstantNode(0)
|
702 | }
|
703 |
|
704 |
|
705 | return new OperatorNode('*', 'multiply', [
|
706 | node,
|
707 | new OperatorNode('*', 'multiply', [
|
708 | new FunctionNode('log', [arg0.clone()]),
|
709 | _derivative(arg1.clone(), constNodes)
|
710 | ])
|
711 | ])
|
712 | }
|
713 |
|
714 | if (constNodes[arg1] !== undefined) {
|
715 | if (isConstantNode(arg1)) {
|
716 |
|
717 | if (isZero(arg1.value)) {
|
718 | return createConstantNode(0)
|
719 | }
|
720 |
|
721 | if (equal(arg1.value, 1)) {
|
722 | return _derivative(arg0, constNodes)
|
723 | }
|
724 | }
|
725 |
|
726 |
|
727 | const powMinusOne = new OperatorNode('^', 'pow', [
|
728 | arg0.clone(),
|
729 | new OperatorNode('-', 'subtract', [
|
730 | arg1,
|
731 | createConstantNode(1)
|
732 | ])
|
733 | ])
|
734 |
|
735 | return new OperatorNode('*', 'multiply', [
|
736 | arg1.clone(),
|
737 | new OperatorNode('*', 'multiply', [
|
738 | _derivative(arg0, constNodes),
|
739 | powMinusOne
|
740 | ])
|
741 | ])
|
742 | }
|
743 |
|
744 |
|
745 | return new OperatorNode('*', 'multiply', [
|
746 | new OperatorNode('^', 'pow', [arg0.clone(), arg1.clone()]),
|
747 | new OperatorNode('+', 'add', [
|
748 | new OperatorNode('*', 'multiply', [
|
749 | _derivative(arg0, constNodes),
|
750 | new OperatorNode('/', 'divide', [arg1.clone(), arg0.clone()])
|
751 | ]),
|
752 | new OperatorNode('*', 'multiply', [
|
753 | _derivative(arg1, constNodes),
|
754 | new FunctionNode('log', [arg0.clone()])
|
755 | ])
|
756 | ])
|
757 | ])
|
758 | }
|
759 |
|
760 | throw new Error('Operator "' + node.op + '" is not supported by derivative, or a wrong number of arguments is passed')
|
761 | }
|
762 | })
|
763 |
|
764 | |
765 |
|
766 |
|
767 |
|
768 |
|
769 |
|
770 | function funcArgsCheck (node) {
|
771 |
|
772 | if ((node.name === 'log' || node.name === 'nthRoot' || node.name === 'pow') && node.args.length === 2) {
|
773 | return
|
774 | }
|
775 |
|
776 |
|
777 |
|
778 |
|
779 |
|
780 | for (let i = 0; i < node.args.length; ++i) {
|
781 | node.args[i] = createConstantNode(0)
|
782 | }
|
783 |
|
784 | node.compile().evaluate()
|
785 | throw new Error('Expected TypeError, but none found')
|
786 | }
|
787 |
|
788 | |
789 |
|
790 |
|
791 |
|
792 |
|
793 |
|
794 |
|
795 | function createConstantNode (value, valueType) {
|
796 | return new ConstantNode(numeric(value, valueType || config.number))
|
797 | }
|
798 |
|
799 | return derivative
|
800 | })
|