mathjs 11.3.3 → 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/HISTORY.md +14 -0
  2. package/lib/browser/math.js +1 -1
  3. package/lib/browser/math.js.LICENSE.txt +2 -2
  4. package/lib/browser/math.js.map +1 -1
  5. package/lib/cjs/entry/dependenciesAny/dependenciesLyap.generated.js +26 -0
  6. package/lib/cjs/entry/dependenciesAny/dependenciesPolynomialRoot.generated.js +42 -0
  7. package/lib/cjs/entry/dependenciesAny/dependenciesSchur.generated.js +30 -0
  8. package/lib/cjs/entry/dependenciesAny/dependenciesSylvester.generated.js +46 -0
  9. package/lib/cjs/entry/dependenciesAny.generated.js +28 -0
  10. package/lib/cjs/entry/impureFunctionsAny.generated.js +21 -17
  11. package/lib/cjs/entry/pureFunctionsAny.generated.js +100 -48
  12. package/lib/cjs/expression/embeddedDocs/embeddedDocs.js +8 -0
  13. package/lib/cjs/expression/embeddedDocs/function/algebra/polynomialRoot.js +15 -0
  14. package/lib/cjs/expression/embeddedDocs/function/matrix/lyap.js +15 -0
  15. package/lib/cjs/expression/embeddedDocs/function/matrix/schur.js +15 -0
  16. package/lib/cjs/expression/embeddedDocs/function/matrix/sylvester.js +15 -0
  17. package/lib/cjs/factoriesAny.js +28 -0
  18. package/lib/cjs/function/algebra/decomposition/schur.js +75 -0
  19. package/lib/cjs/function/algebra/lyap.js +57 -0
  20. package/lib/cjs/function/algebra/polynomialRoot.js +139 -0
  21. package/lib/cjs/function/algebra/simplify/wildcards.js +38 -0
  22. package/lib/cjs/function/algebra/simplify.js +104 -44
  23. package/lib/cjs/function/algebra/simplifyConstant.js +29 -12
  24. package/lib/cjs/function/algebra/sylvester.js +127 -0
  25. package/lib/cjs/function/matrix/forEach.js +1 -1
  26. package/lib/cjs/header.js +2 -2
  27. package/lib/cjs/version.js +1 -1
  28. package/lib/esm/entry/dependenciesAny/dependenciesLyap.generated.js +18 -0
  29. package/lib/esm/entry/dependenciesAny/dependenciesPolynomialRoot.generated.js +34 -0
  30. package/lib/esm/entry/dependenciesAny/dependenciesSchur.generated.js +22 -0
  31. package/lib/esm/entry/dependenciesAny/dependenciesSylvester.generated.js +38 -0
  32. package/lib/esm/entry/dependenciesAny.generated.js +4 -0
  33. package/lib/esm/entry/impureFunctionsAny.generated.js +22 -18
  34. package/lib/esm/entry/pureFunctionsAny.generated.js +87 -39
  35. package/lib/esm/expression/embeddedDocs/embeddedDocs.js +8 -0
  36. package/lib/esm/expression/embeddedDocs/function/algebra/polynomialRoot.js +8 -0
  37. package/lib/esm/expression/embeddedDocs/function/matrix/lyap.js +8 -0
  38. package/lib/esm/expression/embeddedDocs/function/matrix/schur.js +8 -0
  39. package/lib/esm/expression/embeddedDocs/function/matrix/sylvester.js +8 -0
  40. package/lib/esm/factoriesAny.js +4 -0
  41. package/lib/esm/function/algebra/decomposition/schur.js +70 -0
  42. package/lib/esm/function/algebra/lyap.js +52 -0
  43. package/lib/esm/function/algebra/polynomialRoot.js +122 -0
  44. package/lib/esm/function/algebra/simplify/wildcards.js +20 -0
  45. package/lib/esm/function/algebra/simplify.js +105 -45
  46. package/lib/esm/function/algebra/simplifyConstant.js +29 -12
  47. package/lib/esm/function/algebra/sylvester.js +118 -0
  48. package/lib/esm/function/matrix/forEach.js +1 -1
  49. package/lib/esm/version.js +1 -1
  50. package/package.json +8 -8
  51. package/types/index.d.ts +83 -5
