pimath 0.2.13 → 0.2.15
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/pimath.js +856 -1882
- package/dist/pimath.js.map +1 -1
- package/package.json +2 -2
- package/src/algebra/equation.ts +562 -558
- package/src/algebra/equationSolver.ts +489 -489
- package/src/algebra/factor.ts +396 -392
- package/src/algebra/linearSystem.ts +446 -442
- package/src/algebra/matrix.ts +515 -511
- package/src/algebra/monom.ts +932 -928
- package/src/algebra/polyFactor.ts +724 -720
- package/src/algebra/polynom.ts +1233 -1229
- package/src/coefficients/fraction.ts +907 -748
- package/src/coefficients/root.ts +500 -359
- package/src/geometry/TupleN.ts +129 -129
- package/src/geometry/circle.ts +455 -455
- package/src/geometry/line.ts +658 -654
- package/src/geometry/point.ts +105 -105
- package/src/geometry/sphere3.ts +2 -2
- package/src/geometry/triangle.ts +488 -488
- package/src/geometry/vector.ts +230 -226
- package/src/numeric.ts +136 -51
- package/src/pimath.interface.ts +2 -0
- package/types/algebra/equation.d.ts +1 -0
- package/types/algebra/equation.d.ts.map +1 -1
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/factor.d.ts +1 -0
- package/types/algebra/factor.d.ts.map +1 -1
- package/types/algebra/linearSystem.d.ts +1 -0
- package/types/algebra/linearSystem.d.ts.map +1 -1
- package/types/algebra/matrix.d.ts +6 -5
- package/types/algebra/matrix.d.ts.map +1 -1
- package/types/algebra/monom.d.ts +1 -0
- package/types/algebra/monom.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +1 -0
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/algebra/polynom.d.ts +1 -0
- package/types/algebra/polynom.d.ts.map +1 -1
- package/types/coefficients/fraction.d.ts +62 -53
- package/types/coefficients/fraction.d.ts.map +1 -1
- package/types/coefficients/root.d.ts +3 -0
- package/types/coefficients/root.d.ts.map +1 -1
- package/types/geometry/TupleN.d.ts +1 -1
- package/types/geometry/TupleN.d.ts.map +1 -1
- package/types/geometry/circle.d.ts.map +1 -1
- package/types/geometry/line.d.ts +1 -0
- package/types/geometry/line.d.ts.map +1 -1
- package/types/geometry/point.d.ts.map +1 -1
- package/types/geometry/sphere3.d.ts +2 -2
- package/types/geometry/sphere3.d.ts.map +1 -1
- package/types/geometry/triangle.d.ts.map +1 -1
- package/types/geometry/vector.d.ts +1 -0
- package/types/geometry/vector.d.ts.map +1 -1
- package/types/index.d.ts +3 -3
- package/types/numeric.d.ts +4 -4
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +1 -0
- package/types/pimath.interface.d.ts.map +1 -1
- package/types/primes.data.d.ts +2 -0
- package/types/primes.data.d.ts.map +1 -0
package/src/algebra/equation.ts
CHANGED
|
@@ -1,558 +1,562 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
EQUATION_SIGN,
|
|
3
|
-
IAlgebra,
|
|
4
|
-
IEquation,
|
|
5
|
-
InputAlgebra,
|
|
6
|
-
InputValue,
|
|
7
|
-
IPiMathObject,
|
|
8
|
-
literalType
|
|
9
|
-
} from "../pimath.interface"
|
|
10
|
-
import {Fraction} from "../coefficients"
|
|
11
|
-
import {Numeric} from "../numeric"
|
|
12
|
-
import {ParseError} from "../errors"
|
|
13
|
-
import {EquationSolver} from "./equationSolver"
|
|
14
|
-
import {Monom} from "./monom"
|
|
15
|
-
import {Polynom} from "./polynom"
|
|
16
|
-
import type {Solution} from "../analyze"
|
|
17
|
-
|
|
18
|
-
export class Equation implements IPiMathObject<Equation>,
|
|
19
|
-
IEquation<Equation>,
|
|
20
|
-
IAlgebra<Equation> {
|
|
21
|
-
|
|
22
|
-
// Left part of the equation
|
|
23
|
-
#left: Polynom
|
|
24
|
-
// Right part of the equation
|
|
25
|
-
#right: Polynom
|
|
26
|
-
// Signe of the equation
|
|
27
|
-
#sign: EQUATION_SIGN
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
constructor(equation: InputAlgebra<Polynom> | Equation)
|
|
31
|
-
constructor(left: InputAlgebra<Polynom>, right: InputAlgebra<Polynom>, sign?: EQUATION_SIGN)
|
|
32
|
-
constructor(left?: InputAlgebra<Polynom> | Equation, right?: InputAlgebra<Polynom>, sign?: EQUATION_SIGN) {
|
|
33
|
-
// Default equation
|
|
34
|
-
this.#left = new Polynom().zero()
|
|
35
|
-
this.#right = new Polynom().zero()
|
|
36
|
-
this.#sign = '='
|
|
37
|
-
|
|
38
|
-
// Only one value, it's an equation
|
|
39
|
-
if (left !== undefined && right === undefined) {
|
|
40
|
-
if (left instanceof Equation) {
|
|
41
|
-
return left.clone()
|
|
42
|
-
} else if (typeof left === 'string') {
|
|
43
|
-
// Parse the equation as a string.
|
|
44
|
-
this.parse(left)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
} else if (left !== undefined && right !== undefined) {
|
|
48
|
-
// Two values, it's an equation with left and right polynoms.
|
|
49
|
-
this.left = new Polynom(left as InputAlgebra<Polynom>)
|
|
50
|
-
this.right = new Polynom(right)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (sign !== undefined) {
|
|
54
|
-
this.sign = sign
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return this
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ------------------------------------------
|
|
61
|
-
|
|
62
|
-
// Find the string separator
|
|
63
|
-
const strSign: string | false = this.#findSign(equationString)
|
|
64
|
-
|
|
65
|
-
if (strSign === false) {
|
|
66
|
-
throw new ParseError('The equation is not valid (no sign found)')
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// The StrSign is found
|
|
70
|
-
const pStr: string[] = equationString.split(strSign)
|
|
71
|
-
|
|
72
|
-
return this.create(new Polynom(pStr[0]), new Polynom(pStr[1]), this.#formatSign(strSign))
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return `${this.#left.
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
this
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
this.#left
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return this
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
this
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
//
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return this
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
this.#right
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
if (this.#sign === '
|
|
437
|
-
return '\\
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
return
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
return
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
return
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
return '
|
|
497
|
-
} else if (equationString.includes('
|
|
498
|
-
return '
|
|
499
|
-
} else if (equationString.includes('
|
|
500
|
-
return '
|
|
501
|
-
} else if (equationString.includes('
|
|
502
|
-
return '
|
|
503
|
-
} else if (equationString.includes('
|
|
504
|
-
return '
|
|
505
|
-
} else if (equationString.includes('
|
|
506
|
-
return '
|
|
507
|
-
} else if (equationString.includes('
|
|
508
|
-
return '
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (signStr
|
|
522
|
-
return '
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
return '>='
|
|
527
|
-
} else if (signStr.includes('
|
|
528
|
-
return '
|
|
529
|
-
} else if (signStr.includes('
|
|
530
|
-
return '
|
|
531
|
-
} else if (signStr.includes('
|
|
532
|
-
return '
|
|
533
|
-
} else if (signStr.includes('
|
|
534
|
-
return '<='
|
|
535
|
-
} else if (signStr.includes('
|
|
536
|
-
return '
|
|
537
|
-
} else {
|
|
538
|
-
return '
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if (this.#sign
|
|
548
|
-
this
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
if (this.#sign.includes('
|
|
552
|
-
this.#sign.replace('
|
|
553
|
-
return this
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
1
|
+
import type {
|
|
2
|
+
EQUATION_SIGN,
|
|
3
|
+
IAlgebra,
|
|
4
|
+
IEquation,
|
|
5
|
+
InputAlgebra,
|
|
6
|
+
InputValue,
|
|
7
|
+
IPiMathObject,
|
|
8
|
+
literalType
|
|
9
|
+
} from "../pimath.interface"
|
|
10
|
+
import {Fraction} from "../coefficients"
|
|
11
|
+
import {Numeric} from "../numeric"
|
|
12
|
+
import {NotImplementedError, ParseError} from "../errors"
|
|
13
|
+
import {EquationSolver} from "./equationSolver"
|
|
14
|
+
import {Monom} from "./monom"
|
|
15
|
+
import {Polynom} from "./polynom"
|
|
16
|
+
import type {Solution} from "../analyze"
|
|
17
|
+
|
|
18
|
+
export class Equation implements IPiMathObject<Equation>,
|
|
19
|
+
IEquation<Equation>,
|
|
20
|
+
IAlgebra<Equation> {
|
|
21
|
+
|
|
22
|
+
// Left part of the equation
|
|
23
|
+
#left: Polynom
|
|
24
|
+
// Right part of the equation
|
|
25
|
+
#right: Polynom
|
|
26
|
+
// Signe of the equation
|
|
27
|
+
#sign: EQUATION_SIGN
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
constructor(equation: InputAlgebra<Polynom> | Equation)
|
|
31
|
+
constructor(left: InputAlgebra<Polynom>, right: InputAlgebra<Polynom>, sign?: EQUATION_SIGN)
|
|
32
|
+
constructor(left?: InputAlgebra<Polynom> | Equation, right?: InputAlgebra<Polynom>, sign?: EQUATION_SIGN) {
|
|
33
|
+
// Default equation
|
|
34
|
+
this.#left = new Polynom().zero()
|
|
35
|
+
this.#right = new Polynom().zero()
|
|
36
|
+
this.#sign = '='
|
|
37
|
+
|
|
38
|
+
// Only one value, it's an equation
|
|
39
|
+
if (left !== undefined && right === undefined) {
|
|
40
|
+
if (left instanceof Equation) {
|
|
41
|
+
return left.clone()
|
|
42
|
+
} else if (typeof left === 'string') {
|
|
43
|
+
// Parse the equation as a string.
|
|
44
|
+
this.parse(left)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
} else if (left !== undefined && right !== undefined) {
|
|
48
|
+
// Two values, it's an equation with left and right polynoms.
|
|
49
|
+
this.left = new Polynom(left as InputAlgebra<Polynom>)
|
|
50
|
+
this.right = new Polynom(right)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (sign !== undefined) {
|
|
54
|
+
this.sign = sign
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return this
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ------------------------------------------
|
|
61
|
+
parse = (equationString: string): this => {
|
|
62
|
+
// Find the string separator
|
|
63
|
+
const strSign: string | false = this.#findSign(equationString)
|
|
64
|
+
|
|
65
|
+
if (strSign === false) {
|
|
66
|
+
throw new ParseError('The equation is not valid (no sign found)')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The StrSign is found
|
|
70
|
+
const pStr: string[] = equationString.split(strSign)
|
|
71
|
+
|
|
72
|
+
return this.create(new Polynom(pStr[0]), new Polynom(pStr[1]), this.#formatSign(strSign))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
copy(): this {
|
|
76
|
+
throw new NotImplementedError("copy() is not yet implemented for Equation")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
clone = (): Equation => {
|
|
80
|
+
return new Equation(this.#left.clone(), this.#right.clone(), this.#sign)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get tex(): string {
|
|
84
|
+
return `${this.#left.tex}${this.signAsTex}${this.#right.tex}`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get display(): string {
|
|
88
|
+
return `${this.#left.display}${this.signAsTex}${this.#right.display}`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static isEquationString(equationString: string): boolean {
|
|
92
|
+
// The equation sign can be one of the following:
|
|
93
|
+
// =, <, >, <=, >=
|
|
94
|
+
|
|
95
|
+
return equationString.includes('=') ||
|
|
96
|
+
equationString.includes('<') ||
|
|
97
|
+
equationString.includes('>') ||
|
|
98
|
+
equationString.includes('<=') ||
|
|
99
|
+
equationString.includes('>=')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static makeSolutionsUnique(solutions: Solution[], sorted?: boolean): Solution[] {
|
|
103
|
+
const solutionAsTex: string[] = []
|
|
104
|
+
const uniqueSolutions = solutions.filter(sol => {
|
|
105
|
+
if (!solutionAsTex.includes(sol.tex)) {
|
|
106
|
+
solutionAsTex.push(sol.tex)
|
|
107
|
+
return true
|
|
108
|
+
} else {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
if (sorted === true) {
|
|
114
|
+
uniqueSolutions.sort((a, b) => a.value - b.value)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return uniqueSolutions
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Add a value to the equation
|
|
122
|
+
* if value is an equation, add the left part to the left part of the equation
|
|
123
|
+
* and the right part to the right part of the equation
|
|
124
|
+
* if value is a string, try to create an equation
|
|
125
|
+
* if it fails, create a polynom and add it to the left and right part of the equation
|
|
126
|
+
* @param value | Polynom | Monom | Fraction | string | monom
|
|
127
|
+
*/
|
|
128
|
+
add(value: InputValue<Equation | Polynom>): this {
|
|
129
|
+
|
|
130
|
+
if (value instanceof Equation) {
|
|
131
|
+
// add the left part of the equation
|
|
132
|
+
this.#left.add(value.left)
|
|
133
|
+
// add the right part of the equation
|
|
134
|
+
this.#right.add(value.right)
|
|
135
|
+
|
|
136
|
+
return this
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (typeof value === 'string' &&
|
|
140
|
+
!Equation.isEquationString(value)) {
|
|
141
|
+
|
|
142
|
+
return this.add(new Equation(value))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const p = new Polynom(value)
|
|
146
|
+
this.#left.add(p)
|
|
147
|
+
this.#right.add(p)
|
|
148
|
+
|
|
149
|
+
return this
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
create = (left: Polynom, right: Polynom, sign?: string): this => {
|
|
153
|
+
this.#left = left
|
|
154
|
+
this.#right = right
|
|
155
|
+
this.#sign = this.#formatSign(sign ?? "=")
|
|
156
|
+
return this
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get the degree of the equation
|
|
161
|
+
* @param letter
|
|
162
|
+
*/
|
|
163
|
+
degree = (letter?: string): Fraction => {
|
|
164
|
+
return Fraction.max(this.#left.degree(letter), this.#right.degree(letter))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* divide an equation by a given value (transformed as a fraction)
|
|
169
|
+
*
|
|
170
|
+
* ```
|
|
171
|
+
* 8x+10=6x \vert 2
|
|
172
|
+
* 4x+5=3x
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* |>Alternatively with $3x-4$ maybe it's working ?
|
|
176
|
+
* $$\frac{3x}{5}$$
|
|
177
|
+
*
|
|
178
|
+
* @param value
|
|
179
|
+
* @returns {Equation}
|
|
180
|
+
*/
|
|
181
|
+
divide = (value: InputValue<Fraction>): this => {
|
|
182
|
+
// Make sure we have a fraction.
|
|
183
|
+
const F: Fraction = new Fraction(value)
|
|
184
|
+
|
|
185
|
+
if (F.isZero()) {
|
|
186
|
+
return this
|
|
187
|
+
} else {
|
|
188
|
+
return this.multiply(F.inverse())
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Create an Equation using two polynoms.
|
|
194
|
+
* Markdown *support* is cool
|
|
195
|
+
* @param values
|
|
196
|
+
* @param asNumeric
|
|
197
|
+
*/
|
|
198
|
+
evaluate(values: InputValue<Fraction> | literalType<number | Fraction>, asNumeric: boolean): boolean {
|
|
199
|
+
// Evaluate the left and right part of the equation.
|
|
200
|
+
// compare the results.
|
|
201
|
+
|
|
202
|
+
// Evaluate the left and right part of the equation.
|
|
203
|
+
const left = this.#left.evaluate(values, asNumeric)
|
|
204
|
+
const right = this.#right.evaluate(values, asNumeric)
|
|
205
|
+
|
|
206
|
+
// compare the results.
|
|
207
|
+
if (asNumeric) {
|
|
208
|
+
return left === right
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return (left as Fraction).isEqual(right as Fraction)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// -----------------------------------------------
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Determine if the equation contains a variable.
|
|
218
|
+
* @param letter
|
|
219
|
+
*/
|
|
220
|
+
hasVariable = (letter: string): boolean => {
|
|
221
|
+
return this.variables.includes(letter)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
isEqual(value: InputValue<Equation>): boolean {
|
|
225
|
+
const equ = new Equation(value)
|
|
226
|
+
return equ.left.isEqual(this.#left) && equ.right.isEqual(this.#right)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// -----------------------------------------------
|
|
230
|
+
// Equations operations
|
|
231
|
+
|
|
232
|
+
// Equations helpers
|
|
233
|
+
isEqualTo = (equ: Equation): boolean => {
|
|
234
|
+
const p1 = equ.clone().moveLeft().left
|
|
235
|
+
const p2 = this.clone().moveLeft().left
|
|
236
|
+
|
|
237
|
+
// They are the same.
|
|
238
|
+
return p1.isEqual(p2) || p1.isOppositeAt(p2)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
isLinearTo = (equ: Equation): boolean => {
|
|
242
|
+
// Move all left.
|
|
243
|
+
const p1 = equ.clone().moveLeft().simplify().left
|
|
244
|
+
const p2 = this.clone().moveLeft().simplify().left
|
|
245
|
+
|
|
246
|
+
// They are the same.
|
|
247
|
+
return p1.isEqual(p2) || p1.isOppositeAt(p2)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Determine if the equation contains more than one letter/variable.
|
|
252
|
+
*/
|
|
253
|
+
isMultiVariable = (): boolean => {
|
|
254
|
+
return this.#left.isMultiVariable || this.#right.isMultiVariable
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Reorder the polynom to have only one letter on the left, the rest on the right.
|
|
259
|
+
* @param letter
|
|
260
|
+
*/
|
|
261
|
+
isolate = (letter?: string): this | false => {
|
|
262
|
+
// Determine if we can isolate the variables.
|
|
263
|
+
|
|
264
|
+
// Both part of the equations must be of the first degree.
|
|
265
|
+
if (!this.degree(letter).isOne()) {
|
|
266
|
+
return false
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Modify the equation to isolate the asked variable.
|
|
270
|
+
if (this.isMultiVariable()) {
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Isolate the letter.
|
|
275
|
+
let mMove: Monom
|
|
276
|
+
// Start by moving everything to the left.
|
|
277
|
+
this.#left.subtract(this.#right)
|
|
278
|
+
this.#right.zero()
|
|
279
|
+
const values = [...this.#left.monoms]
|
|
280
|
+
for (const m of values) {
|
|
281
|
+
if (!m.hasVariable(letter)) {
|
|
282
|
+
mMove = m.clone()
|
|
283
|
+
this.#left.subtract(mMove)
|
|
284
|
+
this.#right.subtract(mMove)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// In theory, we should have only one item on the left.
|
|
289
|
+
if (this.#left.length !== 1) {
|
|
290
|
+
return false
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const cMove: Fraction = this.#left.monoms[0].coefficient.clone()
|
|
294
|
+
this.#left.divide(cMove)
|
|
295
|
+
this.#right.divide(cMove)
|
|
296
|
+
return this
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Getter and setter
|
|
300
|
+
get left(): Polynom {
|
|
301
|
+
return this.#left
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
set left(value: Polynom) {
|
|
305
|
+
this.#left = value
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// -----------------------------------------------
|
|
309
|
+
letters = (): string[] => {
|
|
310
|
+
return [...new Set([...this.#left.variables, ...this.#right.variables])]
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// -----------------------------------------------
|
|
314
|
+
/**
|
|
315
|
+
* Reorder will move all monoms containing a letter on the left, all the other on the right.
|
|
316
|
+
*/
|
|
317
|
+
moveLeft = (): this => {
|
|
318
|
+
this.#left.subtract(this.#right)
|
|
319
|
+
this.#right.zero()
|
|
320
|
+
return this
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Multiple an equation by a fraction value.
|
|
325
|
+
* @param value
|
|
326
|
+
*/
|
|
327
|
+
multiply = (value: InputValue<Fraction>): this => {
|
|
328
|
+
// Make sure we have a fraction.
|
|
329
|
+
const F: Fraction = new Fraction(value)
|
|
330
|
+
|
|
331
|
+
// Multiply each part of the equation by the fraction
|
|
332
|
+
this.#left.multiply(F)
|
|
333
|
+
this.#right.multiply(F)
|
|
334
|
+
|
|
335
|
+
// The sign of the inequality must be changed.
|
|
336
|
+
if (this.#sign !== '=' && F.sign() === -1) {
|
|
337
|
+
this.#reverseSign()
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return this
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
get numberOfVars(): number {
|
|
344
|
+
return this.variables.length
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
opposite = (): this => {
|
|
348
|
+
this.#left = this.#left.opposite()
|
|
349
|
+
this.#right = this.#right.opposite()
|
|
350
|
+
return this
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
pow(value: number): this {
|
|
354
|
+
this.#left.pow(value)
|
|
355
|
+
this.#right.pow(value)
|
|
356
|
+
return this
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
reduce(): this {
|
|
360
|
+
// reduce means moving everything to the left
|
|
361
|
+
// remove the fractions
|
|
362
|
+
// simplify the equation
|
|
363
|
+
// reorder the equation
|
|
364
|
+
// start with a positive left part
|
|
365
|
+
|
|
366
|
+
// Move all left. The right part is now zero.
|
|
367
|
+
this.moveLeft()
|
|
368
|
+
|
|
369
|
+
// Reduce the equation: simplify and reorder.
|
|
370
|
+
this.#left.reduce()
|
|
371
|
+
|
|
372
|
+
// Simplify the equation.
|
|
373
|
+
this.simplify()
|
|
374
|
+
|
|
375
|
+
// Make sure the first part is positive.
|
|
376
|
+
if (this.#left.monoms[0].coefficient.isNegative()) {
|
|
377
|
+
this.multiply(-1)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return this
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
reorder = (allLeft?: boolean): this => {
|
|
384
|
+
// Move all monoms of degree greater than 0 to the left.
|
|
385
|
+
// and all zero degree monoms to the right.
|
|
386
|
+
this.#left.subtract(this.#right)
|
|
387
|
+
this.#right.zero()
|
|
388
|
+
this.#left.reorder()
|
|
389
|
+
|
|
390
|
+
// we have all left (so equal zero) : it's done !
|
|
391
|
+
if (allLeft) {
|
|
392
|
+
return this
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Fetch all zero degree monoms.
|
|
396
|
+
this.#left.monoms
|
|
397
|
+
.filter(m => m.degree().isZero())
|
|
398
|
+
.forEach(m => {
|
|
399
|
+
const move = m.clone()
|
|
400
|
+
this.#left.subtract(move)
|
|
401
|
+
this.#right.subtract(move)
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
// Reorder the left and right polynoms
|
|
405
|
+
this.#left.reorder()
|
|
406
|
+
this.#right.reorder()
|
|
407
|
+
return this
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ------------------------------------------
|
|
411
|
+
replaceBy = (letter: string, P: Polynom): this => {
|
|
412
|
+
this.#left.replaceBy(letter, P)
|
|
413
|
+
this.#right.replaceBy(letter, P)
|
|
414
|
+
return this
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
get right(): Polynom {
|
|
418
|
+
return this.#right
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
set right(value: Polynom) {
|
|
422
|
+
this.#right = value
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// ------------------------------------------
|
|
426
|
+
get sign(): string {
|
|
427
|
+
return this.#sign
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
set sign(value: string) {
|
|
431
|
+
// Set the sign value as formatted.
|
|
432
|
+
this.#sign = this.#formatSign(value)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
get signAsTex(): string {
|
|
436
|
+
if (this.#sign === '>=') {
|
|
437
|
+
return '\\geq'
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (this.#sign === '<=') {
|
|
441
|
+
return '\\leq'
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return this.#sign
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Multiply by the lcm denominator and divide by the gcm numerators.
|
|
449
|
+
*/
|
|
450
|
+
simplify = (): this => {
|
|
451
|
+
this.multiply(Numeric.lcm(...this.#left.getDenominators(), ...this.#right.getDenominators()))
|
|
452
|
+
this.divide(Numeric.gcd(...this.#left.getNumerators(), ...this.#right.getNumerators()))
|
|
453
|
+
return this
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// -----------------------------------------------
|
|
457
|
+
solve = (): Solution[] => {
|
|
458
|
+
const solver = new EquationSolver(this.clone())
|
|
459
|
+
return solver.solve()
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
split(): [Polynom, Polynom] {
|
|
463
|
+
return [this.#left.clone(), this.#right.clone()]
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
subtract(value: InputValue<Equation | Polynom>): this {
|
|
467
|
+
if (value instanceof Equation) {
|
|
468
|
+
this.#left.subtract(value.left)
|
|
469
|
+
this.#right.subtract(value.right)
|
|
470
|
+
|
|
471
|
+
return this
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (typeof value === 'string' &&
|
|
475
|
+
!Equation.isEquationString(value)) {
|
|
476
|
+
return this.subtract(new Equation(value))
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const p = new Polynom(value)
|
|
480
|
+
this.#left.subtract(p)
|
|
481
|
+
this.#right.subtract(p)
|
|
482
|
+
|
|
483
|
+
return this
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
test = (values: literalType<Fraction>): boolean => {
|
|
487
|
+
return (this.left.evaluate(values)).isEqual(this.right.evaluate(values))
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
get variables(): string[] {
|
|
491
|
+
return [...new Set(this.#right.variables.concat(this.#left.variables))]
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
#findSign = (equationString: string): string | false => {
|
|
495
|
+
if (equationString.includes('geq')) {
|
|
496
|
+
return (equationString.includes('\\geq')) ? '\\geq' : 'geq'
|
|
497
|
+
} else if (equationString.includes('leq')) {
|
|
498
|
+
return (equationString.includes('\\leq')) ? '\\leq' : 'leq'
|
|
499
|
+
} else if (equationString.includes('>=')) {
|
|
500
|
+
return '>='
|
|
501
|
+
} else if (equationString.includes('=>')) {
|
|
502
|
+
return '=>'
|
|
503
|
+
} else if (equationString.includes('>')) {
|
|
504
|
+
return '>'
|
|
505
|
+
} else if (equationString.includes('<=')) {
|
|
506
|
+
return '<='
|
|
507
|
+
} else if (equationString.includes('=<')) {
|
|
508
|
+
return '=<'
|
|
509
|
+
} else if (equationString.includes('<')) {
|
|
510
|
+
return '<'
|
|
511
|
+
} else if (equationString.includes('=')) {
|
|
512
|
+
return '='
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
throw new ParseError('The equation is not valid (no sign found)')
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// -----------------------------------------------
|
|
519
|
+
// Equations solving algorithms
|
|
520
|
+
#formatSign = (signStr?: string): EQUATION_SIGN => {
|
|
521
|
+
if (signStr === undefined) {
|
|
522
|
+
return '='
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (signStr.includes('geq')) {
|
|
526
|
+
return '>='
|
|
527
|
+
} else if (signStr.includes('>=')) {
|
|
528
|
+
return '>='
|
|
529
|
+
} else if (signStr.includes('=>')) {
|
|
530
|
+
return '>='
|
|
531
|
+
} else if (signStr.includes('>')) {
|
|
532
|
+
return '>'
|
|
533
|
+
} else if (signStr.includes('leq')) {
|
|
534
|
+
return '<='
|
|
535
|
+
} else if (signStr.includes('<=')) {
|
|
536
|
+
return '<='
|
|
537
|
+
} else if (signStr.includes('=<')) {
|
|
538
|
+
return '<='
|
|
539
|
+
} else if (signStr.includes('<')) {
|
|
540
|
+
return '<'
|
|
541
|
+
} else {
|
|
542
|
+
return '='
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
#reverseSign = (): this => {
|
|
547
|
+
if (this.#sign === '=') {
|
|
548
|
+
return this
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (this.#sign.includes('<')) {
|
|
552
|
+
this.#sign.replace('<', '>')
|
|
553
|
+
return this
|
|
554
|
+
}
|
|
555
|
+
if (this.#sign.includes('>')) {
|
|
556
|
+
this.#sign.replace('>', '<')
|
|
557
|
+
return this
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return this
|
|
561
|
+
}
|
|
562
|
+
}
|