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.

Angular UnitDescription
radradians, 2π radians is a full circle
degdegrees, 360 degrees is a full circle
gradgradians, 400 gradians is a full circle
turnturns, 1 turn is a full circle

To change the angular unit used by the Compute Engine, use:

ce.angularUnit = 'deg';

AssignValue

type AssignValue = KernelAssignValue<Expression, ExpressionInput, ComputeEngine>;

Assignable value for ce.assign().

ExpressionComputeEngine

Compute engine surface used by expression types.

This interface is augmented by types-engine.ts with the concrete IComputeEngine members to avoid type-layer circular dependencies.

ExpressionComputeEngine.latexDictionary
latexDictionary: readonly OnlyFirst<
| DefaultEntry
| ExpressionEntry
| MatchfixEntry
| InfixEntry
| PostfixEntry
| PrefixEntry
| EnvironmentEntry
| SymbolEntry
| FunctionEntry, {} &
| DefaultEntry
| ExpressionEntry
| MatchfixEntry
| InfixEntry
| PostfixEntry
| PrefixEntry
| EnvironmentEntry
| SymbolEntry
| FunctionEntry>[];
ExpressionComputeEngine.decimalSeparator
decimalSeparator: string;
ExpressionComputeEngine.True
readonly True: Expression;
ExpressionComputeEngine.False
readonly False: Expression;
ExpressionComputeEngine.Pi
readonly Pi: Expression;
ExpressionComputeEngine.E
readonly E: Expression;
ExpressionComputeEngine.Nothing
readonly Nothing: Expression;
ExpressionComputeEngine.Zero
readonly Zero: Expression;
ExpressionComputeEngine.One
readonly One: Expression;
ExpressionComputeEngine.Half
readonly Half: Expression;
ExpressionComputeEngine.NegativeOne
readonly NegativeOne: Expression;
ExpressionComputeEngine.I
readonly I: Expression;

ImaginaryUnit

ExpressionComputeEngine.NaN
readonly NaN: Expression;
ExpressionComputeEngine.PositiveInfinity
readonly PositiveInfinity: Expression;
ExpressionComputeEngine.NegativeInfinity
readonly NegativeInfinity: Expression;
ExpressionComputeEngine.ComplexInfinity
readonly ComplexInfinity: Expression;
ExpressionComputeEngine.context
readonly context: EvalContext;
ExpressionComputeEngine.contextStack
contextStack: readonly EvalContext[];
ExpressionComputeEngine.timeLimit
timeLimit: number;
ExpressionComputeEngine.iterationLimit
iterationLimit: number;
ExpressionComputeEngine.recursionLimit
recursionLimit: number;
ExpressionComputeEngine.bignum()
bignum: (a) => Decimal;
ExpressionComputeEngine.complex()
complex: (a, b?) => Complex;
ExpressionComputeEngine.tolerance
tolerance: number;
ExpressionComputeEngine.angularUnit
angularUnit: AngularUnit;
ExpressionComputeEngine.costFunction()
costFunction: (expr) => number;
ExpressionComputeEngine.simplificationRules
simplificationRules: Rule[];

The rules used by .simplify() when no explicit rules option is passed. Initialized to the built-in simplification rules. Users can push() additional rules or replace the entire array.

ExpressionComputeEngine.strict
strict: boolean;
ExpressionComputeEngine.trace
trace: readonly string[];

A list of the function calls to the current evaluation context

ExpressionComputeEngine.precision
get precision(): number
set precision(p: number | "auto" | "machine"): void
ExpressionComputeEngine.chop()
chop(n)
chop(n): number

####### n

number

chop(n)
chop(n): 0 | Decimal

####### n

Decimal

chop(n)
chop(n): number | Decimal

####### n

number | Decimal

ExpressionComputeEngine.box()
box(expr, options?): Expression

####### expr

NumericValue | ExpressionInput

####### options?

####### form?

FormOption

####### scope?

Scope

ExpressionComputeEngine.function()
function(name, ops, options?): Expression

####### name

string

####### ops

readonly ExpressionInput[]

####### options?

####### metadata?

Metadata

####### form?

FormOption

####### scope?

Scope

ExpressionComputeEngine.registerCompilationTarget()
registerCompilationTarget(name, target): void

Register a custom compilation target.

####### name

string

####### target

LanguageTarget<Expression>

ExpressionComputeEngine.getCompilationTarget()
getCompilationTarget(name): LanguageTarget<Expression>

Get a registered compilation target by name.

####### name

string

ExpressionComputeEngine.listCompilationTargets()
listCompilationTargets(): string[]

Return the names of all registered compilation targets.

ExpressionComputeEngine.unregisterCompilationTarget()
unregisterCompilationTarget(name): void

Remove a registered compilation target.

####### name

string

ExpressionComputeEngine.number()
number(value, options?): Expression

####### value

any

####### options?

####### metadata?

Metadata

####### canonical?

CanonicalOptions

ExpressionComputeEngine.symbol()
symbol(sym, options?): Expression

####### sym

string

####### options?

####### canonical?

CanonicalOptions

####### metadata?

Metadata

ExpressionComputeEngine.string()
string(s, metadata?): Expression

####### s

string

####### metadata?

Metadata

ExpressionComputeEngine.error()
error(message, where?): Expression

####### message

string | string[]

####### where?

string

ExpressionComputeEngine.typeError()
typeError(expectedType, actualType, where?): Expression

####### expectedType

Type

####### actualType

Type | BoxedType

####### where?

ExpressionInput

ExpressionComputeEngine.hold()
hold(expr): Expression

####### expr

ExpressionInput

ExpressionComputeEngine.tuple()
tuple(elements)
tuple(...elements): Expression

####### elements

...readonly number[]

tuple(elements)
tuple(...elements): Expression

####### elements

...readonly Expression[]

ExpressionComputeEngine.rules()
rules(rules, options?): BoxedRuleSet

####### rules

Rule | BoxedRuleSet | readonly Rule | BoxedRule[]

####### options?

####### canonical?

boolean

ExpressionComputeEngine.getRuleSet()
getRuleSet(id?): BoxedRuleSet

####### id?

"harmonization" | "solve-univariate" | "standard-simplification"

ExpressionComputeEngine.parse()
parse(latex, options)
parse(latex, options?): null

####### latex

null

####### options?

Partial<ParseLatexOptions> & { form: FormOption; }

parse(latex, options)
parse(latex, options?): Expression

####### latex

string

####### options?

Partial<ParseLatexOptions> & { form: FormOption; }

parse(latex, options)
parse(latex, options?): Expression

####### latex

string

####### options?

Partial<ParseLatexOptions> & { form: FormOption; }

ExpressionComputeEngine.pushScope()
pushScope(scope?, name?): void

####### scope?

Scope

####### name?

string

ExpressionComputeEngine.popScope()
popScope(): void
ExpressionComputeEngine.lookupDefinition()
lookupDefinition(id): BoxedDefinition

####### id

string

ExpressionComputeEngine.assign()
assign(ids)
assign(ids): IComputeEngine

####### ids

assign(id, value)
assign(id, value): IComputeEngine

####### id

string

####### value

AssignValue

assign(arg1, arg2)
assign(arg1, arg2?): IComputeEngine

####### arg1

string | {}

####### arg2?

AssignValue

ExpressionComputeEngine.declareType()
declareType(name, type, options?): void

####### name

string

####### type

Type

####### options?

####### alias?

boolean

ExpressionComputeEngine.declare()
declare(symbols)
declare(symbols): IComputeEngine

####### symbols

declare(id, def, scope)
declare(id, def, scope?): IComputeEngine

####### id

string

####### def

