# 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: ```js 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 build by manually creating nodes: ```js 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 function `evaluate([scope])` to evaluate. Example: ```js 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: ```js 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 as `callback(node: Node, path: string, parent: Node) : boolean` for every node in the tree, and must return a boolean. The function `filter` returns an array with nodes for which the test returned true. Parameter `path` is a string containing a relative JSON Path. Example: ```js 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) : Node[]` Execute a callback for each of the child nodes of this node. The `callback` function is called as `callback(child: Node, path: string, parent: Node)`. Parameter `path` is a string containing a relative JSON Path. See also `traverse`, which is a recursive version of `forEach`. Example: ```js 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 as `callback(child: Node, path: string, parent: Node)` and must return a Node. Parameter `path` is a string containing a relative JSON Path. See also `transform`, which is a recursive version of `map`. - `toHTML(options: object): string` Get a HTML representation of the parsed expression. Example: ```js const node = math.parse('sqrt(2/3)') node.toHTML() // returns // sqrt // ( // 2 // / // 3 // ) ``` Information about the available HTML classes in [HTML Classes](html_classes.md). Information about the options in [Customization](customization.md#custom-html-latex-and-string-output). - `toString(options: object) : string` Get a string representation of the parsed expression. This is not exactly the same as the original input. Example: ```js const node = math.parse('3+4*2') node.toString() // returns '3 + (4 * 2)' ``` Information about the options in [Customization](customization.md#custom-html-latex-and-string-output). - `toTex(options: object): string` Get a [LaTeX](https://en.wikipedia.org/wiki/LaTeX) representation of the expression. Example: ```js const node = math.parse('sqrt(2/3)') node.toTex() // returns '\sqrt{\frac{2}{3}}' ``` Information about the options in [Customization](customization.md#custom-html-latex-and-string-output). - `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. Function `callback` is called as `callback(node: Node, path: string, parent: Node)` for every node in the tree, and must return a `Node`. Parameter `path` 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 value `3`: ```js 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)` 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. Function `callback` is called as `callback(node: Node, path: string, parent: Node)` for every node in the tree. Parameter `path` is a string containing a relative JSON Path. Example: ```js 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 a `SymbolNode` as has a property `isSymbolNode: true`. - `type: string` The type of the node, for example `'SymbolNode'` in case of a `SymbolNode`. ## 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: ```js const node1 = math.parse('a[3]') const object = new math.SymbolNode('a') const index = new math.IndexNode([3]) const node2 = new math.AccessorNode(object, index) ``` ### ArrayNode Construction: ``` new ArrayNode(items: Node[]) ``` Properties: - `items: Node[]` Examples: ```js 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: ```js 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: ```js 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: ```js 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: ```js 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: ```js 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[]` Examples: ```js 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: ```js 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.AccessNode(A, index) ``` ### ObjectNode Construction: ``` new ObjectNode(properties: Object.) ``` Properties: - `properties: Object.` Examples: ```js 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: ```js 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: ```js 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: ```js 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: ```js 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: ```js 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: ```js 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` Examples: ```js const node = math.parse('x') const x = new math.SymbolNode('x') ```