16 KiB
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:
var 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 build by manually creating nodes:
var node1 = new math.expression.node.ConstantNode(2);
var node2 = new math.expression.node.SymbolNode('x');
var node3 = new math.expression.node.OperatorNode('+', 'add', [node1, node2]);
var node4 = new math.expression.node.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() : NodeCreate a shallow clone of the node. The node itself is cloned, its childs are not cloned.
-
cloneDeep() : NodeCreate a deep clone of the node. Both the node as well as all its childs are cloned recursively.
-
compile() : ObjectCompile an expression into optimized JavaScript code.
compilereturns an object with a functioneval([scope])to evaluate. Example:var node = math.parse('2 + x'); // returns the root Node of an expression tree var code = node.compile(); // returns {eval: function (scope) {...}} var eval = code.eval({x: 3}); // returns 5 -
eval([scope]) : ObjectCompile and eval an expression, this is the equivalent of doing
node.compile().eval(scope). Example:var node = math.parse('2 + x'); // returns the root Node of an expression tree var eval = node.eval({x: 3}); // returns 5 -
equals(other: Node) : booleanTest 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
callbackfunction is called ascallback(node: Node, path: string, parent: Node) : booleanfor every node in the tree, and must return a boolean. The functionfilterreturns an array with nodes for which the test returned true. Parameterpathis a string containing a relative JSON Path.Example:
var node = math.parse('x^2 + x/4 + 3*y'); var filtered = node.filter(function (node) { return node.isSymbolNode && node.name === 'x'; }); // returns an array with two entries: two SymbolNodes 'x' -
forEach(callback: function) : Node[]Execute a callback for each of the child nodes of this node. The
callbackfunction is called ascallback(child: Node, path: string, parent: Node). Parameterpathis a string containing a relative JSON Path.See also
traverse, which is a recursive version offorEach.Example:
var 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
callbackfunction is called ascallback(child: Node, path: string, parent: Node)and must return a Node. Parameterpathis a string containing a relative JSON Path.See also
transform, which is a recursive version ofmap. -
toHTML(options: object): stringGet a HTML representation of the parsed expression. Example:
var node = math.parse('sqrt(2/3)'); node.toString(); // 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) : stringGet a string representation of the parsed expression. This is not exactly the same as the original input. Example:
var node = math.parse('3+4*2'); node.toString(); // returns '3 + (4 * 2)'Information about the options in Customization.
-
toTex(options: object): stringGet a LaTeX representation of the expression. Example:
var 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. Functioncallbackis called ascallback(node: Node, path: string, parent: Node)for every node in the tree, and must return aNode. Parameterpathis a string containing a relative JSON Path.For example, to replace all nodes of type
SymbolNodehaving name 'x' with a ConstantNode with value3:var node = math.parse('x^2 + 5*x'); var transformed = node.transform(function (node, path, parent) { if (node.isSymbolNode && node.name === 'x') { return new math.expression.node.ConstantNode(3); } else { return node; } }); transformed.toString(); // returns '(3 ^ 2) + (5 * 3)' -
traverse(callback)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 a replacement for the node or the original node. Functioncallbackis called ascallback(node: Node, path: string, parent: Node)for every node in the tree. Parameterpathis a string containing a relative JSON Path. Example:var 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: stringA 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: trueIs defined with value
trueon Nodes. Additionally, each type of node adds it's own flag, for example aSymbolNodeas has a propertyisSymbolNode: true. -
type: stringThe 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.expression.node.
AccessorNode
Construction:
new AccessorNode(object: Node, index: IndexNode)
Properties:
object: Nodeindex: IndexNodename: string(read-only) The function or method name. Returns an empty string when undefined.
Examples:
var node1 = math.parse('a[3]');
var object = new math.expression.node.SymbolNode('a');
var index = new math.expression.node.IndexNode([3]);
var node2 = new math.expression.node.AccessorNode(object, index);
ArrayNode
Construction:
new ArrayNode(items: Node[])
Properties:
items: Node[]
Examples:
var node1 = math.parse('[1, 2, 3]');
var one = new math.expression.node.ConstantNode(1);
var two = new math.expression.node.ConstantNode(2);
var three = new math.expression.node.ConstantNode(3);
var node2 = new math.expression.node.ArrayNode([one, two, three]);
AssignmentNode
Construction:
new AssignmentNode(object: SymbolNode, value: Node)
new AssignmentNode(object: SymbolNode | AccessorNode, index: IndexNode, value: Node)
Properties:
object: SymbolNode | AccessorNodeindex: IndexNode | nullvalue: Nodename: string(read-only) The function or method name. Returns an empty string when undefined.
Examples:
var node1 = math.parse('a = 3');
var object = new math.expression.node.SymbolNode('a');
var value = new math.expression.node.ConstantNode(3);
var node2 = new math.expression.node.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:
var block1 = math.parse('a=1; b=2; c=3');
var a = new math.expression.node.SymbolNode('a');
var one = new math.expression.node.ConstantNode(1);
var ass1 = new math.expression.node.AssignmentNode(a, one);
var b = new math.expression.node.SymbolNode('b');
var two = new math.expression.node.ConstantNode(2);
var ass2 = new math.expression.node.AssignmentNode(b, two);
var c = new math.expression.node.SymbolNode('c');
var three = new math.expression.node.ConstantNode(3);
var ass3 = new math.expression.node.AssignmentNode(c, three);
var 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: NodetrueExpr: NodefalseExpr: Node
Examples:
var node1 = math.parse('a > 0 ? a : -a');
var a = new math.expression.node.SymbolNode('a');
var zero = new math.expression.node.ConstantNode(0);
var condition = new math.expression.node.OperatorNode('>', 'larger', [a, zero]);
var trueExpr = a;
var falseExpr = new math.expression.node.OperatorNode('-', 'unaryMinus', [a]);
var node2 = new math.expression.node.ConditionalNode(condition, trueExpr, falseExpr);
ConstantNode
Construction:
new ConstantNode(value: * [, valueType: string])
Properties:
value: *valueType: string
Examples:
var node1 = math.parse('2.4');
var node2 = new math.expression.node.ConstantNode(2.4);
var node3 = new math.expression.node.ConstantNode('2.4', 'number');
FunctionAssignmentNode
Construction:
new FunctionAssignmentNode(name: string, params: string[], expr: Node)
Properties:
name: stringparams: string[]expr: Node
Examples:
var node1 = math.parse('f(x) = x^2');
var x = new math.expression.node.SymbolNode('x');
var two = new math.expression.node.ConstantNode(2);
var expr = new math.expression.node.OperatorNode('^', 'pow', [x, 2]);
var node2 = new math.expression.node.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[]
Examples:
var node1 = math.parse('sqrt(4)');
var four = new math.expression.node.ConstantNode(4);
var node3 = new math.expression.node.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:
var node1 = math.parse('A[1:3, 2]');
var A = new math.expression.node.SymbolNode('A');
var one = new math.expression.node.ConstantNode(1);
var two = new math.expression.node.ConstantNode(2);
var three = new math.expression.node.ConstantNode(3);
var range = new math.expression.node.RangeNode(one, three);
var index = new math.expression.node.IndexNode([range, two]);
var node2 = new math.expression.node.AccessNode(A, index);
ObjectNode
Construction:
new ObjectNode(properties: Object.<string, Node>)
Properties:
properties: Object.<string, Node>
Examples:
var node1 = math.parse('{a: 1, b: 2, c: 3}');
var a = new math.expression.node.ConstantNode(1);
var b = new math.expression.node.ConstantNode(2);
var c = new math.expression.node.ConstantNode(3);
var node2 = new math.expression.node.ObjectNode({a: a, b: b, c: c});
OperatorNode
Construction:
new OperatorNode(op: string, fn: string, args: Node[])
Properties:
op: stringfn: stringargs: Node[]
Examples:
var node1 = math.parse('2.3 + 5');
var a = new math.expression.node.ConstantNode(2.3);
var b = new math.expression.node.ConstantNode(5);
var node2 = new math.expression.node.OperatorNode('+', 'add', [a, b]);
ParenthesisNode
Construction:
new ParenthesisNode(content: Node)
Properties:
content: Node
Examples:
var node1 = math.parse('(1)');
var a = new math.expression.node.ConstantNode(1);
var node2 = new math.expression.node.ParenthesisNode(a);
RangeNode
Construction:
new RangeNode(start: Node, end: Node [, step: Node])
Properties:
start: Nodeend: Nodestep: Node | null
Examples:
var node1 = math.parse('1:10');
var node2 = math.parse('0:2:10');
var zero = new math.expression.node.ConstantNode(0);
var one = new math.expression.node.ConstantNode(1);
var two = new math.expression.node.ConstantNode(2);
var ten = new math.expression.node.ConstantNode(10);
var node3 = new math.expression.node.RangeNode(one, ten);
var node4 = new math.expression.node.RangeNode(zero, ten, two);
SymbolNode
Construction:
new SymbolNode(name: string)
Properties:
name: string
Examples:
var node = math.parse('x');
var x = new math.expression.node.SymbolNode('x');