UNPKG

17.8 kBMarkdownView Raw
1# Expression trees
2
3When parsing an expression via `math.parse(expr)`, math.js generates an
4expression tree and returns the root node of the tree. An expression tree can
5be used to analyze, manipulate, and evaluate expressions.
6
7Example:
8
9```js
10const node = math.parse('sqrt(2 + x)')
11```
12
13In this case, the expression `sqrt(2 + x)` is parsed as:
14
15```
16 FunctionNode sqrt
17 |
18 OperatorNode +
19 / \
20 ConstantNode 2 x SymbolNode
21```
22
23Alternatively, this expression tree can be build by manually creating nodes:
24
25```js
26const node1 = new math.expression.node.ConstantNode(2)
27const node2 = new math.expression.node.SymbolNode('x')
28const node3 = new math.expression.node.OperatorNode('+', 'add', [node1, node2])
29const node4 = new math.expression.node.FunctionNode('sqrt', [node3])
30```
31
32The resulting expression tree with root node `node4` is equal to the expression
33tree generated by `math.parse('sqrt(2 + x)')`.
34
35
36## API
37
38### Methods
39
40All nodes have the following methods:
41
42- `clone() : Node`
43
44 Create a shallow clone of the node.
45 The node itself is cloned, its childs are not cloned.
46
47- `cloneDeep() : Node`
48
49 Create a deep clone of the node.
50 Both the node as well as all its childs are cloned recursively.
51
52- `compile() : Object`
53
54 Compile an expression into optimized JavaScript code. `compile` returns an
55 object with a function `eval([scope])` to evaluate. Example:
56
57 ```js
58 const node = math.parse('2 + x') // returns the root Node of an expression tree
59 const code = node.compile() // returns {eval: function (scope) {...}}
60 const eval = code.eval({x: 3}) // returns 5
61 ```
62
63- `eval([scope]) : Object`
64
65 Compile and eval an expression, this is the equivalent of doing
66 `node.compile().eval(scope)`. Example:
67
68 ```js
69 const node = math.parse('2 + x') // returns the root Node of an expression tree
70 const eval = node.eval({x: 3}) // returns 5
71 ```
72
73- `equals(other: Node) : boolean`
74
75 Test whether this node equals an other node. Does a deep comparison of the
76 values of both nodes.
77
78- `filter(callback: function) : Node[]`
79
80 Recursively filter nodes in an expression tree. The `callback` function is
81 called as `callback(node: Node, path: string, parent: Node) : boolean` for
82 every node in the tree, and must return a boolean. The function `filter`
83 returns an array with nodes for which the test returned true.
84 Parameter `path` is a string containing a relative JSON Path.
85
86 Example:
87
88 ```js
89 const node = math.parse('x^2 + x/4 + 3*y')
90 const filtered = node.filter(function (node) {
91 return node.isSymbolNode && node.name === 'x'
92 })
93 // returns an array with two entries: two SymbolNodes 'x'
94 ```
95
96- `forEach(callback: function) : Node[]`
97
98 Execute a callback for each of the child nodes of this node. The `callback`
99 function is called as `callback(child: Node, path: string, parent: Node)`.
100 Parameter `path` is a string containing a relative JSON Path.
101
102 See also `traverse`, which is a recursive version of `forEach`.
103
104 Example:
105
106 ```js
107 const node = math.parse('3 * x + 2')
108 node.forEach(function (node, path, parent) {
109 switch (node.type) {
110 case 'OperatorNode':
111 console.log(node.type, node.op)
112 break
113 case 'ConstantNode':
114 console.log(node.type, node.value)
115 break
116 case 'SymbolNode':
117 console.log(node.type, node.name)
118 break
119 default:
120 console.log(node.type)
121 }
122 })
123 // outputs:
124 // OperatorNode *
125 // ConstantNode 2
126 ```
127
128- `map(callback: function) : Node[]`
129
130 Transform a node. Creates a new Node having it's childs be the results of
131 calling the provided callback function for each of the childs of the original
132 node. The `callback` function is called as `callback(child: Node, path: string,
133 parent: Node)` and must return a Node. Parameter `path` is a string containing
134 a relative JSON Path.
135
136 See also `transform`, which is a recursive version of `map`.
137
138- `toHTML(options: object): string`
139
140 Get a HTML representation of the parsed expression. Example:
141
142 ```js
143 const node = math.parse('sqrt(2/3)')
144 node.toString()
145 // returns
146 // <span class="math-function">sqrt</span>
147 // <span class="math-paranthesis math-round-parenthesis">(</span>
148 // <span class="math-number">2</span>
149 // <span class="math-operator math-binary-operator math-explicit-binary-operator">/</span>
150 // <span class="math-number">3</span>
151 // <span class="math-paranthesis math-round-parenthesis">)</span>
152 ```
153
154 Information about the available HTML classes in [HTML Classes](html_classes.md).
155 Information about the options in [Customization](customization.md#custom-html-latex-and-string-output).
156
157- `toString(options: object) : string`
158
159 Get a string representation of the parsed expression. This is not exactly
160 the same as the original input. Example:
161
162 ```js
163 const node = math.parse('3+4*2')
164 node.toString() // returns '3 + (4 * 2)'
165 ```
166
167 Information about the options in [Customization](customization.md#custom-html-latex-and-string-output).
168
169- `toTex(options: object): string`
170
171 Get a [LaTeX](https://en.wikipedia.org/wiki/LaTeX) representation of the
172 expression. Example:
173
174 ```js
175 const node = math.parse('sqrt(2/3)')
176 node.toTex() // returns '\sqrt{\frac{2}{3}}'
177 ```
178
179 Information about the options in [Customization](customization.md#custom-html-latex-and-string-output).
180
181- `transform(callback: function)`
182
183 Recursively transform an expression tree via a transform function. Similar
184 to `Array.map`, but recursively executed on all nodes in the expression tree.
185 The callback function is a mapping function accepting a node, and returning
186 a replacement for the node or the original node. Function `callback` is
187 called as `callback(node: Node, path: string, parent: Node)` for every node
188 in the tree, and must return a `Node`. Parameter `path` is a string containing
189 a relative JSON Path.
190
191 For example, to replace all nodes of type `SymbolNode` having name 'x' with a
192 ConstantNode with value `3`:
193
194 ```js
195 const node = math.parse('x^2 + 5*x')
196 const transformed = node.transform(function (node, path, parent) {
197 if (node.isSymbolNode && node.name === 'x') {
198 return new math.expression.node.ConstantNode(3)
199 }
200 else {
201 return node
202 }
203 })
204 transformed.toString() // returns '3 ^ 2 + 5 * 3'
205 ```
206
207- `traverse(callback)`
208
209 Recursively traverse all nodes in a node tree. Executes given callback for
210 this node and each of its child nodes. Similar to `Array.forEach`, except
211 recursive.
212 The callback function is a mapping function accepting a node, and returning
213 a replacement for the node or the original node. Function `callback` is
214 called as `callback(node: Node, path: string, parent: Node)` for every node
215 in the tree. Parameter `path` is a string containing a relative JSON Path.
216 Example:
217
218 ```js
219 const node = math.parse('3 * x + 2')
220 node.traverse(function (node, path, parent) {
221 switch (node.type) {
222 case 'OperatorNode':
223 console.log(node.type, node.op)
224 break
225 case 'ConstantNode':
226 console.log(node.type, node.value)
227 break
228 case 'SymbolNode':
229 console.log(node.type, node.name)
230 break
231 default:
232 console.log(node.type)
233 }
234 })
235 // outputs:
236 // OperatorNode +
237 // OperatorNode *
238 // ConstantNode 3
239 // SymbolNode x
240 // ConstantNode 2
241 ```
242
243
244### Properties
245
246Each `Node` has the following properties:
247
248- `comment: string`
249
250 A string holding a comment if there was any in the expression, or else the
251 string will be empty string. A comment can be attached to the root node of
252 an expression or to each of the childs nodes of a `BlockNode`.
253
254- `isNode: true`
255
256 Is defined with value `true` on Nodes. Additionally, each type of node
257 adds it's own flag, for example a `SymbolNode` as has a property
258 `isSymbolNode: true`.
259
260- `type: string`
261
262 The type of the node, for example `'SymbolNode'` in case of a `SymbolNode`.
263
264
265## Nodes
266
267math.js has the following types of nodes. All nodes are available at the
268namespace `math.expression.node`.
269
270
271### AccessorNode
272
273Construction:
274
275```
276new AccessorNode(object: Node, index: IndexNode)
277```
278
279Properties:
280
281- `object: Node`
282- `index: IndexNode`
283- `name: string` (read-only) The function or method name. Returns an empty string when undefined.
284
285Examples:
286
287```js
288const node1 = math.parse('a[3]')
289
290const object = new math.expression.node.SymbolNode('a')
291const index = new math.expression.node.IndexNode([3])
292const node2 = new math.expression.node.AccessorNode(object, index)
293```
294
295
296### ArrayNode
297
298Construction:
299
300```
301new ArrayNode(items: Node[])
302```
303
304Properties:
305
306- `items: Node[]`
307
308Examples:
309
310```js
311const node1 = math.parse('[1, 2, 3]')
312
313const one = new math.expression.node.ConstantNode(1)
314const two = new math.expression.node.ConstantNode(2)
315const three = new math.expression.node.ConstantNode(3)
316const node2 = new math.expression.node.ArrayNode([one, two, three])
317```
318
319
320### AssignmentNode
321
322Construction:
323
324```
325new AssignmentNode(object: SymbolNode, value: Node)
326new AssignmentNode(object: SymbolNode | AccessorNode, index: IndexNode, value: Node)
327```
328
329Properties:
330
331- `object: SymbolNode | AccessorNode`
332- `index: IndexNode | null`
333- `value: Node`
334- `name: string` (read-only) The function or method name. Returns an empty string when undefined.
335
336Examples:
337
338```js
339const node1 = math.parse('a = 3')
340
341const object = new math.expression.node.SymbolNode('a')
342const value = new math.expression.node.ConstantNode(3)
343const node2 = new math.expression.node.AssignmentNode(object, value)
344```
345
346
347### BlockNode
348
349A `BlockNode` is created when parsing a multi line expression like `a=2;b=3` or
350`a=2\nb=3`. Evaluating a `BlockNode` returns a `ResultSet`. The results can be
351retrieved via `ResultSet.entries` or `ResultSet.valueOf()`, which contains
352an `Array` with the results of the visible lines (i.e. lines not ending with
353a semicolon).
354
355Construction:
356
357```
358block = new BlockNode(Array.<{node: Node} | {node: Node, visible: boolean}>)
359```
360
361Properties:
362
363- `blocks: Array.<{node: Node, visible: boolean}>`
364
365Examples:
366
367```js
368const block1 = math.parse('a=1; b=2; c=3')
369
370const a = new math.expression.node.SymbolNode('a')
371const one = new math.expression.node.ConstantNode(1)
372const ass1 = new math.expression.node.AssignmentNode(a, one)
373
374const b = new math.expression.node.SymbolNode('b')
375const two = new math.expression.node.ConstantNode(2)
376const ass2 = new math.expression.node.AssignmentNode(b, two)
377
378const c = new math.expression.node.SymbolNode('c')
379const three = new math.expression.node.ConstantNode(3)
380const ass3 = new math.expression.node.AssignmentNode(c, three)
381
382const block2 = new BlockNode([
383 {node: ass1, visible: false},
384 {node: ass2, visible: false},
385 {node: ass3, visible: true}
386])
387```
388
389
390### ConditionalNode
391
392Construction:
393
394```
395new ConditionalNode(condition: Node, trueExpr: Node, falseExpr: Node)
396```
397
398Properties:
399
400- `condition: Node`
401- `trueExpr: Node`
402- `falseExpr: Node`
403
404Examples:
405
406```js
407const node1 = math.parse('a > 0 ? a : -a')
408
409const a = new math.expression.node.SymbolNode('a')
410const zero = new math.expression.node.ConstantNode(0)
411const condition = new math.expression.node.OperatorNode('>', 'larger', [a, zero])
412const trueExpr = a
413const falseExpr = new math.expression.node.OperatorNode('-', 'unaryMinus', [a])
414const node2 = new math.expression.node.ConditionalNode(condition, trueExpr, falseExpr)
415```
416
417### ConstantNode
418
419Construction:
420
421```
422new ConstantNode(value: *)
423```
424
425Properties:
426
427- `value: *`
428
429Examples:
430
431```js
432const node1 = math.parse('2.4')
433
434const node2 = new math.expression.node.ConstantNode(2.4)
435const node3 = new math.expression.node.ConstantNode('foo')
436```
437
438
439### FunctionAssignmentNode
440
441Construction:
442
443```
444new FunctionAssignmentNode(name: string, params: string[], expr: Node)
445```
446
447Properties:
448
449- `name: string`
450- `params: string[]`
451- `expr: Node`
452
453Examples:
454
455```js
456const node1 = math.parse('f(x) = x^2')
457
458const x = new math.expression.node.SymbolNode('x')
459const two = new math.expression.node.ConstantNode(2)
460const expr = new math.expression.node.OperatorNode('^', 'pow', [x, 2])
461const node2 = new math.expression.node.FunctionAssignmentNode('f', ['x'], expr)
462```
463
464
465### FunctionNode
466
467Construction:
468
469```
470new FunctionNode(fn: Node | string, args: Node[])
471```
472
473Properties:
474
475- `fn: Node | string` (read-only) The object or function name which to invoke.
476- `args: Node[]`
477
478Examples:
479
480```js
481const node1 = math.parse('sqrt(4)')
482
483const four = new math.expression.node.ConstantNode(4)
484const node3 = new math.expression.node.FunctionNode(new SymbolNode('sqrt'), [four])
485```
486
487
488### IndexNode
489
490Construction:
491
492```
493new IndexNode(dimensions: Node[])
494new IndexNode(dimensions: Node[], dotNotation: boolean)
495```
496
497Each dimension can be a single value, a range, or a property. The values of
498indices are one-based, including range end.
499
500An optional property `dotNotation` can be provided describing whether this index
501was written using dot notation like `a.b`, or using bracket notation
502like `a["b"]`. Default value is `false`. This information is used when
503stringifying the IndexNode.
504
505Properties:
506
507- `dimensions: Node[]`
508- `dotNotation: boolean`
509
510Examples:
511
512```js
513const node1 = math.parse('A[1:3, 2]')
514
515const A = new math.expression.node.SymbolNode('A')
516const one = new math.expression.node.ConstantNode(1)
517const two = new math.expression.node.ConstantNode(2)
518const three = new math.expression.node.ConstantNode(3)
519
520const range = new math.expression.node.RangeNode(one, three)
521const index = new math.expression.node.IndexNode([range, two])
522const node2 = new math.expression.node.AccessNode(A, index)
523```
524
525### ObjectNode
526
527Construction:
528
529```
530new ObjectNode(properties: Object.<string, Node>)
531```
532
533Properties:
534
535- `properties: Object.<string, Node>`
536
537Examples:
538
539```js
540const node1 = math.parse('{a: 1, b: 2, c: 3}')
541
542const a = new math.expression.node.ConstantNode(1)
543const b = new math.expression.node.ConstantNode(2)
544const c = new math.expression.node.ConstantNode(3)
545const node2 = new math.expression.node.ObjectNode({a: a, b: b, c: c})
546```
547
548
549### OperatorNode
550
551Construction:
552
553```
554new OperatorNode(op: string, fn: string, args: Node[])
555```
556
557Additional methods:
558
559- `isUnary() : boolean`
560
561 Returns true when the `OperatorNode` contains exactly one argument,
562 like with a unary minus:
563
564 ```js
565 const a = new math.expression.node.ConstantNode(2)
566 const b = new math.expression.node.OperatorNode('-', 'unaryMinus', [a])
567 b.isUnary() // true
568 ```
569
570- `isBinary() : boolean`
571
572 Returns true when the `OperatorNode` contains exactly two arguments,
573 like with most regular operators:
574
575 ```js
576 const a = new math.expression.node.ConstantNode(2)
577 const b = new math.expression.node.ConstantNode(3)
578 const c = new math.expression.node.OperatorNode('+', 'add', [a, b])
579 c.isBinary() // true
580 ```
581
582Properties:
583
584- `op: string`
585- `fn: string`
586- `args: Node[]`
587
588Examples:
589
590```js
591const node1 = math.parse('2.3 + 5')
592
593const a = new math.expression.node.ConstantNode(2.3)
594const b = new math.expression.node.ConstantNode(5)
595const node2 = new math.expression.node.OperatorNode('+', 'add', [a, b])
596```
597
598### ParenthesisNode
599
600Construction:
601
602```
603new ParenthesisNode(content: Node)
604```
605
606Properties:
607
608- `content: Node`
609
610Examples:
611
612```js
613const node1 = math.parse('(1)')
614
615const a = new math.expression.node.ConstantNode(1)
616const node2 = new math.expression.node.ParenthesisNode(a)
617```
618
619### RangeNode
620
621Construction:
622
623```
624new RangeNode(start: Node, end: Node [, step: Node])
625```
626
627Properties:
628
629- `start: Node`
630- `end: Node`
631- `step: Node | null`
632
633Examples:
634
635```js
636const node1 = math.parse('1:10')
637const node2 = math.parse('0:2:10')
638
639const zero = new math.expression.node.ConstantNode(0)
640const one = new math.expression.node.ConstantNode(1)
641const two = new math.expression.node.ConstantNode(2)
642const ten = new math.expression.node.ConstantNode(10)
643
644const node3 = new math.expression.node.RangeNode(one, ten)
645const node4 = new math.expression.node.RangeNode(zero, ten, two)
646```
647
648### RelationalNode
649
650Construction:
651
652```
653new RelationalNode(conditionals: string[], params: Node[])
654```
655
656`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`.
657
658Properties:
659
660- `conditionals: string[]`
661- `params: Node[]`
662
663A `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`).
664
665Examples:
666
667```js
668
669const ten = new Math.expression.node.ConstantNode(10)
670const x = new Math.expression.node.SymbolNode('x')
671const fifty = new Math.expression.node.ConstantNode(50)
672
673const node1 = new math.expression.node.RelationalNode(['smaller', 'smallerEq'], [ten, x, fifty])
674const node2 = math.parse('10 < x <= 50')
675```
676
677
678### SymbolNode
679
680Construction:
681
682```
683new SymbolNode(name: string)
684```
685
686Properties:
687
688- `name: string`
689
690Examples:
691
692```js
693const node = math.parse('x')
694
695const x = new math.expression.node.SymbolNode('x')
696```