@@ -0,0 +1,8 @@
1
+ export var lyapDocs = {
2
+ name: 'lyap',
3
+ category: 'Matrix',
4
+ syntax: ['lyap(A,Q)'],
5
+ description: 'Solves the Continuous-time Lyapunov equation AP+PA\'+Q=0 for P',
6
+ examples: ['lyap([[-2, 0], [1, -4]], [[3, 1], [1, 3]])', 'lyap(A,Q)'],
7
+ seealso: ['schur', 'sylvester']
8
+ };
@@ -0,0 +1,8 @@
1
+ export var schurDocs = {
2
+ name: 'schur',
3
+ category: 'Matrix',
4
+ syntax: ['schur(A)'],
5
+ description: 'Performs a real Schur decomposition of the real matrix A = UTU\'',
6
+ examples: ['schur([[1, 0], [-4, 3]])', 'schur(A)'],
7
+ seealso: ['lyap', 'sylvester']
8
+ };
@@ -0,0 +1,8 @@
1
+ export var sylvesterDocs = {
2
+ name: 'sylvester',
3
+ category: 'Matrix',
4
+ syntax: ['sylvester(A,B,C)'],
5
+ description: 'Solves the real-valued Sylvester equation AX+XB=C for X',
6
+ examples: ['sylvester([[-1, -2], [1, 1]], [[-2, 1], [-1, 2]], [[-3, 2], [3, 0]])', 'sylvester(A,B,C)'],
7
+ seealso: ['schur', 'lyap']
8
+ };
@@ -210,6 +210,7 @@ export { createLup } from './function/algebra/decomposition/lup.js';
210
210
  export { createQr } from './function/algebra/decomposition/qr.js';
211
211
  export { createSlu } from './function/algebra/decomposition/slu.js';
212
212
  export { createLusolve } from './function/algebra/solver/lusolve.js';
213
+ export { createPolynomialRoot } from './function/algebra/polynomialRoot.js';
213
214
  export { createHelpClass } from './expression/Help.js';
214
215
  export { createChainClass } from './type/chain/Chain.js';
215
216
  export { createHelp } from './expression/function/help.js';
@@ -220,6 +221,9 @@ export { createPinv } from './function/matrix/pinv.js';
220
221
  export { createEigs } from './function/matrix/eigs.js';
221
222
  export { createExpm } from './function/matrix/expm.js';
222
223
  export { createSqrtm } from './function/matrix/sqrtm.js';
224
+ export { createSylvester } from './function/algebra/sylvester.js';
225
+ export { createSchur } from './function/algebra/decomposition/schur.js';
226
+ export { createLyap } from './function/algebra/lyap.js';
223
227
  export { createDivide } from './function/arithmetic/divide.js';
224
228
  export { createDistance } from './function/geometry/distance.js';
225
229
  export { createIntersect } from './function/geometry/intersect.js';