string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | Partial<OnlyFirst<ValueDefinition, BaseDefinition & { holdUntil: "never" | "evaluate" | "N"; type: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; inferred: boolean; value: | ExpressionInput | (ce) => Expression; eq: (a) => boolean; neq: (a) => boolean; cmp: (a) => ">" | "<" | "="; collection: CollectionHandlers; subscriptEvaluate: (subscript, options) => Expression; } & Partial<BaseDefinition> & Partial<OperatorDefinitionFlags> & { signature: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; type: (ops, options) => | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; sgn: (ops, options) => Sign; isPositive: boolean; isNonNegative: boolean; isNegative: boolean; isNonPositive: boolean; even: (ops, options) => boolean; complexity: number; canonical: (ops, options) => Expression; evaluate: | Expression | (ops, options) => Expression; evaluateAsync: (ops, options) => Promise<Expression>; evalDimension: (args, options) => Expression; xcompile: (expr) => CompiledExpression; eq: (a, b) => boolean; neq: (a, b) => boolean; collection: CollectionHandlers; }>> | Partial<OnlyFirst<OperatorDefinition, BaseDefinition & { holdUntil: "never" | "evaluate" | "N"; type: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; inferred: boolean; value: | ExpressionInput | (ce) => Expression; eq: (a) => boolean; neq: (a) => boolean; cmp: (a) => ">" | "<" | "="; collection: CollectionHandlers; subscriptEvaluate: (subscript, options) => Expression; } & Partial<BaseDefinition> & Partial<OperatorDefinitionFlags> & { signature: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; type: (ops, options) => | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; sgn: (ops, options) => Sign; isPositive: boolean; isNonNegative: boolean; isNegative: boolean; isNonPositive: boolean; even: (ops, options) => boolean; complexity: number; canonical: (ops, options) => Expression; evaluate: | Expression | (ops, options) => Expression; evaluateAsync: (ops, options) => Promise<Expression>; evalDimension: (args, options) => Expression; xcompile: (expr) => CompiledExpression; eq: (a, b) => boolean; neq: (a, b) => boolean; collection: CollectionHandlers; }>>

####### scope?

Scope

declare(arg1, arg2, arg3)
declare(arg1, arg2?, arg3?): IComputeEngine

####### arg1

string | {}

####### arg2?

string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | Partial<OnlyFirst<ValueDefinition, BaseDefinition & { holdUntil: "never" | "evaluate" | "N"; type: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; inferred: boolean; value: | ExpressionInput | (ce) => Expression; eq: (a) => boolean; neq: (a) => boolean; cmp: (a) => ">" | "<" | "="; collection: CollectionHandlers; subscriptEvaluate: (subscript, options) => Expression; } & Partial<BaseDefinition> & Partial<OperatorDefinitionFlags> & { signature: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; type: (ops, options) => | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; sgn: (ops, options) => Sign; isPositive: boolean; isNonNegative: boolean; isNegative: boolean; isNonPositive: boolean; even: (ops, options) => boolean; complexity: number; canonical: (ops, options) => Expression; evaluate: | Expression | (ops, options) => Expression; evaluateAsync: (ops, options) => Promise<Expression>; evalDimension: (args, options) => Expression; xcompile: (expr) => CompiledExpression; eq: (a, b) => boolean; neq: (a, b) => boolean; collection: CollectionHandlers; }>> | Partial<OnlyFirst<OperatorDefinition, BaseDefinition & { holdUntil: "never" | "evaluate" | "N"; type: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; inferred: boolean; value: | ExpressionInput | (ce) => Expression; eq: (a) => boolean; neq: (a) => boolean; cmp: (a) => ">" | "<" | "="; collection: CollectionHandlers; subscriptEvaluate: (subscript, options) => Expression; } & Partial<BaseDefinition> & Partial<OperatorDefinitionFlags> & { signature: | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; type: (ops, options) => | string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference | BoxedType; sgn: (ops, options) => Sign; isPositive: boolean; isNonNegative: boolean; isNegative: boolean; isNonPositive: boolean; even: (ops, options) => boolean; complexity: number; canonical: (ops, options) => Expression; evaluate: | Expression | (ops, options) => Expression; evaluateAsync: (ops, options) => Promise<Expression>; evalDimension: (args, options) => Expression; xcompile: (expr) => CompiledExpression; eq: (a, b) => boolean; neq: (a, b) => boolean; collection: CollectionHandlers; }>>

####### arg3?

Scope

ExpressionComputeEngine.assume()
assume(predicate): AssumeResult

####### predicate

Expression

ExpressionComputeEngine.declareSequence()
declareSequence(name, def): IComputeEngine

Declare a sequence with a recurrence relation.

####### name

string

####### def

SequenceDefinition

Example
// Fibonacci sequence
ce.declareSequence('F', {
base: { 0: 0, 1: 1 },
recurrence: 'F_{n-1} + F_{n-2}',
});
ce.parse('F_{10}').evaluate(); // → 55
ExpressionComputeEngine.getSequenceStatus()
getSequenceStatus(name): SequenceStatus

Get the status of a sequence definition.

####### name

string

Example
ce.parse('F_0 := 0').evaluate();
ce.getSequenceStatus('F');
// → { status: 'pending', hasBase: true, hasRecurrence: false, baseIndices: [0] }
ExpressionComputeEngine.getSequence()
getSequence(name): SequenceInfo

Get information about a defined sequence. Returns undefined if the symbol is not a sequence.

####### name

string

ExpressionComputeEngine.listSequences()
listSequences(): string[]

List all defined sequences. Returns an array of sequence names.

ExpressionComputeEngine.isSequence()
isSequence(name): boolean

Check if a symbol is a defined sequence.

####### name

string

ExpressionComputeEngine.clearSequenceCache()
clearSequenceCache(name?): void

Clear the memoization cache for a sequence. If no name is provided, clears caches for all sequences.

####### name?

string

ExpressionComputeEngine.getSequenceCache()
getSequenceCache(name): Map<string | number, Expression>

Get the memoization cache for a sequence. Returns a Map of index → value, or undefined if not a sequence or memoization is disabled.

For single-index sequences, keys are numbers. For multi-index sequences, keys are comma-separated strings (e.g., '5,2').

####### name

string

ExpressionComputeEngine.getSequenceTerms()
getSequenceTerms(
name,
start,
end,
step?): Expression[]

Generate a list of sequence terms from start to end (inclusive).

####### name

string

The sequence name

####### start

number

Starting index (inclusive)

####### end

number

Ending index (inclusive)

####### step?

number

Step size (default: 1)

Example
ce.declareSequence('F', { base: { 0: 0, 1: 1 }, recurrence: 'F_{n-1} + F_{n-2}' });
ce.getSequenceTerms('F', 0, 10);
// → [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
ExpressionComputeEngine.lookupOEIS()
lookupOEIS(terms, options?): Promise<OEISSequenceInfo[]>

Look up sequences in OEIS by their terms.

####### terms

(number | Expression)[]

Array of sequence terms to search for

####### options?

OEISOptions

Optional configuration (timeout, maxResults)

Example
const results = await ce.lookupOEIS([0, 1, 1, 2, 3, 5, 8, 13]);
// → [{ id: 'A000045', name: 'Fibonacci numbers', ... }]
ExpressionComputeEngine.checkSequenceOEIS()
checkSequenceOEIS(name, count?, options?): Promise<{
matches: OEISSequenceInfo[];
terms: number[];
}>

Check if a defined sequence matches an OEIS sequence.

####### name

string

Name of the defined sequence

####### count?

number

Number of terms to check (default: 10)

####### options?

OEISOptions

Optional configuration

Example
ce.declareSequence('F', { base: { 0: 0, 1: 1 }, recurrence: 'F_{n-1} + F_{n-2}' });
const result = await ce.checkSequenceOEIS('F', 10);
// → { matches: [{ id: 'A000045', name: 'Fibonacci numbers', ... }], terms: [0, 1, 1, ...] }
ExpressionComputeEngine.forget()
forget(symbol?): void

####### symbol?

string | string[]

ExpressionComputeEngine.ask()
ask(pattern): BoxedSubstitution[]

####### pattern

Expression

ExpressionComputeEngine.verify()
verify(query): boolean

####### query

Expression

Boxed Expression

SimplifyOptions

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

Options for Expression.simplify()

EvaluateOptions

type EvaluateOptions = KernelEvaluateOptions;

Options for evaluating boxed expressions.

This is the compute-engine-specialized form of the generic kernel type.

Expression

THEORY OF OPERATIONS

The Expression 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 Expression its value is undefined. For example expr.symbol for a BoxedNumber is undefined.

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

Expression.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".

Numeric Expression

Expression.isEven
readonly isEven: boolean;

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

Expression.isOdd
readonly isOdd: boolean;

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

Expression.re
readonly re: number;

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

Otherwise, return NaN (not a number).

Expression.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).

Expression.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.

Expression.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.

Expression.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.

Expression.isPositive
readonly isPositive: boolean;

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

