mathjs 14.0.0 → 14.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -66,9 +66,18 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
66
66
  let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
67
67
  simplify: true
68
68
  };
69
- const constNodes = {};
70
- constTag(constNodes, expr, variable.name);
71
- const res = _derivative(expr, constNodes);
69
+ const cache = new Map();
70
+ const variableName = variable.name;
71
+ function isConstCached(node) {
72
+ const cached = cache.get(node);
73
+ if (cached !== undefined) {
74
+ return cached;
75
+ }
76
+ const res = _isConst(isConstCached, node, variableName);
77
+ cache.set(node, res);
78
+ return res;
79
+ }
80
+ const res = _derivative(expr, isConstCached);
72
81
  return options.simplify ? simplify(res) : res;
73
82
  }
74
83
  function parseIdentifier(string) {
@@ -88,9 +97,8 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
88
97
  'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) {
89
98
  let res = expr
90
99
  for (let i = 0; i < order; i++) {
91
- let constNodes = {}
92
- constTag(constNodes, expr, variable.name)
93
- res = _derivative(res, constNodes)
100
+ <create caching isConst>
101
+ res = _derivative(res, isConst)
94
102
  }
95
103
  return res
96
104
  }
@@ -133,56 +141,39 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
133
141
  });
134
142
 
135
143
  /**
136
- * Does a depth-first search on the expression tree to identify what Nodes
137
- * are constants (e.g. 2 + 2), and stores the ones that are constants in
138
- * constNodes. Classification is done as follows:
144
+ * Checks if a node is constants (e.g. 2 + 2).
145
+ * Accepts (usually memoized) version of self as the first parameter for recursive calls.
146
+ * Classification is done as follows:
139
147
  *
140
148
  * 1. ConstantNodes are constants.
141
149
  * 2. If there exists a SymbolNode, of which we are differentiating over,
142
150
  * in the subtree it is not constant.
143
151
  *
144
- * @param {Object} constNodes Holds the nodes that are constant
152
+ * @param {function} isConst Function that tells whether sub-expression is a constant
145
153
  * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
146
154
  * @param {string} varName Variable that we are differentiating
147
155
  * @return {boolean} if node is constant
148
156
  */
