1 | /**
|
2 | * Expressions can be evaluated in various ways:
|
3 | *
|
4 | * 1. using the function math.eval
|
5 | * 2. using the function math.parse
|
6 | * 3. using a parser. A parser contains functions eval and parse,
|
7 | * and keeps a scope with assigned variables in memory
|
8 | */
|
9 |
|
10 | // load math.js (using node.js)
|
11 | const math = require('../index')
|
12 |
|
13 | // 1. using the function math.eval
|
14 | //
|
15 | // Function `eval` accepts a single expression or an array with
|
16 | // expressions as first argument, and has an optional second argument
|
17 | // containing a scope with variables and functions. The scope is a regular
|
18 | // JavaScript Object. The scope will be used to resolve symbols, and to write
|
19 | // assigned variables or function.
|
20 | console.log('1. USING FUNCTION MATH.EVAL')
|
21 |
|
22 | // evaluate expressions
|
23 | console.log('\nevaluate expressions')
|
24 | print(math.eval('sqrt(3^2 + 4^2)')) // 5
|
25 | print(math.eval('sqrt(-4)')) // 2i
|
26 | print(math.eval('2 inch to cm')) // 5.08 cm
|
27 | print(math.eval('cos(45 deg)')) // 0.70711
|
28 |
|
29 | // evaluate multiple expressions at once
|
30 | console.log('\nevaluate multiple expressions at once')
|
31 | print(math.eval([
|
32 | 'f = 3',
|
33 | 'g = 4',
|
34 | 'f * g'
|
35 | ])) // [3, 4, 12]
|
36 |
|
37 | // provide a scope (just a regular JavaScript Object)
|
38 | console.log('\nevaluate expressions providing a scope with variables and functions')
|
39 | let scope = {
|
40 | a: 3,
|
41 | b: 4
|
42 | }
|
43 |
|
44 | // variables can be read from the scope
|
45 | print(math.eval('a * b', scope)) // 12
|
46 |
|
47 | // variable assignments are written to the scope
|
48 | print(math.eval('c = 2.3 + 4.5', scope)) // 6.8
|
49 | print(scope.c) // 6.8
|
50 |
|
51 | // scope can contain both variables and functions
|
52 | scope.hello = function (name) {
|
53 | return 'hello, ' + name + '!'
|
54 | }
|
55 | print(math.eval('hello("hero")', scope)) // "hello, hero!"
|
56 |
|
57 | // define a function as an expression
|
58 | const f = math.eval('f(x) = x ^ a', scope)
|
59 | print(f(2)) // 8
|
60 | print(scope.f(2)) // 8
|
61 |
|
62 | // 2. using function math.parse
|
63 | //
|
64 | // Function `math.parse` parses expressions into a node tree. The syntax is
|
65 | // similar to function `math.eval`.
|
66 | // Function `parse` accepts a single expression or an array with
|
67 | // expressions as first argument. The function returns a node tree, which
|
68 | // then can be compiled against math, and then evaluated against an (optional
|
69 | // scope. This scope is a regular JavaScript Object. The scope will be used
|
70 | // to resolve symbols, and to write assigned variables or function.
|
71 | console.log('\n2. USING FUNCTION MATH.PARSE')
|
72 |
|
73 | // parse an expression
|
74 | console.log('\nparse an expression into a node tree')
|
75 | const node1 = math.parse('sqrt(3^2 + 4^2)')
|
76 | print(node1.toString()) // "sqrt((3 ^ 2) + (4 ^ 2))"
|
77 |
|
78 | // compile and evaluate the compiled code
|
79 | // you could also do this in two steps: node1.compile().eval()
|
80 | print(node1.eval()) // 5
|
81 |
|
82 | // provide a scope
|
83 | console.log('\nprovide a scope')
|
84 | const node2 = math.parse('x^a')
|
85 | const code2 = node2.compile()
|
86 | print(node2.toString()) // "x ^ a"
|
87 | let scope2 = {
|
88 | x: 3,
|
89 | a: 2
|
90 | }
|
91 | print(code2.eval(scope2)) // 9
|
92 |
|
93 | // change a value in the scope and re-evaluate the node
|
94 | scope.a = 3
|
95 | print(code2.eval(scope2)) // 27
|
96 |
|
97 | // 3. using function math.compile
|
98 | //
|
99 | // Function `math.compile` compiles expressions into a node tree. The syntax is
|
100 | // similar to function `math.eval`.
|
101 | // Function `compile` accepts a single expression or an array with
|
102 | // expressions as first argument, and returns an object with a function eval
|
103 | // to evaluate the compiled expression. On evaluation, an optional scope can
|
104 | // be provided. This scope will be used to resolve symbols, and to write
|
105 | // assigned variables or function.
|
106 | console.log('\n3. USING FUNCTION MATH.COMPILE')
|
107 |
|
108 | // parse an expression
|
109 | console.log('\ncompile an expression')
|
110 | const code3 = math.compile('sqrt(3^2 + 4^2)')
|
111 |
|
112 | // evaluate the compiled code
|
113 | print(code3.eval()) // 5
|
114 |
|
115 | // provide a scope for the variable assignment
|
116 | console.log('\nprovide a scope')
|
117 | const code4 = math.compile('a = a + 3')
|
118 | let scope3 = {
|
119 | a: 7
|
120 | }
|
121 | code4.eval(scope3)
|
122 | print(scope3.a) // 10
|
123 |
|
124 | // 4. using a parser
|
125 | //
|
126 | // In addition to the static functions `math.eval` and `math.parse`, math.js
|
127 | // contains a parser with functions `eval` and `parse`, which automatically
|
128 | // keeps a scope with assigned variables in memory. The parser also contains
|
129 | // some convenience methods to get, set, and remove variables from memory.
|
130 | console.log('\n4. USING A PARSER')
|
131 | const parser = math.parser()
|
132 |
|
133 | // evaluate with parser
|
134 | console.log('\nevaluate expressions')
|
135 | print(parser.eval('sqrt(3^2 + 4^2)')) // 5
|
136 | print(parser.eval('sqrt(-4)')) // 2i
|
137 | print(parser.eval('2 inch to cm')) // 5.08 cm
|
138 | print(parser.eval('cos(45 deg)')) // 0.70710678118655
|
139 |
|
140 | // define variables and functions
|
141 | console.log('\ndefine variables and functions')
|
142 | print(parser.eval('x = 7 / 2')) // 3.5
|
143 | print(parser.eval('x + 3')) // 6.5
|
144 | print(parser.eval('f2(x, y) = x^y')) // f2(x, y)
|
145 | print(parser.eval('f2(2, 3)')) // 8
|
146 |
|
147 | // manipulate matrices
|
148 | // Note that matrix indexes in the expression parser are one-based with the
|
149 | // upper-bound included. On a JavaScript level however, math.js uses zero-based
|
150 | // indexes with an excluded upper-bound.
|
151 | console.log('\nmanipulate matrices')
|
152 | print(parser.eval('k = [1, 2; 3, 4]')) // [[1, 2], [3, 4]]
|
153 | print(parser.eval('l = zeros(2, 2)')) // [[0, 0], [0, 0]]
|
154 | print(parser.eval('l[1, 1:2] = [5, 6]')) // [5, 6]
|
155 | print(parser.eval('l')) // [[5, 6], [0, 0]]
|
156 | print(parser.eval('l[2, :] = [7, 8]')) // [7, 8]
|
157 | print(parser.eval('l')) // [[5, 6], [7, 8]]
|
158 | print(parser.eval('m = k * l')) // [[19, 22], [43, 50]]
|
159 | print(parser.eval('n = m[2, 1]')) // 43
|
160 | print(parser.eval('n = m[:, 1]')) // [[19], [43]]
|
161 |
|
162 | // get and set variables and functions
|
163 | console.log('\nget and set variables and function in the scope of the parser')
|
164 | const x = parser.get('x')
|
165 | console.log('x =', x) // x = 3.5
|
166 | const f2 = parser.get('f2')
|
167 | console.log('f2 =', math.format(f2)) // f2 = f2(x, y)
|
168 | const h = f2(3, 3)
|
169 | console.log('h =', h) // g = 27
|
170 |
|
171 | parser.set('i', 500)
|
172 | print(parser.eval('i / 2')) // 250
|
173 | parser.set('hello', function (name) {
|
174 | return 'hello, ' + name + '!'
|
175 | })
|
176 | print(parser.eval('hello("hero")')) // "hello, hero!"
|
177 |
|
178 | // clear defined functions and variables
|
179 | parser.clear()
|
180 |
|
181 | /**
|
182 | * Helper function to output a value in the console. Value will be formatted.
|
183 | * @param {*} value
|
184 | */
|
185 | function print (value) {
|
186 | const precision = 14
|
187 | console.log(math.format(value, precision))
|
188 | }
|