Expression.isNonNegative
readonly isNonNegative: boolean;

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

Expression.isNegative
readonly isNegative: boolean;

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

Expression.isNonPositive
readonly isNonPositive: boolean;

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

Expression.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).

Expression.isInfinity
readonly isInfinity: boolean;

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

Expression.isFinite
readonly isFinite: boolean;

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

Other

Expression.engine
readonly engine: ExpressionComputeEngine;

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

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

Serialize to a LaTeX string.

Note that lazy collections are eagerly evaluated.

Will ignore any LaTeX metadata.

####### options?

Partial<SerializeLatexOptions>

Expression.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 that lazy collections are eagerly evaluated.

Note

Applicable to canonical and non-canonical expressions.

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

Serialize to a MathJSON expression with specified options

####### options?

Readonly<Partial<JsonSerializationOptions>>

Expression.json
readonly json: MathJsonExpression;

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 that lazy collections are not eagerly evaluated.

Note

Applicable to canonical and non-canonical expressions.

Expression.print()
print(): void

Output to the console a string representation of the expression.

Note that lazy collections are eagerly evaluated when printed.

Expression.verbatimLatex?
optional verbatimLatex: string;

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

Expression.isCanonical

If true, this expression is in a canonical form.

Expression.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 Expression object.

Expression.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).

Expression.structural

Return the structural form of this expression.

Some expressions, such as rational numbers, are represented with a Expression 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.

Expression.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.

Expression.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

Expression.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.
Expression.errors
readonly errors: readonly Expression[];

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.

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

All the subexpressions matching the named operator, recursively.

Example:

const expr = ce.parse('a + b * c + d');
const subexpressions = expr.getSubexpressions('Add');
// -> `[['Add', 'a', 'b'], ['Add', 'c', 'd']]`
Note

Applicable to canonical and non-canonical expressions.

####### operator

string

Expression.subexpressions
readonly subexpressions: readonly Expression[];

All the subexpressions in this expression, recursively

Example:

const expr = ce.parse('a + b * c + d');
const subexpressions = expr.subexpressions;
// -> `[['Add', 'a', 'b'], ['Add', 'c', 'd'], 'a', 'b', 'c', 'd']`
Note

Applicable to canonical and non-canonical expressions.

Expression.symbols
readonly symbols: readonly string[];

All the symbols in the expression, recursively, including bound variables (e.g., summation/product index variables).

Use unknowns or freeVariables to get only the symbols that are free (not bound by a scoping construct).

const expr = ce.parse('a + b * c + d');
const symbols = expr.symbols;
// -> ['a', 'b', 'c', 'd']
Note

Applicable to canonical and non-canonical expressions.

Expression.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.

Expression.freeVariables
readonly freeVariables: readonly string[];

The free variables of the expression: symbols that are not constants, not operators, not bound to a value, and not locally scoped (e.g., summation/product index variables are excluded).

This is an alias for unknowns.

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

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']]]
Expression.neg()
neg(): Expression

Negate (additive inverse)

Expression.inv()
inv(): Expression

Inverse (multiplicative inverse)

Expression.abs()
abs(): Expression

Absolute value

Expression.add()
add(rhs): Expression

Addition

####### rhs

number | Expression

Expression.sub()
sub(rhs): Expression

Subtraction

####### rhs

Expression

Expression.mul()
mul(rhs): Expression

Multiplication

####### rhs

number | NumericValue | Expression

Expression.div()
div(rhs): Expression

Division

####### rhs

number | Expression

Expression.pow()
pow(exp): Expression

Power

####### exp

number | Expression

Expression.root()
root(exp): Expression

Exponentiation

####### exp

number | Expression

Expression.sqrt()
sqrt(): Expression

Square root

Expression.ln()
ln(base?): Expression

Logarithm (natural by default)

####### base?

number | Expression

Expression.numerator

Return this expression expressed as a numerator.

Expression.denominator

Return this expression expressed as a denominator.

Expression.numeratorDenominator

Return this expression expressed as a numerator and denominator.

Expression.toRational()
toRational(): [number, number]

Return the value of this expression as a pair of integer numerator and denominator, or null if the expression is not a rational number.

  • For a BoxedNumber with an exact rational value, extracts from the numeric representation.
  • For an integer, returns [n, 1].
  • For a Divide or Rational function with integer operands, returns [num, den].
  • For everything else, returns null.

The returned rational is always in lowest terms.

ce.parse('\\frac{6}{4}').toRational()  // [3, 2]
ce.parse('7').toRational() // [7, 1]
ce.parse('x + 1').toRational() // null
ce.number(1.5).toRational() // null (machine float)
Expression.factors()
factors(): readonly Expression[]

Return the multiplicative factors of this expression as a flat array.

This is a structural decomposition — it does not perform algebraic factoring (use ce.function('Factor', [expr]) for that).

  • Multiply(a, b, c) returns [a, b, c]
  • Negate(x) returns [-1, ...x.factors()]
  • Anything else returns [expr]
ce.parse('2xyz').factors()     // [2, x, y, z]
ce.parse('-3x').factors() // [-1, 3, x]
ce.parse('x + 1').factors() // [x + 1]
Expression.polynomialCoefficients()
polynomialCoefficients(variable?): readonly Expression[]

Return the coefficients of this expression as a polynomial in variable, in descending order of degree. Returns undefined if the expression is not a polynomial in the given variable.

If variable is omitted, auto-detects when the expression has exactly one unknown. Returns undefined if there are zero or multiple unknowns.

ce.parse('x^2 + 2x + 1').polynomialCoefficients('x')  // [1, 2, 1]
ce.parse('x^3 + 2x + 1').polynomialCoefficients('x') // [1, 0, 2, 1]
ce.parse('sin(x)').polynomialCoefficients('x') // undefined
ce.parse('x^2 + 5').polynomialCoefficients() // [1, 0, 5]

Subsumes isPolynomial:

const isPolynomial = expr.polynomialCoefficients('x') !== undefined;

Subsumes polynomialDegree:

const degree = expr.polynomialCoefficients('x')?.length - 1;

When variable is an array, the expression must be polynomial in ALL listed variables. Coefficients are decomposed by the first variable; remaining variables appear as symbolic coefficients.

ce.parse('x^2*y + 3x + y^2').polynomialCoefficients(['x', 'y'])
// → [y, 3, y²] (coefficients of x², x¹, x⁰)

####### variable?

string | string[]

Expression.polynomialRoots()
polynomialRoots(variable?): readonly Expression[]

Return the roots of this expression treated as a polynomial in variable. Returns undefined if the expression is not a polynomial in the given variable. Returns an empty array if no roots can be found.

If variable is omitted, auto-detects when the expression has exactly one unknown.

ce.parse('x^2 - 5x + 6').polynomialRoots('x')  // [2, 3]
ce.parse('x^2 + 1').polynomialRoots('x') // [] (no real roots)
ce.parse('sin(x)').polynomialRoots('x') // undefined

####### variable?

string

Expression.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.

Expression.localScope

If this expression has a local scope, return it.

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

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.

If this is a function, an empty substitution is given, and the computed value of canonical does not differ from that of this expr.: then a call this method is analagous to requesting a clone.

####### sub

Substitution<ExpressionInput>

####### options?

####### canonical?

CanonicalOptions

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

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) => Expression

####### options?

####### canonical

CanonicalOptions

####### recursive?

boolean

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

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.

Procedure for the determining the canonical-status of the input expression and replacements:

  • If options.canonical is set, the entire expr. is canonicalized to this degree: whether the replacement occurs at the top-level, or within/recursively.

  • If otherwise, the direct replacement will be canonical if either the 'replaced' expression is canonical, or the given replacement (- is a Expression and -) is canonical. Notably also, if this replacement takes place recursively (not at the top-level), then exprs. containing the replaced expr. will still however have their (previous) canonical-status preserved... unless this expr. was previously non-canonical, and replacements have resulted in canonical operands. In this case, an expr. meeting this criteria will be updated to canonical status. (Canonicalization is opportunistic here, in other words).

Note

Applicable to canonical and non-canonical expressions.

To match a specific symbol (not a wildcard pattern), the match must be a Expression (e.g., { match: ce.box('x'), replace: ... }). For simple symbol substitution, consider using subs() instead.

####### rules

Rule | BoxedRuleSet | Rule[]

