@khanacademy/kas 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,90 +0,0 @@
1
- import _ from "underscore";
2
-
3
- import * as KAS from "../index";
4
-
5
- expect.extend({
6
- toHaveNorm(input: string, reference: string): jest.CustomMatcherResult {
7
- const actual = KAS.parse(input).expr.normalize().print();
8
- const expected = KAS.parse(reference).expr.normalize().print();
9
-
10
- return {
11
- pass: actual === expected,
12
- message: () => `${input} is the same as ${reference}`,
13
- };
14
- },
15
- toHaveStripNorm(
16
- input: string,
17
- reference: string,
18
- ): jest.CustomMatcherResult {
19
- const actual = KAS.parse(input).expr.strip().normalize().print();
20
- const expected = KAS.parse(reference).expr.strip().normalize().print();
21
-
22
- return {
23
- pass: actual === expected,
24
- message: () => `${input} is the same as ${reference}`,
25
- };
26
- },
27
- });
28
-
29
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
30
- declare global {
31
- // eslint-disable-next-line @typescript-eslint/no-namespace
32
- namespace jest {
33
- interface Matchers<R> {
34
- toHaveNorm(reference: string): R;
35
- toHaveStripNorm(reference: string): R;
36
- }
37
- }
38
- }
39
-
40
- describe("checking form", () => {
41
- test("normalize", () => {
42
- expect("ab").toHaveNorm("ba");
43
- expect("(ab)c").toHaveNorm("(cb)a");
44
-
45
- const forms = [
46
- "(6x+1)(x-1)",
47
- "(1+6x)(x-1)",
48
- "(6x+1)(-1+x)",
49
- "(1+6x)(-1+x)",
50
- "(x-1)(6x+1)",
51
- "(x-1)(1+6x)",
52
- "(-1+x)(6x+1)",
53
- "(-1+x)(1+6x)",
54
- ];
55
-
56
- _.each(forms, function (form) {
57
- expect(forms[0]).toHaveNorm(form);
58
- });
59
- });
60
-
61
- test("strip then normalize", () => {
62
- expect("ab").toHaveStripNorm("ba");
63
- expect("(ab)c").toHaveStripNorm("(cb)a");
64
-
65
- const forms = [
66
- "(6x+1)(x-1)",
67
- "(1+6x)(x-1)",
68
- "(6x+1)(-1+x)",
69
- "(1+6x)(-1+x)",
70
- "(-6x-1)(-x+1)",
71
- "(-1-6x)(-x+1)",
72
- "(-6x-1)(1-x)",
73
- "(-1-6x)(1-x)",
74
- "(x-1)(6x+1)",
75
- "(x-1)(1+6x)",
76
- "(-1+x)(6x+1)",
77
- "(-1+x)(1+6x)",
78
- "(-x+1)(-6x-1)",
79
- "(-x+1)(-1-6x)",
80
- "(1-x)(-6x-1)",
81
- "(1-x)(-1-6x)",
82
- "-(6x+1)(1-x)",
83
- "-(-6x-1)(x-1)",
84
- ];
85
-
86
- _.each(forms, function (form) {
87
- expect(forms[0]).toHaveStripNorm(form);
88
- });
89
- });
90
- });
@@ -1,336 +0,0 @@
1
- import _ from "underscore";
2
-
3
- import * as KAS from "../index";
4
-
5
- expect.extend({
6
- toEqualExpr(input: string, expected: string): jest.CustomMatcherResult {
7
- const inputExpr = KAS.parse(input, {functions: ["f", "g", "h"]}).expr;
8
- const expectedExpr = KAS.parse(expected, {
9
- functions: ["f", "g", "h"],
10
- }).expr;
11
-
12
- const actual = KAS.compare(inputExpr, expectedExpr, {form: false});
13
-
14
- if (this.isNot) {
15
- return actual.equal
16
- ? {pass: true, message: () => ""}
17
- : {
18
- pass: false,
19
- message: () => `${input} is NOT the same as ${expected}`,
20
- };
21
- }
22
- return actual.equal
23
- ? {pass: true, message: () => ""}
24
- : {
25
- pass: false,
26
- message: () => `${input} is the same as ${expected}`,
27
- };
28
- },
29
- toEqualExprAndForm(
30
- input: string,
31
- expected: string,
32
- ): jest.CustomMatcherResult {
33
- const inputExpr = KAS.parse(input, {functions: ["f", "g", "h"]}).expr;
34
- const expectedExpr = KAS.parse(expected, {
35
- functions: ["f", "g", "h"],
36
- }).expr;
37
-
38
- const actual = KAS.compare(inputExpr, expectedExpr, {form: true});
39
-
40
- if (this.isNot) {
41
- return actual.equal
42
- ? {pass: true, message: () => ""}
43
- : {
44
- pass: false,
45
- message: () => `${input} is NOT the same as ${expected}`,
46
- };
47
- }
48
- return actual.equal
49
- ? {pass: true, message: () => ""}
50
- : {
51
- pass: false,
52
- message: () => `${input} is the same as ${expected}`,
53
- };
54
- },
55
- });
56
-
57
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
58
- declare global {
59
- // eslint-disable-next-line @typescript-eslint/no-namespace
60
- namespace jest {
61
- interface Matchers<R> {
62
- toEqualExpr(expected: string): R;
63
- toEqualExprAndForm(expected: string): R;
64
- }
65
- }
66
- }
67
-
68
- describe("comparing", () => {
69
- test("evaluate only", () => {
70
- expect("2+2").toEqualExpr("4");
71
- expect("a(b+c)").toEqualExpr("ab+ac");
72
- expect("a/b").toEqualExpr("a*b^-1");
73
-
74
- expect("1.2^2").toEqualExpr("1.44");
75
- expect("1.3^2").toEqualExpr("1.69");
76
- expect("1.4^2").toEqualExpr("1.96");
77
- expect("1.5^2").toEqualExpr("2.25");
78
-
79
- expect("1.2345^2").toEqualExpr("1.52399025");
80
- expect("1.2345*1.2345").toEqualExpr("1.52399025");
81
- expect("(1+.2345)^2").toEqualExpr("1.52399025");
82
- expect("(-5)^(1/3)").toEqualExpr("-1.709975946");
83
- expect("(-5)^(2/6)").toEqualExpr("-1.709975946");
84
- expect("(-5)^(4/3)").toEqualExpr("8.549879733");
85
- expect("(-5)^(-1/3)").toEqualExpr("-0.584803547");
86
-
87
- expect("(-5)^(1/5)").toEqualExpr("-1.379729661");
88
- expect("(-5)^(0.2)").toEqualExpr("-1.379729661");
89
-
90
- expect("x^(1/5)").toEqualExpr("x^(0.2)");
91
- expect("x^(8/5)").toEqualExpr("x^(1.6)");
92
-
93
- expect("(1-x)(-1-6x)").toEqualExpr("(6x+1)(x-1)");
94
- expect("y=x").not.toEqualExpr("x");
95
- expect("x").not.toEqualExpr("y=x");
96
- expect("y=x").toEqualExpr("y=x");
97
- expect("y=x").toEqualExpr("x=y");
98
- expect("y=x").toEqualExpr("-y=-x");
99
- expect("y=x").toEqualExpr("-x=-y");
100
- expect("y=x").not.toEqualExpr("y=-x");
101
- expect("y=x").not.toEqualExpr("-y=x");
102
- expect("y=x").not.toEqualExpr("y=/=x");
103
- expect("y<x").toEqualExpr("x>y");
104
- expect("y<=x").toEqualExpr("x>=y");
105
- expect("y>x").toEqualExpr("x<y");
106
- expect("y>x").not.toEqualExpr("x>y");
107
- expect("y>=x").toEqualExpr("x<=y");
108
- expect("a+b<c-d").toEqualExpr("a+b-c+d<0");
109
-
110
- expect("y=mx+b").toEqualExpr("-b-mx=-y");
111
- expect("y=mx+b").toEqualExpr("y-b=mx");
112
-
113
- // all of these normalize to the same expression, set to zero
114
- const forms = [
115
- "y=2x-5",
116
- "2x-5=y",
117
- "2x-y=5",
118
- "(y+5)/2=x",
119
- "(y+5)/x=2",
120
- "1/2(y+5)=x",
121
- ".5(y+5)=x",
122
- "y-3=2(x-4)",
123
- "2y=4x-10",
124
- "yz=2xz-5z",
125
- ];
126
-
127
- _.each(forms, (form) => {
128
- expect(forms[0]).toEqualExpr(form);
129
- });
130
-
131
- expect("3y=2x-15").toEqualExpr("3/2(y+5)=x");
132
-
133
- const forms2 = ["1/3p-3=114", "1/3p=117", "p=351", "p-351=0"];
134
-
135
- _.each(forms2, (form) => {
136
- expect(forms2[0]).toEqualExpr(form);
137
- });
138
-
139
- expect("x").toEqualExpr("xy/y");
140
- expect("e^x").toEqualExpr("e^x");
141
- expect("e^x").not.toEqualExpr("e^x + 1");
142
-
143
- const forms3 = [
144
- "x+x+x+6=12",
145
- "x+2x+6=12",
146
- "3x+6=12",
147
- "x+2x=6",
148
- "2x=6-x",
149
- "3x=6",
150
- "x=2",
151
- ];
152
-
153
- _.each(forms3, function (form) {
154
- expect(forms3[0]).toEqualExpr(form);
155
- });
156
-
157
- expect("100/55.6=t").toEqualExpr("t=100/55.6");
158
- expect("100/1.6^2=t").toEqualExpr("t=100/1.6^2");
159
- expect("7/3x+x=15").toEqualExpr("(2+1/3)x+x=15");
160
- expect("7/3x+x=15").not.toEqualExpr("(1+1/3)x+x=15");
161
-
162
- // Symmetric equations
163
- expect("x^2+y^2=r^2").toEqualExpr("r^2=x^2+y^2");
164
- expect("23^1.5=110.304").toEqualExpr("110.304=23^1.5");
165
-
166
- // TODO(alex): make sure that I have both positive and negative
167
- // test cases for all functionality
168
- expect("6.12*10^-2").toEqualExpr("6.12*10^-2");
169
- expect("6.12*10^-2").not.toEqualExpr("6.12*10^-6");
170
-
171
- expect("3^-x").toEqualExpr("(1/3)^x");
172
- expect("(1/3)^-x").toEqualExpr("3^x");
173
- expect("(3)^-x").not.toEqualExpr("3^x");
174
-
175
- expect("5.6=x+0.4+5.2").toEqualExpr("5.6=x+0.4+5.2");
176
-
177
- // Reciprocal trig functions
178
- expect("csc x").toEqualExpr("1/sin x");
179
- expect("sec x").toEqualExpr("1/cos x");
180
- expect("cot x").toEqualExpr("1/tan x");
181
- expect("arccsc x").toEqualExpr("arcsin (1/x)");
182
- expect("arcsec x").toEqualExpr("arccos (1/x)");
183
- expect("arccot x").toEqualExpr("arctan (1/x)");
184
-
185
- // Reciprocal hyperbolic trig functions
186
- expect("csch x").toEqualExpr("1/sinh x");
187
- expect("sech x").toEqualExpr("1/cosh x");
188
- expect("coth x").toEqualExpr("1/tanh x");
189
-
190
- // Make sure trig functions that are the same for all integer values
191
- // are not the same
192
- expect("-2sin(pi x) + 4").not.toEqualExpr("4");
193
- expect("2sin(pi x) + 4").not.toEqualExpr("-2sin(pi x) + 4");
194
- expect("sin(pi x)").not.toEqualExpr("0");
195
- expect("0").not.toEqualExpr("sin(pi x)");
196
- expect("cos(pi x)").not.toEqualExpr("cos(2 pi x)");
197
- expect("sin(pi x)").not.toEqualExpr("sin(500pi x)");
198
- expect("sin(500pi x)").not.toEqualExpr("sin(pi x)");
199
-
200
- // Check that floating point error isn't killing us
201
- // TODO(jack): These don't seem to test much; make better tests
202
- expect("0").toEqualExpr("sin(7pi)");
203
- expect("sin(7pi)").toEqualExpr("0");
204
- expect("0").toEqualExpr("sin(500pi)");
205
- expect("sin(500pi)").toEqualExpr("0");
206
-
207
- // Handle denominators the same way regardless of a fraction's format
208
- expect("x=1.2^2").toEqualExpr("x=1.44");
209
- expect("x=1.2^2").toEqualExpr("x=36/25");
210
- expect("x=1.44").toEqualExpr("x=36/25");
211
- expect("x=1.44").not.toEqualExpr("x=35/25");
212
-
213
- expect("x=1.2^(2y)").toEqualExpr("x=1.44^y");
214
- expect("x=1.2^(2y)").toEqualExpr("x=(36/25)^y");
215
- expect("x=1.44^y").toEqualExpr("x=(36/25)^y");
216
-
217
- expect("x=1.3^2").toEqualExpr("x=1.69");
218
- expect("x=1.4^2").toEqualExpr("x=1.96");
219
- expect("x=1.5^2").toEqualExpr("x=2.25");
220
- expect("x=1.5^2").toEqualExpr("x=2.25");
221
-
222
- expect("x=1.2345^2").toEqualExpr("x=1.52399025");
223
- expect("x=1.2345*1.2345").toEqualExpr("x=1.52399025");
224
- expect("x=(1+.2345)^2").toEqualExpr("x=1.52399025");
225
- expect("x=(1+.2345)^2").not.toEqualExpr("x=1.52399022");
226
-
227
- // Varying small and large comparisons
228
- expect("1.1234567891235 * 10^200").toEqualExpr(
229
- "1.1234567891234 * 10^200",
230
- );
231
- expect("1.1234567891235 * 10^200").not.toEqualExpr("0.10");
232
- expect("0.10").not.toEqualExpr("1.1234567891235 * 10^200");
233
- expect("0.50").not.toEqualExpr("0.51");
234
- expect("0.51").not.toEqualExpr("0.50");
235
-
236
- expect("1.00").toEqualExpr("1.00");
237
- expect("0.9").not.toEqualExpr("1.1");
238
- expect("1.1").not.toEqualExpr("0.9");
239
-
240
- // Real-world examples of equivalent equations that are now accepted
241
- expect("12(1-r)^2+58(1-r)=10").toEqualExpr("(1-r)(70-12r)=10");
242
- expect("720m+480(m-5)=42000").toEqualExpr("720m+480m-2400=42000");
243
- expect("2w+50/w=25").toEqualExpr("w(12.5-w)=25");
244
- expect("(n*(8+4n))/2>19206").toEqualExpr("6n+2n(n-1)>19206");
245
-
246
- // Correctly handle exponents with negative bases and variables in exponent
247
- expect("( 2)^n").not.toEqualExpr("( 2)^(n-1)");
248
- expect("( 2)^n").toEqualExpr("( 2)^(n)");
249
- expect("( 2)^n").not.toEqualExpr("( 2)^(n+1)");
250
-
251
- expect("(-2)^n").not.toEqualExpr("(-2)^(n-1)");
252
- expect("(-2)^n").toEqualExpr("(-2)^(n)");
253
- expect("(-2)^n").not.toEqualExpr("(-2)^(n+1)");
254
-
255
- expect("(-2)^(a)").not.toEqualExpr("(-2)^(ab)");
256
- expect("(-2)^(a)").not.toEqualExpr("(-2)^(a^b)");
257
-
258
- // This is incorrect, but accurately captures the current behavior
259
- // See comment in `Expr.compare()` for more details
260
- expect("(-2)^(n+0.1)").toEqualExpr("(-2)^(n+1.1)");
261
- });
262
-
263
- test("simplify can't yet handle these", () => {
264
- expect("sin(x + 2pi)").toEqualExpr("sin(x)");
265
- expect("y = sin(x + 2pi)").toEqualExpr("y = sin(x)");
266
- expect("sin^2(x)+cos^2(x)").toEqualExpr("x/x");
267
- expect("y = sin^2(x)+cos^2(x)").toEqualExpr("y = x/x");
268
- });
269
-
270
- test("partially evaluating functions", () => {
271
- expect("f(x)").toEqualExpr("f(x)");
272
- expect("f(x)").not.toEqualExpr("g(x)");
273
- expect("f(g(x))").toEqualExpr("f(g(x))");
274
- expect("sin(f(3x-x))/cos(f(x+x))").toEqualExpr("tan(f(2x))");
275
- expect("f(x) = sin(x + 2pi)").toEqualExpr("f(x) = sin(x)");
276
- // NOTE(kevinb): This test is flaky, because Expr.prototype.compare
277
- // is non-deterministic. When comparing expressions this normally
278
- // wouldn't be an issue because we could just evaluate the different
279
- // variables at different point and then check that the difference
280
- // between the expressions is always less than some very small number.
281
- // In this case though, we convert equations to expressions, e.g.
282
- // `f(x) = 1` is converted to `1-f(x)`, but because `f` is a function,
283
- // we can't evaluate it. One possible solution to this would be
284
- // to isolate `f(x)` in each expression and then check that the
285
- // expressions that they're equal to are equal. In this case that
286
- // would be `sin^2(x)+cos^2(x)` and `1`.
287
- // TODO(TP-11651): Update compare to isolate functions on wide side
288
- // before comparing expressions on the other side.
289
- // expect("f(x) = sin^2(x)+cos^2(x)").toEqualExpr("f(x) = 1");
290
- expect("f(x) = ln|x|+c").toEqualExpr("f(x)-ln|x|-c = 0");
291
- });
292
-
293
- test("evaluating and comparing form", () => {
294
- expect("ab").toEqualExprAndForm("ba");
295
- expect("(ab)c").toEqualExprAndForm("(cb)a");
296
-
297
- const forms = [
298
- "(6x+1)(x-1)",
299
- "(1+6x)(x-1)",
300
- "(6x+1)(-1+x)",
301
- "(1+6x)(-1+x)",
302
- "(-6x-1)(-x+1)",
303
- "(-1-6x)(-x+1)",
304
- "(-6x-1)(1-x)",
305
- "(-1-6x)(1-x)",
306
- "(x-1)(6x+1)",
307
- "(x-1)(1+6x)",
308
- "(-1+x)(6x+1)",
309
- "(-1+x)(1+6x)",
310
- "(-x+1)(-6x-1)",
311
- "(-x+1)(-1-6x)",
312
- "(1-x)(-6x-1)",
313
- "(1-x)(-1-6x)",
314
- "-(6x+1)(1-x)",
315
- "-(-6x-1)(x-1)",
316
- ];
317
-
318
- _.each(forms, function (form) {
319
- expect(forms[0]).toEqualExprAndForm(form);
320
- });
321
-
322
- expect("(6x+1)(x+1)").not.toEqualExprAndForm("(6x+1)(x-1)");
323
- expect("a-b-c").not.toEqualExprAndForm("c+b+a");
324
-
325
- expect("(6x+1)(x+1)").not.toEqualExprAndForm("(6x+1)(x-1)");
326
- expect("a-b-c").not.toEqualExprAndForm("c+b+a");
327
- expect("mx+b").toEqualExprAndForm("b+mx");
328
-
329
- expect("y=mx+b").toEqualExprAndForm("-b-mx=-y");
330
- expect("y=mx+b").not.toEqualExprAndForm("y-b=mx");
331
-
332
- expect("y-3=2(x-4)").not.toEqualExprAndForm("y=2x-5");
333
- expect("y-3=2(x-4)").not.toEqualExprAndForm("2x-y=5");
334
- expect("y=2x-5").not.toEqualExprAndForm("2x-y=5");
335
- });
336
- });
@@ -1,104 +0,0 @@
1
- import _ from "underscore";
2
-
3
- import * as KAS from "../index";
4
-
5
- type Variables = {
6
- [key: string]: string | number | ((arg1: number) => number);
7
- };
8
-
9
- expect.extend({
10
- toCompileAs(
11
- input: string,
12
- expected: number,
13
- vars: Variables = {},
14
- ): jest.CustomMatcherResult {
15
- const functions = Object.keys(vars).filter(
16
- (k) => typeof vars[k] === "function",
17
- );
18
- const func = KAS.parse(input, {functions}).expr.compile();
19
-
20
- const actual = func(vars);
21
-
22
- return Math.abs(actual - expected) < 1e-9
23
- ? {pass: true, message: () => ""}
24
- : {
25
- pass: false,
26
- message: () =>
27
- `${input} should evaluate to ${expected}, was ${actual}; by func: ${func.toString()}`,
28
- };
29
- },
30
- });
31
-
32
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
33
- declare global {
34
- // eslint-disable-next-line @typescript-eslint/no-namespace
35
- namespace jest {
36
- interface Matchers<R> {
37
- toCompileAs(expected: number, vars?: Variables): R;
38
- }
39
- }
40
- }
41
-
42
- describe("compilation", () => {
43
- test("empty", () => {
44
- expect("").toCompileAs(0);
45
- });
46
-
47
- test("simple expressions", () => {
48
- expect("1+2+3+4").toCompileAs(10);
49
- expect("1+2-3+4").toCompileAs(4);
50
- expect("1*2*3*4").toCompileAs(24);
51
- expect("1*2/3*4").toCompileAs(2 + 2 / 3);
52
- expect("4^3^2^1").toCompileAs(262144);
53
- expect("-1").toCompileAs(-1);
54
- expect("--1").toCompileAs(1);
55
- expect("---1").toCompileAs(-1);
56
- expect("2^-2").toCompileAs(0.25);
57
- expect("8^(1/3)").toCompileAs(2);
58
- expect("0^0").toCompileAs(1);
59
- expect(".25*4").toCompileAs(1);
60
- expect("ln e").toCompileAs(1);
61
- expect("log 10").toCompileAs(1);
62
- expect("log_2 2").toCompileAs(1);
63
- });
64
-
65
- test("variable expressions", () => {
66
- expect("x").toCompileAs(3, {x: 3});
67
- expect("x^2").toCompileAs(9, {x: 3});
68
- expect("(x^2+y^2)^.5").toCompileAs(5, {x: 3, y: 4});
69
- expect("log x_0").toCompileAs(1, {x_0: 10});
70
- expect("log x_0 + log x_1").toCompileAs(3, {x_0: 10, x_1: 100});
71
- expect("log x_42").toCompileAs(1, {x_42: 10});
72
- expect("x_a + x_bc").toCompileAs(7, {x_a: 1, x_b: 2, c: 3});
73
- });
74
-
75
- test("function expressions", () => {
76
- expect("f(2)").toCompileAs(4, {
77
- f: function (x) {
78
- return 2 * x;
79
- },
80
- });
81
- expect("f(4+8)").toCompileAs(48, {
82
- f: function (x) {
83
- return 4 * x;
84
- },
85
- });
86
- expect("f(x-1)-f(x)").toCompileAs(-7, {
87
- f: function (x) {
88
- return Math.pow(x, 3);
89
- },
90
- x: 2,
91
- });
92
- });
93
-
94
- test("trig expressions", () => {
95
- expect("-2sin(pi x) + 4").toCompileAs(4, {x: 32});
96
- expect("sin(pi x)").toCompileAs(0, {x: 6});
97
- expect("sin(x)").toCompileAs(1, {x: Math.PI / 2});
98
- expect("sin(pi x)").toCompileAs(-1, {x: 3 / 2});
99
- expect("cos(x)").toCompileAs(1, {x: 0});
100
- expect("cos x").toCompileAs(-1, {x: Math.PI});
101
- expect("tan(x)").toCompileAs(0, {x: 0});
102
- expect("tan x").toCompileAs(1, {x: Math.PI / 4});
103
- });
104
- });
@@ -1,91 +0,0 @@
1
- import _ from "underscore";
2
-
3
- import * as KAS from "../index";
4
-
5
- type Variables = {
6
- [key: string]: string | number;
7
- };
8
-
9
- expect.extend({
10
- toEvaluateAs(
11
- input: string,
12
- expected: number,
13
- vars: Variables = {},
14
- functions?: ReadonlyArray<string>,
15
- ) {
16
- const actual = KAS.parse(input, {functions: functions}).expr.eval(
17
- vars,
18
- {functions: functions},
19
- );
20
-
21
- if (actual !== expected) {
22
- return {
23
- pass: actual !== expected,
24
- message: () => `${input} evaluates as ${expected}`,
25
- };
26
- }
27
-
28
- return {pass: !this.isNot, message: () => ""};
29
- },
30
- });
31
-
32
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
33
- declare global {
34
- // eslint-disable-next-line @typescript-eslint/no-namespace
35
- namespace jest {
36
- interface Matchers<R> {
37
- toEvaluateAs(
38
- expected: number,
39
- vars?: Variables,
40
- functions?: ReadonlyArray<string>,
41
- ): R;
42
- }
43
- }
44
- }
45
-
46
- describe("evaluating", () => {
47
- test("empty", () => {
48
- expect("").toEvaluateAs(0);
49
- });
50
-
51
- test("simple expressions", () => {
52
- expect("1+2+3+4").toEvaluateAs(10);
53
- expect("1+2-3+4").toEvaluateAs(4);
54
- expect("1*2*3*4").toEvaluateAs(24);
55
- expect("1*2/3*4").toEvaluateAs(2 + 2 / 3);
56
- expect("4^3^2^1").toEvaluateAs(262144);
57
- expect("-1").toEvaluateAs(-1);
58
- expect("--1").toEvaluateAs(1);
59
- expect("---1").toEvaluateAs(-1);
60
- expect("2^-2").toEvaluateAs(0.25);
61
- expect("8^(1/3)").toEvaluateAs(2);
62
- expect("0^0").toEvaluateAs(1);
63
- expect(".25*4").toEvaluateAs(1);
64
- expect("ln e").toEvaluateAs(1);
65
- expect("log 10").toEvaluateAs(1);
66
- expect("log_2 2").toEvaluateAs(1);
67
- });
68
-
69
- test("hyperbolic expressions", () => {
70
- expect("cosh(0.2)").toEvaluateAs(1.020066755619076);
71
- expect("coth(0.2)").toEvaluateAs(5.066489563439473);
72
- expect("csch(3 * 2)").toEvaluateAs(0.00495753481347936);
73
- });
74
-
75
- test("variable expressions", () => {
76
- expect("x").toEvaluateAs(3, {x: 3});
77
- expect("x^2").toEvaluateAs(9, {x: 3});
78
- expect("(x^2+y^2)^.5").toEvaluateAs(5, {x: 3, y: 4});
79
- expect("log x_0").toEvaluateAs(1, {x_0: 10});
80
- expect("log x_0 + log x_1").toEvaluateAs(3, {x_0: 10, x_1: 100});
81
- expect("log x_42").toEvaluateAs(1, {x_42: 10});
82
- expect("x_a + x_bc").toEvaluateAs(7, {x_a: 1, x_b: 2, c: 3});
83
- });
84
-
85
- test("function expressions", () => {
86
- expect("f(2)").toEvaluateAs(4, {f: "2x"}, ["f"]);
87
- expect("f(4+8)").toEvaluateAs(48, {f: "4x"}, ["f"]);
88
- expect("f(x-1)-f(x)").toEvaluateAs(-7, {f: "x^3", x: 2}, ["f"]);
89
- expect("g(1)").toEvaluateAs(-1, {f: "x", g: "-f(x)"}, ["f", "g"]);
90
- });
91
- });