@cortex-js/compute-engine
Advanced tools
Changelog
0.10.0 2022-11-17
expr.isLiteral
has been removed. Use expr.numericValue !== null
and
expr.string !== null
instead.ce.forget()
would not affect expressions that previously referenced
the symbol.ce.set()
. Up to 10x faster
when evaluating a simple polynomial in a loop.ce.strict
can be set to false
to bypass some domain and validity checks.Changelog
0.9.0 2022-11-15
Number
. Use expr.domain
to be
get more specific info about what kind of number this is.ce.box()
and ce.parse()
return a canonical expression. A flag
can be used if a non-canonical expression is desired.BoxedExpression
has been reduced. The properties
machineValue
, bignumValue
, asFloat
, asSmallInteger
, asRational
etc... have been replaced with a single numericValue
property.parseUnknownSymbol
is now parseUnknownIdentifier
Support angles in degrees with 30\degree
, 30^\circ
and \ang{30}
.
More accurate error expressions, for example if there is a missing closing
delimiter an ["Error", ["ErrorCode", "'expected-closing-delimiter'", "')'"]]
is produced.
["Expand"]
handles more cases
The trig functions can now have a regular exponent, i.e.\cos^2(x)
in
addition to -1
for inverse, and a combination of \prime
, \doubleprime
and '
for derivatives.
ce.assume()
handle more expressions and can be used to define new symbols by
domain or value.
Better error message when parsing, e.g. \sqrt(2)
(instead of \sqrt{2}
)
Better simplification for square root expressions:
\sqrt{25x^2}
-> 5x
Improved evaluation of ["Power"]
expressions, including for negative
arguments and non-integer exponents and complex arguments and exponents.
Added Arccot
, Arcoth
, Arcsch
, Arcscc
, Arsech
and Arccsc
expr.solve()
returns result for polynomials of order up to 2.
The pattern.match()
function now work correctly for commutative functions,
i.e. ce.pattern(['Add', '_a', 'x']).match(ce.parse('x+y')) -> {"_a": "y"}
Added ce.let()
and ce.set()
to declare and assign values to identifiers.
Preserve exact calculations involving rationals or square root of rationals.
\sqrt{\frac{49}{25}}
-> \frac{7}{5}
Addition and multiplication provide more consistent results for evaluate()
and N()
. Evaluate returns an exact result when possible.
More consistent behavior of the auto
numeric mode: calculations are done
with bignum
and complex
in most cases.
JsonSerializationOptions
has a new option to specify the numeric precision
in the MathJSON serialization.
Shorthand numbers can now be strings if they do not fit in a float-64:
// Before
["Rational", { "num": "1234567890123456789"}, { "num": "2345678901234567889"}]
// Now
["Rational", "1234567890123456789", "2345678901234567889"]
\sum
is now correctly parsed and evaluated. This includes creating a local
scope with the index and expression value of the sum.\gamma
command now correctly maps to ["Gamma"]
["Gamma"]
function when using bignum0
(i.e. with expr.subs({})
) did not work.\mathrm{V_a}
\sqrt{-49}
-> 7i
"auto"
numeric mode if
the precision was less than 15. Now, if the numeric mode is "auto"
,
calculations are done as bignum or complex numbers.V20_20
.isReal
for real numbersChangelog
0.8.0 2022-10-02
Corrected the implementation of expr.toJSON()
, expr.valueOf()
and added
the esoteric [Symbol.toPrimitive]()
method. These are used by JavaScript
when interacting with other primitive types. A major change is that
expr.toJSON()
now returns an Expression
as an object literal, and not a
string serialization of the Expression
.
Changed from "decimal" to "bignum". "Decimal" is a confusing name, since it is
used to represent both integers and floating point numbers. Its key
characteristic is that it is an arbitrary precision number, aka "bignum". This
affects ce.numericMode
which now uses bignum
instead of
decimal',
expr.decimalValue->
expr.bignumValue,
decimalValue()->
bignumValue()`
decimal
or auto
mode produced incorrect results. Example: e^{i\\pi}
Changelog
0.7.0 2022-09-30
ce.latexOptions.preserveLatex
default value is now false
["Error"]
expression (default value) has been
dropped. The first argument is now an error code, either as a string or an
["ErrorCode"]
expression.["Error"]
subexpressions indicating where the problems were.FixedPoint
, Loop
, Product
, Sum
, Break
, Continue
, Block
,
If
, Let
, Set
, Function
, Apply
, Return
Min
, Max
, Clamp
\sum
, \prod
, \int
.\lb
, \ln
, \ln_{10}
, \ln_2
, etc...expr.
subexpressions,
expr.getSubexpressions(),
expr.errors,
expr.symbols,
expr.isValid`.ce.box('Sin').domain
correctly returns ["Domain", "Function"]
.Missing
symbol an ["Error", "'missing'"]
expression is used.1.(3)
.ce.parse('\\sin^{-1}(.5)).N()
Read more at Core Reference and [Arithmetic Reference] (https://cortexjs.io/compute-engine/reference/arithmetic/)
ce.parse()
is an empty string, return an empty
string for expr.latex
or expr.json.latex
: that is, ensure verbatim LaTeX
round-tripping\arccos
would result in a crash{,}
Changelog
0.6.0 2022-04-18
\vec{}
)ComputeEngine.getLatexDictionary
\mathit{speed}
and
\mathrm{radius}
\displaystyle
, \tiny
and moreChangelog
0.5.0 2022-04-05
\begin{pmatrix}...\end{pmatrix}
{...}
simplify()
, evaluate()
and N()
.Changelog
0.4.4
Release Date: 2022-03-27
ComputeEngine
constructorexpr.valueOf
returns rational numbers as [number, number]
when applicablecompute-engine.min.js
) now targets vintage JavaScript
for improved compatibility with outdated toolchains (e.g. Webpack 4) and
environments. The ESM build (compute-engine.min.esm.js
) targets evergreen
JavaScript (currently ECMAScript 2020).Changelog
Transition Guide from 0.4.2
The API has changed substantially between 0.4.2 and 0.4.3, however adapting code to the new API is very straightforward.
The two major changes are the introduction of the BoxedExpression
class and
the removal of top level functions.
The BoxedExpression
class is a immutable box (wrapper) that encapsulates a
MathJSON Expression
. It provides some member functions that can be used to
manipulate the expression, for example expr.simplify()
or expr.evaluate()
.
The boxed expresson itself is immutable. For example, calling expr.simplify()
will return a new, simplified, expression, without modifying expr
.
To create a "boxed" expression from a "raw" MathJSON expression, use ce.box()
.
To create a boxed expression from a LaTeX string, use ce.parse()
.
To access the "raw" MathJSON expression, use the expr.json
property. To
serialize the expression to LaTeX, use the expr.latex
property.
The top level functions such as parse()
and evaluate()
are now member
functions of the ComputeEngine
class or the BoxedExpression
class.
There are additional member functions to examine the content of a boxed
expression. For example, expr.symbol
will return null
if the expression is
not a MathJSON symbol, otherwise it will return the name of the symbol as a
string. Similarly, expr.ops
return the arguments (operands) of a function,
expr.asFloat
return null
if the expression does not have a numeric value
that can be represented by a float, a number
otherwise, etc...
Use expr.canonical
to obtain the canonical form of an expression rather than
the ce.format()
method.
The canonical form is less aggressive in its attempt to simplify than what was
performed by ce.format()
.
The canonical form still accounts for distributive and associative functions,
and will collapse some integer constants. However, in some cases it may be
necessary to invoke expr.simplify()
in order to get the same results as
ce.format(expr)
.
In addition to machine floating points, arbitrary precision numbers and complex numbers, the Compute Engine now also recognize and process rational numbers.
This is mostly an implementation detail, although you may see
["Rational", 3, 4]
, for example, in the value of a expr.json
property.
If you do not want rational numbers represented in the value of the .json
property, you can exclude the Rational
function from the serialization of JSON
(see below) in which case Divide
will be used instead.
Note also that internally (as a result of boxing), Divide
is represented as a
product of a power with a negative exponent. This makes some pattern detection
and simplifications easier. However, when the .json
property is accessed,
product of powers with a negative exponents are converted to a Divide
, unless
you have included Divide
as an excluded function for serialization.
Similarly, Subtract
is converted internally to Add
, but may be serialized
unless excluded.
Rather than using a separate instance of the LatexSyntax
class to customize
the parsing or serialization, use a ComputeEngine
instance and its
ce.parse()
method and the expr.latex
property.
Custom dictionaries (to parse/serialize custom LaTeX syntax) can be passed as an
argument to the ComputeEngine
constructor.
For more advanced customizations, use ce.latexOptions = {...}
. For example, to
change the formatting options of numbers, how the invisible operator is
interpreted, how unknown commands and symbols are interpreted, etc...
Note that there are also now options available for the "serialization" to
MathJSON, i.e. when the expr.json
property is used. It is possible to control
for example if metadata should be included, if shorthand forms are allowed, or
whether some functions should be avoided (Divide
, Sqrt
, Subtract
, etc...).
These options can be set using ce.jsonSerializationOptions = {...}
.
There are more options to compare two expressions.
Previously, match()
could be used to check if one expression matched another
as a pattern.
If match()
returned null
, the first expression could not be matched to the
second. If it returned an object literal, the two expressions matched.
The top-level match()
function is replaced by the expr.match()
method.
However, there are two other options that may offer better results:
expr.isSame(otherExpr)
return true if expr
and otherExpr
are
structurally identical. Structural identity is closely related to the concept
of pattern matching, that is ["Add", 1, "x"]
and ["Add", "x", 1]
are not
the same, since the order of the arguments is different. It is useful for
example to compare some input to an answer that is expected to have a specific
form.expr.isEqual(otherExpr)
return true if expr
and otherExpr
are
mathematically identical. For example ce.parse("1+1").isEqual(ce.parse("2"))
will return true. This is useful if the specific structure of the expression
is not important.It is also possible to evaluate a boolean expression with a relational operator,
such as Equal
:
console.log(ce.box(["Equal", expr, 2]).evaluate().symbol);
// -> "True"
console.log(expr.isEqual(ce.box(2)));
// -> true
| Before | After |
| :---------------------------------------- | :--------------------------------------- |
| expr = ["Add", 1, 2]
| expr = ce.box(["Add", 1, 2])
|
| expr = ce.evaluate(expr)
| expr = expr.evaluate()
|
| console.log(expr)
| console.log(expr.json)
|
| expr = new LatexSyntax().parse("x^2+1")
| expr = ce.parse("x^2+1")
|
| new LatexSyntax().serialize(expr)
| expr.latex
|
| ce.simplify(expr)
| expr.simplify()
|
| await ce.evaluate(expr)
| expr.evaluate()
|
| ce.N(expr)
| expr.N()
|
| ce.domain(expr)
| expr.domain
|
| ce.format(expr...)
| expr.canonical
<br/> expr.simplify()
|