####### options?

Partial<ReplaceOptions>

Expression.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[]

Expression.match()
match(pattern, options?): BoxedSubstitution<Expression>

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, {}.

pattern can be:

  • A string (LaTeX): single-character symbols are auto-converted to wildcards (e.g., 'ax^2+bx+c' treats a, b, c as wildcards). Results use unprefixed keys ({a: 3} not {_a: 3}) and self-matches are filtered out. useVariations and matchMissingTerms default to true. Unprefixed keys are accepted in substitution.
  • A MathJSON array (e.g., ['Add', '_a', '_b']): boxed automatically.
  • A BoxedExpression: used directly.

Read more about patterns and rules.

Note

Applicable to canonical and non-canonical expressions.

####### pattern

ExpressionInput

####### options?

PatternMatchOptions<Expression>

Expression.wikidata
readonly wikidata: string;

Wikidata identifier.

If not a canonical expression, return undefined.

Expression.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.

Expression.url
readonly url: string;

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

If not a canonical expression, return undefined.

Expression.complexity
readonly complexity: number;

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

If not a canonical expression, return undefined.

Expression.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.

Expression.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.

Expression.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.

Expression.simplify()
simplify(options?): Expression

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>

Expression.evaluate()
evaluate(options?): Expression

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>

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

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>

Expression.N()
N(): Expression

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.

Expression.solve()
solve(vars?): 
| readonly Expression[]
| Record<string, Expression>
| Record<string, Expression>[]

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

For univariate equations, returns an array of solutions (roots). For systems of linear equations (List of Equal expressions), returns an object mapping variable names to their values. For non-linear polynomial systems (like xy=6, x+y=5), returns an array of solution objects (multiple solutions possible).

// Univariate equation
const expr = ce.parse("x^2 + 2*x + 1 = 0");
console.log(expr.solve("x")); // Returns array of roots

// System of linear equations
const system = ce.parse("\\begin{cases}x+y=70\\\\2x-4y=80\\end{cases}");
console.log(system.solve(["x", "y"])); // Returns { x: 60, y: 10 }

// Non-linear polynomial system (product + sum)
const nonlinear = ce.parse("\\begin{cases}xy=6\\\\x+y=5\\end{cases}");
console.log(nonlinear.solve(["x", "y"])); // Returns [{ x: 2, y: 3 }, { x: 3, y: 2 }]

####### vars?

string | Iterable<string, any, any> | Expression | Iterable<Expression, any, any>

Expression.value
get value(): Expression
set value(value:
| string
| number
| boolean
| number[]
| Decimal
| OnlyFirst<{
re: number;
im: number;
}, {
re: number;
im: number;
} & {
num: number;
denom: number;
} & Expression>
| OnlyFirst<{
num: number;
denom: number;
}, {
re: number;
im: number;
} & {
num: number;
denom: number;
} & Expression>
| OnlyFirst<Expression, {
re: number;
im: number;
} & {
num: number;
denom: number;
} & Expression>): 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.

Expression.isCollection
isCollection: boolean;

Is true if the expression is a collection.

When isCollection is true, the expression:

  • has an each() method that returns a generator over the elements of the collection.
  • has a size property that returns the number of elements in the collection.
  • has a contains(other) method that returns true if the other expression is in the collection.
Expression.isIndexedCollection
isIndexedCollection: boolean;

Is true if this is an indexed collection, such as a list, a vector, a matrix, a tuple, etc...

The elements of an indexed collection can be accessed by a one-based index.

When isIndexedCollection is true, the expression:

  • has an each(), size() and contains(rhs) methods as for a collection.
  • has an at(index: number) method that returns the element at the specified index.
  • has an indexWhere(predicate: (element: Expression) => boolean) method that returns the index of the first element that matches the predicate.
Expression.isLazyCollection
isLazyCollection: boolean;

False if not a collection, or if the elements of the collection are not computed lazily.

The elements of a lazy collection are computed on demand, when iterating over the collection using each().

Use ListFrom and related functions to create eager collections from lazy collections.

Expression.each()
each(): Generator<Expression>

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

const expr = ce.parse('[1, 2, 3, 4]');
for (const e of expr.each()) {
console.log(e);
}
Expression.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 without iterating over the collection.

####### rhs

Expression

Expression.subsetOf()
subsetOf(other, strict): boolean

Check if this collection is a subset of another collection.

####### other

Expression

The other collection to check against.

####### strict

boolean

If true, the subset relation is strict (i.e., proper subset).

Expression.count

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

If the collection is infinite, return Infinity.

If the number of elements cannot be determined, return undefined, for example, if the collection is lazy and not finite and the size cannot be determined without iterating over the collection.

Expression.isFiniteCollection
isFiniteCollection: boolean;

If this is a finite collection, return true.

Expression.isEmptyCollection
isEmptyCollection: boolean;

If this is an empty collection, return true.

An empty collection has a size of 0.

Expression.at()
at(index): Expression

If this is an indexed collection, return the element at the specified index. The first element is at index 1.

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

The last element is at index -1.

####### index

number

Expression.get()
get(key): Expression

If this is a keyed collection (map, record, tuple), return the value of the corresponding key.

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

####### key

string | Expression

Expression.indexWhere()
indexWhere(predicate): number

If this is an indexed collection, return the index of the first element that matches the predicate.

####### predicate

(element) => boolean

Primitive Methods

Expression.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.

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

Similar toexpr.valueOf() but includes a hint.

####### hint

"string" | "number" | "default"

Expression.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.

Note that lazy collections are eagerly evaluated.

Used when coercing a Expression to a String.

Expression.toJSON()
toJSON(): MathJsonExpression

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

Method version of expr.json.

Based on Object.toJSON().

Note that lazy collections are not eagerly evaluated.

Expression.is()
is(other, tolerance?): boolean

Smart equality check: structural first, then numeric evaluation fallback. Symmetric: a.is(b) always equals b.is(a).

First tries an exact structural check (same as isSame()). If that fails and the expression is constant (no free variables), evaluates numerically and compares within engine.tolerance.

For literal numbers compared to primitives (number, bigint), behaves identically to isSame() — no tolerance is applied. Tolerance only applies to expressions that require evaluation (e.g., \\sin(\\pi)).

ce.parse('\\cos(\\frac{\\pi}{2})').is(0)  // true — evaluates, within tolerance
ce.number(1e-17).is(0) // false — literal, no tolerance
ce.parse('x + 1').is(1) // false — has free variables
ce.parse('\\pi').is(3.14, 0.01) // true — within custom tolerance

After the structural check, attempts to expand both sides (distributing products, applying the multinomial theorem, etc.) and re-checks structural equality. This catches equivalences like (x+1)^2 vs x^2+2x+1 even when the expression has free variables.

####### other

string | number | bigint | boolean | Expression

####### tolerance?

number

If provided, overrides engine.tolerance for the numeric comparison. Has no effect when the comparison is structural (i.e., when isSame() succeeds or the expression has free variables).

Relational Operator

Expression.isSame()
isSame(rhs): boolean

Fast exact structural/symbolic equality check.

Returns true if the expression is structurally identical to rhs. For symbols with value bindings, follows the binding (e.g., if one = 1, then ce.symbol('one').isSame(1) is true).

Accepts JavaScript primitives: number, bigint, boolean, string.

Does not evaluate expressions — purely structural.

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

See expr.is() for a smart check with numeric evaluation fallback, and expr.isEqual() for full mathematical equality.

Note

Applicable to canonical and non-canonical expressions.

####### rhs

string | number | bigint | boolean | Expression

