mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-25 15:07:57 +00:00
526 lines
12 KiB
Markdown
526 lines
12 KiB
Markdown
# 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
|
|
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:
|
|
|
|
```js
|
|
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() : Node`
|
|
|
|
Recursively clone an expression tree.
|
|
|
|
- `compile(namespace: Object) : Object`
|
|
|
|
Compile an expression into optimized JavaScript code.
|
|
The expression is compiled against a namespace, typically `math`, needed to
|
|
bind internally used functions. `compile` returns an object with a function
|
|
`eval([scope])` to evaluate. Example:
|
|
|
|
```js
|
|
var node = math.parse('2 + x'); // returns the root Node of an expression tree
|
|
var code = node.compile(math); // returns {eval: function (scope) {...}}
|
|
var eval = code.eval({x: 3}; // returns 5
|
|
```
|
|
|
|
- `filter(callback: function) : Array.<Node>`
|
|
|
|
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
|
|
var node = math.parse('x^2 + x/4 + 3*y');
|
|
var filtered = node.filter(function (node) {
|
|
return node.type == 'SymbolNode' && node.name == 'x';
|
|
});
|
|
// returns an array with two entries: two SymbolNodes 'x'
|
|
```
|
|
|
|
- `forEach(callback: function) : Array.<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
|
|
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) : Array.<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`.
|
|
|
|
- `toString() : string`
|
|
|
|
Get a string representation of the parsed expression. This is not exactly
|
|
the same as the original input. Example:
|
|
|
|
```js
|
|
var node = math.parse('3+4*2');
|
|
node.toString(); // returns '3 + (4 * 2)'
|
|
```
|
|
|
|
- `toTex(): string`
|
|
|
|
Get a [LaTeX](http://en.wikipedia.org/wiki/LaTeX) representation of the
|
|
expression. Example:
|
|
|
|
```js
|
|
var node = math.parse('sqrt(2/3)');
|
|
node.toTex(); // returns '\sqrt{\frac{2}{3}}'
|
|
```
|
|
|
|
- `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.
|
|
|
|
For example, to replace all nodes of type `SymbolNode` having name 'x' with a
|
|
ConstantNode with value 2:
|
|
|
|
```js
|
|
var node = math.parse('x^2 + 5*x');
|
|
var transformed = node.transform(function (node, path, parent) {
|
|
if (node.type == 'SymbolNode' && 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. 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
|
|
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
|
|
```
|
|
|
|
|
|
### Static methods
|
|
|
|
- `Node.isNode(object) : boolean`
|
|
|
|
Test whether an object is a `Node`. Returns `true` when `object` is an
|
|
instance of `Node`, else returns `false`.
|
|
|
|
|
|
### Properties
|
|
|
|
Each `Node` has the following properties:
|
|
|
|
- `type: string`
|
|
|
|
The type of the node, for example `'SymbolNode'`.
|
|
|
|
|
|
## Nodes
|
|
|
|
math.js has the following types of nodes. All nodes are available at the
|
|
namespace `math.expression.node`.
|
|
|
|
### ArrayNode
|
|
|
|
Construction:
|
|
|
|
```
|
|
new ArrayNode(nodes: Node[])
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `nodes: Node[]`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
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(name: string, expr: Node)
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `name: string`
|
|
- `expr: Node`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
var node1 = math.parse('a = 3');
|
|
|
|
var expr = new math.expression.node.ConstantNode(3);
|
|
var node2 = new math.expression.node.AssignmentNode('a', expr);
|
|
```
|
|
|
|
|
|
### 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
|
|
var block1 = math.parse('a=1; b=2; c=3');
|
|
|
|
var one = new math.expression.node.ConstantNode(1);
|
|
var a = new math.expression.node.AssignmentNode('a', one);
|
|
|
|
var two = new math.expression.node.ConstantNode(2);
|
|
var b = new math.expression.node.AssignmentNode('b', two);
|
|
|
|
var three = new math.expression.node.ConstantNode(3);
|
|
var c = new math.expression.node.AssignmentNode('c', three);
|
|
|
|
var block2 = new BlockNode([
|
|
{node: a, visible: false},
|
|
{node: b, visible: false},
|
|
{node: c, visible: true}
|
|
]);
|
|
```
|
|
|
|
|
|
### ConditionalNode
|
|
|
|
Construction:
|
|
|
|
```
|
|
new ConditionalNode(condition: Node, trueExpr: Node, falseExpr: Node)
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `condition: Node`
|
|
- `trueExpr: Node`
|
|
- `falseExpr: Node`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
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: string`
|
|
- `params: string[]`
|
|
- `expr: Node`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
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(name: string, args: Node[])
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `symbol: Node`
|
|
- `args: Node[]`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
var node1 = math.parse('sqrt(4)');
|
|
|
|
var four = new math.expression.node.ConstantNode(4);
|
|
var node2 = new math.expression.node.FunctionNode('sqrt', [four]);
|
|
```
|
|
|
|
|
|
### IndexNode
|
|
|
|
Construction:
|
|
|
|
```
|
|
new IndexNode(object: Node, ranges: Node[])
|
|
```
|
|
|
|
Note that ranges are one-based, including range end.
|
|
|
|
Properties:
|
|
|
|
- `object: Node`
|
|
- `ranges: Node[]`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
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 node2 = new math.expression.node.IndexNode(A, [range, two]);
|
|
```
|
|
|
|
### OperatorNode
|
|
|
|
Construction:
|
|
|
|
```
|
|
new OperatorNode(op: string, fn: string, args: Node[])
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `op: string`
|
|
- `fn: string`
|
|
- `args: Node[]`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
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]);
|
|
```
|
|
|
|
### RangeNode
|
|
|
|
Construction:
|
|
|
|
```
|
|
new RangeNode(start: Node, end: Node [, step: Node])
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `start: Node`
|
|
- `end: Node`
|
|
- `step: Node | null`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
var node = math.parse('x');
|
|
|
|
var x = new math.expression.node.SymbolNode('x');
|
|
```
|
|
|
|
|
|
### UpdateNode
|
|
|
|
Construction:
|
|
|
|
```
|
|
new UpdateNode(index: IndexNode, expr: Node)
|
|
```
|
|
|
|
Properties:
|
|
|
|
- `index: IndexNode`
|
|
- `expr: Node`
|
|
|
|
Examples:
|
|
|
|
```js
|
|
var node1 = math.parse('A[3, 1] = 4');
|
|
|
|
var A = new math.expression.node.SymbolNode('A');
|
|
var one = new math.expression.node.ConstantNode(1);
|
|
var three = new math.expression.node.ConstantNode(3);
|
|
var four = new math.expression.node.ConstantNode(4);
|
|
|
|
var index = new math.expression.node.IndexNode(A, [three, one]);
|
|
var node2 = new math.expression.node.UpdateNode(index, four);
|
|
```
|