149
- // TODO: can we rewrite constTag into a pure function?
150
- const constTag = typed('constTag', {
151
- 'Object, ConstantNode, string': function (constNodes, node) {
152
- constNodes[node] = true;
157
+ const _isConst = typed('_isConst', {
158
+ 'function, ConstantNode, string': function () {
153
159
  return true;
154
160
  },
155
- 'Object, SymbolNode, string': function (constNodes, node, varName) {
161
+ 'function, SymbolNode, string': function (isConst, node, varName) {
156
162
  // Treat other variables like constants. For reasoning, see:
157
163
  // https://en.wikipedia.org/wiki/Partial_derivative
158
- if (node.name !== varName) {
159
- constNodes[node] = true;
160
- return true;
161
- }
162
- return false;
164
+ return node.name !== varName;
163
165
  },
164
- 'Object, ParenthesisNode, string': function (constNodes, node, varName) {
165
- return constTag(constNodes, node.content, varName);
166
+ 'function, ParenthesisNode, string': function (isConst, node, varName) {
167
+ return isConst(node.content, varName);
166
168
  },
167
- 'Object, FunctionAssignmentNode, string': function (constNodes, node, varName) {
169
+ 'function, FunctionAssignmentNode, string': function (isConst, node, varName) {
168
170
  if (!node.params.includes(varName)) {
169
- constNodes[node] = true;
170
171
  return true;
171
172
  }
172
- return constTag(constNodes, node.expr, varName);
173
+ return isConst(node.expr, varName);
173
174
  },
174
- 'Object, FunctionNode | OperatorNode, string': function (constNodes, node, varName) {
175
- if (node.args.length > 0) {
176
- let isConst = constTag(constNodes, node.args[0], varName);
177
- for (let i = 1; i < node.args.length; ++i) {
178
- isConst = constTag(constNodes, node.args[i], varName) && isConst;
179
- }
180
- if (isConst) {
181
- constNodes[node] = true;
182
- return true;
183
- }
184
- }
185
- return false;
175
+ 'function, FunctionNode | OperatorNode, string': function (isConst, node, varName) {
176
+ return node.args.every(arg => isConst(arg, varName));
186
177
  }
187
178
  });
188
179
 
@@ -190,30 +181,30 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
190
181
  * Applies differentiation rules.
191
182
  *
192
183
  * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
193
- * @param {Object} constNodes Holds the nodes that are constant
184
+ * @param {function} isConst Function that tells if a node is constant
194
185
  * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr`
195
186
  */
196
187
  const _derivative = typed('_derivative', {
197
- 'ConstantNode, Object': function (node) {
188
+ 'ConstantNode, function': function () {
198
189
  return createConstantNode(0);
199
190
  },
200
- 'SymbolNode, Object': function (node, constNodes) {
201
- if (constNodes[node] !== undefined) {
191
+ 'SymbolNode, function': function (node, isConst) {
192
+ if (isConst(node)) {
202
193
  return createConstantNode(0);
203
194
  }
204
195
  return createConstantNode(1);
205
196
  },
206
- 'ParenthesisNode, Object': function (node, constNodes) {
207
- return new ParenthesisNode(_derivative(node.content, constNodes));
197
+ 'ParenthesisNode, function': function (node, isConst) {
198
+ return new ParenthesisNode(_derivative(node.content, isConst));
208
199
  },
209
- 'FunctionAssignmentNode, Object': function (node, constNodes) {
210
- if (constNodes[node] !== undefined) {
200
+ 'FunctionAssignmentNode, function': function (node, isConst) {
201
+ if (isConst(node)) {
211
202
  return createConstantNode(0);
212
203
  }
213
- return _derivative(node.expr, constNodes);
204
+ return _derivative(node.expr, isConst);
214
205
  },
215
- 'FunctionNode, Object': function (node, constNodes) {
216
- if (constNodes[node] !== undefined) {
206
+ 'FunctionNode, function': function (node, isConst) {
207
+ if (isConst(node)) {
217
208
  return createConstantNode(0);
218
209
  }
219
210
  const arg0 = node.args[0];
@@ -237,10 +228,7 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
237
228
  } else if (node.args.length === 2) {
238
229
  // Rearrange from nthRoot(x, a) -> x^(1/a)
239
230
  arg1 = new OperatorNode('/', 'divide', [createConstantNode(1), node.args[1]]);
240
-
241
- // Is a variable?
242
- constNodes[arg1] = constNodes[node.args[1]];
243
- return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), constNodes);
231
+ return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), isConst);
244
232
  }
245
233
  break;
246
234
  case 'log10':
@@ -251,20 +239,19 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
251
239
  // d/dx(log(x)) = 1 / x
252
240
  funcDerivative = arg0.clone();
253
241
  div = true;
254
- } else if (node.args.length === 1 && arg1 || node.args.length === 2 && constNodes[node.args[1]] !== undefined) {
242
+ } else if (node.args.length === 1 && arg1 || node.args.length === 2 && isConst(node.args[1])) {
255
243
  // d/dx(log(x, c)) = 1 / (x*ln(c))
256
244
  funcDerivative = new OperatorNode('*', 'multiply', [arg0.clone(), new FunctionNode('log', [arg1 || node.args[1]])]);
257
245
  div = true;
258
246
  } else if (node.args.length === 2) {
259
247
  // d/dx(log(f(x), g(x))) = d/dx(log(f(x)) / log(g(x)))
260
- return _derivative(new OperatorNode('/', 'divide', [new FunctionNode('log', [arg0]), new FunctionNode('log', [node.args[1]])]), constNodes);
248
+ return _derivative(new OperatorNode('/', 'divide', [new FunctionNode('log', [arg0]), new FunctionNode('log', [node.args[1]])]), isConst);
261
249
  }
262
250
  break;
263
251
  case 'pow':
264
252
  if (node.args.length === 2) {
265
- constNodes[arg1] = constNodes[node.args[1]];
266
253
  // Pass to pow operator node parser
267
- return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), constNodes);
254
+ return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), isConst);
268
255
  }
269
256
  break;
270
257
  case 'exp':
@@ -410,51 +397,51 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
410
397
  /* Apply chain rule to all functions:
411
398
  F(x) = f(g(x))
412
399
  F'(x) = g'(x)*f'(g(x)) */
413
- let chainDerivative = _derivative(arg0, constNodes);
400
+ let chainDerivative = _derivative(arg0, isConst);
414
401
  if (negative) {
415
402
  chainDerivative = new OperatorNode('-', 'unaryMinus', [chainDerivative]);
416
403
  }
417
404
  return new OperatorNode(op, func, [chainDerivative, funcDerivative]);
418
405
  },
419
- 'OperatorNode, Object': function (node, constNodes) {
420
- if (constNodes[node] !== undefined) {
406
+ 'OperatorNode, function': function (node, isConst) {
407
+ if (isConst(node)) {
421
408
  return createConstantNode(0);
422
409
  }
423
410
  if (node.op === '+') {
424
411
  // d/dx(sum(f(x)) = sum(f'(x))
425
412
  return new OperatorNode(node.op, node.fn, node.args.map(function (arg) {
426
- return _derivative(arg, constNodes);
413
+ return _derivative(arg, isConst);
427
414
  }));
428
415
  }
429
416
  if (node.op === '-') {
430
417
  // d/dx(+/-f(x)) = +/-f'(x)
431
418
  if (node.isUnary()) {
432
- return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes)]);
419
+ return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], isConst)]);
433
420
  }
434
421
 
435
422
  // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x)
436
423
  if (node.isBinary()) {
437
- return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes), _derivative(node.args[1], constNodes)]);
424
+ return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], isConst), _derivative(node.args[1], isConst)]);
438
425
  }
439
426
  }
440
427
  if (node.op === '*') {
441
428
  // d/dx(c*f(x)) = c*f'(x)
442
429
  const constantTerms = node.args.filter(function (arg) {
443
- return constNodes[arg] !== undefined;
430
+ return isConst(arg);
444
431
  });
445
432
  if (constantTerms.length > 0) {
446
433
  const nonConstantTerms = node.args.filter(function (arg) {
447
- return constNodes[arg] === undefined;
434
+ return !isConst(arg);
448
435
  });
449
436
  const nonConstantNode = nonConstantTerms.length === 1 ? nonConstantTerms[0] : new OperatorNode('*', 'multiply', nonConstantTerms);
450
- const newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes));
437
+ const newArgs = constantTerms.concat(_derivative(nonConstantNode, isConst));
451
438
  return new OperatorNode('*', 'multiply', newArgs);
452
439
  }
453
440
 
454
441
  // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x)
455
442
  return new OperatorNode('+', 'add', node.args.map(function (argOuter) {
456
443
  return new OperatorNode('*', 'multiply', node.args.map(function (argInner) {
457
- return argInner === argOuter ? _derivative(argInner, constNodes) : argInner.clone();
444
+ return argInner === argOuter ? _derivative(argInner, isConst) : argInner.clone();
458
445
  }));
459
446
  }));
460
447
  }
@@ -463,31 +450,31 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
463
450
  const arg1 = node.args[1];
464
451
 
465
452
  // d/dx(f(x) / c) = f'(x) / c
466
- if (constNodes[arg1] !== undefined) {
467
- return new OperatorNode('/', 'divide', [_derivative(arg0, constNodes), arg1]);
453
+ if (isConst(arg1)) {
454
+ return new OperatorNode('/', 'divide', [_derivative(arg0, isConst), arg1]);
468
455
  }
469
456
 
470
457
  // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2)
471
- if (constNodes[arg0] !== undefined) {
472
- return new OperatorNode('*', 'multiply', [new OperatorNode('-', 'unaryMinus', [arg0]), new OperatorNode('/', 'divide', [_derivative(arg1, constNodes), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])])]);
458
+ if (isConst(arg0)) {
459
+ return new OperatorNode('*', 'multiply', [new OperatorNode('-', 'unaryMinus', [arg0]), new OperatorNode('/', 'divide', [_derivative(arg1, isConst), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])])]);
473
460
  }
474
461
 
475
462
  // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2
476
- 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)])]);
463
+ return new OperatorNode('/', 'divide', [new OperatorNode('-', 'subtract', [new OperatorNode('*', 'multiply', [_derivative(arg0, isConst), arg1.clone()]), new OperatorNode('*', 'multiply', [arg0.clone(), _derivative(arg1, isConst)])]), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])]);
477
464
  }
478
465
  if (node.op === '^' && node.isBinary()) {
479
466
  const arg0 = node.args[0];
480
467
  const arg1 = node.args[1];
481
- if (constNodes[arg0] !== undefined) {
468
+ if (isConst(arg0)) {
482
469
  // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1
483
470
  if ((0, _is.isConstantNode)(arg0) && (isZero(arg0.value) || equal(arg0.value, 1))) {
484
471
  return createConstantNode(0);
485
472
  }
486
473
 
487
474
  // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x)
488
- return new OperatorNode('*', 'multiply', [node, new OperatorNode('*', 'multiply', [new FunctionNode('log', [arg0.clone()]), _derivative(arg1.clone(), constNodes)])]);
475
+ return new OperatorNode('*', 'multiply', [node, new OperatorNode('*', 'multiply', [new FunctionNode('log', [arg0.clone()]), _derivative(arg1.clone(), isConst)])]);
489
476
  }
490
- if (constNodes[arg1] !== undefined) {
477
+ if (isConst(arg1)) {
491
478
  if ((0, _is.isConstantNode)(arg1)) {
492
479
  // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0
493
480
  if (isZero(arg1.value)) {
@@ -495,17 +482,17 @@ const createDerivative = exports.createDerivative = /* #__PURE__ */(0, _factory.
495
482
  }
496
483
  // Ignore exponent; f(x)^1 = f(x)
497
484
  if (equal(arg1.value, 1)) {
498
- return _derivative(arg0, constNodes);
485
+ return _derivative(arg0, isConst);
499
486
  }
500
487
  }
501
488
 
502
489
  // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1)
503
490
  const powMinusOne = new OperatorNode('^', 'pow', [arg0.clone(), new OperatorNode('-', 'subtract', [arg1, createConstantNode(1)])]);
504
- return new OperatorNode('*', 'multiply', [arg1.clone(), new OperatorNode('*', 'multiply', [_derivative(arg0, constNodes), powMinusOne])]);
491
+ return new OperatorNode('*', 'multiply', [arg1.clone(), new OperatorNode('*', 'multiply', [_derivative(arg0, isConst), powMinusOne])]);
505
492
  }
506
493
 
507
494
  // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)]
508
- return new OperatorNode('*', 'multiply', [new OperatorNode('^', 'pow', [arg0.clone(), arg1.clone()]), new OperatorNode('+', 'add', [new OperatorNode('*', 'multiply', [_derivative(arg0, constNodes), new OperatorNode('/', 'divide', [arg1.clone(), arg0.clone()])]), new OperatorNode('*', 'multiply', [_derivative(arg1, constNodes), new FunctionNode('log', [arg0.clone()])])])]);
495
+ return new OperatorNode('*', 'multiply', [new OperatorNode('^', 'pow', [arg0.clone(), arg1.clone()]), new OperatorNode('+', 'add', [new OperatorNode('*', 'multiply', [_derivative(arg0, isConst), new OperatorNode('/', 'divide', [arg1.clone(), arg0.clone()])]), new OperatorNode('*', 'multiply', [_derivative(arg1, isConst), new FunctionNode('log', [arg0.clone()])])])]);
509
496
  }
510
497
  throw new Error('Cannot process operator "' + node.op + '" in derivative: ' + 'the operator is not supported, undefined, or the number of arguments passed to it are not supported');
511
498
  }
package/lib/cjs/header.js CHANGED
@@ -6,8 +6,8 @@
6
6
  * It features real and complex numbers, units, matrices, a large set of
7
7
  * mathematical functions, and a flexible expression parser.
8
8
  *
9
- * @version 14.0.0
10
- * @date 2024-11-20
9
+ * @version 14.0.1
10
+ * @date 2024-12-11
11
11
  *
12
12
  * @license
13
13
  * Copyright (C) 2013-2024 Jos de Jong <wjosdejong@gmail.com>
@@ -4,6 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.version = void 0;
7
- const version = exports.version = '14.0.0';
7
+ const version = exports.version = '14.0.1';
8
8
  // Note: This file is automatically generated when building math.js.
9
9
  // Changes made in this file will be overwritten.
@@ -60,9 +60,18 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
60
60
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
61
61
  simplify: true
62
62
  };
63
- var constNodes = {};
64
- constTag(constNodes, expr, variable.name);
65
- var res = _derivative(expr, constNodes);
63
+ var cache = new Map();
64
+ var variableName = variable.name;
65
+ function isConstCached(node) {
66
+ var cached = cache.get(node);
67
+ if (cached !== undefined) {
68
+ return cached;
69
+ }
70
+ var res = _isConst(isConstCached, node, variableName);
71
+ cache.set(node, res);
72
+ return res;
73
+ }
74
+ var res = _derivative(expr, isConstCached);
66
75
  return options.simplify ? simplify(res) : res;
67
76
  }
68
77
  function parseIdentifier(string) {
@@ -82,9 +91,8 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
82
91
  'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) {
83
92
  let res = expr
84
93
  for (let i = 0; i < order; i++) {
85
- let constNodes = {}
86
- constTag(constNodes, expr, variable.name)
87
- res = _derivative(res, constNodes)
94
+ <create caching isConst>
95
+ res = _derivative(res, isConst)
88
96
  }
89
97
  return res
90
98
  }
@@ -127,56 +135,39 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
127
135
  });
128
136
 
129
137
  /**
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:
138
+ * Checks if a node is constants (e.g. 2 + 2).
139
+ * Accepts (usually memoized) version of self as the first parameter for recursive calls.
140
+ * Classification is done as follows:
133
141
  *
134
142
  * 1. ConstantNodes are constants.
135
143
  * 2. If there exists a SymbolNode, of which we are differentiating over,
136
144
  * in the subtree it is not constant.
137
145
  *
138
- * @param {Object} constNodes Holds the nodes that are constant
146
+ * @param {function} isConst Function that tells whether sub-expression is a constant
139
147
  * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
140
148
  * @param {string} varName Variable that we are differentiating
141
149
  * @return {boolean} if node is constant
142
150
  */
143
- // TODO: can we rewrite constTag into a pure function?
144
- var constTag = typed('constTag', {
145
- 'Object, ConstantNode, string': function Object_ConstantNode_string(constNodes, node) {
146
- constNodes[node] = true;
151
+ var _isConst = typed('_isConst', {
152
+ 'function, ConstantNode, string': function function_ConstantNode_string() {
147
153
  return true;
148
154
  },
149
- 'Object, SymbolNode, string': function Object_SymbolNode_string(constNodes, node, varName) {
155
+ 'function, SymbolNode, string': function function_SymbolNode_string(isConst, node, varName) {
150
156
  // Treat other variables like constants. For reasoning, see:
151
157
  // https://en.wikipedia.org/wiki/Partial_derivative
152
- if (node.name !== varName) {
153
- constNodes[node] = true;
154
- return true;
155
- }
156
- return false;
158
+ return node.name !== varName;
157
159
  },
158
- 'Object, ParenthesisNode, string': function Object_ParenthesisNode_string(constNodes, node, varName) {
159
- return constTag(constNodes, node.content, varName);
160
+ 'function, ParenthesisNode, string': function function_ParenthesisNode_string(isConst, node, varName) {
161
+ return isConst(node.content, varName);
160
162
  },
161
- 'Object, FunctionAssignmentNode, string': function Object_FunctionAssignmentNode_string(constNodes, node, varName) {
163
+ 'function, FunctionAssignmentNode, string': function function_FunctionAssignmentNode_string(isConst, node, varName) {
162
164
  if (!node.params.includes(varName)) {
163
- constNodes[node] = true;
164
165
  return true;
165
166
  }
166
- return constTag(constNodes, node.expr, varName);
167
+ return isConst(node.expr, varName);
167
168
  },
168
- 'Object, FunctionNode | OperatorNode, string': function Object_FunctionNode__OperatorNode_string(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;
169
+ 'function, FunctionNode | OperatorNode, string': function function_FunctionNode__OperatorNode_string(isConst, node, varName) {
170
+ return node.args.every(arg => isConst(arg, varName));
180
171
  }
181
172
  });
182
173
 
@@ -184,30 +175,30 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
184
175
  * Applies differentiation rules.
185
176
  *
186
177
  * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
187
- * @param {Object} constNodes Holds the nodes that are constant
178
+ * @param {function} isConst Function that tells if a node is constant
188
179
  * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr`
189
180
  */
190
181
  var _derivative = typed('_derivative', {
191
- 'ConstantNode, Object': function ConstantNode_Object(node) {
182
+ 'ConstantNode, function': function ConstantNode_function() {
192
183
  return createConstantNode(0);
193
184
  },
194
- 'SymbolNode, Object': function SymbolNode_Object(node, constNodes) {
195
- if (constNodes[node] !== undefined) {
185
+ 'SymbolNode, function': function SymbolNode_function(node, isConst) {
186
+ if (isConst(node)) {
196
187
  return createConstantNode(0);
197
188
  }
198
189
  return createConstantNode(1);
199
190
  },
200
- 'ParenthesisNode, Object': function ParenthesisNode_Object(node, constNodes) {
201
- return new ParenthesisNode(_derivative(node.content, constNodes));
191
+ 'ParenthesisNode, function': function ParenthesisNode_function(node, isConst) {
192
+ return new ParenthesisNode(_derivative(node.content, isConst));
202
193
  },
203
- 'FunctionAssignmentNode, Object': function FunctionAssignmentNode_Object(node, constNodes) {
204
- if (constNodes[node] !== undefined) {
194
+ 'FunctionAssignmentNode, function': function FunctionAssignmentNode_function(node, isConst) {
195
+ if (isConst(node)) {
205
196
  return createConstantNode(0);
206
197
  }
207
- return _derivative(node.expr, constNodes);
198
+ return _derivative(node.expr, isConst);
208
199
  },
209
- 'FunctionNode, Object': function FunctionNode_Object(node, constNodes) {
210
- if (constNodes[node] !== undefined) {
200
+ 'FunctionNode, function': function FunctionNode_function(node, isConst) {
201
+ if (isConst(node)) {
211
202
  return createConstantNode(0);
212
203
  }
213
204
  var arg0 = node.args[0];
@@ -231,10 +222,7 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
231
222
  } else if (node.args.length === 2) {
232
223
  // Rearrange from nthRoot(x, a) -> x^(1/a)
233
224
  arg1 = new OperatorNode('/', 'divide', [createConstantNode(1), node.args[1]]);
234
-
235
- // Is a variable?
236
- constNodes[arg1] = constNodes[node.args[1]];
237
- return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), constNodes);
225
+ return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), isConst);
238
226
  }
239
227
  break;
240
228
  case 'log10':
@@ -245,20 +233,19 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
245
233
  // d/dx(log(x)) = 1 / x
246
234
  funcDerivative = arg0.clone();
247
235
  div = true;
248
- } else if (node.args.length === 1 && arg1 || node.args.length === 2 && constNodes[node.args[1]] !== undefined) {
236
+ } else if (node.args.length === 1 && arg1 || node.args.length === 2 && isConst(node.args[1])) {
249
237
  // d/dx(log(x, c)) = 1 / (x*ln(c))
250
238
  funcDerivative = new OperatorNode('*', 'multiply', [arg0.clone(), new FunctionNode('log', [arg1 || node.args[1]])]);
251
239
  div = true;
252
240
  } else if (node.args.length === 2) {
253
241
  // 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);
242
+ return _derivative(new OperatorNode('/', 'divide', [new FunctionNode('log', [arg0]), new FunctionNode('log', [node.args[1]])]), isConst);
255
243
  }
256
244
  break;
257
245
  case 'pow':
258
246
  if (node.args.length === 2) {
259
- constNodes[arg1] = constNodes[node.args[1]];
260
247
  // Pass to pow operator node parser
261
- return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), constNodes);
248
+ return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), isConst);
262
249
  }
263
250
  break;
264
251
  case 'exp':
@@ -404,51 +391,51 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
404
391
  /* Apply chain rule to all functions:
405
392
  F(x) = f(g(x))
406
393
  F'(x) = g'(x)*f'(g(x)) */
407
- var chainDerivative = _derivative(arg0, constNodes);
394
+ var chainDerivative = _derivative(arg0, isConst);
408
395
  if (negative) {
409
396
  chainDerivative = new OperatorNode('-', 'unaryMinus', [chainDerivative]);
410
397
  }
411
398
  return new OperatorNode(op, func, [chainDerivative, funcDerivative]);
412
399
  },
413
- 'OperatorNode, Object': function OperatorNode_Object(node, constNodes) {
414
- if (constNodes[node] !== undefined) {
400
+ 'OperatorNode, function': function OperatorNode_function(node, isConst) {
401
+ if (isConst(node)) {
415
402
  return createConstantNode(0);
416
403
  }
417
404
  if (node.op === '+') {
418
405
  // d/dx(sum(f(x)) = sum(f'(x))
419
406
  return new OperatorNode(node.op, node.fn, node.args.map(function (arg) {
420
- return _derivative(arg, constNodes);
407
+ return _derivative(arg, isConst);
421
408
  }));
422
409
  }
423
410
  if (node.op === '-') {
424
411
  // d/dx(+/-f(x)) = +/-f'(x)
425
412
  if (node.isUnary()) {
426
- return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes)]);
413
+ return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], isConst)]);
427
414
  }
428
415
 
429
416
  // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x)
430
417
  if (node.isBinary()) {
431
- return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes), _derivative(node.args[1], constNodes)]);
418
+ return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], isConst), _derivative(node.args[1], isConst)]);
432
419
  }