Expression.isLess()
isLess(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | Expression

Expression.isLessEqual()
isLessEqual(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | Expression

Expression.isGreater()
isGreater(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | Expression

Expression.isGreaterEqual()
isGreaterEqual(other): boolean

The value of both expressions are compared.

If the expressions cannot be compared, return undefined

####### other

number | Expression

Expression.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 fast exact structural comparison (no evaluation)
  • expr.is(other) for a smart check that tries structural first, then numeric evaluation fallback for constant expressions

Examples

let expr = ce.parse('2 + 2');
console.log(expr.isEqual(4)); // true
console.log(expr.isSame(4)); // false (structural only)
console.log(expr.is(4)); // true (evaluates, within tolerance)

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

####### other

number | Expression

Tensor Expression

Expression.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].

Expression.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

Expression.type
get type(): BoxedType
set type(type:
| string
| AlgebraicType
| NegationType
| CollectionType
| ListType
| SetType
| RecordType
| DictionaryType
| TupleType
| SymbolType
| ExpressionType
| NumericType
| 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".

Expression.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.

Expression.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.

Expression.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.

Expression.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.

NumberLiteralInterface

Narrowed interface for number literal expressions.

Obtained via isNumber().

NumberLiteralInterface.numericValue
readonly numericValue: number | NumericValue;
NumberLiteralInterface.isExact
readonly isExact: boolean;
NumberLiteralInterface.isNumberLiteral
readonly isNumberLiteral: true;

SymbolInterface

Narrowed interface for symbol expressions.

Obtained via isSymbol().

SymbolInterface.symbol
readonly symbol: string;

FunctionInterface

Narrowed interface for function expressions.

Obtained via isFunction().

FunctionInterface.isFunctionExpression
readonly isFunctionExpression: true;
FunctionInterface.ops
readonly ops: readonly Expression[];
FunctionInterface.nops
readonly nops: number;
FunctionInterface.op1
readonly op1: Expression;
FunctionInterface.op2
readonly op2: Expression;
FunctionInterface.op3
readonly op3: Expression;

StringInterface

Narrowed interface for string expressions.

Obtained via isString().

StringInterface.string
readonly string: string;

TensorInterface

Narrowed interface for tensor expressions.

Obtained via isTensor().

TensorInterface.tensor
readonly tensor: Tensor<keyof DataTypeMap>;
TensorInterface.shape
readonly shape: number[];
TensorInterface.rank
readonly rank: number;

CollectionInterface

Narrowed interface for collection expressions.

Obtained via isCollection().

Extended by

CollectionInterface.isCollection
readonly isCollection: true;
CollectionInterface.count
readonly count: number;
CollectionInterface.isFiniteCollection
readonly isFiniteCollection: boolean;
CollectionInterface.isEmptyCollection
readonly isEmptyCollection: boolean;
CollectionInterface.each()
each(): Generator<Expression>
CollectionInterface.contains()
contains(rhs): boolean

####### rhs

Expression

CollectionInterface.subsetOf()
subsetOf(other, strict): boolean

####### other

Expression

####### strict

boolean

IndexedCollectionInterface

Narrowed interface for indexed collection expressions (lists, vectors, matrices, tuples).

Obtained via isIndexedCollection().

Extends

IndexedCollectionInterface.isIndexedCollection
readonly isIndexedCollection: true;
IndexedCollectionInterface.at()
at(index): Expression

####### index

number

IndexedCollectionInterface.indexWhere()
indexWhere(predicate): number

####### predicate

(element) => boolean

ExpressionInput

type ExpressionInput = 
| number
| bigint
| string
| BigNum
| MathJsonNumberObject
| MathJsonStringObject
| MathJsonSymbolObject
| MathJsonFunctionObject
| MathJsonDictionaryObject
| readonly [MathJsonSymbol, ...ExpressionInput[]]
| Expression;

An expression input is a MathJSON expression which can include some engine expression terms.

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

ReplaceOptions

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

Options for Expression.replace().

CanonicalForm

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

Canonical normalization transforms.

CanonicalOptions

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

FormOption

type FormOption = 
| "canonical"
| "structural"
| "raw"
| CanonicalForm
| CanonicalForm[];

Controls how expressions are created.

Metadata

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

Metadata that can be associated with a MathJSON expression.

Pattern Matching

Substitution

type Substitution<T> = KernelSubstitution<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 = ExpressionInput

BoxedSubstitution

type BoxedSubstitution<T> = KernelBoxedSubstitution<T>;

Type Parameters

• T = Expression

PatternMatchOptions

type PatternMatchOptions<T> = KernelPatternMatchOptions<T>;

Control how a pattern is matched to an expression.

Type Parameters

• T = Expression

Rules

RuleReplaceFunction

type RuleReplaceFunction = KernelRuleReplaceFunction<Expression>;

Rule replacement callback specialized to boxed expressions.

RuleConditionFunction

type RuleConditionFunction = KernelRuleConditionFunction<Expression, ComputeEngine>;

Rule condition callback with access to the compute engine.

RuleFunction

type RuleFunction = KernelRuleFunction<Expression>;

Dynamic rule callback.

Rule

type Rule = KernelRule<Expression, ExpressionInput, ComputeEngine>;

Rule declaration specialized to boxed expression and compute engine types.

Assumptions

ExpressionMapInterface

type ExpressionMapInterface<U> = KernelExpressionMapInterface<U, Expression>;

Map-like interface keyed by boxed expressions.

Type Parameters

• U

Assumption

type Assumption = KernelAssumption<Expression, ComputeEngine>;

Assumption predicates bound to this compute engine.

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 | Expression;
};

Definitions

ValueDefinition

type ValueDefinition = BaseDefinition & {
holdUntil: "never" | "evaluate" | "N";
type: | Type
| TypeString
| BoxedType;
inferred: boolean;
value: | LatexString
| ExpressionInput
| (ce) => Expression | null;
eq: (a) => boolean | undefined;
neq: (a) => boolean | undefined;
cmp: (a) => "=" | ">" | "<" | undefined;
collection: CollectionHandlers;
subscriptEvaluate: (subscript, options) => Expression | undefined;
};

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
| ExpressionInput
| (ce) => Expression | 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

ValueDefinition.subscriptEvaluate()?

optional subscriptEvaluate: (subscript, options) => Expression | undefined;

Custom evaluation handler for subscripted expressions of this symbol. Called when evaluating Subscript(symbol, index).

subscript

Expression

The subscript expression (already evaluated)

options

Contains the compute engine and evaluation options

####### engine

ComputeEngine

####### numericApproximation?

boolean

SequenceDefinition

Definition for a sequence declared with ce.declareSequence().

A sequence is defined by base cases and a recurrence relation.

Example

// Fibonacci sequence
ce.declareSequence('F', {
base: { 0: 0, 1: 1 },
recurrence: 'F_{n-1} + F_{n-2}',
});
ce.parse('F_{10}').evaluate(); // → 55
SequenceDefinition.variable?
optional variable: string;

Index variable name for single-index sequences, default 'n'. For multi-index sequences, use variables instead.

SequenceDefinition.variables?
optional variables: string[];

Index variable names for multi-index sequences. Example: ['n', 'k'] for Pascal's triangle P\_{n,k}

If provided, this takes precedence over variable.

SequenceDefinition.base
base: Record<number | string, number | Expression>;

Base cases as index → value mapping.

For single-index sequences, use numeric keys:

base: { 0: 0, 1: 1 }  // F_0 = 0, F_1 = 1

For multi-index sequences, use comma-separated string keys:

base: {
'0,0': 1, // Exact: P_{0,0} = 1
'n,0': 1, // Pattern: P_{n,0} = 1 for all n
'n,n': 1, // Pattern: P_{n,n} = 1 (diagonal)
}

Pattern keys use variable names to match any value. When the same variable appears multiple times (e.g., 'n,n'), the indices must be equal.

SequenceDefinition.recurrence
recurrence: string | Expression;

Recurrence relation as LaTeX string or Expression

SequenceDefinition.memoize?
optional memoize: boolean;

Whether to memoize computed values (default: true)

SequenceDefinition.domain?
optional domain: 
| {
min: number;
max: number;
}
| Record<string, {
min: number;
max: number;
}>;

Valid index domain constraints.

For single-index sequences:

domain: { min: 0, max: 100 }

For multi-index sequences, use per-variable constraints:

domain: { n: { min: 0 }, k: { min: 0 } }
SequenceDefinition.constraints?
optional constraints: string | Expression;

Constraint expression for multi-index sequences. The expression should evaluate to a boolean/numeric value. If it evaluates to false or 0, the subscript is considered out of domain.

Example: 'k <= n' for Pascal's triangle (only valid when k ≤ n)

SequenceStatus

Status of a sequence definition.

SequenceStatus.status
status: "complete" | "pending" | "not-a-sequence";

Status of the sequence:

  • 'complete': Both base case(s) and recurrence defined
  • 'pending': Waiting for base case(s) or recurrence
  • 'not-a-sequence': Symbol is not a sequence
SequenceStatus.hasBase
hasBase: boolean;

Whether at least one base case is defined

SequenceStatus.hasRecurrence
hasRecurrence: boolean;

Whether a recurrence relation is defined

SequenceStatus.baseIndices
baseIndices: (string | number)[];

Keys of defined base cases. For single-index: numeric indices (e.g., [0, 1]) For multi-index: string keys including patterns (e.g., ['0,0', 'n,0', 'n,n'])

SequenceStatus.variable?
optional variable: string;

Index variable name if recurrence is defined (single-index)

SequenceStatus.variables?
optional variables: string[];

Index variable names if recurrence is defined (multi-index)

SequenceInfo

Information about a defined sequence for introspection.

SequenceInfo.name
name: string;

The sequence name

SequenceInfo.variable?
optional variable: string;

Index variable name for single-index sequences (e.g., "n")

SequenceInfo.variables?
optional variables: string[];

Index variable names for multi-index sequences (e.g., ["n", "k"])

SequenceInfo.baseIndices
baseIndices: (string | number)[];

Base case keys. For single-index: numeric indices For multi-index: string keys including patterns

SequenceInfo.memoize
memoize: boolean;

Whether memoization is enabled

SequenceInfo.domain
domain: 
| {
min: number;
max: number;
}
| Record<string, {
min: number;
max: number;
}>;

Domain constraints. For single-index: { min?, max? } For multi-index: per-variable constraints

SequenceInfo.cacheSize
cacheSize: number;

Number of cached values

SequenceInfo.isMultiIndex
isMultiIndex: boolean;

Whether this is a multi-index sequence

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) => Expression | null;
evaluate: | (ops, options) => Expression | undefined
| Expression;
evaluateAsync: (ops, options) => Promise<Expression | undefined>;
evalDimension: (args, options) => Expression;
xcompile: (expr) => CompiledExpression;
eq: (a, b) => boolean | undefined;
neq: (a, b) => boolean | undefined;
collection: 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) => Expression | 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) => Expression | undefined
| Expression;

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<Expression | undefined>;