@@ -0,0 +1,70 @@
1
+ import { factory } from '../../../utils/factory.js';
2
+ var name = 'schur';
3
+ var dependencies = ['typed', 'matrix', 'identity', 'multiply', 'qr', 'norm', 'subtract'];
4
+ export var createSchur = /* #__PURE__ */factory(name, dependencies, _ref => {
5
+ var {
6
+ typed,
7
+ matrix,
8
+ identity,
9
+ multiply,
10
+ qr,
11
+ norm,
12
+ subtract
13
+ } = _ref;
14
+ /**
15
+ *
16
+ * Performs a real Schur decomposition of the real matrix A = UTU' where U is orthogonal
17
+ * and T is upper quasi-triangular.
18
+ * https://en.wikipedia.org/wiki/Schur_decomposition
19
+ *
20
+ * Syntax:
21
+ *
22
+ * math.schur(A)
23
+ *
24
+ * Examples:
25
+ *
26
+ * const A = [[1, 0], [-4, 3]]
27
+ * math.schur(A) // returns {T: [[3, 4], [0, 1]], R: [[0, 1], [-1, 0]]}
28
+ *
29
+ * See also:
30
+ *
31
+ * sylvester, lyap, qr
32
+ *
33
+ * @param {Array | Matrix} A Matrix A
34
+ * @return {{U: Array | Matrix, T: Array | Matrix}} Object containing both matrix U and T of the Schur Decomposition A=UTU'
35
+ */
36
+ return typed(name, {
37
+ Array: function Array(X) {
38
+ var r = _schur(matrix(X));
39
+ return {
40
+ U: r.U.valueOf(),
41
+ T: r.T.valueOf()
42
+ };
43
+ },
44
+ Matrix: function Matrix(X) {
45
+ return _schur(X);
46
+ }
47
+ });
48
+ function _schur(X) {
49
+ var n = X.size()[0];
50
+ var A = X;
51
+ var U = identity(n);
52
+ var k = 0;
53
+ var A0;
54
+ do {
55
+ A0 = A;
56
+ var QR = qr(A);
57
+ var Q = QR.Q;
58
+ var R = QR.R;
59
+ A = multiply(R, Q);
60
+ U = multiply(U, Q);
61
+ if (k++ > 100) {
62
+ break;
63
+ }
64
+ } while (norm(subtract(A, A0)) > 1e-4);
65
+ return {
66
+ U,
67
+ T: A
68
+ };
69
+ }
70
+ });
@@ -0,0 +1,52 @@
1
+ import { factory } from '../../utils/factory.js';
2
+ var name = 'lyap';
3
+ var dependencies = ['typed', 'matrix', 'sylvester', 'multiply', 'transpose'];
4
+ export var createLyap = /* #__PURE__ */factory(name, dependencies, _ref => {
5
+ var {
6
+ typed,
7
+ matrix,
8
+ sylvester,
9
+ multiply,
10
+ transpose
11
+ } = _ref;
12
+ /**
13
+ *
14
+ * Solves the Continuous-time Lyapunov equation AP+PA'+Q=0 for P, where
15
+ * Q is an input matrix. When Q is symmetric, P is also symmetric. Notice
16
+ * that different equivalent definitions exist for the Continuous-time
17
+ * Lyapunov equation.
18
+ * https://en.wikipedia.org/wiki/Lyapunov_equation
19
+ *
20
+ * Syntax:
21
+ *
22
+ * math.lyap(A, Q)
23
+ *
24
+ * Examples:
25
+ *
26
+ * const A = [[-2, 0], [1, -4]]
27
+ * const Q = [[3, 1], [1, 3]]
28
+ * const P = math.lyap(A, Q)
29
+ *
30
+ * See also:
31
+ *
32
+ * sylvester, schur
33
+ *
34
+ * @param {Matrix | Array} A Matrix A
35
+ * @param {Matrix | Array} Q Matrix Q
36
+ * @return {Matrix | Array} Matrix P solution to the Continuous-time Lyapunov equation AP+PA'=Q
37
+ */
38
+ return typed(name, {
39
+ 'Matrix, Matrix': function MatrixMatrix(A, Q) {
40
+ return sylvester(A, transpose(A), multiply(-1, Q));
41
+ },
42
+ 'Array, Matrix': function ArrayMatrix(A, Q) {
43
+ return sylvester(matrix(A), transpose(matrix(A)), multiply(-1, Q));
44
+ },
45
+ 'Matrix, Array': function MatrixArray(A, Q) {
46
+ return sylvester(A, transpose(matrix(A)), matrix(multiply(-1, Q)));
47
+ },
48
+ 'Array, Array': function ArrayArray(A, Q) {
49
+ return sylvester(matrix(A), transpose(matrix(A)), matrix(multiply(-1, Q))).toArray();
50
+ }
51
+ });
52
+ });
@@ -0,0 +1,122 @@
1
+ import { factory } from '../../utils/factory.js';
2
+ var name = 'polynomialRoot';
3
+ var dependencies = ['typed', 'isZero', 'equalScalar', 'add', 'subtract', 'multiply', 'divide', 'sqrt', 'unaryMinus', 'cbrt', 'typeOf', 'im', 're'];
4
+ export var createPolynomialRoot = /* #__PURE__ */factory(name, dependencies, _ref => {
5
+ var {
6
+ typed,
7
+ isZero,
8
+ equalScalar,
9
+ add,
10
+ subtract,
11
+ multiply,
12
+ divide,
13
+ sqrt,
14
+ unaryMinus,
15
+ cbrt,
16
+ typeOf,
17
+ im,
18
+ re
19
+ } = _ref;
20
+ /**
21
+ * Finds the numerical values of the distinct roots of a polynomial with real or complex coefficients.
22
+ * Currently operates only on linear, quadratic, and cubic polynomials using the standard
23
+ * formulas for the roots.
24
+ *
25
+ * Syntax:
26
+ *
27
+ * polynomialRoot(constant, linearCoeff, quadraticCoeff, cubicCoeff)
28
+ *
29
+ * Examples:
30
+ * // linear
31
+ * math.polynomialRoot(6, 3) // [-2]
32
+ * math.polynomialRoot(math.complex(6,3), 3) // [-2 - i]
33
+ * math.polynomialRoot(math.complex(6,3), math.complex(2,1)) // [-3 + 0i]
34
+ * // quadratic
35
+ * math.polynomialRoot(2, -3, 1) // [2, 1]
36
+ * math.polynomialRoot(8, 8, 2) // [-2]
37
+ * math.polynomialRoot(-2, 0, 1) // [1.4142135623730951, -1.4142135623730951]
38
+ * math.polynomialRoot(2, -2, 1) // [1 + i, 1 - i]
39
+ * math.polynomialRoot(math.complex(1,3), math.complex(-3, -2), 1) // [2 + i, 1 + i]
40
+ * // cubic
41
+ * math.polynomialRoot(-6, 11, -6, 1) // [1, 3, 2]
42
+ * math.polynomialRoot(-8, 0, 0, 1) // [-1 - 1.7320508075688774i, 2, -1 + 1.7320508075688774i]
43
+ * math.polynomialRoot(0, 8, 8, 2) // [0, -2]
44
+ * math.polynomialRoot(1, 1, 1, 1) // [-1 + 0i, 0 - i, 0 + i]
45
+ *
46
+ * See also:
47
+ * cbrt, sqrt
48
+ *
49
+ * @param {... number | Complex} coeffs
50
+ * The coefficients of the polynomial, starting with with the constant coefficent, followed
51
+ * by the linear coefficient and subsequent coefficients of increasing powers.
52
+ * @return {Array} The distinct roots of the polynomial
53
+ */
54
+
55
+ return typed(name, {
56
+ 'number|Complex, ...number|Complex': (constant, restCoeffs) => {
57
+ var coeffs = [constant, ...restCoeffs];
58
+ while (coeffs.length > 0 && isZero(coeffs[coeffs.length - 1])) {
59
+ coeffs.pop();
60
+ }
61
+ if (coeffs.length < 2) {
62
+ throw new RangeError("Polynomial [".concat(constant, ", ").concat(restCoeffs, "] must have a non-zero non-constant coefficient"));
63
+ }
64
+ switch (coeffs.length) {
65
+ case 2:
66
+ // linear
67
+ return [unaryMinus(divide(coeffs[0], coeffs[1]))];
68
+ case 3:
69
+ {
70
+ // quadratic
71
+ var [c, b, a] = coeffs;
72
+ var denom = multiply(2, a);
73
+ var d1 = multiply(b, b);
74
+ var d2 = multiply(4, a, c);
75
+ if (equalScalar(d1, d2)) return [divide(unaryMinus(b), denom)];
76
+ var discriminant = sqrt(subtract(d1, d2));
77
+ return [divide(subtract(discriminant, b), denom), divide(subtract(unaryMinus(discriminant), b), denom)];
78
+ }
79
+ case 4:
80
+ {
81
+ // cubic, cf. https://en.wikipedia.org/wiki/Cubic_equation
82
+ var [d, _c, _b, _a] = coeffs;
83
+ var _denom = unaryMinus(multiply(3, _a));
84
+ var D0_1 = multiply(_b, _b);
85
+ var D0_2 = multiply(3, _a, _c);
86
+ var D1_1 = add(multiply(2, _b, _b, _b), multiply(27, _a, _a, d));
87
+ var D1_2 = multiply(9, _a, _b, _c);
88
+ if (equalScalar(D0_1, D0_2) && equalScalar(D1_1, D1_2)) {
89
+ return [divide(_b, _denom)];
90
+ }
91
+ var Delta0 = subtract(D0_1, D0_2);
92
+ var Delta1 = subtract(D1_1, D1_2);
93
+ var discriminant1 = add(multiply(18, _a, _b, _c, d), multiply(_b, _b, _c, _c));
94
+ var discriminant2 = add(multiply(4, _b, _b, _b, d), multiply(4, _a, _c, _c, _c), multiply(27, _a, _a, d, d));
95
+ if (equalScalar(discriminant1, discriminant2)) {
96
+ return [divide(subtract(multiply(4, _a, _b, _c), add(multiply(9, _a, _a, d), multiply(_b, _b, _b))), multiply(_a, Delta0)),
97
+ // simple root
98
+ divide(subtract(multiply(9, _a, d), multiply(_b, _c)), multiply(2, Delta0)) // double root
99
+ ];
100
+ }
101
+ // OK, we have three distinct roots
102
+ var Ccubed;
103
+ if (equalScalar(D0_1, D0_2)) {
104
+ Ccubed = Delta1;
105
+ } else {
106
+ Ccubed = divide(add(Delta1, sqrt(subtract(multiply(Delta1, Delta1), multiply(4, Delta0, Delta0, Delta0)))), 2);
107
+ }
108
+ var allRoots = true;
109
+ var rawRoots = cbrt(Ccubed, allRoots).toArray().map(C => divide(add(_b, C, divide(Delta0, C)), _denom));
110
+ return rawRoots.map(r => {
111
+ if (typeOf(r) === 'Complex' && equalScalar(re(r), re(r) + im(r))) {
112
+ return re(r);
113
+ }
114
+ return r;
115
+ });
116
+ }
117
+ default:
118
+ throw new RangeError("only implemented for cubic or lower-order polynomials, not ".concat(coeffs));
119
+ }
120
+ }
121
+ });
122
+ });
@@ -0,0 +1,20 @@
1
+ import { isConstantNode, isFunctionNode, isOperatorNode, isParenthesisNode } from '../../../utils/is.js';
2
+ export { isConstantNode, isSymbolNode as isVariableNode } from '../../../utils/is.js';
3
+ export function isNumericNode(x) {
4
+ return isConstantNode(x) || isOperatorNode(x) && x.isUnary() && isConstantNode(x.args[0]);
5
+ }
6
+ export function isConstantExpression(x) {
7
+ if (isConstantNode(x)) {
8
+ // Basic Constant types
9
+ return true;
10
+ }
11
+ if ((isFunctionNode(x) || isOperatorNode(x)) && x.args.every(isConstantExpression)) {
12
+ // Can be constant depending on arguments
13
+ return true;
14
+ }
15
+ if (isParenthesisNode(x) && isConstantExpression(x.content)) {
16
+ // Parenthesis are transparent
17
+ return true;
18
+ }
19
+ return false; // Probably missing some edge cases
20
+ }
@@ -1,4 +1,5 @@
1
- import { isConstantNode, isParenthesisNode } from '../../utils/is.js';
1
+ import { isParenthesisNode } from '../../utils/is.js';
2
+ import { isConstantNode, isVariableNode, isNumericNode, isConstantExpression } from './simplify/wildcards.js';
2
3
  import { factory } from '../../utils/factory.js';
