@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.
- package/dist/es/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -2
- package/.eslintrc.js +0 -12
- package/CHANGELOG.md +0 -81
- package/experimenter.html +0 -100
- package/src/__genfiles__/parser.js +0 -840
- package/src/__genfiles__/unitparser.js +0 -679
- package/src/__tests__/checking-form.test.ts +0 -90
- package/src/__tests__/comparing.test.ts +0 -336
- package/src/__tests__/compilation.test.ts +0 -104
- package/src/__tests__/evaluating.test.ts +0 -91
- package/src/__tests__/index.test.ts +0 -379
- package/src/__tests__/parsing.test.ts +0 -505
- package/src/__tests__/rendering.test.ts +0 -286
- package/src/__tests__/transforming.test.ts +0 -348
- package/src/__tests__/units.test.ts +0 -213
- package/src/compare.js +0 -70
- package/src/index.js +0 -4
- package/src/nodes.js +0 -3926
- package/src/parser-generator.js +0 -239
- package/src/unitvalue.jison +0 -161
- package/src/version.ts +0 -10
- package/tsconfig-build.json +0 -10
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import _ from "underscore";
|
|
2
|
-
|
|
3
|
-
import * as KAS from "../index";
|
|
4
|
-
|
|
5
|
-
expect.extend({
|
|
6
|
-
toRenderTex(
|
|
7
|
-
input: string,
|
|
8
|
-
expected: string,
|
|
9
|
-
options?: any,
|
|
10
|
-
): jest.CustomMatcherResult {
|
|
11
|
-
const actual = KAS.parse(input, options).expr.tex();
|
|
12
|
-
|
|
13
|
-
if (actual !== expected) {
|
|
14
|
-
return {
|
|
15
|
-
pass: false,
|
|
16
|
-
message: () => `${input} renders as ${expected}`,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return {pass: !this.isNot, message: () => ""};
|
|
21
|
-
},
|
|
22
|
-
toRenderTexOpt(
|
|
23
|
-
input: string,
|
|
24
|
-
expected: string,
|
|
25
|
-
...optlist: ReadonlyArray<any>
|
|
26
|
-
) {
|
|
27
|
-
const options = {
|
|
28
|
-
display: false,
|
|
29
|
-
dynamic: false,
|
|
30
|
-
times: false,
|
|
31
|
-
} as const;
|
|
32
|
-
_.each(optlist, function (opt) {
|
|
33
|
-
options[opt] = true;
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const actual = KAS.parse(input).expr.asTex(options);
|
|
37
|
-
|
|
38
|
-
if (actual !== expected) {
|
|
39
|
-
return {
|
|
40
|
-
pass: false,
|
|
41
|
-
message: () => `${input} renders with options as ${expected}`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {pass: true, message: () => ""};
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
50
|
-
declare global {
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
52
|
-
namespace jest {
|
|
53
|
-
interface Matchers<R> {
|
|
54
|
-
toRenderTex(expected: string, options?: any): R;
|
|
55
|
-
toRenderTexOpt(expected: string, ...optlist: ReadonlyArray<any>): R;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
describe("rendering", () => {
|
|
61
|
-
test("positive and negative primitives", () => {
|
|
62
|
-
expect("0").toRenderTex("0");
|
|
63
|
-
expect("-1").toRenderTex("-1");
|
|
64
|
-
expect("--1").toRenderTex("--1");
|
|
65
|
-
expect("-2").toRenderTex("-2");
|
|
66
|
-
expect("--2").toRenderTex("--2");
|
|
67
|
-
expect("x").toRenderTex("x");
|
|
68
|
-
expect("theta").toRenderTex("\\theta");
|
|
69
|
-
expect("1/2").toRenderTex("\\frac{1}{2}");
|
|
70
|
-
expect("-1/2").toRenderTex("-\\frac{1}{2}");
|
|
71
|
-
expect("1/-2").toRenderTex("-\\frac{1}{2}");
|
|
72
|
-
expect("-1/-2").toRenderTex("--\\frac{1}{2}");
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("addition", () => {
|
|
76
|
-
expect("1-2").toRenderTex("1-2");
|
|
77
|
-
expect("a+b").toRenderTex("a+b");
|
|
78
|
-
expect("a-b").toRenderTex("a-b");
|
|
79
|
-
expect("a-1b").toRenderTex("a-1b");
|
|
80
|
-
expect("a+-b").toRenderTex("a+-b");
|
|
81
|
-
expect("a+-1b").toRenderTex("a+-1b");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("multiplication", () => {
|
|
85
|
-
expect("ab").toRenderTex("ab");
|
|
86
|
-
expect("a*b").toRenderTex("ab");
|
|
87
|
-
expect("a/b").toRenderTex("\\frac{a}{b}");
|
|
88
|
-
expect("a/bc/d").toRenderTex("\\frac{ac}{bd}");
|
|
89
|
-
|
|
90
|
-
expect("1/(x+y)").toRenderTex("\\frac{1}{x+y}");
|
|
91
|
-
expect("2/(x+y)").toRenderTex("\\frac{2}{x+y}");
|
|
92
|
-
expect("(z+2)/(x+y)").toRenderTex("\\frac{z+2}{x+y}");
|
|
93
|
-
expect("(z+2)/4").toRenderTex("\\frac{z+2}{4}");
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("rational expressions", () => {
|
|
97
|
-
expect("x+1/2").toRenderTex("x+\\frac{1}{2}");
|
|
98
|
-
expect("x-1/2").toRenderTex("x-\\frac{1}{2}");
|
|
99
|
-
|
|
100
|
-
expect("1/2x").toRenderTex("\\frac{1}{2}x");
|
|
101
|
-
expect("1/2x/y").toRenderTex("\\frac{1}{2}\\frac{x}{y}");
|
|
102
|
-
expect("5*1/2x/y").toRenderTex("\\frac{1}{2}\\frac{5x}{y}");
|
|
103
|
-
expect("1/2*4*x/y").toRenderTex("\\frac{1}{2}\\frac{4x}{y}");
|
|
104
|
-
expect("-1/2x").toRenderTex("-\\frac{1}{2}x");
|
|
105
|
-
expect("a-1/2x").toRenderTex("a-\\frac{1}{2}x");
|
|
106
|
-
|
|
107
|
-
expect("1/(2x)").toRenderTex("\\frac{1}{2x}");
|
|
108
|
-
expect("8/(7p^4)").toRenderTex("\\frac{8}{7p^{4}}");
|
|
109
|
-
|
|
110
|
-
expect("x/2").toRenderTex("\\frac{x}{2}");
|
|
111
|
-
expect("1x/2").toRenderTex("\\frac{1x}{2}");
|
|
112
|
-
expect("-x/2").toRenderTex("-\\frac{x}{2}");
|
|
113
|
-
expect("x/-2").toRenderTex("-\\frac{x}{2}");
|
|
114
|
-
expect("x/-2/-3").toRenderTex("--\\frac{x}{2 \\cdot 3}");
|
|
115
|
-
expect("--x/2/3").toRenderTex("--\\frac{x}{2 \\cdot 3}");
|
|
116
|
-
expect("a-x/2").toRenderTex("a-\\frac{x}{2}");
|
|
117
|
-
|
|
118
|
-
expect("1*-2").toRenderTex("1 \\cdot -2");
|
|
119
|
-
expect("1*-2*3").toRenderTex("1 \\cdot -2 \\cdot 3");
|
|
120
|
-
expect("1*-2*3/4").toRenderTex("1 \\cdot -2 \\cdot \\frac{3}{4}");
|
|
121
|
-
expect("1*-2*3/4/5").toRenderTex(
|
|
122
|
-
"1 \\cdot -2 \\cdot \\frac{3}{4} \\cdot \\frac{1}{5}",
|
|
123
|
-
);
|
|
124
|
-
expect("1/2*1/2").toRenderTex("\\frac{1}{2} \\cdot \\frac{1}{2}");
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("exponentiation", () => {
|
|
128
|
-
expect("x^y").toRenderTex("x^{y}");
|
|
129
|
-
expect("xy^z").toRenderTex("xy^{z}");
|
|
130
|
-
expect("(xy)^z").toRenderTex("(xy)^{z}");
|
|
131
|
-
expect("(x+y)^z").toRenderTex("(x+y)^{z}");
|
|
132
|
-
expect("x^(yz)").toRenderTex("x^{yz}");
|
|
133
|
-
expect("x^-(yz)").toRenderTex("x^{-yz}");
|
|
134
|
-
expect("x^(y+z)").toRenderTex("x^{y+z}");
|
|
135
|
-
expect("x^-(y+z)").toRenderTex("x^{-(y+z)}");
|
|
136
|
-
expect("(x^y)^z").toRenderTex("(x^{y})^{z}");
|
|
137
|
-
expect("pir^2").toRenderTex("\\pi r^{2}");
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test("square root", () => {
|
|
141
|
-
expect("sqrt(x)").toRenderTex("\\sqrt{x}");
|
|
142
|
-
expect("sqrt(x)y").toRenderTex("\\sqrt{x}y");
|
|
143
|
-
expect("1/sqrt(x)").toRenderTex("\\frac{1}{\\sqrt{x}}");
|
|
144
|
-
expect("1/sqrt(x)y").toRenderTex("\\frac{y}{\\sqrt{x}}");
|
|
145
|
-
|
|
146
|
-
expect("sqrt(2)/2").toRenderTex("\\frac{\\sqrt{2}}{2}");
|
|
147
|
-
expect("sqrt(2)^2").toRenderTex("(\\sqrt{2})^{2}");
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
test("nth root", () => {
|
|
151
|
-
// This is an unfortunate case, but only nth degree roots with integer
|
|
152
|
-
// n's get nicely printed as tex.
|
|
153
|
-
expect("sqrt[z]{x}").toRenderTex("x^{\\frac{1}{z}}");
|
|
154
|
-
|
|
155
|
-
expect("sqrt[3]{x}").toRenderTex("\\sqrt[3]{x}");
|
|
156
|
-
expect("sqrt[3]{x}z").toRenderTex("\\sqrt[3]{x}z");
|
|
157
|
-
expect("1/sqrt[4]{x}").toRenderTex("\\frac{1}{\\sqrt[4]{x}}");
|
|
158
|
-
expect("1/sqrt[4]{x}y").toRenderTex("\\frac{y}{\\sqrt[4]{x}}");
|
|
159
|
-
|
|
160
|
-
expect("sqrt[9]{2}/2").toRenderTex("\\frac{\\sqrt[9]{2}}{2}");
|
|
161
|
-
expect("sqrt[9]{2}^2").toRenderTex("(\\sqrt[9]{2})^{2}");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("absolute value", () => {
|
|
165
|
-
expect("|x|").toRenderTex("\\left|x\\right|");
|
|
166
|
-
expect("|x|y").toRenderTex("\\left|x\\right|y");
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test("logarithms", () => {
|
|
170
|
-
expect("lnx").toRenderTex("\\ln(x)");
|
|
171
|
-
expect("logx").toRenderTex("\\log_{10}(x)");
|
|
172
|
-
expect("lnx^y").toRenderTex("\\ln(x^{y})");
|
|
173
|
-
expect("logx^y").toRenderTex("\\log_{10}(x^{y})");
|
|
174
|
-
expect("(lnx)^y").toRenderTex("[\\ln(x)]^{y}");
|
|
175
|
-
expect("(logx)^y").toRenderTex("[\\log_{10}(x)]^{y}");
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test("trig functions", () => {
|
|
179
|
-
expect("sinx").toRenderTex("\\sin(x)");
|
|
180
|
-
|
|
181
|
-
expect("arcsin x").toRenderTex("\\arcsin(x)");
|
|
182
|
-
expect("sin^-1 x").toRenderTex("\\arcsin(x)");
|
|
183
|
-
|
|
184
|
-
expect("(sinx)^2").toRenderTex("\\sin^{2}(x)");
|
|
185
|
-
expect("sin^2 x").toRenderTex("\\sin^{2}(x)");
|
|
186
|
-
|
|
187
|
-
expect("1/(sinx)^2").toRenderTex("\\frac{1}{\\sin^{2}(x)}");
|
|
188
|
-
expect("1/sin^2x").toRenderTex("\\frac{1}{\\sin^{2}(x)}");
|
|
189
|
-
|
|
190
|
-
expect("sin^2 x + cos^2 x = 1").toRenderTex(
|
|
191
|
-
"\\sin^{2}(x)+\\cos^{2}(x) = 1",
|
|
192
|
-
);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
test("hyperbolic functions", () => {
|
|
196
|
-
expect("sinhx").toRenderTex("\\sinh(x)");
|
|
197
|
-
expect("sinh^2 x").toRenderTex("\\sinh^{2}(x)");
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
test("multiplication with numbers", () => {
|
|
201
|
-
expect("4*10").toRenderTex("4 \\cdot 10");
|
|
202
|
-
expect("10^5").toRenderTex("10^{5}");
|
|
203
|
-
expect("4*10^5").toRenderTex("4 \\cdot 10^{5}");
|
|
204
|
-
expect("10^5x").toRenderTex("10^{5}x");
|
|
205
|
-
expect("4*10^5x").toRenderTex("4 \\cdot 10^{5}x");
|
|
206
|
-
expect("x*(10+4)^5").toRenderTex("x(10+4)^{5}");
|
|
207
|
-
|
|
208
|
-
expect("-1*2").toRenderTex("-1 \\cdot 2");
|
|
209
|
-
expect("1*-2").toRenderTex("1 \\cdot -2");
|
|
210
|
-
expect("-1*-2").toRenderTex("-1 \\cdot -2");
|
|
211
|
-
expect("-1*2*3").toRenderTex("-1 \\cdot 2 \\cdot 3");
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("inverses and division", () => {
|
|
215
|
-
expect("x^-1").toRenderTex("x^{-1}");
|
|
216
|
-
expect("2x^-1").toRenderTex("2x^{-1}");
|
|
217
|
-
expect("1/x").toRenderTex("\\frac{1}{x}");
|
|
218
|
-
expect("-1/x").toRenderTex("\\frac{-1}{x}");
|
|
219
|
-
expect("2/x").toRenderTex("\\frac{2}{x}");
|
|
220
|
-
expect("1/x^2").toRenderTex("\\frac{1}{x^{2}}");
|
|
221
|
-
expect("2/x^2").toRenderTex("\\frac{2}{x^{2}}");
|
|
222
|
-
expect("1/1/x").toRenderTex("\\frac{1}{x}");
|
|
223
|
-
expect("1/(1/x)").toRenderTex("\\frac{1}{\\frac{1}{x}}");
|
|
224
|
-
expect("1/x/x").toRenderTex("\\frac{1}{xx}");
|
|
225
|
-
expect("1/(x/x)").toRenderTex("\\frac{1}{\\frac{x}{x}}");
|
|
226
|
-
expect("-1/1/x").toRenderTex("\\frac{-1}{x}");
|
|
227
|
-
expect("-1/(1/x)").toRenderTex("\\frac{-1}{\\frac{1}{x}}");
|
|
228
|
-
expect("-1/x/x").toRenderTex("\\frac{-1}{xx}");
|
|
229
|
-
expect("-1/(x/x)").toRenderTex("\\frac{-1}{\\frac{x}{x}}");
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
test("distributive property", () => {
|
|
233
|
-
expect("ab+c").toRenderTex("ab+c");
|
|
234
|
-
expect("ab+ac").toRenderTex("ab+ac");
|
|
235
|
-
expect("a(b+c)").toRenderTex("a(b+c)");
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
test("numerical exponents", () => {
|
|
239
|
-
expect("9^4").toRenderTex("9^{4}");
|
|
240
|
-
expect("-9^4").toRenderTex("-9^{4}");
|
|
241
|
-
expect("1-9^4").toRenderTex("1-9^{4}");
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
test("negating a Mul", () => {
|
|
245
|
-
expect("-3x").toRenderTex("-3x");
|
|
246
|
-
expect("--3x").toRenderTex("--3x");
|
|
247
|
-
expect("-x*3").toRenderTex("-3x");
|
|
248
|
-
expect("--x*3").toRenderTex("--3x");
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test("equations", () => {
|
|
252
|
-
expect("y=x").toRenderTex("y = x");
|
|
253
|
-
expect("y<x").toRenderTex("y < x");
|
|
254
|
-
expect("y>x").toRenderTex("y > x");
|
|
255
|
-
expect("y<>x").toRenderTex("y \\ne x");
|
|
256
|
-
expect("y=/=x").toRenderTex("y \\ne x");
|
|
257
|
-
expect("y<=x").toRenderTex("y \\le x");
|
|
258
|
-
expect("y>=x").toRenderTex("y \\ge x");
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
test("function variables", () => {
|
|
262
|
-
expect("f(x)").toRenderTex("fx");
|
|
263
|
-
expect("f(x)").toRenderTex("f(x)", {functions: ["f"]});
|
|
264
|
-
expect("f(sin x)").toRenderTex("f(\\sin(x))", {functions: ["f"]});
|
|
265
|
-
expect("sin f(x)").toRenderTex("\\sin(f(x))", {functions: ["f"]});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test("options", () => {
|
|
269
|
-
expect("x").toRenderTexOpt("x");
|
|
270
|
-
expect("x").toRenderTexOpt("\\displaystyle x", "display");
|
|
271
|
-
expect("a(b+c(d+e))").toRenderTexOpt("a(b+c(d+e))");
|
|
272
|
-
expect("a(b+c(d+e))").toRenderTexOpt(
|
|
273
|
-
"a\\left(b+c\\left(d+e\\right)\\right)",
|
|
274
|
-
"dynamic",
|
|
275
|
-
);
|
|
276
|
-
expect("2*2").toRenderTexOpt("2 \\cdot 2");
|
|
277
|
-
expect("2*2").toRenderTexOpt("2 \\times 2", "times");
|
|
278
|
-
|
|
279
|
-
expect("1*2(3+4)").toRenderTexOpt(
|
|
280
|
-
"\\displaystyle 1 \\times 2\\left(3+4\\right)",
|
|
281
|
-
"display",
|
|
282
|
-
"dynamic",
|
|
283
|
-
"times",
|
|
284
|
-
);
|
|
285
|
-
});
|
|
286
|
-
});
|
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
import _ from "underscore";
|
|
2
|
-
|
|
3
|
-
import * as KAS from "../index";
|
|
4
|
-
|
|
5
|
-
expect.extend({
|
|
6
|
-
toFactorAs(input: string, reference: string): jest.CustomMatcherResult {
|
|
7
|
-
const actual = KAS.parse(input).expr.factor().normalize().repr();
|
|
8
|
-
const expected = KAS.parse(reference).expr.normalize().repr();
|
|
9
|
-
|
|
10
|
-
return actual === expected
|
|
11
|
-
? {pass: true, message: () => ""}
|
|
12
|
-
: {pass: false, message: () => `${input} factors as ${reference}`};
|
|
13
|
-
},
|
|
14
|
-
toExpandAs(input: string, reference: string): jest.CustomMatcherResult {
|
|
15
|
-
const actual = KAS.parse(input).expr.expand().normalize().print();
|
|
16
|
-
const expected = KAS.parse(reference).expr.normalize().print();
|
|
17
|
-
|
|
18
|
-
return actual === expected
|
|
19
|
-
? {pass: true, message: () => ""}
|
|
20
|
-
: {pass: false, message: () => `${input} expands as ${reference}`};
|
|
21
|
-
},
|
|
22
|
-
toExpandAsRepr(input: string, reference: string): jest.CustomMatcherResult {
|
|
23
|
-
const actual = KAS.parse(input).expr.expand().repr();
|
|
24
|
-
|
|
25
|
-
return actual === reference
|
|
26
|
-
? {pass: true, message: () => ""}
|
|
27
|
-
: {pass: false, message: () => `${input} expands as ${reference}`};
|
|
28
|
-
},
|
|
29
|
-
toExpandAsTex(input: string, reference: string): jest.CustomMatcherResult {
|
|
30
|
-
const actual = KAS.parse(input).expr.expand().tex();
|
|
31
|
-
|
|
32
|
-
return actual === reference
|
|
33
|
-
? {pass: true, message: () => ""}
|
|
34
|
-
: {pass: false, message: () => `${input} expands as ${reference}`};
|
|
35
|
-
},
|
|
36
|
-
toCollectAs(input: string, reference: string): jest.CustomMatcherResult {
|
|
37
|
-
const actual = KAS.parse(input).expr.collect().normalize().print();
|
|
38
|
-
const expected = KAS.parse(reference)
|
|
39
|
-
.expr.collect()
|
|
40
|
-
.normalize()
|
|
41
|
-
.print();
|
|
42
|
-
|
|
43
|
-
return actual === expected
|
|
44
|
-
? {pass: true, message: () => ""}
|
|
45
|
-
: {pass: false, message: () => `${input} collects as ${reference}`};
|
|
46
|
-
},
|
|
47
|
-
toCollectAsRepr(
|
|
48
|
-
input: string,
|
|
49
|
-
reference: string,
|
|
50
|
-
): jest.CustomMatcherResult {
|
|
51
|
-
const actual = KAS.parse(input).expr.collect().repr();
|
|
52
|
-
|
|
53
|
-
return actual === reference
|
|
54
|
-
? {pass: true, message: () => ""}
|
|
55
|
-
: {pass: false, message: () => `${input} collects as ${reference}`};
|
|
56
|
-
},
|
|
57
|
-
toCollectAsTex(input: string, reference: string): jest.CustomMatcherResult {
|
|
58
|
-
const actual = KAS.parse(input).expr.collect().tex();
|
|
59
|
-
|
|
60
|
-
return actual === reference
|
|
61
|
-
? {pass: true, message: () => ""}
|
|
62
|
-
: {pass: false, message: () => `${input} collects as ${reference}`};
|
|
63
|
-
},
|
|
64
|
-
toSimplifyAs(input: string, reference: string): jest.CustomMatcherResult {
|
|
65
|
-
const actual = KAS.parse(input).expr.simplify().normalize().print();
|
|
66
|
-
const expected = KAS.parse(reference).expr.normalize().print();
|
|
67
|
-
|
|
68
|
-
return actual === expected
|
|
69
|
-
? {pass: true, message: () => ""}
|
|
70
|
-
: {
|
|
71
|
-
pass: false,
|
|
72
|
-
message: () => `${input} simplifies as ${reference}`,
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
78
|
-
declare global {
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
80
|
-
namespace jest {
|
|
81
|
-
interface Matchers<R> {
|
|
82
|
-
toFactorAs(reference: string): R;
|
|
83
|
-
toExpandAs(reference: string): R;
|
|
84
|
-
toExpandAsRepr(reference: string): R;
|
|
85
|
-
toExpandAsTex(reference: string): R;
|
|
86
|
-
toCollectAs(reference: string): R;
|
|
87
|
-
toCollectAsRepr(reference: string): R;
|
|
88
|
-
toCollectAsTex(reference: string): R;
|
|
89
|
-
toSimplifyAs(reference: string): R;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
describe("transforming", () => {
|
|
95
|
-
test("factoring Adds", () => {
|
|
96
|
-
expect("2+2").toFactorAs("2(1+1)");
|
|
97
|
-
expect("-2-2").toFactorAs("-2(1+1)");
|
|
98
|
-
expect("2x+2").toFactorAs("2(x+1)");
|
|
99
|
-
expect("x^3+x^2").toFactorAs("x^2(x+1)");
|
|
100
|
-
expect("2x+xy").toFactorAs("x(2+y)");
|
|
101
|
-
expect("2xy+xy^2").toFactorAs("xy(2+y)");
|
|
102
|
-
expect("2+2/3").toFactorAs("2/3(3+1)"); // a little questionable, but 2/3 is what
|
|
103
|
-
// wolframalpha returns for the gcd, so
|
|
104
|
-
// we pull it out
|
|
105
|
-
expect("2x+1.1").toFactorAs("2x+1.1");
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("factoring Muls", () => {
|
|
109
|
-
expect("(2x+2)/(x+1)").toFactorAs("2 (x+1)/(x+1)");
|
|
110
|
-
expect("(x+1)/(2x+2)").toFactorAs("1/2 (x+1)/(x+1)");
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
test("factoring Pows", () => {
|
|
114
|
-
expect("x^y+x^(2y)").toFactorAs("x^y(1+x^y)");
|
|
115
|
-
expect("x^y+x^z").toFactorAs("x^y+x^z");
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test("distribute over multiplication", () => {
|
|
119
|
-
expect("a(b+c)").toExpandAs("ab+ac");
|
|
120
|
-
expect("a(b+c)").toExpandAsTex("ab+ac");
|
|
121
|
-
expect("a(b+c)").toExpandAsRepr(
|
|
122
|
-
"Add(Mul(Var(a),Var(b)),Mul(Var(a),Var(c)))",
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
expect("a(b-c)").toExpandAs("ab-ac");
|
|
126
|
-
expect("a(b-c)").toExpandAsTex("ab-ac");
|
|
127
|
-
expect("a(b-c)").toExpandAsRepr(
|
|
128
|
-
"Add(Mul(Var(a),Var(b)),Mul(Var(a),-1,Var(c)))",
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
expect("a(b+c)d").toExpandAs("abd+acd");
|
|
132
|
-
expect("a(b+c)d").toExpandAsRepr(
|
|
133
|
-
"Add(Mul(Var(a),Var(d),Var(b)),Mul(Var(a),Var(d),Var(c)))",
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
expect("(a+b)(c+d)").toExpandAs("ac+ad+bc+bd");
|
|
137
|
-
expect("(a+b)(c+d)ef").toExpandAs("acef+adef+bcef+bdef");
|
|
138
|
-
expect("(a+b)c^d").toExpandAs("ac^d+bc^d");
|
|
139
|
-
expect("ab(c+d)e^f").toExpandAs("abce^f+abde^f");
|
|
140
|
-
|
|
141
|
-
expect("(a+b(c+d))e").toExpandAs("ae+bce+bde");
|
|
142
|
-
expect("(a+b(c+d))e").toExpandAsRepr(
|
|
143
|
-
"Add(Mul(Const(e),Var(a)),Mul(Const(e),Var(b),Var(c)),Mul(Const(e),Var(b),Var(d)))",
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("distribute over rational expressions", () => {
|
|
148
|
-
expect("(a+b)/(c+d)").toExpandAs("(a+b)/(c+d)");
|
|
149
|
-
expect("(a+b)/(c+d)*a").toExpandAs("(aa+ab)/(c+d)");
|
|
150
|
-
expect("(a+b)/(c+d)*1/e").toExpandAs("(a+b)/(ce+de)");
|
|
151
|
-
expect("(a+b)/(c+d)*a/e").toExpandAs("(aa+ab)/(ce+de)");
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test("expand exponentiation", () => {
|
|
155
|
-
expect("(ab)^2").toExpandAs("a^2 b^2");
|
|
156
|
-
expect("2*(ab)^2").toExpandAs("2 a^2 b^2");
|
|
157
|
-
expect("(a+b)^2").toExpandAs("a^2+2ab+b^2");
|
|
158
|
-
|
|
159
|
-
expect("(ab)^-2").toExpandAs("a^-2 b^-2");
|
|
160
|
-
expect("2*(ab)^-2").toExpandAs("2 a^-2 b^-2");
|
|
161
|
-
expect("(a+b)^-2").toExpandAs("(a^2+2ab+b^2)^-1");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("expand absolute value", () => {
|
|
165
|
-
expect("|a+b|").toExpandAs("|a+b|");
|
|
166
|
-
expect("|ab|").toExpandAs("|a|*|b|");
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test("expand logarithms", () => {
|
|
170
|
-
expect("ln(xy)").toExpandAs("lnx+lny");
|
|
171
|
-
expect("log_b(x)").toExpandAs("lnx/lnb");
|
|
172
|
-
expect("log_b(xy)").toExpandAs("lnx/lnb+lny/lnb");
|
|
173
|
-
expect("ln(xy/z)").toExpandAs("lnx+lny-lnz");
|
|
174
|
-
|
|
175
|
-
expect("ln(x^y)").toExpandAs("ylnx");
|
|
176
|
-
expect("log_b(x^y)").toExpandAs("ylnx/lnb");
|
|
177
|
-
expect("ln(x^y^z)").toExpandAs("y^zlnx");
|
|
178
|
-
|
|
179
|
-
expect("ln(x^y/z)").toExpandAs("ylnx-lnz");
|
|
180
|
-
|
|
181
|
-
// ln((xy)^z) -> ln(x^z*y^z) -> z*ln(x)+z*ln(y)
|
|
182
|
-
expect("ln((xy)^z)").toExpandAs("zlnx+zlny");
|
|
183
|
-
|
|
184
|
-
expect("log_b(x)log_x(y)").toExpandAs("ln(x)/ln(b)*ln(y)/ln(x)");
|
|
185
|
-
expect("log_b(x)log_x(y)log_y(z)").toExpandAs(
|
|
186
|
-
"ln(x)/ln(b)*ln(y)/ln(x)*ln(z)/ln(y)",
|
|
187
|
-
);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
test("expand trig functions", () => {
|
|
191
|
-
expect("sin(x)").toExpandAs("sin(x)");
|
|
192
|
-
expect("cos(x)").toExpandAs("cos(x)");
|
|
193
|
-
expect("tan(x)").toExpandAs("sin(x)/cos(x)");
|
|
194
|
-
expect("csc(x)").toExpandAs("1/sin(x)");
|
|
195
|
-
expect("sec(x)").toExpandAs("1/cos(x)");
|
|
196
|
-
expect("cot(x)").toExpandAs("cos(x)/sin(x)");
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("expand hyperbolic functions", () => {
|
|
200
|
-
expect("sinh(x)").toExpandAs("sinh(x)");
|
|
201
|
-
expect("cosh(x)").toExpandAs("cosh(x)");
|
|
202
|
-
expect("tanh(x)").toExpandAs("sinh(x)/cosh(x)");
|
|
203
|
-
expect("csch(x)").toExpandAs("1/sinh(x)");
|
|
204
|
-
expect("sech(x)").toExpandAs("1/cosh(x)");
|
|
205
|
-
expect("coth(x)").toExpandAs("cosh(x)/sinh(x)");
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test("collect over addition", () => {
|
|
209
|
-
expect("").toCollectAs("0");
|
|
210
|
-
expect("0").toCollectAs("0");
|
|
211
|
-
expect("1+3").toCollectAs("4");
|
|
212
|
-
expect("x+3").toCollectAs("3+x");
|
|
213
|
-
expect("x+3x").toCollectAs("4x");
|
|
214
|
-
expect("x+3x").toCollectAsRepr("Mul(4,Var(x))");
|
|
215
|
-
expect("a+a+a").toCollectAs("3a");
|
|
216
|
-
expect("a+a+a").toCollectAsRepr("Mul(3,Var(a))");
|
|
217
|
-
expect("a+b+b+c").toCollectAs("a+2b+c");
|
|
218
|
-
expect("a+b+b+c").toCollectAsRepr("Add(Var(a),Mul(2,Var(b)),Var(c))");
|
|
219
|
-
expect("4x^2-x^2+8x+7-5x-4").toCollectAs("3+3x+3x^2");
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test("collect over multiplication", () => {
|
|
223
|
-
expect("5*7").toCollectAs("35");
|
|
224
|
-
expect("5*7x+20x").toCollectAs("55x");
|
|
225
|
-
expect("3x*xy+2yx^2").toCollectAs("5x^2y");
|
|
226
|
-
expect("4/6").toCollectAs("2/3");
|
|
227
|
-
expect("1/1").toCollectAs("1");
|
|
228
|
-
expect("1/2+1/3").toCollectAs("5/6");
|
|
229
|
-
expect("1/2+1/3+1").toCollectAs("11/6");
|
|
230
|
-
expect("1.2+1/2").toCollectAs("1.7");
|
|
231
|
-
expect("1/2-1/2").toCollectAs("0");
|
|
232
|
-
expect("1/2-.5").toCollectAs("0");
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test("collect over exponentiation", () => {
|
|
236
|
-
expect("x^0").toCollectAs("1");
|
|
237
|
-
expect("x^1").toCollectAs("x");
|
|
238
|
-
expect("x^(log_x y)").toCollectAs("y");
|
|
239
|
-
expect("(x^y)^z").toCollectAs("x^(yz)");
|
|
240
|
-
expect("0^0").toCollectAs("1");
|
|
241
|
-
expect("4^1.5").toCollectAs("8");
|
|
242
|
-
expect("(2/3)^2").toCollectAs("4/9");
|
|
243
|
-
expect("(2/3)^-2").toCollectAs("9/4");
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
test("collect over roots", () => {
|
|
247
|
-
expect("sqrt(2)^2").toCollectAs("2");
|
|
248
|
-
expect("sqrt[3]{3}^3").toCollectAs("3");
|
|
249
|
-
expect("(2^(1/3))^3").toCollectAs("2");
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test("collect over absolute value", () => {
|
|
253
|
-
expect("|x|").toCollectAs("|x|");
|
|
254
|
-
expect("|2|").toCollectAs("2");
|
|
255
|
-
expect("|0|").toCollectAs("0");
|
|
256
|
-
expect("|-2|").toCollectAs("2");
|
|
257
|
-
expect("|pi|").toCollectAs("pi");
|
|
258
|
-
expect("|2^x|").toCollectAs("2^x");
|
|
259
|
-
expect("|x^2|").toCollectAs("x^2");
|
|
260
|
-
expect("|-2pix^2y^3|").toCollectAs("2pix^2*|y^3|");
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
test("collect over logarithms", () => {
|
|
264
|
-
expect("log(1)").toCollectAs("0");
|
|
265
|
-
expect("log_x(x)").toCollectAs("1");
|
|
266
|
-
expect("log_b(b^x)").toCollectAs("x");
|
|
267
|
-
|
|
268
|
-
expect("b^(2*y*log_b x)").toCollectAs("x^(2y)");
|
|
269
|
-
expect("b^(log_b a) b^(-log_b c)").toCollectAs("a/c");
|
|
270
|
-
|
|
271
|
-
expect("ln(x)/ln(b)").toCollectAs("log_b(x)");
|
|
272
|
-
expect("ln(x)/ln(b)*ln(y)/ln(x)").toCollectAs("log_b(y)");
|
|
273
|
-
expect("ln(x)/ln(b)*ln(y)/ln(x)*ln(z)/ln(y)").toCollectAs("log_b(z)");
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
test("collect trig functions", () => {
|
|
277
|
-
expect("sin(x)cos(x)").toCollectAs("sin(x)cos(x)");
|
|
278
|
-
expect("sin(x)/cos(x)").toCollectAs("tan(x)");
|
|
279
|
-
|
|
280
|
-
expect("sin^2(x)/cos^2(x)").toCollectAs("tan^2(x)");
|
|
281
|
-
expect("cos^2(x)/sin^2(x)").toCollectAs("cot^2(x)");
|
|
282
|
-
|
|
283
|
-
expect("sin^-2(x)/cos^-2(x)").toCollectAs("cot^2(x)");
|
|
284
|
-
expect("cos^-2(x)/sin^-2(x)").toCollectAs("tan^2(x)");
|
|
285
|
-
|
|
286
|
-
expect("sin^--2(x)/cos^--2(x)").toCollectAs("tan^2(x)");
|
|
287
|
-
expect("cos^--2(x)/sin^--2(x)").toCollectAs("cot^2(x)");
|
|
288
|
-
|
|
289
|
-
expect("sin^2(x)/cos(x)").toCollectAs("sin^2(x)/cos(x)");
|
|
290
|
-
expect("sin(x)/cos^2(x)").toCollectAs("sin(x)/cos^2(x)");
|
|
291
|
-
|
|
292
|
-
expect("sin(-x)").toCollectAs("-sin(x)");
|
|
293
|
-
expect("cos(-x)").toCollectAs("cos(x)");
|
|
294
|
-
expect("tan(-x)").toCollectAs("-tan(x)");
|
|
295
|
-
expect("csc(-x)").toCollectAs("-csc(x)");
|
|
296
|
-
expect("sec(-x)").toCollectAs("sec(x)");
|
|
297
|
-
expect("cot(-x)").toCollectAs("-cot(x)");
|
|
298
|
-
|
|
299
|
-
expect("sin(--x)").toCollectAs("sin(x)");
|
|
300
|
-
expect("arcsin(-x)").toCollectAs("arcsin(-x)");
|
|
301
|
-
|
|
302
|
-
expect("sin(-x)cos(-x)").toCollectAs("-sin(x)cos(x)");
|
|
303
|
-
expect("sin(-x)/cos(-x)").toCollectAs("-tan(x)");
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test("collect then output tex", () => {
|
|
307
|
-
// user-friendly tex representation is not guaranteed after collect(assert, )
|
|
308
|
-
expect("-x").toCollectAs("-1x");
|
|
309
|
-
expect("-x").toCollectAsTex("-1x");
|
|
310
|
-
expect("a-b").toCollectAs("a+-1b");
|
|
311
|
-
expect("a-b").toCollectAsTex("a+-1b");
|
|
312
|
-
expect("a/b").toCollectAs("ab^-1");
|
|
313
|
-
expect("a/b").toCollectAsTex("ab^{-1}");
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
test("collect over an equation", () => {
|
|
317
|
-
// collect does not try to collect across both sides of an equation
|
|
318
|
-
expect("y+1-1=x*x").toCollectAs("y=x^(2)");
|
|
319
|
-
expect("1+y=1+x^2").toCollectAs("1+y=1+x^(2)");
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
test("simplify", () => {
|
|
323
|
-
expect("(a+b)^2").toSimplifyAs("(a+b)^2");
|
|
324
|
-
expect("(a+b)(a+b)").toSimplifyAs("(a+b)^2");
|
|
325
|
-
|
|
326
|
-
// (ab)^2 ->[factor]-> a^2 * b^2 ->[collect]-> a^2 * b^2
|
|
327
|
-
// (no change during collect, therefore factoring is rolled back)
|
|
328
|
-
expect("(ab)^2").toSimplifyAs("(ab)^2");
|
|
329
|
-
|
|
330
|
-
// (3x)^2 ->[factor]-> 3^2 * x^2 ->[collect]-> 9x^2
|
|
331
|
-
// (changed during collect, therefore factoring persists)
|
|
332
|
-
expect("(3x)^2").toSimplifyAs("9x^2");
|
|
333
|
-
|
|
334
|
-
expect("(2sqrt(2))^4").toSimplifyAs("64");
|
|
335
|
-
expect("(3sqrt[3]{3})^9").toSimplifyAs("531441");
|
|
336
|
-
|
|
337
|
-
// from "Simplifying expressions with exponents"
|
|
338
|
-
expect("((nx^5)^5)").toSimplifyAs("n^5 x^25");
|
|
339
|
-
expect("((nx^5)^5)/2").toSimplifyAs("1/2 n^5 x^25");
|
|
340
|
-
expect("((nx^5)^5)/(n^-2x^2)^-3").toSimplifyAs("n^-1 x^31");
|
|
341
|
-
|
|
342
|
-
expect("1/(xya)+1/(xyb)").toSimplifyAs("1/(xya)+1/(xyb)");
|
|
343
|
-
|
|
344
|
-
// Simplify rationals correctly
|
|
345
|
-
expect("2*(x+1/3)").toSimplifyAs("2*x+2/3");
|
|
346
|
-
expect("-1*(1/3+x)").toSimplifyAs("-1*x+-1/3");
|
|
347
|
-
});
|
|
348
|
-
});
|