An asynchronous version of evaluate.

OperatorDefinition.evalDimension()?

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

Experimental

Dimensional analysis

OperatorDefinition.xcompile()?

optional xcompile: (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.examples
examples: string | string[];

A list of examples of how to use this symbol or operator.

Each example is a string, which can be a MathJSON expression or LaTeX, bracketed by $ signs. For example, ["Add", 1, 2] or $\\sin(\\pi/4)$.

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<{}>;

LibraryDefinition

A library bundles symbol/operator definitions with their LaTeX dictionary entries and declares dependencies on other libraries.

Use with the libraries constructor option to load standard or custom libraries:

const ce = new ComputeEngine({
libraries: ['core', 'arithmetic', {
name: 'custom',
requires: ['arithmetic'],
definitions: { G: { value: 6.674e-11, type: 'real', isConstant: true } },
}],
});
LibraryDefinition.name
name: string;

Library identifier

LibraryDefinition.requires?
optional requires: string[];

Libraries that must be loaded before this one

LibraryDefinition.definitions?
optional definitions: Readonly<{}> | Readonly<{}>[];

Symbol and operator definitions

LibraryDefinition.latexDictionary?
optional latexDictionary: readonly Partial<OnlyFirst<
| DefaultEntry
| ExpressionEntry
| MatchfixEntry
| InfixEntry
| PostfixEntry
| PrefixEntry
| EnvironmentEntry
| SymbolEntry
| FunctionEntry, {} &
| DefaultEntry
| ExpressionEntry
| MatchfixEntry
| InfixEntry
| PostfixEntry
| PrefixEntry
| EnvironmentEntry
| SymbolEntry
| FunctionEntry>>[];

LaTeX dictionary entries for parsing/serialization

BaseCollectionHandlers

These handlers are the primitive operations that can be performed on all collections, indexed or not.

Definitions

BaseCollectionHandlers.iterator()
iterator: (collection) => Iterator<Expression, undefined, any>;

Return an iterator that iterates over the elements of the collection.

The order in which the elements are returned is not defined. Requesting two iterators on the same collection may return the elements in a different order.

Other

BaseCollectionHandlers.count()
count: (collection) => number;

Return the number of elements in the collection.

An empty collection has a count of 0.

BaseCollectionHandlers.isEmpty()?
optional isEmpty: (collection) => boolean;

Optional flag to quickly check if the collection is empty, without having to count exactly how may elements it has (useful for lazy evaluation).

BaseCollectionHandlers.isFinite()?
optional isFinite: (collection) => boolean;

Optional flag to quickly check if the collection is finite, without having to count exactly how many elements it has (useful for lazy evaluation).

BaseCollectionHandlers.isLazy()?
optional isLazy: (collection) => boolean;

Return true if the collection is lazy, false otherwise. If the collection is lazy, it means that the elements are not computed until they are needed, for example when iterating over the collection.

Default: true

BaseCollectionHandlers.contains()?
optional contains: (collection, target) => boolean;

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

Return undefined if the membership cannot be determined.

BaseCollectionHandlers.subsetOf()?
optional subsetOf: (collection, other, strict) => boolean;

Return true if all the elements of other are in collection. Both collection and other are collections.

If strict is true, the subset must be strict, that is, collection must have more elements than other.

Return undefined if the subset relation cannot be determined.

BaseCollectionHandlers.eltsgn()?
optional eltsgn: (collection) => Sign;

Return the sign of all the elements of the collection.

BaseCollectionHandlers.elttype()?
optional elttype: (collection) => Type;

Return the widest type of all the elements in the collection

IndexedCollectionHandlers

These additional collection handlers are applicable to indexed collections only.

The elements of an indexed collection can be accessed by index, and the order of the elements is defined.

IndexedCollectionHandlers.at()
at: (collection, index) => Expression;

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 count() + index + 1.

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

If the index is invalid, return undefined.

IndexedCollectionHandlers.indexWhere()
indexWhere: (collection, predicate) => number;

Return the index of the first element that matches the predicate.

If no element matches the predicate, return undefined.

CollectionHandlers

type CollectionHandlers = BaseCollectionHandlers & Partial<IndexedCollectionHandlers>;

The collection handlers are the primitive operations that can be performed on collections, such as lists, sets, tuples, etc...

TaggedValueDefinition

type TaggedValueDefinition = {
value: BoxedValueDefinition;
};

The definition for a value, represented as a tagged object literal.

TaggedOperatorDefinition

type TaggedOperatorDefinition = {
operator: BoxedOperatorDefinition;
};

The definition for an operator, represented as a tagged object literal.

BoxedDefinition

type BoxedDefinition = 
| TaggedValueDefinition
| TaggedOperatorDefinition;

A 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: 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
value: Expression;

The current value of the symbol. For constants, this is immutable. The definition object is the single source of truth — there is no separate evaluation-context values map.

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;
BoxedValueDefinition.subscriptEvaluate()?
optional subscriptEvaluate: (subscript, options) => Expression;

Custom evaluation handler for subscripted expressions of this symbol. Called when evaluating Subscript(symbol, index).

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.

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
| RecordType
| DictionaryType
| TupleType
| SymbolType
| ExpressionType
| NumericType
| 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) => Expression;
BoxedOperatorDefinition.evaluate()?
optional evaluate: (ops, options) => Expression;
BoxedOperatorDefinition.evaluateAsync()?
optional evaluateAsync: (ops, options?) => Promise<Expression>;
BoxedOperatorDefinition.evalDimension()?
optional evalDimension: (ops, options) => Expression;
BoxedOperatorDefinition.compile()?
optional compile: (expr) => CompiledExpression;

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";

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 = 
| "arithmetic"
| "calculus"
| "collections"
| "colors"
| "control-structures"
| "combinatorics"
| "core"
| "linear-algebra"
| "logic"
| "number-theory"
| "other"
| "physics"
| "polynomials"
| "relop"
| "statistics"
| "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 ranges from 0 to 1000. The larger the number, the higher the precedence, the more "binding" the operator is.

Operator Precedence Table