433
420
  }
434
421
  if (node.op === '*') {
435
422
  // d/dx(c*f(x)) = c*f'(x)
436
423
  var constantTerms = node.args.filter(function (arg) {
437
- return constNodes[arg] !== undefined;
424
+ return isConst(arg);
438
425
  });
439
426
  if (constantTerms.length > 0) {
440
427
  var nonConstantTerms = node.args.filter(function (arg) {
441
- return constNodes[arg] === undefined;
428
+ return !isConst(arg);
442
429
  });
443
430
  var nonConstantNode = nonConstantTerms.length === 1 ? nonConstantTerms[0] : new OperatorNode('*', 'multiply', nonConstantTerms);
444
- var newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes));
431
+ var newArgs = constantTerms.concat(_derivative(nonConstantNode, isConst));
445
432
  return new OperatorNode('*', 'multiply', newArgs);
446
433
  }
447
434
 
448
435
  // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x)
449
436
  return new OperatorNode('+', 'add', node.args.map(function (argOuter) {
450
437
  return new OperatorNode('*', 'multiply', node.args.map(function (argInner) {
451
- return argInner === argOuter ? _derivative(argInner, constNodes) : argInner.clone();
438
+ return argInner === argOuter ? _derivative(argInner, isConst) : argInner.clone();
452
439
  }));
453
440
  }));
