Skip to main content

Compute Engine API Reference

Compute Engine

AngularUnit

type AngularUnit = "rad" | "deg" | "grad" | "turn";

When a unitless value is passed to or returned from a trigonometric function, the angular unit of the value.

  • rad: radians, 2π radians is a full circle
  • deg: degrees, 360 degrees is a full circle
  • grad: gradians, 400 gradians is a full circle
  • turn: turns, 1 turn is a full circle

AssignValue

type AssignValue = 
| boolean
| number
| bigint
| SemiBoxedExpression
| (args, options) => BoxedExpression
| undefined;

EvalContext

type EvalContext = {
lexicalScope: Scope;
assumptions: ExpressionMapInterface<boolean>;
values: Record<string, BoxedExpression | undefined>;
name: undefined | string;
};

An evaluation context is a set of bindings mapping symbols to their values. It also includes a reference to the lexical scope of the context, as well as a set of assumptions about the values of the symbols.

Eval contexts are arranged in a stack structure. When a new context is created, it is pushed on the top of the stack.

A new eval context is created when a function expression that needs to track its own local variables and named arguments is evaluated. This kind of function is a "scoped" function, meaning that it has its own local variables and named arguments.

For example, the Sum function creates a new eval context to track the local variable used as the index of the sum.

The eval context stack is used to resolve the value of symbols.

When a scoped recursive function is called, a new context is created for each recursive call.

In contrast, the lexical scope is used to resolve the metadata about symbols, such as their type, whether they are constant, etc... A new scope is not created for recursive calls, since the metadata does not change, only the values of the symbols change.

The name of the eval context is used to print a "stack trace" for debugging.

Boxed Expression

BoxedExpression

THEORY OF OPERATIONS

The BoxedExpression interface includes the methods and properties applicable to all kinds of expression. For example it includes expr.symbol which only applies to symbols or expr.ops which only applies to function expressions.

When a property is not applicable to this BoxedExpression its value is null. For example expr.symbol for a BoxedNumber is null.

This convention makes it convenient to manipulate expressions without having to check what kind of instance they are before manipulating them.

THEORY OF OPERATIONS

A boxed expression can represent a canonical or a non-canonical expression. A non-canonical expression is a "raw" form of the expression. For example, the non-canonical representation of \frac{10}{20} is ["Divide", 10, 20]. The canonical representation of the same expression is the boxed number 1/2.

The canonical representation of symbols and function expressions are bound to a definition. The definition contains metadata about the symbol or function operator, such as its type, its signature, and other attributes. The value of symbols are tracked in a separate table for each evaluation context.

The binding only occurs when the expression is constructed, if it is created as a canonical expression. If the expression is constructed as a non-canonical expression, no binding is done.

THEORY OF OPERATIONS

The value of an expression is a number, a string, a boolean or a tensor.

The value of number literals and strings are themselves.

A symbol can have a value associated with it, in which case the value of the symbol is the value associated with it.

Some symbols (unknowns) are purely symbolic and have no value associated with them.

Function expressions do not have a value associated with them. For example, ["Add", 2, 3] has no value associated with it, it is a symbolic expression.

Some properties of a Boxed Expression are only applicable if the expression has a value associated with it. For example, expr.isNumber is only applicable if the value of the expression is a number, that is if the expression is a number literal or a symbol with a numeric value.

The following properties are applicable to expressions with a value:

  • expr.isNumber

To create a boxed expression:

ce.box() and ce.parse()

Use ce.box() or ce.parse().

Use ce.parse() to get a boxed expression from a LaTeX string. Use ce.box() to get a boxed expression from a MathJSON expression.

By default, the result of these methods is a canonical expression. For example, if it is a rational literal, it is reduced to its canonical form. If it is a function expression:

  • the arguments are put in canonical form
  • the arguments of commutative functions are sorted
  • invisible operators are made explicit
  • a limited number of core simplifications are applied, for example rationals are reduced
  • sequences are flattened: ["Add", 1, ["Sequence", 2, 3]] is transformed to ["Add", 1, 2, 3]
  • associative functions are flattened: ["Add", 1, ["Add", 2, 3]] is transformed to ["Add", 1, 2, 3]
  • symbols are not replaced with their values (unless they have a holdUntil flag set to never).

ce.function()

This is a specialized version of ce.box() for creating a new function expression.

The canonical handler of the operator is called.

Algebraic methods (expr.add(), expr.mul(), etc...)

The boxed expression have some algebraic methods, i.e. add(), mul(), div(), pow(), etc. These methods are suitable for internal calculations, although they may be used as part of the public API as well.

  • a runtime error is thrown if the expression is not canonical
  • the arguments are not evaluated
  • the canonical handler (of the corresponding operation) is not called
  • some additional simplifications over canonicalization are applied. For example number literals are combined. However, the result is exact, and no approximation is made. Use .N() to get an approximate value. This is equivalent to calling simplify() on the expression (but without simplifying the arguments).
  • sequences were already flattened as part of the canonicalization process

For 'add()' and 'mul()', which take multiple arguments, separate functions are provided that take an array of arguments. They are equivalent to calling the boxed algebraic method, i.e. ce.Zero.add(1, 2, 3) and add(1, 2, 3) are equivalent.

These methods are not equivalent to calling expr.evaluate() on the expression: evaluate will replace symbols with their values, and evaluate the expression.

For algebraic functions (add(), mul(), etc..), use the corresponding canonicalization function, i.e. canonicalAdd(a, b) instead of ce.function('Add', [a, b]).

Another option is to use the algebraic methods directly, i.e. a.add(b) instead of ce.function('Add', [a, b]). However, the algebraic methods will apply further simplifications which may or may not be desirable. For example, number literals will be combined.

ce._fn()

This method is a low level method to create a new function expression which is typically invoked in the canonical handler of an operator definition.

The arguments are not modified. The expression is not put in canonical form. The canonical handler is not called.

A canonical flag can be set when calling this method, but it only asserts that the function expression is canonical. The caller is responsible for ensuring that is the case.

Canonical Handlers

Canonical handlers are responsible for:

  • validating the signature: this can involve checking the number of arguments. It is recommended to avoid checking the type of non-literal arguments, since the type of symbols or function expressions may change. Similarly, the canonicalization process should not rely on the value of or assumptions about non-literal arguments.
  • flattening sequences
  • flattening arguments if the function is associative
  • sort the arguments (if the function is commutative)
  • calling ce._fn() to create a new function expression

When the canonical handler is invoked, the arguments have been put in canonical form unless the lazy flag is set to true.

Note that the result of a canonical handler should be a canonical expression, but not all arguments need to be canonical. For example, the arguments of ["Declare", "x", 2] are not canonical, since x refers to the name of the symbol, not its value.

Function Expression

BoxedExpression.isFunctionExpression
readonly isFunctionExpression: boolean;

Return true if this expression is a function expression.

If true, expr.ops is not null, and expr.operator is the name of the function.

BoxedExpression.operator
readonly operator: string;

The name of the operator of the expression.

For example, the name of the operator of ["Add", 2, 3] is "Add".

A string literal has a "String" operator.

A symbol has a "Symbol" operator.

A number has a "Number", "Real", "Rational" or "Integer" operator; amongst some others. Practically speaking, for fully canonical and valid expressions, all of these are likely to collapse to "Number".

BoxedExpression.ops
readonly ops: readonly BoxedExpression[];

The list of operands of the function.

If the expression is not a function, return null.

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.nops
readonly nops: number;

If this expression is a function, the number of operands, otherwise 0.

Note that a function can have 0 operands, so to check if this expression is a function, check if this.ops !== null instead.

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.op1
readonly op1: BoxedExpression;

First operand, i.e.this.ops[0].

If there is no first operand, return the symbol Nothing.

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.op2
readonly op2: BoxedExpression;

Second operand, i.e.this.ops[1]

If there is no second operand, return the symbol Nothing.

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.op3
readonly op3: BoxedExpression;

Third operand, i.e. this.ops[2]

If there is no third operand, return the symbol Nothing.

Note

Applicable to canonical and non-canonical expressions.

Numeric Expression

BoxedExpression.isNumberLiteral
readonly isNumberLiteral: boolean;

Return true if this expression is a number literal, for example 2, 3.14, 1/2, √2 etc.

When true, expr.numericValue is not null.

BoxedExpression.numericValue
readonly numericValue: number | NumericValue;

Return the value of this expression, if a number literal.

Note it is possible for expr.numericValue to be null, and for expr.isNotZero to be true. For example, when a symbol has been defined with an assumption.

