CortexJS Compute Engine Changelog

[Unreleased]

Breaking Changes

  • The ce.latexOptions.preserveLatex default value is now false

Bug 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

Release Date: 2022-04-18

Improvements

  • Parse more cases of tabular environments
  • Handle simplify and evaluate of inert functions by default
  • Avoid unnecessary wrapping of functins 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

Release Date: 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, simplfied, 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, arbitrarily long decimal numbers and complex number, 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:

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.evaluatate(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
expr.simplify()

0.3.0

Release Date: 2021-06-18

Improvements

  • In LaTeX, parse \operatorname{foo} as the MathJSON symbol "foo".