3
4
  import { createUtil } from './simplify/util.js';
4
5
  import { hasOwnProperty } from '../../utils/object.js';
@@ -75,9 +76,15 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
75
76
  * expression is that variables starting with the following characters are
76
77
  * interpreted as wildcards:
77
78
  *
78
- * - 'n' - matches any Node
79
- * - 'c' - matches any ConstantNode
80
- * - 'v' - matches any Node that is not a ConstantNode
79
+ * - 'n' - Matches any node [Node]
80
+ * - 'c' - Matches a constant literal (5 or 3.2) [ConstantNode]
81
+ * - 'cl' - Matches a constant literal; same as c [ConstantNode]
82
+ * - 'cd' - Matches a decimal literal (5 or -3.2) [ConstantNode or unaryMinus wrapping a ConstantNode]
83
+ * - 'ce' - Matches a constant expression (-5 or √3) [Expressions consisting of only ConstantNodes, functions, and operators]
84
+ * - 'v' - Matches a variable; anything not matched by c (-5 or x) [Node that is not a ConstantNode]
85
+ * - 'vl' - Matches a variable literal (x or y) [SymbolNode]
86
+ * - 'vd' - Matches a non-decimal expression; anything not matched by cd (x or √3) [Node that is not a ConstantNode or unaryMinus that is wrapping a ConstantNode]
87
+ * - 've' - Matches a variable expression; anything not matched by ce (x or 2x) [Expressions that contain a SymbolNode or other non-constant term]
81
88
  *
