Expression trees #
When parsing an expression via math.parse(expr)
, math.js generates an
expression tree and returns the root node of the tree. An expression tree can
be used to analyze, manipulate, and evaluate expressions.
Example:
const node = math.parse('sqrt(2 + x)')
In this case, the expression sqrt(2 + x)
is parsed as:
FunctionNode sqrt
|
OperatorNode +
/ \
ConstantNode 2 x SymbolNode
Alternatively, this expression tree can be built by manually creating nodes:
const node1 = new math.ConstantNode(2)
const node2 = new math.SymbolNode('x')
const node3 = new math.OperatorNode('+', 'add', [node1, node2])
const node4 = new math.FunctionNode('sqrt', [node3])
The resulting expression tree with root node node4
is equal to the expression
tree generated by math.parse('sqrt(2 + x)')
.
API #
Methods #
All nodes have the following methods:
-
clone() : Node
Create a shallow clone of the node. The node itself is cloned, its childs are not cloned.
-
cloneDeep() : Node
Create a deep clone of the node. Both the node as well as all its childs are cloned recursively.
-
compile() : Object
Compile an expression into optimized JavaScript code.
compile
returns an object with a functionevaluate([scope])
to evaluate. Example:const node = math.parse('2 + x') // returns the root Node of an expression tree const code = node.compile() // returns {evaluate: function (scope) {...}} const evaluate = code.evaluate({x: 3}) // returns 5
-
evaluate([scope]) : Object
Compile and evaluate an expression, this is the equivalent of doing
node.compile().evaluate(scope)
. Example:const node = math.parse('2 + x') // returns the root Node of an expression tree const evaluate = node.evaluate({x: 3}) // returns 5
-
equals(other: Node) : boolean
Test whether this node equals an other node. Does a deep comparison of the values of both nodes.
-
filter(callback: function) : Node[]
Recursively filter nodes in an expression tree. The
callback
function is called ascallback(node: Node, path: string, parent: Node) : boolean
for every node in the tree, and must return a boolean. The functionfilter
returns an array with nodes for which the test returned true. Parameterpath
is a string containing a relative JSON Path.Example:
const node = math.parse('x^2 + x/4 + 3*y') const filtered = node.filter(function (node) { return node.isSymbolNode && node.name === 'x' }) // returns an array with two entries: two SymbolNodes 'x'
-
forEach(callback: function) : void
Execute a callback for each of the child nodes of this node. The
callback
function is called ascallback(child: Node, path: string, parent: Node): void
. Parameterpath
is a string containing a relative JSON Path.See also
traverse
, which is a recursive version offorEach
.Example:
const node = math.parse('3 * x + 2') node.forEach(function (node, path, parent) { switch (node.type) { case 'OperatorNode': console.log(node.type, node.op) break case 'ConstantNode': console.log(node.type, node.value) break case 'SymbolNode': console.log(node.type, node.name) break default: console.log(node.type) } }) // outputs: // OperatorNode * // ConstantNode 2
-
map(callback: function) : Node[]
Transform a node. Creates a new Node having it’s childs be the results of calling the provided callback function for each of the childs of the original node. The
callback
function is called ascallback(child: Node, path: string, parent: Node)
and must return a Node. Parameterpath
is a string containing a relative JSON Path.See also
transform
, which is a recursive version ofmap
. -
toHTML(options: object): string
Get a HTML representation of the parsed expression. Example:
const node = math.parse('sqrt(2/3)') node.toHTML() // returns // <span class="math-function">sqrt</span> // <span class="math-paranthesis math-round-parenthesis">(</span> // <span class="math-number">2</span> // <span class="math-operator math-binary-operator math-explicit-binary-operator">/</span> // <span class="math-number">3</span> // <span class="math-paranthesis math-round-parenthesis">)</span>
Information about the available HTML classes in HTML Classes. Information about the options in Customization.
-
toString(options: object) : string
Get a string representation of the parsed expression. This is not exactly the same as the original input. Example:
const node = math.parse('3+4*2') node.toString() // returns '3 + (4 * 2)'
Information about the options in Customization.
-
toTex(options: object): string
Get a LaTeX representation of the expression. Example:
const node = math.parse('sqrt(2/3)') node.toTex() // returns '\sqrt{\frac{2}{3}}'
Information about the options in Customization.
-
transform(callback: function)
Recursively transform an expression tree via a transform function. Similar to
Array.map
, but recursively executed on all nodes in the expression tree. The callback function is a mapping function accepting a node, and returning a replacement for the node or the original node. Functioncallback
is called ascallback(node: Node, path: string, parent: Node)
for every node in the tree, and must return aNode
. Parameterpath
is a string containing a relative JSON Path.The transform function will stop iterating when a node is replaced by the callback function, it will not iterate over replaced nodes.
For example, to replace all nodes of type
SymbolNode
having name ‘x’ with a ConstantNode with value3
:const node = math.parse('x^2 + 5*x') const transformed = node.transform(function (node, path, parent) { if (node.isSymbolNode && node.name === 'x') { return new math.ConstantNode(3) } else { return node } }) transformed.toString() // returns '3 ^ 2 + 5 * 3'
-
traverse(callback: function): void
Recursively traverse all nodes in a node tree. Executes given callback for this node and each of its child nodes. Similar to
Array.forEach
, except recursive. The callback function is a mapping function accepting a node, and returning nothing. Functioncallback
is called ascallback(node: Node, path: string, parent: Node)
for every node in the tree. Parameterpath
is a string containing a relative JSON Path. Example:const node = math.parse('3 * x + 2') node.traverse(function (node, path, parent) { switch (node.type) { case 'OperatorNode': console.log(node.type, node.op) break case 'ConstantNode': console.log(node.type, node.value) break case 'SymbolNode': console.log(node.type, node.name) break default: console.log(node.type) } }) // outputs: // OperatorNode + // OperatorNode * // ConstantNode 3 // SymbolNode x // ConstantNode 2
Properties #
Each Node
has the following properties:
-
comment: string
A string holding a comment if there was any in the expression, or else the string will be empty string. A comment can be attached to the root node of an expression or to each of the childs nodes of a
BlockNode
. -
isNode: true
Is defined with value
true
on Nodes. Additionally, each type of node adds it’s own flag, for example aSymbolNode
as has a propertyisSymbolNode: true
. -
type: string
The type of the node, for example
'SymbolNode'
in case of aSymbolNode
.
Nodes #
math.js has the following types of nodes. All nodes are available at the
namespace math
.
AccessorNode #
Construction:
new AccessorNode(object: Node, index: IndexNode)
Properties:
object: Node
index: IndexNode
name: string
(read-only) The function or method name. Returns an empty string when undefined.
Examples:
const node1 = math.parse('a[3]')
const object = new math.SymbolNode('a')
const constant3 = new math.ConstantNode(3)
const index = new math.IndexNode([constant3])
const node2 = new math.AccessorNode(object, index)
ArrayNode #
Construction:
new ArrayNode(items: Node[])
Properties:
items: Node[]
Examples:
const node1 = math.parse('[1, 2, 3]')
const one = new math.ConstantNode(1)
const two = new math.ConstantNode(2)
const three = new math.ConstantNode(3)
const node2 = new math.ArrayNode([one, two, three])
AssignmentNode #
Construction:
new AssignmentNode(object: SymbolNode, value: Node)
new AssignmentNode(object: SymbolNode | AccessorNode, index: IndexNode, value: Node)
Properties:
object: SymbolNode | AccessorNode
index: IndexNode | null
value: Node
name: string
(read-only) The function or method name. Returns an empty string when undefined.
Examples:
const node1 = math.parse('a = 3')
const object = new math.SymbolNode('a')
const value = new math.ConstantNode(3)
const node2 = new math.AssignmentNode(object, value)
BlockNode #
A BlockNode
is created when parsing a multi line expression like a=2;b=3
or
a=2\nb=3
. Evaluating a BlockNode
returns a ResultSet
. The results can be
retrieved via ResultSet.entries
or ResultSet.valueOf()
, which contains
an Array
with the results of the visible lines (i.e. lines not ending with
a semicolon).
Construction:
block = new BlockNode(Array.<{node: Node} | {node: Node, visible: boolean}>)
Properties:
blocks: Array.<{node: Node, visible: boolean}>
Examples:
const block1 = math.parse('a=1; b=2; c=3')
const a = new math.SymbolNode('a')
const one = new math.ConstantNode(1)
const ass1 = new math.AssignmentNode(a, one)
const b = new math.SymbolNode('b')
const two = new math.ConstantNode(2)
const ass2 = new math.AssignmentNode(b, two)
const c = new math.SymbolNode('c')
const three = new math.ConstantNode(3)
const ass3 = new math.AssignmentNode(c, three)
const block2 = new BlockNode([
{node: ass1, visible: false},
{node: ass2, visible: false},
{node: ass3, visible: true}
])
ConditionalNode #
Construction:
new ConditionalNode(condition: Node, trueExpr: Node, falseExpr: Node)
Properties:
condition: Node
trueExpr: Node
falseExpr: Node
Examples:
const node1 = math.parse('a > 0 ? a : -a')
const a = new math.SymbolNode('a')
const zero = new math.ConstantNode(0)
const condition = new math.OperatorNode('>', 'larger', [a, zero])
const trueExpr = a
const falseExpr = new math.OperatorNode('-', 'unaryMinus', [a])
const node2 = new math.ConditionalNode(condition, trueExpr, falseExpr)
ConstantNode #
Construction:
new ConstantNode(value: *)
Properties:
value: *
Examples:
const node1 = math.parse('2.4')
const node2 = new math.ConstantNode(2.4)
const node3 = new math.ConstantNode('foo')
FunctionAssignmentNode #
Construction:
new FunctionAssignmentNode(name: string, params: string[], expr: Node)
Properties:
name: string
params: string[]
expr: Node
Examples:
const node1 = math.parse('f(x) = x^2')
const x = new math.SymbolNode('x')
const two = new math.ConstantNode(2)
const expr = new math.OperatorNode('^', 'pow', [x, 2])
const node2 = new math.FunctionAssignmentNode('f', ['x'], expr)
FunctionNode #
Construction:
new FunctionNode(fn: Node | string, args: Node[])
Properties:
fn: Node | string
(read-only) The object or function name which to invoke.args: Node[]
Static functions:
FunctionNode.onUndefinedFunction(name: string)
. This function is invoked when an undefined function is evaluated. By default, the function throws an exception “Undefined function x”. The function can be overwritten to customize this behavior. See alsoSymbolNode.onUndefinedSymbol
.
Examples:
const node1 = math.parse('sqrt(4)')
const four = new math.ConstantNode(4)
const node3 = new math.FunctionNode(new SymbolNode('sqrt'), [four])
IndexNode #
Construction:
new IndexNode(dimensions: Node[])
new IndexNode(dimensions: Node[], dotNotation: boolean)
Each dimension can be a single value, a range, or a property. The values of indices are one-based, including range end.
An optional property dotNotation
can be provided describing whether this index
was written using dot notation like a.b
, or using bracket notation
like a["b"]
. Default value is false
. This information is used when
stringifying the IndexNode.
Properties:
dimensions: Node[]
dotNotation: boolean
Examples:
const node1 = math.parse('A[1:3, 2]')
const A = new math.SymbolNode('A')
const one = new math.ConstantNode(1)
const two = new math.ConstantNode(2)
const three = new math.ConstantNode(3)
const range = new math.RangeNode(one, three)
const index = new math.IndexNode([range, two])
const node2 = new math.AccessorNode(A, index)
ObjectNode #
Construction:
new ObjectNode(properties: Object.<string, Node>)
Properties:
properties: Object.<string, Node>
Examples:
const node1 = math.parse('{a: 1, b: 2, c: 3}')
const a = new math.ConstantNode(1)
const b = new math.ConstantNode(2)
const c = new math.ConstantNode(3)
const node2 = new math.ObjectNode({a: a, b: b, c: c})
OperatorNode #
Construction:
new OperatorNode(op: string, fn: string, args: Node[], implicit: boolean = false)
Additional methods:
-
isUnary() : boolean
Returns true when the
OperatorNode
contains exactly one argument, like with a unary minus:const a = new math.ConstantNode(2) const b = new math.OperatorNode('-', 'unaryMinus', [a]) b.isUnary() // true
-
isBinary() : boolean
Returns true when the
OperatorNode
contains exactly two arguments, like with most regular operators:const a = new math.ConstantNode(2) const b = new math.ConstantNode(3) const c = new math.OperatorNode('+', 'add', [a, b]) c.isBinary() // true
Properties:
op: string
fn: string
args: Node[]
implicit: boolean
True in case of an implicit multiplication, false otherwise
Examples:
const node1 = math.parse('2.3 + 5')
const a = new math.ConstantNode(2.3)
const b = new math.ConstantNode(5)
const node2 = new math.OperatorNode('+', 'add', [a, b])
ParenthesisNode #
Construction:
new ParenthesisNode(content: Node)
Properties:
content: Node
Examples:
const node1 = math.parse('(1)')
const a = new math.ConstantNode(1)
const node2 = new math.ParenthesisNode(a)
RangeNode #
Construction:
new RangeNode(start: Node, end: Node [, step: Node])
Properties:
start: Node
end: Node
step: Node | null
Examples:
const node1 = math.parse('1:10')
const node2 = math.parse('0:2:10')
const zero = new math.ConstantNode(0)
const one = new math.ConstantNode(1)
const two = new math.ConstantNode(2)
const ten = new math.ConstantNode(10)
const node3 = new math.RangeNode(one, ten)
const node4 = new math.RangeNode(zero, ten, two)
RelationalNode #
Construction:
new RelationalNode(conditionals: string[], params: Node[])
conditionals
is an array of strings, each of which may be ‘smaller’, ‘larger’, ‘smallerEq’, ‘largerEq’, ‘equal’, or ‘unequal’. The conditionals
array must contain exactly one fewer item than params
.
Properties:
conditionals: string[]
params: Node[]
A RelationalNode
efficiently represents a chained conditional expression with two or more comparison operators, such as 10 < x <= 50
. The expression is equivalent to 10 < x and x <= 50
, except that x
is evaluated only once, and evaluation stops (is “short-circuited”) once any condition tests false. Operators that are subject to chaining are <
, >
, <=
, >=
, ==
, and !=
. For backward compatibility, math.parse
will return an OperatorNode
if only a single conditional is present (such as x > 2
).
Examples:
const ten = new math.ConstantNode(10)
const x = new math.SymbolNode('x')
const fifty = new math.ConstantNode(50)
const node1 = new math.RelationalNode(['smaller', 'smallerEq'], [ten, x, fifty])
const node2 = math.parse('10 < x <= 50')
SymbolNode #
Construction:
new SymbolNode(name: string)
Properties:
name: string
Static functions:
SymbolNode.onUndefinedSymbol(name: string)
. This function is invoked when an undefined symbol is evaluated. By default, the function throws an exception “Undefined symbol x”. The function can be overwritten to customize this behavior. See alsoFunctionNode.onUndefinedFunction
.
Examples:
const node = math.parse('x')
const x = new math.SymbolNode('x')