derivative.js 24 KB

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