@cortex-js/compute-engine 0.9.0 → 0.10.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 (83) hide show
  1. package/dist/compute-engine.esm.js +370 -220
  2. package/dist/compute-engine.min.esm.js +2 -2
  3. package/dist/compute-engine.min.js +2 -2
  4. package/dist/math-json.esm.js +2 -2
  5. package/dist/math-json.min.esm.js +2 -2
  6. package/dist/math-json.min.js +2 -2
  7. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  8. package/dist/types/common/signals.d.ts +1 -1
  9. package/dist/types/common/utils.d.ts +1 -1
  10. package/dist/types/compute-engine/assume.d.ts +1 -1
  11. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +1 -2
  12. package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
  13. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
  14. package/dist/types/compute-engine/boxed-expression/boxed-domain.d.ts +1 -1
  15. package/dist/types/compute-engine/boxed-expression/boxed-function-definition.d.ts +1 -1
  16. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +1 -2
  17. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -2
  18. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  19. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -2
  20. package/dist/types/compute-engine/boxed-expression/boxed-symbol-definition.d.ts +2 -3
  21. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +1 -2
  22. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  23. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  24. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  25. package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
  26. package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
  27. package/dist/types/compute-engine/compute-engine.d.ts +3 -2
  28. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  29. package/dist/types/compute-engine/domain-utils.d.ts +1 -1
  30. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  31. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  32. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  33. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  34. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-inequalities.d.ts +1 -1
  35. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
  36. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  37. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  38. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  39. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  40. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
  41. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
  42. package/dist/types/compute-engine/latex-syntax/parse.d.ts +1 -1
  43. package/dist/types/compute-engine/latex-syntax/public.d.ts +1 -1
  44. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  45. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  46. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
  47. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  48. package/dist/types/compute-engine/library/arithmetic-add.d.ts +1 -1
  49. package/dist/types/compute-engine/library/arithmetic-divide.d.ts +1 -1
  50. package/dist/types/compute-engine/library/arithmetic-multiply.d.ts +1 -1
  51. package/dist/types/compute-engine/library/arithmetic-power.d.ts +1 -1
  52. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  53. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  54. package/dist/types/compute-engine/library/collections.d.ts +1 -1
  55. package/dist/types/compute-engine/library/core.d.ts +1 -1
  56. package/dist/types/compute-engine/library/domains.d.ts +1 -1
  57. package/dist/types/compute-engine/library/library.d.ts +1 -1
  58. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  59. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  60. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  61. package/dist/types/compute-engine/library/sets.d.ts +1 -1
  62. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  63. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  64. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  65. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  66. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  67. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  68. package/dist/types/compute-engine/public.d.ts +12 -14
  69. package/dist/types/compute-engine/rules.d.ts +1 -1
  70. package/dist/types/compute-engine/simplify-rules.d.ts +1 -1
  71. package/dist/types/compute-engine/solve.d.ts +1 -1
  72. package/dist/types/compute-engine/symbolic/expand.d.ts +1 -1
  73. package/dist/types/compute-engine/symbolic/flatten.d.ts +1 -1
  74. package/dist/types/compute-engine/symbolic/negate.d.ts +1 -1
  75. package/dist/types/compute-engine/symbolic/polynomials.d.ts +1 -1
  76. package/dist/types/compute-engine/symbolic/product.d.ts +1 -1
  77. package/dist/types/compute-engine/symbolic/sum.d.ts +1 -1
  78. package/dist/types/compute-engine/symbolic/utils.d.ts +1 -1
  79. package/dist/types/compute-engine.d.ts +2 -2
  80. package/dist/types/math-json/math-json-format.d.ts +1 -1
  81. package/dist/types/math-json/utils.d.ts +1 -1
  82. package/dist/types/math-json.d.ts +2 -2
  83. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- /** CortexJS Compute Engine 0.9.0 */
1
+ /** CortexJS Compute Engine 0.10.0 */
2
2
  /** @internal */
