0
# Expression Parser and Evaluation
1
2
This document covers Math.js's powerful expression parser and evaluation system, including parsing mathematical expressions, compiling for performance, working with Abstract Syntax Trees (AST), symbolic operations, and advanced expression manipulation.
3
4
## Import
5
6
```typescript
7
import {
8
// Core parsing and evaluation
9
evaluate, parse, compile,
10
// Parser creation
11
parser,
12
// Symbolic operations
13
derivative, simplify, simplifyConstant, simplifyCore, rationalize,
14
resolve, leafCount,
15
// AST Node constructors
16
AccessorNode, ArrayNode, AssignmentNode, BlockNode, ConditionalNode,
17
ConstantNode, FunctionAssignmentNode, FunctionNode, IndexNode,
18
ObjectNode, OperatorNode, ParenthesisNode, RangeNode,
19
RelationalNode, SymbolNode,
20
// Utility
21
symbolicEqual
22
} from 'mathjs'
23
```
24
25
## Basic Expression Evaluation
26
27
### Direct Evaluation
28
29
```typescript
30
evaluate(expr: string | string[], scope?: object): any
31
```
32
{ .api }
33
34
```typescript
35
// Simple arithmetic
36
evaluate('2 + 3') // 5
37
evaluate('2 * 3 + 4') // 10 (follows order of operations)
38
evaluate('sqrt(16)') // 4
39
40
// Complex expressions
41
evaluate('sin(pi/2) + cos(0)') // 2
42
evaluate('2^3 * (4 + 1)') // 40
43
44
// With variables (scope)
45
evaluate('a * x + b', { a: 2, b: 3, x: 4 }) // 11
46
47
// Multiple expressions
48
evaluate(['a = 3', 'b = 4', 'a * b']) // [3, 4, 12]
49
50
// Matrix and array operations in expressions
51
evaluate('[[1,2],[3,4]] * [5,6]') // Matrix-vector multiplication
52
evaluate('sum([1,2,3,4,5])') // 15
53
```
54
55
### Expression Syntax
56
57
Math.js supports a rich expression syntax:
58
59
```typescript
60
// Arithmetic operators
61
evaluate('5 + 3') // Addition: 8
62
evaluate('5 - 3') // Subtraction: 2
63
evaluate('5 * 3') // Multiplication: 15
64
evaluate('5 / 3') // Division: 1.667...
65
evaluate('5 ^ 3') // Exponentiation: 125
66
evaluate('5 % 3') // Modulo: 2
67
68
// Comparison operators
69
evaluate('5 > 3') // true
70
evaluate('5 < 3') // false
71
evaluate('5 >= 5') // true
72
evaluate('5 == 5') // true
73
evaluate('5 != 3') // true
74
75
// Logical operators
76
evaluate('true and false') // false
77
evaluate('true or false') // true
78
evaluate('not true') // false
79
80
// Bitwise operators (with integers)
81
evaluate('5 & 3') // Bitwise AND: 1
82
evaluate('5 | 3') // Bitwise OR: 7
83
evaluate('5 xor 3') // Bitwise XOR: 6
84
evaluate('~5') // Bitwise NOT: -6
85
evaluate('5 << 2') // Left shift: 20
86
evaluate('5 >> 1') // Right shift: 2
87
```
88
89
## Parsing to AST
90
91
### Parse Function
92
93
```typescript
94
parse(expr: string, options?: ParseOptions): MathNode
95
parse(exprs: string[], options?: ParseOptions): MathNode[]
96
```
97
{ .api }
98
99
```typescript
100
interface ParseOptions {
101
nodes?: Record<string, MathNode>
102
}
103
```
104
105
```typescript
106
// Parse to Abstract Syntax Tree
107
const node = parse('2 * x + 1')
108
console.log(node.type) // 'OperatorNode'
109
console.log(node.op) // '+'
110
111
// Parse multiple expressions
112
const nodes = parse(['x = 5', 'y = x^2', 'y + 1'])
113
nodes.forEach(node => console.log(node.type))
114
115
// With custom nodes
116
const customNodes = {
117
myFunction: new FunctionNode('myCustomFunction', [])
118
}
119
const nodeWithCustom = parse('myFunction(x)', { nodes: customNodes })
120
```
121
122
### Working with AST Nodes
123
124
```typescript
125
// Navigate the AST
126
const expr = parse('a * (b + c)')
127
console.log(expr.type) // 'OperatorNode'
128
console.log(expr.fn) // 'multiply'
129
console.log(expr.args.length) // 2
130
131
// First argument is 'a'
132
console.log(expr.args[0].type) // 'SymbolNode'
133
console.log(expr.args[0].name) // 'a'
134
135
// Second argument is '(b + c)'
136
console.log(expr.args[1].type) // 'ParenthesisNode'
137
console.log(expr.args[1].content.type) // 'OperatorNode'
138
139
// Evaluate AST with scope
140
const result = expr.evaluate({ a: 2, b: 3, c: 4 }) // 14
141
```
142
143
## Compilation for Performance
144
145
### Compile Function
146
147
```typescript
148
compile(expr: string | MathNode): EvalFunction
149
```
150
{ .api }
151
152
```typescript
153
interface EvalFunction {
154
evaluate(scope?: object): any
155
}
156
```
157
158
```typescript
159
// Compile expression for repeated evaluation
160
const compiled = compile('a * x^2 + b * x + c')
161
162
// Evaluate multiple times (much faster than parsing each time)
163
const results = [
164
compiled.evaluate({ a: 1, b: 2, c: 3, x: 0 }), // 3
165
compiled.evaluate({ a: 1, b: 2, c: 3, x: 1 }), // 6
166
compiled.evaluate({ a: 1, b: 2, c: 3, x: 2 }), // 11
167
compiled.evaluate({ a: 1, b: 2, c: 3, x: 3 }) // 18
168
]
169
170
// Compile from parsed node
171
const node = parse('sin(x) + cos(y)')
172
const compiledFromNode = compile(node)
173
compiledFromNode.evaluate({ x: pi/2, y: 0 }) // 2
174
175
// Performance comparison
176
const expr = 'sqrt(x^2 + y^2)'
177
const compiled_expr = compile(expr)
178
179
// Fast: compile once, evaluate many times
180
const fastResults = points.map(({x, y}) => compiled_expr.evaluate({x, y}))
181
182
// Slow: parse and evaluate each time
183
const slowResults = points.map(({x, y}) => evaluate(expr, {x, y}))
184
```
185
186
## Parser Instance
187
188
### Creating Parser
189
190
```typescript
191
parser(): Parser
192
```
193
{ .api }
194
195
```typescript
196
interface Parser {
197
evaluate(expr: string): any
198
get(variable: string): any
199
getAll(): object
200
set(variable: string, value: any): void
201
remove(variable: string): void
202
clear(): void
203
}
204
```
205
206
```typescript
207
// Create parser instance with persistent scope
208
const mathParser = parser()
209
210
// Set variables
211
mathParser.set('a', 3)
212
mathParser.set('b', 4)
213
214
// Evaluate with persistent scope
215
mathParser.evaluate('c = a^2 + b^2') // 25
216
mathParser.evaluate('sqrt(c)') // 5
217
218
// Get variables
219
mathParser.get('c') // 25
220
mathParser.getAll() // { a: 3, b: 4, c: 25 }
221
222
// Remove and clear
223
mathParser.remove('c')
224
mathParser.clear() // Remove all variables
225
226
// Multi-line expressions
227
mathParser.evaluate(`
228
x = 5
229
y = x^2
230
z = sqrt(y)
231
`) // 5 (returns last expression result)
232
```
233
234
## AST Node Types and Construction
235
236
### Symbol and Constant Nodes
237
238
```typescript
239
SymbolNode(name: string): SymbolNode
240
ConstantNode(value: any): ConstantNode
241
```
242
{ .api }
243
244
```typescript
245
// Create symbol (variable reference)
246
const xSymbol = new SymbolNode('x')
247
xSymbol.evaluate({ x: 5 }) // 5
248
249
// Create constant
250
const constPi = new ConstantNode(pi)
251
constPi.evaluate() // π
252
253
// Create complex constants
254
const constComplex = new ConstantNode(complex(2, 3))
255
const constMatrix = new ConstantNode(matrix([[1, 2], [3, 4]]))
256
```
257
258
### Operator Nodes
259
260
```typescript
261
OperatorNode(op: string, fn: string, args: MathNode[], implicit?: boolean): OperatorNode
262
```
263
{ .api }
264
265
```typescript
266
// Create binary operation: x + y
267
const addNode = new OperatorNode('+', 'add', [
268
new SymbolNode('x'),
269
new SymbolNode('y')
270
])
271
addNode.evaluate({ x: 3, y: 4 }) // 7
272
273
// Create unary operation: -x
274
const negNode = new OperatorNode('-', 'unaryMinus', [
275
new SymbolNode('x')
276
], false)
277
negNode.evaluate({ x: 5 }) // -5
278
279
// Implicit multiplication: 2x
280
const implicitMult = new OperatorNode('*', 'multiply', [
281
new ConstantNode(2),
282
new SymbolNode('x')
283
], true) // implicit = true
284
```
285
286
### Function Nodes
287
288
```typescript
289
FunctionNode(fn: string | MathNode, args: MathNode[]): FunctionNode
290
```
291
{ .api }
292
293
```typescript
294
// Create function call: sin(x)
295
const sinNode = new FunctionNode('sin', [
296
new SymbolNode('x')
297
])
298
sinNode.evaluate({ x: pi/2 }) // 1
299
300
// Function with multiple arguments: pow(x, y)
301
const powNode = new FunctionNode('pow', [
302
new SymbolNode('x'),
303
new ConstantNode(2)
304
])
305
powNode.evaluate({ x: 3 }) // 9
306
307
// Custom function reference
308
const customFn = new SymbolNode('myFunction')
309
const customCall = new FunctionNode(customFn, [new SymbolNode('x')])
310
```
311
312
### Assignment Nodes
313
314
```typescript
315
AssignmentNode(object: MathNode, index?: IndexNode, value: MathNode): AssignmentNode
316
```
317
{ .api }
318
319
```typescript
320
// Simple assignment: x = 5
321
const assign = new AssignmentNode(
322
new SymbolNode('x'),
323
undefined,
324
new ConstantNode(5)
325
)
326
const scope = {}
327
assign.evaluate(scope) // 5, and scope.x = 5
328
329
// Array element assignment: arr[2] = 10
330
const arrAssign = new AssignmentNode(
331
new SymbolNode('arr'),
332
new IndexNode([new ConstantNode(2)]),
333
new ConstantNode(10)
334
)
335
arrAssign.evaluate({ arr: [1, 2, 3, 4] }) // Sets arr[2] = 10
336
```
337
338
### Array and Object Nodes
339
340
```typescript
341
ArrayNode(items: MathNode[]): ArrayNode
342
ObjectNode(properties: Record<string, MathNode>): ObjectNode
343
```
344
{ .api }
345
346
```typescript
347
// Create array: [1, 2, x]
348
const arrayNode = new ArrayNode([
349
new ConstantNode(1),
350
new ConstantNode(2),
351
new SymbolNode('x')
352
])
353
arrayNode.evaluate({ x: 3 }) // [1, 2, 3]
354
355
// Create object: {a: 1, b: x+1}
356
const objectNode = new ObjectNode({
357
a: new ConstantNode(1),
358
b: new OperatorNode('+', 'add', [
359
new SymbolNode('x'),
360
new ConstantNode(1)
361
])
362
})
363
objectNode.evaluate({ x: 2 }) // {a: 1, b: 3}
364
```
365
366
### Conditional Nodes
367
368
```typescript
369
ConditionalNode(condition: MathNode, trueExpr: MathNode, falseExpr: MathNode): ConditionalNode
370
```
371
{ .api }
372
373
```typescript
374
// Create ternary: x > 0 ? x : -x (absolute value)
375
const absNode = new ConditionalNode(
376
new OperatorNode('>', 'larger', [
377
new SymbolNode('x'),
378
new ConstantNode(0)
379
]),
380
new SymbolNode('x'),
381
new OperatorNode('-', 'unaryMinus', [new SymbolNode('x')])
382
)
383
384
absNode.evaluate({ x: 5 }) // 5
385
absNode.evaluate({ x: -3 }) // 3
386
```
387
388
### Range Nodes
389
390
```typescript
391
RangeNode(start: MathNode, end: MathNode, step?: MathNode): RangeNode
392
```
393
{ .api }
394
395
```typescript
396
// Create range: 1:5
397
const rangeNode = new RangeNode(
398
new ConstantNode(1),
399
new ConstantNode(5)
400
)
401
rangeNode.evaluate() // [1, 2, 3, 4, 5]
402
403
// Range with step: 0:2:10
404
const stepRange = new RangeNode(
405
new ConstantNode(0),
406
new ConstantNode(10),
407
new ConstantNode(2)
408
)
409
stepRange.evaluate() // [0, 2, 4, 6, 8, 10]
410
```
411
412
## Symbolic Operations
413
414
### Symbolic Differentiation
415
416
```typescript
417
derivative(expr: MathNode | string, variable: MathNode | string, options?: DerivativeOptions): MathNode
418
```
419
{ .api }
420
421
```typescript
422
interface DerivativeOptions {
423
simplify?: boolean
424
}
425
```
426
427
```typescript
428
// Basic differentiation
429
derivative('x^2', 'x') // Returns AST for '2*x'
430
derivative('sin(x)', 'x') // Returns AST for 'cos(x)'
431
derivative('a*x + b', 'x') // Returns AST for 'a'
432
433
// Multi-variable expressions
434
derivative('x^2 + y^2', 'x') // Returns AST for '2*x'
435
derivative('x*y + y^2', 'y') // Returns AST for 'x + 2*y'
436
437
// Complex expressions
438
const expr = 'sin(x^2) * cos(y)'
439
const dfdx = derivative(expr, 'x') // 2*x*cos(x^2)*cos(y)
440
const dfdy = derivative(expr, 'y') // -sin(x^2)*sin(y)
441
442
// Chain rule example
443
derivative('sin(cos(x))', 'x') // -cos(cos(x))*sin(x)
444
445
// Product rule example
446
derivative('x^2 * sin(x)', 'x') // 2*x*sin(x) + x^2*cos(x)
447
448
// Evaluate derivative at point
449
const f_prime = derivative('x^3 - 2*x', 'x')
450
f_prime.evaluate({ x: 2 }) // 3*4 - 2 = 10
451
```
452
453
### Expression Simplification
454
455
```typescript
456
simplify(expr: MathNode | string, rules?: MathNode[] | string[], scope?: object, options?: SimplifyOptions): MathNode
457
```
458
{ .api }
459
460
```typescript
461
// Basic simplification
462
simplify('2 + 3') // ConstantNode(5)
463
simplify('x + x') // OperatorNode for '2*x'
464
simplify('x * 1') // SymbolNode('x')
465
simplify('0 + x') // SymbolNode('x')
466
467
// Algebraic simplification
468
simplify('(x + 1)^2') // x^2 + 2*x + 1
469
simplify('x^2 - 1') // (x-1)*(x+1) (if factorization rules applied)
470
471
// Trigonometric simplification
472
simplify('sin(x)^2 + cos(x)^2') // 1
473
simplify('2*sin(x)*cos(x)') // sin(2*x)
474
475
// Custom rules
476
const rules = ['n1*n2 -> n1*n2', 'x + x -> 2*x']
477
simplify('a + a + b + b', rules) // 2*a + 2*b
478
479
// With scope (substitute known values)
480
simplify('a*x + b*x', {}, { a: 2, b: 3 }) // 5*x
481
```
482
483
### Specific Simplification Functions
484
485
```typescript
486
simplifyConstant(expr: MathNode | string, options?: SimplifyOptions): MathNode
487
simplifyCore(expr: MathNode | string, options?: SimplifyOptions): MathNode
488
```
489
{ .api }
490
491
```typescript
492
// Simplify only constant expressions
493
simplifyConstant('2 + 3 * x') // 5 + 3*x (only 2+3 simplified)
494
simplifyConstant('sin(0) + cos(pi)') // 0 + (-1) = -1
495
496
// Core simplification (basic algebraic rules)
497
simplifyCore('x + 0') // x
498
simplifyCore('x * 1') // x
499
simplifyCore('x * 0') // 0
500
simplifyCore('x + x') // 2*x
501
```
502
503
### Rationalization
504
505
```typescript
506
rationalize(expr: MathNode | string, optional?: object, detailed?: boolean): MathNode
507
```
508
{ .api }
509
510
```typescript
511
// Convert to rational form
512
rationalize('0.125') // 1/8
513
rationalize('0.333333') // 1/3 (approximately)
514
rationalize('sqrt(2)/2') // More rational form
515
516
// Rationalize denominators
517
rationalize('1/sqrt(2)') // sqrt(2)/2
518
rationalize('1/(1+sqrt(2))') // -1 + sqrt(2)
519
```
520
521
## Advanced Expression Manipulation
522
523
### Expression Resolution
524
525
```typescript
526
resolve(node: MathNode, scope?: object): MathNode
527
```
528
{ .api }
529
530
```typescript
531
// Resolve variables in expression
532
const expr = parse('a * x + b')
533
const resolved = resolve(expr, { a: 2, b: 3 })
534
// Returns AST equivalent to '2 * x + 3'
535
536
resolved.evaluate({ x: 4 }) // 11
537
```
538
539
### Leaf Count
540
541
```typescript
542
leafCount(expr: MathNode | string): number
543
```
544
{ .api }
545
546
```typescript
547
// Count leaf nodes (complexity measure)
548
leafCount('x') // 1
549
leafCount('x + y') // 2
550
leafCount('x^2 + 2*x + 1') // 5 (x, 2, x, 2, 1)
551
552
// Useful for measuring expression complexity
553
const expr1 = 'x + 1'
554
const expr2 = '(x + 1)^2'
555
leafCount(expr1) // 2
556
leafCount(expr2) // 4 (after expansion)
557
```
558
559
### Symbolic Equality
560
561
```typescript
562
symbolicEqual(expr1: MathNode | string, expr2: MathNode | string, options?: SymbolicEqualOptions): boolean
563
```
564
{ .api }
565
566
```typescript
567
// Test if expressions are symbolically equivalent
568
symbolicEqual('x + 1', '1 + x') // true (commutative)
569
symbolicEqual('2*x', 'x + x') // true
570
symbolicEqual('(x+1)^2', 'x^2 + 2*x + 1') // true
571
symbolicEqual('sin(x)^2 + cos(x)^2', '1') // true
572
573
// Different but not simplified
574
symbolicEqual('x + 0', 'x') // true
575
symbolicEqual('x * 1', 'x') // true
576
```
577
578
## Working with Units in Expressions
579
580
```typescript
581
// Units are first-class citizens in expressions
582
evaluate('5 meter + 3 meter') // 8 meter
583
evaluate('10 km/h * 2 hours') // 20 km
584
evaluate('5 kg * 9.8 m/s^2') // 49 N (automatically converts)
585
586
// Unit conversions in expressions
587
evaluate('5 km to mile') // ~3.1 mile
588
evaluate('to(100 fahrenheit, celsius)') // ~37.8 celsius
589
590
// Complex unit calculations
591
evaluate('(60 mile/hour) * (2 hour) to km') // ~193 km
592
evaluate('force = 10 newton; area = 2 cm^2; force/area to bar') // Pressure calculation
593
```
594
595
## Matrix and Array Expressions
596
597
```typescript
598
// Matrix operations in expressions
599
evaluate('[[1,2],[3,4]] * [[5,6],[7,8]]') // Matrix multiplication
600
evaluate('inv([[1,2],[3,4]])') // Matrix inverse
601
evaluate('det([[1,2],[3,4]])') // Determinant: -2
602
603
// Element access and modification
604
evaluate('A = [[1,2,3],[4,5,6]]; A[1,2]') // 5 (0-indexed)
605
evaluate('A[0,:] = [10,20,30]; A') // Modify first row
606
607
// Array operations
608
evaluate('sum([1,2,3,4,5])') // 15
609
evaluate('mean([1,2,3,4,5])') // 3
610
evaluate('std([1,2,3,4,5])') // ~1.58
611
```
612
613
## Function Definition in Expressions
614
615
```typescript
616
// Define functions within expressions
617
const parser_instance = parser()
618
619
// Simple function
620
parser_instance.evaluate('f(x) = x^2 + 1')
621
parser_instance.evaluate('f(3)') // 10
622
623
// Multi-parameter functions
624
parser_instance.evaluate('g(x,y) = sqrt(x^2 + y^2)')
625
parser_instance.evaluate('g(3,4)') // 5
626
627
// Recursive functions (be careful with stack overflow)
628
parser_instance.evaluate('factorial(n) = n <= 1 ? 1 : n * factorial(n-1)')
629
parser_instance.evaluate('factorial(5)') // 120
630
631
// Functions with conditionals
632
parser_instance.evaluate('abs(x) = x >= 0 ? x : -x')
633
parser_instance.evaluate('abs(-5)') // 5
634
```
635
636
## Error Handling in Expressions
637
638
```typescript
639
import { ArgumentsError, SyntaxError } from 'mathjs'
640
641
try {
642
evaluate('1 / 0') // May return Infinity or throw
643
} catch (error) {
644
console.log('Division by zero')
645
}
646
647
try {
648
evaluate('unknown_function(5)')
649
} catch (error) {
650
if (error instanceof Error) {
651
console.log('Undefined function:', error.message)
652
}
653
}
654
655
try {
656
parse('1 + + 2') // Syntax error
657
} catch (error) {
658
console.log('Parse error:', error.message)
659
}
660
661
// Validate expressions before evaluation
662
function safeEvaluate(expr, scope = {}) {
663
try {
664
const node = parse(expr)
665
return node.evaluate(scope)
666
} catch (error) {
667
return { error: error.message }
668
}
669
}
670
```
671
672
## Performance Optimization
673
674
### Expression Compilation Strategies
675
676
```typescript
677
// Pre-compile frequently used expressions
678
const expressions = {
679
quadratic: compile('a*x^2 + b*x + c'),
680
distance: compile('sqrt((x2-x1)^2 + (y2-y1)^2)'),
681
interest: compile('P * (1 + r/n)^(n*t)')
682
}
683
684
// Batch evaluation
685
function evaluateQuadratic(coefficients, xValues) {
686
return xValues.map(x =>
687
expressions.quadratic.evaluate({ ...coefficients, x })
688
)
689
}
690
691
// Memoization for expensive symbolic operations
692
const memoizedSimplify = (() => {
693
const cache = new Map()
694
return (expr) => {
695
const key = typeof expr === 'string' ? expr : expr.toString()
696
if (!cache.has(key)) {
697
cache.set(key, simplify(expr))
698
}
699
return cache.get(key)
700
}
701
})()
702
```
703
704
### Tree Transformation and Optimization
705
706
```typescript
707
// Custom AST transformations
708
function optimizeExpression(node) {
709
// Traverse and transform AST
710
if (node.type === 'OperatorNode') {
711
if (node.op === '*' && node.args.some(arg =>
712
arg.type === 'ConstantNode' && arg.value === 0
713
)) {
714
return new ConstantNode(0) // x * 0 = 0
715
}
716
717
if (node.op === '+' && node.args.some(arg =>
718
arg.type === 'ConstantNode' && arg.value === 0
719
)) {
720
// Remove zero terms
721
return node.args.find(arg => !(arg.type === 'ConstantNode' && arg.value === 0))
722
}
723
}
724
725
// Recursively optimize children
726
if (node.args) {
727
node.args = node.args.map(optimizeExpression)
728
}
729
730
return node
731
}
732
```
733
734
## Integration with Math.js Ecosystem
735
736
### Chain Interface with Expressions
737
738
```typescript
739
// Use expressions in chain operations
740
const result = chain('x^2 + 2*x + 1')
741
.parse()
742
.simplify()
743
.evaluate({ x: 3 })
744
.done() // 16
745
746
// Complex chain with symbolic operations
747
const derivative_result = chain('sin(x^2)')
748
.parse()
749
.derivative('x')
750
.simplify()
751
.evaluate({ x: pi/2 })
752
.done()
753
```
754
755
### Custom Function Registration
756
757
```typescript
758
// Register custom functions for use in expressions
759
const math = create(all)
760
761
math.import({
762
myCustomFunction: (x) => x^2 + 1,
763
factorial: factorial // Re-export built-in
764
})
765
766
evaluate('myCustomFunction(5)', {}, { math }) // 26
767
```
768
769
## Common Expression Patterns
770
771
### Mathematical Modeling
772
773
```typescript
774
// Population growth model
775
const exponentialGrowth = compile('P0 * e^(r * t)')
776
const logisticGrowth = compile('K / (1 + ((K - P0) / P0) * e^(-r * t))')
777
778
// Physical equations
779
const kineticEnergy = compile('0.5 * m * v^2')
780
const gravitationalForce = compile('G * m1 * m2 / r^2')
781
782
// Economic calculations
783
const compoundInterest = compile('P * (1 + r/n)^(n*t)')
784
const presentValue = compile('FV / (1 + r)^t')
785
```
786
787
### Numerical Methods Integration
788
789
```typescript
790
// Newton's method for root finding
791
function newtonMethod(expr, guess, tolerance = 1e-10) {
792
const f = compile(expr)
793
const f_prime = compile(derivative(expr, 'x'))
794
795
let x = guess
796
let iterations = 0
797
798
while (iterations < 100) {
799
const fx = f.evaluate({ x })
800
const fpx = f_prime.evaluate({ x })
801
802
if (Math.abs(fx) < tolerance) break
803
804
x = x - fx / fpx
805
iterations++
806
}
807
808
return x
809
}
810
811
// Find root of x^2 - 2 = 0 (sqrt(2))
812
const root = newtonMethod('x^2 - 2', 1) // ≈ 1.414
813
```
814
815
### Expression Analysis
816
817
```typescript
818
// Extract variables from expression
819
function extractVariables(expr) {
820
const node = parse(expr)
821
const variables = new Set()
822
823
node.traverse((node, path, parent) => {
824
if (node.type === 'SymbolNode' && !isFunction(node.name)) {
825
variables.add(node.name)
826
}
827
})
828
829
return Array.from(variables)
830
}
831
832
// Analyze expression complexity
833
function analyzeExpression(expr) {
834
const node = parse(expr)
835
836
return {
837
leafCount: leafCount(node),
838
variables: extractVariables(expr),
839
hasConstants: node.toString().match(/\d+/) !== null,
840
hasFunctions: node.toString().match(/\w+\(/) !== null,
841
complexity: leafCount(node) + extractVariables(expr).length
842
}
843
}
844
```