454
441
  }
@@ -457,31 +444,31 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
457
444
  var arg1 = node.args[1];
458
445
 
459
446
  // d/dx(f(x) / c) = f'(x) / c
460
- if (constNodes[arg1] !== undefined) {
461
- return new OperatorNode('/', 'divide', [_derivative(arg0, constNodes), arg1]);
447
+ if (isConst(arg1)) {
448
+ return new OperatorNode('/', 'divide', [_derivative(arg0, isConst), arg1]);
462
449
  }
463
450
 
464
451
  // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2)
465
- if (constNodes[arg0] !== undefined) {
466
- return new OperatorNode('*', 'multiply', [new OperatorNode('-', 'unaryMinus', [arg0]), new OperatorNode('/', 'divide', [_derivative(arg1, constNodes), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])])]);
452
+ if (isConst(arg0)) {
453
+ return new OperatorNode('*', 'multiply', [new OperatorNode('-', 'unaryMinus', [arg0]), new OperatorNode('/', 'divide', [_derivative(arg1, isConst), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])])]);
467
454
  }
468
455
 
469
456
  // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2
470
- 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)])]);
457
+ return new OperatorNode('/', 'divide', [new OperatorNode('-', 'subtract', [new OperatorNode('*', 'multiply', [_derivative(arg0, isConst), arg1.clone()]), new OperatorNode('*', 'multiply', [arg0.clone(), _derivative(arg1, isConst)])]), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])]);
471
458
  }