82
89
  * The default list of rules is exposed on the function as `simplify.rules`
83
90
  * and can be used as a basis to built a set of custom rules. Note that since
@@ -250,7 +257,7 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
250
257
  }
251
258
  }
252
259
  }, {
253
- s: '-(c*v) -> v * (-c)',
260
+ s: '-(cl*v) -> v * (-cl)',
254
261
  // make non-constant terms positive
255
262
  assuming: {
256
263
  multiply: {
@@ -261,7 +268,7 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
261
268
  }
262
269
  }
263
270
  }, {
264
- s: '-(c*v) -> (-c) * v',
271
+ s: '-(cl*v) -> (-cl) * v',
265
272
  // non-commutative version, part 1
266
273
  assuming: {
267
274
  multiply: {
@@ -272,7 +279,7 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
272
279
  }
273
280
  }
274
281
  }, {
275
- s: '-(v*c) -> v * (-c)',
282
+ s: '-(v*cl) -> v * (-cl)',
276
283
  // non-commutative version, part 2
277
284
  assuming: {
278
285
  multiply: {
@@ -330,24 +337,24 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
330
337
  },
331
338
  // collect like factors; into a sum, only do this for nonconstants
332
339
  {
333
- l: ' v * ( v * n1 + n2)',
334
- r: 'v^2 * n1 + v * n2'
340
+ l: ' vd * ( vd * n1 + n2)',
341
+ r: 'vd^2 * n1 + vd * n2'
335
342
  }, {
336
- s: ' v * (v^n4 * n1 + n2) -> v^(1+n4) * n1 + v * n2',
343
+ s: ' vd * (vd^n4 * n1 + n2) -> vd^(1+n4) * n1 + vd * n2',
337
344
  assuming: {
338
345
  divide: {
339
346
  total: true
340
347
  }
341
348
  } // v*1/v = v^(1+-1) needs 1/v
342
349
  }, {
343
- s: 'v^n3 * ( v * n1 + n2) -> v^(n3+1) * n1 + v^n3 * n2',
350
+ s: 'vd^n3 * ( vd * n1 + n2) -> vd^(n3+1) * n1 + vd^n3 * n2',
344
351
  assuming: {
345
352
  divide: {
346
353
  total: true
347
354
  }
348
355
  }
349
356
  }, {
350
- s: 'v^n3 * (v^n4 * n1 + n2) -> v^(n3+n4) * n1 + v^n3 * n2',
357
+ s: 'vd^n3 * (vd^n4 * n1 + n2) -> vd^(n3+n4) * n1 + vd^n3 * n2',
351
358
  assuming: {
352
359
  divide: {
353
360
  total: true
@@ -390,8 +397,8 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
390
397
  l: 'n+-n',
391
398
  r: '0'
392
399
  }, {
393
- l: 'v*n + v',
394
- r: 'v*(n+1)'
400
+ l: 'vd*n + vd',
401
+ r: 'vd*(n+1)'
395
402
  },
396
403
  // NOTE: leftmost position is special:
397
404
  {
@@ -406,7 +413,7 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
406
413
  l: 'n3^(-n4)*n1 + n3^n5 * n2',
407
414
  r: 'n3^(-n4)*(n1 + n3^(n4+n5)*n2)'
408
415
  }, {
409
- s: 'n*v + v -> (n+1)*v',
416
+ s: 'n*vd + vd -> (n+1)*vd',
410
417
  // noncommutative additional cases
411
418
  assuming: {
412
419
  multiply: {
@@ -435,10 +442,10 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
435
442
  }
436
443
  }
437
444
  }, {
438
- l: 'n*c + c',
439
- r: '(n+1)*c'
445
+ l: 'n*cd + cd',
446
+ r: '(n+1)*cd'
440
447
  }, {
441
- s: 'c*n + c -> c*(n+1)',
448
+ s: 'cd*n + cd -> cd*(n+1)',
442
449
  assuming: {
443
450
  multiply: {
444
451
  commutative: false
@@ -469,7 +476,7 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
469
476
  },
470
477
  // final ordering of constants
471
478
  {
472
- s: 'c+v -> v+c',
479
+ s: 'ce+ve -> ve+ce',
473
480
  assuming: {
474
481
  add: {
475
482
  commutative: true
@@ -481,7 +488,7 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
481
488
  }
482
489
  }
483
490
  }, {
484
- s: 'v*c -> c*v',
491
+ s: 'vd*cd -> cd*vd',
485
492
  assuming: {
486
493
  multiply: {
487
494
  commutative: true
@@ -1047,9 +1054,8 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
1047
1054
  }
1048
1055
  } else if (rule instanceof SymbolNode) {
1049
1056
  // If the rule is a SymbolNode, then it carries a special meaning
1050
- // according to the first character of the symbol node name.
1051
- // c.* matches a ConstantNode
1052
- // n.* matches any node
1057
+ // according to the first one or two characters of the symbol node name.
1058
+ // These meanings are expalined in the documentation for simplify()
1053
1059
  if (rule.name.length === 0) {
1054
1060
  throw new Error('Symbol in rule has 0 length...!?');
1055
1061
  }
@@ -1058,29 +1064,83 @@ export var createSimplify = /* #__PURE__ */factory(name, dependencies, _ref => {
1058
1064
  if (rule.name !== node.name) {
1059
1065
  return [];
1060
1066
  }
1061
- } else if (rule.name[0] === 'n' || rule.name.substring(0, 2) === '_p') {
1062
- // rule matches _anything_, so assign this node to the rule.name placeholder
1063
- // Assign node to the rule.name placeholder.
1064
- // Our parent will check for matches among placeholders.
1065
- res[0].placeholders[rule.name] = node;
1066
- } else if (rule.name[0] === 'v') {
1067
- // rule matches any variable thing (not a ConstantNode)
1068
- if (!isConstantNode(node)) {
1069
- res[0].placeholders[rule.name] = node;
1070
- } else {
1071
- // Mis-match: rule was expecting something other than a ConstantNode
1072
- return [];
1073
- }
1074
- } else if (rule.name[0] === 'c') {
1075
- // rule matches any ConstantNode
1076
- if (node instanceof ConstantNode) {
1077
- res[0].placeholders[rule.name] = node;
1078
- } else {
1079
- // Mis-match: rule was expecting a ConstantNode
1080
- return [];
1081
- }
1082
1067
  } else {
1083
- throw new Error('Invalid symbol in rule: ' + rule.name);
1068
+ // wildcards are composed of up to two alphabetic or underscore characters
1069
+ switch (rule.name[1] >= 'a' && rule.name[1] <= 'z' ? rule.name.substring(0, 2) : rule.name[0]) {
1070
+ case 'n':
1071
+ case '_p':
1072
+ // rule matches _anything_, so assign this node to the rule.name placeholder
1073
+ // Assign node to the rule.name placeholder.
1074
+ // Our parent will check for matches among placeholders.
1075
+ res[0].placeholders[rule.name] = node;
1076
+ break;
1077
+ case 'c':
1078
+ case 'cl':
1079
+ // rule matches a ConstantNode
1080
+ if (isConstantNode(node)) {
1081
+ res[0].placeholders[rule.name] = node;
1082
+ } else {
1083
+ // mis-match: rule does not encompass current node
1084
+ return [];
1085
+ }
1086
+ break;
1087
+ case 'v':
1088
+ // rule matches anything other than a ConstantNode
1089
+ if (!isConstantNode(node)) {
1090
+ res[0].placeholders[rule.name] = node;
1091
+ } else {
1092
+ // mis-match: rule does not encompass current node
1093
+ return [];
1094
+ }
1095
+ break;
1096
+ case 'vl':
1097
+ // rule matches VariableNode
1098
+ if (isVariableNode(node)) {
1099
+ res[0].placeholders[rule.name] = node;
1100
+ } else {
1101
+ // mis-match: rule does not encompass current node
1102
+ return [];
1103
+ }
1104
+ break;
1105
+ case 'cd':
1106
+ // rule matches a ConstantNode or unaryMinus-wrapped ConstantNode
1107
+ if (isNumericNode(node)) {
1108
+ res[0].placeholders[rule.name] = node;
1109
+ } else {
1110
+ // mis-match: rule does not encompass current node
1111
+ return [];
1112
+ }
1113
+ break;
1114
+ case 'vd':
1115
+ // rule matches anything other than a ConstantNode or unaryMinus-wrapped ConstantNode
1116
+ if (!isNumericNode(node)) {
1117
+ res[0].placeholders[rule.name] = node;
1118
+ } else {
1119
+ // mis-match: rule does not encompass current node
1120
+ return [];
1121
+ }
1122
+ break;
1123
+ case 'ce':
1124
+ // rule matches expressions that have a constant value
1125
+ if (isConstantExpression(node)) {
1126
+ res[0].placeholders[rule.name] = node;
1127
+ } else {
1128
+ // mis-match: rule does not encompass current node
1129
+ return [];
1130
+ }
1131
+ break;
1132
+ case 've':
1133
+ // rule matches expressions that do not have a constant value
1134
+ if (!isConstantExpression(node)) {
1135
+ res[0].placeholders[rule.name] = node;
1136
+ } else {
1137
+ // mis-match: rule does not encompass current node
1138
+ return [];
1139
+ }
1140
+ break;
1141
+ default:
1142
+ throw new Error('Invalid symbol in rule: ' + rule.name);
1143
+ }
1084
1144
  }
1085
1145
  } else if (rule instanceof ConstantNode) {
1086
1146
  // Literal constant must match exactly
@@ -286,20 +286,37 @@ export var createSimplifyConstant = /* #__PURE__ */factory(name, dependencies, _
286
286
  * @return - Either a Node representing a binary expression or Fraction
287
287
  */
288
288
  function foldOp(fn, args, makeNode, options) {
289
- return args.reduce(function (a, b) {
290
- if (!isNode(a) && !isNode(b)) {
289
+ var first = args.shift();
290
+
291
+ // In the following reduction, sofar always has one of the three following
292
+ // forms: [NODE], [CONSTANT], or [NODE, CONSTANT]
293
+ var reduction = args.reduce((sofar, next) => {
294
+ if (!isNode(next)) {
295
+ var last = sofar.pop();
296
+ if (isNode(last)) {
297
+ return [last, next];
298
+ }
299
+ // Two constants in a row, try to fold them into one
291
300
  try {
292
- return _eval(fn, [a, b], options);
293
- } catch (ignoreandcontinue) {}
294
- a = _toNode(a);
295
- b = _toNode(b);
296
- } else if (!isNode(a)) {
297
- a = _toNode(a);
298
- } else if (!isNode(b)) {
299
- b = _toNode(b);
301
+ sofar.push(_eval(fn, [last, next], options));
302
+ return sofar;
303
+ } catch (ignoreandcontinue) {
304
+ sofar.push(last);
305
+ // fall through to Node case
306
+ }
300
307
  }
301
- return makeNode([a, b]);
302
- });
308
+
309
+ // Encountered a Node, or failed folding --
310
+ // collapse everything so far into a single tree:
311
+ sofar.push(_ensureNode(sofar.pop()));
312
+ var newtree = sofar.length === 1 ? sofar[0] : makeNode(sofar);
313
+ return [makeNode([newtree, _ensureNode(next)])];
314
+ }, [first]);
315
+ if (reduction.length === 1) {
316
+ return reduction[0];
317
+ }
318
+ // Might end up with a tree and a constant at the end:
319
+ return makeNode([reduction[0], _toNode(reduction[1])]);
303
320
  }
304
321
 
305
322
  // destroys the original node and returns a folded one