3
3
  function isSymbolEntry(entry) {
4
4
  return !('kind' in entry) || entry.kind === 'symbol';
@@ -13988,6 +13988,8 @@ function primeFactors$1(n) {
13988
13988
  *
13989
13989
  */
13990
13990
  function factorPower$1(n, exponent) {
13991
+ if (n >= Number.MAX_SAFE_INTEGER)
13992
+ return [1, n];
13991
13993
  // @todo: handle negative n
13992
13994
  console.assert(Number.isInteger(n) && n > 0 && n < Number.MAX_SAFE_INTEGER);
13993
13995
  const factors = primeFactors$1(n);
@@ -14562,6 +14564,9 @@ function validateArgumentCount(ce, ops, count) {
14562
14564
  * the number of expected arguments.
14563
14565
  */
14564
14566
  function validateNumericArgs(ce, ops, count) {
14567
+ // @fastpath
14568
+ if (!ce.strict)
14569
+ return ops.map((x) => ce.box(x));
14565
14570
  let xs = [];
14566
14571
  if (count === undefined) {
14567
14572
  xs = ops.map((x) => ce.box(x));
@@ -14585,6 +14590,9 @@ function validateNumericArgs(ce, ops, count) {
14585
14590
  */
14586
14591
  function validateSignature(sig, ops, codomain) {
14587
14592
  const ce = sig.engine;
14593
+ // @fastpath
14594
+ if (!ce.strict)
14595
+ return ops;
14588
14596
  const opsDomain = ops.map((x) => x.domain);
14589
14597
  const targetSig = ce.domain([
14590
14598
  'Function',
@@ -14996,7 +15004,8 @@ function asMachineRational(r) {
14996
15004
  * @returns
14997
15005
  */
14998
15006
  function add(lhs, rhs) {
14999
- console.assert(Array.isArray(rhs) || (rhs.isLiteral && !(rhs instanceof Complex)));
15007
+ console.assert(Array.isArray(rhs) ||
15008
+ (rhs.numericValue !== null && !(rhs instanceof Complex)));
15000
15009
  if (Array.isArray(rhs)) {
15001
15010
  if (isBigRational(rhs))
15002
15011
  return [rhs[1].mul(lhs[0]).add(rhs[0].mul(lhs[1])), rhs[1].mul(lhs[1])];
@@ -15034,7 +15043,8 @@ function add(lhs, rhs) {
15034
15043
  return lhs;
15035
15044
  }
15036
15045
  function mul(lhs, rhs) {
15037
- console.assert(Array.isArray(rhs) || (rhs.isLiteral && !(rhs instanceof Complex)));
15046
+ console.assert(Array.isArray(rhs) ||
15047
+ (rhs.numericValue !== null && !(rhs instanceof Complex)));
15038
15048
  if (Array.isArray(rhs)) {
15039
15049
  if (isBigRational(lhs))
15040
15050
  return [lhs[0].mul(rhs[0]), lhs[1].mul(rhs[1])];
@@ -15199,7 +15209,7 @@ function asCoefficient(expr) {
15199
15209
  //
15200
15210
  if (expr.head === 'Power') {
15201
15211
  // We can only extract a coef if the exponent is a literal
15202
- if (!expr.op2.isLiteral)
15212
+ if (expr.op2.numericValue === null)
15203
15213
  return [[1, 1], expr];
15204
15214
  // eslint-disable-next-line prefer-const
15205
15215
  let [coef, base] = asCoefficient(expr.op1);
@@ -15274,7 +15284,9 @@ function signDiff(lhs, rhs, tolerance) {
15274
15284
  return 0;
15275
15285
  const lhsN = lhs.N();
15276
15286
  const rhsN = rhs.N();
15277
- if (!lhsN.isLiteral || !rhsN.isLiteral) {
15287
+ const lhsNum = lhsN.numericValue;
15288
+ const rhsNum = rhsN.numericValue;
15289
+ if (lhsNum === null || rhsNum === null) {
15278
15290
  // Couldn't calculate a numeric value, use the `sgn`
15279
15291
  const lhsS = lhs.sgn;
15280
15292
  const rhsS = rhs.sgn;
@@ -15289,8 +15301,6 @@ function signDiff(lhs, rhs, tolerance) {
15289
15301
  return undefined;
15290
15302
  }
15291
15303
  tolerance ?? (tolerance = lhs.engine.tolerance);
15292
- const lhsNum = lhsN.numericValue;
15293
- const rhsNum = rhsN.numericValue;
15294
15304
  if (lhsNum instanceof Complex && rhsNum instanceof Complex)
15295
15305
  return chop(lhsNum.re - rhsNum.re, tolerance) === 0 &&
15296
15306
  chop(lhsNum.im - rhsNum.im, tolerance) === 0
@@ -15322,11 +15332,11 @@ function negateLiteral(expr, metadata) {
15322
15332
  return null;
15323
15333
  if (typeof n === 'number')
15324
15334
  n = -n;
15325
- if (n instanceof Decimal)
15335
+ else if (n instanceof Decimal)
15326
15336
  n = n.neg();
15327
- if (n instanceof complex.exports.Complex)
15337
+ else if (n instanceof complex.exports.Complex)
15328
15338
  n = n.neg();
15329
- if (Array.isArray(n))
15339
+ else if (Array.isArray(n))
15330
15340
  n = neg(n);
15331
15341
  return expr.engine.number(n, { metadata });
15332
15342
  }
@@ -15344,7 +15354,7 @@ function canonicalNegate(expr, metadata) {
15344
15354
  if (expr.head === 'Negate')
15345
15355
  return validateArgument(expr.engine, expr.op1?.canonical, 'Number');
15346
15356
  expr = validateArgument(expr.engine, expr.canonical, 'Number');
15347
- if (expr.isLiteral)
15357
+ if (expr.numericValue !== null)
15348
15358
  return negateLiteral(expr, metadata);
15349
15359
  // Distribute over addition
15350
15360
  // Negate(Add(a, b)) -> Add(Negate(a), Negate(b))
@@ -15369,10 +15379,10 @@ function canonicalNegate(expr, metadata) {
15369
15379
  * `canonical` chain.
15370
15380
  */
15371
15381
  function distributeNegate(expr) {
15382
+ if (expr.numericValue !== null)
15383
+ return negateLiteral(expr);
15372
15384
  if (expr.head === 'Negate')
15373
15385
  return expr.op1;
15374
- if (expr.isLiteral)
15375
- return negateLiteral(expr);
15376
15386
  const ce = expr.engine;
15377
15387
  // Distribute over addition
15378
15388
  // Negate(Add(a, b)) -> Add(Negate(a), Negate(b))
@@ -15414,7 +15424,7 @@ function negateProduct(ce, args) {
15414
15424
  // else If there is a literal integer, negate it
15415
15425
  result = [];
15416
15426
  for (const arg of args) {
15417
- if (done || !arg.isLiteral || !arg.isInteger)
15427
+ if (done || arg.numericValue === null || !arg.isInteger)
15418
15428
  result.push(arg);
15419
15429
  else {
15420
15430
  done = true;
@@ -15426,7 +15436,7 @@ function negateProduct(ce, args) {
15426
15436
  // else If there is a literal number, negate it
15427
15437
  result = [];
15428
15438
  for (const arg of args) {
15429
- if (done || !arg.isLiteral || !arg.isNumber)
15439
+ if (done || arg.numericValue === null || !arg.isNumber)
15430
15440
  result.push(arg);
15431
15441
  else {
15432
15442
  done = true;
@@ -16185,9 +16195,6 @@ class AbstractBoxedExpression {
16185
16195
  get url() {
16186
16196
  return undefined;
16187
16197
  }
16188
- get isLiteral() {
16189
- return false;
16190
- }
16191
16198
  get wikidata() {
16192
16199
  return this._wikidata;
16193
16200
  }
@@ -16285,7 +16292,7 @@ class AbstractBoxedExpression {
16285
16292
  * `3√2x^5y^3` -> 8 (5 + 3)
16286
16293
  */
16287
16294
  function totalDegree(expr) {
16288
- if (expr.head === 'Power' && expr.op2.isLiteral) {
16295
+ if (expr.head === 'Power' && expr.op2.numericValue !== null) {
16289
16296
  const deg = asSmallInteger(expr.op2);
16290
16297
  if (deg !== null && deg > 0)
16291
16298
  return deg;
@@ -16310,7 +16317,7 @@ function totalDegree(expr) {
16310
16317
  *
16311
16318
  */
16312
16319
  function maxDegree(expr) {
16313
- if (expr.head === 'Power' && expr.op2.isLiteral) {
16320
+ if (expr.head === 'Power' && expr.op2.numericValue !== null) {
16314
16321
  const deg = asSmallInteger(expr.op2);
16315
16322
  if (deg !== null && deg > 0)
16316
16323
  return deg;
@@ -16404,17 +16411,17 @@ function order(a, b) {
16404
16411
  // 1/ Literal numeric values
16405
16412
  //
16406
16413
  const af = asFloat(a);
16407
- if (a.isLiteral && af !== null) {
16414
+ if (af !== null) {
16408
16415
  const bf = asFloat(b);
16409
- if (b.isLiteral && bf !== null)
16416
+ if (bf !== null)
16410
16417
  return af - bf;
16411
16418
  return -1;
16412
16419
  }
16413
16420
  //
16414
16421
  // 2/ Complex numbers
16415
16422
  //
16416
- if (a.isLiteral && a.numericValue instanceof Complex) {
16417
- if (b.isLiteral && b.numericValue instanceof Complex) {
16423
+ if (a.numericValue instanceof Complex) {
16424
+ if (b.numericValue instanceof Complex) {
16418
16425
  if (a.numericValue.re === b.numericValue.re) {
16419
16426
  if (Math.abs(a.numericValue.im) === Math.abs(b.numericValue.im)) {
16420
16427
  return a.numericValue.im - b.numericValue.im;
@@ -16423,7 +16430,7 @@ function order(a, b) {
16423
16430
  }
16424
16431
  return a.numericValue.re - b.numericValue.re;
16425
16432
  }
16426
- if (b.isLiteral && b.isNumber)
16433
+ if (b.numericValue !== null)
16427
16434
  return +1;
16428
16435
  return -1;
16429
16436
  }
@@ -16436,7 +16443,7 @@ function order(a, b) {
16436
16443
  return 0;
16437
16444
  return a.symbol > b.symbol ? 1 : -1;
16438
16445
  }
16439
- if (b.isLiteral && b.isNumber)
16446
+ if (b.numericValue !== null)
16440
16447
  return +1;
16441
16448
  return -1;
16442
16449
  }
@@ -16466,7 +16473,7 @@ function order(a, b) {
16466
16473
  }
16467
16474
  return aComplexity - bComplexity;
16468
16475
  }
16469
- if ((b.isLiteral && b.isNumber) || b.symbol)
16476
+ if (b.numericValue !== null || b.symbol)
16470
16477
  return +1;
16471
16478
  return -1;
16472
16479
  }
@@ -16589,7 +16596,7 @@ class Product {
16589
16596
  // }
16590
16597
  // If we're calculation a canonical product, fold exact literals into
16591
16598
  // running terms
16592
- if (term.isLiteral) {
16599
+ if (term.numericValue !== null) {
16593
16600
  if (term.isOne)
16594
16601
  return;
16595
16602
  if (term.isZero) {
@@ -16608,9 +16615,10 @@ class Product {
16608
16615
  }
16609
16616
  let num = term.numericValue;
16610
16617
  if (typeof num === 'number') {
16611
- if (num < 0)
16618
+ if (num < 0) {
16612
16619
  this._sign *= -1;
16613
- num = Math.abs(num);
16620
+ num = -num;
16621
+ }
16614
16622
  if (Number.isInteger(num))
16615
16623
  this._rational = mul(this._rational, [num, 1]);
16616
16624
  else if (bignumPreferred(this.engine))
@@ -16661,11 +16669,11 @@ class Product {
16661
16669
  }
16662
16670
  }
16663
16671
  // Note: rest should be positive, so no need to handle the -1 case
16664
- if (rest.isLiteral && rest.isOne)
16672
+ if (rest.numericValue !== null && rest.isOne)
16665
16673
  return;
16666
16674
  // If this is a power expression, extract the exponent
16667
16675
  let exponent = [1, 1];
16668
- if (rest.head === 'Power' && rest.op2.isLiteral) {
16676
+ if (rest.head === 'Power') {
16669
16677
  // Term is `Power(op1, op2)`
16670
16678
  const r = asRational(rest.op2);
16671
16679
  if (r) {
@@ -16726,38 +16734,36 @@ class Product {
16726
16734
  return [];
16727
16735
  return [{ exponent: [1, 1], terms: [ce.number(b)] }];
16728
16736
  }
16729
- else {
16730
- // Machine preferred
16731
- let n = 1;
16732
- if (!isRationalOne(this._rational)) {
16733
- if (isBigRational(this._rational))
16734
- n = this._rational[0].toNumber() / this._rational[1].toNumber();
16735
- else
16736
- n = this._rational[0] / this._rational[1];
16737
- }
16738
- // if (!isRationalOne(this._squareRootRational)) {
16739
- // if (isBigRational(this._squareRootRational))
16740
- // n *= Math.sqrt(
16741
- // this._squareRootRational[0].toNumber() /
16742
- // this._squareRootRational[1].toNumber()
16743
- // );
16744
- // else
16745
- // n *= Math.sqrt(
16746
- // this._squareRootRational[0] / this._squareRootRational[1]
16747
- // );
16748
- // }
16749
- n *= this._sign * this._number * this._bignum.toNumber();
16750
- if (this._complex.im !== 0) {
16751
- const z = this._complex.mul(n);
16752
- if (z.equals(1))
16753
- return [];
16754
- return [{ exponent: [1, 1], terms: [ce.number(z)] }];
16755
- }
16756
- n *= this._complex.re;
16757
- if (n === 1)
16737
+ // Machine preferred
16738
+ let n = 1;
16739
+ if (!isRationalOne(this._rational)) {
16740
+ if (isBigRational(this._rational))
16741
+ n = this._rational[0].toNumber() / this._rational[1].toNumber();
16742
+ else
16743
+ n = this._rational[0] / this._rational[1];
16744
+ }
16745
+ // if (!isRationalOne(this._squareRootRational)) {
16746
+ // if (isBigRational(this._squareRootRational))
16747
+ // n *= Math.sqrt(
16748
+ // this._squareRootRational[0].toNumber() /
16749
+ // this._squareRootRational[1].toNumber()
16750
+ // );
16751
+ // else
16752
+ // n *= Math.sqrt(
16753
+ // this._squareRootRational[0] / this._squareRootRational[1]
16754
+ // );
16755
+ // }
16756
+ n *= this._sign * this._number * this._bignum.toNumber();
16757
+ if (this._complex.im !== 0) {
16758
+ const z = this._complex.mul(n);
16759
+ if (z.equals(1))
16758
16760
  return [];
16759
- return [{ exponent: [1, 1], terms: [ce.number(n)] }];
16761
+ return [{ exponent: [1, 1], terms: [ce.number(z)] }];
16760
16762
  }
16763
+ n *= this._complex.re;
16764
+ if (n === 1)
16765
+ return [];
16766
+ return [{ exponent: [1, 1], terms: [ce.number(n)] }];
16761
16767
  }
16762
16768
  //
16763
16769
  // Terms of degree 1 (exponent = [1,1])
@@ -16795,7 +16801,12 @@ class Product {
16795
16801
  });
16796
16802
  }
16797
16803
  else {
16798
- unitTerms.push(ce.number(this._rational));
16804
+ if (n === -1) {
16805
+ unitTerms.push(ce.number(neg(this._rational)));
16806
+ n = 1;
16807
+ }
16808
+ else
16809
+ unitTerms.push(ce.number(this._rational));
16799
16810
  }
16800
16811
  }
16801
16812
  // if (!isRationalOne(this._squareRootRational)) {
@@ -16926,7 +16937,7 @@ class Product {
16926
16937
  }
16927
16938
  asRationalExpression() {
16928
16939
  const [numerator, denominator] = this.asNumeratorDenominator();
16929
- if (denominator.isLiteral) {
16940
+ if (denominator.numericValue !== null) {
16930
16941
  if (denominator.isOne)
16931
16942
  return numerator;
16932
16943
  if (denominator.isNegativeOne)
@@ -16992,7 +17003,7 @@ function termsAsExpressions(ce, terms) {
16992
17003
  }
16993
17004
 
16994
17005
  function subtract(ce, a, b, metadata) {
16995
- if (a.isLiteral) {
17006
+ if (a.numericValue !== null) {
16996
17007
  if (isRational(a.numericValue)) {
16997
17008
  if (machineNumerator(a.numericValue) < 0) {
16998
17009
  return serializeJsonFunction(ce, 'Subtract', [b, ce.number(neg(a.numericValue))], metadata);
@@ -17025,7 +17036,7 @@ function serializeJsonCanonicalFunction(ce, head, args, metadata) {
17025
17036
  return serializeJsonFunction(ce, 'Multiply', [args[0], ce._fn('Power', [args[1], ce._NEGATIVE_ONE])], metadata);
17026
17037
  }
17027
17038
  if (head === 'Multiply' && !exclusions.includes('Negate')) {
17028
- if (args[0]?.isLiteral && asFloat(args[0]) === -1)
17039
+ if (asFloat(args[0]) === -1)
17029
17040
  return serializeJsonFunction(ce, 'Negate', [ce._fn('Multiply', args.slice(1))], metadata);
17030
17041
  }
17031
17042
  if (head === 'Multiply' && !exclusions.includes('Divide')) {
@@ -17040,7 +17051,7 @@ function serializeJsonCanonicalFunction(ce, head, args, metadata) {
17040
17051
  if (head === 'Power') {
17041
17052
  if (!exclusions.includes('Exp') && args[0]?.symbol === 'ExponentialE')
17042
17053
  return serializeJsonFunction(ce, 'Exp', [args[1]], metadata);
17043
- if (args[1]?.isLiteral) {
17054
+ if (args[1]?.numericValue !== null) {
17044
17055
  const exp = asSmallInteger(args[1]);
17045
17056
  if (exp === 2 && !exclusions.includes('Square'))
17046
17057
  return serializeJsonFunction(ce, 'Square', [args[0]], metadata);
@@ -17105,7 +17116,7 @@ function serializeJsonFunction(ce, head, args, metadata) {
17105
17116
  return serializeJsonFunction(ce, 'Add', [args[0], ce._fn('Multiply', [args[1], ce.symbol('ImaginaryUnit')])], metadata);
17106
17117
  if (head === 'Sqrt' && args.length === 1)
17107
17118
  return serializeJsonFunction(ce, 'Power', [args[0], exclusions.includes('Half') ? ce.number([1, 2]) : ce._HALF], metadata);
17108
- if (head === 'Root' && args.length === 2 && args[1].isLiteral) {
17119
+ if (head === 'Root' && args.length === 2 && args[1].numericValue !== null) {
17109
17120
  const n = asSmallInteger(args[1]);
17110
17121
  if (n === 2)
17111
17122
  return serializeJsonFunction(ce, 'Sqrt', [args[0]]);
@@ -17127,7 +17138,7 @@ function serializeJsonFunction(ce, head, args, metadata) {
17127
17138
  return serializeJsonFunction(ce, 'Negate', args, metadata);
17128
17139
  }
17129
17140
  if (head === 'Add' && args.length === 2 && !exclusions.includes('Subtract')) {
17130
- if (args[1].isLiteral) {
17141
+ if (args[1].numericValue !== null) {
17131
17142
  const t1 = asSmallInteger(args[1]);
17132
17143
  if (t1 !== null && t1 < 0)
17133
17144
  return serializeJsonFunction(ce, 'Subtract', [args[0], ce.number(-t1)], metadata);
@@ -17900,14 +17911,13 @@ class BoxedFunction extends AbstractBoxedExpression {
17900
17911
  set isCanonical(val) {
17901
17912
  this._canonical = val ? this : undefined;
17902
17913
  }
17903
- get isLiteral() {
17904
- return false;
17905
- }
17906
17914
  get isPure() {
17907
- if (!this.isCanonical)
17908
- return false;
17909
17915
  if (this._isPure !== undefined)
17910
17916
  return this._isPure;
17917
+ if (!this.isCanonical) {
17918
+ this._isPure = false;
17919
+ return false;
17920
+ }
17911
17921
  let result = undefined;
17912
17922
  if (this.functionDefinition?.pure !== undefined)
17913
17923
  result = this.functionDefinition.pure;
@@ -18113,9 +18123,7 @@ class BoxedFunction extends AbstractBoxedExpression {
18113
18123
  debugger;
18114
18124
  }
18115
18125
  get value() {
18116
- if (!this.isCanonical)
18117
- return undefined;
18118
- if (!this.isPure)
18126
+ if (!this.isCanonical || !this.isPure)
18119
18127
  return undefined;
18120
18128
  // Use cached value if the function is pure
18121
18129
  if (!this._value)
@@ -18459,12 +18467,12 @@ class BoxedFunction extends AbstractBoxedExpression {
18459
18467
  //
18460
18468
  // 1/ Use canonical form
18461
18469
  //
18462
- if (!this.isValid)
18470
+ if (this._numericValue)
18471
+ return this._numericValue;
18472
+ if (this.engine.strict && !this.isValid)
18463
18473
  return this;
18464
18474
  if (!this.isCanonical)
18465
18475
  return this.canonical.N(options);
18466
- if (this._numericValue)
18467
- return this._numericValue;
18468
18476
  //
18469
18477
  // 2/ Evaluate the applicable operands
18470
18478
  //
@@ -18541,7 +18549,7 @@ function makeNumericFunction(ce, head, semiOps, metadata) {
18541
18549
  return ce.power(ops[0], ce.number(2), metadata);
18542
18550
  if (head === 'Sqrt') {
18543
18551
  const op = ops[0].canonical;
18544
- if (op.isLiteral && op.isRational)
18552
+ if (isRational(op.numericValue))
18545
18553
  return new BoxedFunction(ce, 'Sqrt', [op], { metadata, canonical: true });
18546
18554
  return ce.power(op, ce.number([1, 2]), metadata);
18547
18555
  }
@@ -18895,12 +18903,13 @@ class BoxedNumber extends AbstractBoxedExpression {
18895
18903
  * range
18896
18904
  */
18897
18905
  constructor(ce, value, options) {
18898
- options ?? (options = {});
18899
- super(ce, options.metadata);
18900
- this._isCanonical = true;
18906
+ super(ce, options?.metadata);
18907
+ if (typeof value === 'number') {
18908
+ this._value = value;
18909
+ this._isCanonical = true;
18910
+ return;
18911
+ }
18901
18912
  if (isRational(value)) {
18902
- if (!('canonical' in options))
18903
- options.canonical = true;
18904
18913
  //
18905
18914
  // This is a rational (or big rational)
18906
18915
  //
@@ -18909,7 +18918,7 @@ class BoxedNumber extends AbstractBoxedExpression {
18909
18918
  (Number.isInteger(n) && Number.isInteger(d) && d !== n && d !== 1));
18910
18919
  console.assert(!(n instanceof Decimal && d instanceof Decimal) ||
18911
18920
  (n.isInteger() && d.isInteger() && !d.eq(n) && !d.eq(1)));
18912
- if (options.canonical) {
18921
+ if (options?.canonical ?? true) {
18913
18922
  this._value = canonicalNumber(ce, value);
18914
18923
  this._isCanonical = true;
18915
18924
  }
@@ -18931,7 +18940,6 @@ class BoxedNumber extends AbstractBoxedExpression {
18931
18940
  this._value = canonicalNumber(ce, value);
18932
18941
  this._isCanonical = true;
18933
18942
  }
18934
- ce._register(this);
18935
18943
  }
18936
18944
  get hash() {
18937
18945
  if (this._hash !== undefined)
@@ -18954,9 +18962,6 @@ class BoxedNumber extends AbstractBoxedExpression {
18954
18962
  get isPure() {
18955
18963
  return true;
18956
18964
  }
18957
- get isLiteral() {
18958
- return true;
18959
- }
18960
18965
  get isExact() {
18961
18966
  if (typeof this._value === 'number')
18962
18967
  return Number.isInteger(this._value);
@@ -19386,9 +19391,6 @@ class BoxedString extends AbstractBoxedExpression {
19386
19391
  get isPure() {
19387
19392
  return true;
19388
19393
  }
19389
- get isLiteral() {
19390
- return true;
19391
- }
19392
19394
  get isCanonical() {
19393
19395
  return true;
19394
19396
  }
@@ -19722,7 +19724,7 @@ function boxFunction(ce, head, ops, options) {
19722
19724
  if (key.isValid && !key.isNothing) {
19723
19725
  const value = arg.op2;
19724
19726
  let k = key.symbol ?? key.string;
19725
- if (!k && key.isLiteral) {
19727
+ if (!k && (key.numericValue !== null || key.string)) {
19726
19728
  const n = typeof key.numericValue === 'number'
19727
19729
  ? key.numericValue
19728
19730
  : asSmallInteger(key);
@@ -19923,7 +19925,7 @@ class Sum {
19923
19925
  if (this._isCanonical) {
19924
19926
  if (term.isNothing)
19925
19927
  return;
19926
- if (term.isLiteral) {
19928
+ if (term.numericValue !== null) {
19927
19929
  if (term.isInfinity) {
19928
19930
  if (term.isPositive)
19929
19931
  this._posInfinityCount += 1;
@@ -19995,13 +19997,13 @@ class Sum {
19995
19997
  return;
19996
19998
  }
19997
19999
  let hasTerm = false;
19998
- if (!term.isLiteral) {
20000
+ if (term.numericValue === null) {
19999
20001
  // There's an overhead to calculate the hash.
20000
20002
  // For best results, only use the hash if there are many terms
20001
20003
  if (this._terms.length > 500) {
20002
20004
  const h = term.hash;
20003
20005
  for (let i = 0; i < this._terms.length; i++) {
20004
- if (!this._terms[i].term.isLiteral &&
20006
+ if (this._terms[i].term.numericValue === null &&
20005
20007
  h === this._terms[i].term.hash &&
20006
20008
  term.isSame(this._terms[i].term)) {
20007
20009
  this._terms[i].coef = add(this._terms[i].coef, coef);
@@ -20012,7 +20014,7 @@ class Sum {
20012
20014
  }
20013
20015
  else {
20014
20016
  for (let i = 0; i < this._terms.length; i++) {
20015
- if (!this._terms[i].term.isLiteral &&
20017
+ if (this._terms[i].term.numericValue === null &&
20016
20018
  term.isSame(this._terms[i].term)) {
20017
20019
  this._terms[i].coef = add(this._terms[i].coef, coef);
20018
20020
  hasTerm = true;
@@ -21034,7 +21036,7 @@ function canonicalAdd(ce, ops) {
21034
21036
  console.assert(ops.every((x) => x.isCanonical));
21035
21037
  ops = flattenOps(flattenSequence(ops.map((x) => x.canonical)), 'Add') ?? ops;
21036
21038
  // Remove literal 0
21037
- ops = ops.filter((x) => !(x.isLiteral && x.isZero));
21039
+ ops = ops.filter((x) => x.numericValue === null || !x.isZero);
21038
21040
  if (ops.length === 0)
21039
21041
  return ce.number(0);
21040
21042
  if (ops.length === 1)
@@ -21045,8 +21047,7 @@ function canonicalAdd(ce, ops) {
21045
21047
  if (ops.length === 2) {
21046
21048
  let im = 0;
21047
21049
  let re = 0;
21048
- if (ops[0].numericValue !== null)
21049
- re = asFloat(ops[0]);
21050
+ re = asFloat(ops[0]);
21050
21051
  if (re !== null && re !== 0)
21051
21052
  im = getImaginaryCoef(ops[1]);
21052
21053
  else {
@@ -21077,7 +21078,8 @@ function domainAdd(_ce, args) {
21077
21078
  function simplifyAdd(ce, args) {
21078
21079
  console.assert(args.length > 1, `simplifyAdd: not enough args`);
21079
21080
  const sum = new Sum(ce);
21080
- for (const arg of args) {
21081
+ for (let arg of args) {
21082
+ arg = arg.simplify();
21081
21083
  if (arg.isImaginary && arg.isInfinity)
21082
21084
  return ce.symbol('ComplexInfinity');
21083
21085
  if (arg.isNaN || arg.symbol === 'Undefined')
@@ -21087,7 +21089,25 @@ function simplifyAdd(ce, args) {
21087
21089
  }
21088
21090
  return sum.asExpression('expression');
21089
21091
  }
21092
+ function evalAddNum(ops) {
21093
+ let sum = 0;
21094
+ for (const op of ops) {
21095
+ const v = op.numericValue;
21096
+ if (typeof v === 'number')
21097
+ sum += v;
21098
+ else
21099
+ return null;
21100
+ }
21101
+ return sum;
21102
+ }
21090
21103
  function evalAdd(ce, ops, mode = 'evaluate') {
21104
+ // @fastpath
21105
+ if (mode === 'N' && ce.numericMode === 'machine') {
21106
+ ops = ops.map((x) => x.N());
21107
+ const sum = evalAddNum(ops);
21108
+ if (sum !== null)
21109
+ return ce.number(sum);
21110
+ }
21091
21111
  //
21092
21112
  // First pass: looking for early exits
21093
21113
  //
@@ -21102,6 +21122,8 @@ function evalAdd(ce, ops, mode = 'evaluate') {
21102
21122
  console.assert(flattenOps(ops, 'Add') === null);
21103
21123
  if (mode === 'N')
21104
21124
  ops = ops.map((x) => x.N());
21125
+ else
21126
+ ops = ops.map((x) => x.evaluate());
21105
21127
  return new Sum(ce, ops).asExpression(mode === 'N' ? 'numeric' : 'expression');
21106
21128
  }
21107
21129
  function canonicalSummation(ce, body, range) {
@@ -21198,7 +21220,7 @@ function evalSummation(ce, expr, range, mode) {
21198
21220
  if (!fn.scope)
21199
21221
  for (let i = lower; i <= upper; i++) {
21200
21222
  const term = fn.N();
21201
- if (!term.isLiteral)
21223
+ if (term.numericValue === null)
21202
21224
  return undefined;
21203
21225
  sum = add(sum, term);
21204
21226
  }
@@ -21206,7 +21228,7 @@ function evalSummation(ce, expr, range, mode) {
21206
21228
  for (let i = lower; i <= upper; i++) {
21207
21229
  ce.set({ [index]: i });
21208
21230
  const term = fn.N();
21209
- if (!term.isLiteral) {
21231
+ if (term.numericValue === null) {
21210
21232
  ce.context = savedContext;
21211
21233
  return undefined;
21212
21234
  }
@@ -21241,8 +21263,8 @@ function makePositive(expr) {
21241
21263
  return [1, expr];
21242
21264
  }
21243
21265
  function apply(expr, fn, bigFn, complexFn) {
21244
- console.assert(expr.isLiteral);
21245
21266
  const n = expr.numericValue;
21267
+ console.assert(n !== null);
21246
21268
  if (typeof n === 'number') {
21247
21269
  if (bignumPreferred(expr.engine) && bigFn)
21248
21270
  return expr.engine.chop(bigFn(expr.engine.bignum(n)));
@@ -21269,12 +21291,12 @@ function apply(expr, fn, bigFn, complexFn) {
21269
21291
  return NaN;
21270
21292
  }
21271
21293
  function applyN(expr, fn, bigFn, complexFn) {
21272
- if (!expr.isLiteral)
21294
+ if (expr.numericValue === null)
21273
21295
  return undefined;
21274
21296
  return expr.engine.number(apply(expr, fn, bigFn, complexFn));
21275
21297
  }
21276
21298
  function apply2(expr1, expr2, fn, bigFn, complexFn) {
21277
- console.assert(expr1.isLiteral && expr2.isLiteral);
21299
+ console.assert(expr1.numericValue !== null && expr2.numericValue !== null);
21278
21300
  const ce = expr1.engine;
21279
21301
  let m1 = expr1.numericValue;
21280
21302
  if (isMachineRational(m1))
@@ -21309,7 +21331,7 @@ function apply2(expr1, expr2, fn, bigFn, complexFn) {
21309
21331
  return NaN;
21310
21332
  }
21311
21333
  function apply2N(expr1, expr2, fn, bigFn, complexFn) {
21312
- if (!expr1.isLiteral || !expr2.isLiteral)
21334
+ if (expr1.numericValue === null || expr2.numericValue === null)
21313
21335
  return undefined;
21314
21336
  return expr1.engine.number(apply2(expr1, expr2, fn, bigFn, complexFn));
21315
21337
  }
@@ -21324,11 +21346,11 @@ function canonicalPower(ce, base, exponent, metadata) {
21324
21346
  exponent = validateArgument(ce, exponent?.canonical, 'Number');
21325
21347
  if (exponent.symbol === 'ComplexInfinity')
21326
21348
  return ce._NAN;
21327
- if (exponent.isLiteral) {
21349
+ if (exponent.numericValue !== null) {
21328
21350
  if (exponent.isZero)
21329
21351
  return ce._ONE;
21330
- if (base.isLiteral) {
21331
- const smallBase = asFloat(base);
21352
+ if (base.numericValue !== null) {
21353
+ const numBase = asFloat(base);
21332
21354
  //
21333
21355
  // Special cases
21334
21356
  //
@@ -21336,10 +21358,10 @@ function canonicalPower(ce, base, exponent, metadata) {
21336
21358
  // See https://docs.sympy.org/1.6/modules/core.html#pow
21337
21359
  //
21338
21360
  // if (base.isOne) return ce._ONE;
21339
- if (smallBase === 1)
21361
+ if (numBase === 1)
21340
21362
  return ce._ONE;
21341
21363
  // if (base.isZero) {
21342
- if (smallBase === 0) {
21364
+ if (numBase === 0) {
21343
21365
  if (exponent.isPositive)
21344
21366
  return ce._ZERO;
21345
21367
  if (exponent.isNegative)
@@ -21351,21 +21373,19 @@ function canonicalPower(ce, base, exponent, metadata) {
21351
21373
  // x^(-1)
21352
21374
  // if (base.isOne) return ce._ONE;
21353
21375
  // if (base.isNegativeOne) return ce._NEGATIVE_ONE;
21354
- if (smallBase === 1)
21376
+ if (numBase === 1)
21355
21377
  return ce._ONE;
21356
- if (smallBase === -1)
21378
+ if (numBase === -1)
21357
21379
  return ce._NEGATIVE_ONE;
21358
21380
  if (base.isInfinity)
21359
21381
  return ce._ZERO;
21360
21382
  const r = base.numericValue;
21361
- if (r !== null) {
21362
- if (typeof r === 'number' && Number.isInteger(r))
21363
- return ce.number([1, r], { metadata });
21364
- if (r instanceof Decimal && r.isInteger())
21365
- return ce.number([ce._BIGNUM_ONE, r], { metadata });
21366
- if (isRational(r))
21367
- return ce.number(inverse(r), { metadata });
21368
- }
21383
+ if (typeof r === 'number' && Number.isInteger(r))
21384
+ return ce.number([1, r], { metadata });
21385
+ if (r instanceof Decimal && r.isInteger())
21386
+ return ce.number([ce._BIGNUM_ONE, r], { metadata });
21387
+ if (isRational(r))
21388
+ return ce.number(inverse(r), { metadata });
21369
21389
  return ce._fn('Power', [base, ce._NEGATIVE_ONE], metadata);
21370
21390
  }
21371
21391
  // x^{0.5}, x^{1/2} -> Square Root
@@ -21597,7 +21617,7 @@ function processPower(ce, base, exponent, mode) {
21597
21617
  // If square root or cube root, attempt to factor out the perfect
21598
21618
  // factors: sqrt(75) -> 5^2 * 3
21599
21619
  //
21600
- if (mode !== 'N' && base.isLiteral && base.isInteger) {
21620
+ if (mode !== 'N' && base.numericValue !== null && base.isInteger) {
21601
21621
  const smallExpr = asSmallInteger(exponent);
21602
21622
  if (smallExpr)
21603
21623
  return numEvalPower(ce, base, exponent);
@@ -21632,7 +21652,8 @@ function processPower(ce, base, exponent, mode) {
21632
21652
  }
21633
21653
  }
21634
21654
  else if (typeof base.numericValue === 'number') {
21635
- if (d % 2 === 0 && base.numericValue < 0 && !complexAllowed(ce))
21655
+ // Square root of a negative number, and no complex allowed
21656
+ if (base.numericValue < 0 && d % 2 === 0 && !complexAllowed(ce))
21636
21657
  return ce._NAN;
21637
21658
  const [factor, root] = factorPower$1(Math.abs(base.numericValue), d);
21638
21659
  const sign = base.numericValue < 0
@@ -21662,7 +21683,9 @@ function processPower(ce, base, exponent, mode) {
21662
21683
  return undefined;
21663
21684
  }
21664
21685
  }
21665
- if (mode !== 'simplify' && base.isLiteral && exponent.isLiteral)
21686
+ if (mode !== 'simplify' &&
21687
+ base.numericValue !== null &&
21688
+ exponent.numericValue !== null)
21666
21689
  return numEvalPower(ce, base, exponent);
21667
21690
  return undefined;
21668
21691
  }
@@ -21777,22 +21800,46 @@ function canonicalMultiply(ce, ops) {
21777
21800
  return ops[0];
21778
21801
  if (ops.length === 2)
21779
21802
  return multiply2(ops[0], ops[1]);
21780
- return simplifyMultiply(ce, ops);
21781
- // return new Product(ce, ops).asExpression();
21803
+ const product = new Product(ce);
21804
+ for (const op of ops) {
21805
+ if (op.isNaN || op.symbol === 'Undefined')
21806
+ return ce._NAN;
21807
+ product.addTerm(op);
21808
+ }
21809
+ return product.asExpression();
21782
21810
  }
21783
21811
  function simplifyMultiply(ce, ops) {
21784
21812
  console.assert(flattenOps(ops, 'Multiply') === null);
21785
21813
  const product = new Product(ce);
21786
- for (const op of ops) {
21814
+ for (let op of ops) {
21815
+ op = op.simplify();
21787
21816
  if (op.isNaN || op.symbol === 'Undefined')
21788
21817
  return ce._NAN;
21789
21818
  product.addTerm(op);
21790
21819
  }
21791
21820
  return product.asExpression();
21792
21821
  }
21822
+ function fastEvalMultiply(ops) {
21823
+ let prod = 1;
21824
+ for (const op of ops) {
21825
+ if (typeof op.numericValue !== 'number')
21826
+ return null;
21827
+ prod *= op.numericValue;
21828
+ }
21829
+ return prod;
21830
+ }
21793
21831
  function evalMultiply(ce, ops, mode = 'evaluate') {
21794
21832
  console.assert(ops.length > 1, 'evalMultiply(): no arguments');
21795
21833
  //
21834
+ // @fastpath
21835
+ //
21836
+ if (mode === 'N' && ce.numericMode === 'machine') {
21837
+ ops = ops.map((x) => x.N());
21838
+ const result = fastEvalMultiply(ops);
21839
+ if (result !== null)
21840
+ return ce.number(result);
21841
+ }
21842
+ //
21796
21843
  // First pass: looking for early exits
21797
21844
  //
21798
21845
  for (const op of ops) {
@@ -21804,6 +21851,8 @@ function evalMultiply(ce, ops, mode = 'evaluate') {
21804
21851
  console.assert(flattenOps(ops, 'Multiply') === null);
21805
21852
  if (mode === 'N')
21806
21853
  ops = ops.map((x) => x.N());
21854
+ else
21855
+ ops = ops.map((x) => x.evaluate());
21807
21856
  //
21808
21857
  // Second pass
21809
21858
  //
@@ -21822,34 +21871,41 @@ function multiply2(op1, op2, metadata) {
21822
21871
  console.assert(op1.isCanonical);
21823
21872
  console.assert(op2.isCanonical);
21824
21873
  const ce = op1.engine;
21825
- if (op1.isLiteral && op2.isLiteral && op1.isInteger && op2.isInteger) {
21874
+ if (op1.numericValue !== null &&
21875
+ op2.numericValue !== null &&
21876
+ op1.isInteger &&
21877
+ op2.isInteger) {
21826
21878
  return (apply2N(op1, op2, (a, b) => a * b, (a, b) => a.mul(b)) ?? ce._NAN);
21827
21879
  }
21880
+ if (op1.isNaN ||
21881
+ op2.isNaN ||
21882
+ op1.symbol === 'Undefined' ||
21883
+ op2.symbol === 'Undefined')
21884
+ return ce._NAN;
21828
21885
  if (op1.isNothing)
21829
21886
  return op2;
21830
21887
  if (op2.isNothing)
21831
21888
  return op1;
21832
- if (op1.isLiteral && op1.isOne)
21833
- return op2;
21834
- if (op2.isLiteral && op2.isOne)
21835
- return op1;
21836
- if (op1.isLiteral && op1.isNegativeOne)
21837
- return canonicalNegate(op2);
21838
- if (op2.isLiteral && op2.isNegativeOne)
21839
- return canonicalNegate(op1);
21840
- let sign = 1;
21841
- let c = op1;
21842
- let t = op2;
21843
- if (!c.isLiteral) {
21844
- t = op2;
21845
- c = op1;
21889
+ if (op1.numericValue !== null) {
21890
+ if (op1.isOne)
21891
+ return op2;
21892
+ if (op1.isNegativeOne)
21893
+ return canonicalNegate(op2);
21894
+ }
21895
+ if (op2.numericValue !== null) {
21896
+ if (op2.isOne)
21897
+ return op1;
21898
+ if (op2.isNegativeOne)
21899
+ return canonicalNegate(op1);
21846
21900
  }
21901
+ let sign = 1;
21902
+ let [t, c] = op1.numericValue !== null ? [op1, op2] : [op2, op1];
21847
21903
  console.assert(t.head !== 'Subtract');
21848
21904
  if (t.head === 'Negate') {
21849
21905
  t = t.op1;
21850
21906
  sign = -sign;
21851
21907
  }
21852
- if (c.isLiteral) {
21908
+ if (c.numericValue !== null) {
21853
21909
  const r = asRational(c);
21854
21910
  if (r) {
21855
21911
  if (isRationalOne(r))
@@ -21861,12 +21917,10 @@ function multiply2(op1, op2, metadata) {
21861
21917
  c = canonicalNegate(c);
21862
21918
  return ce.add(t.ops.map((x) => multiply2(c, x)), metadata);
21863
21919
  }
21864
- if (t.isLiteral) {
21865
- const tr = asRational(t);
21866
- if (tr) {
21867
- const p = mul(r, tr);
21868
- return ce.number(sign < 0 ? neg(p) : p, { metadata });
21869
- }
21920
+ const tr = asRational(t);
21921
+ if (tr) {
21922
+ const p = mul(r, tr);
21923
+ return ce.number(sign < 0 ? neg(p) : p, { metadata });
21870
21924
  }
21871
21925
  if (sign < 0)
21872
21926
  return ce._fn('Multiply', [canonicalNegate(c), t], metadata);
@@ -21958,7 +22012,7 @@ function evalMultiplication(ce, expr, range, mode) {
21958
22012
  const n = ce.number(i);
21959
22013
  const r = fn.subs({ _1: n, _: n });
21960
22014
  const term = r.N();
21961
- if (!term.isLiteral)
22015
+ if (term.numericValue === null)
21962
22016
  return undefined;
21963
22017
  product = mul(product, term);
21964
22018
  }
@@ -21981,7 +22035,7 @@ function canonicalDivide(ce, op1, op2) {
21981
22035
  op2 = validateArgument(ce, op2, 'Number');
21982
22036
  if (!op1.isValid || !op2.isValid)
21983
22037
  return ce._fn('Divide', [op1, op2]);
21984
- if (op1.isLiteral && op2.isLiteral) {
22038
+ if (op1.numericValue !== null && op2.numericValue !== null) {
21985
22039
  if (op2.isOne)
21986
22040
  return op1;
21987
22041
  if (op2.isNegativeOne)
@@ -21999,25 +22053,25 @@ function canonicalDivide(ce, op1, op2) {
21999
22053
  (op2.head === 'Divide' || op2.head === 'Rational')) {
22000
22054
  return canonicalDivide(ce, ce.mul([op1.op1, op2.op2]), ce.mul([op1.op2, op2.op1]));
22001
22055
  }
22002
- if (op1.isLiteral) {
22003
- const r = op1.numericValue;
22004
- if (isMachineRational(r)) {
22005
- const [a, b] = r;
22056
+ const num1 = op1.numericValue;
22057
+ if (num1 !== null) {
22058
+ if (isMachineRational(num1)) {
22059
+ const [a, b] = num1;
22006
22060
  return canonicalDivide(ce, ce.mul([ce.number(a), op2]), ce.number(b));
22007
22061
  }
22008
- if (isBigRational(r)) {
22009
- const [a, b] = r;
22062
+ if (isBigRational(num1)) {
22063
+ const [a, b] = num1;
22010
22064
  return canonicalDivide(ce, ce.mul([ce.number(a), op2]), ce.number(b));
22011
22065
  }
22012
22066
  }
22013
- if (op2.isLiteral) {
22014
- const r = op2.numericValue;
22015
- if (isMachineRational(r)) {
22016
- const [a, b] = r;
22067
+ const num2 = op2.numericValue;
22068
+ if (num2 !== null) {
22069
+ if (isMachineRational(num2)) {
22070
+ const [a, b] = num2;
22017
22071
  return canonicalDivide(ce, ce.mul([op1, ce.number(b)]), ce.number(a));
22018
22072
  }
22019
- if (isBigRational(r)) {
22020
- const [a, b] = r;
22073
+ if (isBigRational(num2)) {
22074
+ const [a, b] = num2;
22021
22075
  return canonicalDivide(ce, ce.mul([op1, ce.number(b)]), ce.number(a));
22022
22076
  }
22023
22077
  }
@@ -22031,11 +22085,11 @@ function canonicalDivide(ce, op1, op2) {
22031
22085
  let [dSign, d] = makePositive(op2);
22032
22086
  n = n.canonical;
22033
22087
  d = d.canonical;
22034
- if (d.isLiteral && d.isOne)
22088
+ if (d.numericValue !== null && d.isOne)
22035
22089
  return nSign * dSign < 0 ? canonicalNegate(n) : n;
22036
22090
  // Divide: transform into multiply/power
22037
22091
  d = ce.inverse(d);
22038
- if (n.isLiteral) {
22092
+ if (n.numericValue !== null) {
22039
22093
  if (n.isOne)
22040
22094
  return d;
22041
22095
  if (n.isNegativeOne)
@@ -22049,7 +22103,7 @@ function canonicalDivide(ce, op1, op2) {
22049
22103
  * Simplify form of 'Divide' (and 'Rational')
22050
22104
  */
22051
22105
  function simplifyDivide(ce, op1, op2) {
22052
- if (op1.isLiteral && op2.isLiteral) {
22106
+ if (op1.numericValue !== null && op2.numericValue !== null) {
22053
22107
  const r1 = asRational(op1);
22054
22108
  const r2 = asRational(op2);
22055
22109
  if (r1 && r2 && !isRationalZero(r2))
@@ -22112,6 +22166,7 @@ const ARITHMETIC_LIBRARY = [
22112
22166
  threadable: true,
22113
22167
  idempotent: true,
22114
22168
  complexity: 1300,
22169
+ hold: 'all',
22115
22170
  signature: {
22116
22171
  domain: 'NumericFunction',
22117
22172
  codomain: (ce, args) => domainAdd(ce, args.map((x) => x.domain)),
@@ -22366,6 +22421,7 @@ const ARITHMETIC_LIBRARY = [
22366
22421
  commutative: true,
22367
22422
  idempotent: true,
22368
22423
  complexity: 2100,
22424
+ hold: 'all',
22369
22425
  signature: {
22370
22426
  domain: 'NumericFunction',
22371
22427
  canonical: (ce, args) => canonicalMultiply(ce, args),
@@ -22427,7 +22483,14 @@ const ARITHMETIC_LIBRARY = [
22427
22483
  canonical: (ce, args) => canonicalPower(ce, args[0], args[1]) ?? ce._fn('Power', args),
22428
22484
  simplify: (ce, ops) => processPower(ce, ops[0], ops[1], 'simplify'),
22429
22485
  evaluate: (ce, ops) => processPower(ce, ops[0], ops[1], 'evaluate'),
22430
- N: (ce, ops) => processPower(ce, ops[0], ops[1], 'N'),
22486
+ N: (ce, ops) => {
22487
+ // @fastpath
22488
+ if (ce.numericMode === 'machine' &&
22489
+ typeof ops[0].numericValue === 'number' &&
22490
+ typeof ops[1].numericValue === 'number')
22491
+ return ce.number(Math.pow(ops[0].numericValue, ops[1].numericValue));
22492
+ return processPower(ce, ops[0], ops[1], 'N');
22493
+ },
22431
22494
  // Defined as RealNumber for all power in RealNumber when base > 0;
22432
22495
  // when x < 0, only defined if n is an integer
22433
22496
  // if x is a non-zero complex, defined as ComplexNumber
@@ -23262,8 +23325,8 @@ const CORE_LIBRARY = [
23262
23325
  // Is it a string in a base form:
23263
23326
  // `"deadbeef"_{16}` `"0101010"_2?
23264
23327
  if (op1.string) {
23265
- if (op2.isLiteral && asSmallInteger(op2) !== null) {
23266
- const base = asSmallInteger(op2);
23328
+ const base = asSmallInteger(op2);
23329
+ if (base !== null) {
23267
23330
  if (base > 1 && base <= 36) {
23268
23331
  const [value, rest] = fromDigits(op1.string, base);
23269
23332
  if (rest) {
@@ -23280,9 +23343,7 @@ const CORE_LIBRARY = [
23280
23343
  if (op1.symbolDefinition?.at)
23281
23344
  return ce._fn('At', [op1, op2.canonical]);
23282
23345
  // Maybe a compound symbol
23283
- let sub = op2.string ?? op2.symbol;
23284
- if (!sub && op2.isLiteral && asSmallInteger(op2) !== null)
23285
- sub = asSmallInteger(op2).toString();
23346
+ const sub = op2.string ?? op2.symbol ?? asSmallInteger(op2)?.toString();
23286
23347
  if (sub)
23287
23348
  return ce.symbol(op1.symbol + '_' + sub);
23288
23349
  }
@@ -23304,10 +23365,7 @@ const CORE_LIBRARY = [
23304
23365
  if (ops.length === 0)
23305
23366
  return ce.symbol('Nothing');
23306
23367
  const arg = ops
23307
- .map((x) => x.symbol ??
23308
- x.string ??
23309
- (x.isLiteral ? asSmallInteger(x)?.toString() : null) ??
23310
- '')
23368
+ .map((x) => x.symbol ?? x.string ?? asSmallInteger(x)?.toString() ?? '')
23311
23369
  .join('');
23312
23370
  if (arg.length > 0)
23313
23371
  return ce.symbol(arg);
@@ -24445,7 +24503,7 @@ const TRIGONOMETRY_LIBRARY = [
24445
24503
  if (ops.length !== 1)
24446
24504
  return ce.box(['Degrees', ops]);
24447
24505
  const arg = validateArgument(ce, ops[0].canonical, 'Number');
24448
- if (!arg.isValid || !arg.isLiteral)
24506
+ if (arg.numericValue === null || !arg.isValid)
24449
24507
  return ce.box(['Degrees', arg]);
24450
24508
  return ce.mul([arg, ce.box(['Divide', 'Pi', 180])]);
24451
24509
  },
@@ -25066,7 +25124,7 @@ function constructibleValues(ce, head, x) {
25066
25124
  return cache;
25067
25125
  });
25068
25126
  x = x.N();
25069
- if (!x.isLiteral)
25127
+ if (x.numericValue === null)
25070
25128
  return undefined;
25071
25129
  let theta = asFloat(x) ?? null;
25072
25130
  if (theta === null)
@@ -25163,7 +25221,10 @@ function evalTrig(ce, mode, head, op) {
25163
25221
  case 'Artanh':
25164
25222
  return applyN(op, Math.atanh, (x) => x.atanh(), (x) => x.atanh());
25165
25223
  case 'Cos':
25166
- return applyN(op, Math.cos, (x) => x.cos(), (x) => x.cos());
25224
+ return applyN(op, Math.cos, (x) => x
25225
+ .toSignificantDigits(ce.precision + 4)
25226
+ .cos()
25227
+ .toSignificantDigits(ce.precision), (x) => x.cos());
25167
25228
  case 'Cosh':
25168
25229
  return applyN(op, Math.cosh, (x) => x.cosh(), (x) => x.cosh());
25169
25230
  case 'Cot':
@@ -25179,11 +25240,17 @@ function evalTrig(ce, mode, head, op) {
25179
25240
  case 'Sech':
25180
25241
  return applyN(op, (x) => 1 / Math.cosh(x), (x) => ce._BIGNUM_ONE.div(x.cosh()), (x) => x.cosh().inverse());
25181
25242
  case 'Sin':
25182
- return applyN(op, Math.sin, (x) => x.sin(), (x) => x.sin());
25243
+ return applyN(op, Math.sin, (x) => x
25244
+ .toSignificantDigits(ce.precision + 4)
25245
+ .sin()
25246
+ .toSignificantDigits(ce.precision), (x) => x.sin());
25183
25247
  case 'Sinh':
25184
25248
  return applyN(op, Math.sinh, (x) => x.sinh(), (x) => x.sinh());
25185
25249
  case 'Tan':
25186
- return applyN(op, Math.tan, (x) => x.tan(), (x) => x.tan());
25250
+ return applyN(op, Math.tan, (x) => x
25251
+ .toSignificantDigits(ce.precision + 4)
25252
+ .tan()
25253
+ .toSignificantDigits(ce.precision), (x) => x.tan());
25187
25254
  case 'Tanh':
25188
25255
  return applyN(op, Math.tanh, (x) => x.tanh(), (x) => x.tanh());
25189
25256
  }
@@ -25429,8 +25496,6 @@ function valueToFlags(value) {
25429
25496
  finite: value.isFinite,
25430
25497
  even: value.isEven,
25431
25498
  odd: value.isOdd,
25432
- prime: value.isPrime,
25433
- composite: value.isComposite,
25434
25499
  });
25435
25500
  }
25436
25501
  class BoxedSymbolDefinitionImpl {
@@ -25549,11 +25614,47 @@ class BoxedSymbolDefinitionImpl {
25549
25614
  this.bind();
25550
25615
  if (this.constant)
25551
25616
  throw new Error(`The value of the constant "${this.name}" cannot be changed`);
25552
- if (typeof val === 'number')
25617
+ if (typeof val === 'number') {
25618
+ if (typeof this._value?.numericValue === 'number') {
25619
+ this._value['_value'] = val;
25620
+ }
25621
+ else {
25622
+ this._value = this._engine.number(val);
25623
+ }
25624
+ // this.setProps(valueToFlags(val));
25625
+ this._number = undefined;
25626
+ this._integer = undefined;
25627
+ this._rational = undefined;
25628
+ this._algebraic = undefined;
25629
+ this._real = undefined;
25630
+ this._extendedReal = undefined;
25631
+ this._complex = undefined;
25632
+ this._extendedComplex = undefined;
25633
+ this._imaginary = undefined;
25634
+ this._positive = undefined;
25635
+ this._nonPositive = undefined;
25636
+ this._negative = undefined;
25637
+ this._nonNegative = undefined;
25638
+ this._zero = undefined;
25639
+ this._notZero = undefined;
25640
+ this._one = undefined;
25641
+ this._negativeOne = undefined;
25642
+ this._infinity = undefined;
25643
+ this._finite = undefined;
25644
+ this._NaN = undefined;
25645
+ this._even = undefined;
25646
+ this._odd = undefined;
25647
+ this._prime = undefined;
25648
+ this._composite = undefined;
25649
+ }
25650
+ else if (val) {
25553
25651
  val = this._engine.box(val);
25554
- this._value = val ?? null;
25555
- if (val)
25556
- this.setProps(valueToFlags(val));
25652
+ this._value = val;
25653
+ if (val)
25654
+ this.setProps(valueToFlags(val));
25655
+ }
25656
+ else
25657
+ this._value = null;
25557
25658
  }
25558
25659
  get domain() {
25559
25660
  if (this._domain === null)
@@ -26200,12 +26301,12 @@ function costFunction(expr) {
26200
26301
  //
26201
26302
  // 2/ Literal Numeric Values
26202
26303
  //
26203
- if (expr.isLiteral) {
26304
+ const num = expr.numericValue;
26305
+ if (num !== null) {
26204
26306
  if (expr.isZero)
26205
26307
  return 1;
26206
- if (expr.isInteger && asFloat(expr) !== null)
26308
+ if (expr.isInteger)
26207
26309
  return numericCostFunction(asFloat(expr));
26208
- const num = expr.numericValue;
26209
26310
  if (isRational(num)) {
26210
26311
  if (isMachineRational(num))
26211
26312
  return numericCostFunction(num[0]) + numericCostFunction(num[1]) + 1;
@@ -26725,9 +26826,6 @@ class BoxedSymbol extends AbstractBoxedExpression {
26725
26826
  get isNothing() {
26726
26827
  return this._name === 'Nothing';
26727
26828
  }
26728
- get isLiteral() {
26729
- return false;
26730
- }
26731
26829
  // A base definition is the base class of both symbol and function definition
26732
26830
  get baseDefinition() {
26733
26831
  if (this._def === null)
@@ -27124,7 +27222,7 @@ function makeCanonicalSymbol(ce, name) {
27124
27222
  const def = ce.lookupSymbol(name, undefined, ce.context);
27125
27223
  if (def) {
27126
27224
  if (def.hold === false && def.value)
27127
- return ce.box(def.value);
27225
+ return def.value;
27128
27226
  }
27129
27227
  return new BoxedSymbol(ce, name, { canonical: true });
27130
27228
  }
@@ -27245,6 +27343,7 @@ class ComputeEngine {
27245
27343
  };
27246
27344
  if (options !== undefined && typeof options !== 'object')
27247
27345
  throw Error('Unexpected argument');
27346
+ this.strict = true;
27248
27347
  this._latexDictionary = options?.latexDictionary;
27249
27348
  this._jsonSerializationOptions = {
27250
27349
  exclude: [],
@@ -27627,6 +27726,16 @@ class ComputeEngine {
27627
27726
  * wikidata, if provided.
27628
27727
  */
27629
27728
  lookupSymbol(symbol, wikidata, scope) {
27729
+ // @fastpath
27730
+ if (!this.strict) {
27731
+ scope ?? (scope = this.context ?? undefined);
27732
+ let def = undefined;
27733
+ while (scope && !def) {
27734
+ def = scope.symbolTable?.symbols.get(symbol);
27735
+ scope = scope.parentScope;
27736
+ }
27737
+ return def;
27738
+ }
27630
27739
  if (typeof symbol !== 'string')
27631
27740
  throw Error('Expected a string');
27632
27741
  // Wildcards never have definitions
@@ -27795,20 +27904,46 @@ class ComputeEngine {
27795
27904
  console.assert(this.context !== null);
27796
27905
  }
27797
27906
  set(identifiers) {
27907
+ // @fastpath
27908
+ if (!this.strict) {
27909
+ for (const k of Object.keys(identifiers)) {
27910
+ if (k !== 'Nothing') {
27911
+ const def = this.lookupSymbol(k);
27912
+ const idk = identifiers[k];
27913
+ if (def)
27914
+ def.value = idk ?? undefined;
27915
+ else if (idk !== undefined && idk !== null) {
27916
+ const val = this.box(idk);
27917
+ if (val.domain.isNumeric)
27918
+ this.defineSymbol({ name: k, value: val, domain: 'Number' });
27919
+ else
27920
+ this.defineSymbol({ name: k, value: val });
27921
+ }
27922
+ }
27923
+ }
27924
+ return;
27925
+ }
27798
27926
  for (const k of Object.keys(identifiers)) {
27799
27927
  if (k !== 'Nothing') {
27800
27928
  const def = this.lookupSymbol(k);
27801
- const val = this.box(identifiers[k]);
27802
- if (def) {
27803
- if (def.domain && !val.domain.isCompatible(def.domain))
27804
- throw Error(`Expected value with domain ${def.domain.toString()} for "${k}"`);
27805
- def.value = val;
27929
+ const idk = identifiers[k];
27930
+ if (idk === undefined || idk === null) {
27931
+ if (def)
27932
+ def.value = undefined;
27806
27933
  }
27807
27934
  else {
27808
- if (val.domain.isNumeric)
27809
- this.defineSymbol({ name: k, value: val, domain: 'Number' });
27810
- else
27811
- this.defineSymbol({ name: k, value: val });
27935
+ const val = this.box(idk);
27936
+ if (def) {
27937
+ if (def.domain && !val.domain.isCompatible(def.domain))
27938
+ throw Error(`Expected value with domain ${def.domain.toString()} for "${k}"`);
27939
+ def.value = val;
27940
+ }
27941
+ else {
27942
+ if (val.domain.isNumeric)
27943
+ this.defineSymbol({ name: k, value: val, domain: 'Number' });
27944
+ else
27945
+ this.defineSymbol({ name: k, value: val });
27946
+ }
27812
27947
  }
27813
27948
  }
27814
27949
  }
@@ -27938,7 +28073,7 @@ class ComputeEngine {
27938
28073
  }
27939
28074
  add(ops, metadata) {
27940
28075
  // Short path. Note that are arguments are **not** validated.
27941
- ops = flattenSequence(ops);
28076
+ // ops = flattenSequence(ops);
27942
28077
  const result = canonicalAdd(this, ops);
27943
28078
  if (metadata?.latex !== undefined)
27944
28079
  result.latex = metadata.latex;
@@ -28062,7 +28197,7 @@ class ComputeEngine {
28062
28197
  // `Half` is a synonym for the rational 1/2
28063
28198
  if (name === 'Half')
28064
28199
  return this._HALF;
28065
- if (!isValidIdentifier(name)) {
28200
+ if (this.strict && !isValidIdentifier(name)) {
28066
28201
  const where = options?.metadata?.latex;
28067
28202
  const nameStr = `'${name}'`;
28068
28203
  if (where)
@@ -28128,16 +28263,15 @@ class ComputeEngine {
28128
28263
  return this._ZERO;
28129
28264
  if (n === -1)
28130
28265
  return this._NEGATIVE_ONE;
28131
- if (isNaN(n))
28132
- return this._NAN;
28133
- if (!Number.isFinite(n))
28134
- return n < 0 ? this._NEGATIVE_INFINITY : this._POSITIVE_INFINITY;
28135
- if (Number.isInteger(n) && this._commonNumbers[n] === null) {
28136
- this._commonNumbers[n] = boxNumber(this, value);
28266
+ if (Number.isInteger(n) && this._commonNumbers[n] !== undefined) {
28137
28267
  if (this._commonNumbers[n] === null)
28138
- return this._NAN;
28268
+ this._commonNumbers[n] = boxNumber(this, value) ?? this._NAN;
28139
28269
  return this._commonNumbers[n];
28140
28270
  }
28271
+ if (Number.isNaN(n))
28272
+ return this._NAN;
28273
+ if (!Number.isFinite(n))
28274
+ return n < 0 ? this._NEGATIVE_INFINITY : this._POSITIVE_INFINITY;
28141
28275
  }
28142
28276
  return boxNumber(this, value, options) ?? this._NAN;
28143
28277
  }
@@ -28271,8 +28405,20 @@ class ComputeEngine {
28271
28405
  forget(symbol) {
28272
28406
  if (!this.context)
28273
28407
  throw Error('No scope available');
28408
+ //
28409
+ // Theory of Operations
28410
+ //
28411
+ // When forgeting we need to preserve existing definitions for symbols,
28412
+ // as some expressions may be pointing to them. Instead, we
28413
+ // reset the value/domain of those definitions.
28414
+ //
28274
28415
  if (symbol === undefined) {
28275
- this.context.symbolTable = undefined;
28416
+ if (this.context.symbolTable?.symbols)
28417
+ for (const k of this.context.symbolTable.symbols.keys())
28418
+ this.forget(k);
28419
+ if (this.context.symbolTable?.functions)
28420
+ for (const k of this.context.symbolTable.functions.keys())
28421
+ this.forget(k);
28276
28422
  this.assumptions.clear();
28277
28423
  return;
28278
28424
  }
@@ -28284,13 +28430,17 @@ class ComputeEngine {
28284
28430
  if (typeof symbol === 'string') {
28285
28431
  // Remove symbol definition in the current scope (if any)
28286
28432
  if (this.context.symbolTable) {
28287
- this.context.symbolTable.symbols.delete(symbol);
28433
+ const sdef = this.context.symbolTable.symbols.get(symbol);
28434
+ if (sdef) {
28435
+ sdef.value = undefined;
28436
+ sdef.domain = undefined;
28437
+ }
28438
+ this.context.symbolTable.functions.get(symbol);
28288
28439
  this.context.symbolTable.symbolWikidata.delete(symbol);
28289
- this.context.symbolTable.functions.delete(symbol);
28290
28440
  this.context.symbolTable.functionWikidata.delete(symbol);
28291
28441
  }
28292
28442
  // Remove any assumptions that make a reference to this symbol
28293
- // (note that when a scope if created, any assumptions from the
28443
+ // (note that when a scope is created, any assumptions from the
28294
28444
  // parent scope are copied over, so this effectively removes any
28295
28445
  // reference to this symbol, even if there are assumptions about
28296
28446
  // it in a parent scope. However, when the current scope exits,
@@ -28305,6 +28455,6 @@ class ComputeEngine {
28305
28455
  }
28306
28456
 
28307
28457
  // This file is the root of the `compute-engine` package
28308
- const version = '0.9.0';
28458
+ const version = '0.10.0';
28309
28459
 
28310
28460
  export { ComputeEngine, getVars, isEnvironmentEntry, isFunctionEntry, isInfixEntry, isMatchfixEntry, isPostfixEntry, isPrefixEntry, isSymbolEntry, version };