472
459
  if (node.op === '^' && node.isBinary()) {
473
460
  var _arg = node.args[0];
474
461
  var _arg2 = node.args[1];
475
- if (constNodes[_arg] !== undefined) {
462
+ if (isConst(_arg)) {
476
463
  // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1
477
464
  if (isConstantNode(_arg) && (isZero(_arg.value) || equal(_arg.value, 1))) {
478
465
  return createConstantNode(0);
479
466
  }
480
467
 
481
468
  // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x)
482
- return new OperatorNode('*', 'multiply', [node, new OperatorNode('*', 'multiply', [new FunctionNode('log', [_arg.clone()]), _derivative(_arg2.clone(), constNodes)])]);
469
+ return new OperatorNode('*', 'multiply', [node, new OperatorNode('*', 'multiply', [new FunctionNode('log', [_arg.clone()]), _derivative(_arg2.clone(), isConst)])]);
483
470
  }
484
- if (constNodes[_arg2] !== undefined) {
471
+ if (isConst(_arg2)) {
485
472
  if (isConstantNode(_arg2)) {
486
473
  // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0
487
474
  if (isZero(_arg2.value)) {
@@ -489,17 +476,17 @@ export var createDerivative = /* #__PURE__ */factory(name, dependencies, _ref =>
489
476
  }
490
477
  // Ignore exponent; f(x)^1 = f(x)
491
478
  if (equal(_arg2.value, 1)) {
492
- return _derivative(_arg, constNodes);
479
+ return _derivative(_arg, isConst);
493
480
  }
494
481
  }
495
482
 
496
483
  // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1)
497
484
  var powMinusOne = new OperatorNode('^', 'pow', [_arg.clone(), new OperatorNode('-', 'subtract', [_arg2, createConstantNode(1)])]);
498
- return new OperatorNode('*', 'multiply', [_arg2.clone(), new OperatorNode('*', 'multiply', [_derivative(_arg, constNodes), powMinusOne])]);
485
+ return new OperatorNode('*', 'multiply', [_arg2.clone(), new OperatorNode('*', 'multiply', [_derivative(_arg, isConst), powMinusOne])]);
499
486
  }
500
487
 
501
488
  // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)]
502
- 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()])])])]);
489
+ return new OperatorNode('*', 'multiply', [new OperatorNode('^', 'pow', [_arg.clone(), _arg2.clone()]), new OperatorNode('+', 'add', [new OperatorNode('*', 'multiply', [_derivative(_arg, isConst), new OperatorNode('/', 'divide', [_arg2.clone(), _arg.clone()])]), new OperatorNode('*', 'multiply', [_derivative(_arg2, isConst), new FunctionNode('log', [_arg.clone()])])])]);
503
490
  }
504
491
  throw new Error('Cannot process operator "' + node.op + '" in derivative: ' + 'the operator is not supported, undefined, or the number of arguments passed to it are not supported');
505
492
  }
@@ -1,3 +1,3 @@
1
- export var version = '14.0.0';
1
+ export var version = '14.0.1';
2
2
  // Note: This file is automatically generated when building math.js.
3
3
  // Changes made in this file will be overwritten.