Conversely, expr.isNumber may be true even if expr.numericValue is null, for example the symbol Pi return true for isNumber but expr.numericValue is null (it's a symbol, not a number literal). Its value can be accessed with expr.value.

To check if an expression is a number literal, use expr.isNumberLiteral. If expr.isNumberLiteral is true, expr.numericValue is not null.

BoxedExpression.isEven
readonly isEven: boolean;

If the value of this expression is not an integer return undefined.

BoxedExpression.isOdd
readonly isOdd: boolean;

If the value of this expression is not an integer return undefined.

BoxedExpression.re
readonly re: number;

Return the real part of the value of this expression, if a number.

Otherwise, return NaN (not a number).

BoxedExpression.im
readonly im: number;

If value of this expression is a number, return the imaginary part of the value. If the value is a real number, the imaginary part is 0.

Otherwise, return NaN (not a number).

BoxedExpression.bignumRe
readonly bignumRe: Decimal;

If the value of this expression is a number, return the real part of the value as a BigNum.

If the value is not available as a bignum return undefined. That is, the value is not upconverted to a bignum.

To get the real value either as a bignum or a number, use expr.bignumRe ?? expr.re.

When using this pattern, the value is returned as a bignum if available, otherwise as a number or NaN if the value is not a number.

BoxedExpression.bignumIm
readonly bignumIm: Decimal;

If the value of this expression is a number, return the imaginary part as a BigNum.

It may be 0 if the number is real.

If the value of the expression is not a number or the value is not available as a bignum return undefined. That is, the value is not upconverted to a bignum.

To get the imaginary value either as a bignum or a number, use expr.bignumIm ?? expr.im.

When using this pattern, the value is returned as a bignum if available, otherwise as a number or NaN if the value is not a number.

BoxedExpression.sgn
readonly sgn: Sign;

Return the sign of the expression.

Note that complex numbers have no natural ordering, so if the value is an imaginary number (a complex number with a non-zero imaginary part), this.sgn will return unsigned.

If a symbol, this does take assumptions into account, that is this.sgn will return positive if the symbol is assumed to be positive using ce.assume().

Non-canonical expressions return undefined.

BoxedExpression.isPositive
readonly isPositive: boolean;

The value of this expression is > 0, same as isGreaterEqual(0)

BoxedExpression.isNonNegative
readonly isNonNegative: boolean;

The value of this expression is >= 0, same as isGreaterEqual(0)

BoxedExpression.isNegative
readonly isNegative: boolean;

The value of this expression is < 0, same as isLess(0)

BoxedExpression.isNonPositive
readonly isNonPositive: boolean;

The value of this expression is <= 0, same as isLessEqual(0)

BoxedExpression.isNaN
readonly isNaN: boolean;

If true, the value of this expression is "Not a Number".

A value representing undefined result of computations, such as 0/0, as per the floating point format standard IEEE-754.

Note that if isNaN is true, isNumber is also true (yes, NaN is a number).

BoxedExpression.isInfinity
readonly isInfinity: boolean;

The numeric value of this expression is ±Infinity or ComplexInfinity.

BoxedExpression.isFinite
readonly isFinite: boolean;

This expression is a number, but not ±Infinity, ComplexInfinity or NaN

Other

BoxedExpression.engine
readonly engine: ComputeEngine;

The Compute Engine instance associated with this expression provides a context in which to interpret it, such as definition of symbols and functions.

BoxedExpression.toLatex()
toLatex(options?): string

Serialize to a LaTeX string.

Will ignore any LaTeX metadata.

####### options?

Partial<SerializeLatexOptions>

BoxedExpression.latex

LaTeX representation of this expression.

If the expression was parsed from LaTeX, the LaTeX representation is the same as the input LaTeX.

To customize the serialization, use expr.toLatex().

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.toMathJson()
toMathJson(options?): Expression

Serialize to a MathJSON expression with specified options

####### options?

Readonly<Partial<JsonSerializationOptions>>

BoxedExpression.json
readonly json: Expression;

MathJSON representation of this expression.

This representation always use shorthands when possible. Metadata is not included.

Numbers are converted to JavaScript numbers and may lose precision.

The expression is represented exactly and no sugaring is applied. For example, ["Power", "x", 2] is not represented as ["Square", "x"].

For more control over the serialization, use expr.toMathJson().

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.print()
print(): void

Output to the console a string representation of the expression.

BoxedExpression.verbatimLatex?
optional verbatimLatex: string;

If the expression was constructed from a LaTeX string, the verbatim LaTeX string it was parsed from.

BoxedExpression.isCanonical

If true, this expression is in a canonical form.

BoxedExpression.isStructural

If true, this expression is in a structural form.

The structural form of an expression is used when applying rules to an expression. For example, a rational number is represented as a function expression instead of a BoxedExpression object.

BoxedExpression.canonical

Return the canonical form of this expression.

If a function expression or symbol, they are first bound with a definition in the current scope.

When determining the canonical form the following operator definition flags are applied:

  • associative: \( f(a, f(b), c) \longrightarrow f(a, b, c) \)
  • idempotent: \( f(f(a)) \longrightarrow f(a) \)
  • involution: \( f(f(a)) \longrightarrow a \)
  • commutative: sort the arguments.

If this expression is already canonical, the value of canonical is this.

The arguments of a canonical function expression may not all be canonical, for example in the ["Declare", "i", 2] expression, i is not canonical since it is used only as the name of a symbol, not as a (potentially) existing symbol.

Note

Partially canonical expressions, such as those produced through CanonicalForm, also yield an expression which is marked as canonical. This means that, likewise for partially canonical expressions, the canonical property will return the self-same expression (and 'isCanonical' will also be true).

BoxedExpression.structural

Return the structural form of this expression.

Some expressions, such as rational numbers, are represented with a BoxedExpression object. In some cases, for example when doing a structural comparison of two expressions, it is useful to have a structural representation of the expression where the rational numbers is represented by a function expression instead.

If there is a structural representation of the expression, return it, otherwise return this.

BoxedExpression.isValid
readonly isValid: boolean;

false if this expression or any of its subexpressions is an ["Error"] expression.

Note

Applicable to canonical and non-canonical expressions. For non-canonical expression, this may indicate a syntax error while parsing LaTeX. For canonical expression, this may indicate argument type mismatch, or missing or unexpected arguments.

BoxedExpression.isPure
readonly isPure: boolean;

If true, evaluating this expression has no side-effects (does not change the state of the Compute Engine).

If false, evaluating this expression may change the state of the Compute Engine or it may return a different value each time it is evaluated, even if the state of the Compute Engine is the same.

As an example, the ["Add", 2, 3]function expression is pure, but the["Random"]` function expression is not pure.

For a function expression to be pure, the function itself (its operator) must be pure, and all of its arguments must be pure too.

A pure function expression may return a different value each time it is evaluated if its arguments are not constant. For example, the ["Add", "x", 1] function expression is pure, but it is not constant, because x is not constant.

Note

Applicable to canonical expressions only

BoxedExpression.isConstant
readonly isConstant: boolean;

True if evaluating this expression always returns the same value.

If true and a function expression, implies that it is pure and that all of its arguments are constant.

Number literals, symbols with constant values, and pure numeric functions with constant arguments are all constant, i.e.:

  • 42 is constant
  • Pi is constant
  • ["Divide", "Pi", 2] is constant
  • x is not constant, unless declared with a constant flag.
  • ["Add", "x", 2] is either constant only if x is constant.
BoxedExpression.errors
readonly errors: readonly BoxedExpression[];

All the ["Error"] subexpressions.

If an expression includes an error, the expression is also an error. In that case, the this.isValid property is false.

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.getSubexpressions()
getSubexpressions(operator): readonly BoxedExpression[]

All the subexpressions matching the named operator, recursively.

Note

Applicable to canonical and non-canonical expressions.

####### operator

string

BoxedExpression.subexpressions
readonly subexpressions: readonly BoxedExpression[];

All the subexpressions in this expression, recursively

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.symbols
readonly symbols: readonly string[];

All the symbols in the expression, recursively

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.unknowns
readonly unknowns: readonly string[];

All the symbols used in the expression that do not have a value associated with them, i.e. they are declared but not defined.

BoxedExpression.toNumericValue()
toNumericValue(): [NumericValue, BoxedExpression]

Attempt to factor a numeric coefficient c and a rest out of a canonical expression such that rest.mul(c) is equal to this.

Attempts to make rest a positive value (i.e. pulls out negative sign).

['Multiply', 2, 'x', 3, 'a']
-> [NumericValue(6), ['Multiply', 'x', 'a']]

['Divide', ['Multiply', 2, 'x'], ['Multiply', 3, 'y', 'a']]
-> [NumericValue({rational: [2, 3]}), ['Divide', 'x', ['Multiply, 'y', 'a']]]
BoxedExpression.neg()
neg(): BoxedExpression

Negate (additive inverse)

BoxedExpression.inv()
inv(): BoxedExpression

Inverse (multiplicative inverse)

BoxedExpression.abs()
abs(): BoxedExpression

Absolute value

BoxedExpression.add()
add(rhs): BoxedExpression

Addition

####### rhs

number | BoxedExpression

BoxedExpression.sub()
sub(rhs): BoxedExpression

Subtraction

####### rhs

BoxedExpression

BoxedExpression.mul()
mul(rhs): BoxedExpression

Multiplication

####### rhs

number | NumericValue | BoxedExpression

BoxedExpression.div()
div(rhs): BoxedExpression

Division

####### rhs

number | BoxedExpression

BoxedExpression.pow()
pow(exp): BoxedExpression

Power

####### exp

number | BoxedExpression

BoxedExpression.root()
root(exp): BoxedExpression

Exponentiation

####### exp

number | BoxedExpression

BoxedExpression.sqrt()
sqrt(): BoxedExpression

Square root

BoxedExpression.ln()
ln(base?): BoxedExpression

Logarithm (natural by default)

####### base?

number | BoxedExpression

BoxedExpression.numerator

Return this expression expressed as a numerator.

BoxedExpression.denominator

Return this expression expressed as a denominator.

BoxedExpression.numeratorDenominator

Return this expression expressed as a numerator and denominator.

BoxedExpression.isScoped
readonly isScoped: boolean;

If true, the expression has its own local scope that can be used for local variables and arguments. Only true if the expression is a function expression.

BoxedExpression.localScope

If this expression has a local scope, return it.

BoxedExpression.subs()
subs(sub, options?): BoxedExpression

Replace all the symbols in the expression as indicated.

Note the same effect can be achieved with this.replace(), but using this.subs() is more efficient and simpler, but limited to replacing symbols.

The result is bound to the current scope, not to this.scope.

If options.canonical is not set, the result is canonical if this is canonical.

Note

Applicable to canonical and non-canonical expressions.

####### sub

Substitution<SemiBoxedExpression>

####### options?

####### canonical

CanonicalOptions

BoxedExpression.map()
map(fn, options?): BoxedExpression

Recursively replace all the subexpressions in the expression as indicated.

To remove a subexpression, return an empty ["Sequence"] expression.

The canonical option is applied to each function subexpression after the substitution is applied.

If no options.canonical is set, the result is canonical if this is canonical.

Default: { canonical: this.isCanonical, recursive: true }

Note

Applicable to canonical and non-canonical expressions.

####### fn

(expr) => BoxedExpression

####### options?

####### canonical

CanonicalOptions

####### recursive

boolean

BoxedExpression.replace()
replace(rules, options?): BoxedExpression

Transform the expression by applying one or more replacement rules:

  • If the expression matches the match pattern and the condition predicate is true, replace it with the replace pattern.

  • If no rules apply, return null.

See also expr.subs() for a simple substitution of symbols.

If options.canonical is not set, the result is canonical if this is canonical.

Note

Applicable to canonical and non-canonical expressions.

####### rules

BoxedRuleSet | Rule | Rule[]

####### options?

Partial<ReplaceOptions>

BoxedExpression.has()
has(v): boolean

True if the expression includes a symbol v or a function operator v.

Note

Applicable to canonical and non-canonical expressions.

####### v

string | string[]

BoxedExpression.match()
match(pattern, options?): BoxedSubstitution

If this expression matches pattern, return a substitution that makes pattern equal to this. Otherwise return null.

If pattern includes wildcards (symbols that start with _), the substitution will include a prop for each matching named wildcard.

If this expression matches pattern but there are no named wildcards, return the empty substitution, {}.

Read more about patterns and rules.

Note

Applicable to canonical and non-canonical expressions.

####### pattern

BoxedExpression

####### options?

PatternMatchOptions

BoxedExpression.wikidata
readonly wikidata: string;

Wikidata identifier.

If not a canonical expression, return undefined.

BoxedExpression.description
readonly description: string[];

An optional short description if a symbol or function expression.

May include markdown. Each string is a paragraph.

If not a canonical expression, return undefined.

BoxedExpression.url
readonly url: string;

An optional URL pointing to more information about the symbol or function operator.

If not a canonical expression, return undefined.

BoxedExpression.complexity
readonly complexity: number;

Expressions with a higher complexity score are sorted first in commutative functions

If not a canonical expression, return undefined.

BoxedExpression.baseDefinition
readonly baseDefinition: BoxedBaseDefinition;

For symbols and functions, a definition associated with the expression. this.baseDefinition is the base class of symbol and function definition.

If not a canonical expression, return undefined.

BoxedExpression.operatorDefinition
readonly operatorDefinition: BoxedOperatorDefinition;

For function expressions, the definition of the operator associated with the expression. For symbols, the definition of the symbol if it is an operator, for example "Sin".

If not a canonical expression or not a function expression, its value is undefined.

BoxedExpression.valueDefinition
readonly valueDefinition: BoxedValueDefinition;

For symbols, a definition associated with the expression, if it is not an operator.

If not a canonical expression, or not a value, its value is undefined.

BoxedExpression.simplify()
simplify(options?): BoxedExpression

Return a simpler form of this expression.

A series of rewriting rules are applied repeatedly, until no more rules apply.

The values assigned to symbols and the assumptions about symbols may be used, for example expr.isInteger or expr.isPositive.

No calculations involving decimal numbers (numbers that are not integers) are performed but exact calculations may be performed, for example:

\sin(\frac{\pi}{4}) \longrightarrow \frac{\sqrt{2}}{2}.

The result is canonical.

To manipulate symbolically non-canonical expressions, use expr.replace().

####### options?

Partial<SimplifyOptions>

BoxedExpression.expand()
expand(): BoxedExpression

Expand the expression: distribute multiplications over additions, and expand powers.

BoxedExpression.evaluate()
evaluate(options?): BoxedExpression

Return the value of the canonical form of this expression.

A pure expression always returns the same value (provided that it remains constant / values of sub-expressions or symbols do not change), and has no side effects.

Evaluating an impure expression may return a varying value, and may have some side effects such as adjusting symbol assumptions.

To perform approximate calculations, use expr.N() instead, or call with options.numericApproximation to true.

It is possible that the result of expr.evaluate() may be the same as expr.simplify().

The result is in canonical form.

####### options?

Partial<EvaluateOptions>

BoxedExpression.evaluateAsync()
evaluateAsync(options?): Promise<BoxedExpression>

Asynchronous version of evaluate().

The options argument can include a signal property, which is an AbortSignal object. If the signal is aborted, a CancellationError is thrown.

####### options?

Partial<EvaluateOptions>

BoxedExpression.N()
N(): BoxedExpression

Return a numeric approximation of the canonical form of this expression.

Any necessary calculations, including on decimal numbers (non-integers), are performed.

The calculations are performed according to the precision property of the ComputeEngine.

To only perform exact calculations, use this.evaluate() instead.

If the function is not numeric, the result of this.N() is the same as this.evaluate().

The result is in canonical form.

BoxedExpression.compile()
compile(options?): (args?) => CompiledType

Compile the expression to a JavaScript function.

The function takes an object as argument, with the keys being the symbols in the expression, and returns the value of the expression.

const expr = ce.parse("x^2 + y^2");
const f = expr.compile();
console.log(f({x: 2, y: 3}));

####### options?

####### to

"javascript"

####### functions

Record<string, string | (...any) => any>

####### vars

Record<string, CompiledType>

####### imports

(...any) => any[]

####### preamble

string

BoxedExpression.solve()
solve(vars?): readonly BoxedExpression[]

If this is an equation, solve the equation for the variables in vars. Otherwise, solve the equation this = 0 for the variables in vars.

const expr = ce.parse("x^2 + 2*x + 1 = 0");
console.log(expr.solve("x"));

####### vars?

string | Iterable<string> | BoxedExpression | Iterable<BoxedExpression>

BoxedExpression.value
get value(): BoxedExpression
set value(value:
| string
| number
| boolean
| number[]
| Decimal
| OnlyFirst<{
re: number;
im: number;
}, {
re: number;
im: number;
} & {
num: number;
denom: number;
} & BoxedExpression>
| OnlyFirst<{
num: number;
denom: number;
}, {
re: number;
im: number;
} & {
num: number;
denom: number;
} & BoxedExpression>
| OnlyFirst<BoxedExpression, {
re: number;
im: number;
} & {
num: number;
denom: number;
} & BoxedExpression>): void

If this expression is a number literal, a string literal or a function literal, return the expression.

If the expression is a symbol, return the value of the symbol.

Otherwise, the expression is a symbolic expression, including an unknown symbol, i.e. a symbol with no value, return undefined.

If the expression is a symbol, set the value of the symbol.

Will throw a runtime error if either not a symbol, or a symbol with the constant flag set to true.

Setting the value of a symbol results in the forgetting of all assumptions about it in the current scope.

BoxedExpression.isCollection
isCollection: boolean;

Return true if the expression is a collection: a list, a vector, a matrix, a map, a tuple, etc...

BoxedExpression.contains()
contains(rhs): boolean

If this is a collection, return true if the rhs expression is in the collection.

Return undefined if the membership cannot be determined.

####### rhs

BoxedExpression

BoxedExpression.size

If this is a collection, return the number of elements in the collection.

If the collection is infinite, return Infinity.

BoxedExpression.each()
each: (start?, count?) => Iterator<BoxedExpression, undefined>;

If this is a collection, return an iterator over the elements of the collection.

If start is not specified, start from the first element.

If count is not specified or negative, return all the elements from start to the end.

const expr = ce.parse('[1, 2, 3, 4]');
for (const e of expr.each()) {
console.log(e);
}
BoxedExpression.at()
at(index): BoxedExpression

If this is an indexable collection, return the element at the specified index.

If the index is negative, return the element at index size() + index + 1.

####### index

number

BoxedExpression.get()
get(key): BoxedExpression

If this is a map or a tuple, return the value of the corresponding key.

If key is a BoxedExpression, it should be a string.

####### key

string | BoxedExpression

BoxedExpression.indexOf()
indexOf(expr): number

If this is an indexable collection, return the index of the first element that matches the target expression.

####### expr

BoxedExpression

Primitive Methods

BoxedExpression.valueOf()
valueOf(): string | number | boolean | number[] | number[][] | number[][][]

Return a JavaScript primitive value for the expression, based on Object.valueOf().

This method is intended to make it easier to work with JavaScript primitives, for example when mixing JavaScript computations with symbolic computations from the Compute Engine.

If the expression is a machine number, a bignum, or a rational that can be converted to a machine number, return a JavaScript number. This conversion may result in a loss of precision.

If the expression is the symbol "True" or the symbol "False", return true or false, respectively.

If the expression is a symbol with a numeric value, return the numeric value of the symbol.

If the expression is a string literal, return the string value.

If the expression is a tensor (list of number or multidimensional array or matrix), return an array of numbers, or an array of arrays of numbers, or an array of arrays of arrays of numbers.

If the expression is a function expression return a string representation of the expression.

BoxedExpression.[toPrimitive]()
toPrimitive: string | number

Similar toexpr.valueOf() but includes a hint.

####### hint

"string" | "number" | "default"

BoxedExpression.toString()
toString(): string

Return an ASCIIMath representation of the expression. This string is suitable to be output to the console for debugging, for example.

Based on Object.toString().

To get a LaTeX representation of the expression, use expr.latex.

Used when coercing a BoxedExpression to a String.

BoxedExpression.toJSON()
toJSON(): Expression

Used by JSON.stringify() to serialize this object to JSON.

Method version of expr.json.

Based on Object.toJSON().

BoxedExpression.is()
is(other): boolean

Equivalent to BoxedExpression.isSame() but the argument can be a JavaScript primitive. For example, expr.is(2) is equivalent to expr.isSame(ce.number(2)).

####### other

string | number | bigint | boolean | BoxedExpression

Relational Operator

BoxedExpression.isSame()
isSame(rhs): boolean

Structural/symbolic equality (weak equality).

ce.parse('1+x', {canonical: false}).isSame(ce.parse('x+1', {canonical: false})) is false.

See expr.isEqual() for mathematical equality.

Note

Applicable to canonical and non-canonical expressions.

####### rhs

BoxedExpression

BoxedExpression.isLess()
isLess(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | BoxedExpression

BoxedExpression.isLessEqual()
isLessEqual(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | BoxedExpression

BoxedExpression.isGreater()
isGreater(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | BoxedExpression

BoxedExpression.isGreaterEqual()
isGreaterEqual(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | BoxedExpression

BoxedExpression.isEqual()
isEqual(other): boolean

Mathematical equality (strong equality), that is the value of this expression and the value of other are numerically equal.

Both expressions are evaluated and the result is compared numerically.

Numbers whose difference is less than engine.tolerance are considered equal. This tolerance is set when the engine.precision is changed to be such that the last two digits are ignored.

Evaluating the expressions may be expensive. Other options to consider to compare two expressions include:

  • expr.isSame(other) for a structural comparison which does not involve evaluating the expressions.
  • expr.is(other) for a comparison of a number literal

Examples

let expr = ce.parse('2 + 2');
console.log(expr.isEqual(4)); // true
console.log(expr.isSame(ce.parse(4))); // false
console.log(expr.is(4)); // false

expr = ce.parse('4');
console.log(expr.isEqual(4)); // true
console.log(expr.isSame(ce.parse(4))); // true
console.log(expr.is(4)); // true (fastest)

####### other

number | BoxedExpression

String Expression

BoxedExpression.string
readonly string: string;

If this expression is a string, return the value of the string. Otherwise, return null.

Note

Applicable to canonical and non-canonical expressions.

Symbol Expression

BoxedExpression.symbol
readonly symbol: string;

If this expression is a symbol, return the name of the symbol as a string. Otherwise, return null.

Note

Applicable to canonical and non-canonical expressions.

Tensor Expression

BoxedExpression.tensor
readonly tensor: Tensor<any>;

If this expression is a tensor, return the tensor data. Otherwise, return null.

Note

Applicable to canonical and non-canonical expressions.

BoxedExpression.shape
readonly shape: number[];

The shape describes the axes of the expression, where each axis represent a way to index the elements of the expression.

When the expression is a scalar (number), the shape is [].

When the expression is a vector of length n, the shape is [n].

When the expression is a n by m matrix, the shape is [n, m].

BoxedExpression.rank
readonly rank: number;

The rank refers to the number of dimensions (or axes) of the expression.

Return 0 for a scalar, 1 for a vector, 2 for a matrix, > 2 for a multidimensional matrix.

The rank is equivalent to the length of expr.shape

Note

There are several definitions of rank in the literature. For example, the row rank of a matrix is the number of linearly independent rows. The rank can also refer to the number of non-zero singular values of a matrix.

Type Properties

BoxedExpression.type
get type(): BoxedType
set type(type:
| string
| AlgebraicType
| NegationType
| CollectionType
| ListType
| SetType
| MapType
| TupleType
| FunctionSignature
| ValueType
| TypeReference
| BoxedType): void

The type of the value of this expression.

If a symbol the type of the value of the symbol.

If a function expression, the type of the value of the function (the result type).

If a symbol with a "function" type (a function literal), returns the signature.

If not valid, return "error".

If the type is not known, return "unknown".

BoxedExpression.isNumber
readonly isNumber: boolean;

true if the value of this expression is a number.

Note that in a fateful twist of cosmic irony, NaN ("Not a Number") is a number.

If isNumber is true, this indicates that evaluating the expression will return a number.

This does not indicate that the expression is a number literal. To check if the expression is a number literal, use expr.isNumberLiteral.

For example, the expression ["Add", 1, "x"] is a number if "x" is a number and expr.isNumber is true, but isNumberLiteral is false.

BoxedExpression.isInteger
readonly isInteger: boolean;

The value of this expression is an element of the set ℤ: ...,-2, -1, 0, 1, 2...

Note that ±∞ and NaN are not integers.

BoxedExpression.isRational
readonly isRational: boolean;

The value of this expression is an element of the set ℚ, p/q with p ∈ ℕ, q ∈ ℤ ⃰ q >= 1

Note that every integer is also a rational.

This is equivalent to this.type === "rational" || this.type === "integer"

Note that ±∞ and NaN are not rationals.

BoxedExpression.isReal
readonly isReal: boolean;

The value of this expression is a real number.

This is equivalent to this.type === "rational" || this.type === "integer" || this.type === "real"

Note that ±∞ and NaN are not real numbers.

SemiBoxedExpression

type SemiBoxedExpression = 
| number
| bigint
| string
| BigNum
| MathJsonNumberObject
| MathJsonStringObject
| MathJsonSymbolObject
| MathJsonFunctionObject
| readonly [MathJsonSymbol, ...SemiBoxedExpression[]]
| BoxedExpression;

A semi boxed expression is a MathJSON expression which can include some boxed terms.

This is convenient when creating new expressions from portions of an existing BoxedExpression while avoiding unboxing and reboxing.

ReplaceOptions

type ReplaceOptions = {
recursive: boolean;
once: boolean;
useVariations: boolean;
iterationLimit: number;
canonical: CanonicalOptions;
};

ReplaceOptions.recursive

recursive: boolean;

If true, apply replacement rules to all sub-expressions.

If false, only consider the top-level expression.

Default: false

ReplaceOptions.once

once: boolean;

If true, stop after the first rule that matches.

If false, apply all the remaining rules even after the first match.

Default: false

ReplaceOptions.useVariations

useVariations: boolean;

If true the rule will use some equivalent variations to match.

For example when useVariations is true:

  • x matches a + x with a = 0
  • x matches ax with a = 1
  • etc...

Setting this to true can save time by condensing multiple rules into one. This can be particularly useful when describing equations solutions. However, it can lead to infinite recursion and should be used with caution.

ReplaceOptions.iterationLimit

iterationLimit: number;

If iterationLimit > 1, the rules will be repeatedly applied until no rules apply, up to maxIterations times.

Note that if once is true, iterationLimit has no effect.

Default: 1

ReplaceOptions.canonical

canonical: CanonicalOptions;

Indicate if the expression should be canonicalized after the replacement. If not provided, the expression is canonicalized if the expression that matched the pattern is canonical.

SimplifyOptions

type SimplifyOptions = {
rules: | null
| Rule
| ReadonlyArray<BoxedRule | Rule>
| BoxedRuleSet;
costFunction: (expr) => number;
};

Options for BoxedExpression.simplify()

SimplifyOptions.rules?

optional rules: 
| null
| Rule
| ReadonlyArray<BoxedRule | Rule>
| BoxedRuleSet;

The set of rules to apply. If null, use no rules. If not provided, use the default simplification rules.

SimplifyOptions.costFunction()?

optional costFunction: (expr) => number;

Use this cost function to determine if a simplification is worth it.

If not provided, ce.costFunction, the cost function of the engine is used.

CanonicalForm

type CanonicalForm = 
| "InvisibleOperator"
| "Number"
| "Multiply"
| "Add"
| "Power"
| "Divide"
| "Flatten"
| "Order";

When provided, canonical forms are used to put an expression in a "standard" form.

Each canonical form applies some transformation to an expression. When specified as an array, each transformation is done in the order in which it was provided.

  • InvisibleOperator: replace use of the InvisibleOperator with another operation, such as multiplication (i.e. 2x or function application (f(x)). Also replaces ['InvisibleOperator', real, imaginary] instances with complex (imaginary) numbers.
  • Number: replace all numeric values with their canonical representation, for example, reduce rationals and replace complex numbers with no imaginary part with a real number.
  • Multiply: replace negation with multiplication by -1, remove 1 from multiplications, simplify signs (-y \times -x -> x \times y), complex numbers are promoted (['Multiply', 2, 'ImaginaryUnit'] -> ["Complex", 0, 2])
  • Add: replace Subtract with Add, removes 0 in addition, promote complex numbers (["Add", "a", ["Complex", 0, "b"] -> ["Complex", "a", "b"])
  • Power: simplify Power expression, for example, x^{-1} -> \frac{1}{x}, x^0 -> 1, x^1 -> x, 1^x -> 1, x^{\frac{1}{2}} -> \sqrt{x}, a^b^c -> a^{bc}...
  • Divide: replace with a Rational number if numerator and denominator are integers, simplify, e.g. \frac{x}{1} -> x...
  • Flatten: remove any unnecessary Delimiter expression, and flatten any associative functions, for example ["Add", ["Add", "a", "b"], "c"] -> ["Add", "a", "b", "c"]
  • Order: when applicable, sort the arguments in a specific order, for example for addition and multiplication.

CanonicalOptions

type CanonicalOptions = 
| boolean
| CanonicalForm
| CanonicalForm[];

EvaluateOptions

type EvaluateOptions = {
numericApproximation: boolean;
signal: AbortSignal;
withArguments: Record<MathJsonSymbol, BoxedExpression>;
};

Options for BoxedExpression.evaluate()

Metadata

type Metadata = {
latex: string;
wikidata: string;
};

Metadata that can be associated with an MathJSON expression.

Pattern Matching

PatternMatchOptions

type PatternMatchOptions = {
substitution: BoxedSubstitution;
recursive: boolean;
useVariations: boolean;
};

Control how a pattern is matched to an expression.

  • substitution: if present, assumes these values for the named wildcards, and ensure that subsequent occurrence of the same wildcard have the same value.

  • recursive: if true, match recursively, otherwise match only the top level.

  • useVariations: if false, only match expressions that are structurally identical. If true, match expressions that are structurally identical or equivalent.

    For example, when true, ["Add", '_a', 2] matches 2, with a value of _a of 0. If false, the expression does not match. Default: false

Substitution<T>

type Substitution<T> = {};

A substitution describes the values of the wildcards in a pattern so that the pattern is equal to a target expression.

A substitution can also be considered a more constrained version of a rule whose match is always a symbol.

Type Parameters

• T = SemiBoxedExpression

BoxedSubstitution

type BoxedSubstitution = Substitution<BoxedExpression>;

Rules

RuleReplaceFunction()

type RuleReplaceFunction = (expr, wildcards) => BoxedExpression | undefined;

Given an expression and set of wildcards, return a new expression.

For example:

{
match: '_x',
replace: (expr, {_x}) => { return ['Add', 1, _x] }
}

RuleConditionFunction()

type RuleConditionFunction = (wildcards, ce) => boolean;

RuleFunction()

type RuleFunction = (expr) => 
| undefined
| BoxedExpression
| RuleStep;

RuleStep

type RuleStep = {
value: BoxedExpression;
because: string;
};

RuleSteps

type RuleSteps = RuleStep[];

Rule

type Rule = 
| string
| RuleFunction
| {
match: | LatexString
| SemiBoxedExpression
| BoxedExpression;
replace: | LatexString
| SemiBoxedExpression
| RuleReplaceFunction
| RuleFunction;
condition: | LatexString
| RuleConditionFunction;
useVariations: boolean;
id: string;
onBeforeMatch: (rule, expr) => void;
onMatch: (rule, expr, replace) => void;
};

A rule describes how to modify an expressions that matches a pattern match into a new expression replace.

  • x-1 ( \to ) 1-x
  • (x+1)(x-1) ( \to ) `x^2-1

The patterns can be expressed as LaTeX strings or a MathJSON expressions.

As a shortcut, a rule can be defined as a LaTeX string: x-1 -> 1-x. The expression to the left of -> is the match and the expression to the right is the replace. When using LaTeX strings, single character variables are assumed to be wildcards.

When using MathJSON expressions, anonymous wildcards (_) will match any expression. Named wildcards (_x, _a, etc...) will match any expression and bind the expression to the wildcard name.

In addition the sequence wildcard (__1, __a, etc...) will match a sequence of one or more expressions, and bind the sequence to the wildcard name.

Sequence wildcards are useful when the number of elements in the sequence is not known in advance. For example, in a sum, the number of terms is not known in advance. ["Add", 0, __a] will match two or more terms and the __a wildcard will be a sequence of the matchign terms.

If exact is false, the rule will match variants.

For example 'x' will match 'a + x', 'x' will match 'ax', etc...

For simplification rules, you generally want exact to be true, but to solve equations, you want it to be false. Default to true.

When set to false, infinite recursion is possible.

BoxedRule

type BoxedRule = {
match: undefined | BoxedExpression;
replace: | BoxedExpression
| RuleReplaceFunction
| RuleFunction;
condition: undefined | RuleConditionFunction;
useVariations: boolean;
id: string;
onBeforeMatch: (rule, expr) => void;
onMatch: (rule, expr, replace) => void;
};

If the match property is undefined, all expressions match this rule and condition should also be undefined. The replace property should be a BoxedExpression or a RuleFunction, and further filtering can be done in the replace function.

BoxedRuleSet

type BoxedRuleSet = {
rules: ReadonlyArray<BoxedRule>;
};

To create a BoxedRuleSet use the ce.rules() method.

Do not create a BoxedRuleSet directly.

Assumptions

Assumption

Assumption.isPositive
isPositive: boolean;
Assumption.isNonNegative
isNonNegative: boolean;
Assumption.isNegative
isNegative: boolean;
Assumption.isNonPositive
isNonPositive: boolean;
Assumption.isNumber
isNumber: boolean;
Assumption.isInteger
isInteger: boolean;
Assumption.isRational
isRational: boolean;
Assumption.isReal
isReal: boolean;
Assumption.isComplex
isComplex: boolean;
Assumption.isImaginary
isImaginary: boolean;
Assumption.isFinite
isFinite: boolean;
Assumption.isInfinite
isInfinite: boolean;
Assumption.isNaN
isNaN: boolean;
Assumption.isZero
isZero: boolean;
Assumption.matches()
matches(t): boolean

####### t

string | BoxedType

Assumption.isGreater()
isGreater(other): boolean

####### other

BoxedExpression

Assumption.isGreaterEqual()
isGreaterEqual(other): boolean

####### other

BoxedExpression

Assumption.isLess()
isLess(other): boolean

####### other

BoxedExpression

Assumption.isLessEqual()
isLessEqual(other): boolean

####### other

BoxedExpression

Assumption.isEqual()
isEqual(other): boolean

####### other

BoxedExpression

Assumption.toExpression()
toExpression(ce, x): BoxedExpression

####### ce

ComputeEngine

####### x

string

ExpressionMapInterface<U>

ExpressionMapInterface.has()
has(expr): boolean

####### expr

BoxedExpression

ExpressionMapInterface.get()
get(expr): U

####### expr

BoxedExpression

ExpressionMapInterface.set()
set(expr, value): void

####### expr

BoxedExpression

####### value

U

ExpressionMapInterface.delete()
delete(expr): void

####### expr

BoxedExpression

ExpressionMapInterface.clear()
clear(): void
ExpressionMapInterface.[iterator]()
iterator: IterableIterator<[BoxedExpression, U]>
ExpressionMapInterface.entries()
entries(): IterableIterator<[BoxedExpression, U]>

AssumeResult

type AssumeResult = 
| "internal-error"
| "not-a-predicate"
| "contradiction"
| "tautology"
| "ok";

Compiling

CompiledType

type CompiledType = boolean | number | string | object;

JSSource

type JSSource = string;

CompiledExpression

type CompiledExpression = {
evaluate: (scope) => number | BoxedExpression;
};

Definitions

EqHandlers

These handlers compare two expressions.

If only one of the handlers is provided, the other is derived from it.

Having both may be useful if comparing non-equality is faster than equality.

EqHandlers.eq()
eq: (a, b) => boolean;
EqHandlers.neq()
neq: (a, b) => boolean;

Hold

type Hold = "none" | "all" | "first" | "rest" | "last" | "most";

ValueDefinition

type ValueDefinition = BaseDefinition & {
holdUntil: "never" | "evaluate" | "N";
type: | Type
| TypeString
| BoxedType;
inferred: boolean;
value: | LatexString
| SemiBoxedExpression
| (ce) => BoxedExpression | null;
eq: (a) => boolean | undefined;
neq: (a) => boolean | undefined;
cmp: (a) => "=" | ">" | "<" | undefined;
collection: Partial<CollectionHandlers>;
};

A bound symbol (i.e. one with an associated definition) has either a type (e.g. ∀ x ∈ ℝ), a value (x = 5) or both (π: value = 3.14... type = 'real').

ValueDefinition.inferred

inferred: boolean;

If true, the type is inferred, and could be adjusted later as more information becomes available or if the symbol is explicitly declared.

ValueDefinition.value

value: 
| LatexString
| SemiBoxedExpression
| (ce) => BoxedExpression | null;

value can be a JS function since for some constants, such as Pi, the actual value depends on the precision setting of the ComputeEngine and possible other environment settings

OperatorDefinition

type OperatorDefinition = Partial<BaseDefinition> & Partial<OperatorDefinitionFlags> & {
signature: | Type
| TypeString
| BoxedType;
type: (ops, options) =>
| Type
| TypeString
| BoxedType
| undefined;
sgn: (ops, options) => Sign | undefined;
isPositive: boolean;
isNonNegative: boolean;
isNegative: boolean;
isNonPositive: boolean;
even: (ops, options) => boolean | undefined;
complexity: number;
canonical: (ops, options) => BoxedExpression | null;
evaluate: | (ops, options) => BoxedExpression | undefined
| BoxedExpression;
evaluateAsync: (ops, options) => Promise<BoxedExpression | undefined>;
evalDimension: (args, options) => BoxedExpression;
compile: (expr) => CompiledExpression;
eq: (a, b) => boolean | undefined;
neq: (a, b) => boolean | undefined;
collection: Partial<CollectionHandlers>;
};

Definition record for a function.

OperatorDefinition.signature?

optional signature: 
| Type
| TypeString
| BoxedType;

The function signature, describing the type of the arguments and the return type.

If a type handler is provided, the return type of the function should be a subtype of the return type in the signature.

OperatorDefinition.type()?

optional type: (ops, options) => 
| Type
| TypeString
| BoxedType
| undefined;

The type of the result (return type) based on the type of the arguments.

Should be a subtype of the type indicated by the signature.

For example, if the signature is (number) -> real, the type of the result could be real or integer, but not complex.

Note

Do not evaluate the arguments.

However, the type of the arguments can be used to determine the type of the result.

OperatorDefinition.sgn()?

optional sgn: (ops, options) => Sign | undefined;

Return the sign of the function expression.

If the sign cannot be determined, return undefined.

When determining the sign, only literal values and the values of symbols, if they are literals, should be considered.

Do not evaluate the arguments.

However, the type and sign of the arguments can be used to determine the sign.

OperatorDefinition.isPositive?

readonly optional isPositive: boolean;

The value of this expression is > 0, same as isGreater(0)

OperatorDefinition.isNonNegative?

readonly optional isNonNegative: boolean;

The value of this expression is >= 0, same as isGreaterEqual(0)

OperatorDefinition.isNegative?

readonly optional isNegative: boolean;

The value of this expression is < 0, same as isLess(0)

OperatorDefinition.isNonPositive?

readonly optional isNonPositive: boolean;

The value of this expression is <= 0, same as isLessEqual(0)

OperatorDefinition.even()?

optional even: (ops, options) => boolean | undefined;

Return true if the function expression is even, false if it is odd and undefined if it is neither (for example if it is not a number, or if it is a complex number).

OperatorDefinition.complexity?

optional complexity: number;

A number used to order arguments.

Argument with higher complexity are placed after arguments with lower complexity when ordered canonically in commutative functions.

  • Additive functions: 1000-1999
  • Multiplicative functions: 2000-2999
  • Root and power functions: 3000-3999
  • Log functions: 4000-4999
  • Trigonometric functions: 5000-5999
  • Hypertrigonometric functions: 6000-6999
  • Special functions (factorial, Gamma, ...): 7000-7999
  • Collections: 8000-8999
  • Inert and styling: 9000-9999
  • Logic: 10000-10999
  • Relational: 11000-11999

Default: 100,000

OperatorDefinition.canonical()?

optional canonical: (ops, options) => BoxedExpression | null;

Return the canonical form of the expression with the arguments args.

The arguments (args) may not be in canonical form. If necessary, they can be put in canonical form.

This handler should validate the type and number of the arguments (arity).

If a required argument is missing, it should be indicated with a ["Error", "'missing"] expression. If more arguments than expected are present, this should be indicated with an ["Error", "'unexpected-argument'"] error expression

If the type of an argument is not compatible, it should be indicated with an incompatible-type error.

["Sequence"] expressions are not folded and need to be handled explicitly.

If the function is associative, idempotent or an involution, this handler should account for it. Notably, if it is commutative, the arguments should be sorted in canonical order.

Values of symbols should not be substituted, unless they have a holdUntil attribute of "never".

The handler should not consider the value or any assumptions about any of the arguments that are symbols or functions (i.e. arg.isZero, arg.isInteger, etc...) since those may change over time.

The result of the handler should be a canonical expression.

If the arguments do not match, they should be replaced with an appropriate ["Error"] expression. If the expression cannot be put in canonical form, the handler should return null.

OperatorDefinition.evaluate?

optional evaluate: 
| (ops, options) => BoxedExpression | undefined
| BoxedExpression;

Evaluate a function expression.

When the handler is invoked, the arguments have been evaluated, except if the lazy option is set to true.

It is not necessary to further simplify or evaluate the arguments.

If performing numerical calculations and options.numericalApproximation is false return an exact numeric value, for example return a rational number or a square root, rather than a floating point approximation. Use ce.number() to create the numeric value.

If the expression cannot be evaluated, due to the values, types, or assumptions about its arguments, return undefined or an ["Error"] expression.

OperatorDefinition.evaluateAsync()?

optional evaluateAsync: (ops, options) => Promise<BoxedExpression | undefined>;

An asynchronous version of evaluate.

OperatorDefinition.evalDimension()?

optional evalDimension: (args, options) => BoxedExpression;

Experimental

Dimensional analysis

OperatorDefinition.compile()?

optional compile: (expr) => CompiledExpression;

Return a compiled (optimized) expression.

BaseDefinition

Metadata common to both symbols and functions.

BaseDefinition.description
description: string | string[];

If a string, a short description, about one line long.

Otherwise, a list of strings, each string a paragraph.

May contain Markdown.

BaseDefinition.url
url: string;

A URL pointing to more information about this symbol or operator.

BaseDefinition.wikidata
wikidata: string;

A short string representing an entry in a wikibase.

For example "Q167" is the wikidata entry for the Pi constant.

BaseDefinition.isConstant?
readonly optional isConstant: boolean;

If true, the value or type of the definition cannot be changed

SymbolDefinition

type SymbolDefinition = OneOf<[ValueDefinition, OperatorDefinition]>;

A table mapping symbols to their definition.

Symbols should be valid MathJSON symbols. In addition, the following rules are recommended:

  • Use only latin letters, digits and -: /[a-zA-Z0-9-]+/
  • The first character should be a letter: /^[a-zA-Z]/
  • Functions and symbols exported from a library should start with an uppercase letter /^[A-Z]/

SymbolDefinitions

type SymbolDefinitions = Readonly<{}>;

CollectionHandlers

type CollectionHandlers = {
size: (collection) => number;
contains: (collection, target) => boolean;
iterator: (collection, start?, count?) => Iterator<BoxedExpression, undefined>;
at: (collection, index) => undefined | BoxedExpression;
keys: (collection) => undefined | Iterable<string>;
indexOf: (collection, target, from?) => number | undefined;
subsetOf: (collection, target, strict) => boolean;
eltsgn: (collection) => Sign | undefined;
elttype: (collection) => Type | undefined;
};

These handlers are the primitive operations that can be performed on collections.

There are two types of collections:

  • finite collections, such as lists, tuples, sets, matrices, etc... The size() handler of finite collections returns the number of elements

  • infinite collections, such as sequences, ranges, etc... The size() handler of infinite collections returns Infinity Infinite collections are not indexable: they have no at() handler.

Definitions

CollectionHandlers.iterator()
iterator: (collection, start?, count?) => Iterator<BoxedExpression, undefined>;

Return an iterator

  • start is optional and is a 1-based index.
  • if start is not specified, start from index 1
  • count is optional and is the number of elements to return
  • if count is not specified or negative, return all the elements from start to the end

If there is a keys() handler, there is no iterator() handler.

Other

CollectionHandlers.size()
size: (collection) => number;

Return the number of elements in the collection.

An empty collection has a size of 0.

CollectionHandlers.contains()
contains: (collection, target) => boolean;

Return true if the target expression is in the collection, false otherwise.

CollectionHandlers.at()
at: (collection, index) => undefined | BoxedExpression;

Return the element at the specified index.

The first element is at(1), the last element is at(-1).

If the index is <0, return the element at index size() + index + 1.

The index can also be a string for example for maps. The set of valid keys is returned by the keys() handler.

If the index is invalid, return undefined.

CollectionHandlers.keys()
keys: (collection) => undefined | Iterable<string>;

If the collection can be indexed by strings, return the valid values for the index.

CollectionHandlers.indexOf()
indexOf: (collection, target, from?) => number | undefined;

Return the index of the first element that matches the target expression.

The comparison is done using the target.isEqual() method.

If the expression is not found, return undefined.

If the expression is found, return the index, 1-based.

Return the index of the first match.

from is the starting index for the search. If negative, start from the end and search backwards.

CollectionHandlers.subsetOf()
subsetOf: (collection, target, strict) => boolean;

Return true if all theelements of target are in expr. Both expr and target are collections. If strict is true, the subset must be strict, that is, expr must have more elements than target.

CollectionHandlers.eltsgn()
eltsgn: (collection) => Sign | undefined;

Return the sign of all the elements of the collection.

CollectionHandlers.elttype()
elttype: (collection) => Type | undefined;

Return the widest type of all the elements in the collection

BoxedDefinition

type BoxedDefinition = 
| TaggedValueDefinition
| TaggedOperatorDefinition;

A boxed definition can be either a value or an operator.

It is collected in a tagged object literal, instead of being a simple union type, so that the type of the definition can be changed while keeping references to the definition in bound expressions.

BoxedBaseDefinition

Extends

Extended by

BoxedBaseDefinition.collection?
optional collection: Partial<CollectionHandlers>;

If this is the definition of a collection, the set of primitive operations that can be performed on this collection (counting the number of elements, enumerating it, etc...).

BoxedValueDefinition

Extends

BoxedValueDefinition.holdUntil
holdUntil: "never" | "evaluate" | "N";

If the symbol has a value, it is held as indicated in the table below. A green checkmark indicate that the symbol is substituted.

Operation"never""evaluate""N"
canonical()(X)
evaluate()(X)(X)
"N()"(X)(X)(X)

Some examples:

  • ImaginaryUnit has holdUntil: 'never': it is substituted during canonicalization
  • x has holdUntil: 'evaluate' (variables)
  • Pi has holdUntil: 'N' (special numeric constant)

Default: evaluate

BoxedValueDefinition.value
readonly value: BoxedExpression;

This is either the initial value of the symbol (i.e. when a new evaluation context is created), or its constant value, if a constant. Otherwise, the current value is tracked in the evaluation context.

BoxedValueDefinition.eq()?
optional eq: (a) => boolean;
BoxedValueDefinition.neq()?
optional neq: (a) => boolean;
BoxedValueDefinition.cmp()?
optional cmp: (a) => ">" | "<" | "=";
BoxedValueDefinition.inferredType
inferredType: boolean;

True if the type has been inferred. An inferred type can be updated as more information becomes available.

A type that is not inferred, but has been set explicitly, cannot be updated.

BoxedValueDefinition.type
type: BoxedType;

OperatorDefinitionFlags

type OperatorDefinitionFlags = {
lazy: boolean;
scoped: boolean;
broadcastable: boolean;
associative: boolean;
commutative: boolean;
commutativeOrder: (a, b) => number | undefined;
idempotent: boolean;
involution: boolean;
pure: boolean;
};

An operator definition can have some flags to indicate specific properties of the operator.

OperatorDefinitionFlags.lazy

lazy: boolean;

If true, the arguments to this operator are not automatically evaluated. The default is false (the arguments are evaluated).

This can be useful for example for operators that take symbolic expressions as arguments, such as Declare or Integrate.

This is also useful for operators that take an argument that is potentially an infinite collection.

It will be up to the evaluate() handler to evaluate the arguments as needed. This is convenient to pass symbolic expressions as arguments to operators without having to explicitly use a Hold expression.

This also applies to the canonical() handler.

OperatorDefinitionFlags.scoped

scoped: boolean;

If true, the operator requires a new lexical scope when canonicalized. This will allow it to declare variables that are not visible outside the function expression using the operator.

Default: false

OperatorDefinitionFlags.broadcastable

broadcastable: boolean;

If true, the operator is applied element by element to lists, matrices (["List"] or ["Tuple"] expressions) and equations (relational operators).

Default: false

OperatorDefinitionFlags.associative

associative: boolean;

If true, ["f", ["f", a], b] simplifies to ["f", a, b]

Default: false

OperatorDefinitionFlags.commutative

commutative: boolean;

If true, ["f", a, b] equals ["f", b, a]. The canonical version of the function will order the arguments.

Default: false

OperatorDefinitionFlags.commutativeOrder

commutativeOrder: (a, b) => number | undefined;

If commutative is true, the order of the arguments is determined by this function.

If the function is not provided, the arguments are ordered by the default order of the arguments.

OperatorDefinitionFlags.idempotent

idempotent: boolean;

If true, ["f", ["f", x]] simplifies to ["f", x].

Default: false

OperatorDefinitionFlags.involution

involution: boolean;

If true, ["f", ["f", x]] simplifies to x.

Default: false

OperatorDefinitionFlags.pure

pure: boolean;

If true, the value of this operator is always the same for a given set of arguments and it has no side effects.

An expression using this operator is pure if the operator and all its arguments are pure.

For example Sin is pure, Random isn't.

This information may be used to cache the value of expressions.

Default: true

BoxedOperatorDefinition

The definition includes information specific about an operator, such as handlers to canonicalize or evaluate a function expression with this operator.

Extends

BoxedOperatorDefinition.complexity
complexity: number;
BoxedOperatorDefinition.inferredSignature
inferredSignature: boolean;

If true, the signature was inferred from usage and may be modified as more information becomes available.

BoxedOperatorDefinition.signature
signature: BoxedType;

The type of the arguments and return value of this function

BoxedOperatorDefinition.type()?
optional type: (ops, options) => 
| string
| AlgebraicType
| NegationType
| CollectionType
| ListType
| SetType
| MapType
| TupleType
| FunctionSignature
| ValueType
| TypeReference
| BoxedType;

If present, this handler can be used to more precisely determine the return type based on the type of the arguments. The arguments themselves should not be evaluated, only their types should be used.

BoxedOperatorDefinition.sgn()?
optional sgn: (ops, options) => Sign;

If present, this handler can be used to determine the sign of the return value of the function, based on the sign and type of its arguments.

The arguments themselves should not be evaluated, only their types and sign should be used.

This can be used in some case for example to determine when certain simplifications are valid.

BoxedOperatorDefinition.eq()?
optional eq: (a, b) => boolean;
BoxedOperatorDefinition.neq()?
optional neq: (a, b) => boolean;
BoxedOperatorDefinition.canonical()?
optional canonical: (ops, options) => BoxedExpression;
BoxedOperatorDefinition.evaluate()?
optional evaluate: (ops, options) => BoxedExpression;
BoxedOperatorDefinition.evaluateAsync()?
optional evaluateAsync: (ops, options?) => Promise<BoxedExpression>;
BoxedOperatorDefinition.evalDimension()?
optional evalDimension: (ops, options) => BoxedExpression;
BoxedOperatorDefinition.compile()?
optional compile: (expr) => CompiledExpression;

Scope

type Scope = {
parent: Scope | null;
bindings: Map<string, BoxedDefinition>;
};

A lexical scope is a table mapping symbols to their definitions. The symbols are the names of the variables, unknowns and functions in the scope.

The lexical scope is used to resolve the metadata about symbols, such as their type, whether they are constant, etc...

It does not resolve the values of the symbols, since those depend on the evaluation context. For example, the local variables of a recursive function will have the same lexical scope, but different values in each evaluation context.

Latex Parsing and Serialization

LatexToken

type LatexToken = string | "<{>" | "<}>" | "<space>" | "<$>" | "<$$>";

A LatexToken is a token as returned by Parser.peek.

It can be one of the indicated tokens, or a string that starts with a `` for LaTeX commands, or a LaTeX character which includes digits, letters and punctuation.

LatexString

type LatexString = string;

A LatexString is a regular string of LaTeX, for example: \frac{\pi}{2}

Delimiter

type Delimiter = 
| ")"
| "("
| "]"
| "["
| "{"
| "}"
| "<"
| ">"
| "|"
| "||"
| "\lceil"
| "\rceil"
| "\lfloor"
| "\rfloor"
| "\llbracket"
| "\rrbracket";

Open and close delimiters that can be used with MatchfixEntry record to define new LaTeX dictionary entries.

DelimiterScale

type DelimiterScale = "normal" | "scaled" | "big" | "none";

LibraryCategory

type LibraryCategory = 
| "algebra"
| "arithmetic"
| "calculus"
| "collections"
| "control-structures"
| "combinatorics"
| "complex"
| "core"
| "data-structures"
| "dimensions"
| "domains"
| "linear-algebra"
| "logic"
| "numeric"
| "other"
| "physics"
| "polynomials"
| "relop"
| "sets"
| "statistics"
| "styling"
| "symbols"
| "trigonometry"
| "units";

Precedence

type Precedence = number;
THEORY OF OPERATIONS

The precedence of an operator is a number that indicates the order in which operators are applied.

For example, in 1 + 2 * 3, the * operator has a higher precedence than the + operator, so it is applied first.

The precedence range from 0 to 1000. The larger the number, the higher the precedence, the more "binding" the operator is.

Here are some rough ranges for the precedence:

  • 800: prefix and postfix operators: \lnot etc...
    • POSTFIX_PRECEDENCE = 810: !, '
  • 700: some arithmetic operators
    • EXPONENTIATION_PRECEDENCE = 700: ^
  • 600: some binary operators
    • DIVISION_PRECEDENCE = 600: \div
  • 500: not used
  • 400: not used
  • 300: some logic and arithmetic operators: \land, \lor, \times, etc...
    • MULTIPLICATION_PRECEDENCE = 390: \times
  • 200: arithmetic operators, inequalities:
    • ADDITION_PRECEDENCE = 275: + -
    • ARROW_PRECEDENCE = 270: \to \rightarrow
    • ASSIGNMENT_PRECEDENCE = 260: :=
    • COMPARISON_PRECEDENCE = 245: \lt \gt
    • 241: \leq
  • 100: not used
  • 0: ,, ;, etc...

Some constants are defined below for common precedence values.

Note: MathML defines some operator precedence, but it has some issues and inconsistencies. However, whenever possible we adopted the MathML precedence.

The JavaScript operator precedence is documented here.

Terminator

type Terminator = {
minPrec: Precedence;
condition: (parser) => boolean;
};

This indicates a condition under which parsing should stop:

  • an operator of a precedence higher than specified has been encountered
  • the last token has been reached
  • or if a condition is provided, the condition returns true

ParseHandler

type ParseHandler = 
| ExpressionParseHandler
| SymbolParseHandler
| FunctionParseHandler
| EnvironmentParseHandler
| PostfixParseHandler
| InfixParseHandler
| MatchfixParseHandler;

Custom parsing handler.

When this handler is invoked the parser points right after the LaTeX fragment that triggered it.

Tokens can be consumed with parser.nextToken() and other parser methods such as parser.parseGroup(), parser.parseOptionalGroup(), etc...

If it was in an infix or postfix context, lhs will represent the left-hand side argument. In a prefix or matchfix context, lhs is null.

In a superfix (^) or subfix (_) context (that is if the first token of the trigger is ^ or _), lhs is ["Superscript", lhs, rhs] and ["Subscript", lhs, rhs], respectively.

The handler should return null if the tokens could not be parsed (didn't match the syntax that was expected), or the matching expression otherwise.

If the tokens were parsed but should be ignored, the handler should return Nothing.

ExpressionParseHandler()

type ExpressionParseHandler = (parser, until?) => Expression | null;

PrefixParseHandler()

type PrefixParseHandler = (parser, until?) => Expression | null;

SymbolParseHandler()

type SymbolParseHandler = (parser, until?) => Expression | null;

FunctionParseHandler()

type FunctionParseHandler = (parser, until?) => Expression | null;

EnvironmentParseHandler()

type EnvironmentParseHandler = (parser, until?) => Expression | null;

PostfixParseHandler()

type PostfixParseHandler = (parser, lhs, until?) => Expression | null;

InfixParseHandler()

type InfixParseHandler = (parser, lhs, until) => Expression | null;

MatchfixParseHandler()

type MatchfixParseHandler = (parser, body) => Expression | null;

LatexArgumentType

type LatexArgumentType = 
| "{expression}"
| "[expression]"
| "{text}"
| "[text]"
| "{unit}"
| "[unit]"
| "{glue}"
| "[glue]"
| "{string}"
| "[string]"
| "{color}"
| "[color]";

Trigger

type Trigger = {
latexTrigger: | LatexString
| LatexToken[];
symbolTrigger: MathJsonSymbol;
};

A trigger is the set of tokens that will make an entry in the LaTeX dictionary eligible to parse the stream and generate an expression. If the trigger matches, the parse handler is called, if available.

The trigger can be specified either as a LaTeX string (latexTrigger) or as an symbol (symbolTrigger). A symbol match several LaTeX expressions that are equivalent, for example \operatorname{gcd} or \mathbin{gcd}, match the "gcd" symbol

matchfix operators use openTrigger and closeTrigger instead.

BaseEntry

type BaseEntry = {
name: MathJsonSymbol;
serialize: | LatexString
| SerializeHandler;
};

Maps a string of LaTeX tokens to a function or symbol and vice-versa.

BaseEntry.name?

optional name: MathJsonSymbol;

Map a MathJSON symbol to this entry.

Each entry should have at least a name or a parse handler.

An entry with no name cannot be serialized: the name is used to map a MathJSON function or symbol name to the appropriate entry for serializing.

However, an entry with no name can be used to define a synonym (for example for the symbol \varnothing which is a synonym for \emptyset).

If no parse handler is provided, only the trigger is used to select this entry. Otherwise, if the trigger of the entry matches the current token, the parse handler is invoked.

BaseEntry.serialize?

optional serialize: 
| LatexString
| SerializeHandler;

Transform an expression into a LaTeX string. If no serialize handler is provided, the trigger is used.

DefaultEntry

type DefaultEntry = BaseEntry & Trigger & {
parse: | Expression
| ExpressionParseHandler;
};

ExpressionEntry

type ExpressionEntry = BaseEntry & Trigger & {
kind: "expression";
parse: | Expression
| ExpressionParseHandler;
precedence: Precedence;
};

MatchfixEntry

type MatchfixEntry = BaseEntry & {
kind: "matchfix";
openTrigger: Delimiter | LatexToken[];
closeTrigger: Delimiter | LatexToken[];
parse: MatchfixParseHandler;
};

MatchfixEntry.openTrigger

openTrigger: Delimiter | LatexToken[];

If kind is 'matchfix': the openTrigger and closeTrigger properties are required.

MatchfixEntry.parse?

optional parse: MatchfixParseHandler;

When invoked, the parser is pointing after the close delimiter. The argument of the handler is the body, i.e. the content between the open delimiter and the close delimiter.

InfixEntry

type InfixEntry = BaseEntry & Trigger & {
kind: "infix";
associativity: "right" | "left" | "none" | "any";
precedence: Precedence;
parse: string | InfixParseHandler;
};

InfixEntry.kind

kind: "infix";

Infix position, with an operand before and an operand after: a ⊛ b.

Example: +, \times.

InfixEntry.associativity?

optional associativity: "right" | "left" | "none" | "any";
  • none: a ? b ? c -> syntax error

  • any: a + b + c -> +(a, b, c)

  • left: a / b / c -> /(/(a, b), c)

  • right: a = b = c -> =(a, =(b, c))

  • any-associative operators have an unlimited number of arguments

  • left, right or none associative operators have two arguments

PostfixEntry

type PostfixEntry = BaseEntry & Trigger & {
kind: "postfix";
precedence: Precedence;
parse: string | PostfixParseHandler;
};

PostfixEntry.kind

kind: "postfix";

Postfix position, with an operand before: a ⊛

Example: !.

PrefixEntry

type PrefixEntry = BaseEntry & Trigger & {
kind: "prefix";
precedence: Precedence;
parse: string | PrefixParseHandler;
};

PrefixEntry.kind

kind: "prefix";

Prefix position, with an operand after: ⊛ a

Example: -, \not.

EnvironmentEntry

type EnvironmentEntry = BaseEntry & {
kind: "environment";
parse: EnvironmentParseHandler;
symbolTrigger: MathJsonSymbol;
};

A LaTeX dictionary entry for an environment, that is a LaTeX construct using \begin{...}...\end{...}.

SymbolEntry

type SymbolEntry = BaseEntry & Trigger & {
kind: "symbol";
precedence: Precedence;
parse: | Expression
| SymbolParseHandler;
};

SymbolEntry.precedence?

optional precedence: Precedence;

Used for appropriate wrapping (i.e. when to surround it with parens)

FunctionEntry

type FunctionEntry = BaseEntry & Trigger & {
kind: "function";
parse: | Expression
| FunctionParseHandler;
};

A function is a symbol followed by:

  • some postfix operators such as \prime
  • an optional list of arguments in an enclosure (parentheses)

For more complex situations, for example implicit arguments or inverse functions postfix (i.e. ^-1), use a custom parse handler with a entry of kind expression.

LatexDictionaryEntry

type LatexDictionaryEntry = OneOf<[
| ExpressionEntry
| MatchfixEntry
| InfixEntry
| PostfixEntry
| PrefixEntry
| SymbolEntry
| FunctionEntry
| EnvironmentEntry
| DefaultEntry]>;

A dictionary entry is a record that maps a LaTeX token or string of tokens ( a trigger) to a MathJSON expression or to a parsing handler.

Set the ComputeEngine.latexDictionary property to an array of dictionary entries to define custom LaTeX parsing and serialization.

ParseLatexOptions

type ParseLatexOptions = NumberFormat & {
skipSpace: boolean;
parseNumbers: "auto" | "rational" | "decimal" | "never";
getSymbolType: (symbol) => BoxedType;
parseUnexpectedToken: (lhs, parser) => Expression | null;
preserveLatex: boolean;
};

The LaTeX parsing options can be used with the ce.parse() method.

ParseLatexOptions.skipSpace

skipSpace: boolean;

If true, ignore space characters in math mode.

Default: true

ParseLatexOptions.parseNumbers

parseNumbers: "auto" | "rational" | "decimal" | "never";

When parsing a decimal number, e.g. 3.1415:

  • "auto" or "decimal": if a decimal number, parse it as an approximate decimal number with a whole part and a fractional part
  • "rational": if a decimal number, parse it as an exact rational number with a numerator and a denominator. If not a decimal number, parse it as a regular number.
  • "never": do not parse numbers, instead return each token making up the number (minus sign, digits, decimal marker, etc...).

Note: if the number includes repeating digits (e.g. 1.33(333)), it will be parsed as a decimal number even if this setting is "rational".

Default: "auto"

ParseLatexOptions.getSymbolType()

getSymbolType: (symbol) => BoxedType;

This handler is invoked when the parser encounters a that has not yet been declared.

The symbol argument is a valid symbol.

ParseLatexOptions.parseUnexpectedToken()

parseUnexpectedToken: (lhs, parser) => Expression | null;

This handler is invoked when the parser encounters an unexpected token.

The lhs argument is the left-hand side of the token, if any.

The handler can access the unexpected token with parser.peek. If it is a token that should be recognized, the handler can consume it by calling parser.nextToken().

The handler should return an expression or null if the token is not recognized.

ParseLatexOptions.preserveLatex

preserveLatex: boolean;

If true, the expression will be decorated with the LaTeX fragments corresponding to each elements of the expression.

The top-level expression, that is the one returned by parse(), will include the verbatim LaTeX input that was parsed. The sub-expressions may contain a slightly different LaTeX, for example with consecutive spaces replaced by one, with comments removed and with some low-level LaTeX commands replaced, for example \egroup and \bgroup.

Default: false

Parser

An instance of Parser is provided to the parse handlers of custom LaTeX dictionary entries.

Parser.options
readonly options: Required<ParseLatexOptions>;
Parser.index
index: number;

The index of the current token

Parser.atEnd
readonly atEnd: boolean;

True if the last token has been reached. Consider also atTerminator().

Parser.peek
readonly peek: string;

Return the next token, without advancing the index

Parser.atBoundary
Parser.getSymbolType()
getSymbolType(id): BoxedType

####### id

string

Parser.pushSymbolTable()
pushSymbolTable(): void
Parser.popSymbolTable()
popSymbolTable(): void
Parser.addSymbol()
addSymbol(id, type): void

####### id

string

####### type

string | BoxedType

Parser.atTerminator()
atTerminator(t): boolean

Return true if the terminator condition is met or if the last token has been reached.

####### t

Terminator

Parser.nextToken()
nextToken(): string

Return the next token and advance the index

Parser.latex()
latex(start, end?): string

Return a string representation of the expression between start and end (default: the whole expression)

####### start

number

####### end?

number

Parser.error()
error(code, fromToken): Expression

Return an error expression with the specified code and arguments

####### code

string | [string, ...Expression[]]

####### fromToken

number

Parser.skipSpace()
skipSpace(): boolean

If there are any space, advance the index until a non-space is encountered

Parser.skipVisualSpace()
skipVisualSpace(): void

Skip over "visual space" which includes space tokens, empty groups {}, and commands such as \, and \!

Parser.match()
match(token): boolean

If the next token matches the target advance and return true. Otherwise return false

####### token

string

Parser.matchAll()
matchAll(tokens): boolean

Return true if the next tokens match the argument, an array of tokens, or null otherwise

####### tokens

string[]

Parser.matchAny()
matchAny(tokens): string

Return the next token if it matches any of the token in the argument or null otherwise

####### tokens

string[]

Parser.matchChar()
matchChar(): string

If the next token is a character, return it and advance the index This includes plain characters (e.g. 'a', '+'...), characters defined in hex (^^ and ^^^^), the \char and \unicode command.

Parser.parseGroup()
parseGroup(): Expression

Parse an expression in a LaTeX group enclosed in curly brackets {}. These are often used as arguments to LaTeX commands, for example \frac{1}{2}.

Return null if none was found Return Nothing if an empty group {} was found

Parser.parseToken()
parseToken(): Expression

Some LaTeX commands (but not all) can accept arguments as single tokens (i.e. without braces), for example ^2, \sqrt3 or \frac12

This argument will usually be a single token, but can be a sequence of tokens (e.g. \sqrt\frac12 or \sqrt\operatorname{speed}).

The following tokens are excluded from consideration in order to fail early when encountering a likely syntax error, for example x^(2) instead of x^{2}. With ( in the list of excluded tokens, the match will fail and the error can be recovered.

The excluded tokens include !"#$%&(),/;:?@[]|~", \left, \bigl, etc...

Parser.parseOptionalGroup()
parseOptionalGroup(): Expression

Parse an expression enclosed in a LaTeX optional group enclosed in square brackets [].

Return null if none was found.

Parser.parseEnclosure()
parseEnclosure(): Expression

Parse an enclosure (open paren/close paren, etc..) and return the expression inside the enclosure

Parser.parseStringGroup()
parseStringGroup(optional?): string

Some LaTeX commands have arguments that are not interpreted as expressions, but as strings. For example, \begin{array}{ccc} (both array and ccc are strings), \color{red} or \operatorname{lim sup}.

If the next token is the start of a group ({), return the content of the group as a string. This may include white space, and it may need to be trimmed at the start and end of the string.

LaTeX commands are typically not allowed inside a string group (for example, \alpha would result in an error), but we do not enforce this.

If optional is true, this should be an optional group in square brackets otherwise it is a regular group in braces.

####### optional?

boolean

Parser.parseSymbol()
parseSymbol(until?): Expression

A symbol can be:

  • a single-letter symbol: x
  • a single LaTeX command: \pi
  • a multi-letter symbol: \operatorname{speed}

####### until?

Partial<Terminator>

Parser.parseTabular()
parseTabular(): Expression[][]

Parse an expression in a tabular format, where rows are separated by \\ and columns by &.

Return rows of sparse columns: empty rows are indicated with Nothing, and empty cells are also indicated with Nothing.

Parser.parseArguments()
parseArguments(kind?, until?): readonly Expression[]

Parse an argument list, for example: (12, x+1) or \left(x\right)

  • 'enclosure' : will look for arguments inside an enclosure (an open/close fence) (default)
  • 'implicit': either an expression inside a pair of (), or just a primary (i.e. we interpret \cos x + 1 as \cos(x) + 1)

Return an array of expressions, one for each argument, or null if no argument was found.

####### kind?

"implicit" | "enclosure"

####### until?

Terminator

Parser.parsePostfixOperator()
parsePostfixOperator(lhs, until?): Expression

Parse a postfix operator, such as ' or !.

Prefix, infix and matchfix operators are handled by parseExpression()

####### lhs

Expression

####### until?

Partial<Terminator>

Parser.parseExpression()
parseExpression(until?): Expression

Parse an expression:

<expression> ::=
| <primary> ( <infix-op> <expression> )?
| <prefix-op> <expression>

<primary> :=
(<number> | <symbol> | <function-call> | <matchfix-expr>)
(<subsup> | <postfix-operator>)*

<matchfix-expr> :=
<matchfix-op-open> <expression> <matchfix-op-close>

<function-call> ::=
| <function><matchfix-op-group-open><expression>[',' <expression>]<matchfix-op-group-close>

This is the top-level parsing entry point.

Stop when an operator of precedence less than until.minPrec or the sequence of tokens until.tokens is encountered

until is { minPrec:0 } by default.

####### until?

Partial<Terminator>

Parser.parseNumber()
parseNumber(): Expression

Parse a number.

Parser.addBoundary()
addBoundary(boundary): void

Boundaries are used to detect the end of an expression.

They are used for unusual syntactic constructs, for example \int \sin x dx where the dx is not an argument to the \sin function, but a boundary of the integral.

They are also useful when handling syntax errors and recovery.

For example, \begin{bmatrix} 1 & 2 { \end{bmatrix} has an extraneous {, but the parser will attempt to recover and continue parsing when it encounters the \end{bmatrix} boundary.

####### boundary

string[]

Parser.removeBoundary()
removeBoundary(): void
Parser.matchBoundary()
matchBoundary(): boolean
Parser.boundaryError()
boundaryError(msg): Expression

####### msg

string | [string, ...Expression[]]

SerializeLatexOptions

type SerializeLatexOptions = NumberSerializationFormat & {
prettify: boolean;
invisibleMultiply: LatexString;
invisiblePlus: LatexString;
multiply: LatexString;
missingSymbol: LatexString;
applyFunctionStyle: (expr, level) => DelimiterScale;
groupStyle: (expr, level) => DelimiterScale;
rootStyle: (expr, level) => "radical" | "quotient" | "solidus";
fractionStyle: (expr, level) =>
| "quotient"
| "block-quotient"
| "inline-quotient"
| "inline-solidus"
| "nice-solidus"
| "reciprocal"
| "factor";
logicStyle: (expr, level) => "word" | "boolean" | "uppercase-word" | "punctuation";
powerStyle: (expr, level) => "root" | "solidus" | "quotient";
numericSetStyle: (expr, level) => "compact" | "regular" | "interval" | "set-builder";
};

The LaTeX serialization options can used with the expr.toLatex() method.

SerializeLatexOptions.prettify

prettify: boolean;

If true, prettify the LaTeX output.

For example, render \frac{a}{b}\frac{c}{d} as \frac{ac}{bd}

SerializeLatexOptions.invisibleMultiply

invisibleMultiply: LatexString;

LaTeX string used to render an invisible multiply, e.g. in '2x'.

If empty, both operands are concatenated, i.e. 2x.

Use \cdot to insert a \cdot operator between them, i.e. 2 \cdot x.

Empty by default.

SerializeLatexOptions.invisiblePlus

invisiblePlus: LatexString;

LaTeX string used to render mixed numbers e.g. '1 3/4'.

Leave it empty to join the main number and the fraction, i.e. render it as 1\frac{3}{4}.

Use + to insert an explicit + operator between them, i.e. 1+\frac{3}{4}

Empty by default.

SerializeLatexOptions.multiply

multiply: LatexString;

LaTeX string used to render an explicit multiply operator.

For example, \times, \cdot, etc...

Default: \times

SerializeLatexOptions.missingSymbol

missingSymbol: LatexString;

Serialize the expression ["Error", "'missing'"], with this LaTeX string

Serializer

An instance of Serializer is provided to the serialize handlers of custom LaTeX dictionary entries.

Serializer.options
readonly options: Required<SerializeLatexOptions>;
Serializer.dictionary
readonly dictionary: IndexedLatexDictionary;
Serializer.level
level: number;

"depth" of the expression:

  • 0 for the root
  • 1 for a subexpression of the root
  • 2 for subexpressions of the subexpressions of the root
  • etc...

This allows the serialized LaTeX to vary depending on the depth of the expression.

For example use \Bigl( for the top level, and \bigl( or ( for others.

Serializer.serialize()
serialize: (expr) => string;

Output a LaTeX string representing the expression

Serializer.wrap()
wrap: (expr, prec?) => string;

Add a group fence around the expression if it is an operator of precedence less than or equal to prec.

Serializer.applyFunctionStyle()
applyFunctionStyle: (expr, level) => DelimiterScale;

Styles

Serializer.groupStyle()
groupStyle: (expr, level) => DelimiterScale;
Serializer.rootStyle()
rootStyle: (expr, level) => "radical" | "quotient" | "solidus";
Serializer.fractionStyle()
fractionStyle: (expr, level) => 
| "quotient"
| "block-quotient"
| "inline-quotient"
| "inline-solidus"
| "nice-solidus"
| "reciprocal"
| "factor";
Serializer.logicStyle()
logicStyle: (expr, level) => "boolean" | "word" | "uppercase-word" | "punctuation";
Serializer.powerStyle()
powerStyle: (expr, level) => "quotient" | "solidus" | "root";
Serializer.numericSetStyle()
numericSetStyle: (expr, level) => "interval" | "compact" | "regular" | "set-builder";
Serializer.serializeFunction()
serializeFunction(expr, def?): string

####### expr

Expression

####### def?

IndexedLatexDictionaryEntry

Serializer.serializeSymbol()
serializeSymbol(expr): string

####### expr

Expression

Serializer.wrapString()
wrapString(s, style, delimiters?): string

Output s surrounded by delimiters.

If delimiters is not specified, use ()

####### s

string

####### style

DelimiterScale

####### delimiters?

string

Serializer.wrapArguments()
wrapArguments(expr): string

A string with the arguments of expr fenced appropriately and separated by commas.

####### expr

Expression

Serializer.wrapShort()
wrapShort(expr): string

Add a group fence around the expression if it is short (not a function)

####### expr

Expression

SerializeHandler()

type SerializeHandler = (serializer, expr) => string;

The serialize handler of a custom LaTeX dictionary entry can be a function of this type.

Numerics

Sign

type Sign = 
| "zero"
| "positive"
| "negative"
| "non-negative"
| "non-positive"
| "not-zero"
| "unsigned";

ExactNumericValueData

type ExactNumericValueData = {
rational: Rational;
radical: number;
};

The value is equal to (decimal * rational * sqrt(radical)) + im * i

NumericValueData

type NumericValueData = {
re: Decimal | number;
im: number;
};

NumericValueFactory()

type NumericValueFactory = (data) => NumericValue;

abstract NumericValue

new NumericValue()
new NumericValue(): NumericValue
NumericValue.im
im: number;

The imaginary part of this numeric value.

Can be negative, zero or positive.

NumericValue.type
NumericValue.isExact

True if numeric value is the product of a rational and the square root of an integer.

This includes: 3/4√5, -2, √2, etc...

But it doesn't include 0.5, 3.141592, etc...

NumericValue.asExact

If isExact(), returns an ExactNumericValue, otherwise returns undefined.

NumericValue.re

The real part of this numeric value.

Can be negative, 0 or positive.

NumericValue.bignumRe

bignum version of .re, if available

NumericValue.bignumIm
NumericValue.numerator
NumericValue.denominator
NumericValue.isNaN
NumericValue.isPositiveInfinity
NumericValue.isNegativeInfinity
NumericValue.isComplexInfinity
NumericValue.isZero
NumericValue.isOne
NumericValue.isNegativeOne
NumericValue.isZeroWithTolerance()
isZeroWithTolerance(_tolerance): boolean

####### _tolerance

number | Decimal

NumericValue.sgn()
abstract sgn(): -1 | 0 | 1

The sign of complex numbers is undefined

NumericValue.N()
abstract N(): NumericValue

Return a non-exact representation of the numeric value

NumericValue.neg()
abstract neg(): NumericValue
NumericValue.inv()
abstract inv(): NumericValue
NumericValue.add()
abstract add(other): NumericValue

####### other

number | NumericValue

NumericValue.sub()
abstract sub(other): NumericValue

####### other

NumericValue

NumericValue.mul()
abstract mul(other): NumericValue

####### other

number | Decimal | NumericValue

NumericValue.div()
abstract div(other): NumericValue

####### other

number | NumericValue

NumericValue.pow()
abstract pow(n): NumericValue

####### n

number | NumericValue | { re: number; im: number; }

NumericValue.root()
abstract root(n): NumericValue

####### n

number

NumericValue.sqrt()
abstract sqrt(): NumericValue
NumericValue.gcd()
abstract gcd(other): NumericValue

####### other

NumericValue

NumericValue.abs()
abstract abs(): NumericValue
NumericValue.ln()
abstract ln(base?): NumericValue

####### base?

number

NumericValue.exp()
abstract exp(): NumericValue
NumericValue.floor()
abstract floor(): NumericValue
NumericValue.ceil()
abstract ceil(): NumericValue
NumericValue.round()
abstract round(): NumericValue
NumericValue.eq()
abstract eq(other): boolean

####### other

number | NumericValue

NumericValue.lt()
abstract lt(other): boolean

####### other

number | NumericValue

NumericValue.lte()
abstract lte(other): boolean

####### other

number | NumericValue

NumericValue.gt()
abstract gt(other): boolean

####### other

number | NumericValue

NumericValue.gte()
abstract gte(other): boolean

####### other

number | NumericValue

NumericValue.valueOf()
valueOf(): string | number

Object.valueOf(): returns a primitive value, preferably a JavaScript number over a string, even if at the expense of precision

NumericValue.[toPrimitive]()
toPrimitive: string | number

Object.toPrimitive()

####### hint

"string" | "number" | "default"

NumericValue.toJSON()
toJSON(): any

Object.toJSON

NumericValue.print()
print(): void

SmallInteger

type SmallInteger = IsInteger<number>;

A SmallInteger is an integer < 1e6

Rational

type Rational = 
| [SmallInteger, SmallInteger]
| [bigint, bigint];

A rational number is a number that can be expressed as the quotient or fraction p/q of two integers, a numerator p and a non-zero denominator q.

A rational can either be represented as a pair of small integers or a pair of big integers.

BigNum

type BigNum = Decimal;

IBigNum

IBigNum._BIGNUM_NAN
readonly _BIGNUM_NAN: Decimal;
IBigNum._BIGNUM_ZERO
readonly _BIGNUM_ZERO: Decimal;
IBigNum._BIGNUM_ONE
readonly _BIGNUM_ONE: Decimal;
IBigNum._BIGNUM_TWO
readonly _BIGNUM_TWO: Decimal;
IBigNum._BIGNUM_HALF
readonly _BIGNUM_HALF: Decimal;
IBigNum._BIGNUM_PI
readonly _BIGNUM_PI: Decimal;
IBigNum._BIGNUM_NEGATIVE_ONE
readonly _BIGNUM_NEGATIVE_ONE: Decimal;
IBigNum.bignum()
bignum(value): Decimal

####### value

string | number | bigint | Decimal

Other

TaggedValueDefinition

type TaggedValueDefinition = {
value: BoxedValueDefinition;
};

TaggedOperatorDefinition

type TaggedOperatorDefinition = {
operator: BoxedOperatorDefinition;
};

SymbolTable

type SymbolTable = {
parent: SymbolTable | null;
ids: {};
};

BigNumFactory()

type BigNumFactory = (value) => Decimal;

Serialization

JsonSerializationOptions

type JsonSerializationOptions = {
prettify: boolean;
exclude: string[];
shorthands: ("all" | "number" | "symbol" | "function" | "string")[];
metadata: ("all" | "wikidata" | "latex")[];
repeatingDecimal: boolean;
fractionalDigits: "auto" | "max" | number;
};

Options to control the serialization to MathJSON when using BoxedExpression.toMathJson().

JsonSerializationOptions.prettify

prettify: boolean;

If true, the serialization applies some transformations to make the JSON more readable. For example, ["Power", "x", 2] is serialized as ["Square", "x"].

JsonSerializationOptions.exclude

exclude: string[];

A list of space separated function names that should be excluded from the JSON output.

Those functions are replaced with an equivalent, for example, Square with Power, etc...

Possible values include Sqrt, Root, Square, Exp, Subtract, Rational, Complex

Default: [] (none)

JsonSerializationOptions.shorthands

shorthands: ("all" | "number" | "symbol" | "function" | "string")[];

A list of space separated keywords indicating which MathJSON expressions can use a shorthand.

Default: ["all"]

JsonSerializationOptions.metadata

metadata: ("all" | "wikidata" | "latex")[];

A list of space separated keywords indicating which metadata should be included in the MathJSON. If metadata is included, shorthand notation is not used.

Default: [] (none)

JsonSerializationOptions.repeatingDecimal

repeatingDecimal: boolean;

If true, repeating decimals are detected and serialized accordingly For example:

  • 1.3333333333333333 ( \to ) 1.(3)
  • 0.142857142857142857142857142857142857142857142857142 ( \to ) 0.(1428571)

Default: true

JsonSerializationOptions.fractionalDigits

fractionalDigits: "auto" | "max" | number;

The maximum number of significant digits in serialized numbers.

  • "max": all availabe digits are serialized.
  • "auto": use the same precision as the compute engine.

Default: "auto"

NumberFormat

type NumberFormat = {
positiveInfinity: LatexString;
negativeInfinity: LatexString;
notANumber: LatexString;
imaginaryUnit: LatexString;
decimalSeparator: LatexString;
digitGroupSeparator: | LatexString
| [LatexString, LatexString];
digitGroup: "lakh" | number | [number | "lakh", number];
exponentProduct: LatexString;
beginExponentMarker: LatexString;
endExponentMarker: LatexString;
truncationMarker: LatexString;
repeatingDecimal: "auto" | "vinculum" | "dots" | "parentheses" | "arc" | "none";
};

These options control how numbers are parsed and serialized.

NumberFormat.decimalSeparator

decimalSeparator: LatexString;

A string representing the decimal separator, the string separating the whole portion of a number from the fractional portion, i.e. the "." in "3.1415".

Some countries use a comma rather than a dot. In this case it is recommended to use "{,}" as the separator: the surrounding brackets ensure there is no additional gap after the comma.

Default: "."

NumberFormat.digitGroupSeparator

digitGroupSeparator: 
| LatexString
| [LatexString, LatexString];

A string representing the separator between groups of digits, to make numbers with many digits easier to read.

If a single string is provided, it is used to group digits in the whole and the fractional part of the number. If two strings are provided, the first is used for the whole part and the second for the fractional part.

Caution: some values may lead to unexpected results.

For example, if the digitGroupSeparator is , (comma) the expression \operatorname{Hypot}(1,2) will parse as ["Hypot", 1.2] rather than ["Hypot", 1, 2]. You can however use {,} which will avoid this issue and display with correct spacing.

Default: "\\," (thin space, 3/18mu) (Resolution 7 of the 1948 CGPM)

NumberFormat.digitGroup

digitGroup: "lakh" | number | [number | "lakh", number];

Maximum length of digits between digit group separators.

If a single number is provided, it is used for the whole and the fractional part of the number. If two numbers are provided, the first is used for the whole part and the second for the fractional part.

If '"lakh"' is provided, the number is grouped in groups of 2 digits, except for the last group which has 3 digits. For example: 1,00,00,000.

Default: 3

NumberSerializationFormat

type NumberSerializationFormat = NumberFormat & {
fractionalDigits: "auto" | "max" | number;
notation: "auto" | "engineering" | "scientific";
avoidExponentsInRange: undefined | null | [number, number];
};

NumberSerializationFormat.fractionalDigits

fractionalDigits: "auto" | "max" | number;

The maximum number of significant digits in serialized numbers.

  • "max": all availabe digits are serialized.
  • "auto": use the same precision as the compute engine.

Default: "auto"

Tensors

DataTypeMap

type DataTypeMap = {
float64: number;
float32: number;
int32: number;
uint8: number;
complex128: Complex;
complex64: Complex;
bool: boolean;
expression: BoxedExpression;
};

Map of TensorDataType to JavaScript type.

TensorDataType

type TensorDataType = keyof DataTypeMap;

The type of the cells in a tensor.

TensorData<DT>

A record representing the type, shape and data of a tensor.

Extended by

TensorData.dtype
dtype: DT;
TensorData.shape
shape: number[];
TensorData.rank?
optional rank: number;
TensorData.data
data: DataTypeMap[DT][];

TensorField<T>

TensorField.one
readonly one: T;
TensorField.zero
readonly zero: T;
TensorField.nan
readonly nan: T;
TensorField.cast()
cast(x, dtype)
cast(x, dtype): number

####### x

T

####### dtype

"float64"

cast(x, dtype)
cast(x, dtype): number

####### x

T

####### dtype

"float32"

cast(x, dtype)
cast(x, dtype): number

####### x

T

####### dtype

"int32"

cast(x, dtype)
cast(x, dtype): number

####### x

T

####### dtype

"uint8"

cast(x, dtype)
cast(x, dtype): any

####### x

T

####### dtype

"complex128"

cast(x, dtype)
cast(x, dtype): any

####### x

T

####### dtype

"complex64"

cast(x, dtype)
cast(x, dtype): boolean

####### x

T

####### dtype

"bool"

cast(x, dtype)
cast(x, dtype): BoxedExpression

####### x

T

####### dtype

"expression"

cast(x, dtype)
cast(x, dtype): number[]

####### x

T[]

####### dtype

"float64"

cast(x, dtype)
cast(x, dtype): number[]

####### x

T[]

####### dtype

"float32"

cast(x, dtype)
cast(x, dtype): number[]

####### x

T[]

####### dtype

"int32"

cast(x, dtype)
cast(x, dtype): number[]

####### x

T[]

####### dtype

"uint8"

cast(x, dtype)
cast(x, dtype): Complex[]

####### x

T[]

####### dtype

"complex128"

cast(x, dtype)
cast(x, dtype): Complex[]

####### x

T[]

####### dtype

"complex64"

cast(x, dtype)
cast(x, dtype): boolean[]

####### x

T[]

####### dtype

"bool"

cast(x, dtype)
cast(x, dtype): BoxedExpression[]

####### x

T[]

####### dtype

"expression"

cast(x, dtype)
cast(x, dtype): any

####### x

T | T[]

####### dtype

keyof DataTypeMap

TensorField.expression()
expression(x): BoxedExpression

####### x

T

TensorField.isZero()
isZero(x): boolean

####### x

T

TensorField.isOne()
isOne(x): boolean

####### x

T

TensorField.equals()
equals(lhs, rhs): boolean

####### lhs

T

####### rhs

T

TensorField.add()
add(lhs, rhs): T

####### lhs

T

####### rhs

T

TensorField.addn()
addn(...xs): T

####### xs

...T[]

TensorField.neg()
neg(x): T

####### x

T

TensorField.sub()
sub(lhs, rhs): T

####### lhs

T

####### rhs

T

TensorField.mul()
mul(lhs, rhs): T

####### lhs

T

####### rhs

T

TensorField.muln()
muln(...xs): T

####### xs

...T[]

TensorField.div()
div(lhs, rhs): T

####### lhs

T

####### rhs

T

TensorField.pow()
pow(rhs, n): T

####### rhs

T

####### n

number

TensorField.conjugate()
conjugate(x): T

####### x

T

Tensor<DT>

Extends

Tensor.dtype
dtype: DT;
Tensor.shape
shape: number[];
Tensor.rank
rank: number;
Tensor.data
data: DataTypeMap[DT][];
Tensor.field
readonly field: TensorField<DT>;
Tensor.expression
readonly expression: BoxedExpression;
Tensor.array
readonly array: NestedArray<DataTypeMap[DT]>;
Tensor.isSquare
readonly isSquare: boolean;
Tensor.isSymmetric
readonly isSymmetric: boolean;
Tensor.isSkewSymmetric
readonly isSkewSymmetric: boolean;
Tensor.isDiagonal
readonly isDiagonal: boolean;
Tensor.isUpperTriangular
readonly isUpperTriangular: boolean;
Tensor.isLowerTriangular
readonly isLowerTriangular: boolean;
Tensor.isTriangular
readonly isTriangular: boolean;
Tensor.isIdentity
readonly isIdentity: boolean;
Tensor.isZero
readonly isZero: boolean;
Tensor.at()
at(...indices): DataTypeMap[DT]

####### indices

...number[]

Tensor.diagonal()
diagonal(axis1?, axis2?): DataTypeMap[DT][]

####### axis1?

number

####### axis2?

number

Tensor.trace()
trace(axis1?, axis2?): DataTypeMap[DT]

####### axis1?

number

####### axis2?

number

Tensor.reshape()
reshape(...shape): Tensor<DT>

####### shape

...number[]

Tensor.flatten()
flatten(): DataTypeMap[DT][]
Tensor.upcast()
upcast<DT>(dtype): Tensor<DT>

• DT extends keyof DataTypeMap

####### dtype

DT

Tensor.transpose()
transpose(axis1?, axis2?): Tensor<DT>

####### axis1?

number

####### axis2?

number

Tensor.conjugateTranspose()
conjugateTranspose(axis1?, axis2?): Tensor<DT>

####### axis1?

number

####### axis2?

number

Tensor.determinant()
determinant(): DataTypeMap[DT]
Tensor.inverse()
inverse(): Tensor<DT>
Tensor.pseudoInverse()
pseudoInverse(): Tensor<DT>
Tensor.adjugateMatrix()
adjugateMatrix(): Tensor<DT>
Tensor.minor()
minor(axis1, axis2): DataTypeMap[DT]

####### axis1

number

####### axis2

number

Tensor.map1()
map1(fn, scalar): Tensor<DT>

####### fn

(lhs, rhs) => DataTypeMap[DT]

####### scalar

DataTypeMap[DT]

Tensor.map2()
map2(fn, rhs): Tensor<DT>

####### fn

(lhs, rhs) => DataTypeMap[DT]

####### rhs

Tensor<DT>

Tensor.add()
add(other): Tensor<DT>

####### other

Tensor<DT> | DataTypeMap[DT]

Tensor.subtract()
subtract(other): Tensor<DT>

####### other

Tensor<DT> | DataTypeMap[DT]

Tensor.multiply()
multiply(other): Tensor<DT>

####### other

Tensor<DT> | DataTypeMap[DT]

Tensor.divide()
divide(other): Tensor<DT>

####### other

Tensor<DT> | DataTypeMap[DT]

Tensor.power()
power(other): Tensor<DT>

####### other

Tensor<DT> | DataTypeMap[DT]

Tensor.equals()
equals(other): boolean

####### other

Tensor<DT>

Type

BoxedType

new BoxedType()
new BoxedType(type): BoxedType

####### type

string | AlgebraicType | NegationType | CollectionType | ListType | SetType | MapType | TupleType | FunctionSignature | ValueType | TypeReference

BoxedType.unknown
static unknown: BoxedType;
BoxedType.number
static number: BoxedType;
BoxedType.non_finite_number
static non_finite_number: BoxedType;
BoxedType.finite_number
static finite_number: BoxedType;
BoxedType.finite_integer
static finite_integer: BoxedType;
BoxedType.finite_real
static finite_real: BoxedType;
BoxedType.string
static string: BoxedType;
BoxedType.type
type: Type;
BoxedType.isUnknown
BoxedType.matches()
matches(other): boolean

####### other

string | AlgebraicType | NegationType | CollectionType | ListType | SetType | MapType | TupleType | FunctionSignature | ValueType | TypeReference | BoxedType

BoxedType.is()
is(other): boolean

####### other

string | AlgebraicType | NegationType | CollectionType | ListType | SetType | MapType | TupleType | FunctionSignature | ValueType | TypeReference

BoxedType.toString()
toString(): string
BoxedType.toJSON()
toJSON(): string
BoxedType.[toPrimitive]()
toPrimitive: string

####### hint

string

BoxedType.valueOf()
valueOf(): string

MathJSON

MathJsonAttributes

type MathJsonAttributes = {
comment: string;
documentation: string;
latex: string;
wikidata: string;
wikibase: string;
openmathSymbol: string;
openmathCd: string;
sourceUrl: string;
sourceContent: string;
sourceOffsets: [number, number];
};

MathJsonAttributes.comment?

optional comment: string;

A human readable string to annotate this expression, since JSON does not allow comments in its encoding

MathJsonAttributes.documentation?

optional documentation: string;

A Markdown-encoded string providing documentation about this expression.

MathJsonAttributes.latex?

optional latex: string;

A visual representation of this expression as a LaTeX string.

This can be useful to preserve non-semantic details, for example parentheses in an expression or styling attributes.

MathJsonAttributes.wikidata?

optional wikidata: string;

A short string referencing an entry in a wikibase.

For example:

"Q167" is the wikidata entry for the Pi constant.

MathJsonAttributes.wikibase?

optional wikibase: string;

A base URL for the wikidata key.

A full URL can be produced by concatenating this key with the wikidata key. This key applies to this node and all its children.

The default value is "https://www.wikidata.org/wiki/"

MathJsonAttributes.openmathSymbol?

optional openmathSymbol: string;

A short string indicating an entry in an OpenMath Content Dictionary.

For example: arith1/#abs.

MathJsonAttributes.openmathCd?

optional openmathCd: string;

A base URL for an OpenMath content dictionary. This key applies to this node and all its children.

The default value is "http://www.openmath.org/cd".

MathJsonAttributes.sourceUrl?

optional sourceUrl: string;

A URL to the source code from which this expression was generated.

MathJsonAttributes.sourceContent?

optional sourceContent: string;

The source code from which this expression was generated.

It could be a LaTeX expression, or some other source language.

MathJsonAttributes.sourceOffsets?

optional sourceOffsets: [number, number];

A character offset in sourceContent or sourceUrl from which this expression was generated.

MathJsonSymbol

type MathJsonSymbol = string;

MathJsonNumberObject

type MathJsonNumberObject = {
num: "NaN" | "-Infinity" | "+Infinity" | string;
} & MathJsonAttributes;

A MathJSON numeric quantity.

The num string is made of:

  • an optional - minus sign
  • a string of decimal digits
  • an optional fraction part (a . decimal marker followed by decimal digits)
  • an optional repeating decimal pattern: a string of digits enclosed in parentheses
  • an optional exponent part (a e or E exponent marker followed by an optional - minus sign, followed by a string of digits)

It can also consist of the value NaN, -Infinity and +Infinity to represent these respective values.

A MathJSON number may contain more digits or an exponent with a greater range than can be represented in an IEEE 64-bit floating-point.

For example:

  • -12.34
  • 0.234e-56
  • 1.(3)
  • 123456789123456789.123(4567)e999

MathJsonSymbolObject

type MathJsonSymbolObject = {
sym: MathJsonSymbol;
} & MathJsonAttributes;

MathJsonStringObject

type MathJsonStringObject = {
str: string;
} & MathJsonAttributes;

MathJsonFunctionObject

type MathJsonFunctionObject = {
fn: [MathJsonSymbol, ...Expression[]];
} & MathJsonAttributes;

ExpressionObject

type ExpressionObject = 
| MathJsonNumberObject
| MathJsonStringObject
| MathJsonSymbolObject
| MathJsonFunctionObject;

Expression

type Expression = 
| ExpressionObject
| number
| MathJsonSymbol
| string
| readonly [MathJsonSymbol, ...Expression[]];

A MathJSON expression is a recursive data structure.

The leaf nodes of an expression are numbers, strings and symbols. The dictionary and function nodes can contain expressions themselves.

Type

PrimitiveType

type PrimitiveType = 
| NumericType
| "collection"
| "list"
| "set"
| "map"
| "tuple"
| "value"
| "scalar"
| "function"
| "symbol"
| "boolean"
| "string"
| "expression"
| "unknown"
| "error"
| "nothing"
| "never"
| "any";

A primitive type is a simple type that represents a concrete value.

  • any: the top type

    • expression
    • error: an invalid value, such as ["Error", "missing"]
    • nothing: the type of the Nothing symbol, the unit type
    • never: the bottom type
    • unknown: a value whose type is not known
  • expression:

    • a symbolic expression, such as ["Add", "x", 1]
    • <value>
    • symbol: a symbol, such as x.
    • function: a function literal such as ["Function", ["Add", "x", 1], "x"].
  • value

    • scalar
      • <number>
      • boolean: a boolean value: True or False.
      • string: a string of characters.
    • collection
      • list: a collection of expressions, possibly recursive, with optional dimensions, e.g. [number], [boolean^32], [number^(2x3)]. Used to represent a vector, a matrix or a tensor when the type of its elements is a number
      • set: a collection of unique expressions, e.g. set<string>.
      • tuple: a fixed-size collection of named or unnamed elements, e.g. tuple<number, boolean>, tuple<x: number, y: boolean>.
      • map: a set key-value pairs, e.g. map<x: number, y: boolean>.

NumericType

type NumericType = 
| "number"
| "finite_number"
| "complex"
| "finite_complex"
| "imaginary"
| "real"
| "finite_real"
| "rational"
| "finite_rational"
| "integer"
| "finite_integer"
| "non_finite_number";
  • number: any numeric value = complex + real plus NaN
  • complex: a number with non-zero real and imaginary parts = finite_complex plus ComplexInfinity
  • finite_complex: a finite complex number = imaginary + finite_real
  • imaginary: a complex number with a real part of 0 (pure imaginary)
  • finite_number: a finite numeric value = finite_complex
  • finite_real: a finite real number = finite_rational + finite_integer
  • finite_rational: a pure rational number
  • finite_integer: a whole number
  • real: a complex number with an imaginary part of 0 = finite_real + non_finite_number
  • non_finite_number: PositiveInfinity, NegativeInfinity
  • integer: a whole number = finite_integer + non_finite_number
  • rational: a pure rational number (not an integer) = finite_rational + non_finite_number

NamedElement

type NamedElement = {
name: string;
type: Type;
};

FunctionSignature

type FunctionSignature = {
kind: "signature";
args: NamedElement[];
optArgs: NamedElement[];
restArg: NamedElement;
result: Type;
};

AlgebraicType

type AlgebraicType = {
kind: "union" | "intersection";
types: Type[];
};

NegationType

type NegationType = {
kind: "negation";
type: Type;
};

ValueType

type ValueType = {
kind: "value";
value: any;
};

MapType

type MapType = {
kind: "map";
elements: Record<string, Type>;
};

Map is a non-indexable collection of key/value pairs. An element of a map whose type is a subtype of nothing is optional. For example, in {x: number, y: boolean | nothing} the element y is optional.

CollectionType

type CollectionType = {
kind: "collection";
elements: Type;
};

Collection, List, Set, Tuple and Map are collections.

CollectionType is a generic collection of elements of a certain type.

ListType

type ListType = {
kind: "list";
elements: Type;
dimensions: number[];
};

The elements of a list are ordered.

All elements of a list have the same type, but it can be a broad type, up to any.

The same element can be present in the list more than once.

A list can be multi-dimensional. For example, a list of integers with dimensions 2x3x4 is a 3D tensor with 2 layers, 3 rows and 4 columns.

SetType

type SetType = {
kind: "set";
elements: Type;
};

Each element of a set is unique (is not present in the set more than once). The elements of a set are not ordered.

TupleType

type TupleType = {
kind: "tuple";
elements: NamedElement[];
};

TypeReference

type TypeReference = {
kind: "reference";
ref: string;
};

Nominal typing

Type

type Type = 
| PrimitiveType
| AlgebraicType
| NegationType
| CollectionType
| ListType
| SetType
| MapType
| TupleType
| FunctionSignature
| ValueType
| TypeReference;

TypeString

type TypeString = string;

The type of a boxed expression indicates the kind of expression it is and the value it represents.

The type is represented either by a primitive type (e.g. number, complex, collection, etc.), or a compound type (e.g. tuple, function signature, etc.).

Types are described using the following BNF grammar:

<type> ::= <union_type> | "(" <type> ")"

<union_type> ::= <intersection_type> (" | " <intersection_type>)*

<intersection_type> ::= <primary_type> (" & " <primary_type>)*

<primary_type> ::= <primitive>
| <tuple_type>
| <signature>
| <list_type>

<primitive> ::= "any" | "unknown" | <value-type> | <symbolic-type> | <numeric-type>

<numeric-type> ::= "number" | "complex" | "imaginary" | "real" | "rational" | "integer"

<value-type> ::= "value" | <numeric-type> | "collection" | "boolean" | "string"

<symbolic-type> ::= "expression" | "function" | "symbol"

<tuple_type> ::= "tuple<" (<name> <type> "," <named_tuple_elements>*) ">"
| "tuple<" (<type> "," <unnamed_tuple_elements>*) ">" |
| "tuple<" <tuple_elements> ">"

<tuple_elements> ::= <unnamed_tuple_elements> | <named_tuple_elements>

<unnamed_tuple_elements> ::= <type> ("," <type>)*

<named_tuple_elements> ::= <name> <type> ("," <name> <type>)*

<signature> ::= <arguments> " -> " <type>

<arguments> ::= "()"
| <argument>
| "(" <argument-list> ")"

<argument> ::= <type>
| <name> <type>

<rest_argument> ::= "..." <type>
| <name> "..." <type>

<optional_argument> ::= <argument> "?"

<optional_arguments> ::= <optional_argument> ("," <optional_argument>)*

<required_arguments> ::= <argument> ("," <argument>)*

<argument-list> ::= <required_arguments> ("," <rest_argument>)?
| <required_arguments> <optional_arguments>?
| <optional_arguments>?
| <rest_argument>

<list_type> ::= "list<" <type> <dimensions>? ">"

<dimensions> ::= "^" <fixed_size>
| "^(" <multi_dimensional_size> ")"

<fixed_size> ::= <positive-integer_literal>

<multi_dimensional_size> ::= <positive-integer_literal> "x" <positive-integer_literal> ("x" <positive-integer_literal>)*

<map> ::= "map" | "map<" <map_elements> ">"

<map_elements> ::= <name> <type> ("," <name> <type>)*

<set> ::= "set<" <type> ">"

<collection ::= "collection<" <type> ">"

<name> ::= <identifier> ":"

<identifier> ::= [a-zA-Z_][a-zA-Z0-9_]*

<positive-integer_literal> ::= [1-9][0-9]*

Examples of types strings:

  • "number" -- a simple type primitive
  • "(number, boolean)" -- a tuple type
  • "(x: number, y:boolean)" -- a named tuple/record type. Either all arguments are named, or none are
  • "collection<any>" -- an arbitrary collection type, with no length or element type restrictions
  • "collection<integer>" -- a collection type where all the elements are integers
  • "collection<(number, boolean)>" -- a collection of tuples
  • "collection<(value:number, seen:boolean)>" -- a collection of named tuples
  • "[boolean]^32" -- a collection type with a fixed size of 32 elements
  • "[integer]^(2x3)" -- an integer matrix of 2 columns and 3 rows
  • "[integer]^(2x3x4)" -- a tensor of dimensions 2x3x4
  • "number -> number" -- a signature with a single argument
  • "(x: number, number) -> number" -- a signature with a named argument
  • "(number, y:number?) -> number" -- a signature with an optional named argument (can have several optional arguments, at the end)
  • "(number, ...number) -> number" -- a signature with a rest argument (can have only one, and no optional arguments if there is a rest argument).
  • "() -> number" -- a signature with an empty argument list
  • "number | boolean" -- a union type
  • "(x: number) & (y: number)" -- an intersection type
  • "number | ((x: number) & (y: number))" -- a union type with an intersection type
  • "(number -> number) | number" -- a union type with a signature and a primitive type

TypeCompatibility

type TypeCompatibility = "covariant" | "contravariant" | "bivariant" | "invariant";

TypeResolver()

type TypeResolver = (name) => Type | undefined;