@cortex-js/compute-engine 0.29.1 → 0.30.1

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 (150) hide show
  1. package/dist/compute-engine.esm.js +28319 -24614
  2. package/dist/compute-engine.min.esm.js +70 -68
  3. package/dist/compute-engine.min.umd.js +131 -0
  4. package/dist/{compute-engine.cjs → compute-engine.umd.js} +29615 -25910
  5. package/dist/math-json.esm.js +22 -294
  6. package/dist/math-json.min.esm.js +22 -294
  7. package/dist/math-json.min.umd.js +4 -0
  8. package/dist/math-json.umd.js +141 -0
  9. package/dist/types/common/ansi-codes.d.ts +1 -1
  10. package/dist/types/common/configuration-change.d.ts +28 -0
  11. package/dist/types/common/fuzzy-string-match.d.ts +1 -1
  12. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  13. package/dist/types/common/interruptible.d.ts +1 -1
  14. package/dist/types/common/one-of.d.ts +1 -1
  15. package/dist/types/common/signals.d.ts +1 -1
  16. package/dist/types/common/type/boxed-type.d.ts +20 -4
  17. package/dist/types/common/type/parse.d.ts +4 -4
  18. package/dist/types/common/type/primitive.d.ts +3 -2
  19. package/dist/types/common/type/serialize.d.ts +1 -1
  20. package/dist/types/common/type/subtype.d.ts +1 -1
  21. package/dist/types/common/type/types.d.ts +91 -25
  22. package/dist/types/common/type/utils.d.ts +2 -1
  23. package/dist/types/common/utils.d.ts +1 -1
  24. package/dist/types/compute-engine/assume.d.ts +2 -2
  25. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +72 -73
  26. package/dist/types/compute-engine/boxed-expression/apply.d.ts +1 -1
  27. package/dist/types/compute-engine/boxed-expression/arithmetic-add.d.ts +1 -1
  28. package/dist/types/compute-engine/boxed-expression/arithmetic-mul-div.d.ts +2 -2
  29. package/dist/types/compute-engine/boxed-expression/arithmetic-power.d.ts +19 -1
  30. package/dist/types/compute-engine/boxed-expression/ascii-math.d.ts +1 -1
  31. package/dist/types/compute-engine/boxed-expression/box.d.ts +6 -6
  32. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +42 -0
  33. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +48 -27
  34. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +17 -5
  35. package/dist/types/compute-engine/boxed-expression/{boxed-function-definition.d.ts → boxed-operator-definition.d.ts} +12 -12
  36. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  37. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +7 -8
  38. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +91 -52
  39. package/dist/types/compute-engine/boxed-expression/boxed-tensor.d.ts +22 -25
  40. package/dist/types/compute-engine/boxed-expression/boxed-value-definition.d.ts +46 -0
  41. package/dist/types/compute-engine/boxed-expression/cache.d.ts +1 -1
  42. package/dist/types/compute-engine/boxed-expression/canonical-utils.d.ts +5 -0
  43. package/dist/types/compute-engine/boxed-expression/canonical.d.ts +2 -2
  44. package/dist/types/compute-engine/boxed-expression/compare.d.ts +1 -1
  45. package/dist/types/compute-engine/boxed-expression/expand.d.ts +1 -1
  46. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  47. package/dist/types/compute-engine/boxed-expression/factor.d.ts +1 -1
  48. package/dist/types/compute-engine/boxed-expression/flatten.d.ts +1 -1
  49. package/dist/types/compute-engine/boxed-expression/hold.d.ts +2 -2
  50. package/dist/types/compute-engine/boxed-expression/match.d.ts +1 -1
  51. package/dist/types/compute-engine/boxed-expression/negate.d.ts +1 -1
  52. package/dist/types/compute-engine/boxed-expression/numerics.d.ts +30 -3
  53. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  54. package/dist/types/compute-engine/boxed-expression/polynomials.d.ts +1 -1
  55. package/dist/types/compute-engine/boxed-expression/product.d.ts +2 -2
  56. package/dist/types/compute-engine/boxed-expression/rules.d.ts +1 -1
  57. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  58. package/dist/types/compute-engine/boxed-expression/sgn.d.ts +41 -1
  59. package/dist/types/compute-engine/boxed-expression/simplify.d.ts +1 -1
  60. package/dist/types/compute-engine/boxed-expression/solve.d.ts +3 -1
  61. package/dist/types/compute-engine/boxed-expression/terms.d.ts +1 -1
  62. package/dist/types/compute-engine/boxed-expression/trigonometry.d.ts +1 -1
  63. package/dist/types/compute-engine/boxed-expression/utils.d.ts +23 -23
  64. package/dist/types/compute-engine/boxed-expression/validate.d.ts +2 -1
  65. package/dist/types/compute-engine/collection-utils.d.ts +22 -57
  66. package/dist/types/compute-engine/compile.d.ts +61 -10
  67. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  68. package/dist/types/compute-engine/function-utils.d.ts +46 -29
  69. package/dist/types/compute-engine/global-types.d.ts +1432 -893
  70. package/dist/types/compute-engine/index.d.ts +154 -124
  71. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  72. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  73. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  74. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-complex.d.ts +1 -1
  75. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  76. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-linear-algebra.d.ts +1 -1
  77. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
  78. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  79. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-relational-operators.d.ts +1 -1
  80. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  81. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-statistics.d.ts +1 -1
  82. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  83. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  84. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +3 -3
  85. package/dist/types/compute-engine/latex-syntax/parse-symbol.d.ts +21 -0
  86. package/dist/types/compute-engine/latex-syntax/parse.d.ts +14 -12
  87. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  88. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  89. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +2 -2
  90. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  91. package/dist/types/compute-engine/latex-syntax/types.d.ts +51 -39
  92. package/dist/types/compute-engine/latex-syntax/utils.d.ts +5 -0
  93. package/dist/types/compute-engine/library/arithmetic.d.ts +2 -2
  94. package/dist/types/compute-engine/library/calculus.d.ts +2 -2
  95. package/dist/types/compute-engine/library/collections.d.ts +3 -3
  96. package/dist/types/compute-engine/library/combinatorics.d.ts +2 -0
  97. package/dist/types/compute-engine/library/complex.d.ts +2 -2
  98. package/dist/types/compute-engine/library/control-structures.d.ts +2 -2
  99. package/dist/types/compute-engine/library/core.d.ts +2 -2
  100. package/dist/types/compute-engine/library/invisible-operator.d.ts +1 -1
  101. package/dist/types/compute-engine/library/library.d.ts +5 -5
  102. package/dist/types/compute-engine/library/linear-algebra.d.ts +2 -2
  103. package/dist/types/compute-engine/library/logic.d.ts +2 -2
  104. package/dist/types/compute-engine/library/number-theory.d.ts +2 -0
  105. package/dist/types/compute-engine/library/polynomials.d.ts +2 -2
  106. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  107. package/dist/types/compute-engine/library/relational-operator.d.ts +2 -2
  108. package/dist/types/compute-engine/library/sets.d.ts +2 -2
  109. package/dist/types/compute-engine/library/statistics.d.ts +2 -2
  110. package/dist/types/compute-engine/library/trigonometry.d.ts +2 -2
  111. package/dist/types/compute-engine/library/utils.d.ts +24 -2
  112. package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +3 -4
  113. package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +3 -3
  114. package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +3 -4
  115. package/dist/types/compute-engine/numeric-value/types.d.ts +7 -5
  116. package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
  117. package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
  118. package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
  119. package/dist/types/compute-engine/numerics/monte-carlo.d.ts +4 -19
  120. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  121. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  122. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  123. package/dist/types/compute-engine/numerics/numeric.d.ts +9 -1
  124. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  125. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  126. package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
  127. package/dist/types/compute-engine/numerics/special-functions.d.ts +1 -1
  128. package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
  129. package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
  130. package/dist/types/compute-engine/numerics/types.d.ts +1 -1
  131. package/dist/types/compute-engine/symbolic/antiderivative.d.ts +3 -0
  132. package/dist/types/compute-engine/symbolic/derivative.d.ts +2 -4
  133. package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
  134. package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
  135. package/dist/types/compute-engine/tensor/tensor-fields.d.ts +5 -46
  136. package/dist/types/compute-engine/tensor/tensors.d.ts +4 -14
  137. package/dist/types/compute-engine/types.d.ts +1 -4
  138. package/dist/types/compute-engine.d.ts +1 -1
  139. package/dist/types/math-json/symbols.d.ts +11 -0
  140. package/dist/types/math-json/types.d.ts +19 -11
  141. package/dist/types/math-json/utils.d.ts +18 -9
  142. package/dist/types/math-json.d.ts +2 -2
  143. package/package.json +13 -11
  144. package/dist/compute-engine.min.cjs +0 -129
  145. package/dist/math-json.cjs +0 -413
  146. package/dist/math-json.min.cjs +0 -6
  147. package/dist/types/common/json5.d.ts +0 -3
  148. package/dist/types/compute-engine/boxed-expression/boxed-symbol-definition.d.ts +0 -64
  149. package/dist/types/compute-engine/latex-syntax/parse-identifier.d.ts +0 -21
  150. package/dist/types/math-json/identifiers.d.ts +0 -11
@@ -1,12 +1,13 @@
1
- /* 0.29.1 */
1
+ /* 0.30.1 */
2
2
  import type { OneOf } from '../common/one-of';
3
- import type { Expression, MathJsonNumber, MathJsonString, MathJsonSymbol, MathJsonFunction, MathJsonIdentifier } from '../math-json';
4
- import { LatexDictionaryEntry, LatexString, ParseLatexOptions, SerializeLatexOptions } from './latex-syntax/types';
5
- import { ExactNumericValueData, NumericValue, NumericValueData } from './numeric-value/types';
6
- import { BigNum, IBigNum, Rational } from './numerics/types';
7
- import { Type, TypeString } from '../common/type/types';
8
- import { BoxedType } from '../common/type/boxed-type';
9
- import { IndexedLatexDictionary } from './latex-syntax/dictionary/definitions';
3
+ import type { Expression, MathJsonNumberObject, MathJsonStringObject, MathJsonFunctionObject, MathJsonSymbolObject, MathJsonSymbol, MathJsonDictionaryObject } from '../math-json';
4
+ import type { Type, TypeReference, TypeResolver, TypeString } from '../common/type/types';
5
+ import type { BoxedType } from '../common/type/boxed-type';
6
+ import type { ConfigurationChangeListener } from '../common/configuration-change';
7
+ import type { ExactNumericValueData, NumericValue, NumericValueData } from './numeric-value/types';
8
+ import type { BigNum, IBigNum, Rational } from './numerics/types';
9
+ import type { LatexDictionaryEntry, LatexString, ParseLatexOptions, SerializeLatexOptions } from './latex-syntax/types';
10
+ import type { IndexedLatexDictionary } from './latex-syntax/dictionary/definitions';
10
11
  /** @category Compiling */
11
12
  export type CompiledType = boolean | number | string | object;
12
13
  /** @category Compiling */
@@ -17,7 +18,10 @@ export type CompiledExpression = {
17
18
  [symbol: string]: BoxedExpression;
18
19
  }) => number | BoxedExpression;
19
20
  };
