Cortex Compute Engine
Symbolic manipulation and numeric evaluation of MathJSON expressions
MathJSON is a lightweight mathematical
notation interchange format based on JSON.
The Cortex Compute Engine can parse LaTeX to MathJSON, serialize MathJSON to
LaTeX or MathASCII, format, simplify and evaluate MathJSON expressions.
Reference documentation and guides at
cortexjs.io/compute-engine.

Using Compute Engine
$ npm install --save @cortex-js/compute-engine
import { ComputeEngine } from "@cortex-js/compute-engine";
const ce = new ComputeEngine();
ce.parse("2^{11}-1 \\in \\Z").evaluate().print()
FAQ
Q How do I build the project?
Build instructions
Related Projects
- MathJSON
- A lightweight mathematical notation interchange format
- MathLive (on GitHub)
- A Web Component for math input.
- Cortex (on GitHub)
- A programming language for scientific computing
Support the Project
License
This project is licensed under the MIT License.
0.30.2 2025-07-15
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 the
expr.value
property to get the value of an expression, you should now use
the expr.N().valueOf()
method instead. The valueOf()
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 accepted
ce.assign("f(x, y)", ce.parse("x+y"))
. This is now deprecated. Use
ce.assign("f", ce.parse("(x, y) \\mapsto x+y")
instead.
-
It was previously possible to invoke expr.evaluate()
or expr.N()
on a
non-canonical expression. This will now return the expression itself.
To evaluate a non-canonical expression, use expr.canonical.evaluate()
or
expr.canonical.N()
.
That's also the case for the methods numeratorDenominator()
, numerator()
,
and denominator()
.
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
-
Collections now support lazy materialization. This means that the elements of
some collection are not computed until they are needed. This can significantly
improve performance when working with large collections, and allow working
with infinite collections. For example:
ce.box(['Map', 'Integers', 'Square']).evaluate().print();
// -> [0, 1, 4, 9, 16, ...]
Materialization can be controlled with the materialization
option of the
evaluate()
method. Lazy collections are materialized by default when
converted to a string or LaTeX, or when assigned to a variable.
-
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.
-
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.
-
Added Number Theory functions: Totient
, Sigma0
, Sigma1
,
SigmaMinus1
, IsPerfect
, Eulerian
, Stirling
, NPartition
,
IsTriangular
, IsSquare
, IsOctahedral
, IsCenteredSquare
, IsHappy
,
IsAbundant
.
-
Added Combinatorics functions: Choose
, Fibonacci
, Binomial
,
CartesianProduct
, PowerSet
, Permutations
, Combinations
, Multinomial
,
Subfactorial
and BellNumber
.
-
The symbol
type can be refined to match a specific symbol. For example
symbol<True>
. The type expression
can be refined to match expressions with
a specific operator, for example expression<Add>
is a type that matches
expressions with the Add
operator. The numeric types can be refined with a
lower and upper bound. For example integer<0..10>
is a type that matches
integers between 0 and 10. The type real<1..>
matches real numbers greater
than 1 and rational<..0>
matches non-positive rational numbers.
-
Numeric types can now be constrained with a lower and upper bound. For
example, real<0..10>
is a type that matches real numbers between 0 and 10.
The type integer<1..>
matches integers greater than or equal to 1.
-
Collections that can be indexed (list
, tuple
) are now a subtype of
indexed_collection
.
-
The map
type has been replaced with dictionary
for collections of
arbitrary key-value pairs and record
for collections of structured key-value
pairs.
-
Support for structural typing has been added. To define a structural type, use
ce.declareType()
with the alias
flag, for example:
ce.declareType(
"point", "tuple<x: integer, y: integer>",
{ alias: true }
);
-
Recursive types are now supported by using the type
keyword to forward
reference types. For example, to define a type for a binary tree:
ce.declareType(
"binary_tree",
"tuple<value: integer, left: type binary_tree?, right: type binary_tree?>",
);
-
The syntax for variadic arguments has changeed. To indicate a variadic
argument, use a +
or *
after the type, for example:
ce.declare('f', '(number+) -> number');
Use +
for a non-empty list of arguments and *
for a possibly empty list.
-
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, but x^y
(where y===0
), or x^{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)