PrecedenceOperatorsDescription
880\lnot \neg ++ -- + - (prefix)Prefix/postfix unary
810! ' !! '''Factorial, prime (postfix)
800_ (subscript)Subscript
780\degree \primeDegree, prime symbols
740\%Percent
720/ (inline division)Inline division
700^ \overset \undersetExponentiation, over/underscript
650(invisible multiply) \cdotImplicit multiplication
600\div \fracDivision
390\times * /Multiplication
350\cup \capSet union/intersection
275+ - (infix)Addition, subtraction
270\to \rightarrow \mapstoArrows
265\setminus \smallsetminus : (range)Set difference, range
260:=Assignment
255\neNot equal
250\not\approxeqNot approximately equal
247\approxApproximately
245-246= < > \lt \gt \nless \ngtrEquality, comparison
241-244\le \leq \ge \geq >=Less/greater or equal
240\in \notin \subset \supset ...Set membership/relations
235\land \wedge \&Logical AND
232\veebar \barwedge (Xor, Nand, Nor)Logical XOR, NAND, NOR
230\lor \vee \parallelLogical OR
220\implies \Rightarrow \vdash \modelsImplication, entailment
219\iff \Leftrightarrow \equivEquivalence
200\forall \exists \exists!Quantifiers
160\mid \vert (set builder)Set builder notation
19-20, ; \ldotsSequence separators

Key Relationships

  • Comparisons bind tighter than logic: x = 1 \lor y = 2 parses as (x = 1) \lor (y = 2), not x = (1 \lor y) = 2
  • AND binds tighter than OR: a \land b \lor c parses as (a \land b) \lor c
  • Logic operators bind tighter than implication: a \lor b \implies c parses as (a \lor b) \implies c

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?) => MathJsonExpression | null;

PrefixParseHandler()

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

SymbolParseHandler()

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

FunctionParseHandler()

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

EnvironmentParseHandler()

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

PostfixParseHandler()

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

InfixParseHandler()

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

MatchfixParseHandler()

type MatchfixParseHandler = (parser, body) => MathJsonExpression | 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.

DefaultEntry

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

ExpressionEntry

type ExpressionEntry = BaseEntry & Trigger & {
kind: "expression";
parse: | MathJsonExpression
| 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: | MathJsonExpression
| 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: | MathJsonExpression
| FunctionParseHandler;
arguments: "enclosure" | "implicit";
};

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.

FunctionEntry.arguments?

optional arguments: "enclosure" | "implicit";

How arguments are parsed:

  • 'enclosure' (default): arguments must be enclosed in parentheses, e.g. \max(a, b).
  • 'implicit': arguments can be provided with or without parentheses, e.g. \det A is parsed as \det(A). Bare arguments are parsed at multiplication precedence, so \det 2A + 1 is parsed as \det(2A) + 1.

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 & {
strict: boolean;
skipSpace: boolean;
parseNumbers: "auto" | "rational" | "decimal" | "never";
getSymbolType: (symbol) =>
| BoxedType
| TypeString;
hasSubscriptEvaluate: (symbol) => boolean;
parseUnexpectedToken: (lhs, parser) => MathJsonExpression | null;
preserveLatex: boolean;
quantifierScope: "tight" | "loose";
timeDerivativeVariable: string;
};

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

ParseLatexOptions.strict

strict: boolean;

Controls the strictness of LaTeX parsing:

  • true: Strict LaTeX syntax required (e.g., \sin{x}, x^{n+1})
  • false: Accept relaxed Math-ASCII/Typst-like syntax in addition to LaTeX (e.g., sin(x), x^(n+1))

Default: true

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
| TypeString;

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

The symbol argument is a valid symbol.

ParseLatexOptions.hasSubscriptEvaluate()?

optional hasSubscriptEvaluate: (symbol) => boolean;

This handler is invoked when the parser needs to determine if a symbol has a custom subscript evaluation handler. If true, subscripts on this symbol will be kept as Subscript expressions rather than being absorbed into a compound symbol name.

ParseLatexOptions.parseUnexpectedToken()

parseUnexpectedToken: (lhs, parser) => MathJsonExpression | 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

ParseLatexOptions.quantifierScope

quantifierScope: "tight" | "loose";

Controls how quantifier scope is determined when parsing expressions like \forall x. P(x) \rightarrow Q(x).

  • "tight": The quantifier binds only to the immediately following well-formed formula, stopping at logical connectives (\rightarrow, \implies, \land, \lor, etc.). This follows standard First-Order Logic conventions. Use explicit parentheses for wider scope: \forall x. (P(x) \rightarrow Q(x)).

  • "loose": The quantifier scope extends to the end of the expression or until a lower-precedence operator is encountered.

Default: "tight"

Example
// With "tight" (default):
// \forall x. P(x) \rightarrow Q(x)
// parses as: (∀x. P(x)) → Q(x)

// With "loose":
// \forall x. P(x) \rightarrow Q(x)
// parses as: ∀x. (P(x) → Q(x))

ParseLatexOptions.timeDerivativeVariable

timeDerivativeVariable: string;

The variable used for time derivatives in Newton notation (\dot{x}, \ddot{x}, etc.).

When parsing \dot{x}, it will be interpreted as ["D", "x", timeDerivativeVariable].

Default: "t"

Parser

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

Parser.options
readonly options: Readonly<ParseLatexOptions>;
Parser.inQuantifierScope
readonly inQuantifierScope: boolean;

True if currently parsing inside a quantifier body (ForAll, Exists, etc.)

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.hasSubscriptEvaluate()
hasSubscriptEvaluate(id): boolean

Check if a symbol has a custom subscript evaluation handler.

####### id

string

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

####### id

string

####### type

string | BoxedType

Parser.enterQuantifierScope()
enterQuantifierScope(): void

Enter a quantifier scope for parsing the body of ForAll, Exists, etc.

Parser.exitQuantifierScope()
exitQuantifierScope(): void

Exit the current quantifier scope

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): MathJsonExpression

Return an error expression with the specified code and arguments

####### code

string | [string, ...MathJsonExpression[]]

####### 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.parseChar()
parseChar(): 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(): MathJsonExpression

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(): MathJsonExpression

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(): MathJsonExpression

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

Return null if none was found.

Parser.parseEnclosure()
parseEnclosure(): MathJsonExpression

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?): MathJsonExpression

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(): MathJsonExpression[][]

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 MathJsonExpression[]

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?

"enclosure" | "implicit"

####### until?

Terminator

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

Parse a postfix operator, such as ' or !.

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

####### lhs

MathJsonExpression

####### until?

Partial<Terminator>

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

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(): MathJsonExpression

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): MathJsonExpression

####### msg

string | [string, ...MathJsonExpression[]]

SerializeLatexOptions

type SerializeLatexOptions = NumberSerializationFormat & {
prettify: boolean;
materialization: boolean | number | [number, number];
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";
dmsFormat: boolean;
angleNormalization: "none" | "0...360" | "-180...180";
};

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.materialization

materialization: boolean | number | [number, number];

Controls the materialization of the lazy collections.

  • If true, lazy collections are materialized, i.e. it is rendered as a LaTeX expression with all its elements.
  • If false, the expression is not materialized, i.e. it is rendered as a LaTeX command with its arguments.
  • If a number is provided, it is the maximum number of elements that will be materialized.
  • If a pair of numbers is provided, it is the number of elements of the head and the tail that will be materialized, respectively.

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

SerializeLatexOptions.dmsFormat?

optional dmsFormat: boolean;

When true, serialize angle quantities in degrees-minutes-seconds format. When false (default), use decimal degrees.

Default
false
Example
const ce = new ComputeEngine();
const angle = ce.box(['Quantity', 9.5, 'deg']);

// DMS format
angle.latex({ dmsFormat: true }); // "9°30'"

// Decimal format (default)
angle.latex({ dmsFormat: false }); // "9.5°"

// Full DMS notation
ce.box(['Quantity', 9.504166, 'deg'])
.latex({ dmsFormat: true }); // "9°30'15\""

SerializeLatexOptions.angleNormalization?

optional angleNormalization: "none" | "0...360" | "-180...180";

Normalize angles to a specific range during serialization. Useful for geographic coordinates and rotations.

Default
'none'
Example
const ce = new ComputeEngine();

// No normalization (show exact value)
ce.box(['Degrees', 370])
.latex({ angleNormalization: 'none' }); // "370°"

// Normalize to [0, 360) - useful for bearings
ce.box(['Degrees', 370])
.latex({ angleNormalization: '0...360' }); // "10°"

ce.box(['Degrees', -45])
.latex({ angleNormalization: '0...360' }); // "315°"