20
- /** @category Tensors */
21
+ /**
22
+ * Map of `TensorDataType` to JavaScript type.
23
+ *
24
+ * @category Tensors */
21
25
  export type DataTypeMap = {
22
26
  float64: number;
23
27
  float32: number;
@@ -26,199 +30,373 @@ export type DataTypeMap = {
26
30
  complex128: Complex;
27
31
  complex64: Complex;
28
32
  bool: boolean;
29
- string: string;
30
33
  expression: BoxedExpression;
31
34
  };
32
- /** @category Tensors */
35
+ /**
36
+ * The type of the cells in a tensor.
37
+ * @category Tensors */
33
38
  export type TensorDataType = keyof DataTypeMap;
39
+ /** @internal */
40
+ export type NestedArray<T> = NestedArray_<T>[];
41
+ /** @internal */
42
+ export type NestedArray_<T> = T | NestedArray_<T>[];
43
+ /**
44
+ * A record representing the type, shape and data of a tensor.
45
+ * @category Tensors */
46
+ export interface TensorData<DT extends TensorDataType> {
47
+ dtype: DT;
48
+ shape: number[];
49
+ rank?: number;
50
+ data: DataTypeMap[DT][];
51
+ }
34
52
  /** @category Tensors */
35
- export interface TensorData<DT extends keyof DataTypeMap = 'float64'> {
53
+ export interface TensorField<T extends number | Complex | BoxedExpression | boolean | string = number> {
54
+ readonly one: T;
55
+ readonly zero: T;
56
+ readonly nan: T;
57
+ cast(x: T, dtype: 'float64'): undefined | number;
58
+ cast(x: T, dtype: 'float32'): undefined | number;
59
+ cast(x: T, dtype: 'int32'): undefined | number;
60
+ cast(x: T, dtype: 'uint8'): undefined | number;
61
+ cast(x: T, dtype: 'complex128'): undefined | Complex;
62
+ cast(x: T, dtype: 'complex64'): undefined | Complex;
63
+ cast(x: T, dtype: 'bool'): undefined | boolean;
64
+ cast(x: T, dtype: 'expression'): undefined | BoxedExpression;
65
+ cast(x: T[], dtype: 'float64'): undefined | number[];
66
+ cast(x: T[], dtype: 'float32'): undefined | number[];
67
+ cast(x: T[], dtype: 'int32'): undefined | number[];
68
+ cast(x: T[], dtype: 'uint8'): undefined | number[];
69
+ cast(x: T[], dtype: 'complex128'): undefined | Complex[];
70
+ cast(x: T[], dtype: 'complex64'): undefined | Complex[];
71
+ cast(x: T[], dtype: 'bool'): undefined | boolean[];
72
+ cast(x: T[], dtype: 'expression'): undefined | BoxedExpression[];
73
+ cast(x: T | T[], dtype: TensorDataType): undefined | Complex | number | boolean | BoxedExpression | Complex[] | number[] | boolean[] | BoxedExpression[];
74
+ expression(x: T): BoxedExpression;
75
+ isZero(x: T): boolean;
76
+ isOne(x: T): boolean;
77
+ equals(lhs: T, rhs: T): boolean;
78
+ add(lhs: T, rhs: T): T;
79
+ addn(...xs: T[]): T;
80
+ neg(x: T): T;
81
+ sub(lhs: T, rhs: T): T;
82
+ mul(lhs: T, rhs: T): T;
83
+ muln(...xs: T[]): T;
84
+ div(lhs: T, rhs: T): T;
85
+ pow(rhs: T, n: number): T;
86
+ conjugate(x: T): T;
87
+ }
88
+ /**
89
+ * @category Tensors
90
+ */
91
+ export interface Tensor<DT extends TensorDataType> extends TensorData<DT> {
36
92
  dtype: DT;
37
93
  shape: number[];
38
94
  rank: number;
39
95
  data: DataTypeMap[DT][];
96
+ readonly field: TensorField<DT>;
97
+ readonly expression: BoxedExpression;
98
+ readonly array: NestedArray<DataTypeMap[DT]>;
99
+ readonly isSquare: boolean;
100
+ readonly isSymmetric: boolean;
101
+ readonly isSkewSymmetric: boolean;
102
+ readonly isDiagonal: boolean;
103
+ readonly isUpperTriangular: boolean;
104
+ readonly isLowerTriangular: boolean;
105
+ readonly isTriangular: boolean;
106
+ readonly isIdentity: boolean;
107
+ readonly isZero: boolean;
108
+ at(...indices: number[]): DataTypeMap[DT] | undefined;
109
+ diagonal(axis1?: number, axis2?: number): undefined | DataTypeMap[DT][];
110
+ trace(axis1?: number, axis2?: number): undefined | DataTypeMap[DT];
111
+ reshape(...shape: number[]): Tensor<DT>;
112
+ slice(index: number): Tensor<DT>;
113
+ flatten(): DataTypeMap[DT][];
114
+ upcast<DT extends TensorDataType>(dtype: DT): Tensor<DT>;
115
+ transpose(axis1?: number, axis2?: number): undefined | Tensor<DT>;
116
+ conjugateTranspose(axis1?: number, axis2?: number): undefined | Tensor<DT>;
117
+ determinant(): undefined | DataTypeMap[DT];
118
+ inverse(): undefined | Tensor<DT>;
119
+ pseudoInverse(): undefined | Tensor<DT>;
120
+ adjugateMatrix(): undefined | Tensor<DT>;
121
+ minor(axis1: number, axis2: number): undefined | DataTypeMap[DT];
122
+ map1(fn: (lhs: DataTypeMap[DT], rhs: DataTypeMap[DT]) => DataTypeMap[DT], scalar: DataTypeMap[DT]): Tensor<DT>;
123
+ map2(fn: (lhs: DataTypeMap[DT], rhs: DataTypeMap[DT]) => DataTypeMap[DT], rhs: Tensor<DT>): Tensor<DT>;
124
+ add(other: Tensor<DT> | DataTypeMap[DT]): Tensor<DT>;
125
+ subtract(other: Tensor<DT> | DataTypeMap[DT]): Tensor<DT>;
126
+ multiply(other: Tensor<DT> | DataTypeMap[DT]): Tensor<DT>;
127
+ divide(other: Tensor<DT> | DataTypeMap[DT]): Tensor<DT>;
128
+ power(other: Tensor<DT> | DataTypeMap[DT]): Tensor<DT>;
129
+ equals(other: Tensor<DT>): boolean;
40
130
  }
41
131
  /**
42
132
  * :::info[THEORY OF OPERATIONS]
43
133
  *
44
134
  * The `BoxedExpression` interface includes the methods and properties
45
- * applicable to any kind of expression, for example `expr.symbol` or
46
- * `expr.ops`.
135
+ * applicable to all kinds of expression. For example it includes `expr.symbol`
136
+ * which only applies to symbols or `expr.ops` which only applies to
137
+ * function expressions.
47
138
  *
48
- * When a member function is not applicable to this `BoxedExpression`,
49
- * for example `get symbol()` on a `BoxedNumber`, it returns `null`.
139
+ * When a property is not applicable to this `BoxedExpression` its value is
140
+ * `null`. For example `expr.symbol` for a `BoxedNumber` is `null`.
50
141
  *
51
142
  * This convention makes it convenient to manipulate expressions without
52
143
  * having to check what kind of instance they are before manipulating them.
53
144
  * :::
54
145
  *
55
- * To get a boxed expression from a LaTeX string use `ce.parse()`, and to
56
- * get a boxed expression from a MathJSON expression use `ce.box()`.
146
+ * :::info[THEORY OF OPERATIONS]
147
+ * A boxed expression can represent a canonical or a non-canonical
148
+ * expression. A non-canonical expression is a "raw" form of the
149
+ * expression. For example, the non-canonical representation of `\frac{10}{20}`
150
+ * is `["Divide", 10, 20]`. The canonical representation of the same
151
+ * expression is the boxed number `1/2`.
152
+ *
153
+ * The canonical representation of symbols and function expressions are
154
+ * bound to a definition. The definition contains metadata about the symbol
155
+ * or function operator, such as its type, its signature, and other attributes.
156
+ * The value of symbols are tracked in a separate table for each
157
+ * evaluation context.
158
+ *
159
+ * The binding only occurs when the expression is constructed, if it is created
160
+ * as a canonical expression. If the expression is constructed as a
161
+ * non-canonical expression, no binding is done.
162
+ *
163
+ * <!--
164
+ * Rules:
165
+ * - nothing should cause the binding to occur outside of the constructor
166
+ * - if an operation require a canonical expression (e.g. evaluate()),
167
+ * it should return undefined or throw an error if the expression is not
168
+ * canonical
169
+ * -->
170
+ *
171
+ *
172
+ * :::
173
+ *
174
+ * :::info[THEORY OF OPERATIONS]
175
+ * The **value** of an expression is a number, a string, a boolean or a tensor.
176
+ *
177
+ * The value of number literals and strings are themselves.
178
+ *
179
+ * A symbol can have a value associated with it, in which case the value
180
+ * of the symbol is the value associated with it.
181
+ *
182
+ * Some symbols (unknowns) are purely symbolic and have no value associated
183
+ * with them.
57
184
  *
185
+ * Function expressions do not have a value associated with them.
186
+ * For example, `["Add", 2, 3]` has no value associated with it, it is a
187
+ * symbolic expression.
188
+ *
189
+ * Some properties of a Boxed Expression are only applicable if the expression
190
+ * has a value associated with it. For example, `expr.isNumber` is only
191
+ * applicable if the value of the expression is a number, that is if the
192
+ * expression is a number literal or a symbol with a numeric value.
193
+ *
194
+ * The following properties are applicable to expressions with a value:
195
+ * - `expr.isNumber`
196
+ * :::
58
197
  *
59
198
  * To create a boxed expression:
60
199
  *
61
200
  * ### `ce.box()` and `ce.parse()`
62
201
  *
63
- * Use `ce.box()` or `ce.parse()` to get a canonical expression.
202
+ * Use `ce.box()` or `ce.parse()`.
203
+ *
204
+ * Use `ce.parse()` to get a boxed expression from a LaTeX string.
205
+ * Use `ce.box()` to get a boxed expression from a MathJSON expression.
206
+ *
207
+ * By default, the result of these methods is a canonical expression. For
208
+ * example, if it is a rational literal, it is reduced to its canonical form.
209
+ * If it is a function expression:
64
210
  * - the arguments are put in canonical form
211
+ * - the arguments of commutative functions are sorted
65
212
  * - invisible operators are made explicit
66
213
  * - a limited number of core simplifications are applied,
67
- * for example 0 is removed from additions
214
+ * for example rationals are reduced
68
215
  * - sequences are flattened: `["Add", 1, ["Sequence", 2, 3]]` is
69
216
  * transformed to `["Add", 1, 2, 3]`
70
217
  * - associative functions are flattened: `["Add", 1, ["Add", 2, 3]]` is
71
218
  * transformed to `["Add", 1, 2, 3]`
72
- * - the arguments of commutative functions are sorted
73
- * - identifiers are **not** replaced with their values
219
+ * - symbols are **not** replaced with their values (unless they have
220
+ * a `holdUntil` flag set to `never`).
74
221
  *
75
- * ### Algebraic methods (expr.add(), expr.mul(), etc...)
222
+ * ### `ce.function()`
76
223
  *
77
- * The boxed expression have some algebraic methods,
78
- * i.e. `add`, `mul`, `div`, `pow`, etc. These methods are suitable for
224
+ * This is a specialized version of `ce.box()` for creating a new function
225
+ * expression.
226
+ *
227
+ * The canonical handler of the operator is called.
228
+ *
229
+ *
230
+ * ### Algebraic methods (`expr.add()`, `expr.mul()`, etc...)
231
+ *
232
+ * The boxed expression have some algebraic methods, i.e. `add()`, `mul()`,
233
+ * `div()`, `pow()`, etc. These methods are suitable for
79
234
  * internal calculations, although they may be used as part of the public
80
235
  * API as well.
81
236
  *
82
- * - the operation is performed on the canonical version of the expression
83
- *
237
+ * - a runtime error is thrown if the expression is not canonical
84
238
  * - the arguments are not evaluated
85
- *
86
239
  * - the canonical handler (of the corresponding operation) is not called
87
- *
88
240
  * - some additional simplifications over canonicalization are applied.
89
241
  * For example number literals are combined.
90
242
  * However, the result is exact, and no approximation is made. Use `.N()`
91
243
  * to get an approximate value.
92
244
  * This is equivalent to calling `simplify()` on the expression (but
93
245
  * without simplifying the arguments).
94
- *
95
246
  * - sequences were already flattened as part of the canonicalization process
96
247
  *
97
- * For 'add' and 'mul', which take multiple arguments, separate functions
98
- * are provided that take an array of arguments. They are equivalent
99
- * to calling the boxed algebraic method, i.e. `ce.Zero.add(1, 2, 3)` and
100
- * `add(1, 2, 3)` are equivalent.
248
+ * For 'add()' and 'mul()', which take multiple arguments, separate functions
249
+ * are provided that take an array of arguments. They are equivalent
250
+ * to calling the boxed algebraic method, i.e. `ce.Zero.add(1, 2, 3)` and
251
+ * `add(1, 2, 3)` are equivalent.
101
252
  *
102
253
  * These methods are not equivalent to calling `expr.evaluate()` on the
103
- * expression: evaluate will replace identifiers with their values, and
104
- * evaluate the expression
254
+ * expression: evaluate will replace symbols with their values, and
255
+ * evaluate the expression.
105
256
  *
106
- * ### `ce._fn()`
257
+ * For algebraic functions (`add()`, `mul()`, etc..), use the corresponding
258
+ * canonicalization function, i.e. `canonicalAdd(a, b)` instead of
259
+ * `ce.function('Add', [a, b])`.
260
+ *
261
+ * Another option is to use the algebraic methods directly, i.e. `a.add(b)`
262
+ * instead of `ce.function('Add', [a, b])`. However, the algebraic methods will
263
+ * apply further simplifications which may or may not be desirable. For
264
+ * example, number literals will be combined.
107
265
  *
108
- * Use `ce._fn()` to create a new function expression.
266
+ * ### `ce._fn()`
109
267
  *
110
- * This is a low level method which is typically invoked in the canonical
111
- * handler of a function definition.
268
+ * This method is a low level method to create a new function expression which
269
+ * is typically invoked in the canonical handler of an operator definition.
112
270
  *
113
271
  * The arguments are not modified. The expression is not put in canonical
114
272
  * form. The canonical handler is *not* called.
115
273
  *
116
- * A canonical flag can be set when calling the function, but it only
117
- * asserts that the function and its arguments are canonical. The caller
118
- * is responsible for ensuring that is the case.
274
+ * A canonical flag can be set when calling this method, but it only
275
+ * asserts that the function expression is canonical. The caller is responsible
276
+ * for ensuring that is the case.
119
277
  *
120
278
  *
121
- * ### `ce.function()`
122
- *
123
- * This is a specialized version of `ce.box()`. It is used to create a new
124
- * function expression.
125
- *
126
- * The arguments are put in canonical form and the canonical handler is called.
127
- *
128
- * For algebraic functions (add, mul, etc..), use the corresponding
129
- * canonicalization function, i.e. `canonicalAdd(a, b)` instead of
130
- * `ce.function('Add', a, b)`.
131
- *
132
- * Another option is to use the algebraic methods directly, i.e. `a.add(b)`
133
- * instead of `ce.function('Add', a, b)`. However, the algebraic methods will
134
- * apply further simplifications which may or may not be desirable. For
135
- * example, number literals will be combined.
136
279
  *
137
280
  * ### Canonical Handlers
138
281
  *
139
282
  * Canonical handlers are responsible for:
140
- * - validating the signature (type and number of arguments)
283
+ * - validating the signature: this can involve checking the
284
+ * number of arguments. It is recommended to avoid checking the
285
+ * type of non-literal arguments, since the type of symbols or
286
+ * function expressions may change. Similarly, the canonicalization
287
+ * process should not rely on the value of or assumptions about non-literal
288
+ * arguments.
141
289
  * - flattening sequences
142
- * - flattening associative functions
290
+ * - flattening arguments if the function is associative
143
291
  * - sort the arguments (if the function is commutative)
144
292
  * - calling `ce._fn()` to create a new function expression
145
- * - if the function definition has a hold, they should also put
146
- * their arguments in canonical form, if appropriate
147
293
  *
148
294
  * When the canonical handler is invoked, the arguments have been put in
149
- * canonical form according to the `hold` flag.
295
+ * canonical form unless the `lazy` flag is set to `true`.
150
296
  *
151
- * Some canonical handlers are available as separate functions and can be
152
- * used directly, for example `canonicalAdd(a, b)` instead of
153
- * `ce.function('Add', [a, b])`.
297
+ * Note that the result of a canonical handler should be a canonical expression,
298
+ * but not all arguments need to be canonical. For example, the arguments of
299
+ * `["Declare", "x", 2]` are not canonical, since `x` refers to the name
300
+ * of the symbol, not its value.
154
301
  *
155
302
  * @category Boxed Expression
156
303
  *
157
304
  */
158
305
  export interface BoxedExpression {
159
- /** The Compute Engine associated with this expression provides
306
+ /** @internal */
307
+ readonly hash: number;
308
+ /**
309
+ * The Compute Engine instance associated with this expression provides
160
310
  * a context in which to interpret it, such as definition of symbols
161
311
  * and functions.
162
- *
163
312
  */
164
313
  readonly engine: ComputeEngine;
165
- /** From `Object.valueOf()`, return a primitive value for the expression.
314
+ /**
166
315
  *
167
- * If the expression is a machine number, or bignum or rational that can be
168
- * converted to a machine number, return a JavaScript `number`.
316
+ * Return a JavaScript primitive value for the expression, based on
317
+ * `Object.valueOf()`.
169
318
  *
170
- * If the expression is a symbol, return the name of the symbol as a `string`.
319
+ * This method is intended to make it easier to work with JavaScript
320
+ * primitives, for example when mixing JavaScript computations with
321
+ * symbolic computations from the Compute Engine.
171
322
  *
172
- * Otherwise return a JavaScript primitive representation of the expression.
323
+ * If the expression is a **machine number**, a **bignum**, or a **rational**
324
+ * that can be converted to a machine number, return a JavaScript `number`.
325
+ * This conversion may result in a loss of precision.
326
+ *
327
+ * If the expression is the **symbol `"True"`** or the **symbol `"False"`**,
328
+ * return `true` or `false`, respectively.
329
+ *
330
+ * If the expression is a **symbol with a numeric value**, return the numeric
331
+ * value of the symbol.
332
+ *
333
+ * If the expression is a **string literal**, return the string value.
334
+ *
335
+ * If the expression is a **tensor** (list of number or multidimensional
336
+ * array or matrix), return an array of numbers, or an array of
337
+ * arrays of numbers, or an array of arrays of arrays of numbers.
338
+ *
339
+ * If the expression is a function expression return a string representation
340
+ * of the expression.
341
+ *
342
+ * @category Primitive Methods
343
+ */
344
+ valueOf(): number | number[] | number[][] | number[][][] | string | boolean;
345
+ /** Similar to`expr.valueOf()` but includes a hint.
173
346
  *
174
347
  * @category Primitive Methods
175
348
  */
176
- valueOf(): number | any | string | boolean;
177
- /** From `Object.toString()`, return a string representation of the
178
- * expression. This string is suitable to be output to the console
179
- * for debugging, for example. It is formatted as a ASCIIMath expression.
349
+ [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string | null;
350
+ /**
351
+ * Return an ASCIIMath representation of the expression. This string is
352
+ * suitable to be output to the console for debugging, for example.
353
+ *
354
+ * Based on `Object.toString()`.
180
355
  *
181
356
  * To get a LaTeX representation of the expression, use `expr.latex`.
182
357
  *
358
+ * Note that lazy collections are eagerly evaluated.
359
+ *
183
360
  * Used when coercing a `BoxedExpression` to a `String`.
184
361
  *
185
362
  * @category Primitive Methods
186
363
  */
187
364
  toString(): string;
188
- /**
189
- * Output to the console a string representation of the expression.
365
+ /** Serialize to a LaTeX string.
190
366
  *
191
- * @category Primitive Methods
367
+ * Note that lazy collections are eagerly evaluated.
368
+ *
369
+ * Will ignore any LaTeX metadata.
192
370
  */
193
- print(): void;
194
- /** Similar to`expr.valueOf()` but includes a hint.
371
+ toLatex(options?: Partial<SerializeLatexOptions>): LatexString;
372
+ /** LaTeX representation of this expression.
373
+ *
374
+ * If the expression was parsed from LaTeX, the LaTeX representation is
375
+ * the same as the input LaTeX.
376
+ *
377
+ * To customize the serialization, use `expr.toLatex()`.
378
+ *
379
+ * Note that lazy collections are eagerly evaluated.
380
+ *
381
+ * :::info[Note]
382
+ * Applicable to canonical and non-canonical expressions.
383
+ * :::
195
384
  *
196
- * @category Primitive Methods
197
385
  */
198
- [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string | null;
386
+ get latex(): LatexString;
199
387
  /** Used by `JSON.stringify()` to serialize this object to JSON.
200
388
  *
201
389
  * Method version of `expr.json`.
202
390
  *
391
+ * Based on `Object.toJSON()`.
392
+ *
393
+ * Note that lazy collections are *not* eagerly evaluated.
394
+ *
203
395
  * @category Primitive Methods
204
396
  */
205
397
  toJSON(): Expression;
206
- /** Serialize to a MathJSON expression with specified options*/
398
+ /** Serialize to a MathJSON expression with specified options */
207
399
  toMathJson(options?: Readonly<Partial<JsonSerializationOptions>>): Expression;
208
- /** Serialize to a LaTeX string.
209
- *
210
- * Will ignore any LaTeX metadata.
211
- */
212
- toLatex(options?: Partial<SerializeLatexOptions>): LatexString;
213
- verbatimLatex?: string;
214
- /** If `true`, this expression is in a canonical form. */
215
- get isCanonical(): boolean;
216
- /** For internal use only, set when a canonical expression is created.
217
- * @internal
218
- */
219
- set isCanonical(val: boolean);
220
- /** If `true`, this expression is in a structural form. */
221
- get isStructural(): boolean;
222
400
  /** MathJSON representation of this expression.
223
401
  *
224
402
  * This representation always use shorthands when possible. Metadata is not
@@ -231,6 +409,8 @@ export interface BoxedExpression {
231
409
  *
232
410
  * For more control over the serialization, use `expr.toMathJson()`.
233
411
  *
412
+ * Note that lazy collections are *not* eagerly evaluated.
413
+ *
234
414
  * :::info[Note]
235
415
  * Applicable to canonical and non-canonical expressions.
236
416
  * :::
@@ -238,75 +418,161 @@ export interface BoxedExpression {
238
418
  */
239
419
  readonly json: Expression;
240
420
  /**
241
- * The scope in which this expression has been defined.
421
+ * Output to the console a string representation of the expression.
422
+ *
423
+ * Note that lazy collections are eagerly evaluated when printed.
242
424
  *
243
- * Is `null` when the expression is not canonical.
244
425
  */
245
- readonly scope: RuntimeScope | null;
246
- /**
247
- * Equivalent to `BoxedExpression.isSame()` but the argument can be
248
- * a JavaScript primitive. For example, `expr.is(2)` is equivalent to
249
- * `expr.isSame(ce.number(2))`.
426
+ print(): void;
427
+ /** If the expression was constructed from a LaTeX string, the verbatim LaTeX
428
+ * string it was parsed from.
429
+ */
430
+ verbatimLatex?: string;
431
+ /** If `true`, this expression is in a canonical form. */
432
+ get isCanonical(): boolean;
433
+ /** For internal use only, set when a canonical expression is created.
434
+ * @internal
435
+ */
436
+ set isCanonical(val: boolean);
437
+ /** If `true`, this expression is in a structural form.
250
438
  *
251
- * @category Primitive Methods
439
+ * The structural form of an expression is used when applying rules to
440
+ * an expression. For example, a rational number is represented as a
441
+ * function expression instead of a `BoxedExpression` object.
252
442
  *
253
443
  */
254
- is(rhs: any): boolean;
255
- /** @internal */
256
- readonly hash: number;
257
- /** LaTeX representation of this expression.
444
+ get isStructural(): boolean;
445
+ /**
446
+ * Return the canonical form of this expression.
258
447
  *
259
- * If the expression was parsed from LaTeX, the LaTeX representation is
260
- * the same as the input LaTeX.
448
+ * If a function expression or symbol, they are first bound with a definition
449
+ * in the current scope.
261
450
  *
262
- * To customize the serialization, use `expr.toLatex()`.
451
+ * When determining the canonical form the following operator definition
452
+ * flags are applied:
453
+ * - `associative`: \\( f(a, f(b), c) \longrightarrow f(a, b, c) \\)
454
+ * - `idempotent`: \\( f(f(a)) \longrightarrow f(a) \\)
455
+ * - `involution`: \\( f(f(a)) \longrightarrow a \\)
456
+ * - `commutative`: sort the arguments.
457
+ *
458
+ * If this expression is already canonical, the value of canonical is
459
+ * `this`.
460
+ *
461
+ * The arguments of a canonical function expression may not all be
462
+ * canonical, for example in the `["Declare", "i", 2]` expression,
463
+ * `i` is not canonical since it is used only as the name of a symbol, not
464
+ * as a (potentially) existing symbol.
263
465
  *
264
466
  * :::info[Note]
265
- * Applicable to canonical and non-canonical expressions.
467
+ * Partially canonical expressions, such as those produced through
468
+ * `CanonicalForm`, also yield an expression which is marked as `canonical`.
469
+ * This means that, likewise for partially canonical expressions, the
470
+ * `canonical` property will return the self-same expression (and
471
+ * 'isCanonical' will also be true).
266
472
  * :::
267
473
  *
268
474
  */
269
- get latex(): LatexString;
475
+ get canonical(): BoxedExpression;
270
476
  /**
477
+ * Return the structural form of this expression.
478
+ *
479
+ * Some expressions, such as rational numbers, are represented with
480
+ * a `BoxedExpression` object. In some cases, for example when doing a
481
+ * structural comparison of two expressions, it is useful to have a
482
+ * structural representation of the expression where the rational numbers
483
+ * is represented by a function expression instead.
484
+ *
485
+ * If there is a structural representation of the expression, return it,
486
+ * otherwise return `this`.
487
+ *
488
+ */
489
+ get structural(): BoxedExpression;
490
+ /** `false` if this expression or any of its subexpressions is an `["Error"]`
491
+ * expression.
271
492
  *
272
493
  * :::info[Note]
273
- * Applicable to canonical and non-canonical expressions.
494
+ * Applicable to canonical and non-canonical expressions. For
495
+ * non-canonical expression, this may indicate a syntax error while parsing
496
+ * LaTeX. For canonical expression, this may indicate argument type
497
+ * mismatch, or missing or unexpected arguments.
274
498
  * :::
275
- * @internal
499
+ *
276
500
  */
277
- set latex(val: LatexString);
278
- /** If this expression is a symbol, return the name of the symbol as a string.
279
- * Otherwise, return `null`.
501
+ readonly isValid: boolean;
502
+ /** If *true*, evaluating this expression has no side-effects (does not
503
+ * change the state of the Compute Engine).
504
+ *
505
+ * If *false*, evaluating this expression may change the state of the
506
+ * Compute Engine or it may return a different value each time it is
507
+ * evaluated, even if the state of the Compute Engine is the same.
508
+ *
509
+ * As an example, the ["Add", 2, 3]` function expression is pure, but
510
+ * the `["Random"]` function expression is not pure.
511
+ *
512
+ * For a function expression to be pure, the function itself (its operator)
513
+ * must be pure, and all of its arguments must be pure too.
514
+ *
515
+ * A pure function expression may return a different value each time it is
516
+ * evaluated if its arguments are not constant. For example, the
517
+ * `["Add", "x", 1]` function expression is pure, but it is not
518
+ * constant, because `x` is not constant.
280
519
  *
281
520
  * :::info[Note]
282
- * Applicable to canonical and non-canonical expressions.
521
+ * Applicable to canonical expressions only
283
522
  * :::
523
+ */
524
+ readonly isPure: boolean;
525
+ /**
526
+ * `True` if evaluating this expression always returns the same value.
284
527
  *
285
- * @category Symbol Expression
528
+ * If *true* and a function expression, implies that it is *pure* and
529
+ * that all of its arguments are constant.
286
530
  *
531
+ * Number literals, symbols with constant values, and pure numeric functions
532
+ * with constant arguments are all *constant*, i.e.:
533
+ * - `42` is constant
534
+ * - `Pi` is constant
535
+ * - `["Divide", "Pi", 2]` is constant
536
+ * - `x` is not constant, unless declared with a constant flag.
537
+ * - `["Add", "x", 2]` is either constant only if `x` is constant.
287
538
  */
288
- readonly symbol: string | null;
289
- /** If this expression is a string, return the value of the string.
290
- * Otherwise, return `null`.
539
+ readonly isConstant: boolean;
540
+ /** All the `["Error"]` subexpressions.
541
+ *
542
+ * If an expression includes an error, the expression is also an error.
543
+ * In that case, the `this.isValid` property is `false`.
291
544
  *
292
545
  * :::info[Note]
293
546
  * Applicable to canonical and non-canonical expressions.
294
547
  * :::
295
-
296
- * @category String Expression
297
548
  *
298
549
  */
299
- readonly string: string | null;
300
- readonly tensor: null | TensorData<'expression'>;
550
+ readonly errors: ReadonlyArray<BoxedExpression>;
301
551
  /** All the subexpressions matching the named operator, recursively.
552
+ *
553
+ * Example:
554
+ *
555
+ * ```js
556
+ * const expr = ce.parse('a + b * c + d');
557
+ * const subexpressions = expr.getSubexpressions('Add');
558
+ * // -> `[['Add', 'a', 'b'], ['Add', 'c', 'd']]`
559
+ * ```
302
560
  *
303
561
  * :::info[Note]
304
562
  * Applicable to canonical and non-canonical expressions.
305
563
  * :::
306
564
  *
307
565
  */
308
- getSubexpressions(name: string): ReadonlyArray<BoxedExpression>;
566
+ getSubexpressions(operator: string): ReadonlyArray<BoxedExpression>;
309
567
  /** All the subexpressions in this expression, recursively
568
+ *
569
+ * Example:
570
+ *
571
+ * ```js
572
+ * const expr = ce.parse('a + b * c + d');
573
+ * const subexpressions = expr.subexpressions;
574
+ * // -> `[['Add', 'a', 'b'], ['Add', 'c', 'd'], 'a', 'b', 'c', 'd']`
575
+ * ```
310
576
  *
311
577
  * :::info[Note]
312
578
  * Applicable to canonical and non-canonical expressions.
@@ -318,6 +584,12 @@ export interface BoxedExpression {
318
584
  *
319
585
  * All the symbols in the expression, recursively
320
586
  *
587
+ * ```js
588
+ * const expr = ce.parse('a + b * c + d');
589
+ * const symbols = expr.symbols;
590
+ * // -> ['a', 'b', 'c', 'd']
591
+ * ```
592
+ *
321
593
  * :::info[Note]
322
594
  * Applicable to canonical and non-canonical expressions.
323
595
  * :::
@@ -325,42 +597,220 @@ export interface BoxedExpression {
325
597
  */
326
598
  readonly symbols: ReadonlyArray<string>;
327
599
  /**
328
- * All the identifiers used in the expression that do not have a value
600
+ * All the symbols used in the expression that do not have a value
329
601
  * associated with them, i.e. they are declared but not defined.
330
602
  */
331
603
  readonly unknowns: ReadonlyArray<string>;
332
604
  /**
605
+ * Return `true` if this expression is a number literal, for example
606
+ * `2`, `3.14`, `1/2`, `√2` etc.
607
+ *
608
+ * When `true`, `expr.numericValue` is not `null`.
333
609
  *
334
- * All the identifiers (symbols and functions) in the expression that are
335
- * not a local variable or a parameter of that function.
610
+ * @category Numeric Expression
336
611
  *
337
612
  */
338
- readonly freeVariables: ReadonlyArray<string>;
339
- /** All the `["Error"]` subexpressions.
613
+ readonly isNumberLiteral: boolean;
614
+ /**
615
+ * Return the value of this expression, if a number literal.
340
616
  *
341
- * If an expression includes an error, the expression is also an error.
342
- * In that case, the `this.isValid` property is `false`.
617
+ * Note it is possible for `expr.numericValue` to be `null`, and for
618
+ * `expr.isNotZero` to be true. For example, when a symbol has been
619
+ * defined with an assumption.
343
620
  *
344
- * :::info[Note]
345
- * Applicable to canonical and non-canonical expressions.
346
- * :::
621
+ * Conversely, `expr.isNumber` may be true even if `expr.numericValue` is
622
+ * `null`, for example the symbol `Pi` return `true` for `isNumber` but
623
+ * `expr.numericValue` is `null` (it's a symbol, not a number literal).
624
+ * Its value can be accessed with `expr.value`.
625
+ *
626
+ * To check if an expression is a number literal, use `expr.isNumberLiteral`.
627
+ * If `expr.isNumberLiteral` is `true`, `expr.numericValue` is not `null`.
628
+ *
629
+ * @category Numeric Expression
347
630
  *
348
631
  */
349
- readonly errors: ReadonlyArray<BoxedExpression>;
350
- /** `true` if this expression or any of its subexpressions is an `["Error"]`
351
- * expression.
632
+ readonly numericValue: number | NumericValue | null;
633
+ /**
634
+ * Attempt to factor a numeric coefficient `c` and a `rest` out of a
635
+ * canonical expression such that `rest.mul(c)` is equal to `this`.
636
+ *
637
+ * Attempts to make `rest` a positive value (i.e. pulls out negative sign).
638
+ *
639
+ *```json
640
+ * ['Multiply', 2, 'x', 3, 'a']
641
+ * -> [NumericValue(6), ['Multiply', 'x', 'a']]
642
+ *
643
+ * ['Divide', ['Multiply', 2, 'x'], ['Multiply', 3, 'y', 'a']]
644
+ * -> [NumericValue({rational: [2, 3]}), ['Divide', 'x', ['Multiply, 'y', 'a']]]
645
+ * ```
646
+ */
647
+ toNumericValue(): [NumericValue, BoxedExpression];
648
+ /**
649
+ * If the value of this expression is not an **integer** return `undefined`.
650
+ *
651
+ * @category Numeric Expression
652
+ */
653
+ readonly isEven: boolean | undefined;
654
+ /**
655
+ * If the value of this expression is not an **integer** return `undefined`.
656
+ *
657
+ * @category Numeric Expression
658
+ */
659
+ readonly isOdd: boolean | undefined;
660
+ /**
661
+ * Return the real part of the value of this expression, if a number.
662
+ *
663
+ * Otherwise, return `NaN` (not a number).
664
+ *
665
+ * @category Numeric Expression
666
+ */
667
+ readonly re: number;
668
+ /**
669
+ * If value of this expression is a number, return the imaginary part of the
670
+ * value. If the value is a real number, the imaginary part is 0.
671
+ *
672
+ * Otherwise, return `NaN` (not a number).
673
+ *
674
+ * @category Numeric Expression
675
+ */
676
+ readonly im: number;
677
+ /**
678
+ * If the value of this expression is a number, return the real part of the
679
+ * value as a `BigNum`.
680
+ *
681
+ * If the value is not available as a bignum return `undefined`. That is,
682
+ * the value is not upconverted to a bignum.
683
+ *
684
+ * To get the real value either as a bignum or a number, use
685
+ * `expr.bignumRe ?? expr.re`.
686
+ *
687
+ * When using this pattern, the value is returned as a bignum if available,
688
+ * otherwise as a number or `NaN` if the value is not a number.
689
+ *
690
+ * @category Numeric Expression
691
+ *
692
+ */
693
+ readonly bignumRe: BigNum | undefined;
694
+ /**
695
+ * If the value of this expression is a number, return the imaginary part as
696
+ * a `BigNum`.
697
+ *
698
+ * It may be 0 if the number is real.
699
+ *
700
+ * If the value of the expression is not a number or the value is not
701
+ * available as a bignum return `undefined`. That is, the value is not
702
+ * upconverted to a bignum.
703
+ *
704
+ * To get the imaginary value either as a bignum or a number, use
705
+ * `expr.bignumIm ?? expr.im`.
706
+ *
707
+ * When using this pattern, the value is returned as a bignum if available, otherwise as a number or `NaN` if the value is not a number.
708
+ *
709
+ * @category Numeric Expression
710
+ */
711
+ readonly bignumIm: BigNum | undefined;
712
+ /**
713
+ * Return the sign of the expression.
714
+ *
715
+ * Note that complex numbers have no natural ordering, so if the value is an
716
+ * imaginary number (a complex number with a non-zero imaginary part),
717
+ * `this.sgn` will return `unsigned`.
718
+ *
719
+ * If a symbol, this does take assumptions into account, that is `this.sgn`
720
+ * will return `positive` if the symbol is assumed to be positive
721
+ * using `ce.assume()`.
722
+ *
723
+ * Non-canonical expressions return `undefined`.
724
+ *
725
+ * @category Numeric Expression
726
+ *
727
+ */
728
+ readonly sgn: Sign | undefined;
729
+ /** The value of this expression is > 0, same as `isGreaterEqual(0)`
730
+ *
731
+ * @category Numeric Expression
732
+ */
733
+ readonly isPositive: boolean | undefined;
734
+ /** The value of this expression is >= 0, same as `isGreaterEqual(0)`
735
+ *
736
+ * @category Numeric Expression
737
+ */
738
+ readonly isNonNegative: boolean | undefined;
739
+ /** The value of this expression is &lt; 0, same as `isLess(0)`
740
+ *
741
+ * @category Numeric Expression
742
+ */
743
+ readonly isNegative: boolean | undefined;
744
+ /** The value of this expression is &lt;= 0, same as `isLessEqual(0)`
745
+ *
746
+ * @category Numeric Expression
747
+ */
748
+ readonly isNonPositive: boolean | undefined;
749
+ /** Negate (additive inverse) */
750
+ neg(): BoxedExpression;
751
+ /** Inverse (multiplicative inverse) */
752
+ inv(): BoxedExpression;
753
+ /** Absolute value */
754
+ abs(): BoxedExpression;
755
+ /** Addition */
756
+ add(rhs: number | BoxedExpression): BoxedExpression;
757
+ /** Subtraction */
758
+ sub(rhs: BoxedExpression): BoxedExpression;
759
+ /** Multiplication */
760
+ mul(rhs: NumericValue | number | BoxedExpression): BoxedExpression;
761
+ /** Division */
762
+ div(rhs: number | BoxedExpression): BoxedExpression;
763
+ /** Power */
764
+ pow(exp: number | BoxedExpression): BoxedExpression;
765
+ /** Exponentiation */
766
+ root(exp: number | BoxedExpression): BoxedExpression;
767
+ /** Square root */
768
+ sqrt(): BoxedExpression;
769
+ /** Logarithm (natural by default) */
770
+ ln(base?: number | BoxedExpression): BoxedExpression;
771
+ /**
772
+ * Return this expression expressed as a numerator.
773
+ */
774
+ get numerator(): BoxedExpression;
775
+ /**
776
+ * Return this expression expressed as a denominator.
777
+ */
778
+ get denominator(): BoxedExpression;
779
+ /**
780
+ * Return this expression expressed as a numerator and denominator.
781
+ */
782
+ get numeratorDenominator(): [BoxedExpression, BoxedExpression];
783
+ /** If this expression is a symbol, return the name of the symbol as a string.
784
+ * Otherwise, return `null`.
352
785
  *
353
786
  * :::info[Note]
354
- * Applicable to canonical and non-canonical expressions. For
355
- * non-canonical expression, this may indicate a syntax error while parsing
356
- * LaTeX. For canonical expression, this may indicate argument type
357
- * mismatch, or missing or unexpected arguments.
787
+ * Applicable to canonical and non-canonical expressions.
358
788
  * :::
359
789
  *
360
790
  * @category Symbol Expression
361
791
  *
362
792
  */
363
- readonly isValid: boolean;
793
+ readonly symbol: string | null;
794
+ /** If this expression is a string, return the value of the string.
795
+ * Otherwise, return `null`.
796
+ *
797
+ * :::info[Note]
798
+ * Applicable to canonical and non-canonical expressions.
799
+ * :::
800
+
801
+ * @category String Expression
802
+ *
803
+ */
804
+ readonly string: string | null;
805
+ /**
806
+ * Return `true` if this expression is a function expression.
807
+ *
808
+ * If `true`, `expr.ops` is not `null`, and `expr.operator` is the name
809
+ * of the function.
810
+ *
811
+ * @category Function Expression
812
+ */
813
+ readonly isFunctionExpression: boolean;
364
814
  /**
365
815
  * The name of the operator of the expression.
366
816
  *
@@ -370,8 +820,11 @@ export interface BoxedExpression {
370
820
  *
371
821
  * A symbol has a `"Symbol"` operator.
372
822
  *
373
- * A number has a `"Number"`, `"Real"`, `"Rational"` or `"Integer"` operator.
823
+ * A number has a `"Number"`, `"Real"`, `"Rational"` or `"Integer"` operator; amongst some others.
824
+ * Practically speaking, for fully canonical and valid expressions, all of these are likely to
825
+ * collapse to `"Number"`.
374
826
  *
827
+ * @category Function Expression
375
828
  */
376
829
  readonly operator: string;
377
830
  /** The list of operands of the function.
@@ -438,71 +891,18 @@ export interface BoxedExpression {
438
891
  *
439
892
  */
440
893
  readonly op3: BoxedExpression;
441
- /** If true, the value of the expression never changes and evaluating it has
442
- * no side-effects.
443
- *
444
- * If false, the value of the expression may change, if the
445
- * value of other expression changes or for other reasons.
446
- *
447
- * If `this.isPure` is `false`, `this.value` is undefined. Call
448
- * `this.evaluate()` to determine the value of the expression instead.
449
- *
450
- * As an example, the `Random` function is not pure.
451
- *
452
- * :::info[Note]
453
- * Applicable to canonical and non-canonical expressions.
454
- * :::
455
- */
456
- readonly isPure: boolean;
457
- /**
458
- * True if the the value of the expression does not depend on the value of
459
- * any other expression.
460
- *
461
- * For example, a number literal, a symbol with a constant value.
462
- * - `2` is constant
463
- * - `Pi` is constant
464
- * - `["Add", "Pi", 2]` is constant
465
- * - `x` is not constant
466
- * - `["Add", "x", 2]` is not constant
894
+ /** If true, the expression has its own local scope that can be used
895
+ * for local variables and arguments. Only true if the expression is a
896
+ * function expression.
467
897
  */
468
- readonly isConstant: boolean;
469
- /**
470
- * Return the canonical form of this expression.
471
- *
472
- * If this is a function expression, a definition is associated with the
473
- * canonical expression.
474
- *
475
- * When determining the canonical form the following function definition
476
- * flags are applied:
477
- * - `associative`: \\( f(a, f(b), c) \longrightarrow f(a, b, c) \\)
478
- * - `idempotent`: \\( f(f(a)) \longrightarrow f(a) \\)
479
- * - `involution`: \\( f(f(a)) \longrightarrow a \\)
480
- * - `commutative`: sort the arguments.
481
- *
482
- * If this expression is already canonical, the value of canonical is
483
- * `this`.
484
- *
485
- */
486
- get canonical(): BoxedExpression;
487
- /**
488
- * Return the structural form of this expression.
489
- *
490
- * Some expressions, such as rational numbers, are represented with
491
- * a `BoxedExpression` object. In some cases, for example when doing a
492
- * structural comparison of two expressions, it is useful to have a
493
- * structural representation of the expression where the rational numbers
494
- * is represented by a function expression instead.
495
- *
496
- * If there is a structural representation of the expression, return it,
497
- * otherwise return `this`.
498
- *
499
- */
500
- get structural(): BoxedExpression;
898
+ readonly isScoped: boolean;
899
+ /** If this expression has a local scope, return it. */
900
+ get localScope(): Scope | undefined;
501
901
  /**
502
902
  * Replace all the symbols in the expression as indicated.
503
903
  *
504
904
  * Note the same effect can be achieved with `this.replace()`, but
505
- * using `this.subs()` is more efficient, and simpler, but limited
905
+ * using `this.subs()` is more efficient and simpler, but limited
506
906
  * to replacing symbols.
507
907
  *
508
908
  * The result is bound to the current scope, not to `this.scope`.
@@ -511,396 +911,281 @@ export interface BoxedExpression {
511
911
  * is canonical.
512
912
  *
513
913
  * :::info[Note]
514
- * Applicable to canonical and non-canonical expressions.
515
- * :::
516
- *
517
- */
518
- subs(sub: Substitution, options?: {
519
- canonical?: CanonicalOptions;
520
- }): BoxedExpression;
521
- /**
522
- * Recursively replace all the subexpressions in the expression as indicated.
523
- *
524
- * To remove a subexpression, return an empty `["Sequence"]` expression.
525
- *
526
- * The canonical option is applied to each function subexpression after
527
- * the substitution is applied.
528
- *
529
- * If no `options.canonical` is set, the result is canonical if `this`
530
- * is canonical.
531
- *
532
- * **Default**: `{ canonical: this.isCanonical, recursive: true }`
533
- */
534
- map(fn: (expr: BoxedExpression) => BoxedExpression, options?: {
535
- canonical: CanonicalOptions;
536
- recursive?: boolean;
537
- }): BoxedExpression;
538
- /**
539
- * Transform the expression by applying one or more replacement rules:
540
- *
541
- * - If the expression matches the `match` pattern and the `condition`
542
- * predicate is true, replace it with the `replace` pattern.
543
- *
544
- * - If no rules apply, return `null`.
545
- *
546
- * See also `expr.subs()` for a simple substitution of symbols.
547
- *
548
- * If `options.canonical` is not set, the result is canonical if `this`
549
- * is canonical.
550
- *
551
- * :::info[Note]
552
- * Applicable to canonical and non-canonical expressions.
553
- * :::
554
- */
555
- replace(rules: BoxedRuleSet | Rule | Rule[], options?: Partial<ReplaceOptions>): null | BoxedExpression;
556
- /**
557
- * True if the expression includes a symbol `v` or a function operator `v`.
558
- *
559
- * :::info[Note]
560
- * Applicable to canonical and non-canonical expressions.
561
- * :::
562
- */
563
- has(v: string | string[]): boolean;
564
- /** Structural/symbolic equality (weak equality).
565
- *
566
- * `ce.parse('1+x').isSame(ce.parse('x+1'))` is `false`.
567
- *
568
- * See `expr.isEqual()` for mathematical equality.
569
- *
570
- * :::info[Note]
571
- * Applicable to canonical and non-canonical expressions.
572
- * :::
573
- *
574
- * @category Relational Operator
575
- */
576
- isSame(rhs: BoxedExpression): boolean;
577
- /**
578
- * Return this expression expressed as a numerator and denominator.
579
- */
580
- get numerator(): BoxedExpression;
581
- get denominator(): BoxedExpression;
582
- get numeratorDenominator(): [BoxedExpression, BoxedExpression];
583
- /**
584
- * If this expression matches `pattern`, return a substitution that makes
585
- * `pattern` equal to `this`. Otherwise return `null`.
586
- *
587
- * If `pattern` includes wildcards (identifiers that start
588
- * with `_`), the substitution will include a prop for each matching named
589
- * wildcard.
590
- *
591
- * If this expression matches `pattern` but there are no named wildcards,
592
- * return the empty substitution, `{}`.
593
- *
594
- * Read more about [**patterns and rules**](/compute-engine/guides/patterns-and-rules/).
595
- *
596
- * :::info[Note]
597
- * Applicable to canonical and non-canonical expressions.
598
- * :::
599
- *
600
- */
601
- match(pattern: BoxedExpression, options?: PatternMatchOptions): BoxedSubstitution | null;
602
- /**
603
- * "Not a Number".
604
- *
605
- * A value representing undefined result of computations, such as `0/0`,
606
- * as per the floating point format standard IEEE-754.
607
- *
608
- * Note that if `isNaN` is true, `isNumber` is also true (yes, `NaN` is a
609
- * number).
610
- *
611
- * @category Numeric Expression
612
- *
613
- */
614
- readonly isNaN: boolean | undefined;
615
- /**
616
- * The numeric value of this expression is `±Infinity` or Complex Infinity
617
- *
618
- * @category Numeric Expression
619
- */
620
- readonly isInfinity: boolean | undefined;
621
- /** This expression is a number, but not `±Infinity`, 'ComplexInfinity` or
622
- * `NaN`
914
+ * Applicable to canonical and non-canonical expressions.
915
+ * :::
623
916
  *
624
- * @category Numeric Expression
625
- */
626
- readonly isFinite: boolean | undefined;
627
- /**
628
- * @category Numeric Expression
629
- */
630
- readonly isEven: boolean | undefined;
631
- /**
632
- * @category Numeric Expression
633
917
  */
634
- readonly isOdd: boolean | undefined;
918
+ subs(sub: Substitution, options?: {
919
+ canonical?: CanonicalOptions;
920
+ }): BoxedExpression;
635
921
  /**
636
- * Return the value of this expression, if a number literal.
922
+ * Recursively replace all the subexpressions in the expression as indicated.
637
923
  *
638
- * Note it is possible for `this.numericValue` to be `null`, and for
639
- * `this.isNotZero` to be true. For example, when a symbol has been
640
- * defined with an assumption.
924
+ * To remove a subexpression, return an empty `["Sequence"]` expression.
641
925
  *
642
- * Conversely, `this.isNumber` may be true even if `numericValue` is `null`,
643
- * example the symbol `Pi` return `true` for `isNumber` but `numericValue` is
644
- * `null`. Its value can be accessed with `.N().numericValue`.
926
+ * The `canonical` option is applied to each function subexpression after
927
+ * the substitution is applied.
645
928
  *
646
- * To check if an expression is a number literal, use `this.isNumberLiteral`.
647
- * If `this.isNumberLiteral` is `true`, `this.numericValue` is not `null`
929
+ * If no `options.canonical` is set, the result is canonical if `this`
930
+ * is canonical.
648
931
  *
649
- * @category Numeric Expression
932
+ * **Default**: `{ canonical: this.isCanonical, recursive: true }`
650
933
  *
934
+ * :::info[Note]
935
+ * Applicable to canonical and non-canonical expressions.
936
+ * :::
651
937
  */
652
- readonly numericValue: number | NumericValue | null;
938
+ map(fn: (expr: BoxedExpression) => BoxedExpression, options?: {
939
+ canonical: CanonicalOptions;
940
+ recursive?: boolean;
941
+ }): BoxedExpression;
653
942
  /**
654
- * Return `true` if this expression is a number literal, for example
655
- * `2`, `3.14`, `1/2`, `√2` etc.
943
+ * Transform the expression by applying one or more replacement rules:
944
+ *
945
+ * - If the expression matches the `match` pattern and the `condition`
946
+ * predicate is true, replace it with the `replace` pattern.
656
947
  *
657
- * This is equivalent to checking if `this.numericValue` is not `null`.
948
+ * - If no rules apply, return `null`.
658
949
  *
659
- * @category Numeric Expression
950
+ * See also `expr.subs()` for a simple substitution of symbols.
951
+ *
952
+ * If `options.canonical` is not set, the result is canonical if `this`
953
+ * is canonical.
660
954
  *
955
+ * :::info[Note]
956
+ * Applicable to canonical and non-canonical expressions.
957
+ * :::
661
958
  */
662
- readonly isNumberLiteral: boolean;
959
+ replace(rules: BoxedRuleSet | Rule | Rule[], options?: Partial<ReplaceOptions>): null | BoxedExpression;
663
960
  /**
664
- * Return `true` if this expression is a function expression.
961
+ * True if the expression includes a symbol `v` or a function operator `v`.
665
962
  *
666
- * If `true`, `this.ops` is not `null`, and `this.operator` is the name
667
- * of the function.
963
+ * :::info[Note]
964
+ * Applicable to canonical and non-canonical expressions.
965
+ * :::
668
966
  */
669
- readonly isFunctionExpression: boolean;
670
- /**
671
- * If this expression is a number literal or a symbol with a value that
672
- * is a number literal, return the real part of the value.
967
+ has(v: string | string[]): boolean;
968
+ /** Structural/symbolic equality (weak equality).
673
969
  *
674
- * If the expression is not a number literal, or a symbol with a value
675
- * that is a number literal, return `NaN` (not a number).
970
+ * `ce.parse('1+x', {canonical: false}).isSame(ce.parse('x+1', {canonical: false}))` is `false`.
676
971
  *
677
- * @category Numeric Expression
678
- */
679
- readonly re: number;
680
- /**
681
- * If this expression is a number literal or a symbol with a value that
682
- * is a number literal, return the imaginary part of the value. If the value
683
- * is a real number, the imaginary part is 0.
972
+ * See `expr.isEqual()` for mathematical equality.
684
973
  *
685
- * If the expression is not a number literal, or a symbol with a value
686
- * that is a number literal, return `NaN` (not a number).
974
+ * :::info[Note]
975
+ * Applicable to canonical and non-canonical expressions.
976
+ * :::
687
977
  *
688
- * @category Numeric Expression
978
+ * @category Relational Operator
689
979
  */
690
- readonly im: number;
980
+ isSame(rhs: BoxedExpression): boolean;
691
981
  /**
692
- * If this expression is a number literal or a symbol with a value that
693
- * is a number literal, return the real part of the value as a `BigNum`.
694
- *
695
- * If the value is not available as a bignum return `undefined`. That is,
696
- * the value is not upconverted to a bignum.
697
- *
698
- * To get the real value either as a bignum or a number, use
699
- * `this.bignumRe ?? this.re`. When using this pattern, the value is
700
- * returned as a bignum if available, otherwise as a number or NaN if
701
- * the value is not a number literal or a symbol with a value that is a
702
- * number literal.
982
+ * Equivalent to `BoxedExpression.isSame()` but the argument can be
983
+ * a JavaScript primitive. For example, `expr.is(2)` is equivalent to
984
+ * `expr.isSame(ce.number(2))`.
703
985
  *
704
- * @category Numeric Expression
986
+ * @category Primitive Methods
705
987
  *
706
988
  */
707
- readonly bignumRe: BigNum | undefined;
989
+ is(other: BoxedExpression | number | bigint | boolean | string): boolean;
708
990
  /**
709
- * If this expression is a number literal, return the imaginary part as a
710
- * `BigNum`.
991
+ * If this expression matches `pattern`, return a substitution that makes
992
+ * `pattern` equal to `this`. Otherwise return `null`.
711
993
  *
712
- * It may be 0 if the number is real.
994
+ * If `pattern` includes wildcards (symbols that start
995
+ * with `_`), the substitution will include a prop for each matching named
996
+ * wildcard.
997
+ *
998
+ * If this expression matches `pattern` but there are no named wildcards,
999
+ * return the empty substitution, `{}`.
713
1000
  *
714
- * If the expression is not a number literal or the value is not available
715
- * as a bignum return `undefined`. That is, the value is not upconverted
716
- * to a bignum.
1001
+ * Read more about [**patterns and rules**](/compute-engine/guides/patterns-and-rules/).
717
1002
  *
718
- * To get the imaginary value either as a bignum or a number, use
719
- * `this.bignumIm ?? this.im`. When using this pattern, the value is
720
- * returned as a bignum if available, otherwise as a number or NaN if
721
- * the value is not a number literal or a symbol with a value that is a
722
- * number literal.
1003
+ * :::info[Note]
1004
+ * Applicable to canonical and non-canonical expressions.
1005
+ * :::
723
1006
  *
724
- * @category Numeric Expression
725
1007
  */
726
- readonly bignumIm: BigNum | undefined;
727
- /**
728
- * Attempt to factor a numeric coefficient `c` and a `rest` out of a
729
- * canonical expression such that `rest.mul(c)` is equal to `this`.
1008
+ match(pattern: BoxedExpression, options?: PatternMatchOptions): BoxedSubstitution | null;
1009
+ /** If this expression is a tensor, return the tensor data.
1010
+ * Otherwise, return `null`.
730
1011
  *
731
- * Attempts to make `rest` a positive value (i.e. pulls out negative sign).
1012
+ * :::info[Note]
1013
+ * Applicable to canonical and non-canonical expressions.
1014
+ * :::
732
1015
  *
733
- *```json
734
- * ['Multiply', 2, 'x', 3, 'a']
735
- * -> [NumericValue(6), ['Multiply', 'x', 'a']]
1016
+ * @category Tensor Expression
736
1017
  *
737
- * ['Divide', ['Multiply', 2, 'x'], ['Multiply', 3, 'y', 'a']]
738
- * -> [NumericValue({rational: [2, 3]}), ['Divide', 'x', ['Multiply, 'y', 'a']]]
739
- * ```
740
1018
  */
741
- toNumericValue(): [NumericValue, BoxedExpression];
742
- neg(): BoxedExpression;
743
- inv(): BoxedExpression;
744
- abs(): BoxedExpression;
745
- add(rhs: number | BoxedExpression): BoxedExpression;
746
- sub(rhs: BoxedExpression): BoxedExpression;
747
- mul(rhs: NumericValue | number | BoxedExpression): BoxedExpression;
748
- div(rhs: number | BoxedExpression): BoxedExpression;
749
- pow(exp: number | BoxedExpression): BoxedExpression;
750
- root(exp: number | BoxedExpression): BoxedExpression;
751
- sqrt(): BoxedExpression;
752
- ln(base?: number | BoxedExpression): BoxedExpression;
1019
+ readonly tensor: null | Tensor<any>;
753
1020
  /**
754
1021
  *
755
- * The shape describes the axis of the expression.
1022
+ * The **shape** describes the **axes** of the expression, where each axis
1023
+ * represent a way to index the elements of the expression.
756
1024
  *
757
1025
  * When the expression is a scalar (number), the shape is `[]`.
758
1026
  *
759
1027
  * When the expression is a vector of length `n`, the shape is `[n]`.
760
1028
  *
761
1029
  * When the expression is a `n` by `m` matrix, the shape is `[n, m]`.
1030
+ *
1031
+ * @category Tensor Expression
1032
+ *
762
1033
  */
763
1034
  readonly shape: number[];
764
- /** Return 0 for a scalar, 1 for a vector, 2 for a matrix, > 2 for
765
- * a multidimensional matrix.
766
- *
767
- * The rank is equivalent to the length of `expr.shape` */
768
- readonly rank: number;
769
1035
  /**
770
- * Return the sign of the expression.
1036
+ * The **rank** refers to the number of dimensions (or axes) of the
1037
+ * expression.
771
1038
  *
772
- * Note that complex numbers have no natural ordering,
773
- * so if the value is an imaginary number (a complex number with a non-zero
774
- * imaginary part), `this.sgn` will return `unsigned`.
1039
+ * Return 0 for a scalar, 1 for a vector, 2 for a matrix, > 2 for
1040
+ * a multidimensional matrix.
775
1041
  *
776
- * If a symbol, this does take assumptions into account, that is `this.sgn`
777
- * will return `positive` if the symbol is assumed to be positive
778
- * (using `ce.assume()`).
1042
+ * The rank is equivalent to the length of `expr.shape`
779
1043
  *
780
- * @category Numeric Expression
1044
+ * :::info[Note]
1045
+ * There are several definitions of rank in the literature.
1046
+ * For example, the row rank of a matrix is the number of linearly
1047
+ * independent rows. The rank can also refer to the number of non-zero
1048
+ * singular values of a matrix.
1049
+ * :::
781
1050
  *
782
- */
783
- readonly sgn: Sign | undefined;
784
- /** If the expressions cannot be compared, return `undefined`
1051
+ * @category Tensor Expression
1052
+ * */
1053
+ readonly rank: number;
1054
+ /**
785
1055
  *
786
- * The numeric value of both expressions are compared.
1056
+ * The value of both expressions are compared.
787
1057
  *
788
- * The expressions are evaluated before being compared, which may be
789
- * expensive.
1058
+ * If the expressions cannot be compared, return `undefined`
790
1059
  *
791
1060
  * @category Relational Operator
792
1061
  */
793
1062
  isLess(other: number | BoxedExpression): boolean | undefined;
794
1063
  /**
795
- * The numeric value of both expressions are compared.
1064
+ * The value of both expressions are compared.
1065
+ *
1066
+ * If the expressions cannot be compared, return `undefined`
796
1067
  * @category Relational Operator
797
1068
  */
798
1069
  isLessEqual(other: number | BoxedExpression): boolean | undefined;
799
1070
  /**
800
- * The numeric value of both expressions are compared.
1071
+ * The value of both expressions are compared.
1072
+ *
1073
+ * If the expressions cannot be compared, return `undefined`
801
1074
  * @category Relational Operator
802
1075
  */
803
1076
  isGreater(other: number | BoxedExpression): boolean | undefined;
804
1077
  /**
805
- * The numeric value of both expressions are compared.
1078
+ * The value of both expressions are compared.
1079
+ *
1080
+ * If the expressions cannot be compared, return `undefined`
806
1081
  * @category Relational Operator
807
1082
  */
808
1083
  isGreaterEqual(other: number | BoxedExpression): boolean | undefined;
809
- /** The numeric value of this expression is > 0, same as `isGreater(0)`
1084
+ /**
1085
+ * If true, the value of this expression is "Not a Number".
810
1086
  *
811
- * @category Numeric Expression
812
- */
813
- readonly isPositive: boolean | undefined;
814
- /** The numeric value of this expression is >= 0, same as `isGreaterEqual(0)`
1087
+ * A value representing undefined result of computations, such as `0/0`,
1088
+ * as per the floating point format standard IEEE-754.
1089
+ *
1090
+ * Note that if `isNaN` is true, `isNumber` is also true (yes, `NaN` is a
1091
+ * number).
815
1092
  *
816
1093
  * @category Numeric Expression
1094
+ *
817
1095
  */
818
- readonly isNonNegative: boolean | undefined;
819
- /** The numeric value of this expression is < 0, same as `isLess(0)`
1096
+ readonly isNaN: boolean | undefined;
1097
+ /**
1098
+ * The numeric value of this expression is `±Infinity` or ComplexInfinity.
820
1099
  *
821
1100
  * @category Numeric Expression
822
1101
  */
823
- readonly isNegative: boolean | undefined;
824
- /** The numeric value of this expression is &lt;= 0, same as `isLessEqual(0)`
1102
+ readonly isInfinity: boolean | undefined;
1103
+ /** This expression is a number, but not `±Infinity`, `ComplexInfinity` or
1104
+ * `NaN`
825
1105
  *
826
1106
  * @category Numeric Expression
827
1107
  */
828
- readonly isNonPositive: boolean | undefined;
829
- /** Wikidata identifier.
1108
+ readonly isFinite: boolean | undefined;
1109
+ /**
1110
+ * Wikidata identifier.
1111
+ *
1112
+ * If not a canonical expression, return `undefined`.
830
1113
  *
831
- * :::info[Note]
832
- * `undefined` if not a canonical expression.
833
- * :::
834
1114
  */
835
1115
  readonly wikidata: string | undefined;
836
1116
  /** An optional short description if a symbol or function expression.
837
1117
  *
838
1118
  * May include markdown. Each string is a paragraph.
839
1119
  *
840
- * :::info[Note]
841
- * `undefined` if not a canonical expression.
842
- * :::
1120
+ * If not a canonical expression, return `undefined`.
843
1121
  *
844
1122
  */
845
1123
  readonly description: undefined | string[];
846
1124
  /** An optional URL pointing to more information about the symbol or
847
1125
  * function operator.
848
1126
  *
849
- * :::info[Note]
850
- * `undefined` if not a canonical expression.
851
- * :::
1127
+ * If not a canonical expression, return `undefined`.
852
1128
  *
853
1129
  */
854
1130
  readonly url: string | undefined;
855
1131
  /** Expressions with a higher complexity score are sorted
856
1132
  * first in commutative functions
857
1133
  *
858
- * :::info[Note]
859
- * `undefined` if not a canonical expression.
860
- * :::
1134
+ * If not a canonical expression, return `undefined`.
861
1135
  */
862
1136
  readonly complexity: number | undefined;
863
1137
  /**
864
1138
  * For symbols and functions, a definition associated with the
865
- * expression. `this.baseDefinition` is the base class of symbol and function
866
- * definition.
1139
+ * expression. `this.baseDefinition` is the base class of symbol and function
1140
+ * definition.
867
1141
  *
868
- * :::info[Note]
869
- * `undefined` if not a canonical expression.
870
- * :::
1142
+ * If not a canonical expression, return `undefined`.
871
1143
  *
872
1144
  */
873
1145
  readonly baseDefinition: BoxedBaseDefinition | undefined;
874
1146
  /**
875
- * For functions, a definition associated with the expression.
1147
+ * For function expressions, the definition of the operator associated with
1148
+ * the expression. For symbols, the definition of the symbol if it is an
1149
+ * operator, for example `"Sin"`.
876
1150
  *
877
- * :::info[Note]
878
- * `undefined` if not a canonical expression or not a function.
879
- * :::
1151
+ * If not a canonical expression or not a function expression,
1152
+ * its value is `undefined`.
880
1153
  *
881
1154
  */
882
- readonly functionDefinition: BoxedFunctionDefinition | undefined;
1155
+ readonly operatorDefinition: BoxedOperatorDefinition | undefined;
883
1156
  /**
884
- * For symbols, a definition associated with the expression.
1157
+ * For symbols, a definition associated with the expression, if it is
1158
+ * not an operator.
885
1159
  *
886
- * Return `undefined` if not a symbol
1160
+ * If not a canonical expression, or not a value, its value is `undefined`.
887
1161
  *
888
1162
  */
889
- readonly symbolDefinition: BoxedSymbolDefinition | undefined;
1163
+ readonly valueDefinition: BoxedValueDefinition | undefined;
890
1164
  /**
891
1165
  *
892
1166
  * Infer the type of this expression.
893
1167
  *
894
- * If the type of this expression is already known, return `false`.
1168
+ * For symbols, inference may take place for undeclared symbols,
1169
+ * symbols with an `unknown` type, or symbols with an inferred type.
895
1170
  *
896
- * If the type was not set, set it to the inferred type, return `true`
897
- * If the type was previously inferred, widen it and return `true`.
1171
+ * Constant symbols always have a defined type, and will return `false`.
1172
+ *
1173
+ * For functions, inference only takes place if it has an *inferred
1174
+ * signature*.
1175
+ *
1176
+ *
1177
+ * For a successful inference, *narrows* the type for symbols,
1178
+ * and for functions, narrows the *(return) type*.
1179
+ *
1180
+ * Subsequent inferences can be made and will refine previous ones if valid.
1181
+ *
1182
+ * If the given type is incompatible with the declared or previously inferred
1183
+ * type, return `false`.
898
1184
  *
899
- * If the type cannot be inferred, return `false`.
900
1185
  *
901
1186
  * @internal
902
1187
  */
903
- infer(t: Type): boolean;
1188
+ infer(t: Type, inferenceMode?: 'narrow' | 'widen'): boolean;
904
1189
  /**
905
1190
  * Update the definition associated with this expression, using the
906
1191
  * current scope (`ce.context`).
@@ -947,23 +1232,18 @@ export interface BoxedExpression {
947
1232
  /**
948
1233
  * Return the value of the canonical form of this expression.
949
1234
  *
950
- * A pure expression always return the same value and has no side effects.
951
- * If `expr.isPure` is `true`, `expr.value` and `expr.evaluate()` are
952
- * synonyms.
953
- *
954
- * For an impure expression, `expr.value` is undefined.
955
- *
956
- * Evaluating an impure expression may have some side effects, for
957
- * example modifying the `ComputeEngine` environment, such as its set of
958
- * assumptions.
1235
+ * A pure expression always returns the same value (provided that it
1236
+ * remains constant / values of sub-expressions or symbols do not change),
1237
+ * and has no side effects.
959
1238
  *
960
- * The result may be a rational number or the product of a rational number
961
- * and the square root of an integer.
1239
+ * Evaluating an impure expression may return a varying value, and may have
1240
+ * some side effects such as adjusting symbol assumptions.
962
1241
  *
963
1242
  * To perform approximate calculations, use `expr.N()` instead,
964
- * or set `options.numericApproximation` to `true`.
1243
+ * or call with `options.numericApproximation` to `true`.
965
1244
  *
966
- * The result of `expr.evaluate()` may be the same as `expr.simplify()`.
1245
+ * It is possible that the result of `expr.evaluate()` may be the same as
1246
+ * `expr.simplify()`.
967
1247
  *
968
1248
  * The result is in canonical form.
969
1249
  *
@@ -1000,72 +1280,101 @@ export interface BoxedExpression {
1000
1280
  *
1001
1281
  *
1002
1282
  * ```javascript
1003
- * const expr = ce.parse('x^2 + y^2');
1283
+ * const expr = ce.parse("x^2 + y^2");
1004
1284
  * const f = expr.compile();
1005
1285
  * console.log(f({x: 2, y: 3}));
1286
+ * // -> 13
1006
1287
  * ```
1288
+ *
1289
+ * If the expression is a function literal, the function takes the
1290
+ * arguments of the function as arguments, and returns the value of the
1291
+ * expression.
1292
+ *
1293
+ * ```javascript
1294
+ * const expr = ce.parse("(x) \mapsto 2x");
1295
+ * const f = expr.compile();
1296
+ * console.log(f(42));
1297
+ * // -> 84
1298
+ * ```
1299
+ *
1300
+ * If the expression cannot be compiled, a JS function is returned that
1301
+ * falls back to the interpreting the expression, unless the
1302
+ * `options.fallback` is set to `false`. If it is set to `false`, the
1303
+ * function will throw an error if it cannot be compiled.
1304
+ *
1007
1305
  */
1008
1306
  compile(options?: {
1009
1307
  to?: 'javascript';
1010
- optimize?: ('simplify' | 'evaluate')[];
1011
- functions?: Record<MathJsonIdentifier, JSSource | ((...any: any[]) => any)>;
1012
- vars?: Record<MathJsonIdentifier, CompiledType>;
1013
- imports?: unknown[];
1308
+ functions?: Record<MathJsonSymbol, JSSource | ((...any: any[]) => any)>;
1309
+ vars?: Record<MathJsonSymbol, CompiledType>;
1310
+ imports?: ((...any: any[]) => any)[];
1014
1311
  preamble?: string;
1015
- }): (args?: Record<string, CompiledType>) => CompiledType;
1312
+ fallback?: boolean;
1313
+ }): ((...args: any[]) => any) & {
1314
+ isCompiled?: boolean;
1315
+ };
1016
1316
  /**
1017
1317
  * If this is an equation, solve the equation for the variables in vars.
1018
1318
  * Otherwise, solve the equation `this = 0` for the variables in vars.
1019
1319
  *
1020
1320
  *
1021
1321
  * ```javascript
1022
- * const expr = ce.parse('x^2 + 2*x + 1 = 0');
1023
- * console.log(expr.solve('x'));
1322
+ * const expr = ce.parse("x^2 + 2*x + 1 = 0");
1323
+ * console.log(expr.solve("x"));
1024
1324
  * ```
1025
1325
  *
1026
1326
  *
1027
1327
  */
1028
1328
  solve(vars?: Iterable<string> | string | BoxedExpression | Iterable<BoxedExpression>): null | ReadonlyArray<BoxedExpression>;
1029
1329
  /**
1030
- * Return a JavaScript primitive representing the value of this expression.
1330
+ * If this expression is a number literal, a string literal or a function
1331
+ * literal, return the expression.
1031
1332
  *
1032
- * Equivalent to `expr.N().valueOf()`.
1333
+ * If the expression is a symbol, return the value of the symbol.
1334
+ *
1335
+ * Otherwise, the expression is a symbolic expression, including an unknown
1336
+ * symbol, i.e. a symbol with no value, return `undefined`.
1033
1337
  *
1034
1338
  */
1035
- get value(): number | boolean | string | object | undefined;
1339
+ get value(): BoxedExpression | undefined;
1036
1340
  /**
1037
- * Only the value of variables can be changed (symbols that are not
1038
- * constants).
1341
+ * If the expression is a symbol, set the value of the symbol.
1039
1342
  *
1040
- * Throws a runtime error if a constant.
1343
+ * Will throw a runtime error if either not a symbol, or a symbol with the
1344
+ * `constant` flag set to `true`.
1041
1345
  *
1042
- * :::info[Note]
1043
- * If non-canonical, does nothing
1044
- * :::
1346
+ * Setting the value of a symbol results in the forgetting of all assumptions
1347
+ * about it in the current scope.
1045
1348
  *
1046
1349
  */
1047
- set value(value: boolean | string | BigNum | {
1048
- re: number;
1049
- im: number;
1050
- } | {
1051
- num: number;
1052
- denom: number;
1053
- } | number[] | BoxedExpression | number | undefined);
1350
+ set value(value: boolean | string | BigNum | OneOf<[
1351
+ {
1352
+ re: number;
1353
+ im: number;
1354
+ },
1355
+ {
1356
+ num: number;
1357
+ denom: number;
1358
+ },
1359
+ BoxedExpression
1360
+ ]> | number[] | number | undefined);
1054
1361
  /**
1055
1362
  *
1056
1363
  * The type of the value of this expression.
1057
1364
  *
1365
+ * If a symbol the type of the value of the symbol.
1366
+ *
1058
1367
  * If a function expression, the type of the value of the function
1059
1368
  * (the result type).
1060
1369
  *
1061
- * If a symbol the type of the value of the symbol.
1370
+ * If a symbol with a `"function"` type (a function literal), returns the
1371
+ * signature.
1062
1372
  *
1063
- * :::info[Note]
1064
1373
  * If not valid, return `"error"`.
1065
- * If non-canonical, return `undefined`.
1374
+ *
1066
1375
  * If the type is not known, return `"unknown"`.
1067
- * :::
1068
1376
  *
1377
+ * @category Type Properties
1069
1378
  */
1070
1379
  get type(): BoxedType;
1071
1380
  set type(type: Type | TypeString | BoxedType);
@@ -1128,9 +1437,10 @@ export interface BoxedExpression {
1128
1437
  * considered equal. This tolerance is set when the `engine.precision` is
1129
1438
  * changed to be such that the last two digits are ignored.
1130
1439
  *
1131
- * The evaluations may be expensive operations. Other options to consider
1440
+ * Evaluating the expressions may be expensive. Other options to consider
1132
1441
  * to compare two expressions include:
1133
- * - `expr.isSame(other)` for a structural comparison
1442
+ * - `expr.isSame(other)` for a structural comparison which does not involve
1443
+ * evaluating the expressions.
1134
1444
  * - `expr.is(other)` for a comparison of a number literal
1135
1445
  *
1136
1446
  * **Examples**
@@ -1152,29 +1462,51 @@ export interface BoxedExpression {
1152
1462
  */
1153
1463
  isEqual(other: number | BoxedExpression): boolean | undefined;
1154
1464
  /**
1155
- * Return true if the expression is a collection: a list, a vector, a matrix, a map, a tuple, etc...
1465
+ * Is `true` if the expression is a collection.
1466
+ *
1467
+ * When `isCollection` is `true`, the expression:
1468
+ *
1469
+ * - has an `each()` method that returns a generator over the elements
1470
+ * of the collection.
1471
+ * - has a `size` property that returns the number of elements in the
1472
+ * collection.
1473
+ * - has a `contains(other)` method that returns `true` if the `other`
1474
+ * expression is in the collection.
1475
+ *
1156
1476
  */
1157
1477
  isCollection: boolean;
1158
1478
  /**
1159
- * If this is a collection, return true if the `rhs` expression is in the
1160
- * collection.
1479
+ * Is `true` if this is an indexed collection, such as a list, a vector,
1480
+ * a matrix, a tuple, etc...
1161
1481
  *
1162
- * Return `undefined` if the membership cannot be determined.
1482
+ * The elements of an indexed collection can be accessed by a one-based
1483
+ * index.
1484
+ *
1485
+ * When `isIndexedCollection` is `true`, the expression:
1486
+ * - has an `each()`, `size()` and `contains(rhs)` methods
1487
+ * as for a collection.
1488
+ * - has an `at(index: number)` method that returns the element at the
1489
+ * specified index.
1490
+ * - has an `indexWhere(predicate: (element: BoxedExpression) => boolean)`
1491
+ * method that returns the index of the first element that matches the
1492
+ * predicate.
1163
1493
  */
1164
- contains(rhs: BoxedExpression): boolean | undefined;
1494
+ isIndexedCollection: boolean;
1165
1495
  /**
1166
- * If this is a collection, return the number of elements in the collection.
1496
+ * False if not a collection, or if the elements of the collection
1497
+ * are not computed lazily.
1167
1498
  *
1168
- * If the collection is infinite, return `Infinity`.
1499
+ * The elements of a lazy collection are computed on demand, when
1500
+ * iterating over the collection using `each()`.
1501
+ *
1502
+ * Use `ListFrom` and related functions to create eager collections from
1503
+ * lazy collections.
1169
1504
  *
1170
1505
  */
1171
- get size(): number;
1506
+ isLazyCollection: boolean;
1172
1507
  /**
1173
- * If this is a collection, return an iterator over the elements of the collection.
1174
- *
1175
- * If `start` is not specified, start from the first element.
1176
- *
1177
- * If `count` is not specified or negative, return all the elements from `start` to the end.
1508
+ * If this is a collection, return an iterator over the elements of the
1509
+ * collection.
1178
1510
  *
1179
1511
  * ```js
1180
1512
  * const expr = ce.parse('[1, 2, 3, 4]');
@@ -1183,25 +1515,62 @@ export interface BoxedExpression {
1183
1515
  * }
1184
1516
  * ```
1185
1517
  */
1186
- each: (start?: number, count?: number) => Iterator<BoxedExpression, undefined>;
1187
- /** If this is an indexable collection, return the element at the specified
1188
- * index.
1518
+ each(): Generator<BoxedExpression>;
1519
+ /**
1520
+ * If this is a collection, return true if the `rhs` expression is in the
1521
+ * collection.
1522
+ *
1523
+ * Return `undefined` if the membership cannot be determined without
1524
+ * iterating over the collection.
1525
+ */
1526
+ xcontains(rhs: BoxedExpression): boolean | undefined;
1527
+ /**
1528
+ * Check if this collection is a subset of another collection.
1529
+ *
1530
+ * @param other The other collection to check against.
1531
+ * @param strict If true, the subset relation is strict (i.e., proper subset).
1532
+ */
1533
+ subsetOf(other: BoxedExpression, strict: boolean): boolean | undefined;
1534
+ /**
1535
+ * If this is a collection, return the number of elements in the collection.
1536
+ *
1537
+ * If the collection is infinite, return `Infinity`.
1538
+ *
1539
+ * If the number of elements cannot be determined, return `undefined`, for
1540
+ * example, if the collection is lazy and not finite and the size cannot
1541
+ * be determined without iterating over the collection.
1542
+ *
1543
+ */
1544
+ get xsize(): number | undefined;
1545
+ /** If this is a finite collection, return true. */
1546
+ isFiniteCollection: boolean | undefined;
1547
+ /** If this is an empty collection, return true.
1548
+ *
1549
+ * An empty collection has a size of 0.
1550
+ */
1551
+ isEmptyCollection: boolean | undefined;
1552
+ /** If this is an indexed collection, return the element at the specified
1553
+ * index. The first element is at index 1.
1189
1554
  *
1190
1555
  * If the index is negative, return the element at index `size() + index + 1`.
1191
1556
  *
1557
+ * The last element is at index -1.
1558
+ *
1192
1559
  */
1193
1560
  at(index: number): BoxedExpression | undefined;
1194
- /** If this is a map or a tuple, return the value of the corresponding key.
1561
+ /** If this is a keyed collection (map, record, tuple), return the value of
1562
+ * the corresponding key.
1195
1563
  *
1196
1564
  * If `key` is a `BoxedExpression`, it should be a string.
1197
1565
  *
1198
1566
  */
1199
1567
  get(key: string | BoxedExpression): BoxedExpression | undefined;
1200
1568
  /**
1201
- * If this is an indexable collection, return the index of the first element
1202
- * that matches the target expression.
1569
+ * If this is an indexed collection, return the index of the first element
1570
+ * that matches the predicate.
1571
+ *
1203
1572
  */
1204
- indexOf(expr: BoxedExpression): number | undefined;
1573
+ indexWhere(predicate: (element: BoxedExpression) => boolean): number | undefined;
1205
1574
  }
1206
1575
  /** A semi boxed expression is a MathJSON expression which can include some
1207
1576
  * boxed terms.
@@ -1211,7 +1580,17 @@ export interface BoxedExpression {
1211
1580
  *
1212
1581
  * @category Boxed Expression
1213
1582
  */
1214
- export type SemiBoxedExpression = number | bigint | string | BigNum | MathJsonNumber | MathJsonString | MathJsonSymbol | MathJsonFunction | readonly [MathJsonIdentifier, ...SemiBoxedExpression[]] | BoxedExpression;
1583
+ export type SemiBoxedExpression = number | bigint | string | BigNum | MathJsonNumberObject | MathJsonStringObject | MathJsonSymbolObject | MathJsonFunctionObject | MathJsonDictionaryObject | readonly [MathJsonSymbol, ...SemiBoxedExpression[]] | BoxedExpression;
1584
+ /** Interface for dictionary-like structures.
1585
+ * Use `isDictionary()` to check if an expression is a dictionary.
1586
+ */
1587
+ export interface DictionaryInterface {
1588
+ get(key: string): BoxedExpression | undefined;
1589
+ has(key: string): boolean;
1590
+ get keys(): string[];
1591
+ get entries(): [string, BoxedExpression][];
1592
+ get values(): BoxedExpression[];
1593
+ }
1215
1594
  /**
1216
1595
  * These handlers compare two expressions.
1217
1596
  *
@@ -1341,7 +1720,7 @@ export type ReplaceOptions = {
1341
1720
  useVariations: boolean;
1342
1721
  /**
1343
1722
  * If `iterationLimit` > 1, the rules will be repeatedly applied
1344
- * until no rules apply, up to `maxIterations` times.
1723
+ * until no rules apply, up to `iterationLimit` times.
1345
1724
  *
1346
1725
  * Note that if `once` is true, `iterationLimit` has no effect.
1347
1726
  *
@@ -1357,49 +1736,57 @@ export type ReplaceOptions = {
1357
1736
  };
1358
1737
  /**
1359
1738
  * A bound symbol (i.e. one with an associated definition) has either a type
1360
- * (e.g. ∀ x ∈ ℝ), a value (x = 5) or both (π: value = 3.14... type = 'real')
1739
+ * (e.g. ∀ x ∈ ℝ), a value (x = 5) or both (π: value = 3.14... type = 'real').
1740
+ *
1361
1741
  * @category Definitions
1362
1742
  */
1363
- export type SymbolDefinition = BaseDefinition & Partial<SymbolAttributes> & {
1364
- type?: Type | TypeString;
1743
+ export type ValueDefinition = BaseDefinition & {
1744
+ holdUntil: 'never' | 'evaluate' | 'N';
1745
+ type: Type | TypeString | BoxedType;
1365
1746
  /** If true, the type is inferred, and could be adjusted later
1366
1747
  * as more information becomes available or if the symbol is explicitly
1367
1748
  * declared.
1368
1749
  */
1369
- inferred?: boolean;
1750
+ inferred: boolean;
1370
1751
  /** `value` can be a JS function since for some constants, such as
1371
1752
  * `Pi`, the actual value depends on the `precision` setting of the
1372
1753
  * `ComputeEngine` and possible other environment settings */
1373
- value?: LatexString | SemiBoxedExpression | ((ce: ComputeEngine) => BoxedExpression | null);
1374
- flags?: Partial<NumericFlags>;
1375
- eq?: (a: BoxedExpression) => boolean | undefined;
1376
- neq?: (a: BoxedExpression) => boolean | undefined;
1377
- cmp?: (a: BoxedExpression) => '=' | '>' | '<' | undefined;
1378
- collection?: Partial<CollectionHandlers>;
1754
+ value: LatexString | SemiBoxedExpression | ((ce: ComputeEngine) => BoxedExpression | null);
1755
+ eq: (a: BoxedExpression) => boolean | undefined;
1756
+ neq: (a: BoxedExpression) => boolean | undefined;
1757
+ cmp: (a: BoxedExpression) => '=' | '>' | '<' | undefined;
1758
+ collection: CollectionHandlers;
1379
1759
  };
1380
1760
  /**
1381
1761
  * Definition record for a function.
1382
1762
  * @category Definitions
1383
1763
  *
1384
1764
  */
1385
- export type FunctionDefinition = BaseDefinition & Partial<FunctionDefinitionFlags> & {
1765
+ export type OperatorDefinition = Partial<BaseDefinition> & Partial<OperatorDefinitionFlags> & {
1386
1766
  /**
1387
- * The function signature.
1767
+ * The function signature, describing the type of the arguments and the
1768
+ * return type.
1388
1769
  *
1389
1770
  * If a `type` handler is provided, the return type of the function should
1390
1771
  * be a subtype of the return type in the signature.
1391
1772
  *
1392
1773
  */
1393
- signature?: Type | TypeString;
1774
+ signature?: Type | TypeString | BoxedType;
1394
1775
  /**
1395
- * The actual type of the result based on the arguments.
1776
+ * The type of the result (return type) based on the type of
1777
+ * the arguments.
1778
+ *
1779
+ * Should be a subtype of the type indicated by the signature.
1396
1780
  *
1397
- * Should be a subtype of the type indicated in the signature.
1781
+ * For example, if the signature is `(number) -> real`, the type of the
1782
+ * result could be `real` or `integer`, but not `complex`.
1398
1783
  *
1784
+ * :::info[Note]
1399
1785
  * Do not evaluate the arguments.
1400
1786
  *
1401
- * The type of the arguments can be used to determine the type of the
1402
- * result.
1787
+ * However, the type of the arguments can be used to determine the type of
1788
+ * the result.
1789
+ * :::
1403
1790
  *
1404
1791
  */
1405
1792
  type?: (ops: ReadonlyArray<BoxedExpression>, options: {
@@ -1414,14 +1801,36 @@ export type FunctionDefinition = BaseDefinition & Partial<FunctionDefinitionFlag
1414
1801
  *
1415
1802
  * Do not evaluate the arguments.
1416
1803
  *
1417
- * The type and sign of the arguments can be used to determine the sign.
1804
+ * However, the type and sign of the arguments can be used to determine the
1805
+ * sign.
1418
1806
  *
1419
1807
  */
1420
1808
  sgn?: (ops: ReadonlyArray<BoxedExpression>, options: {
1421
1809
  engine: ComputeEngine;
1422
1810
  }) => Sign | undefined;
1423
- /** Return true of the function expression is even, false if it is odd and
1424
- * undefined if it is neither.
1811
+ /** The value of this expression is > 0, same as `isGreater(0)`
1812
+ *
1813
+ * @category Numeric Expression
1814
+ */
1815
+ readonly isPositive?: boolean | undefined;
1816
+ /** The value of this expression is >= 0, same as `isGreaterEqual(0)`
1817
+ *
1818
+ * @category Numeric Expression
1819
+ */
1820
+ readonly isNonNegative?: boolean | undefined;
1821
+ /** The value of this expression is &lt; 0, same as `isLess(0)`
1822
+ *
1823
+ * @category Numeric Expression
1824
+ */
1825
+ readonly isNegative?: boolean | undefined;
1826
+ /** The value of this expression is &lt;= 0, same as `isLessEqual(0)`
1827
+ *
1828
+ * @category Numeric Expression
1829
+ */
1830
+ readonly isNonPositive?: boolean | undefined;
1831
+ /** Return `true` if the function expression is even, `false` if it is odd
1832
+ * and `undefined` if it is neither (for example if it is not a number,
1833
+ * or if it is a complex number).
1425
1834
  */
1426
1835
  even?: (ops: ReadonlyArray<BoxedExpression>, options: {
1427
1836
  engine: ComputeEngine;
@@ -1453,12 +1862,13 @@ export type FunctionDefinition = BaseDefinition & Partial<FunctionDefinitionFlag
1453
1862
  * The arguments (`args`) may not be in canonical form. If necessary, they
1454
1863
  * can be put in canonical form.
1455
1864
  *
1456
- * This handler should validate the type and number of the arguments.
1865
+ * This handler should validate the type and number of the arguments
1866
+ * (arity).
1457
1867
  *
1458
1868
  * If a required argument is missing, it should be indicated with a
1459
1869
  * `["Error", "'missing"]` expression. If more arguments than expected
1460
1870
  * are present, this should be indicated with an
1461
- * ["Error", "'unexpected-argument'"]` error expression
1871
+ * `["Error", "'unexpected-argument'"]` error expression
1462
1872
  *
1463
1873
  * If the type of an argument is not compatible, it should be indicated
1464
1874
  * with an `incompatible-type` error.
@@ -1480,19 +1890,20 @@ export type FunctionDefinition = BaseDefinition & Partial<FunctionDefinitionFlag
1480
1890
  *
1481
1891
  * The result of the handler should be a canonical expression.
1482
1892
  *
1483
- * If the arguments do not match, they should be replaced with an appropriate
1484
- * `["Error"]` expression. If the expression cannot be put in canonical form,
1485
- * the handler should return `null`.
1893
+ * If the arguments do not match, they should be replaced with an
1894
+ * appropriate `["Error"]` expression. If the expression cannot be put in
1895
+ * canonical form, the handler should return `null`.
1486
1896
  *
1487
1897
  */
1488
1898
  canonical?: (ops: ReadonlyArray<BoxedExpression>, options: {
1489
1899
  engine: ComputeEngine;
1900
+ scope: Scope | undefined;
1490
1901
  }) => BoxedExpression | null;
1491
1902
  /**
1492
1903
  * Evaluate a function expression.
1493
1904
  *
1494
- * The arguments have been evaluated, except the arguments to which a
1495
- * `hold` applied.
1905
+ * When the handler is invoked, the arguments have been evaluated, except
1906
+ * if the `lazy` option is set to `true`.
1496
1907
  *
1497
1908
  * It is not necessary to further simplify or evaluate the arguments.
1498
1909
  *
@@ -1501,19 +1912,15 @@ export type FunctionDefinition = BaseDefinition & Partial<FunctionDefinitionFlag
1501
1912
  * number or a square root, rather than a floating point approximation.
1502
1913
  * Use `ce.number()` to create the numeric value.
1503
1914
  *
1504
- * When `numericalApproximation` is `false`, return a floating point number:
1505
- * - do not reduce rational numbers to decimal (floating point approximation)
1506
- * - do not reduce square roots of rational numbers
1507
- *
1508
1915
  * If the expression cannot be evaluated, due to the values, types, or
1509
- * assumptions about its arguments, for example, return `undefined` or
1916
+ * assumptions about its arguments, return `undefined` or
1510
1917
  * an `["Error"]` expression.
1511
1918
  */
1512
1919
  evaluate?: ((ops: ReadonlyArray<BoxedExpression>, options: EvaluateOptions & {
1513
1920
  engine: ComputeEngine;
1514
1921
  }) => BoxedExpression | undefined) | BoxedExpression;
1515
1922
  /**
1516
- * An option asynchronous version of `evaluate`.
1923
+ * An asynchronous version of `evaluate`.
1517
1924
  *
1518
1925
  */
1519
1926
  evaluateAsync?: (ops: ReadonlyArray<BoxedExpression>, options: EvaluateOptions & {
@@ -1526,28 +1933,44 @@ export type FunctionDefinition = BaseDefinition & Partial<FunctionDefinitionFlag
1526
1933
  engine: ComputeEngine;
1527
1934
  }) => BoxedExpression;
1528
1935
  /** Return a compiled (optimized) expression. */
1529
- compile?: (expr: BoxedExpression) => CompiledExpression;
1936
+ xcompile?: (expr: BoxedExpression) => CompiledExpression;
1530
1937
  eq?: (a: BoxedExpression, b: BoxedExpression) => boolean | undefined;
1531
1938
  neq?: (a: BoxedExpression, b: BoxedExpression) => boolean | undefined;
1532
- collection?: Partial<CollectionHandlers>;
1939
+ collection?: CollectionHandlers;
1533
1940
  };
1534
1941
  /**
1942
+ * Metadata common to both symbols and functions.
1943
+ *
1535
1944
  * @category Definitions
1536
1945
  *
1537
1946
  */
1538
- export type BaseDefinition = {
1539
- /** A short (about 1 line) description. May contain Markdown. */
1540
- description?: string | string[];
1947
+ export interface BaseDefinition {
1948
+ /**
1949
+ * If a string, a short description, about one line long.
1950
+ *
1951
+ * Otherwise, a list of strings, each string a paragraph.
1952
+ *
1953
+ * May contain Markdown.
1954
+ */
1955
+ description: string | string[];
1956
+ /** A list of examples of how to use this symbol or operator.
1957
+ *
1958
+ * Each example is a string, which can be a MathJSON expression or LaTeX, bracketed by `$` signs.
1959
+ * For example, `["Add", 1, 2]` or `$\\sin(\\pi/4)$`.
1960
+ */
1961
+ examples: string | string[];
1541
1962
  /** A URL pointing to more information about this symbol or operator. */
1542
- url?: string;
1963
+ url: string;
1543
1964
  /**
1544
1965
  * A short string representing an entry in a wikibase.
1545
1966
  *
1546
- * For example `Q167` is the [wikidata entry](https://www.wikidata.org/wiki/Q167)
1967
+ * For example `"Q167"` is the [wikidata entry](https://www.wikidata.org/wiki/Q167)
1547
1968
  * for the `Pi` constant.
1548
1969
  */
1549
- wikidata?: string;
1550
- };
1970
+ wikidata: string;
1971
+ /** If true, the value or type of the definition cannot be changed */
1972
+ readonly isConstant?: boolean;
1973
+ }
1551
1974
  /** Options for `BoxedExpression.simplify()`
1552
1975
  *
1553
1976
  * @category Boxed Expression
@@ -1567,9 +1990,9 @@ export type SimplifyOptions = {
1567
1990
  costFunction?: (expr: BoxedExpression) => number;
1568
1991
  };
1569
1992
  /**
1570
- * A table mapping identifiers to their definition.
1993
+ * A table mapping symbols to their definition.
1571
1994
  *
1572
- * Identifiers should be valid MathJSON identifiers. In addition, the
1995
+ * Symbols should be valid MathJSON symbols. In addition, the
1573
1996
  * following rules are recommended:
1574
1997
  *
1575
1998
  * - Use only latin letters, digits and `-`: `/[a-zA-Z0-9-]+/`
@@ -1579,18 +2002,34 @@ export type SimplifyOptions = {
1579
2002
  * @category Definitions
1580
2003
  *
1581
2004
  */
1582
- export type IdentifierDefinition = OneOf<[
1583
- SymbolDefinition,
1584
- FunctionDefinition,
1585
- SemiBoxedExpression
1586
- ]>;
2005
+ export type SymbolDefinition = OneOf<[ValueDefinition, OperatorDefinition]>;
1587
2006
  /**
1588
2007
  * @category Definitions
1589
2008
  *
1590
2009
  */
1591
- export type IdentifierDefinitions = Readonly<{
1592
- [id: string]: IdentifierDefinition;
2010
+ export type SymbolDefinitions = Readonly<{
2011
+ [id: string]: Partial<SymbolDefinition>;
1593
2012
  }>;
2013
+ /**
2014
+ * When a unitless value is passed to or returned from a trigonometric function,
2015
+ * the angular unit of the value.
2016
+ *
2017
+ * | Angular Unit | Description |
2018
+ * |:--------------|:-------------|
2019
+ * | `rad` | radians, 2π radians is a full circle |
2020
+ * | `deg` | degrees, 360 degrees is a full circle |
2021
+ * | `grad` | gradians, 400 gradians is a full circle |
2022
+ * | `turn` | turns, 1 turn is a full circle |
2023
+ *
2024
+ * To change the angular unit used by the Compute Engine, use:
2025
+ *
2026
+ * ```js
2027
+ * ce.angularUnit = 'deg';
2028
+ * ```
2029
+ *
2030
+ * @category Compute Engine
2031
+ */
2032
+ export type AngularUnit = 'rad' | 'deg' | 'grad' | 'turn';
1594
2033
  /** @category Numerics */
1595
2034
  export type Sign =
1596
2035
  /** The expression is equal to 0 */
@@ -1605,248 +2044,226 @@ export type Sign =
1605
2044
  | 'non-positive'
1606
2045
  /** The expression is not equal to 0 (possibly with an imaginary part) and isPositive, isNegative, isUnsigned are all false or undefined */
1607
2046
  | 'not-zero'
1608
- /** The expression has no imaginary part and a non-zero real part and isPositive and isNegative are false or undefined*/
1609
- | 'real-not-zero'
1610
- /** The expression has no imaginary part and isNotZero,isPositive,isNegative,isNonNegative,isNonPositive,isZero are either false or undefined*/
1611
- | 'real'
1612
- /** The expression is NaN */
1613
- | 'nan'
1614
- /** The expression is +∞ */
1615
- | 'positive-infinity'
1616
- /** The expression is -∞ */
1617
- | 'negative-infinity'
1618
- /** The expression is ~∞ */
1619
- | 'complex-infinity'
1620
2047
  /** The expression has an imaginary part or is NaN */
1621
2048
  | 'unsigned';
1622
- /**
1623
- * When used in a `SymbolDefinition` or `Functiondefinition` these flags
1624
- * provide additional information about the value of the symbol or function.
1625
- *
1626
- * If provided, they will override the value derived from
1627
- * the symbol's value.
1628
- *
1629
- * @category Definitions
1630
- */
1631
- export type NumericFlags = {
1632
- sgn: Sign | undefined;
1633
- even: boolean | undefined;
1634
- odd: boolean | undefined;
1635
- };
1636
2049
  /**
1637
2050
  * These handlers are the primitive operations that can be performed on
1638
- * collections.
1639
- *
1640
- * There are two types of collections:
1641
- *
1642
- * - finite collections, such as lists, tuples, sets, matrices, etc...
1643
- * The `size()` handler of finite collections returns the number of elements
1644
- *
1645
- * - infinite collections, such as sequences, ranges, etc...
1646
- * The `size()` handler of infinite collections returns `Infinity`
1647
- * Infinite collections are not indexable: they have no `at()` handler.
2051
+ * all collections, indexed or not.
1648
2052
  *
1649
2053
  * @category Definitions
1650
2054
  */
1651
- export type CollectionHandlers = {
2055
+ export interface BaseCollectionHandlers {
2056
+ /**
2057
+ * Return an iterator that iterates over the elements of the collection.
2058
+ *
2059
+ * The order in which the elements are returned is not defined. Requesting
2060
+ * two iterators on the same collection may return the elements in a
2061
+ * different order.
2062
+ *
2063
+ * @category Definitions
2064
+ */
2065
+ iterator: (collection: BoxedExpression) => Iterator<BoxedExpression, undefined> | undefined;
1652
2066
  /** Return the number of elements in the collection.
1653
2067
  *
1654
- * An empty collection has a size of 0.
2068
+ * An empty collection has a count of 0.
2069
+ */
2070
+ count: (collection: BoxedExpression) => number | undefined;
2071
+ /** Optional flag to quickly check if the collection is empty, without having to count exactly how may elements it has (useful for lazy evaluation). */
2072
+ isEmpty?: (collection: BoxedExpression) => boolean | undefined;
2073
+ /** Optional flag to quickly check if the collection is finite, without having to count exactly how many elements it has (useful for lazy evaluation). */
2074
+ isFinite?: (collection: BoxedExpression) => boolean | undefined;
2075
+ /** Return `true` if the collection is lazy, `false` otherwise.
2076
+ * If the collection is lazy, it means that the elements are not
2077
+ * computed until they are needed, for example when iterating over the
2078
+ * collection.
2079
+ *
2080
+ * Default: `true`
1655
2081
  */
1656
- size: (collection: BoxedExpression) => number;
2082
+ isLazy?: (collection: BoxedExpression) => boolean;
1657
2083
  /**
1658
- * Return `true` if the target
1659
- * expression is in the collection, `false` otherwise.
2084
+ * Return `true` if the target expression is in the collection,
2085
+ * `false` otherwise.
2086
+ *
2087
+ * Return `undefined` if the membership cannot be determined.
1660
2088
  */
1661
- contains: (collection: BoxedExpression, target: BoxedExpression) => boolean;
1662
- /** Return an iterator
1663
- * - start is optional and is a 1-based index.
1664
- * - if start is not specified, start from index 1
1665
- * - count is optional and is the number of elements to return
1666
- * - if count is not specified or negative, return all the elements from
1667
- * start to the end
2089
+ contains?: (collection: BoxedExpression, target: BoxedExpression) => boolean | undefined;
2090
+ /**
2091
+ * Return `true` if all the elements of `other` are in `collection`.
2092
+ * Both `collection` and `other` are collections.
1668
2093
  *
1669
- * If there is a `keys()` handler, there is no `iterator()` handler.
2094
+ * If strict is `true`, the subset must be strict, that is, `collection` must
2095
+ * have more elements than `other`.
1670
2096
  *
1671
- * @category Definitions
2097
+ * Return `undefined` if the subset relation cannot be determined.
1672
2098
  */
1673
- iterator: (collection: BoxedExpression, start?: number, count?: number) => Iterator<BoxedExpression, undefined>;
2099
+ subsetOf?: (collection: BoxedExpression, other: BoxedExpression, strict: boolean) => boolean | undefined;
2100
+ /** Return the sign of all the elements of the collection. */
2101
+ eltsgn?: (collection: BoxedExpression) => Sign | undefined;
2102
+ /** Return the widest type of all the elements in the collection */
2103
+ elttype?: (collection: BoxedExpression) => Type | undefined;
2104
+ }
2105
+ /**
2106
+ * These additional collection handlers are applicable to indexed
2107
+ * collections only.
2108
+ *
2109
+ * The elements of an indexed collection can be accessed by index, and
2110
+ * the order of the elements is defined.
2111
+ *
2112
+ * @category Definitions
2113
+ */
2114
+ export interface IndexedCollectionHandlers {
1674
2115
  /**
1675
2116
  * Return the element at the specified index.
1676
2117
  *
1677
2118
  * The first element is `at(1)`, the last element is `at(-1)`.
1678
2119
  *
1679
- * If the index is &lt;0, return the element at index `size() + index + 1`.
2120
+ * If the index is &lt;0, return the element at index `count() + index + 1`.
1680
2121
  *
1681
- * The index can also be a string for example for maps. The set of valid keys
1682
- * is returned by the `keys()` handler.
2122
+ * The index can also be a string for example for records. The set of valid
2123
+ * keys is returned by the `keys()` handler.
1683
2124
  *
1684
2125
  * If the index is invalid, return `undefined`.
1685
2126
  */
1686
2127
  at: (collection: BoxedExpression, index: number | string) => undefined | BoxedExpression;
1687
2128
  /**
1688
- * If the collection can be indexed by strings, return the valid values
1689
- * for the index.
1690
- */
1691
- keys: (collection: BoxedExpression) => undefined | Iterable<string>;
1692
- /**
1693
- * Return the index of the first element that matches the target expression.
2129
+ * Return the index of the first element that matches the predicate.
1694
2130
  *
1695
- * The comparison is done using the `target.isEqual()` method.
1696
- *
1697
- * If the expression is not found, return `undefined`.
1698
- *
1699
- * If the expression is found, return the index, 1-based.
1700
- *
1701
- * Return the index of the first match.
1702
- *
1703
- * `from` is the starting index for the search. If negative, start from
1704
- * the end and search backwards.
2131
+ * If no element matches the predicate, return `undefined`.
1705
2132
  */
1706
- indexOf: (collection: BoxedExpression, target: BoxedExpression, from?: number) => number | undefined;
1707
- /**
1708
- * Return `true` if all the elements of `target` are in `expr`.
1709
- * Both `expr` and `target` are collections.
1710
- * If strict is `true`, the subset must be strict, that is, `expr` must
1711
- * have more elements than `target`.
1712
- */
1713
- subsetOf: (collection: BoxedExpression, target: BoxedExpression, strict: boolean) => boolean;
1714
- /** Return the sign of all the elements of the collection. */
1715
- eltsgn: (collection: BoxedExpression) => Sign | undefined;
1716
- /** Return the widest type of all the elements in the collection */
1717
- elttype: (collection: BoxedExpression) => Type | undefined;
2133
+ indexWhere: (collection: BoxedExpression, predicate: (element: BoxedExpression) => boolean) => number | undefined;
2134
+ }
2135
+ /**
2136
+ * The collection handlers are the primitive operations that can be
2137
+ * performed on collections, such as lists, sets, tuples, etc...
2138
+ *
2139
+ * @category Definitions
2140
+ */
2141
+ export type CollectionHandlers = BaseCollectionHandlers & Partial<IndexedCollectionHandlers>;
2142
+ /**
2143
+ *
2144
+ * The definition for a value, represented as a tagged object literal.
2145
+ * @category Definitions
2146
+ *
2147
+ */
2148
+ export type TaggedValueDefinition = {
2149
+ value: BoxedValueDefinition;
1718
2150
  };
1719
2151
  /**
2152
+ *
2153
+ * The definition for an operator, represented as a tagged object literal.
2154
+ *
1720
2155
  * @category Definitions
1721
2156
  *
1722
2157
  */
1723
- export interface BoxedBaseDefinition {
1724
- name: string;
1725
- wikidata?: string;
1726
- description?: string | string[];
1727
- url?: string;
1728
- /**
1729
- * The scope this definition belongs to.
1730
- *
1731
- * This field is usually undefined, but its value is set by `getDefinition()`
1732
- */
1733
- scope: RuntimeScope | undefined;
2158
+ export type TaggedOperatorDefinition = {
2159
+ operator: BoxedOperatorDefinition;
2160
+ };
2161
+ /**
2162
+ * A definition can be either a value or an operator.
2163
+ *
2164
+ * It is collected in a tagged object literal, instead of being a simple union
2165
+ * type, so that the type of the definition can be changed while keeping
2166
+ * references to the definition in bound expressions.
2167
+ *
2168
+ * @category Definitions
2169
+ *
2170
+ */
2171
+ export type BoxedDefinition = TaggedValueDefinition | TaggedOperatorDefinition;
2172
+ /**
2173
+ * @category Definitions
2174
+ *
2175
+ */
2176
+ export interface BoxedBaseDefinition extends Partial<BaseDefinition> {
1734
2177
  /** If this is the definition of a collection, the set of primitive operations
1735
2178
  * that can be performed on this collection (counting the number of elements,
1736
- * enumerating it, etc...). */
1737
- collection?: Partial<CollectionHandlers>;
1738
- /** When the environment changes, for example the numerical precision,
1739
- * call `reset()` so that any cached values can be recalculated.
2179
+ * enumerating it, etc...).
1740
2180
  */
1741
- reset(): void;
2181
+ collection?: CollectionHandlers;
1742
2182
  }
1743
2183
  /**
1744
- * @category Definitions
1745
2184
  *
2185
+ * @category Definitions
1746
2186
  */
1747
- export type SymbolAttributes = {
1748
- /**
1749
- * If `true` the value of the symbol is constant. The value or type of
1750
- * symbols with this attribute set to `true` cannot be changed.
1751
- *
1752
- * If `false`, the symbol is a variable.
1753
- *
1754
- * **Default**: `false`
1755
- */
1756
- constant: boolean;
2187
+ export interface BoxedValueDefinition extends BoxedBaseDefinition {
1757
2188
  /**
1758
- * If the symbol has a value, it is held as indicated in the table below.
1759
- * A green checkmark indicate that the symbol is substituted.
2189
+ * If the symbol has a value, it is held as indicated in the table below.
2190
+ * A green checkmark indicate that the symbol is substituted.
1760
2191
 
1761
- <div className="symbols-table">
2192
+ <div className="symbols-table">
1762
2193
 
1763
- | Operation | `"never"` | `"evaluate"` | `"N"` |
1764
- | :--- | :-----: | :----: | :---: |
1765
- | `canonical()` | (X) | | |
1766
- | `evaluate()` | (X) | (X) | |
1767
- | `"N()"` | (X) | (X) | (X) |
2194
+ | Operation | `"never"` | `"evaluate"` | `"N"` |
2195
+ | :--- | :-----: | :----: | :---: |
2196
+ | `canonical()` | (X) | | |
2197
+ | `evaluate()` | (X) | (X) | |
2198
+ | `"N()"` | (X) | (X) | (X) |
1768
2199
 
1769
- </div>
2200
+ </div>
1770
2201
 
1771
- * Some examples:
1772
- * - `ImaginaryUnit` has `holdUntil: 'never'`: it is substituted during canonicalization
1773
- * - `x` has `holdUntil: 'evaluate'` (variables)
1774
- * - `Pi` has `holdUntil: 'N'` (special numeric constant)
1775
- *
1776
- * **Default:** `evaluate`
1777
- */
2202
+ * Some examples:
2203
+ * - `ImaginaryUnit` has `holdUntil: 'never'`: it is substituted during canonicalization
2204
+ * - `x` has `holdUntil: 'evaluate'` (variables)
2205
+ * - `Pi` has `holdUntil: 'N'` (special numeric constant)
2206
+ *
2207
+ * **Default:** `evaluate`
2208
+ */
1778
2209
  holdUntil: 'never' | 'evaluate' | 'N';
1779
- };
1780
- /**
1781
- * @category Definitions
1782
- */
1783
- export interface BoxedSymbolDefinition extends BoxedBaseDefinition, SymbolAttributes, Partial<NumericFlags> {
1784
- get value(): BoxedExpression | undefined;
1785
- set value(val: BoxedExpression | number | undefined);
1786
- readonly isFunction: boolean;
1787
- readonly isConstant: boolean;
2210
+ /** This is either the initial value of the symbol (i.e. when a new
2211
+ * evaluation context is created), or its constant value, if a constant.
2212
+ * Otherwise, the current value is tracked in the evaluation context.
2213
+ *
2214
+ */
2215
+ readonly value: BoxedExpression | undefined;
1788
2216
  eq?: (a: BoxedExpression) => boolean | undefined;
1789
2217
  neq?: (a: BoxedExpression) => boolean | undefined;
1790
2218
  cmp?: (a: BoxedExpression) => '=' | '>' | '<' | undefined;
2219
+ /**
2220
+ * True if the type has been inferred. An inferred type can be updated as
2221
+ * more information becomes available.
2222
+ *
2223
+ * A type that is not inferred, but has been set explicitly, cannot be updated.
2224
+ */
1791
2225
  inferredType: boolean;
1792
2226
  type: BoxedType;
1793
2227
  }
1794
2228
  /**
1795
- * A scope is a set of names in a dictionary that are bound (defined) in
1796
- * a MathJSON expression.
1797
- *
1798
- * Scopes are arranged in a stack structure. When an expression that defined
1799
- * a new scope is evaluated, the new scope is added to the scope stack.
1800
- * Outside of the expression, the scope is removed from the scope stack.
1801
- *
1802
- * The scope stack is used to resolve symbols, and it is possible for
1803
- * a scope to 'mask' definitions from previous scopes.
1804
- *
1805
- * Scopes are lexical (also called a static scope): they are defined based on
1806
- * where they are in an expression, they are not determined at runtime.
1807
- *
1808
- * @category Compute Engine
1809
- */
1810
- export type Scope = Record<string, any>;
1811
- /** Options for `BoxedExpression.evaluate()`
1812
- *
1813
- * @category Boxed Expression
1814
- */
1815
- export type EvaluateOptions = {
1816
- numericApproximation: boolean;
1817
- signal: AbortSignal;
1818
- };
1819
- /**
1820
- * A function definition can have some flags to indicate specific
1821
- * properties of the function.
2229
+ * An operator definition can have some flags to indicate specific
2230
+ * properties of the operator.
1822
2231
  * @category Definitions
1823
2232
  */
1824
- export type FunctionDefinitionFlags = {
2233
+ export type OperatorDefinitionFlags = {
1825
2234
  /**
1826
- * If `true`, the arguments to this function are not automatically
2235
+ * If `true`, the arguments to this operator are not automatically
1827
2236
  * evaluated. The default is `false` (the arguments are evaluated).
1828
2237
  *
1829
- * This can be useful for example for functions that take symbolic
1830
- * expressions as arguments, such as `D` or `Integrate`.
2238
+ * This can be useful for example for operators that take symbolic
2239
+ * expressions as arguments, such as `Declare` or `Integrate`.
1831
2240
  *
1832
- * This is also useful for functions that take an argument that is
2241
+ * This is also useful for operators that take an argument that is
1833
2242
  * potentially an infinite collection.
1834
2243
  *
1835
2244
  * It will be up to the `evaluate()` handler to evaluate the arguments as
1836
- * needed. This is conveninent to pass symbolic expressions as arguments
1837
- * to functions without having to explicitly use a `Hold` expression.
2245
+ * needed. This is convenient to pass symbolic expressions as arguments
2246
+ * to operators without having to explicitly use a `Hold` expression.
1838
2247
  *
1839
2248
  * This also applies to the `canonical()` handler.
1840
2249
  *
1841
2250
  */
1842
2251
  lazy: boolean;
1843
- /** If `true`, the function is applied element by element to lists, matrices
2252
+ /**
2253
+ * If `true`, the operator requires a new lexical scope when canonicalized.
2254
+ * This will allow it to declare variables that are not visible outside
2255
+ * the function expression using the operator.
2256
+ *
2257
+ * **Default**: `false`
2258
+ */
2259
+ scoped: boolean;
2260
+ /** If `true`, the operator is applied element by element to lists, matrices
1844
2261
  * (`["List"]` or `["Tuple"]` expressions) and equations (relational
1845
2262
  * operators).
1846
2263
  *
1847
2264
  * **Default**: `false`
1848
2265
  */
1849
- threadable: boolean;
2266
+ broadcastable: boolean;
1850
2267
  /** If `true`, `["f", ["f", a], b]` simplifies to `["f", a, b]`
1851
2268
  *
1852
2269
  * **Default**: `false`
@@ -1867,10 +2284,10 @@ export type FunctionDefinitionFlags = {
1867
2284
  *
1868
2285
  */
1869
2286
  commutativeOrder: ((a: BoxedExpression, b: BoxedExpression) => number) | undefined;
1870
- /** If `true`, when the function is univariate, `["f", ["Multiply", x, c]]`
2287
+ /** If `true`, when the operator is univariate, `["f", ["Multiply", x, c]]`
1871
2288
  * simplifies to `["Multiply", ["f", x], c]` where `c` is constant
1872
2289
  *
1873
- * When the function is multivariate, multiplicativity is considered only on
2290
+ * When the operator is multivariate, multiplicativity is considered only on
1874
2291
  * the first argument: `["f", ["Multiply", x, y], z]` simplifies to
1875
2292
  * `["Multiply", ["f", x, z], ["f", y, z]]`
1876
2293
  *
@@ -1886,10 +2303,10 @@ export type FunctionDefinitionFlags = {
1886
2303
  * **Default**: `false`
1887
2304
  */
1888
2305
  involution: boolean;
1889
- /** If `true`, the value of this function is always the same for a given
2306
+ /** If `true`, the value of this operator is always the same for a given
1890
2307
  * set of arguments and it has no side effects.
1891
2308
  *
1892
- * An expression using this function is pure if the function and all its
2309
+ * An expression using this operator is pure if the operator and all its
1893
2310
  * arguments are pure.
1894
2311
  *
1895
2312
  * For example `Sin` is pure, `Random` isn't.
@@ -1901,10 +2318,15 @@ export type FunctionDefinitionFlags = {
1901
2318
  pure: boolean;
1902
2319
  };
1903
2320
  /**
2321
+ *
2322
+ * The definition includes information specific about an operator, such as
2323
+ * handlers to canonicalize or evaluate a function expression with this
2324
+ * operator.
2325
+ *
1904
2326
  * @category Definitions
1905
2327
  *
1906
2328
  */
1907
- export type BoxedFunctionDefinition = BoxedBaseDefinition & FunctionDefinitionFlags & {
2329
+ export interface BoxedOperatorDefinition extends BoxedBaseDefinition, OperatorDefinitionFlags {
1908
2330
  complexity: number;
1909
2331
  /** If true, the signature was inferred from usage and may be modified
1910
2332
  * as more information becomes available.
@@ -1936,6 +2358,7 @@ export type BoxedFunctionDefinition = BoxedBaseDefinition & FunctionDefinitionFl
1936
2358
  neq?: (a: BoxedExpression, b: BoxedExpression) => boolean | undefined;
1937
2359
  canonical?: (ops: ReadonlyArray<BoxedExpression>, options: {
1938
2360
  engine: ComputeEngine;
2361
+ scope: Scope | undefined;
1939
2362
  }) => BoxedExpression | null;
1940
2363
  evaluate?: (ops: ReadonlyArray<BoxedExpression>, options: Partial<EvaluateOptions> & {
1941
2364
  engine?: ComputeEngine;
@@ -1947,16 +2370,33 @@ export type BoxedFunctionDefinition = BoxedBaseDefinition & FunctionDefinitionFl
1947
2370
  engine: ComputeEngine;
1948
2371
  }) => BoxedExpression;
1949
2372
  compile?: (expr: BoxedExpression) => CompiledExpression;
1950
- };
1951
- /**
1952
- * The entries have been validated and optimized for faster evaluation.
1953
- *
1954
- * When a new scope is created with `pushScope()` or when creating a new
1955
- * engine instance, new instances of this type are created as needed.
1956
- *
1957
- * @category Definitions
1958
- */
1959
- export type RuntimeIdentifierDefinitions = Map<string, OneOf<[BoxedSymbolDefinition, BoxedFunctionDefinition]>>;
2373
+ /** @internal */
2374
+ update(def: OperatorDefinition): void;
2375
+ }
2376
+ /** @category Assumptions */
2377
+ export interface Assumption {
2378
+ isPositive: boolean | undefined;
2379
+ isNonNegative: boolean | undefined;
2380
+ isNegative: boolean | undefined;
2381
+ isNonPositive: boolean | undefined;
2382
+ isNumber: boolean | undefined;
2383
+ isInteger: boolean | undefined;
2384
+ isRational: boolean | undefined;
2385
+ isReal: boolean | undefined;
2386
+ isComplex: boolean | undefined;
2387
+ isImaginary: boolean | undefined;
2388
+ isFinite: boolean | undefined;
2389
+ isInfinite: boolean | undefined;
2390
+ isNaN: boolean | undefined;
2391
+ isZero: boolean | undefined;
2392
+ matches(t: BoxedType): boolean | undefined;
2393
+ isGreater(other: BoxedExpression): boolean | undefined;
2394
+ isGreaterEqual(other: BoxedExpression): boolean | undefined;
2395
+ isLess(other: BoxedExpression): boolean | undefined;
2396
+ isLessEqual(other: BoxedExpression): boolean | undefined;
2397
+ isEqual(other: BoxedExpression): boolean | undefined;
2398
+ toExpression(ce: ComputeEngine, x: MathJsonSymbol): BoxedExpression;
2399
+ }
1960
2400
  /** @category Assumptions */
1961
2401
  export interface ExpressionMapInterface<U> {
1962
2402
  has(expr: BoxedExpression): boolean;
@@ -1969,24 +2409,6 @@ export interface ExpressionMapInterface<U> {
1969
2409
  }
1970
2410
  /** @category Assumptions */
1971
2411
  export type AssumeResult = 'internal-error' | 'not-a-predicate' | 'contradiction' | 'tautology' | 'ok';
1972
- /**
1973
- * When a unitless value is passed to or returned from a trigonometric function,
1974
- * the angular unit of the value.
1975
- *
1976
- * - `rad`: radians, 2π radians is a full circle
1977
- * - `deg`: degrees, 360 degrees is a full circle
1978
- * - `grad`: gradians, 400 gradians is a full circle
1979
- * - `turn`: turns, 1 turn is a full circle
1980
- *
1981
- * @category Compute Engine
1982
- */
1983
- export type AngularUnit = 'rad' | 'deg' | 'grad' | 'turn';
1984
- /** @category Compute Engine */
1985
- export type RuntimeScope = Scope & {
1986
- parentScope?: RuntimeScope;
1987
- ids?: RuntimeIdentifierDefinitions;
1988
- assumptions: undefined | ExpressionMapInterface<boolean>;
1989
- };
1990
2412
  /**
1991
2413
  * When provided, canonical forms are used to put an expression in a
1992
2414
  * "standard" form.
@@ -1997,7 +2419,8 @@ export type RuntimeScope = Scope & {
1997
2419
  *
1998
2420
  * - `InvisibleOperator`: replace use of the `InvisibleOperator` with
1999
2421
  * another operation, such as multiplication (i.e. `2x` or function
2000
- * application (`f(x)`).
2422
+ * application (`f(x)`). Also replaces ['InvisibleOperator', real, imaginary] instances with
2423
+ * complex (imaginary) numbers.
2001
2424
  * - `Number`: replace all numeric values with their
2002
2425
  * canonical representation, for example, reduce
2003
2426
  * rationals and replace complex numbers with no imaginary part with a real number.
@@ -2015,8 +2438,38 @@ export type RuntimeScope = Scope & {
2015
2438
  export type CanonicalForm = 'InvisibleOperator' | 'Number' | 'Multiply' | 'Add' | 'Power' | 'Divide' | 'Flatten' | 'Order';
2016
2439
  /** @category Boxed Expression */
2017
2440
  export type CanonicalOptions = boolean | CanonicalForm | CanonicalForm[];
2441
+ /** Options for `BoxedExpression.evaluate()`
2442
+ *
2443
+ * @category Boxed Expression
2444
+ */
2445
+ export type EvaluateOptions = {
2446
+ /**
2447
+ * If `true`, the evaluation will return a numeric approximation
2448
+ * of the expression, if possible.
2449
+ * If `false`, the evaluation will return an exact value, if possible.
2450
+ * Defaults to `false`.
2451
+ */
2452
+ numericApproximation: boolean;
2453
+ /**
2454
+ * If `false`, and the result of the expression is a lazy collection,
2455
+ * the collection will not be evaluated and will remain lazy.
2456
+ *
2457
+ * If `true` and the expression is a finite lazy collection,
2458
+ * the collection will be evaluated and returned as a non-lazy collection.
2459
+ *
2460
+ * If an integer, the collection will be evaluated up to that many elements.
2461
+ *
2462
+ * If a pair of integers `[n,m]`, and the collection is finite, the first `n`
2463
+ * elements will be evaluated, and the last `m` elements will be evaluated.
2464
+ *
2465
+ * Defaults to `false`.
2466
+ */
2467
+ materialization: boolean | number | [number, number];
2468
+ signal: AbortSignal;
2469
+ withArguments: Record<MathJsonSymbol, BoxedExpression>;
2470
+ };
2018
2471
  /**
2019
- * Metadata that can be associated with a `BoxedExpression`
2472
+ * Metadata that can be associated with an MathJSON expression.
2020
2473
  *
2021
2474
  * @category Boxed Expression
2022
2475
  */
@@ -2025,14 +2478,14 @@ export type Metadata = {
2025
2478
  wikidata?: string | undefined;
2026
2479
  };
2027
2480
  /**
2028
- * A substitution describes the values of the wildcards in a pattern so that
2029
- * the pattern is equal to a target expression.
2030
- *
2031
- * A substitution can also be considered a more constrained version of a
2032
- * rule whose `match` is always a symbol.
2481
+ * A substitution describes the values of the wildcards in a pattern so that
2482
+ * the pattern is equal to a target expression.
2483
+ *
2484
+ * A substitution can also be considered a more constrained version of a
2485
+ * rule whose `match` is always a symbol.
2033
2486
 
2034
- * @category Pattern Matching
2035
- */
2487
+ * @category Pattern Matching
2488
+ */
2036
2489
  export type Substitution<T = SemiBoxedExpression> = {
2037
2490
  [symbol: string]: T;
2038
2491
  };
@@ -2110,6 +2563,8 @@ export type Rule = string | RuleFunction | {
2110
2563
  condition?: LatexString | RuleConditionFunction;
2111
2564
  useVariations?: boolean;
2112
2565
  id?: string;
2566
+ onBeforeMatch?: (rule: Rule, expr: BoxedExpression) => void;
2567
+ onMatch?: (rule: Rule, expr: BoxedExpression, replace: BoxedExpression | RuleStep) => void;
2113
2568
  };
2114
2569
  /**
2115
2570
  *
@@ -2128,6 +2583,8 @@ export type BoxedRule = {
2128
2583
  condition: undefined | RuleConditionFunction;
2129
2584
  useVariations?: boolean;
2130
2585
  id?: string;
2586
+ onBeforeMatch?: (rule: Rule, expr: BoxedExpression) => void;
2587
+ onMatch?: (rule: Rule, expr: BoxedExpression, replace: BoxedExpression | RuleStep) => void;
2131
2588
  };
2132
2589
  /**
2133
2590
  * To create a BoxedRuleSet use the `ce.rules()` method.
@@ -2139,15 +2596,77 @@ export type BoxedRule = {
2139
2596
  export type BoxedRuleSet = {
2140
2597
  rules: ReadonlyArray<BoxedRule>;
2141
2598
  };
2142
- /** @category Compute Engine */
2143
- export type AssignValue = boolean | number | SemiBoxedExpression | ((args: ReadonlyArray<BoxedExpression>, options: EvaluateOptions & {
2599
+ /**
2600
+ * The argument of `ce.assign()` is a value that can be assigned to a variable.
2601
+ * It can be a primitive value, a boxed expression, or a function that
2602
+ * takes a list of arguments and returns a boxed expression.
2603
+ * @category Compute Engine */
2604
+ export type AssignValue = boolean | number | bigint | SemiBoxedExpression | ((args: ReadonlyArray<BoxedExpression>, options: EvaluateOptions & {
2144
2605
  engine: ComputeEngine;
2145
2606
  }) => BoxedExpression) | undefined;
2607
+ /**
2608
+ * A lexical scope is a table mapping symbols to their definitions. The
2609
+ * symbols are the names of the variables, unknowns and functions in the scope.
2610
+ *
2611
+ * The lexical scope is used to resolve the metadata about symbols, such as
2612
+ * their type, whether they are constant, etc...
2613
+ *
2614
+ * It does not resolve the values of the symbols, since those depend on the
2615
+ * evaluation context. For example, the local variables of a recursive function
2616
+ * will have the same lexical scope, but different values in each evaluation
2617
+ * context.
2618
+ *
2619
+ * @category Definitions
2620
+ */
2621
+ export type Scope = {
2622
+ parent: Scope | null;
2623
+ bindings: Map<string, BoxedDefinition>;
2624
+ types?: Record<string, TypeReference>;
2625
+ };
2626
+ /**
2627
+ * An evaluation context is a set of bindings mapping symbols to their
2628
+ * values. It also includes a reference to the lexical scope of the
2629
+ * context, as well as a set of assumptions about the values of the
2630
+ * symbols.
2631
+ *
2632
+ *
2633
+ * Eval contexts are arranged in a stack structure. When a new context is
2634
+ * created, it is pushed on the top of the stack.
2635
+ *
2636
+ * A new eval context is created when a function expression that needs to track
2637
+ * its own local variables and named arguments is evaluated. This kind of
2638
+ * function is a "scoped" function, meaning that it has its own local variables
2639
+ * and named arguments.
2640
+ *
2641
+ * For example, the `Sum` function creates a new eval context to track the local
2642
+ * variable used as the index of the sum.
2643
+ *
2644
+ * The eval context stack is used to resolve the value of symbols.
2645
+ *
2646
+ * When a scoped recursive function is called, a new context is created for each
2647
+ * recursive call.
2648
+ *
2649
+ * In contrast, the lexical scope is used to resolve the metadata about
2650
+ * symbols, such as their type, whether they are constant, etc... A new
2651
+ * scope is not created for recursive calls, since the metadata
2652
+ * does not change, only the values of the symbols change.
2653
+ *
2654
+ * The name of the eval context is used to print a "stack trace" for
2655
+ * debugging.
2656
+ *
2657
+ * @category Compute Engine
2658
+ */
2659
+ export type EvalContext = {
2660
+ lexicalScope: Scope;
2661
+ assumptions: ExpressionMapInterface<boolean>;
2662
+ values: Record<string, BoxedExpression | undefined>;
2663
+ name: undefined | string;
2664
+ };
2146
2665
  /** @internal */
2147
2666
  export interface ComputeEngine extends IBigNum {
2148
2667
  latexDictionary: readonly LatexDictionaryEntry[];
2149
2668
  /** @private */
2150
- indexedLatexDictionary: IndexedLatexDictionary;
2669
+ _indexedLatexDictionary: IndexedLatexDictionary;
2151
2670
  decimalSeparator: LatexString;
2152
2671
  readonly True: BoxedExpression;
2153
2672
  readonly False: BoxedExpression;
@@ -2158,6 +2677,7 @@ export interface ComputeEngine extends IBigNum {
2158
2677
  readonly One: BoxedExpression;
2159
2678
  readonly Half: BoxedExpression;
2160
2679
  readonly NegativeOne: BoxedExpression;
2680
+ /** ImaginaryUnit */
2161
2681
  readonly I: BoxedExpression;
2162
2682
  readonly NaN: BoxedExpression;
2163
2683
  readonly PositiveInfinity: BoxedExpression;
@@ -2177,34 +2697,22 @@ export interface ComputeEngine extends IBigNum {
2177
2697
  readonly _BIGNUM_PI: BigNum;
2178
2698
  /** @internal */
2179
2699
  readonly _BIGNUM_NEGATIVE_ONE: BigNum;
2180
- /** The current scope */
2181
- context: RuntimeScope | null;
2700
+ readonly context: EvalContext;
2701
+ contextStack: ReadonlyArray<EvalContext>;
2702
+ /** @internal */
2703
+ readonly _typeResolver: TypeResolver;
2182
2704
  /** Absolute time beyond which evaluation should not proceed
2183
2705
  * @internal
2184
2706
  */
2185
2707
  _deadline?: number;
2186
- /** Time remaining before _deadline */
2187
- _timeRemaining: number;
2188
- /** @private */
2189
- generation: number;
2190
- /** Throw a `CancellationError` when the duration of an evaluation exceeds
2191
- * the time limit.
2192
- *
2193
- * Time in milliseconds, default 2000 ms = 2 seconds.
2194
- *
2708
+ /** Time remaining before _deadline
2709
+ * @internal
2195
2710
  */
2711
+ _timeRemaining: number;
2712
+ /** @internal */
2713
+ _generation: number;
2196
2714
  timeLimit: number;
2197
- /** Throw `CancellationError` `iteration-limit-exceeded` when the iteration limit
2198
- * in a loop is exceeded. Default: no limits.
2199
- *
2200
- * @experimental
2201
- */
2202
2715
  iterationLimit: number;
2203
- /** Signal `recursion-depth-exceeded` when the recursion depth for this
2204
- * scope is exceeded.
2205
- *
2206
- * @experimental
2207
- */
2208
2716
  recursionLimit: number;
2209
2717
  chop(n: number): number;
2210
2718
  chop(n: BigNum): BigNum | 0;
@@ -2213,14 +2721,6 @@ export interface ComputeEngine extends IBigNum {
2213
2721
  complex: (a: number | Complex, b?: number) => Complex;
2214
2722
  /** @internal */
2215
2723
  _numericValue(value: number | bigint | OneOf<[BigNum | NumericValueData | ExactNumericValueData]>): NumericValue;
2216
- /** If the precision is set to `machine`, floating point numbers
2217
- * are represented internally as a 64-bit floating point number (as
2218
- * per IEEE 754-2008), with a 52-bit mantissa, which gives about 15
2219
- * digits of precision.
2220
- *
2221
- * If the precision is set to `auto`, the precision is set to 300 digits.
2222
- *
2223
- */
2224
2724
  set precision(p: number | 'machine' | 'auto');
2225
2725
  get precision(): number;
2226
2726
  tolerance: number;
@@ -2230,18 +2730,37 @@ export interface ComputeEngine extends IBigNum {
2230
2730
  box(expr: NumericValue | SemiBoxedExpression, options?: {
2231
2731
  canonical?: CanonicalOptions;
2232
2732
  structural?: boolean;
2733
+ scope?: Scope;
2233
2734
  }): BoxedExpression;
2234
2735
  function(name: string, ops: ReadonlyArray<SemiBoxedExpression>, options?: {
2235
2736
  metadata?: Metadata;
2236
2737
  canonical?: CanonicalOptions;
2237
2738
  structural?: boolean;
2739
+ scope?: Scope;
2740
+ }): BoxedExpression;
2741
+ /**
2742
+ * This is a primitive to create a boxed function.
2743
+ *
2744
+ * In general, consider using `ce.box()` or `ce.function()` or
2745
+ * `canonicalXXX()` instead.
2746
+ *
2747
+ * The caller must ensure that the arguments are in canonical form:
2748
+ * - arguments are `canonical()`
2749
+ * - arguments are sorted
2750
+ * - arguments are flattened and desequenced
2751
+ *
2752
+ * @internal
2753
+ */
2754
+ _fn(name: string, ops: ReadonlyArray<BoxedExpression>, options?: {
2755
+ metadata?: Metadata;
2756
+ canonical?: boolean;
2757
+ scope?: Scope;
2238
2758
  }): BoxedExpression;
2239
- number(value: number | bigint | string | NumericValue | MathJsonNumber | BigNum | Complex | Rational, options?: {
2759
+ number(value: number | bigint | string | NumericValue | MathJsonNumberObject | BigNum | Complex | Rational, options?: {
2240
2760
  metadata?: Metadata;
2241
2761
  canonical?: CanonicalOptions;
2242
2762
  }): BoxedExpression;
2243
2763
  symbol(sym: string, options?: {
2244
- metadata?: Metadata;
2245
2764
  canonical?: CanonicalOptions;
2246
2765
  }): BoxedExpression;
2247
2766
  string(s: string, metadata?: Metadata): BoxedExpression;
@@ -2254,26 +2773,7 @@ export interface ComputeEngine extends IBigNum {
2254
2773
  rules(rules: Rule | ReadonlyArray<Rule | BoxedRule> | BoxedRuleSet | undefined | null, options?: {
2255
2774
  canonical?: boolean;
2256
2775
  }): BoxedRuleSet;
2257
- /**
2258
- * Return a set of built-in rules.
2259
- */
2260
2776
  getRuleSet(id?: 'harmonization' | 'solve-univariate' | 'standard-simplification'): BoxedRuleSet | undefined;
2261
- /**
2262
- * This is a primitive to create a boxed function.
2263
- *
2264
- * In general, consider using `ce.box()` or `ce.function()` or
2265
- * `canonicalXXX()` instead.
2266
- *
2267
- * The caller must ensure that the arguments are in canonical form:
2268
- * - arguments are `canonical()`
2269
- * - arguments are sorted
2270
- * - arguments are flattened and desequenced
2271
- *
2272
- * @internal
2273
- */
2274
- _fn(name: string, ops: ReadonlyArray<BoxedExpression>, options?: Metadata & {
2275
- canonical?: boolean;
2276
- }): BoxedExpression;
2277
2777
  parse(latex: null, options?: Partial<ParseLatexOptions> & {
2278
2778
  canonical?: CanonicalOptions;
2279
2779
  }): null;
@@ -2283,51 +2783,90 @@ export interface ComputeEngine extends IBigNum {
2283
2783
  parse(latex: LatexString | null, options?: Partial<ParseLatexOptions> & {
2284
2784
  canonical?: CanonicalOptions;
2285
2785
  }): BoxedExpression | null;
2286
- pushScope(scope?: Partial<Scope>): ComputeEngine;
2287
- popScope(): ComputeEngine;
2288
- swapScope(scope: RuntimeScope | null): RuntimeScope | null;
2289
- resetContext(): void;
2290
- defineSymbol(name: string, def: SymbolDefinition): BoxedSymbolDefinition;
2291
- lookupSymbol(name: string, wikidata?: string, scope?: RuntimeScope): undefined | BoxedSymbolDefinition;
2292
- defineFunction(name: string, def: FunctionDefinition): BoxedFunctionDefinition;
2293
- lookupFunction(name: string, scope?: RuntimeScope | null): undefined | BoxedFunctionDefinition;
2786
+ pushScope(scope?: Scope, name?: string): void;
2787
+ popScope(): void;
2788
+ /**
2789
+ *
2790
+ * When a new eval context is created, it has slots for the local variables
2791
+ * from the current lexical scope. It also copies the current set of
2792
+ * assumptions.
2793
+ *
2794
+ * Need a pointer to the current lexical scope (may have a scope chain without an evaluation context). Each lexical scope includes a pointer to the parent scope (it's a DAG).
2795
+ *
2796
+ * If a function is "scoped" (has a `scoped` flag), create a new lexical scope
2797
+ * when the function is canonicalized, store the scope with the function
2798
+ * definition (if the function has a lazy flag, and a canonical handler, it
2799
+ * can behave like a scoped function, but a scoped flag is convenient,
2800
+ * it would still evaluate the arguments).
2801
+ *
2802
+ * Note: if an expression is not canonical, evaluating it return itself.
2803
+ * This is important to support arguments that are just symbol names
2804
+ * (they are not canonicalized).
2805
+ *
2806
+ * When the function expression is evaluated, if it is "scoped", push the
2807
+ * scope associated with the function (maybe not?) and a matching eval
2808
+ * context, including all the symbols in the lexical scope (including
2809
+ * constants). Need some way to indicate that a symbol maps to an argument
2810
+ * (in value definition?).
2811
+ *
2812
+ * When searching the value of a symbol, start with the current
2813
+ * eval context, then the previous one.
2814
+ *
2815
+ * When looking for a definition, start with the lexical scope of the
2816
+ * current eval context, then the parent lexical context.
2817
+ *
2818
+ * @internal */
2819
+ _pushEvalContext(scope: Scope, name?: string): void;
2820
+ /** @internal */
2821
+ _popEvalContext(): void;
2822
+ /**
2823
+ * Temporarily sets the lexical scope to the provided scope, then
2824
+ * executes the function `f` in that scope and returns the result.
2825
+ * @internal */
2826
+ _inScope<T>(scope: Scope | undefined, f: () => T): T;
2827
+ /**
2828
+ * Use `ce.box(id)` instead
2829
+ * @internal */
2830
+ _getSymbolValue(id: MathJsonSymbol): BoxedExpression | undefined;
2831
+ /**
2832
+ * Use `ce.assign(id, value)` instead.
2833
+ * @internal */
2834
+ _setSymbolValue(id: MathJsonSymbol, value: BoxedExpression | boolean | number | undefined): void;
2835
+ /** A list of the function calls to the current evaluation context */
2836
+ trace: ReadonlyArray<string>;
2837
+ lookupContext(id: MathJsonSymbol): undefined | EvalContext;
2838
+ /** @internal */
2839
+ _swapContext(context: EvalContext): void;
2840
+ lookupDefinition(id: MathJsonSymbol): undefined | BoxedDefinition;
2294
2841
  assign(ids: {
2295
- [id: string]: AssignValue;
2842
+ [id: MathJsonSymbol]: AssignValue;
2296
2843
  }): ComputeEngine;
2297
- assign(id: string, value: AssignValue): ComputeEngine;
2298
- assign(arg1: string | {
2299
- [id: string]: AssignValue;
2844
+ assign(id: MathJsonSymbol, value: AssignValue): ComputeEngine;
2845
+ assign(arg1: MathJsonSymbol | {
2846
+ [id: MathJsonSymbol]: AssignValue;
2300
2847
  }, arg2?: AssignValue): ComputeEngine;
2301
- declare(identifiers: {
2302
- [id: string]: Type | TypeString | OneOf<[SymbolDefinition | FunctionDefinition]>;
2848
+ declareType(name: string, type: Type, options?: {
2849
+ alias?: boolean;
2850
+ }): void;
2851
+ declare(symbols: {
2852
+ [id: MathJsonSymbol]: Type | TypeString | Partial<SymbolDefinition>;
2303
2853
  }): ComputeEngine;
2304
- declare(id: string, def: Type | TypeString | SymbolDefinition | FunctionDefinition): ComputeEngine;
2305
- declare(arg1: string | {
2306
- [id: string]: Type | TypeString | OneOf<[SymbolDefinition | FunctionDefinition]>;
2307
- }, arg2?: Type | OneOf<[SymbolDefinition | FunctionDefinition]>): ComputeEngine;
2854
+ declare(id: MathJsonSymbol, def: Type | TypeString | Partial<SymbolDefinition>, scope?: Scope): ComputeEngine;
2855
+ declare(arg1: MathJsonSymbol | {
2856
+ [id: MathJsonSymbol]: Type | TypeString | Partial<SymbolDefinition>;
2857
+ }, arg2?: Type | TypeString | Partial<SymbolDefinition>, arg3?: Scope): ComputeEngine;
2308
2858
  assume(predicate: BoxedExpression): AssumeResult;
2309
- forget(symbol?: string | string[]): void;
2310
- get assumptions(): ExpressionMapInterface<boolean>;
2859
+ forget(symbol?: MathJsonSymbol | MathJsonSymbol[]): void;
2311
2860
  ask(pattern: BoxedExpression): BoxedSubstitution[];
2312
2861
  verify(query: BoxedExpression): boolean;
2313
2862
  /** @internal */
2314
- shouldContinueExecution(): boolean;
2315
- /** @internal */
2316
- checkContinueExecution(): void;
2863
+ _shouldContinueExecution(): boolean;
2317
2864
  /** @internal */
2318
- cache<T>(name: string, build: () => T, purge?: (t: T) => T | undefined): T;
2865
+ _checkContinueExecution(): void;
2319
2866
  /** @internal */
2320
- readonly stats: ComputeEngineStats;
2867
+ _cache<T>(name: string, build: () => T, purge?: (t: T) => T | undefined): T;
2321
2868
  /** @internal */
2322
- reset(): void;
2323
- /** @internal */
2324
- _register(expr: BoxedExpression): void;
2869
+ _reset(): void;
2325
2870
  /** @internal */
2326
- _unregister(expr: BoxedExpression): void;
2327
- }
2328
- /** @internal */
2329
- export interface ComputeEngineStats {
2330
- symbols: Set<BoxedExpression>;
2331
- expressions: null | Set<BoxedExpression>;
2332
- highwaterMark: number;
2871
+ listenToConfigurationChange(tracker: ConfigurationChangeListener): () => void;
2333
2872
  }