UNPKG

16.9 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.ConstantNode(2)
27const node2 = new math.SymbolNode('x')
28const node3 = new math.OperatorNode('+', 'add', [node1, node2])
29const node4 = new math.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 `evaluate([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 {evaluate: function (scope) {...}}
60 const evaluate = code.evaluate({x: 3}) // returns 5
61 ```
62
63- `evaluate([scope]) : Object`
64
65 Compile and evaluate an expression, this is the equivalent of doing
66 `node.compile().evaluate(scope)`. Example:
67
68 ```js
69 const node = math.parse('2 + x') // returns the root Node of an expression tree
70 const evaluate = node.evaluate({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.toHTML()
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 The transform function will stop iterating when a node is replaced by the
192 callback function, it will not iterate over replaced nodes.
193
194 For example, to replace all nodes of type `SymbolNode` having name 'x' with a
195 ConstantNode with value `3`:
196
197 ```js
198 const node = math.parse('x^2 + 5*x')
199 const transformed = node.transform(function (node, path, parent) {
200 if (node.isSymbolNode && node.name === 'x') {
201 return new math.ConstantNode(3)
202 }
203 else {
204 return node
205 }
206 })
207 transformed.toString() // returns '3 ^ 2 + 5 * 3'
208 ```
209
210- `traverse(callback)`
211
212 Recursively traverse all nodes in a node tree. Executes given callback for
213 this node and each of its child nodes. Similar to `Array.forEach`, except
214 recursive.
215 The callback function is a mapping function accepting a node, and returning
216 a replacement for the node or the original node. Function `callback` is
217 called as `callback(node: Node, path: string, parent: Node)` for every node
218 in the tree. Parameter `path` is a string containing a relative JSON Path.
219 Example:
220
221 ```js
222 const node = math.parse('3 * x + 2')
223 node.traverse(function (node, path, parent) {
224 switch (node.type) {
225 case 'OperatorNode':
226 console.log(node.type, node.op)
227 break
228 case 'ConstantNode':
229 console.log(node.type, node.value)
230 break
231 case 'SymbolNode':
232 console.log(node.type, node.name)
233 break
234 default:
235 console.log(node.type)
236 }
237 })
238 // outputs:
239 // OperatorNode +
240 // OperatorNode *
241 // ConstantNode 3
242 // SymbolNode x
243 // ConstantNode 2
244 ```
245
246
247### Properties
248
249Each `Node` has the following properties:
250
251- `comment: string`
252
253 A string holding a comment if there was any in the expression, or else the
254 string will be empty string. A comment can be attached to the root node of
255 an expression or to each of the childs nodes of a `BlockNode`.
256
257- `isNode: true`
258
259 Is defined with value `true` on Nodes. Additionally, each type of node
260 adds it's own flag, for example a `SymbolNode` as has a property
261 `isSymbolNode: true`.
262
263- `type: string`
264
265 The type of the node, for example `'SymbolNode'` in case of a `SymbolNode`.
266
267
268## Nodes
269
270math.js has the following types of nodes. All nodes are available at the
271namespace `math`.
272
273
274### AccessorNode
275
276Construction:
277
278```
279new AccessorNode(object: Node, index: IndexNode)
280```
281
282Properties:
283
284- `object: Node`
285- `index: IndexNode`
286- `name: string` (read-only) The function or method name. Returns an empty string when undefined.
287
288Examples:
289
290```js
291const node1 = math.parse('a[3]')
292
293const object = new math.SymbolNode('a')
294const index = new math.IndexNode([3])
295const node2 = new math.AccessorNode(object, index)
296```
297
298
299### ArrayNode
300
301Construction:
302
303```
304new ArrayNode(items: Node[])
305```
306
307Properties:
308
309- `items: Node[]`
310
311Examples:
312
313```js
314const node1 = math.parse('[1, 2, 3]')
315
316const one = new math.ConstantNode(1)
317const two = new math.ConstantNode(2)
318const three = new math.ConstantNode(3)
319const node2 = new math.ArrayNode([one, two, three])
320```
321
322
323### AssignmentNode
324
325Construction:
326
327```
328new AssignmentNode(object: SymbolNode, value: Node)
329new AssignmentNode(object: SymbolNode | AccessorNode, index: IndexNode, value: Node)
330```
331
332Properties:
333
334- `object: SymbolNode | AccessorNode`
335- `index: IndexNode | null`
336- `value: Node`
337- `name: string` (read-only) The function or method name. Returns an empty string when undefined.
338
339Examples:
340
341```js
342const node1 = math.parse('a = 3')
343
344const object = new math.SymbolNode('a')
345const value = new math.ConstantNode(3)
346const node2 = new math.AssignmentNode(object, value)
347```
348
349
350### BlockNode
351
352A `BlockNode` is created when parsing a multi line expression like `a=2;b=3` or
353`a=2\nb=3`. Evaluating a `BlockNode` returns a `ResultSet`. The results can be
354retrieved via `ResultSet.entries` or `ResultSet.valueOf()`, which contains
355an `Array` with the results of the visible lines (i.e. lines not ending with
356a semicolon).
357
358Construction:
359
360```
361block = new BlockNode(Array.<{node: Node} | {node: Node, visible: boolean}>)
362```
363
364Properties:
365
366- `blocks: Array.<{node: Node, visible: boolean}>`
367
368Examples:
369
370```js
371const block1 = math.parse('a=1; b=2; c=3')
372
373const a = new math.SymbolNode('a')
374const one = new math.ConstantNode(1)
375const ass1 = new math.AssignmentNode(a, one)
376
377const b = new math.SymbolNode('b')
378const two = new math.ConstantNode(2)
379const ass2 = new math.AssignmentNode(b, two)
380
381const c = new math.SymbolNode('c')
382const three = new math.ConstantNode(3)
383const ass3 = new math.AssignmentNode(c, three)
384
385const block2 = new BlockNode([
386 {node: ass1, visible: false},
387 {node: ass2, visible: false},
388 {node: ass3, visible: true}
389])
390```
391
392
393### ConditionalNode
394
395Construction:
396
397```
398new ConditionalNode(condition: Node, trueExpr: Node, falseExpr: Node)
399```
400
401Properties:
402
403- `condition: Node`
404- `trueExpr: Node`
405- `falseExpr: Node`
406
407Examples:
408
409```js
410const node1 = math.parse('a > 0 ? a : -a')
411
412const a = new math.SymbolNode('a')
413const zero = new math.ConstantNode(0)
414const condition = new math.OperatorNode('>', 'larger', [a, zero])
415const trueExpr = a
416const falseExpr = new math.OperatorNode('-', 'unaryMinus', [a])
417const node2 = new math.ConditionalNode(condition, trueExpr, falseExpr)
418```
419
420### ConstantNode
421
422Construction:
423
424```
425new ConstantNode(value: *)
426```
427
428Properties:
429
430- `value: *`
431
432Examples:
433
434```js
435const node1 = math.parse('2.4')
436
437const node2 = new math.ConstantNode(2.4)
438const node3 = new math.ConstantNode('foo')
439```
440
441
442### FunctionAssignmentNode
443
444Construction:
445
446```
447new FunctionAssignmentNode(name: string, params: string[], expr: Node)
448```
449
450Properties:
451
452- `name: string`
453- `params: string[]`
454- `expr: Node`
455
456Examples:
457
458```js
459const node1 = math.parse('f(x) = x^2')
460
461const x = new math.SymbolNode('x')
462const two = new math.ConstantNode(2)
463const expr = new math.OperatorNode('^', 'pow', [x, 2])
464const node2 = new math.FunctionAssignmentNode('f', ['x'], expr)
465```
466
467
468### FunctionNode
469
470Construction:
471
472```
473new FunctionNode(fn: Node | string, args: Node[])
474```
475
476Properties:
477
478- `fn: Node | string` (read-only) The object or function name which to invoke.
479- `args: Node[]`
480
481Examples:
482
483```js
484const node1 = math.parse('sqrt(4)')
485
486const four = new math.ConstantNode(4)
487const node3 = new math.FunctionNode(new SymbolNode('sqrt'), [four])
488```
489
490
491### IndexNode
492
493Construction:
494
495```
496new IndexNode(dimensions: Node[])
497new IndexNode(dimensions: Node[], dotNotation: boolean)
498```
499
500Each dimension can be a single value, a range, or a property. The values of
501indices are one-based, including range end.
502
503An optional property `dotNotation` can be provided describing whether this index
504was written using dot notation like `a.b`, or using bracket notation
505like `a["b"]`. Default value is `false`. This information is used when
506stringifying the IndexNode.
507
508Properties:
509
510- `dimensions: Node[]`
511- `dotNotation: boolean`
512
513Examples:
514
515```js
516const node1 = math.parse('A[1:3, 2]')
517
518const A = new math.SymbolNode('A')
519const one = new math.ConstantNode(1)
520const two = new math.ConstantNode(2)
521const three = new math.ConstantNode(3)
522
523const range = new math.RangeNode(one, three)
524const index = new math.IndexNode([range, two])
525const node2 = new math.AccessNode(A, index)
526```
527
528### ObjectNode
529
530Construction:
531
532```
533new ObjectNode(properties: Object.<string, Node>)
534```
535
536Properties:
537
538- `properties: Object.<string, Node>`
539
540Examples:
541
542```js
543const node1 = math.parse('{a: 1, b: 2, c: 3}')
544
545const a = new math.ConstantNode(1)
546const b = new math.ConstantNode(2)
547const c = new math.ConstantNode(3)
548const node2 = new math.ObjectNode({a: a, b: b, c: c})
549```
550
551
552### OperatorNode
553
554Construction:
555
556```
557new OperatorNode(op: string, fn: string, args: Node[])
558```
559
560Additional methods:
561
562- `isUnary() : boolean`
563
564 Returns true when the `OperatorNode` contains exactly one argument,
565 like with a unary minus:
566
567 ```js
568 const a = new math.ConstantNode(2)
569 const b = new math.OperatorNode('-', 'unaryMinus', [a])
570 b.isUnary() // true
571 ```
572
573- `isBinary() : boolean`
574
575 Returns true when the `OperatorNode` contains exactly two arguments,
576 like with most regular operators:
577
578 ```js
579 const a = new math.ConstantNode(2)
580 const b = new math.ConstantNode(3)
581 const c = new math.OperatorNode('+', 'add', [a, b])
582 c.isBinary() // true
583 ```
584
585Properties:
586
587- `op: string`
588- `fn: string`
589- `args: Node[]`
590
591Examples:
592
593```js
594const node1 = math.parse('2.3 + 5')
595
596const a = new math.ConstantNode(2.3)
597const b = new math.ConstantNode(5)
598const node2 = new math.OperatorNode('+', 'add', [a, b])
599```
600
601### ParenthesisNode
602
603Construction:
604
605```
606new ParenthesisNode(content: Node)
607```
608
609Properties:
610
611- `content: Node`
612
613Examples:
614
615```js
616const node1 = math.parse('(1)')
617
618const a = new math.ConstantNode(1)
619const node2 = new math.ParenthesisNode(a)
620```
621
622### RangeNode
623
624Construction:
625
626```
627new RangeNode(start: Node, end: Node [, step: Node])
628```
629
630Properties:
631
632- `start: Node`
633- `end: Node`
634- `step: Node | null`
635
636Examples:
637
638```js
639const node1 = math.parse('1:10')
640const node2 = math.parse('0:2:10')
641
642const zero = new math.ConstantNode(0)
643const one = new math.ConstantNode(1)
644const two = new math.ConstantNode(2)
645const ten = new math.ConstantNode(10)
646
647const node3 = new math.RangeNode(one, ten)
648const node4 = new math.RangeNode(zero, ten, two)
649```
650
651### RelationalNode
652
653Construction:
654
655```
656new RelationalNode(conditionals: string[], params: Node[])
657```
658
659`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`.
660
661Properties:
662
663- `conditionals: string[]`
664- `params: Node[]`
665
666A `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`).
667
668Examples:
669
670```js
671
672const ten = new math.ConstantNode(10)
673const x = new math.SymbolNode('x')
674const fifty = new math.ConstantNode(50)
675
676const node1 = new math.RelationalNode(['smaller', 'smallerEq'], [ten, x, fifty])
677const node2 = math.parse('10 < x <= 50')
678```
679
680
681### SymbolNode
682
683Construction:
684
685```
686new SymbolNode(name: string)
687```
688
689Properties:
690
691- `name: string`
692
693Examples:
694
695```js
696const node = math.parse('x')
697
698const x = new math.SymbolNode('x')
699```