// Normalize to [-180, 180] - useful for longitude
ce.box(['Degrees', 190])
.latex({ angleNormalization: '-180...180' }); // "-170°"

// Combine with DMS format
ce.box(['Degrees', 370])
.latex({
dmsFormat: true,
angleNormalization: '0...360'
}); // "10°0'0\""

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: SerializerDictionary;
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) => "compact" | "regular" | "interval" | "set-builder";
Serializer.serializeFunction()
serializeFunction(expr, def?): string

####### expr

MathJsonExpression

####### def?

SerializerDictionaryEntry

Serializer.serializeSymbol()
serializeSymbol(expr): string

####### expr

MathJsonExpression

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

MathJsonExpression

Serializer.wrapShort()
wrapShort(expr): string

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

####### expr

MathJsonExpression

SerializeHandler()

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

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

Numerics

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(): unknown

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;

BigNumFactory()

type BigNumFactory = (value) => 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

Sign

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

OEIS

OEISSequenceInfo

Result from an OEIS lookup operation.

OEISSequenceInfo.id
id: string;

OEIS sequence ID (e.g., 'A000045')

OEISSequenceInfo.name
name: string;

Sequence name/description

OEISSequenceInfo.terms
terms: number[];

First several terms of the sequence

OEISSequenceInfo.formula?
optional formula: string;

Formula or recurrence (if available)

OEISSequenceInfo.comments?
optional comments: string[];

Comments about the sequence

OEISSequenceInfo.url
url: string;

URL to the OEIS page

OEISOptions

Options for OEIS operations.

OEISOptions.timeout?
optional timeout: number;

Request timeout in milliseconds (default: 10000)

OEISOptions.maxResults?
optional maxResults: number;

Maximum number of results to return for lookups (default: 5)

Other

SymbolTable

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

RuleStep

type RuleStep = KernelRuleStep<Expression>;

A single rule application step with provenance.

RuleSteps

type RuleSteps = KernelRuleSteps<Expression>;

A list of rule application steps.

BoxedRule

type BoxedRule = KernelBoxedRule<Expression, ComputeEngine>;

A boxed/normalized rule form.

BoxedRuleSet

type BoxedRuleSet = KernelBoxedRuleSet<Expression, ComputeEngine>;

Collection of boxed rules.

Scope

type Scope = KernelScope<BoxedDefinition>;

Lexical scope specialized to boxed definitions.

EvalContext

type EvalContext = KernelEvalContext<Expression, BoxedDefinition>;

Evaluation context specialized to this engine/runtime model.

DictionaryInterface

Interface for dictionary-like structures. Use isDictionary() to check if an expression is a dictionary.

DictionaryInterface.keys
DictionaryInterface.entries
DictionaryInterface.values
DictionaryInterface.get()
get(key): Expression

####### key

string

DictionaryInterface.has()
has(key): boolean

####### key

string

BoxedExpression

type BoxedExpression = Expression;

Deprecated

Use Expression instead.

SemiBoxedExpression

type SemiBoxedExpression = ExpressionInput;

Deprecated

Use ExpressionInput instead.

Serialization

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.

NumberSerializationFormat

type NumberSerializationFormat = NumberFormat & {
fractionalDigits: "auto" | "max" | number;
notation: "auto" | "engineering" | "scientific" | "adaptiveScientific";
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"

JsonSerializationOptions

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

Options to control serialization to MathJSON when using Expression.toMathJson().

Tensors

DataTypeMap

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

Map of TensorDataType to JavaScript type.

TensorDataType

type TensorDataType = keyof DataTypeMap;

The type of the cells in a tensor.

TensorData

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

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): Expression

####### 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): Expression[]

####### x

T[]

####### dtype

"expression"

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

####### x

T | T[]

####### dtype

keyof DataTypeMap

TensorField.expression()
expression(x): Expression

####### 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

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: Expression;
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?): Tensor<DT> | DataTypeMap[DT]

####### axis1?

number

####### axis2?

number

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

####### shape

...number[]

Tensor.slice()
slice(index): Tensor<DT>

####### index

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, typeResolver?): BoxedType

####### type

string | AlgebraicType | NegationType | CollectionType | ListType | SetType | RecordType | DictionaryType | TupleType | SymbolType | ExpressionType | NumericType | FunctionSignature | ValueType | TypeReference

####### typeResolver?

TypeResolver

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.dictionary
static dictionary: BoxedType;
BoxedType.setNumber
static setNumber: BoxedType;
BoxedType.setComplex
static setComplex: BoxedType;
BoxedType.setImaginary
static setImaginary: BoxedType;
BoxedType.setReal
static setReal: BoxedType;
BoxedType.setRational
static setRational: BoxedType;
BoxedType.setFiniteInteger
static setFiniteInteger: BoxedType;
BoxedType.setInteger
static setInteger: BoxedType;
BoxedType.type
type: Type;
BoxedType.isUnknown
BoxedType.widen()
static widen(...types): BoxedType

####### types

...readonly (Type | BoxedType)[]

BoxedType.narrow()
static narrow(...types): BoxedType

####### types

...readonly (Type | BoxedType)[]

BoxedType.matches()
matches(other): boolean

####### other

Type | BoxedType

BoxedType.is()
is(other): boolean

####### other

Type

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];
};

The following properties can be added to any MathJSON expression to provide additional information about the expression.

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 string NaN, -Infinity or +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, ...MathJsonExpression[]];
} & MathJsonAttributes;

DictionaryValue

type DictionaryValue = 
| boolean
| number
| string
| ExpressionObject
| ReadonlyArray<DictionaryValue>;

MathJsonDictionaryObject

type MathJsonDictionaryObject = {
dict: Record<string, DictionaryValue>;
} & MathJsonAttributes;

ExpressionObject

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

MathJsonExpression

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

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 = 
| NumericPrimitiveType
| "collection"
| "indexed_collection"
| "list"
| "set"
| "dictionary"
| "record"
| "dictionary"
| "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
      • set: a collection of unique expressions, e.g. set<string>.
      • record: a collection of specific key-value pairs, e.g. record<x: number, y: boolean>.
      • dictionary: a collection of arbitrary key-value pairs e.g. dictionary<string, number>.
      • indexed_collection: collections whose elements can be accessed by a numeric index
        • 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
        • tuple: a fixed-size collection of named or unnamed elements, e.g. tuple<number, boolean>, tuple<x: number, y: boolean>.

NumericPrimitiveType

type NumericPrimitiveType = 
| "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[];
variadicArg: NamedElement;
variadicMin: 0 | 1;
result: Type;
};

AlgebraicType

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

NegationType

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

ValueType

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

RecordType

type RecordType = {
kind: "record";
elements: Record<string, Type>;
};

A record is a collection of key-value pairs.

The keys are strings. The set of keys is fixed.

For a record type to be a subtype of another record type, it must have a subset of the keys, and all their types must match (width subtyping).

DictionaryType

type DictionaryType = {
kind: "dictionary";
values: Type;
};

A dictionary is a collection of key-value pairs.

The keys are strings. The set of keys is also not defined as part of the type and can be modified at runtime.

A dictionary is suitable for use as cache or data storage.

CollectionType

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

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

  • Indexed collections: List, Tuple
  • Non-indexed: Set, Record, Dictionary

ListType

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

The elements of a list can be accessed by their one-based index.

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.

SymbolType

type SymbolType = {
kind: "symbol";
name: string;
};

ExpressionType

type ExpressionType = {
kind: "expression";
operator: string;
};

NumericType

type NumericType = {
kind: "numeric";
type: NumericPrimitiveType;
lower: number;
upper: number;
};

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 indexed.

TupleType

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

The elements of a tuple are indexed and may be named or unnamed. If one element is named, all elements must be named.

TypeReference

type TypeReference = {
kind: "reference";
name: string;
alias: boolean;
def: Type | undefined;
};

Nominal typing

Type

type Type = 
| PrimitiveType
| AlgebraicType
| NegationType
| CollectionType
| ListType
| SetType
| RecordType
| DictionaryType
| TupleType
| SymbolType
| ExpressionType
| NumericType
| NumericPrimitiveType
| 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 = {
get names: string[];
forward: (name) => TypeReference | undefined;
resolve: (name) => TypeReference | undefined;
};

A type resolver should return a definition for a given type name.