Compute Engine Changelog
Coming Soon
Breaking Changes
-
The
expr.value
property reflects the value of the expression if it is a number literal or a symbol with a literal value. If you previously used theexpr.value
property to get the value of an expression, you should now use theexpr.N().valueOf()
method instead. ThevalueOf()
method is suitable for interoperability with JavaScript, but it may result in a loss of precision for numbers with more than 15 digits. -
BoxedExpr.sgn
now returns undefined for complex numbers, or symbols with a complex-number value. -
The
ce.assign()
method previously acceptedce.assign("f(x, y)", ce.parse("x+y"))
. This is now deprecated. Usece.assign("f", ce.parse("(x, y) \\mapsto x+y")
instead. -
It was previously possible to invoke
expr.evaluate()
orexpr.N()
on a non-canonical expression. This will now return the expression itself.To evaluate a non-canonical expression, use
expr.canonical.evaluate()
orexpr.canonical.N()
.That's also the case for the methods
numeratorDenominator()
,numerator()
, anddenominator()
.In addition, invoking the methods
inv()
,abs()
,add()
,mul()
,div()
,pow()
,root()
,ln()
will throw an error if the expression is not canonical.
New Features and Improvements
- Antiderivatives are now computed symbolically:
ce.parse(`\\int_0^1 \\sin(\\pi x) dx`).evaluate().print();
// -> 2 / pi
ce.parse(`\\int \\sin(\\pi x) dx`).evaluate().print();
// -> -cos(pi * x) / pi
Requesting a numeric approximation of the integral will use a Monte Carlo method:
ce.parse(`\\int_0^1 \\sin(\\pi x) dx`).N().print();
// -> 0.6366
-
Numeric approximations of integrals is several order of magnitude faster.
-
The
symbol
type can be refined to match a specific symbol. For examplesymbol<True>
. The typeexpression
can be refined to match expressions with a specific operator, for exampleexpression<Add>
is a type that matches expressions with theAdd
operator. The numeric types can be refined with a lower and upper bound. For exampleinteger<0..10>
is a type that matches integers between 0 and 10. The typereal<1..>
matches real numbers greater than 1 andrational<..0>
matches non-positive rational numbers. -
The bindings of symbols and function expressions is now consistently done during canonicalization.
-
It was previously not possible to change the type of an identifier from a function to a value or vice versa. This is now possible.
-
Added a rule to solve the equation
a^x + b = 0
-
The LaTeX parser now supports the
\placeholder[]{}
,\phantom{}
,\hphantom{}
,\vphantom{}
,\mathstrut
,\strut
and\smash{}
commands. -
The range of recognized sign values, i.e. as returned from
BoxedExpression.sgn
has been simplified (e.g. '...-infinity' and 'nan' have been removed) -
The Power canonical-form is less aggressive - only carrying-out ops. as listed in doc. - is much more careful in its consideration of operand types & values... (for example, typically, exponents are required to be numbers: e.g.
x^1
will simplify, butx^y
(where y===0), orx^{1+0}
, will not)
Issues Resolved
-
Ensure expression LaTeX serialization is based on MathJSON generated with matching 'pretty' formatting (or not), therefore resulting in LaTeX with less prettification, where
prettify == false
(#daef87f) -
Symbols declare with a
constant
flag are now not marked as 'inferred' -
Some BoxedSymbols properties now more consistently return 'undefined', instead of a 'boolean' (i.e. because the symbol is non-bound)
-
Some
expr.root()
computations -
Canonical-forms
- Fixes the
Number
form - Forms (at least, 'Number', 'Power') do not mistakenly fully canonicalize operands
- This (partial canonicalization) now substitutes symbols (constants) with a
holdUntil
value of never during/prior-to canonicalization (i.e. just like for full canonicalization)
- Fixes the
0.29.1 2025-03-31
- #231 During evaluation, some numbers, for example
10e-15
were incorrectly rounded to 0.
0.28.0 2025-02-06
Issues Resolved
-
#211 More consistent canonicalization and serialization of exact numeric values of the form
(a√b)/c
. -
#219 The
invisibleOperator
canonicalization previously also canonicalized some multiplication. -
#218 Improved performance of parsing invisible operators, including fixing some cases where the parsing was incorrect.
-
#216 Correctly parse subscripts with a single character, for example
x_1
. -
#216 Parse some non-standard integral signs, for example
\int x \cdot \differentialD x
(both the\cdot
and the\differentialD
are non-standard). -
#210 Numeric approximation of odd nth roots of negative numbers evaluate correctly.
-
#153 Correctly parse integrals with
\limits
, e.g.\int\limits_0^1 x^2 \mathrm{d} x
. -
Correctly serialize to ASCIIMath
Delimiter
expressions. -
When inferring the type of numeric values do not constrain them to be
real
. As a result:ce.assign('a', ce.parse('i'));
ce.parse('a+1').evaluate().print();
now returns `1 + i` instead of throwing a type error.
- Correctly parse and evaluate unary and binary `\pm` and `\mp` operators.
### New Features and Improvements
- `expr.isEqual()` will now return true/false if the expressions include the
same unknowns and are structurally equal after expansion and simplifications.
For example:
```js
console.info(ce.parse('(x+1)^2').isEqual(ce.parse('x^2+2x+1')));
// -> true
```
#### Asynchronous Operations
Some computations can be time-consuming, for example, computing a very large
factorial. To prevent the browser from freezing, the Compute Engine can now
perform some operations asynchronously.
To perform an asynchronous operation, use the `expr.evaluateAsync` method. For
example:
```js
try {
const fact = ce.parse('(70!)!');
const factResult = await fact.evaluateAsync();
factResult.print();
} catch (e) {
console.error(e);
}
```
It is also possible to interrupt an operation, for example by providing a
pause/cancel button that the user can press. To do so, use an `AbortController`
object and a `signal`. For example:
```js
const abort = new AbortController();
const signal = abort.signal;
setTimeout(() => abort.abort(), 500);
try {
const fact = ce.parse('(70!)!');
const factResult = await fact.evaluateAsync({ signal });
factResult.print();
} catch (e) {
console.error(e);
}
```
In the example above, we trigger an abort after 500ms.
It is also possible to control how long an operation can run by setting the
`ce.timeLimit` property with a value in milliseconds. For example:
```js
ce.timeLimit = 1000;
try {
const fact = ce.parse('(70!)!');
fact.evaluate().print();
} catch (e) {
console.error(e);
}
```
The time limit applies to either the synchronous or asynchronous evaluation.
The default time limit is 2,000ms (2 seconds).
When an operation is canceled either because of a timeout or an abort, a
`CancellationError` is thrown.
## 0.27.0 _2024-12-02_
- **#217** Correctly parse LaTeX expressions that include a command followed by
a `*` such as `\\pi*2`.
- **#217** Correctly calculate the angle of trigonometric expressions with an
expression containing a reference to `Pi`, for example `\\sin(\\pi^2)`.
- The `Factorial` function will now time out if the argument is too large. The
timeout is signaled by throwing a `CancellationError`.
- When specifying `exp.toMathJSON({shorthands:[]})`, i.e., not to use shorthands
in the MathJSON, actually avoid using shorthands.
- Correctly use custom multiply, plus, etc. for LaTeX serialization.
- When comparing two numeric values, the tolerance is now used to determine if
the values are equal. The tolerance can be set with the `ce.tolerance`
property.
- When comparing two expressions with `isEqual()` the values are compared
structurally when necessary, or with a stochastic test when the expressions
are too complex to compare structurally.
- Correctly serialize nested superscripts, e.g. `x^{y^z}`.
- The result of evaluating a `Hold` expression is now the expression itself.
- To prevent evaluation of an expression temporarily, use the `Unevaluated`
function. The result of evaluating an `Unevaluated` expression is its
argument.
- The type of a `Hold` expression was incorrectly returned as `string`. It now
returns the type of its argument.
- The statistics function (`Mean`, `Median`, `Variance`, `StandardDeviation`,
`Kurtosis`, `Skewness`, `Mode`, `Quartiles` and `InterQuartileRange`) now
accept as argument either a collection or a sequence of values.
```js
ce.parse("\\mathrm{Mean}([7, 2, 11])").evaluate().print();
// -> 20/3
ce.parse("\\mathrm{Mean}(7, 2, 11)").evaluate().print();
// -> 20/3
```
- The `Variance` and `StandardDeviation` functions now have variants for
population statistics, `PopulationVariance` and `PopulationStandardDeviation`.
The default is to use sample statistics.
```js
ce.parse("\\mathrm{PopulationVariance}([7, 2, 11])").evaluate().print();
// -> 13.555
ce.parse("\\mathrm{Variance}([7, 2, 11])").evaluate().print();
// -> 20.333
```
- The statistics function can now be compiled to JavaScript:
```js
const code = ce.parse("\\mathrm{Mean}(7, 2, 11)").compile();
console.log(code());
// -> 13.555
```
- The statistics function calculate either using machine numbers or bignums
depending on the precision. The precision can be set with the `precision`
property of the Compute Engine.
- The argument of compiled function is now optional.
- Compiled expressions can now reference external JavaScript functions. For
example:
```js
ce.defineFunction('Foo', {
signature: 'number -> number',
evaluate: ([x]) => ce.box(['Add', x, 1]),
});
const fn = ce.box(['Foo', 3]).compile({
functions: { Foo: (x) => x + 1 },
})!;
console.info(fn());
// -> 4
```
```js
ce.defineFunction('Foo', {
signature: 'number -> number',
evaluate: ([x]) => ce.box(['Add', x, 1]),
});
function foo(x) {
return x + 1;
}
const fn = ce.box(['Foo', 3]).compile({
functions: { Foo: foo },
})!;
console.info(fn());
// -> 4
```
Additionally, functions can be implicitly imported (in case they are needed by
other JavaScript functions):
```js
ce.defineFunction('Foo', {
signature: 'number -> number',
evaluate: ([x]) => ce.box(['Add', x, 1]),
});
function bar(x, y) {
return x + y;
}
function foo(x) {
return bar(x, 1);
}
const fn = ce.box(['Foo', 3]).compile({
functions: { Foo: 'foo' },
imports: [foo, bar],
})!;
console.info(fn());
// -> 4
```
- Compiled expression can now include an arbitrary preamble (JavaScript source)
that is executed before the compiled function is executed. This can be used to
define additional functions or constants.
```js
ce.defineFunction('Foo', {
signature: 'number -> number',
evaluate: ([x]) => ce.box(['Add', x, 1]),
});
const code = ce.box(['Foo', 3]).compile({
preamble: "function Foo(x) { return x + 1};",
});
```
- The `hold` function definition flag has been renamed to `lazy`
## 0.26.4 _2024-10-17_
- **#201** Identifiers of the form `A_\text{1}` were not parsed correctly.
- **#202** Fixed serialization of integrals and bigops.
## 0.26.3 _2024-10-17_
- Correctly account for `fractionalDigits` when formatting numbers.
- **#191** Correctly handle `\\lnot\\forall` and `\\lnot\\exists`.
- **#206** The square root of 1000000 was canonicalized to 0.
- **#207** When a square root with a literal base greater than 1e6 was preceded
by a non-integer literal number, the literal number was ignored during
canonicalization.
- **#208** **#204** Correctly evaluate numeric approximation of roots, e.g.
`\\sqrt[3]{125}`.
- **#205** `1/ln(0)` was incorrectly evaluated to `1`. It now returns `0`.
## 0.26.1 _2024-10-04_
### Issues Resolved
- **#194** Correctly handle the precedence of unary negate, for example in
`-5^{\frac12}` or `-5!`.
- When using a function definition with `ce.declare()`, do not generate a
runtime error.
### New Features and Improvements
- Added `.expand()` method to boxed expression. This method expands the
expression, for example `ce.parse("(x+1)^2").expand()` will return
`x^2 + 2x + 1`.
## 0.26.0 _2024-10-01_
### Breaking Changes
- The property `expr.head` has been deprecated. Use `expr.operator` instead.
`expr.head` is still supported in this version but will be removed in a future
update.
- The MathJSON utility functions `head()` and `op()` have been renamed to
`operator()` and `operand()` respectively.
- The methods for algebraic operations (`add`, `div`, `mul`, etc...) have been
moved from the Compute Engine to the Boxed Expression class. Instead of
calling `ce.add(a, b)`, call `a.add(b)`.
Those methods also behave more consistently: they apply some additional
simplication rules over canonicalization. For example, while
`ce.parse('1 + 2')` return `["Add", 1, 2]`, `ce.box(1).add(2)` will return
`3`.
- The `ce.numericMode` option has been removed. Instead, set the `ce.precision`
property to the desired precision. Set the precision to `"machine"` for
machine precision calculations (about 15 digits). Set it to `"auto"` for a
default of 21 digits. Set it to a number for a greater fixed precision.
- The MathJSON Dictionary element has been deprecated. Use a `Dictionary`
expression instead.
- The `ExtendedRealNumbers`, `ExtendedComplexNumbers` domains have been
deprecated. Use the `RealNumbers` and `ComplexNumbers` domains instead.
- The "Domain" expression has been deprecated. Use types instead (see below).
- Some `BoxedExpression` properties have been removed:
- Instead of `expr.isZero`, use `expr.is(0)`.
- Instead of `expr.isNotZero`, use `!expr.is(0)`.
- Instead of `expr.isOne`, use `expr.is(1)`.
- Instead of `expr.isNegativeOne`, use `expr.is(-1)`.
- The signature of `ce.declare()` has changed. In particular, the `N` handler
has been replaced with `evaluate`.
```ts
// Before
ce.declare('Mean', {
N: (ce: IComputeEngine): BoxedExpression => {
return ce.number(1);
},
});
// Now
ce.declare('Mean', { evaluate: (ops, { engine }) => ce.number(1) });
```
### New Features and Improvements
- **New Simplification Engine**
The way expressions are simplified has been completely rewritten. The new
engine is more powerful and more flexible.
The core API remains the same: to simplify an expression, use
`expr.simplify()`.
To use a custom set of rules, pass the rules as an argument to `simplify()`:
```js
expr.simplify({rules: [
"|x:<0| -> -x",
"|x:>=0| -> x",
]});
```
There are a few changes to the way rules are represented. The `priority`
property has been removed. Instead, rules are applied in the order in which
they are defined.
A rule can also now be a function that takes an expression and returns a new
expression. For example:
```js
expr.simplify({rules: [
(expr) => {
if (expr.operator !== 'Abs') return undefined;
const x = expr.args[0];
return x.isNegative ? x.negate() : expr;
}
]});
```
This can be used to perform more complex transformations at the cost of more
verbose JavaScript code.
The algorithm for simplification has been simplified. It attempts to apply
each rule in the rule set in turn, then restarts the process until no more
rules can be applied or the result of applying a rule returns a previously
seen expression.
Function definitions previously included a `simplify` handler that could be
used to perform simplifications specific to this function. This has been
removed. Instead, use a rule that matches the function and returns the
simplified expression.
- **Types**
Previously, an expression was associated with a domain such as `RealNumbers`
or `ComplexNumbers`. This has been replaced with a more flexible system of
types.
A type is a set of values that an expression can take. For example, the type
`real` is the set of real numbers, the type `integer` is the set of integers,
The type of an expression can be set with the `type` property. For example:
```js
const expr = ce.parse('\\sqrt{-1}');
console.info(expr.type); // -> imaginary
```
The type of a symbol can be set when declaring the symbol. For example:
```js
ce.declare('x', 'imaginary');
```
In addition to primitive types, the type system supports more complex types
such union types, intersection types, and function types.
For example, the type `real|imaginary` is the union of the real and imaginary
numbers.
When declaring a function, the type of the arguments and the return value can
be specified. For example, to declare a function `f` that takes two integers
and returns a real number:
```js
ce.declare('f', '(integer, integer) -> real');
```
The sets of numbers are defined as follows:
- `number` - any number, real or complex, including NaN and infinity
- `non_finite_number` - NaN or infinity
- `real`
- `finite_real` - finite real numbers (exclude NaN and infinity)
- `imaginary` - imaginary numbers (complex numbers with a real part of 0)
- `finite_imaginary`
- `complex` - complex numbers with a real and imaginary part not equal to 0
- `finite_complex`
- `rational`
- `finite_rational`
- `integer`
- `finite_integer`
To check the type of an expression, use the `isSubtypeOf()` method. For
example:
```js
let expr = ce.parse('5');
console.info(expr.type.isSubtypeOf('rational')); // -> true
console.info(expr.type.isSubtypeOf('integer')); // -> true
expr = ce.parse('\\frac{1}{2}');
console.info(expr.type.isSubtypeOf('rational')); // -> true
console.info(expr.type.isSubtypeOf('integer')); // -> false
```
As a shortcut, the properties `isReal`, `isRational`, `isInteger` are
available on boxed expressions. For example:
```js
let expr = ce.parse('5');
console.info(expr.isInteger); // -> true
console.info(expr.isRational); // -> true
```
They are equivalent to `expr.type.isSubtypeOf('integer')` and
`expr.type.isSubtypeOf('rational')` respectively.
To check if a number has a non-zero imaginary part, use:
```js
let expr = ce.parse('5i');
console.info(expr.isNumber && expr.isReal === false); // -> true
```
- **Collections**
Support for collections has been improved. Collections include `List`, `Set`,
`Tuple`, `Range`, `Interval`, `Linspace` and `Dictionary`.
It is now possible to check if an element is contained in a collection using
an `Element` expression. For example:
```js
let expr = ce.parse('[1, 2, 3]');
ce.box(['Element', 3, expr]).print(); // -> True
ce.box(['Element', 5, expr]).print(); // -> False
```
To check if a collection is a subset of another collection, use the `Subset`
expression. For example:
```js
ce.box(['Subset', 'Integers', 'RealNumbers']).print(); // -> True
```
Collections can also be compared for equality. For example:
```js
let set1 = ce.parse('\\lbrace 1, 2, 3 \\rbrace');
let set2 = ce.parse('\\lbrace 3, 2, 1 \\rbrace');
console.info(set1.isEqual(set2)); // -> true
```
There are also additional convenience methods on boxed expressions:
- `expr.isCollection`
- `expr.contains(element)`
- `expr.size`
- `expr.isSubsetOf(other)`
- `expr.indexOf(element)`
- `expr.at(index)`
- `expr.each()`
- `expr.get(key)`
- **Exact calculations**
The Compute Engine has a new backed for numerical calculations. The new backed
can handle arbitrary precision calculations, including real and complex
numbers. It can also handle exact calculations, preserving calculations with
rationals and radicals (square root of integers). For example `1/2 + 1/3` is
evaluated to `5/6` instead of `0.8(3)`.
To get an approximate result, use the `N()` method, for example
`ce.parse("\\frac12 + \\frac13").N()`.
Previously the result of calculations was not always an exact number but
returned a numerical approximation instead.
This has now been improved by introducing a `NumericValue` type that
encapsulates exact numbers and by doing all calculations in this type.
Previously the calculations were handled manually in the various evaluation
functions. This made the code complicated and error prone.
A `NumericValue` is made of:
- an imaginary part, represented as a fixed-precision number
- a real part, represented either as a fixed or arbitrary precision number or
as the product of a rational number and the square root of an integer.
For example:
- 234.567
- 1/2
- 3√5
- √7/3
- 4-3i
While this is a significant change internally, the external API remains the
same. The result of calculations should be more predictable and more accurate.
One change to the public API is that the `expr.numericValue` property is now
either a machine precision number or a `NumericValue` object.
- **Rule Wildcards**
When defining a rule as a LaTeX expression, single character identifiers are
interpreted as wildcards. For example, the rule `x + x -> 2x` will match any
expression with two identical terms. The wildcard corresponding to `x` is
`_x`.
It is now possible to define sequence wildcards and optional sequence
wildcards. Sequence wildcards match 1 or more expressions, while optional
sequence wildcards match 0 or more expressions.
They are indicated in LaTeX as `...x` and `...x?` respectively. For example:
```js
expr.simplify("x + ...y -> 2x");
```
If `expr` is `a + b + c` the rule will match and return `2a`
```js
expr.simplify("x + ...y? -> 3x");
```
If `expr` is `a + b + c` the rule will match and return `3a`. If `expr` is `a`
the rule will match and return `3a`.
- **Conditional Rules**
Rules can now include conditions that are evaluated at runtime. If the
condition is not satisfied, the rules does not apply.
For example, to simplify the expression `|x|`:
```js
expr.simplify({rules: [
"|x_{>=0}| -> x",
"|x_{<0}| -> -x",
]});
```
The condition is indicated as a subscript of the wildcard. The condition can
be one of:
- `boolean` - a boolean value, True or False
- `string` - a string of characters
- `number` - a number literal
- `symbol`
- `expression`
- `numeric` - an expression that has a numeric value, i.e. 2√3, 1/2, 3.14
- `integer` - an integer value, -2, -1, 0, 1, 2, 3, ...
- `natural` - a natural number, 0, 1, 2, 3, ...
- `real` - real numbers, including integers
- `imaginary` - imaginary numbers, i.e. 2i, 3√-1 (not including real numbers)
- `complex` - complex numbers, including real and imaginary
- `rational` - rational numbers, 1/2, 3/4, 5/6, ...
- `irrational` - irrational numbers, √2, √3, π, ...
- `algebraic` - algebraic numbers, rational and irrational
- `transcendental` - transcendental numbers, π, e, ...
- `positive` - positive real numbers, \> 0
- `negative` - negative real numbers, \< 0
- `nonnegative` - nonnegative real numbers, \>= 0
- `nonpositive` - nonpositive real numbers, \<= 0
- `even` - even integers, 0, 2, 4, 6, ...
- `odd` - odd integers, 1, 3, 5, 7, ...
- `prime` :A000040 - prime numbers, 2, 3, 5, 7, 11, ...
- `composite` :A002808 - composite numbers, 4, 6, 8, 9, 10, ...
- `notzero` - a value that is not zero
- `notone` - a value that is not one
- `finite` - a finite value, not infinite
- `infinite`
- `constant`
- `variable`
- `function`
- `operator`
- `relation` - an equation or inequality
- `equation`
- `inequality`
- `vector` - a tensor of rank 1
- `matrix` - a tensor of rank 2
- `list` - a collection of values
- `set` - a collection of unique values
- `tuple` - a fixed length list
- `single` - a tuple of length 1
- `pair` - a tuple of length 2
- `triple` - a tuple of length 3
- `collection` - a list, set, or tuple
- `tensor` - a nested list of values of the same type
- `scalar` - not a tensor or list
or one of the following expressions:
- `>0'` -> `positive`,
- `\gt0'` -> `positive`,
- `<0'` -> `negative`,
- `\lt0'` -> `negative`,
- `>=0'` -> `nonnegative`,
- `\geq0'` -> `nonnegative`,
- `<=0'` -> `nonpositive`,
- `\leq0'` -> `nonpositive`,
- `!=0'` -> `notzero`,
- `\neq0'` -> `notzero`,
- `!=1'` -> `notone`,
- `\neq1'` -> `notone`,
- `\in\Z'` -> `integer`,
- `\in\mathbb{Z}'` -> `integer`,
- `\in\N'` -> `natural`,
- `\in\mathbb{N}'` -> `natural`,
- `\in\R'` -> `real`,
- `\in\mathbb{R}'` -> `real`,
- `\in\C'` -> `complex`,
- `\in\mathbb{C}'` -> `complex`,
- `\in\Q'` -> `rational`,
- `\in\mathbb{Q}'` -> `rational`,
- `\in\Z^+'` -> `integer,positive`,
- `\in\Z^-'` -> `intger,negative`,
- `\in\Z^*'` -> `nonzero`,
- `\in\R^+'` -> `positive`,
- `\in\R^-'` -> `negative`,
- `\in\R^*'` -> `real,nonzero`,
- `\in\N^*'` -> `integer,positive`,
- `\in\N_0'` -> `integer,nonnegative`,
- `\in\R\backslash\Q'` -> `irrational`,
More complex conditions can be specified following a semi-colon, for example:
```js
expr.simplify({x -> 2x; x < 10});
```
Note that this syntax complements the existing rule syntax, and can be used
together with the existing, more verbose, rule syntax.
```js
expr.simplify({rules: [
{match: "x + x", replace: "2x", condition: "x < 10"}
]});
```
This advanced syntax can specify more complex conditions, for example above
the rule will only apply if `x` is less than 10.
- Improved results for `Expand`. In some cases the expression was not fully
expanded. For example, `4x(3x+2)-5(5x-4)` now returns `12x^2 - 17x + 20`.
Previously it returned `4x(3x+2)+25x-20`.
- **AsciiMath serialization** The `expr.toString()` method now returns a
serialization of the expression using the [AsciiMath](https://asciimath.org/)
format.
The serialization to AsciiMath can be customized using the `toAsciiMath()`
method. For example:
```js
console.log(ce.box(['Sigma', 2]).toAsciiMath({functions: {Sigma: 'sigma'}}));
// -> sigma(2)
```
- The tolerance can now be specified with a value of `"auto"` which will use the
precision to determine a reasonable tolerance. The tolerance is used when
comparing two numbers for equality. The tolerance can be specified with the
`ce.tolerance` property or in the Compute Engine constructor.
- Boxed expressions have some additional properties:
- `expr.isNumberLiteral` - true if the expression is a number literal.This is
equivalent to checking if `expr.numericValue` is not `null`.
- `expr.re` - the real part of the expression, if it is a number literal,
`undefined` if not a number literal.
- `expr.im` - the imaginary part of the expression, if it is a number literal,
`undefined` if not a number literal.
- `expr.bignumRe` - the real part of the expression as a bignum, if it is a
number literal, `undefined` if not a number literal or a bignum
representation is not available.
- `expr.bignumIm` - the imaginary part of the expression as a bignum, if it is
a number literal, `undefined` if not a number literal or if a bignum
representation is not available.
- `expr.root()` to get the root of the expression. For example, `expr.root(3)`
will return the cube root of the expression.
- Additionally, the relational operators (`expr.isLess(), expr.isEqual()`,
etc...) now accept a number argument. For example, `expr.isGreater(1)` will
return true if the expression is greater than 1.
- Added LaTeX syntax to index collections. If `a` is a collection:
- `a[i]` is parsed as `["At", "a", "i"]`.
- `a[i,j]` is parsed as `["At", "a", "i", "j"]`.
- `a_i` is parsed as `["At", "a", "i"]`.
- `a_{i,j}` is parsed as `["At", "a", "i", "j"]`.
- Added support for Kronecker delta notation, i.e. `\delta_{ij}`, which is
parsed as `["KroneckerDelta", "i", "j"]` and is equal to 1 if `i = j` and 0
otherwise.
When a single index is provided the value of the function is 1 if the index is
0 and 0 otherwise
When multiple index are provided, the value of the function is 1 if all the
indexes are equal and 0 otherwise.
- Added support for Iverson Bracket notation, i.e. `[a = b]`, which is parsed as
`["Boole", ["Equal", "a", "b"]]` and is equal to 1 if its argument is true and
0 otherwise. The argument is expected to be a relational expression.
- Implemented `Unique` and `Tally` on collections. `Unique` returns a collection
with only the unique elements of the input collection, and `Tally` returns a
collection with the count of each unique element.
```js
console.log(ce.box(['Unique', ['List', 1, 2, 3, 1, 2, 3, 4, 5]]).value);
// -> [1, 2, 3, 4, 5]
console.log(ce.box(['Tally', ['List', 1, 2, 3, 1, 2, 3, 4, 5]]).value);
// -> [['List', 1, 2, 3, 4, 5], ['List', 2, 2, 2, 1, 1]]
```
- Implemented the `Map`, `Filter` and `Tabulate` functions. These functions can
be used to transform collections, for example:
```js
// Using LaTeX
console.log(ce.parse('\\mathrm{Map}([3, 5, 7], x \\mapsto x^2)').toString());
// -> [9, 25, 49]
// Using boxed expressions
console.log(
ce.box(['Map', ['List', 3, 5, 7], ['Square', '_']]).value
);
// -> [9, 25, 49]
console.log(ce.box(['Tabulate',['Square', '_'], 5]).value);
// -> [1, 4, 9, 16, 25]
```
`Tabulate` can be used with multiple indexes. For example, to generate a 4x4
unit matrix:
```js
console.log(ce.box(['Tabulate', ['If', ['Equal', '_1', '_2'], 1, 0]], 4, 4).value);
// -> [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
// Using the Kronecker delta notation:
console.log(ce.parse('\\mathrm{Tabulate}(i, j \\mapsto \\delta_{ij}, 4, 4)').value);
// -> [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
```
- Added `Random` function. `["Random"]` returns a real pseudo-random number
betwen 0 and 1. `["Random", 10]` returns an integer between 0 and 9,
`["Random", 5, 10]` returns an integer between 5 and 10.
- Extended the definition of `expr.isConstant`. Previously, it only applied to
symbols, e.g. `Pi`. Now it apply to all expressions. `expr.isConstant` is true
if the expression is a number literal, a symbol with a constant value, or a
pure function with constant arguments.
- The boxed expression properties `isPositive`, `isNegative`, `isNonNegative`,
`isNonPositive`, `isZero`, `isNotZero` now return a useful value for most
function expressions. For example, `ce.parse('|x + 1|').isPositive` is true.
If the value cannot be determined, the property will return `undefined`. For
example, `ce.parse('|x + 1|').isZero` is `undefined`.
If the expression is not a real number, the property will return `NaN`. For
example, `ce.parse('i').isPositive` is `NaN`.
- Added `Choose` function to compute binomial coefficients, i.e. `Choose(5, 2)`
is equal to 10.
- The fallback for non-constructible complex values of trigonometric functions
is now implemented via rules.
- The canonical order of the arguments has changed and should be more consistent
and predictable. In particular, for polynomials, the
[monomial order](https://en.wikipedia.org/wiki/Monomial_order) is now
**degrevlex**.
- Canonical expressions can now include a `Root` expression. For example, the
canonical form of `\\sqrt[3]{5}` is `["Root", 5, 3]`. Previously, these were
represented as `["Power", 5, ["Divide", 1, 3]]`.
- The function definitions no longer have a `N` handler. Instead the `evaluate`
handler has an optional `{numericApproximation}` argument.
### Issues Resolved
- **#188** Throw an error when invalid expressions are boxed, for example
`ce.box(["Add", ["3"]])`.
- Some LaTeX renderer can't render `\/`, so use `/` instead.
- When definitions are added to the LaTeX dictionary, they now take precedence
over the built-in definitions. This allows users to override the built-in
definitions.
- Improved parsing of functions, including when a mixture of named and
positional arguments are used.
- **#175** Matching some patterns when the target had not enough operands would
result in a runtime error.
## 0.25.1 _2024-06-27_
### Issues Resolved
- **#174** Fixed some simplifications, such as `\frac{a^n}{a^m} = a^{n-m)`
### New Features
- Rules can be defined using a new shorthand syntax, where each rule is a string
of LaTeX:
```js
expr.simplify(["\\frac{x}{x} -> 1", "x + x -> 2x"]);
```
Single letter variables are assumed to be wildcards, so `x` is interpreted as
the wildcard `_x`.
Additionally, the expanded form can also include LaTeX strings. The previous
syntax using expressions can still be used, and the new and old syntax can be
mixed.
For example:
```js
expr.simplify([
{
match: "\\frac{x}{x}",
replace: "1"
},
{
match: ["Add", "x", "x"],
replace: "2x"
}
]);
```
The `condition` function can also be expressed as a LaTeX string.
```js
expr.simplify([ { match: "\\frac{x}{x}", replace: 1, condition: "x != 0" }, ]);
```
The shorthand syntax can be used any where a ruleset is expected, including with
the `ce.rule()` function.
- A new `ce.getRuleSet()` method gives access to the built-in rules.
- **#171** The `Subtract` and `Divide` function can now accept an arbitrary
number of arguments. For example, `["Subtract", 1, 2, 3]` is equivalent to
`["Subtract", ["Subtract", 1, 2], 3]`.
## 0.25.0 _2024-06-25_
### Breaking Changes
- The canonical form of expressions has changed. It is now more consistent and
simpler and should produce more predictable results.
For example, previously `ce.parse("1-x^2")` would produce
`["Subtract", 1, ["Square", "x"]]`.
While this is a readable form, it introduces some complications when
manipulating the expression: both the `Subtract` and `Square` functions have
to be handled, in addition to `Add` and `Power`.
The new canonical form of this expression is
`["Add", 1, ["Negate", ["Power", "x", 2]]]`. It is a bit more verbose, but it
is simpler to manipulate.
- The `ce.serialize()` method has been replaced with `expr.toLatex()` and
`expr.toMathJson()`. The `ce.latexOptions` and `ce.jsonSerializationOptions`
properties have been removed. Instead, pass the formating options directly to
the `toLatex()` and `toMathJson()` methods. The `ce.parse()` method now takes
an optional argument to specify the format of the input string.
- The default JSON serialization of an expression has changed.
Previously, the default JSON serialization, accessed via the `.json` property,
had some transformations applied to it (sugaring) to make the JSON more human
readable.
For example, `ce.parse("\frac12").json` would return the symbol `"Half"`
instead of `["Divide", 1, 2]`.
However, this could lead to some confusion when manipulating the JSON
directly. Since the JSON is intended to be used by machine more than humans,
these additional transformations have been removed.
The `expr.json` property now returns the JSON representing the expression,
without any transformations.
To get a version of JSON with some transformations applied use the
`ce.toMathJson()` function.
```js
expr = ce.box(["Subtract", 1, ["Square", "x"]]);
console.log(expr.json);
// -> ["Add", 1, ["Negate", ["Power", "x", 2]]]
expr.toMathJson()
// -> ["Subtract", 1, ["Square", "x"]]
expr.toMathJson({exclude: "Square"})
// -> ["Subtract", 1, ["Power", "x", 2]]
```
In practice, the impact of both of these changes should be minimal. If you
were manipulating expressions using `BoxedExpression`, the new canonical form
should make it easier to manipulate expressions. You can potentially simplify
your code by removing special cases for functions such as `Square` and
`Subtract`.
If you were using the JSON serialization directly, you may also be able to
simplify you code since the default output from `expr.json` is now more
consistent and simpler.
- The name of some number formatting options has changed. The number formatting
options are an optional argument of `ce.parse()` and `ce.toLatex()`. See the
`NumberFormat` and `NumberSerializationFormat` types.
- The values +infinity, -infinity and NaN are now represented preferably with
the symbols `PositiveInfinity`, `NegativeInfinity` and `NaN` respectively.
Previously they were represented with numeric values, i.e.
`{num: "+Infinity"}`, `{num: "-Infinity"}` and `{num: "NaN"}`. The numeric
values are still supported, but the symbols are preferred.
- The method `expr.isNothing` has been removed. Instead, use
`expr.symbol === "Nothing"`.
### New Features
- When serializing to LaTeX, the output can be "prettified". This involves
modifying the LaTeX output to make it more pleasant to read, for example:
- `a+\\frac{-b}{c}` -> `a-\\frac{b}{c}`
- `a\\times b^{-1}` -> `\\frac{a}{b}`
- `\\frac{a}{b}\\frac{c}{d}` -> `\\frac{a\\cdot c}{b\\cdot d}`
- `--2` -> `2`
This is on by default and can be turned off by setting the `prettify` option
to `false`. For example:
```js
ce.parse("a+\\frac{-b}{c}").toLatex({prettify: true})
// -> "a-\\frac{b}{c}"
ce.parse("a+\\frac{-b}{c}").toLatex({prettify: false})
// -> "a+\\frac{-b}{c}"
```
- Numbers can have a different digit group length for the whole and fractional
part of a number. For example,
`ce.toLatex(ce.parse("1234.5678"), {digitGroup: [3, 0]})` will return
`1\,234.5678`.
- Numbers can now be formatted using South-East Asian Numbering System, i.e.
lakh and crore. For example:
```js
ce.toLatex(ce.parse("12345678"), {digitGroup: "lakh"})
// -> "1,23,45,678"
```
- Expressions with Integrate functions can now be compiled to JavaScript. The
compiled function can be used to evaluate the integral numerically. For
example:
```js
const f = ce.parse("\\int_0^1 x^2 dx");
const compiled = f.compile();
console.log(compiled()); // -> 0.33232945619482307
```
- **#82** Support for angular units. The default is radians, but degrees can be
used by setting `ce.angularUnit = "deg"`. Other possible values are "grad" and
"turn". This affects how unitless numbers with a trigonometric function are
interpreted. For example, `sin(90)` will return 1 when `ce.angularUnit` is
"deg", 0.8939966636005579 when `ce.angularUnit` is "grad" and 0 when
`ce.angularUnit` is "turn".
- Added `expr.map(fn)` method to apply a function to each subexpression of an
expression. This can be useful to apply custom canonical forms and compare two
expressions.
- An optional canonical form can now be specified with the `ce.function()`.
### Issues Resolved
- **#173** Parsing `1++2` would result in an expression with a `PreIncrement`
function. It is now correctly parsed as `["Add", 1, 2]`.
- **#161** Power expressions would not be processed when their argument was a
Divide expression.
- **#165** More aggressive simplification of expressions with exponent greater
than 3.
- **#169** Calculating a constant integral (and integral that did not depend on
the variable) would result in a runtime error.
- **#164** Negative mixed fractions (e.g. `-1\frac23`) are now parsed correctly.
- **#162** Numeric evaluation of expressions with large exponents could result
in machine precision numbers instead of bignum numbers.
- **#155** The expression
`["Subtract", ["Multiply", 0.5, "x"], ["Divide", "x", 2]]` will now evaluate
to `0`.
- **#154** In some cases, parsing implicit argument of trig function return more
natural results, for example `\cos a \sin b` is now parsed as
`(\cos a)(\sin b)` and not `\cos (a \sin b)`.
- **#147** The associativity of some operators, including `/` was not applied
correctly, resulting in unexpected results. For example, `1/2/3` would be
parsed as `["Divide", 1, ["Divide", 2, 3]]` instead of
`["Divide", ["Divide", 1, 2], 3]`.
- **#146** When parsing an expression like `x(x+1)` where `x` is an undeclared
symbol, do not infer that `x` is a function. Instead, infer that `x` is a
variable and that the expression is a product.
- **#145** The expression `["Or", "False", "False"]`, that is when all the
arguments are `False`, is now evaluates to `False`.
- Fixed canonical form of `e^x^2`, and more generally apply power rule in more
cases.
- Added missing "Sech" and "Csch" functions.
- The digit grouping serializing would place the separator in the wrong place
for some numbers.
- The `avoidExponentsInRange` formating option would not always avoid exponents
in the specified range.
## 0.24.0 _2024-02-23_
### Issues Resolved
- Fix parsing of very deeply nested expressions.
- Correctly apply rules to deeply nested expressions.
- `expr.print()` now correctly prints the expression when using the minified
version of the library.
- `expr.isEqual()` now correctly compares equalities and inequalities.
- `expr.match()` has been improved and works correctly in more cases. The
signature of the `match` function has been changed so that the pattern is the
first argument, i.e. instead of `pattern.match(expr)` use
`expr.match(pattern)`.
- Fix `expr.print()` when using the minified version of the library.
- **#142** Accept complex expressions as the subcript of `\ln` and `\log` in
LaTeX.
- **#139** Parse quantifiers `\forall` and `\exists` in LaTeX.
## 0.23.1 _2024-01-27_
### Issues Resolved
- Using a custom canonical order of `"Multiply"` would not distribute the
`Negate` function.
- **#141** The canonical form `"Order"` was applied to non-commutative
functions.
## 0.23.0 _2024-01-01_
### New Features
- Added `ExpandAll` function to expand an expression recursively.
- Added `Factor` function to factor an expression.
- Added `Together` function to combine rational expressions into a single
fraction.
### Issues Resolved
- The expression `\frac5 7` is now parsed correctly as `\frac{5}{7}` instead of
`\frac{5}{}7`.
- Do not sugar non-canonical expression. Previously,
`ce.parse('\\frac{1}{2}', {canonical: false})` would return `Half` instead of
`['Divide', '1', '2']`.
- **#132** Attempting to set a value to 0 with
`ce.defineSymbol("count", {value: 0})` would fail: the symbol would be
undefined.
- Correctly evaluate power expressions in some cases, for example
`(\sqrt2 + \sqrt2)^2`.
- Comparison of expressions containing non-exact numbers could fail. For
example: `2(13.1+3.1x)` and `26.2+6.2x` would not be considered equal.
### Improvements
- Significant improvements to symbolic computation. Now, boxing,
canonicalization and evaluation are more consistent and produce more
predictable results.
- Adedd the `\neg` command, synonym for `\lnot` -> `Not`.
- Relational expressions (inequalities, etc...) are now properly factored.
- Integers are now factored when simplifying, i.e. `2x = 4x` -> `x = 2x`.
## 0.22.0 _2023-11-13_
### Breaking Changes
- **Rule Syntax**
The syntax to describe rules has changed. The syntax for a rule was previously
a tuple `[lhs, rhs, {condition} ]`. The new syntax is an object with the
properties `match`, `replace` and `condition`. For example:
- previous syntax: `[["Add", "_x", "_x"], ["Multiply", 2, "_x"]]`
- new syntax: `{match: ["Add", "_x", "_x"], replace: ["Multiply", 2, "_x"]}`
The `condition` property is optional, and is either a boxed function or a
JavaScript function. For example, to add a condition that checks that `_x` is
a number literal:
```js
{
match: ["Add", "_x", "_x"],
replace: ["Multiply", 2, "_x"],
condition: ({_x}) => _x.isNumberLiteral
}
```
- **`CanonicalForm`**
The `CanonicalOrder` function has been replaced by the more flexible
`CanonicalForm` function. The `CanonicalForm` function takes an expression and
a list of transformations to apply. To apply the same transformations as
`CanonicalOrder`, use:
```json
['CanonicalForm', expr, 'Order']
```
These canonical forms can also be specified with `box()` and `parse()`
options:
```js
ce.box(expr, { canonical: "Order" });
ce.parse("x^2 + 2x + 1", { canonical: "Order" });
```
### Work In Progress
- Linear algebra functions: `Rank`, `Shape`,`Reshape`, `Flatten`, `Determinant`,
`Trace`, `Transpose`, `ConjugateTranspose`, `Inverse`. See the
[Linear Algebra](/compute-engine/reference/linear-algebra/) reference guide.
Some of these function may not yet return correct result in all cases.
### New Features
- Added a `expr.print()` method as a synonym for `console.log(expr.toString())`.
- Added an `exact` option (false by default) to the `expr.match()` pattern
matching method. When `true` some additional patterns are automatically
recognized, for example, `x` will match `["Multiply", '_a', 'x']` when `exact`
is `false`, but not when `exact` is `true`.
### Improvements
- The equation solver used by `expr.solve()` has been improved and can now solve
more equations.
- The pattern matching engine has been improved and can now match more
expressions, including sequences for commutative functions.
## 0.21.0 _2023-11-02_
### New Features
- **#125** Parse and serialize environemnts, i.e.
`\begin{matrix} 1 & 2 \\ 3 & 4 \end{matrix}` will be parsed as
`["Matrix", ["List", ["List", 1, 2], ["List", 3, 4]]]`.
A new section on
[Linear Algebra](/compute-engine/reference/linear-algebra/#formatting) has
some details on the supported formats.
The linear algebra operations are limited at the moment, but will be expanded
in the future.
- Added `IsSame` function, which is the function expression corresponding to
`expr.isSame()`.
- <s>Added `CanonicalOrder` function, which sorts the arguments of commutative
functions into canonical order. This is useful to compare two non-canonical
expressions for equality.</s>
```js
ce.box(["CanonicalOrder", ["Add", 1, "x"]]).isSame(
ce.box(["CanonicalOrder", ["Add", "x", 1]])
);
// -> true
```
### Issue Resolved
- When evaluating a sum (`\sum`) with a bound that is not a number, return the
sum expression instead of an error.
## 0.20.2 _2023-10-31_
### Issues Resolved
- Fixed numerical evaluation of integrals and limits when parsed from LaTeX.
```js
console.info(ce.parse("\\lim_{x \\to 0} \\frac{\\sin(x)}{x}").value);
// -> 1
console.info(ce.parse("\\int_{0}^{2} x^2 dx").value);
// -> 2.6666666666666665
```
## 0.20.1 _2023-10-31_
### Issues Resolved
- Fixed evaluation of functions with multiple arguments
- Fixed compilation of some function assignments
- Improved serialization of function assignment
## 0.20.0 _2023-10-30_
### Breaking Changes
- **Architectural changes**: the invisible operator is used to represent the
multiplication of two adjacent symbols, i.e. `2x`. It was previously handled
during parsing, but it is now handled during canonicalization. This allows
more complex syntactic structures to be handled correctly, for example
`f(x) := 2x`: previously, the left-hand-side argument would have been parsed
as a function application, while in this case it should be interpreted as a
function definition.
A new `InvisibleOperator` function has been added to support this.
The `applyInvisibleOperator` parsing option has been removed. To support
custom invisible operators, use the `InvisibleOperator` function.
### Issues Resolved
- **#25** Correctly parse chained relational operators, i.e. `a < b <= c`
- **#126** Logic operators only accepted up to two arguments.
- **#127** Correctly compile `Log` with bases other than 10.
- Correctly parse numbers with repeating patterns but no fractional digits, i.e.
`0.(1234)`
- Correctly parse `|1+|a|+2|`
### New Features and Improvements
- Function assignment can now be done with this syntax: `f(x) := 2x+1`. This
syntax is equivalent to `f := x -> 2x+1`.
- Implement the `Mod` and `Congruent` function.
- Correctly parse `11 \bmod 5` (`Mod`) and `26\equiv 11 \pmod5` (`Congruent`)
- Better handle empty argument lists, i.e. `f()`
- When a function is used before being declared, infer that the symbol is a
function, e.g. `f(12)` will infer that `f` is a function (and not a variable
`f` multiplied by 12)
- When a constant is followed by some parentheses, don't assume this is a
function application, e.g. `\pi(3+n)` is now parsed as
`["Multiply", "Pi", ["Add", 3, "n"]]` instead of `["Pi", ["Add", 3, "n"]]`
- Improved parsing of nested lists, sequences and sets.
- Improved error messages when syntax errors are encountered during LaTeX
parsing.
- When parsing with the canonical option set to false, preserve more closely the
original LaTeX syntax.
- When parsing text strings, convert some LaTeX commands to Unicode, including
spacing commands. As a result, `ce.parse("\\text{dead\;beef}_{16}")` correctly
gets evaluated to 3,735,928,559.
## 0.19.1 _2023-10-26_
### Issues Resolved
- Assigning a function to an indentifier works correctly now, i.e.
```js
ce.parse("\\operatorname{f} := x \\mapsto 2x").evaluate();
```
## 0.19.0 _2023-10-25_
### Breaking Changes
- The `domain` property of the function definition `signature` is deprecated and
replaced with the `params`, `optParams`, `restParam` and `result` properties
instead. The `domain` property is still supported for backward compatibility,
but will be removed in a future version.
### Issues Resolved
- When invoking a declared function in a numeric operation, correctly infer the
result type.
```json
["Assign", "f", ["Add", "_", 1]]
["Add", ["f", 1], 1]
// -> 3
```
Previously a domain error was returned, now `f` is inferred to have a numeric
return type.
- Fixed a runtime error when inverting a fraction, i.e. `\frac{3}{4}^{-1}`
- The tangent of π/2 now correctly returns `ComplexInfinity`.
- The exact values of some constructible trigonometric operations (e.g.
`\tan 18\degree = \frac{\sqrt{25-10\sqrt5}}{5}`) returned incorrect results.
The unit test case was incorrect and did not detect the problem. The unit test
case has been fixed and the returned values are now correct.
### New Features
- Implemented `Union` and `Intersection` of collections, for example:
```json
["Intersection", ["List", 3, 5, 7], ["List", 2, 5, 9]]
// -> ["Set", 5]
["Union", ["List", 3, 5, 7], ["List", 2, 5, 9]]
// -> ["Set", 3, 5, 7, 2, 9]
```
- Parse ranges, for example `1..5` or `1, 3..10`. Ranges are collections and can
be used anywhere collections can be used.
- The functions `Sum`, `Product`, `Min`, `Max`, and the statistics functions
(`Mean`, `Median`, `Variance`, etc...) now handle collection arguments:
collections:
- `["Range"]`, `["Interval"]`, `["Linspace"]` expressions
- `["List"]` or `["Set"]` expressions
- `["Tuple"]`, `["Pair"]`, `["Pair"]`, `["Triple"]` expressions
- `["Sequence"]` expressions
- Most mathematical functions are now threadable, that is their arguments can be
collections, for example:
```json
["Sin", ["List", 0, 1, 5]]
// -> ["List", 0, 0.8414709848078965, -0.9589242746631385]
["Add", ["List", 1, 2], ["List", 3, 4]]
// -> ["List", 4, 6]
```
- Added `GCD` and `LCM` functions
```json
["GCD", 10, 5, 15]
// -> 5
["LCM", 10, 5, 15]
// -> 30
```
- Added `Numerator`, `Denominator`, `NumeratorDenominator` functions. These
functions can be used on non-canonical expressions.
- Added `Head` and `Tail` functions which can be used on non-canonical
expressions.
- Added `display-quotient` and `inline-quotient` style for formatting of
division expressions in LaTeX.
### Improvements
- Improved parsing of `\degree` command
```js
ce.parse("30\\degree)
// -> ["Divide", "Pi", 6]
```
- Improved interoperability with JavaScript: `expr.value` will return a
JavaScript primitive (`number`, `boolean`, `string`, etc...) when possible.
This is a more succinct version of `expr.N().valueOf()`.
## 0.18.1 _2023-10-16_
### Issues Resolved
- Parsing of whole numbers while in `rational` mode would return incorrect
results.
- The `ND` function to evaluate derivatives numerically now return correct
values.
```js
ce.parse("\\mathrm{ND}(x \\mapsto 3x^2+5x+7, 2)").N();
// -> 17.000000000001
```
### Improvements
- Speed up `NIntegrate` by temporarily switching the numeric mode to `machine`
while computing the Monte Carlo approximation.
## 0.18.0 _2023-10-16_
### New Features
- Expanded LaTeX dictionary with `\max`, `\min`, `\sup`, `\inf` and `\lim`
functions
- Added `Supremum` and `Infimum` functions
- Compilation of `Block` expressions, local variables, return statements and
conditionals `If`.
- Added numerical evaluation of limits with `Limit` functions and `NLimit`
functions, using a Richardson Extrapolation.
```js
console.info(ce.parse("\\lim_{x\\to0} \\frac{\\sin x}{x}").N().json);
// -> 1
console.info(
ce.box(["NLimit", ["Divide", ["Sin", "_"], "_"], 0]).evaluate().json
);
// -> 1
console.info(ce.parse("\\lim_{x\\to \\infty} \\cos \\frac{1}{x}").N().json);
// -> 1
```
- Added `Assign` and `Declare` functions to assign values to symbols and declare
symbols with a domain.
- `Block` evaluations with local variables work now. For example:
```js
ce.box(["Block", ["Assign", "c", 5], ["Multiply", "c", 2]]).evaluate().json;
// -> 10
```
- When decimal numbers are parsed they are interpreted as inexact numbers by
default, i.e. "1.2" -> `{num: "1.2"}`. To force the number to be interpreted
as a rational number, set `ce.latexOptions.parseNumbers = "rational"`. In that
case, "1.2" -> `["Rational", 12, 10]`, an exact number.
While regular decimals are considered "inexact" numbers (i.e. they are assumed
to be an approximation), rationals are assumed to be exact. In most cases, the
safest thing to do is to consider decimal numbers as inexact to avoid
introducing errors in calculations. If you know that the decimal numbers you
parse are exact, you can use this option to consider them as exact numbers.
### Improvements
- LaTeX parser: empty superscripts are now ignored, e.g. `4^{}` is interpreted
as `4`.
## 0.17.0 _2023-10-12_
### Breaking Changes
- The `Nothing` domain has been renamed to `NothingDomain`
- The `Functions`, `Maybe`, `Sequence`, `Dictionary`, `List` and `Tuple` domain
constructors have been renamed to `FunctionOf`, `OptArg`, `VarArg`,
`DictionaryOf`, `ListOf` and `TupleOf`, respectively.
- Domains no longer require a `["Domain"]` expression wrapper, so for example
`ce.box("Pi").domain` returns `"TranscendentalNumbers"` instead of
`["Domain", "TranscendentalNumbers"]`.
- The `VarArg` domain constructor now indicates the presence of 0 or more
arguments, instead of 1 or more arguments.
- The `MaybeBooleans` domain has been dropped. Use
`["Union", "Booleans", "NothingDomain"]` instead.
- The `ce.defaultDomain` has been dropped. The domain of a symbol is now
determined by the context in which it is used, or by the `ce.assume()` method.
In some circumstances, the domain of a symbol can be `undefined`.
### New Features
- Symbolic derivatives of expressions can be calculated using the `D` function.
For example, `ce.box(["D", ce.parse("x^2 + 3x + 1"), "x"]).evaluate().latex`
returns `"2x + 3"`.
### Improvements
- Some frequently used expressions are now available as predefined constants,
for example `ce.Pi`, `ce.True` and `ce.Numbers`.
- Improved type checking and inference, especially for functions with
complicated or non-numeric signatures.
### Bugs Fixed
- Invoking a function repeatedly would invoke the function in the original scope
rather than using a new scope for each invocation.
## 0.16.0 _2023-09-29_
### Breaking Changes
- The methods `ce.let()` and `ce.set()` have been renamed to `ce.declare()` and
`ce.assign()` respectively.
- The method `ce.assume()` requires a predicate.
- The signatures of `ce.assume()` and `ce.ask()` have been simplified.
- The signature of `ce.pushScope()` has been simplified.
- The `expr.freeVars` property has been renamed to `expr.unknowns`. It returns
the identifiers used in the expression that do not have a value associated
with them. The `expr.freeVariables` property now return the identifiers used
in the expression that are defined outside of the local scope and are not
arguments of the function, if a function.
### New Features
- **Domain Inference** when the domain of a symbol is not set explicitly (for
example with `ce.declare()`), the domain is inferred from the value of the
symbol or from the context of its usage.
- Added `Assume`, `Identity`, `Which`, `Parse`, `N`, `Evaluate`, `Simplify`,
`Domain`.
- Assignments in LaTeX: `x \\coloneq 42` produce `["Assign", "x", 42]`
- Added `ErfInv` (inverse error function)
- Added `Factorial2` (double factorial)
#### Functions
- Functions can now be defined:
- using `ce.assign()` or `ce.declare()`
- evaluating LaTeX: `(x, y) \mapsto x^2 + y^2`
- evaluating MathJSON:
`["Function", ["Add", ["Power", "x", 2], ["Power", "y", 2]]], "x", "y"]`
- Function can be applied using `\operatorname{apply}` or the operators `\rhd`
and `\lhd`:
- `\operatorname{apply}(f, x)`
- `f \rhd x`
- `x \lhd f`
See
[Adding New Definitions](https://cortexjs.io/compute-engine/guides/augmenting/)
and [Functions](https://cortexjs.io/compute-engine/reference/functions/).
#### Control Structures
- Added `FixedPoint`, `Block`, `If`, `Loop`
- Added `Break`, `Continue` and `Return` statements
See
[Control Structures](https://cortexjs.io/compute-engine/reference/control-structures/)
#### Calculus
- Added numeric approximation of derivatives, using an 8-th order centered
difference approximation, with the `ND` function.
- Added numeric approximation of integrals, using a Monte Carlo method with
rebasing for improper integrals, with the `NIntegrate` function
- Added symbolic calculation of derivatives with the `D` function.
#### Collections
Added support for **collections** such as lists, tuples, ranges, etc...
See [Collections](https://cortexjs.io/compute-engine/reference/collections/)
Collections can be used to represent various data structures, such as lists,
vectors, matrixes and more.
They can be iterated, sliced, filtered, mapped, etc...
```json example
["Length", ["List", 19, 23, 5]]
// -> 3
["IsEmpty", ["Range", 1, 10]]
// -> "False"
["Take", ["Linspace", 0, 100, 50], 4]
// -> ["List", 0, 2, 4, 6]
["Map", ["List", 1, 2, 3], ["Function", "x", ["Power", "x", 2]]]
// -> ["List", 1, 4, 9]
["Exclude", ["List", 33, 45, 12, 89, 65], -2, 2]
// -> ["List", 33, 12, 65]
["First", ["List", 33, 45, 12, 89, 65]]
// -> 33
```
### Improvements
- The [documentation](https://cortexjs.io/compute-engine/) has been
significantly rewritten with help from an AI-powered writing assistant.
### Issues Resolved
- The LaTeX string returned in `["Error"]` expression was incorrectly tagged as
`Latex` instead of `LatexString`.
## 0.15.0 _2023-09-14_
### Improvements
- The `ce.serialize()` function now takes an optional `canonical` argument. Set
it to `false` to prevent some transformations that are done to produce more
readable LaTeX, but that may not match exactly the MathJSON. For example, by
default `ce.serialize(["Power", "x", -1])` returns `\frac{1}{x}` while
`ce.serialize(["Power", "x", -1], {canonical: false})` returns `x^{-1}`.
- Improved parsing of delimiters, i.e. `\left(`, `\right]`, etc...
- Added complex functions `Real`, `Imaginary`, `Arg`, `Conjugate`, `AbsArg`. See
[Complex](https://cortexjs.io/compute-engine/reference/complex/)
- Added parsing and evaluation of `\Re`, `\Im`, `\arg`, `^\star` (Conjugate).
- **#104** Added the `["ComplexRoots", x, n]` function which returns the nthroot
of `x`.
- Added parsing and evaluation of statistics functions `Mean`, `Median`,
`StandardDeviation`, `Variance`, `Skewness`, `Kurtosis`, `Quantile`,
`Quartiles`, `InterquartileRange`, `Mode`, `Count`, `Erf`, `Erfc`. See
[Statistics](https://cortexjs.io/compute-engine/reference/statistics/)
## 0.14.0 _2023-09-13_
### Breaking Changes
- The entries in the LaTeX syntax dictionary can now have LaTeX triggers
(`latexTrigger`) or triggers based on identifiers (`symbolTrigger`). The
former replaces the `trigger` property. The latter is new. An entry with a
`triggerIdentifier` of `average` will match `\operatorname{average}`,
`\mathrm{average}` and other variants.
- The `ce.latexOptions` and `ce.jsonSerializationOptions` properties are more
robust. They can be modified directly or one of their properties can be
modified.
### Improvements
- Added more functions and symbols supported by `expr.compile()`:
- `Factorial` postfix operator `5!`
- `Gamma` function `\Gamma(2)`
- `LogGamma` function `\operatorname{LogGamma}(2)`
- `Gcd` function `\operatorname{gcd}(20, 5)`
- `Lcm` function `\operatorname{lcm}(20, 5)`
- `Chop` function `\operatorname{chop}(0.00000000001)`
- `Half` constant `\frac{1}{2}`
- 'MachineEpsilon' constant
- `GoldenRatio` constant
- `CatalanConstant` constant
- `EulerGamma` constant `\gamma`
- `Max` function `\operatorname{max}(1, 2, 3)`
- `Min` function `\operatorname{min}(13, 5, 7)`
- Relational operators: `Less`, `Greater`, `LessEqual`, `GreaterEqual`,
'Equal', 'NotEqual'
- Some logical operators and constants: `And`, `Or`, `Not`, `True`, `False`
- More complex identifiers syntax are recognized, including `\mathbin{}`,
`\mathord{}`, etc... `\operatorname{}` is the recommended syntax, though: it
will display the identifier in upright font and with the propert spacing, and
is properly enclosing. Some commands, such as `\mathrm{}` are not properly
enclosing: two adjacent `\mathrm{}` command could be merged into one.
- Environments are now parsed and serialized correctly.
- When parsing LaTeX, function application is properly handled in more cases,
including custom functions, e.g. `f(x)`
- When parsing LaTeX, multiple arguments are properly handled, e.g. `f(x, y)`
- Add LaTeX syntax for logical operators:
- `And`: `\land`, `\operatorname{and}` (infix or function)
- `Or`: `\lor`, `\operatorname{or}` (infix or function)
- `Not`: `\lnot`, `\operatorname{not}` (prefix or function)
- `Xor`: `\veebar` (infix)
- `Nand`: `\barwedge` (infix)
- `Nor`: `^^^^22BD` (infix)
- `Implies`: `\implies` (infix)
- `Equivalent`: `\iff` (infix)
- When a postfix operator is defined in the LaTeX syntax dictionary of the form
`^` plus a single token, a definition with braces is added automatically so
that both forms will be recognized.
- Extended the LaTeX dictionary with:
- `floor`
- `ceil`
- `round`
- `sgn`
- `exp`
- `abs`
- `gcd`
- `lcm`
- `apply`
- Properly handle inverse and derivate notations, e.g. `\sin^{-1}(x)`,
`\sin'(x)`, `\cos''(x)`, \cos^{(4)}(x)`or even`\sin^{-1}''(x)`
## 0.13.0 _2023-09-09_
### New Features
- **Compilation** Some expressions can be compiled to Javascript. This is useful
to evaluate an expression many times, for example in a loop. The compiled
expression is faster to evaluate than the original expression. To get the
compiled expression, use `expr.compile()`. Read more at
[Compiling](https://cortexjs.io/compute-engine/guides/compiling)
### Issues Resolved and Improvements
- Fixed parsing and serialization of extended LaTeX synonyms for `e` and `i`.
- Fixed serialization of `Half`.
- Fixed serialization of `Which`
- Improved serialization of `["Delimiter"]` expressions.
## 0.12.7 _2023-09-08_
### Improvements
- Made customization of the LaTeX dictionary simpler. The `ce.latexDictionary`
property can be used to access and modify the dictionary. The
[documentation](https://cortexjs.io/compute-engine/guides/latex-syntax/#customizing-the-latex-dictionary)
has been updated.
## 0.12.6 _2023-09-08_
### Breaking Changes
- New API for the `Parser` class.
### Improvements and Bux Fixes
- The `ComputeEngine` now exports the `bignum()` and `complex()` methods that
can be used to create bignum and complex numbers from strings or numbers. The
methods `isBigNum()` and `isComplex()` have also been added to check if a
value is a bignum (`Decimal`) or complex (`Complex`) number, for example as
returned by `expr.numericValue`.
- **#69** `\leq` was incorrectly parsed as `Equals` instead of `LessEqual`
- **#94** The `\exp` command was not parsed correctly.
- Handle `PlusMinus` in infix and prefix position, i.e. `a\pm b` and `\pm a`.
- Improved parsing, serialization
- Improved simplification
- Improved evaluation of `Sum` and `Product`
- Support complex identifiers (i.e. non-latin scripts, emojis).
- Fixed serialization of mixed numbers.
## 0.12.1 _2022-12-01_
Work around unpckg.com issue with libraries using BigInt.
## 0.12.0 _2022-11-27_
### Breaking Changes
- The `expr.symbols` property return an array of `string`. Previously it
returned an array of `BoxedExpression`.
### Improvements
- Rewrote the rational computation engine to use JavaScript `bigint` instead of
`Decimal` instances. Performance improvements of up to 100x.
- `expr.freeVars` provides the free variables in an expression.
- Improved performance of prime factorization of big num by x100.
- Added `["RandomExpression"]`
- Improved accuracy of some operations, for example
`expr.parse("1e999 + 1").simplify()`
### Issues Resolved
- When `ce.numericMode === "auto"`, square roots of negative numbers would
return an expression instead of a complex number.
- The formatting of LaTeX numbers when using
`ce.latexOptions.notation = "engineering"` or `"scientific"` was incorrect.
- The trig functions no longer "simplify" to the less simple exponential
formulas.
- The canonical order of polynomials now orders non-lexicographic terms of
degree 1 last, i.e. "ax^2+ bx+ c" instead of "x + ax^2 + bx".
- Fixed evaluation of inverse functions
- Fixed `expr.isLess`, `expr.isGreater`, `expr.isLessEqual`,
`expr.isGreaterEqual` and `["Min"]`, `["Max"]`
## 0.11.0 _2022-11-18_
### Breaking Changes
- The signature of `ce.defineSymbol()`, `ce.defineFunction()` and
`ce.pushScope()` have changed
### Improvements
- When a constant should be held or substituted with its value can now be more
precisely controlled. The `hold` symbol attribute is now `holdUntil` and can
specify at which stage the substitution should take place.
### Issues Resolved
- Some constants would return a value as bignum or complex even when the
`numericMode` did not allow it.
- Changing the value or domain of a symbol is now correctly taken into account.
Changes can be made with `ce.assume()`, `ce.set()` or `expr.value`.
- When a symbol does not have a value associated with it, assumptions about it
(e.g. "x > 0") are now correctly tracked and reflected.
## 0.10.0 _2022-11-17_
### Breaking Changes
- `expr.isLiteral` has been removed. Use `expr.numericValue !== null` and
`expr.string !== null` instead.
### Issues Resolved
- Calling `ce.forget()` would not affect expressions that previously referenced
the symbol.
### Improvements
- More accurate calculations of some trig functions when using bignums.
- Improved performance when changing a value with `ce.set()`. Up to 10x faster
when evaluating a simple polynomial in a loop.
- `ce.strict` can be set to `false` to bypass some domain and validity checks.
## 0.9.0 _2022-11-15_
### Breaking Changes
- The head of a number expression is always `Number`. Use `expr.domain` to be
get more specific info about what kind of number this is.
- By default, `ce.box()` and `ce.parse()` return a canonical expression. A flag
can be used if a non-canonical expression is desired.
- The API surface of `BoxedExpression` has been reduced. The properties
`machineValue`, `bignumValue`, `asFloat`, `asSmallInteger`, `asRational`
etc... have been replaced with a single `numericValue` property.
- `parseUnknownSymbol` is now `parseUnknownIdentifier`
### Improvements
- Support angles in degrees with `30\degree`, `30^\circ` and `\ang{30}`.
- More accurate error expressions, for example if there is a missing closing
delimiter an `["Error", ["ErrorCode", "'expected-closing-delimiter'", "')'"]]`
is produced.
- `["Expand"]` handles more cases
- The trig functions can now have a regular exponent, i.e.`\cos^2(x)` in
addition to `-1` for inverse, and a combination of `\prime`, `\doubleprime`
and `'` for derivatives.
- `ce.assume()` handle more expressions and can be used to define new symbols by
domain or value.
- Better error message when parsing, e.g. `\sqrt(2)` (instead of `\sqrt{2}`)
- Better simplification for square root expressions:
- `\sqrt{25x^2}` -> `5x`
- Improved evaluation of `["Power"]` expressions, including for negative
arguments and non-integer exponents and complex arguments and exponents.
- Added `Arccot`, `Arcoth`, `Arcsch`, `Arcscc`, `Arsech` and `Arccsc`
- `expr.solve()` returns result for polynomials of order up to 2.
- The `pattern.match()` function now work correctly for commutative functions,
i.e. `ce.pattern(['Add', '_a', 'x']).match(ce.parse('x+y')) -> {"_a": "y"}`
- Added `ce.let()` and `ce.set()` to declare and assign values to identifiers.
- Preserve exact calculations involving rationals or square root of rationals.
- `\sqrt{\frac{49}{25}}` -> `\frac{7}{5}`
- Addition and multiplication provide more consistent results for `evaluate()`
and `N()`. Evaluate returns an exact result when possible.
- EXACT
- 2 + 5 -> 7
- 2 + 5/7 -> 19/7
- 2 + √2 -> 2 + √2
- 2 + √(5/7) -> 2 + √(5/7)
- 5/7 + 9/11 -> 118/77
- 5/7 + √2 -> 5/7 + √2
- 10/14 + √(18/9) -> 5/7 + √2
- √2 + √5 -> √2 + √5
- √2 + √2 -> 2√2
- sin(2) -> sin(2)
- sin(π/3) -> √3/2
- APPROXIMATE
- 2 + 2.1 -> 4.1
- 2 + √2.1 -> 3.44914
- 5/7 + √2.1 -> 2.16342
- sin(2) + √2.1 -> 2.35844
- More consistent behavior of the `auto` numeric mode: calculations are done
with `bignum` and `complex` in most cases.
- `JsonSerializationOptions` has a new option to specify the numeric precision
in the MathJSON serialization.
- Shorthand numbers can now be strings if they do not fit in a float-64:
```json example
// Before
["Rational", { "num": "1234567890123456789"}, { "num": "2345678901234567889"}]
// Now
["Rational", "1234567890123456789", "2345678901234567889"]
```
- `\sum` is now correctly parsed and evaluated. This includes creating a local
scope with the index and expression value of the sum.
### Bugs Fixed
- The parsing and evaluation of log functions could produce unexpected results
- The `\gamma` command now correctly maps to `["Gamma"]`
- Fixed numeric evaluation of the `["Gamma"]` function when using bignum
- **#57** Substituting `0` (i.e. with `expr.subs({})`) did not work.
- **#60** Correctly parse multi-char symbols with underscore, i.e.
`\mathrm{V_a}`
- Parsing a number with repeating decimals and an exponent would drop the
exponent.
- Correct calculation of complex square roots
- `\sqrt{-49}` -> `7i`
- Calculations were not always performed as bignum in `"auto"` numeric mode if
the precision was less than 15. Now, if the numeric mode is `"auto"`,
calculations are done as bignum or complex numbers.
- If an identifier contained multiple strings of digits, it would not be
rendered to LaTeX correctly, e.g. `V20_20`.
- Correctly return `isReal` for real numbers
## 0.8.0 _2022-10-02_
### Breaking Changes
- Corrected the implementation of `expr.toJSON()`, `expr.valueOf()` and added
the esoteric `[Symbol.toPrimitive]()` method. These are used by JavaScript
when interacting with other primitive types. A major change is that
`expr.toJSON()` now returns an `Expression` as an object literal, and not a
string serialization of the `Expression`.
- Changed from "decimal" to "bignum". "Decimal" is a confusing name, since it is
used to represent both integers and floating point numbers. Its key
characteristic is that it is an arbitrary precision number, aka "bignum". This
affects `ce.numericMode` which now uses `bignum` instead of
`decimal', `expr.decimalValue`->`expr.bignumValue`, `decimalValue()`-> `bignumValue()`
### Bugs Fixed
- Numerical evaluation of expressions containing complex numbers when in
`decimal` or `auto` mode produced incorrect results. Example: `e^{i\\pi}`
## 0.7.0 _2022-09-30_
### Breaking Changes
- The `ce.latexOptions.preserveLatex` default value is now `false`
- The first argument of the `["Error"]` expression (default value) has been
dropped. The first argument is now an error code, either as a string or an
`["ErrorCode"]` expression.
### Features
- Much improved LaTeX parser, in particular when parsing invalid LaTeX. The
parser now avoids throwing, but will return a partial expression with
`["Error"]` subexpressions indicating where the problems were.
- Implemented new domain computation system (similar to type systems in
programming languages)
- Added support for multiple signatures per function (ad-hoc polymorphism)
- Added `FixedPoint`, `Loop`, `Product`, `Sum`, `Break`, `Continue`, `Block`,
`If`, `Let`, `Set`, `Function`, `Apply`, `Return`
- Added `Min`, `Max`, `Clamp`
- Parsing of `\sum`, `\prod`, `\int`.
- Added parsing of log functions, `\lb`, `\ln`, `\ln_{10}`, `\ln_2`, etc...
- Added
`expr.`subexpressions`, `expr.getSubexpressions()`, `expr.errors`, `expr.symbols`, `expr.isValid`.
- Symbols can now be used to represent functions, i.e. `ce.box('Sin').domain`
correctly returns `["Domain", "Function"]`.
- Correctly handle rational numbers with a numerator or denominator outside the
range of a 64-bit float.
- Instead of a `Missing` symbol an `["Error", "'missing'"]` expression is used.
- Name binding is now done lazily
- Correctly handle MathJSON numbers with repeating decimals, e.g. `1.(3)`.
- Correctly evaluate inverse functions, e.g. `ce.parse('\\sin^{-1}(.5)).N()`
- Fixed some LaTeX serialization issues
Read more at
[Core Reference](https://cortexjs.io/compute-engine/reference/core/) and
[Arithmetic Reference]
(https://cortexjs.io/compute-engine/reference/arithmetic/)
### Bugs Fixed
- **#43** If the input of `ce.parse()` is an empty string, return an empty
string for `expr.latex` or `expr.json.latex`: that is, ensure verbatim LaTeX
round-tripping
- Evaluating some functions, such as `\arccos` would result in a crash
- Correctly handle parsing of multi-token decimal markers, e.g. `{,}`
## 0.6.0 _2022-04-18_
### Improvements
- Parse more cases of tabular environments
- Handle simplify and evaluate of inert functions by default
- Avoid unnecessary wrapping of functions when serializing LaTeX
- Parse arguments of LaTeX commands (e.g. `\vec{}`)
- **#42** Export static `ComputeEngine.getLatexDictionary`
- Parse multi-character constants and variables, e.g. `\mathit{speed}` and
`\mathrm{radius}`
- Parse/serialize some LaTeX styling commands: `\displaystyle`, `\tiny` and more
## 0.5.0 _2022-04-05_
### Improvements
- Correctly parse tabular content (for example in
`\begin{pmatrix}...\end{pmatrix}`
- Correctly parse LaTeX groups, i.e. `{...}`
- Ensure constructible trigonometric values are canonical
- Correct and simplify evaluation loop for `simplify()`, `evaluate()` and `N()`.
- **#41** Preserve the parsed LaTeX verbatim for top-level expressions
- **#40** Correctly calculate the synthetic LaTeX metadata for numbers
- Only require Node LTS (16.14.2)
- Improved documentation, including Dark Mode support
## 0.4.4
**Release Date**: 2022-03-27
### Improvements
- Added option to specify custom LaTeX dictionaries in `ComputeEngine`
constructor
- `expr.valueOf` returns rational numbers as `[number, number]` when applicable
- The non-ESM builds (`compute-engine.min.js`) now targets vintage JavaScript
for improved compatibility with outdated toolchains (e.g. Webpack 4) and
environments. The ESM build (`compute-engine.min.esm.js`) targets evergreen
JavaScript (currently ECMAScript 2020).
## 0.4.3
**Release Date**: 2022-03-21
### Transition Guide from 0.4.2
The API has changed substantially between 0.4.2 and 0.4.3, however adapting code
to the new API is very straightforward.
The two major changes are the introduction of the `BoxedExpression` class and
the removal of top level functions.
### Boxed Expression
The `BoxedExpression` class is a immutable box (wrapper) that encapsulates a
MathJSON `Expression`. It provides some member functions that can be used to
manipulate the expression, for example `expr.simplify()` or `expr.evaluate()`.
The boxed expresson itself is immutable. For example, calling `expr.simplify()`
will return a new, simplified, expression, without modifying `expr`.
To create a "boxed" expression from a "raw" MathJSON expression, use `ce.box()`.
To create a boxed expression from a LaTeX string, use `ce.parse()`.
To access the "raw" MathJSON expression, use the `expr.json` property. To
serialize the expression to LaTeX, use the `expr.latex` property.
The top level functions such as `parse()` and `evaluate()` are now member
functions of the `ComputeEngine` class or the `BoxedExpression` class.
There are additional member functions to examine the content of a boxed
expression. For example, `expr.symbol` will return `null` if the expression is
not a MathJSON symbol, otherwise it will return the name of the symbol as a
string. Similarly, `expr.ops` return the arguments (operands) of a function,
`expr.asFloat` return `null` if the expression does not have a numeric value
that can be represented by a float, a `number` otherwise, etc...
### Canonical Form
Use `expr.canonical` to obtain the canonical form of an expression rather than
the `ce.format()` method.
The canonical form is less aggressive in its attempt to simplify than what was
performed by `ce.format()`.
The canonical form still accounts for distributive and associative functions,
and will collapse some integer constants. However, in some cases it may be
necessary to invoke `expr.simplify()` in order to get the same results as
`ce.format(expr)`.
### Rational and Division
In addition to machine floating points, arbitrary precision numbers and complex
numbers, the Compute Engine now also recognize and process rational numbers.
This is mostly an implementation detail, although you may see
`["Rational", 3, 4]`, for example, in the value of a `expr.json` property.
If you do not want rational numbers represented in the value of the `.json`
property, you can exclude the `Rational` function from the serialization of JSON
(see below) in which case `Divide` will be used instead.
Note also that internally (as a result of boxing), `Divide` is represented as a
product of a power with a negative exponent. This makes some pattern detection
and simplifications easier. However, when the `.json` property is accessed,
product of powers with a negative exponents are converted to a `Divide`, unless
you have included `Divide` as an excluded function for serialization.
Similarly, `Subtract` is converted internally to `Add`, but may be serialized
unless excluded.
### Parsing and Serialization Customization
Rather than using a separate instance of the `LatexSyntax` class to customize
the parsing or serialization, use a `ComputeEngine` instance and its
`ce.parse()` method and the `expr.latex` property.
Custom dictionaries (to parse/serialize custom LaTeX syntax) can be passed as an
argument to the `ComputeEngine` constructor.
For more advanced customizations, use `ce.latexOptions = {...}`. For example, to
change the formatting options of numbers, how the invisible operator is
interpreted, how unknown commands and symbols are interpreted, etc...
Note that there are also now options available for the "serialization" to
MathJSON, i.e. when the `expr.json` property is used. It is possible to control
for example if metadata should be included, if shorthand forms are allowed, or
whether some functions should be avoided (`Divide`, `Sqrt`, `Subtract`, etc...).
These options can be set using `ce.jsonSerializationOptions = {...}`.
### Comparing Expressions
There are more options to compare two expressions.
Previously, `match()` could be used to check if one expression matched another
as a pattern.
If `match()` returned `null`, the first expression could not be matched to the
second. If it returned an object literal, the two expressions matched.
The top-level `match()` function is replaced by the `expr.match()` method.
However, there are two other options that may offer better results:
- `expr.isSame(otherExpr)` return true if `expr` and `otherExpr` are
structurally identical. Structural identity is closely related to the concept
of pattern matching, that is `["Add", 1, "x"]` and `["Add", "x", 1]` are not
the same, since the order of the arguments is different. It is useful for
example to compare some input to an answer that is expected to have a specific
form.
- `expr.isEqual(otherExpr)` return true if `expr` and `otherExpr` are
mathematically identical. For example `ce.parse("1+1").isEqual(ce.parse("2"))`
will return true. This is useful if the specific structure of the expression
is not important.
It is also possible to evaluate a boolean expression with a relational operator,
such as `Equal`:
```ts
console.log(ce.box(["Equal", expr, 2]).evaluate().symbol);
// -> "True"
console.log(expr.isEqual(ce.box(2)));
// -> true
```
### Before / After
| Before | After |
| :---------------------------------------- | :--------------------------------------- |
| `expr = ["Add", 1, 2]` | `expr = ce.box(["Add", 1, 2])` |
| `expr = ce.evaluate(expr)` | `expr = expr.evaluate()` |
| `console.log(expr)` | `console.log(expr.json)` |
| `expr = new LatexSyntax().parse("x^2+1")` | `expr = ce.parse("x^2+1")` |
| `new LatexSyntax().serialize(expr)` | `expr.latex` |
| `ce.simplify(expr)` | `expr.simplify()` |
| `await ce.evaluate(expr)` | `expr.evaluate()` |
| `ce.N(expr)` | `expr.N()` |
| `ce.domain(expr)` | `expr.domain` |
| `ce.format(expr...)` | `expr.canonical` <br/> `expr.simplify()` |
## 0.3.0
**Release Date**: 2021-06-18
### Improvements
- In LaTeX, parse `\operatorname{foo}` as the MathJSON symbol `"foo"`.