@cortex-js/compute-engine
Advanced tools
Changelog
0.26.0 2024-10-01
The property expr.head
has been deprecated. Use expr.operator
instead.
expr.head
is still supported in this version but will be removed in a future
update.
The MathJSON utility functions head()
and op()
have been renamed to
operator()
and operand()
respectively.
The methods for algebraic operations (add
, div
, mul
, etc...) have been
moved from the Compute Engine to the Boxed Expression class. Instead of
calling ce.add(a, b)
, call a.add(b)
.
Those methods also behave more consistently: they apply some additional
simplication rules over canonicalization. For example, while
ce.parse('1 + 2')
return ["Add", 1, 2]
, ce.box(1).add(2)
will return
3
.
The ce.numericMode
option has been removed. Instead, set the ce.precision
property to the desired precision. Set the precision to "machine"
for
machine precision calculations (about 15 digits). Set it to "auto"
for a
default of 21 digits. Set it to a number for a greater fixed precision.
The MathJSON Dictionary element has been deprecated. Use a Dictionary
expression instead.
The ExtendedRealNumbers
, ExtendedComplexNumbers
domains have been
deprecated. Use the RealNumbers
and ComplexNumbers
domains instead.
The "Domain" expression has been deprecated. Use types instead (see below).
Some BoxedExpression
properties have been removed:
expr.isZero
, use expr.is(0)
.expr.isNotZero
, use !expr.is(0)
.expr.isOne
, use expr.is(1)
.expr.isNegativeOne
, use expr.is(-1)
.The signature of ce.declare()
has changed. In particular, the N
handler
has been replaced with evaluate
.
// Before
ce.declare('Mean', {
N: (ce: IComputeEngine): BoxedExpression => {
return ce.number(1);
},
});
// Now
ce.declare('Mean', { evaluate: (ops, { engine }) => ce.number(1) });
New Simplification Engine
The way expressions are simplified has been completely rewritten. The new engine is more powerful and more flexible.
The core API remains the same: to simplify an expression, use
expr.simplify()
.
To use a custom set of rules, pass the rules as an argument to simplify()
:
expr.simplify({rules: [
"|x:<0| -> -x",
"|x:>=0| -> x",
]});
There are a few changes to the way rules are represented. The priority
property has been removed. Instead, rules are applied in the order in which
they are defined.
A rule can also now be a function that takes an expression and returns a new expression. For example:
expr.simplify({rules: [
(expr) => {
if (expr.operator !== 'Abs') return undefined;
const x = expr.args[0];
return x.isNegative ? x.negate() : expr;
}
]});
This can be used to perform more complex transformations at the cost of more verbose JavaScript code.
The algorithm for simplification has been simplified. It attempts to apply each rule in the rule set in turn, then restarts the process until no more rules can be applied or the result of applying a rule returns a previously seen expression.
Function definitions previously included a simplify
handler that could be
used to perform simplifications specific to this function. This has been
removed. Instead, use a rule that matches the function and returns the
simplified expression.
Types
Previously, an expression was associated with a domain such as RealNumbers
or ComplexNumbers
. This has been replaced with a more flexible system of
types.
A type is a set of values that an expression can take. For example, the type
real
is the set of real numbers, the type integer
is the set of integers,
The type of an expression can be set with the type
property. For example:
const expr = ce.parse('\\sqrt{-1}');
console.info(expr.type); // -> imaginary
The type of a symbol can be set when declaring the symbol. For example:
ce.declare('x', 'imaginary');
In addition to primitive types, the type system supports more complex types such union types, intersection types, and function types.
For example, the type real|imaginary
is the union of the real and imaginary
numbers.
When declaring a function, the type of the arguments and the return value can
be specified. For example, to declare a function f
that takes two integers
and returns a real number:
ce.declare('f', '(integer, integer) -> real');
The sets of numbers are defined as follows:
number
- any number, real or complex, including NaN and infinitynon_finite_number
- NaN or infinityreal
finite_real
- finite real numbers (exclude NaN and infinity)imaginary
- imaginary numbers (complex numbers with a real part of 0)finite_imaginary
complex
- complex numbers with a real and imaginary part not equal to 0finite_complex
rational
finite_rational
integer
finite_integer
To check the type of an expression, use the isSubtypeOf()
method. For
example:
let expr = ce.parse('5');
console.info(expr.type.isSubtypeOf('rational')); // -> true
console.info(expr.type.isSubtypeOf('integer')); // -> true
expr = ce.parse('\\frac{1}{2}');
console.info(expr.type.isSubtypeOf('rational')); // -> true
console.info(expr.type.isSubtypeOf('integer')); // -> false
As a shortcut, the properties isReal
, isRational
, isInteger
are
available on boxed expressions. For example:
let expr = ce.parse('5');
console.info(expr.isInteger); // -> true
console.info(expr.isRational); // -> true
They are equivalent to expr.type.isSubtypeOf('integer')
and
expr.type.isSubtypeOf('rational')
respectively.
To check if a number has a non-zero imaginary part, use:
let expr = ce.parse('5i');
console.info(expr.isNumber && expr.isReal === false); // -> true
Collections
Support for collections has been improved. Collections include List
, Set
,
Tuple
, Range
, Interval
, Linspace
and Dictionary
.
It is now possible to check if an element is contained in a collection using
an Element
expression. For example:
let expr = ce.parse('[1, 2, 3]');
ce.box(['Element', 3, expr]).print(); // -> True
ce.box(['Element', 5, expr]).print(); // -> False
To check if a collection is a subset of another collection, use the Subset
expression. For example:
ce.box(['Subset', 'Integers', 'RealNumbers']).print(); // -> True
Collections can also be compared for equality. For example:
let set1 = ce.parse('\\lbrace 1, 2, 3 \\rbrace');
let set2 = ce.parse('\\lbrace 3, 2, 1 \\rbrace');
console.info(set1.isEqual(set2)); // -> true
There are also additional convenience methods on boxed expressions:
expr.isCollection
expr.contains(element)
expr.size
expr.isSubsetOf(other)
expr.indexOf(element)
expr.at(index)
expr.each()
expr.get(key)
Exact calculations
The Compute Engine has a new backed for numerical calculations. The new backed
can handle arbitrary precision calculations, including real and complex
numbers. It can also handle exact calculations, preserving calculations with
rationals and radicals (square root of integers). For example 1/2 + 1/3
is
evaluated to 5/6
instead of 0.8(3)
.
To get an approximate result, use the N()
method, for example
ce.parse("\\frac12 + \\frac13").N()
.
Previously the result of calculations was not always an exact number but returned a numerical approximation instead.
This has now been improved by introducing a NumericValue
type that
encapsulates exact numbers and by doing all calculations in this type.
Previously the calculations were handled manually in the various evaluation
functions. This made the code complicated and error prone.
A NumericValue
is made of:
For example:
While this is a significant change internally, the external API remains the same. The result of calculations should be more predictable and more accurate.
One change to the public API is that the expr.numericValue
property is now
either a machine precision number or a NumericValue
object.
Rule Wildcards
When defining a rule as a LaTeX expression, single character identifiers are
interpreted as wildcards. For example, the rule x + x -> 2x
will match any
expression with two identical terms. The wildcard corresponding to x
is
_x
.
It is now possible to define sequence wildcards and optional sequence wildcards. Sequence wildcards match 1 or more expressions, while optional sequence wildcards match 0 or more expressions.
They are indicated in LaTeX as ...x
and ...x?
respectively. For example:
expr.simplify("x + ...y -> 2x");
If expr
is a + b + c
the rule will match and return 2a
expr.simplify("x + ...y? -> 3x");
If expr
is a + b + c
the rule will match and return 3a
. If expr
is a
the rule will match and return 3a
.
Conditional Rules
Rules can now include conditions that are evaluated at runtime. If the condition is not satisfied, the rules does not apply.
For example, to simplify the expression |x|
:
expr.simplify({rules: [
"|x_{>=0}| -> x",
"|x_{<0}| -> -x",
]});
The condition is indicated as a subscript of the wildcard. The condition can be one of:
boolean
- a boolean value, True or False
string
- a string of characters
number
- a number literal
symbol
expression
numeric
- an expression that has a numeric value, i.e. 2√3, 1/2, 3.14
integer
- an integer value, -2, -1, 0, 1, 2, 3, ...
natural
- a natural number, 0, 1, 2, 3, ...
real
- real numbers, including integers
imaginary
- imaginary numbers, i.e. 2i, 3√-1 (not including real numbers)
complex
- complex numbers, including real and imaginary
rational
- rational numbers, 1/2, 3/4, 5/6, ...
irrational
- irrational numbers, √2, √3, π, ...
algebraic
- algebraic numbers, rational and irrational
transcendental
- transcendental numbers, π, e, ...
positive
- positive real numbers, > 0
negative
- negative real numbers, < 0
nonnegative
- nonnegative real numbers, >= 0
nonpositive
- nonpositive real numbers, <= 0
even
- even integers, 0, 2, 4, 6, ...
odd
- odd integers, 1, 3, 5, 7, ...
prime
:A000040 - prime numbers, 2, 3, 5, 7, 11, ...
composite
:A002808 - composite numbers, 4, 6, 8, 9, 10, ...
notzero
- a value that is not zero
notone
- a value that is not one
finite
- a finite value, not infinite
infinite
constant
variable
function
operator
relation
- an equation or inequality
equation
inequality
vector
- a tensor of rank 1
matrix
- a tensor of rank 2
list
- a collection of values
set
- a collection of unique values
tuple
- a fixed length list
single
- a tuple of length 1
pair
- a tuple of length 2
triple
- a tuple of length 3
collection
- a list, set, or tuple
tensor
- a nested list of values of the same type
scalar
- not a tensor or list
or one of the following expressions:
>0'
-> positive
,\gt0'
-> positive
,<0'
-> negative
,\lt0'
-> negative
,>=0'
-> nonnegative
,\geq0'
-> nonnegative
,<=0'
-> nonpositive
,\leq0'
-> nonpositive
,!=0'
-> notzero
,\neq0'
-> notzero
,!=1'
-> notone
,\neq1'
-> notone
,\in\Z'
-> integer
,\in\mathbb{Z}'
-> integer
,\in\N'
-> natural
,\in\mathbb{N}'
-> natural
,\in\R'
-> real
,\in\mathbb{R}'
-> real
,\in\C'
-> complex
,\in\mathbb{C}'
-> complex
,\in\Q'
-> rational
,\in\mathbb{Q}'
-> rational
,\in\Z^+'
-> integer,positive
,\in\Z^-'
-> intger,negative
,\in\Z^*'
-> nonzero
,\in\R^+'
-> positive
,\in\R^-'
-> negative
,\in\R^*'
-> real,nonzero
,\in\N^*'
-> integer,positive
,\in\N_0'
-> integer,nonnegative
,\in\R\backslash\Q'
-> irrational
,More complex conditions can be specified following a semi-colon, for example:
expr.simplify({x -> 2x; x < 10});
Note that this syntax complements the existing rule syntax, and can be used together with the existing, more verbose, rule syntax.
expr.simplify({rules: [
{match: "x + x", replace: "2x", condition: "x < 10"}
]});
This advanced syntax can specify more complex conditions, for example above
the rule will only apply if x
is less than 10.
Improved results for Expand
. In some cases the expression was not fully
expanded. For example, 4x(3x+2)-5(5x-4)
now returns 12x^2 - 17x + 20
.
Previously it returned 4x(3x+2)+25x-20
.
AsciiMath serialization The expr.toString()
method now returns a
serialization of the expression using the AsciiMath
format.
The serialization to AsciiMath can be customized using the toAsciiMath()
method. For example:
console.log(ce.box(['Sigma', 2]).toAsciiMath({functions: {Sigma: 'sigma'}}));
// -> sigma(2)
The tolerance can now be specified with a value of "auto"
which will use the
precision to determine a reasonable tolerance. The tolerance is used when
comparing two numbers for equality. The tolerance can be specified with the
ce.tolerance
property or in the Compute Engine constructor.
Boxed expressions have some additional properties:
expr.isNumberLiteral
- true if the expression is a number literal.This is
equivalent to checking if expr.numericValue
is not null
.expr.re
- the real part of the expression, if it is a number literal,
undefined
if not a number literal.expr.im
- the imaginary part of the expression, if it is a number literal,
undefined
if not a number literal.expr.bignumRe
- the real part of the expression as a bignum, if it is a
number literal, undefined
if not a number literal or a bignum
representation is not available.expr.bignumIm
- the imaginary part of the expression as a bignum, if it is
a number literal, undefined
if not a number literal or if a bignum
representation is not available.expr.root()
to get the root of the expression. For example, expr.root(3)
will return the cube root of the expression.expr.isLess(), expr.isEqual()
,
etc...) now accept a number argument. For example, expr.isGreater(1)
will
return true if the expression is greater than 1.Added LaTeX syntax to index collections. If a
is a collection:
a[i]
is parsed as ["At", "a", "i"]
.a[i,j]
is parsed as ["At", "a", "i", "j"]
.a_i
is parsed as ["At", "a", "i"]
.a_{i,j}
is parsed as ["At", "a", "i", "j"]
.Added support for Kronecker delta notation, i.e. \delta_{ij}
, which is
parsed as ["KroneckerDelta", "i", "j"]
and is equal to 1 if i = j
and 0
otherwise.
When a single index is provided the value of the function is 1 if the index is 0 and 0 otherwise
When multiple index are provided, the value of the function is 1 if all the indexes are equal and 0 otherwise.
Added support for Iverson Bracket notation, i.e. [a = b]
, which is parsed as
["Boole", ["Equal", "a", "b"]]
and is equal to 1 if its argument is true and
0 otherwise. The argument is expected to be a relational expression.
Implemented Unique
and Tally
on collections. Unique
returns a collection
with only the unique elements of the input collection, and Tally
returns a
collection with the count of each unique element.
console.log(ce.box(['Unique', ['List', 1, 2, 3, 1, 2, 3, 4, 5]]).value);
// -> [1, 2, 3, 4, 5]
console.log(ce.box(['Tally', ['List', 1, 2, 3, 1, 2, 3, 4, 5]]).value);
// -> [['List', 1, 2, 3, 4, 5], ['List', 2, 2, 2, 1, 1]]
Implemented the Map
, Filter
and Tabulate
functions. These functions can
be used to transform collections, for example:
// Using LaTeX
console.log(ce.parse('\\mathrm{Map}([3, 5, 7], x \\mapsto x^2)').toString());
// -> [9, 25, 49]
// Using boxed expressions
console.log(
ce.box(['Map', ['List', 3, 5, 7], ['Square', '_']]).value
);
// -> [9, 25, 49]
console.log(ce.box(['Tabulate',['Square', '_'], 5]).value);
// -> [1, 4, 9, 16, 25]
Tabulate
can be used with multiple indexes. For example, to generate a 4x4
unit matrix:
console.log(ce.box(['Tabulate', ['If', ['Equal', '_1', '_2'], 1, 0]], 4, 4).value);
// -> [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
// Using the Kronecker delta notation:
console.log(ce.parse('\\mathrm{Tabulate}(i, j \\mapsto \\delta_{ij}, 4, 4)').value);
// -> [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
Added Random
function. ["Random"]
returns a real pseudo-random number
betwen 0 and 1. ["Random", 10]
returns an integer between 0 and 9,
["Random", 5, 10]
returns an integer between 5 and 10.
Extended the definition of expr.isConstant
. Previously, it only applied to
symbols, e.g. Pi
. Now it apply to all expressions. expr.isConstant
is true
if the expression is a number literal, a symbol with a constant value, or a
pure function with constant arguments.
The boxed expression properties isPositive
, isNegative
, isNonNegative
,
isNonPositive
, isZero
, isNotZero
now return a useful value for most
function expressions. For example, ce.parse('|x + 1|').isPositive
is true.
If the value cannot be determined, the property will return undefined
. For
example, ce.parse('|x + 1|').isZero
is undefined
.
If the expression is not a real number, the property will return NaN
. For
example, ce.parse('i').isPositive
is NaN
.
Added Choose
function to compute binomial coefficients, i.e. Choose(5, 2)
is equal to 10.
The fallback for non-constructible complex values of trigonometric functions is now implemented via rules.
The canonical order of the arguments has changed and should be more consistent and predictable. In particular, for polynomials, the monomial order is now degrevlex.
Canonical expressions can now include a Root
expression. For example, the
canonical form of \\sqrt[3]{5}
is ["Root", 5, 3]
. Previously, these were
represented as ["Power", 5, ["Divide", 1, 3]]
.
The function definitions no longer have a N
handler. Instead the evaluate
handler has an optional {numericApproximation}
argument.
#188 Throw an error when invalid expressions are boxed, for example
ce.box(["Add", ["3"]])
.
Some LaTeX renderer can't render \/
, so use /
instead.
When definitions are added to the LaTeX dictionary, they now take precedence over the built-in definitions. This allows users to override the built-in definitions.
Improved parsing of functions, including when a mixture of named and positional arguments are used.
#175 Matching some patterns when the target had not enough operands would result in a runtime error.
Changelog
0.25.1 2024-06-27
\frac{a^n}{a^m} = a^{n-m)
Rules can be defined using a new shorthand syntax, where each rule is a string of LaTeX:
expr.simplify(["\\frac{x}{x} -> 1", "x + x -> 2x"]);
Single letter variables are assumed to be wildcards, so x
is interpreted as
the wildcard _x
.
Additionally, the expanded form can also include LaTeX strings. The previous syntax using expressions can still be used, and the new and old syntax can be mixed.
For example:
expr.simplify([
{
match: "\\frac{x}{x}",
replace: "1"
},
{
match: ["Add", "x", "x"],
replace: "2x"
}
]);
The condition
function can also be expressed as a LaTeX string.
expr.simplify([ { match: "\\frac{x}{x}", replace: 1, condition: "x != 0" }, ]);
The shorthand syntax can be used any where a ruleset is expected, including with
the ce.rule()
function.
ce.getRuleSet()
method gives access to the built-in rules.Subtract
and Divide
function can now accept an arbitrary
number of arguments. For example, ["Subtract", 1, 2, 3]
is equivalent to
["Subtract", ["Subtract", 1, 2], 3]
.Changelog
0.25.0 2024-06-25
The canonical form of expressions has changed. It is now more consistent and simpler and should produce more predictable results.
For example, previously ce.parse("1-x^2")
would produce
["Subtract", 1, ["Square", "x"]]
.
While this is a readable form, it introduces some complications when
manipulating the expression: both the Subtract
and Square
functions have
to be handled, in addition to Add
and Power
.
The new canonical form of this expression is
["Add", 1, ["Negate", ["Power", "x", 2]]]
. It is a bit more verbose, but it
is simpler to manipulate.
The ce.serialize()
method has been replaced with expr.toLatex()
and
expr.toMathJson()
. The ce.latexOptions
and ce.jsonSerializationOptions
properties have been removed. Instead, pass the formating options directly to
the toLatex()
and toMathJson()
methods. The ce.parse()
method now takes
an optional argument to specify the format of the input string.
The default JSON serialization of an expression has changed.
Previously, the default JSON serialization, accessed via the .json
property,
had some transformations applied to it (sugaring) to make the JSON more human
readable.
For example, ce.parse("\frac12").json
would return the symbol "Half"
instead of ["Divide", 1, 2]
.
However, this could lead to some confusion when manipulating the JSON directly. Since the JSON is intended to be used by machine more than humans, these additional transformations have been removed.
The expr.json
property now returns the JSON representing the expression,
without any transformations.
To get a version of JSON with some transformations applied use the
ce.toMathJson()
function.
expr = ce.box(["Subtract", 1, ["Square", "x"]]);
console.log(expr.json);
// -> ["Add", 1, ["Negate", ["Power", "x", 2]]]
expr.toMathJson()
// -> ["Subtract", 1, ["Square", "x"]]
expr.toMathJson({exclude: "Square"})
// -> ["Subtract", 1, ["Power", "x", 2]]
In practice, the impact of both of these changes should be minimal. If you
were manipulating expressions using BoxedExpression
, the new canonical form
should make it easier to manipulate expressions. You can potentially simplify
your code by removing special cases for functions such as Square
and
Subtract
.
If you were using the JSON serialization directly, you may also be able to
simplify you code since the default output from expr.json
is now more
consistent and simpler.
The name of some number formatting options has changed. The number formatting
options are an optional argument of ce.parse()
and ce.toLatex()
. See the
NumberFormat
and NumberSerializationFormat
types.
The values +infinity, -infinity and NaN are now represented preferably with
the symbols PositiveInfinity
, NegativeInfinity
and NaN
respectively.
Previously they were represented with numeric values, i.e.
{num: "+Infinity"}
, {num: "-Infinity"}
and {num: "NaN"}
. The numeric
values are still supported, but the symbols are preferred.
The method expr.isNothing
has been removed. Instead, use
expr.symbol === "Nothing"
.
When serializing to LaTeX, the output can be "prettified". This involves modifying the LaTeX output to make it more pleasant to read, for example:
a+\\frac{-b}{c}
-> a-\\frac{b}{c}
a\\times b^{-1}
-> \\frac{a}{b}
\\frac{a}{b}\\frac{c}{d}
-> \\frac{a\\cdot c}{b\\cdot d}
--2
-> 2
This is on by default and can be turned off by setting the prettify
option
to false
. For example:
ce.parse("a+\\frac{-b}{c}").toLatex({prettify: true})
// -> "a-\\frac{b}{c}"
ce.parse("a+\\frac{-b}{c}").toLatex({prettify: false})
// -> "a+\\frac{-b}{c}"
Numbers can have a different digit group length for the whole and fractional
part of a number. For example,
ce.toLatex(ce.parse("1234.5678"), {digitGroup: [3, 0]})
will return
1\,234.5678
.
Numbers can now be formatted using South-East Asian Numbering System, i.e. lakh and crore. For example:
ce.toLatex(ce.parse("12345678"), {digitGroup: "lakh"})
// -> "1,23,45,678"
Expressions with Integrate functions can now be compiled to JavaScript. The compiled function can be used to evaluate the integral numerically. For example:
const f = ce.parse("\\int_0^1 x^2 dx");
const compiled = f.compile();
console.log(compiled()); // -> 0.33232945619482307
#82 Support for angular units. The default is radians, but degrees can be
used by setting ce.angularUnit = "deg"
. Other possible values are "grad" and
"turn". This affects how unitless numbers with a trigonometric function are
interpreted. For example, sin(90)
will return 1 when ce.angularUnit
is
"deg", 0.8939966636005579 when ce.angularUnit
is "grad" and 0 when
ce.angularUnit
is "turn".
Added expr.map(fn)
method to apply a function to each subexpression of an
expression. This can be useful to apply custom canonical forms and compare two
expressions.
An optional canonical form can now be specified with the ce.function()
.
1++2
would result in an expression with a PreIncrement
function. It is now correctly parsed as ["Add", 1, 2]
.-1\frac23
) are now parsed correctly.["Subtract", ["Multiply", 0.5, "x"], ["Divide", "x", 2]]
will now evaluate
to 0
.\cos a \sin b
is now parsed as
(\cos a)(\sin b)
and not \cos (a \sin b)
./
was not applied
correctly, resulting in unexpected results. For example, 1/2/3
would be
parsed as ["Divide", 1, ["Divide", 2, 3]]
instead of
["Divide", ["Divide", 1, 2], 3]
.x(x+1)
where x
is an undeclared
symbol, do not infer that x
is a function. Instead, infer that x
is a
variable and that the expression is a product.["Or", "False", "False"]
, that is when all the
arguments are False
, is now evaluates to False
.e^x^2
, and more generally apply power rule in more
cases.avoidExponentsInRange
formating option would not always avoid exponents
in the specified range.Changelog
0.24.0 2024-02-23
expr.print()
now correctly prints the expression when using the minified
version of the library.expr.isEqual()
now correctly compares equalities and inequalities.expr.match()
has been improved and works correctly in more cases. The
signature of the match
function has been changed so that the pattern is the
first argument, i.e. instead of pattern.match(expr)
use
expr.match(pattern)
.expr.print()
when using the minified version of the library.\ln
and \log
in
LaTeX.\forall
and \exists
in LaTeX.Changelog
0.23.1 2024-01-27
"Multiply"
would not distribute the
Negate
function."Order"
was applied to non-commutative
functions.Changelog
0.23.0 2024-01-01
ExpandAll
function to expand an expression recursively.Factor
function to factor an expression.Together
function to combine rational expressions into a single
fraction.\frac5 7
is now parsed correctly as \frac{5}{7}
instead of
\frac{5}{}7
.ce.parse('\\frac{1}{2}', {canonical: false})
would return Half
instead of
['Divide', '1', '2']
.ce.defineSymbol("count", {value: 0})
would fail: the symbol would be
undefined.(\sqrt2 + \sqrt2)^2
.2(13.1+3.1x)
and 26.2+6.2x
would not be considered equal.\neg
command, synonym for \lnot
-> Not
.2x = 4x
-> x = 2x
.Changelog
0.22.0 2023-11-13
Rule Syntax
The syntax to describe rules has changed. The syntax for a rule was previously
a tuple [lhs, rhs, {condition} ]
. The new syntax is an object with the
properties match
, replace
and condition
. For example:
[["Add", "_x", "_x"], ["Multiply", 2, "_x"]]
{match: ["Add", "_x", "_x"], replace: ["Multiply", 2, "_x"]}
The condition
property is optional, and is either a boxed function or a
JavaScript function. For example, to add a condition that checks that _x
is
a number literal:
{
match: ["Add", "_x", "_x"],
replace: ["Multiply", 2, "_x"],
condition: ({_x}) => _x.isNumberLiteral
}
CanonicalForm
The CanonicalOrder
function has been replaced by the more flexible
CanonicalForm
function. The CanonicalForm
function takes an expression and
a list of transformations to apply. To apply the same transformations as
CanonicalOrder
, use:
['CanonicalForm', expr, 'Order']
These canonical forms can also be specified with box()
and parse()
options:
ce.box(expr, { canonical: "Order" });
ce.parse("x^2 + 2x + 1", { canonical: "Order" });
Rank
, Shape
,Reshape
, Flatten
, Determinant
,
Trace
, Transpose
, ConjugateTranspose
, Inverse
. See the
Linear Algebra reference guide.
Some of these function may not yet return correct result in all cases.expr.print()
method as a synonym for console.log(expr.toString())
.exact
option (false by default) to the expr.match()
pattern
matching method. When true
some additional patterns are automatically
recognized, for example, x
will match ["Multiply", '_a', 'x']
when exact
is false
, but not when exact
is true
.expr.solve()
has been improved and can now solve
more equations.Changelog
0.21.0 2023-11-02
#125 Parse and serialize environemnts, i.e.
\begin{matrix} 1 & 2 \\ 3 & 4 \end{matrix}
will be parsed as
["Matrix", ["List", ["List", 1, 2], ["List", 3, 4]]]
.
A new section on Linear Algebra has some details on the supported formats.
The linear algebra operations are limited at the moment, but will be expanded in the future.
Added IsSame
function, which is the function expression corresponding to
expr.isSame()
.
<s>Added CanonicalOrder
function, which sorts the arguments of commutative
functions into canonical order. This is useful to compare two non-canonical
expressions for equality.</s>
ce.box(["CanonicalOrder", ["Add", 1, "x"]]).isSame(
ce.box(["CanonicalOrder", ["Add", "x", 1]])
);
// -> true
\sum
) with a bound that is not a number, return the
sum expression instead of an error.Changelog
0.20.2 2023-10-31
console.info(ce.parse("\\lim_{x \\to 0} \\frac{\\sin(x)}{x}").value);
// -> 1
console.info(ce.parse("\\int_{0}^{2} x^2 dx").value);
// -> 2.6666666666666665