pimath 0.2.14 → 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 +850 -1879
- package/dist/pimath.js.map +1 -1
- package/package.json +1 -1
- 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/polynom.ts
CHANGED
|
@@ -1,1229 +1,1233 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Polynom module contains everything necessary to handle polynoms.*
|
|
3
|
-
*/
|
|
4
|
-
import {ShutingYard, ShutingyardType, type Token} from "piexpression"
|
|
5
|
-
import {InvalidArgumentError, MathError, ParseError} from "../errors"
|
|
6
|
-
import type {
|
|
7
|
-
IAlgebra,
|
|
8
|
-
IAnalyse,
|
|
9
|
-
IExpression,
|
|
10
|
-
InputAlgebra,
|
|
11
|
-
InputValue,
|
|
12
|
-
IPiMathObject,
|
|
13
|
-
literalType,
|
|
14
|
-
TABLE_OF_SIGNS,
|
|
15
|
-
TABLE_OF_SIGNS_VALUES
|
|
16
|
-
} from "../pimath.interface"
|
|
17
|
-
import {Fraction} from "../coefficients"
|
|
18
|
-
import {Numeric} from '../numeric'
|
|
19
|
-
import {EquationSolver} from './equationSolver'
|
|
20
|
-
import {Monom} from './monom'
|
|
21
|
-
import {replace_in_array} from "../helpers"
|
|
22
|
-
import {operation_pow} from "./operations"
|
|
23
|
-
import {Solution} from "../analyze/solution"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export type PolynomParsingType = InputValue<Polynom> | Monom
|
|
27
|
-
|
|
28
|
-
export interface IEuclidean {
|
|
29
|
-
quotient: Polynom,
|
|
30
|
-
reminder: Polynom
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Polynom class can handle polynoms, reorder, resolve, ...
|
|
35
|
-
* ```
|
|
36
|
-
* let P = new Polynom('3x-4')
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export class Polynom implements IPiMathObject<Polynom>,
|
|
40
|
-
IExpression<Polynom>,
|
|
41
|
-
IAnalyse<Polynom>,
|
|
42
|
-
IAlgebra<Polynom> {
|
|
43
|
-
|
|
44
|
-
#defaultVariable = 'x'
|
|
45
|
-
#factors: Polynom[]
|
|
46
|
-
#monoms: Monom[]
|
|
47
|
-
#roots: Solution[]
|
|
48
|
-
#rootsCache = false
|
|
49
|
-
|
|
50
|
-
constructor(value: InputValue<Fraction>)
|
|
51
|
-
constructor(value: string)
|
|
52
|
-
constructor(value: Monom)
|
|
53
|
-
constructor(value: Polynom)
|
|
54
|
-
constructor(...values: InputValue<Fraction>[])
|
|
55
|
-
constructor(...values: InputAlgebra<Polynom>[])
|
|
56
|
-
constructor(polynomString?: InputAlgebra<Polynom>, ...values: InputAlgebra<Fraction>[]) {
|
|
57
|
-
this.#monoms = []
|
|
58
|
-
this.#factors = []
|
|
59
|
-
this.#roots = []
|
|
60
|
-
|
|
61
|
-
if (polynomString !== undefined) {
|
|
62
|
-
this.parse(polynomString, ...values)
|
|
63
|
-
}
|
|
64
|
-
return this
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Parse a string to a polynom.
|
|
70
|
-
* @param inputStr
|
|
71
|
-
* @param values
|
|
72
|
-
*/
|
|
73
|
-
|
|
74
|
-
// Reset the main variables.
|
|
75
|
-
this.#monoms = []
|
|
76
|
-
this.#factors = []
|
|
77
|
-
this.#invalidateCache()
|
|
78
|
-
|
|
79
|
-
if (typeof inputStr === 'string') {
|
|
80
|
-
return this.#parseString(inputStr, ...values as InputValue<Fraction>[])
|
|
81
|
-
} else if (
|
|
82
|
-
(typeof inputStr === 'number' || inputStr instanceof Fraction || inputStr instanceof Monom)
|
|
83
|
-
&& (values.length === 0)
|
|
84
|
-
) {
|
|
85
|
-
this.#monoms.push(new Monom(inputStr as Monom))
|
|
86
|
-
} else if (inputStr instanceof Monom && values.length > 0) {
|
|
87
|
-
this.#monoms.push(new Monom(inputStr))
|
|
88
|
-
values.forEach(m => {
|
|
89
|
-
this.#monoms.push(new Monom(m as Monom))
|
|
90
|
-
})
|
|
91
|
-
} else if (inputStr instanceof Polynom) {
|
|
92
|
-
for (const m of inputStr.monoms) {
|
|
93
|
-
this.#monoms.push(m.clone())
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return this
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Clone the polynom
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return this.#genDisplay()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
this.#monoms.
|
|
145
|
-
} else {
|
|
146
|
-
this.#monoms.push(
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
M
|
|
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
|
-
return this
|
|
201
|
-
} else if (value
|
|
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
|
-
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
return
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return Numeric.gcd(...this.
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
return this.
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
//
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
return this.#monoms.
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
return this.#
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
return this.#compare(P, '
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
return
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
return
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
return Numeric.lcm(...this.
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
return this
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (
|
|
562
|
-
return
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
this.#monoms
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
if (value instanceof
|
|
646
|
-
return this.#
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (value instanceof
|
|
650
|
-
return this.#
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (
|
|
654
|
-
return this.#
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
if (typeof value === '
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
this
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
return this
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
return
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
this
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
this.#rootsCache
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
this.#
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
this
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
//
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
//
|
|
873
|
-
const [a] = this.getCoefficients().map(x => x.value)
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
return
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
return this
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
return
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
this.#
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
this.#
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
return this
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
#
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
case ShutingyardType.
|
|
1121
|
-
stack.push(new Polynom(
|
|
1122
|
-
break
|
|
1123
|
-
|
|
1124
|
-
case ShutingyardType.
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
if (
|
|
1138
|
-
stack
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
stack.push(a.
|
|
1143
|
-
} else if (element.token === '
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
{
|
|
1156
|
-
|
|
1157
|
-
} else
|
|
1158
|
-
//
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
case ShutingyardType.
|
|
1188
|
-
// Should never appear.
|
|
1189
|
-
throw new ParseError(
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Polynom module contains everything necessary to handle polynoms.*
|
|
3
|
+
*/
|
|
4
|
+
import {ShutingYard, ShutingyardType, type Token} from "piexpression"
|
|
5
|
+
import {InvalidArgumentError, MathError, NotImplementedError, ParseError} from "../errors"
|
|
6
|
+
import type {
|
|
7
|
+
IAlgebra,
|
|
8
|
+
IAnalyse,
|
|
9
|
+
IExpression,
|
|
10
|
+
InputAlgebra,
|
|
11
|
+
InputValue,
|
|
12
|
+
IPiMathObject,
|
|
13
|
+
literalType,
|
|
14
|
+
TABLE_OF_SIGNS,
|
|
15
|
+
TABLE_OF_SIGNS_VALUES
|
|
16
|
+
} from "../pimath.interface"
|
|
17
|
+
import {Fraction} from "../coefficients"
|
|
18
|
+
import {Numeric} from '../numeric'
|
|
19
|
+
import {EquationSolver} from './equationSolver'
|
|
20
|
+
import {Monom} from './monom'
|
|
21
|
+
import {replace_in_array} from "../helpers"
|
|
22
|
+
import {operation_pow} from "./operations"
|
|
23
|
+
import {Solution} from "../analyze/solution"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export type PolynomParsingType = InputValue<Polynom> | Monom
|
|
27
|
+
|
|
28
|
+
export interface IEuclidean {
|
|
29
|
+
quotient: Polynom,
|
|
30
|
+
reminder: Polynom
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Polynom class can handle polynoms, reorder, resolve, ...
|
|
35
|
+
* ```
|
|
36
|
+
* let P = new Polynom('3x-4')
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class Polynom implements IPiMathObject<Polynom>,
|
|
40
|
+
IExpression<Polynom>,
|
|
41
|
+
IAnalyse<Polynom>,
|
|
42
|
+
IAlgebra<Polynom> {
|
|
43
|
+
|
|
44
|
+
#defaultVariable = 'x'
|
|
45
|
+
#factors: Polynom[]
|
|
46
|
+
#monoms: Monom[]
|
|
47
|
+
#roots: Solution[]
|
|
48
|
+
#rootsCache = false
|
|
49
|
+
|
|
50
|
+
constructor(value: InputValue<Fraction>)
|
|
51
|
+
constructor(value: string)
|
|
52
|
+
constructor(value: Monom)
|
|
53
|
+
constructor(value: Polynom)
|
|
54
|
+
constructor(...values: InputValue<Fraction>[])
|
|
55
|
+
constructor(...values: InputAlgebra<Polynom>[])
|
|
56
|
+
constructor(polynomString?: InputAlgebra<Polynom>, ...values: InputAlgebra<Fraction>[]) {
|
|
57
|
+
this.#monoms = []
|
|
58
|
+
this.#factors = []
|
|
59
|
+
this.#roots = []
|
|
60
|
+
|
|
61
|
+
if (polynomString !== undefined) {
|
|
62
|
+
this.parse(polynomString, ...values)
|
|
63
|
+
}
|
|
64
|
+
return this
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Parse a string to a polynom.
|
|
70
|
+
* @param inputStr
|
|
71
|
+
* @param values
|
|
72
|
+
*/
|
|
73
|
+
parse(inputStr: PolynomParsingType, ...values: InputAlgebra<Monom>[]): this {
|
|
74
|
+
// Reset the main variables.
|
|
75
|
+
this.#monoms = []
|
|
76
|
+
this.#factors = []
|
|
77
|
+
this.#invalidateCache()
|
|
78
|
+
|
|
79
|
+
if (typeof inputStr === 'string') {
|
|
80
|
+
return this.#parseString(inputStr, ...values as InputValue<Fraction>[])
|
|
81
|
+
} else if (
|
|
82
|
+
(typeof inputStr === 'number' || inputStr instanceof Fraction || inputStr instanceof Monom)
|
|
83
|
+
&& (values.length === 0)
|
|
84
|
+
) {
|
|
85
|
+
this.#monoms.push(new Monom(inputStr as Monom))
|
|
86
|
+
} else if (inputStr instanceof Monom && values.length > 0) {
|
|
87
|
+
this.#monoms.push(new Monom(inputStr))
|
|
88
|
+
values.forEach(m => {
|
|
89
|
+
this.#monoms.push(new Monom(m as Monom))
|
|
90
|
+
})
|
|
91
|
+
} else if (inputStr instanceof Polynom) {
|
|
92
|
+
for (const m of inputStr.monoms) {
|
|
93
|
+
this.#monoms.push(m.clone())
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
return this
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Clone the polynom
|
|
103
|
+
*/
|
|
104
|
+
copy(): this {
|
|
105
|
+
throw new NotImplementedError("copy() is not yet implemented for Polynom")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
clone(): Polynom {
|
|
109
|
+
const P = new Polynom()
|
|
110
|
+
const M: Monom[] = []
|
|
111
|
+
P.#defaultVariable = this.#defaultVariable
|
|
112
|
+
|
|
113
|
+
for (const m of this.#monoms) {
|
|
114
|
+
M.push(m.clone())
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
P.monoms = M
|
|
118
|
+
|
|
119
|
+
return P
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get tex(): string {
|
|
123
|
+
return this.#genDisplay('tex')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get display(): string {
|
|
127
|
+
return this.#genDisplay()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static xMultiply(...polynoms: InputValue<Polynom>[]): Polynom {
|
|
131
|
+
const result = new Polynom().one()
|
|
132
|
+
|
|
133
|
+
polynoms.forEach(P => {
|
|
134
|
+
result.multiply(P)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return result
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
add(...values: InputAlgebra<Polynom>[]): this {
|
|
141
|
+
|
|
142
|
+
for (const value of values) {
|
|
143
|
+
if (value instanceof Polynom) {
|
|
144
|
+
this.#monoms = this.#monoms.concat(value.monoms.map(m => m.clone()))
|
|
145
|
+
} else if (value instanceof Monom) {
|
|
146
|
+
this.#monoms.push(value.clone())
|
|
147
|
+
} else if (typeof value === "number" && Number.isSafeInteger(value)) {
|
|
148
|
+
this.#monoms.push(new Monom(value.toString()))
|
|
149
|
+
} else {
|
|
150
|
+
this.#monoms.push(new Monom(value))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
return this.reduce()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
commonMonom(): Monom {
|
|
159
|
+
const M = new Monom().one()
|
|
160
|
+
const numerator: number = this.gcdNumerator()
|
|
161
|
+
const denominator: number = this.gcdDenominator()
|
|
162
|
+
|
|
163
|
+
M.coefficient = new Fraction(numerator, denominator)
|
|
164
|
+
for (const L of this.variables) {
|
|
165
|
+
// Initialize the setLetter with the max degree
|
|
166
|
+
M.setLetter(L, this.degree(L))
|
|
167
|
+
for (const m of this.#monoms) {
|
|
168
|
+
M.setLetter(L, Fraction.min(m.degree(L), M.degree(L)))
|
|
169
|
+
if (M.degree(L).isZero()) {
|
|
170
|
+
break
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return M
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
degree(letter?: string): Fraction {
|
|
179
|
+
let d: Fraction = new Fraction().zero()
|
|
180
|
+
for (const m of this.#monoms) {
|
|
181
|
+
d = Fraction.max(m.degree(letter).value, d)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return d
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
derivative(letter?: string): Polynom {
|
|
188
|
+
const dP = new Polynom()
|
|
189
|
+
|
|
190
|
+
for (const m of this.#monoms) {
|
|
191
|
+
dP.add(m.derivative(letter))
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return dP.reduce()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
divide(value: InputAlgebra<Polynom>): this {
|
|
198
|
+
|
|
199
|
+
if (value instanceof Fraction) {
|
|
200
|
+
return this.#divideByFraction(value)
|
|
201
|
+
} else if (typeof value === 'number' && Number.isSafeInteger(value)) {
|
|
202
|
+
return this.#divideByInteger(value)
|
|
203
|
+
} else if (value instanceof Monom) {
|
|
204
|
+
return this.divide(new Polynom(value))
|
|
205
|
+
} else if (value instanceof Polynom) {
|
|
206
|
+
if (value.monoms.length === 1 && value.variables.length === 0) {
|
|
207
|
+
return this.#divideByFraction(value.monoms[0].coefficient)
|
|
208
|
+
} else {
|
|
209
|
+
const {quotient, reminder} = this.euclidean(value)
|
|
210
|
+
if (reminder.isZero()) {
|
|
211
|
+
this.#monoms = quotient.monoms
|
|
212
|
+
this.#invalidateCache()
|
|
213
|
+
return this
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} else if (typeof value === 'string') {
|
|
217
|
+
return this.divide(new Polynom(value))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
throw new MathError(`Cannot divide by ${value as unknown as string}`)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
empty(): this {
|
|
224
|
+
this.#monoms = []
|
|
225
|
+
this.#invalidateCache()
|
|
226
|
+
return this
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Divide the current polynom by another polynom.
|
|
231
|
+
* @param P
|
|
232
|
+
* returns {quotient: Polynom, reminder: Polynom}
|
|
233
|
+
*/
|
|
234
|
+
euclidean(P: Polynom): IEuclidean {
|
|
235
|
+
const letter: string | undefined = P.variables[0]
|
|
236
|
+
const quotient: Polynom = new Polynom().zero()
|
|
237
|
+
const reminder: Polynom = this.clone().reorder(letter)
|
|
238
|
+
|
|
239
|
+
// There is no variable - means it's a number
|
|
240
|
+
if (P.variables.length === 0) {
|
|
241
|
+
const q = this.clone().divide(P)
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
quotient: q.reduce(),
|
|
245
|
+
reminder: new Polynom().zero()
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!this.degree(letter).isNatural() || !P.degree(letter).isNatural()) {
|
|
250
|
+
throw new MathError('Euclidean division requires integer degrees')
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Get at least a letter
|
|
254
|
+
const maxMP: Monom = P.monomByDegree(undefined, letter)
|
|
255
|
+
const degreeP: Fraction = P.degree(letter)
|
|
256
|
+
|
|
257
|
+
let newM: Monom
|
|
258
|
+
|
|
259
|
+
// Make the Euclidean division of the two polynoms.
|
|
260
|
+
let MaxIteration = this.degree(letter).value - degreeP.value + 1
|
|
261
|
+
|
|
262
|
+
while (reminder.degree(letter).isGeq(degreeP) && MaxIteration > 0) {
|
|
263
|
+
MaxIteration--
|
|
264
|
+
|
|
265
|
+
// Get the greatest monom divided by the max monom of the divider
|
|
266
|
+
newM = reminder.monomByDegree(undefined, letter).clone().divide(maxMP)
|
|
267
|
+
|
|
268
|
+
if (newM.isZero()) {
|
|
269
|
+
continue
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Get the new quotient and reminder.
|
|
273
|
+
quotient.add(newM)
|
|
274
|
+
reminder.subtract(P.clone().multiply(newM)).reduce()
|
|
275
|
+
|
|
276
|
+
// Check if the reminder is zero.
|
|
277
|
+
if (newM.degree(letter).isZero()) {
|
|
278
|
+
break
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
quotient.reduce()
|
|
283
|
+
reminder.reduce()
|
|
284
|
+
return {quotient, reminder}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
evaluate(values: literalType<Fraction | number> | InputValue<Fraction>, asNumeric: true): number
|
|
288
|
+
evaluate(values: literalType<Fraction | number> | InputValue<Fraction>, asNumeric?: false): Fraction
|
|
289
|
+
evaluate(values: literalType<Fraction | number> | InputValue<Fraction>, asNumeric?: boolean): Fraction | number
|
|
290
|
+
evaluate(values: literalType<Fraction | number> | InputValue<Fraction>, asNumeric?: boolean): Fraction | number {
|
|
291
|
+
// Return the numeric value without using Fraction
|
|
292
|
+
if (asNumeric) {
|
|
293
|
+
return this.#evaluateAsNumeric(values)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Build the evaluated fraction
|
|
297
|
+
const r = new Fraction().zero()
|
|
298
|
+
this.#monoms.forEach(monom => {
|
|
299
|
+
r.add(monom.evaluate(values, asNumeric))
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
return r
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// -------------------------------------
|
|
306
|
+
/**
|
|
307
|
+
* Factorize a polynom and store the best results in factors.
|
|
308
|
+
* @param _letter
|
|
309
|
+
* TODO: Handle other letter than 'x'.
|
|
310
|
+
*/
|
|
311
|
+
factorize(_letter?: string): Polynom[] {
|
|
312
|
+
this.#factors = []
|
|
313
|
+
|
|
314
|
+
// There is only one monom - it's already considered as factor.
|
|
315
|
+
if (this.monoms.length === 1) return [this.clone()]
|
|
316
|
+
|
|
317
|
+
let P = this.clone().reorder()
|
|
318
|
+
|
|
319
|
+
// Extract the common monom
|
|
320
|
+
// 2x^3+6x^2 => 2x^2
|
|
321
|
+
const M = P.commonMonom()
|
|
322
|
+
|
|
323
|
+
// If the polynom starts with a negative monom, factorize it.
|
|
324
|
+
if (P.monomByDegree().coefficient.isStrictlyNegative()) M.opposite()
|
|
325
|
+
|
|
326
|
+
if (!M.isOne()) {
|
|
327
|
+
this.#factors.push(new Polynom(M))
|
|
328
|
+
P = P.euclidean(this.#factors[0]).quotient
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const solutions = new EquationSolver(P).solve()
|
|
332
|
+
|
|
333
|
+
if (solutions.length === 0) {
|
|
334
|
+
if (this.#factors.length === 0) {
|
|
335
|
+
// No common monom was extracted: the whole polynomial is irreducible
|
|
336
|
+
this.#factors = [this.clone()]
|
|
337
|
+
} else {
|
|
338
|
+
// Common monom was extracted: P is the irreducible remaining part
|
|
339
|
+
this.#factors.push(P)
|
|
340
|
+
}
|
|
341
|
+
return this.#factors
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
solutions.forEach(sol => {
|
|
345
|
+
if (sol.exact && sol.root.isZero()) {
|
|
346
|
+
for (let i = 0; i < sol.count; i++) {
|
|
347
|
+
if (sol.fraction.hasFractionalPart()) {
|
|
348
|
+
this.#factors.push(new Polynom().fromCoefficients(sol.fraction.denominator, -sol.fraction.numerator))
|
|
349
|
+
} else {
|
|
350
|
+
this.#factors.push(new Polynom().fromCoefficients(1, sol.fraction.clone().opposite()))
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
// Check if we have all factors.
|
|
357
|
+
const fDegrees = this.#factors
|
|
358
|
+
.map(f => f.degree().value)
|
|
359
|
+
.reduce((a, b) => a + b, 0)
|
|
360
|
+
|
|
361
|
+
if (fDegrees < this.degree().value) {
|
|
362
|
+
// missing polynom.
|
|
363
|
+
const fPolynom = Polynom.xMultiply(...this.#factors)
|
|
364
|
+
this.#factors.push(this.clone().divide(fPolynom))
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return this.#factors
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
get factors(): Polynom[] {
|
|
371
|
+
if (this.#factors.length === 0 && !this.isZero()) {
|
|
372
|
+
return this.factorize()
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return this.#factors
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
fromCoefficients(...values: InputValue<Fraction>[]): this {
|
|
379
|
+
|
|
380
|
+
this.#monoms = []
|
|
381
|
+
const letter = this.#defaultVariable ?? 'x'
|
|
382
|
+
values.reverse().forEach((coeff, index) => {
|
|
383
|
+
const monom = new Monom()
|
|
384
|
+
monom.coefficient = new Fraction(coeff)
|
|
385
|
+
monom.setLetter(letter, index)
|
|
386
|
+
|
|
387
|
+
this.#monoms.push(monom)
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
this.#invalidateCache()
|
|
391
|
+
return this.reorder()
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
gcdDenominator(): number {
|
|
395
|
+
return Numeric.gcd(...this.getDenominators())
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
gcdNumerator(): number {
|
|
399
|
+
return Numeric.gcd(...this.getNumerators())
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
getCoefficients(): Fraction[] {
|
|
403
|
+
if (!this.degree().isNatural()) {
|
|
404
|
+
throw new MathError('getCoefficients() requires a polynomial with integer degrees')
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Assume there is only one letter.
|
|
408
|
+
const orderedPolynom = this.clone().reorder()
|
|
409
|
+
|
|
410
|
+
const length = this.degree().value + 1
|
|
411
|
+
const coeffs = Array.from({length}, () => new Fraction(0))
|
|
412
|
+
|
|
413
|
+
orderedPolynom.monoms.forEach(monom => {
|
|
414
|
+
const index = length - monom.degree().value - 1
|
|
415
|
+
coeffs[index] = monom.coefficient.clone()
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
return coeffs
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Next functions are used for for commonMonom, which is used in the factorize method.
|
|
422
|
+
getDenominators(): number[] {
|
|
423
|
+
const denominators: number[] = []
|
|
424
|
+
for (const m of this.#monoms) {
|
|
425
|
+
denominators.push(m.coefficient.denominator)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return denominators
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
getNumerators(): number[] {
|
|
432
|
+
const numerators: number[] = []
|
|
433
|
+
for (const m of this.#monoms) {
|
|
434
|
+
numerators.push(m.coefficient.numerator)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return numerators
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
getZeroes(): Solution[] {
|
|
441
|
+
if (this.degree().isZero()) {
|
|
442
|
+
return []
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
this.roots = new EquationSolver(this.clone()).solve()
|
|
446
|
+
return this.roots
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
hasVariable(letter: string): boolean {
|
|
450
|
+
return this.variables.includes(letter)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
integrate(a: InputValue<Fraction>, b: InputValue<Fraction>, letter = 'x'): Fraction {
|
|
454
|
+
const primitive = this.primitive(letter)
|
|
455
|
+
|
|
456
|
+
const valuesA: literalType<Fraction> = {}
|
|
457
|
+
const valuesB: literalType<Fraction> = {}
|
|
458
|
+
|
|
459
|
+
valuesA[letter] = new Fraction(a)
|
|
460
|
+
valuesB[letter] = new Fraction(b)
|
|
461
|
+
|
|
462
|
+
return (primitive.evaluate(valuesB)).subtract(primitive.evaluate(valuesA))
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
inverse(): Polynom | undefined {
|
|
466
|
+
return undefined
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
isDeveloped(polynomString: string): boolean {
|
|
470
|
+
// Start by removing the parenthesis after a "power"
|
|
471
|
+
const pString = polynomString.replaceAll(/\^\(([-0-9/]+)\)/g, '$1')
|
|
472
|
+
|
|
473
|
+
// There is at least one parenthesis - it is not developed.
|
|
474
|
+
if (pString.includes('(') || pString.includes(')')) {
|
|
475
|
+
return false
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
// Build the polynom. A malformed string throws (ParseError) instead of
|
|
480
|
+
// being silently treated as "not developed".
|
|
481
|
+
const P = new Polynom(polynomString)
|
|
482
|
+
|
|
483
|
+
// Both polynom aren't the same (once developed and reduced => they cannot be equivalent)
|
|
484
|
+
if (!this.isEqual(P)) {
|
|
485
|
+
return false
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
// Check that everything is completely developed. Actually, there are no parentheses... so it is fully developed
|
|
490
|
+
return true
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
isDividableBy(div: Polynom): boolean {
|
|
494
|
+
// Quick evaluation.
|
|
495
|
+
if (div.degree().isOne()) {
|
|
496
|
+
const zero = div.getZeroes()[0]
|
|
497
|
+
|
|
498
|
+
if (zero.exact) {
|
|
499
|
+
return (this.evaluate(zero.fraction)).isZero()
|
|
500
|
+
} else {
|
|
501
|
+
return false
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
} else {
|
|
505
|
+
const {reminder} = this.euclidean(div)
|
|
506
|
+
return reminder.isZero()
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
isEqual(P: Polynom): boolean {
|
|
511
|
+
return this.#compare(P, '=')
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
get isMultiVariable(): boolean {
|
|
515
|
+
// Determine if a monom has more than one variable.
|
|
516
|
+
return this.#monoms.some(m => m.variables.length > 1)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
isOne(): boolean {
|
|
520
|
+
return this.#monoms.length === 1 && this.#monoms[0].coefficient.isOne() && this.degree().isZero()
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
isOppositeAt(P: Polynom): boolean {
|
|
524
|
+
return this.#compare(P.clone().opposite(), '=')
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
isSameAs(P: Polynom): boolean {
|
|
528
|
+
return this.#compare(P, 'same')
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
isZero(): boolean {
|
|
532
|
+
return (this.#monoms.length === 1 && this.#monoms[0].coefficient.isZero()) || this.#monoms.length === 0
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
lcmDenominator(): number {
|
|
536
|
+
return Numeric.lcm(...this.getDenominators())
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
lcmNumerator(): number {
|
|
540
|
+
return Numeric.lcm(...this.getNumerators())
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
get length() {
|
|
544
|
+
return this.#monoms.length
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
limitTo(value: InputValue<Fraction>, letter?: string): Fraction {
|
|
548
|
+
const f = new Fraction(value)
|
|
549
|
+
|
|
550
|
+
// Finite value: evaluate directly
|
|
551
|
+
if (f.isFinite()) {
|
|
552
|
+
const l = letter ?? this.variables[0] ?? 'x'
|
|
553
|
+
return this.evaluate({[l]: f})
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const M = this.monomByDegree(undefined, letter)
|
|
557
|
+
const sign = M.coefficient.sign()
|
|
558
|
+
const degree = M.degree(letter)
|
|
559
|
+
|
|
560
|
+
// Constant polynomial
|
|
561
|
+
if (degree.isZero()) {
|
|
562
|
+
return M.coefficient.clone()
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (!degree.isStrictlyPositive()) {
|
|
566
|
+
return new Fraction().zero()
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Limit at +∞: determined by the leading coefficient sign
|
|
570
|
+
if (f.isPositive()) {
|
|
571
|
+
return sign === 1
|
|
572
|
+
? new Fraction().infinite()
|
|
573
|
+
: new Fraction().infinite().opposite()
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Limit at -∞: accounts for the parity of the degree
|
|
577
|
+
const degreeIsEven = degree.value % 2 === 0
|
|
578
|
+
const limitSign = degreeIsEven ? sign : -sign
|
|
579
|
+
return limitSign === 1
|
|
580
|
+
? new Fraction().infinite()
|
|
581
|
+
: new Fraction().infinite().opposite()
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
monomByDegree(degree?: Fraction | number, letter?: string): Monom {
|
|
585
|
+
// return the highest degree monom.
|
|
586
|
+
if (degree === undefined) {
|
|
587
|
+
return this.monomByDegree(this.degree(letter), letter)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Reduce the polynom.
|
|
591
|
+
const M = this.clone().reduce()
|
|
592
|
+
for (const m of M.#monoms) {
|
|
593
|
+
if (m.degree(letter).isEqual(degree)) {
|
|
594
|
+
return m.clone()
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Nothing was found - return the null monom.
|
|
599
|
+
return new Monom().zero()
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Used in LinearSystem.tex
|
|
603
|
+
monomByLetter(letter: string): Monom {
|
|
604
|
+
const M = this.clone().reduce()
|
|
605
|
+
for (const m of M.#monoms) {
|
|
606
|
+
if (m.hasVariable(letter)) {
|
|
607
|
+
return m.clone()
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return new Monom().zero()
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// ------------------------------------------
|
|
615
|
+
get monoms() {
|
|
616
|
+
return this.#monoms
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
set monoms(M: Monom[]) {
|
|
620
|
+
this.#monoms = M
|
|
621
|
+
this.#invalidateCache()
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
monomsByDegree(degree?: number | Fraction, letter?: string): Monom[] {
|
|
625
|
+
// return the highest degree monom.
|
|
626
|
+
if (degree === undefined) {
|
|
627
|
+
return this.monomsByDegree(this.degree(letter), letter)
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Reduce the polynom.
|
|
631
|
+
const Ms: Monom[] = []
|
|
632
|
+
|
|
633
|
+
const M = this.clone().reduce()
|
|
634
|
+
for (const m of M.#monoms) {
|
|
635
|
+
if (m.degree(letter).isEqual(degree)) {
|
|
636
|
+
Ms.push(m.clone())
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return Ms
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
multiply(value: InputAlgebra<Polynom>): this {
|
|
644
|
+
|
|
645
|
+
if (value instanceof Polynom) {
|
|
646
|
+
return this.#multiplyByPolynom(value)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (value instanceof Fraction) {
|
|
650
|
+
return this.#multiplyByFraction(value)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (value instanceof Monom) {
|
|
654
|
+
return this.#multiplyByMonom(value)
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (Number.isSafeInteger(value) && typeof value === 'number') {
|
|
658
|
+
return this.#multiplyByInteger(value)
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (typeof value === 'string') {
|
|
662
|
+
try {
|
|
663
|
+
const k = new Fraction(value)
|
|
664
|
+
return this.#multiplyByFraction(k)
|
|
665
|
+
} catch (e) {
|
|
666
|
+
throw new MathError('Cannot multiply by this value.', {cause: e})
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// Something went wrong...
|
|
671
|
+
throw new MathError(`Cannot multiply by this value: ${value as unknown as string}`)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
get numberOfVars(): number {
|
|
675
|
+
return this.variables.length
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
one(): this {
|
|
679
|
+
this.#monoms = []
|
|
680
|
+
this.#monoms.push(new Monom().one())
|
|
681
|
+
this.#invalidateCache()
|
|
682
|
+
return this
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// ------------------------------------------
|
|
686
|
+
opposite(): this {
|
|
687
|
+
this.#monoms = this.#monoms.map(m => m.opposite())
|
|
688
|
+
this.#invalidateCache()
|
|
689
|
+
return this
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
get plotFunction(): string {
|
|
693
|
+
return this.#genDisplay('tex', false, false, true)
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
pow(nb: number): Polynom {
|
|
697
|
+
return operation_pow(this as Polynom, nb).reduce()
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
primitive(letter?: string): Polynom {
|
|
701
|
+
const dP = new Polynom()
|
|
702
|
+
|
|
703
|
+
for (const m of this.#monoms) {
|
|
704
|
+
dP.add(m.primitive(letter))
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return dP
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
reduce(): this {
|
|
711
|
+
// Reduce the polynom
|
|
712
|
+
|
|
713
|
+
// Group the monoms by similarity
|
|
714
|
+
let i = 0
|
|
715
|
+
while (i < this.#monoms.length) {
|
|
716
|
+
for (let j = i + 1; j < this.#monoms.length; j++) {
|
|
717
|
+
if (this.#monoms[i].isSameAs(this.#monoms[j])) {
|
|
718
|
+
this.#monoms[i].add(this.#monoms[j])
|
|
719
|
+
this.#monoms.splice(j, 1)
|
|
720
|
+
if (this.#monoms[i].isZero()) {
|
|
721
|
+
this.#monoms[i] = new Monom().zero()
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
j--
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
i++
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Remove all null monoms
|
|
732
|
+
this.#monoms = this.#monoms.filter((m) => {
|
|
733
|
+
return !m.coefficient.isZero()
|
|
734
|
+
})
|
|
735
|
+
|
|
736
|
+
// Reduce all monoms coefficient.
|
|
737
|
+
for (const m of this.#monoms) {
|
|
738
|
+
m.coefficient.reduce()
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (this.length === 0) {
|
|
742
|
+
return this.zero()
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
this.#invalidateCache()
|
|
746
|
+
return this.reorder()
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
reorder(letter = 'x', revert = false): this {
|
|
750
|
+
const otherLetters = this.variables.filter(x => x !== letter)
|
|
751
|
+
this.#monoms.sort(function (a, b) {
|
|
752
|
+
const da = a.degree(letter).value
|
|
753
|
+
const db = b.degree(letter).value
|
|
754
|
+
|
|
755
|
+
// Values are different
|
|
756
|
+
if (da !== db) {
|
|
757
|
+
return revert ? da - db : db - da
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// if values are equals, check other letters - it must be reverted in that case !
|
|
761
|
+
if (otherLetters.length > 0) {
|
|
762
|
+
for (const L of otherLetters) {
|
|
763
|
+
const da = a.degree(L).value
|
|
764
|
+
const db = b.degree(L).value
|
|
765
|
+
|
|
766
|
+
// Values are different
|
|
767
|
+
if (da !== db) {
|
|
768
|
+
return revert ? da - db : db - da
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
return 0
|
|
775
|
+
})
|
|
776
|
+
|
|
777
|
+
return this
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Replace a variable (letter) by a polynom.
|
|
782
|
+
* @param letter
|
|
783
|
+
* @param P
|
|
784
|
+
*/
|
|
785
|
+
replaceBy(letter: string, P: Polynom): this {
|
|
786
|
+
let pow: Fraction
|
|
787
|
+
const resultPolynom: Polynom = new Polynom().zero()
|
|
788
|
+
|
|
789
|
+
for (const m of this.monoms) {
|
|
790
|
+
if (!m.hasVariable(letter) || m.literal[letter].isZero()) {
|
|
791
|
+
resultPolynom.add(m.clone())
|
|
792
|
+
} else {
|
|
793
|
+
// We have found a variable to replace.
|
|
794
|
+
|
|
795
|
+
// Get the power.
|
|
796
|
+
pow = m.literal[letter].clone()
|
|
797
|
+
|
|
798
|
+
// Remove the variable from the monom
|
|
799
|
+
m.removeVariable(letter)
|
|
800
|
+
|
|
801
|
+
// Add the new monom to the result polynom
|
|
802
|
+
if (pow.isStrictlyNegative()) {
|
|
803
|
+
throw new MathError(`Cannot replace variable "${letter}" with negative power in a Polynom`)
|
|
804
|
+
}
|
|
805
|
+
resultPolynom.add(P.clone().pow(pow.numerator).multiply(m))
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
// Reduce the monoms
|
|
811
|
+
this.#monoms = resultPolynom.reduce().monoms
|
|
812
|
+
this.#invalidateCache()
|
|
813
|
+
return this
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// ------------------------------------------
|
|
817
|
+
|
|
818
|
+
root(): Polynom {
|
|
819
|
+
throw new MathError('Cannot take the root from a polynom')
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
get roots(): Solution[] {
|
|
823
|
+
return this.#rootsCache ? this.#roots : this.getZeroes()
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
set roots(value: Solution[]) {
|
|
827
|
+
this.#rootsCache = true
|
|
828
|
+
this.#roots = value
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
setVariable(value: string): this {
|
|
832
|
+
this.#defaultVariable = value
|
|
833
|
+
|
|
834
|
+
return this
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
sqrt(): Polynom {
|
|
838
|
+
throw new MathError('Cannot take the square root from a polynom')
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
subtract(...values: InputAlgebra<Polynom>[]): this {
|
|
842
|
+
for (const value of values) {
|
|
843
|
+
if (value instanceof Polynom) {
|
|
844
|
+
this.add(value.clone().opposite())
|
|
845
|
+
} else if (value instanceof Monom) {
|
|
846
|
+
this.#monoms.push(value.clone().opposite())
|
|
847
|
+
} else {
|
|
848
|
+
this.#monoms.push(new Monom(value).opposite())
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
return this.reduce()
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
tableOfSigns(): TABLE_OF_SIGNS {
|
|
857
|
+
// returns ['+-', 'd|t|z', '+-']...
|
|
858
|
+
|
|
859
|
+
// global roots from eventually Polyfactor. Allows to add "extra column".
|
|
860
|
+
const roots: Solution[] = this.roots
|
|
861
|
+
|
|
862
|
+
// Build the table os sign length and default values
|
|
863
|
+
// The signs looks like: ['+', 't', '+', 't', '+', 't', '+']
|
|
864
|
+
let signs: TABLE_OF_SIGNS_VALUES[] = new Array(2 * roots.length + 1)
|
|
865
|
+
.fill('')
|
|
866
|
+
.map((_x, index) => {
|
|
867
|
+
return index % 2 === 0 ? '' : 'z'
|
|
868
|
+
})
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
if (signs.length === 1) {
|
|
872
|
+
// The polynom is a constant or has not roots
|
|
873
|
+
const [a] = this.getCoefficients().map(x => x.value)
|
|
874
|
+
signs = replace_in_array(signs, '', a > 0 ? '+' : '-')
|
|
875
|
+
} else if (this.degree().isOne()) {
|
|
876
|
+
// First degree: ax+b
|
|
877
|
+
const [a] = this.getCoefficients().map(x => x.value)
|
|
878
|
+
|
|
879
|
+
// Get the index of the zero.
|
|
880
|
+
signs[0] = a > 0 ? '-' : '+'
|
|
881
|
+
signs[1] = 'z'
|
|
882
|
+
signs[2] = a > 0 ? '+' : '-'
|
|
883
|
+
} else {
|
|
884
|
+
const testingRoots = [
|
|
885
|
+
roots[0].value - 1,
|
|
886
|
+
...roots.map((_root, index) => {
|
|
887
|
+
return index === roots.length - 1 ?
|
|
888
|
+
roots[index].value + 1 :
|
|
889
|
+
(roots[index].value + roots[index + 1].value) / 2
|
|
890
|
+
})
|
|
891
|
+
]
|
|
892
|
+
|
|
893
|
+
testingRoots.forEach((test, index) => {
|
|
894
|
+
const sign = this.evaluate({[this.variables[0] ?? 'x']: test}, true)
|
|
895
|
+
signs[index * 2] = sign > 0 ? '+' : '-'
|
|
896
|
+
})
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return {roots, signs}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
get value(): number | undefined {
|
|
903
|
+
if (this.degree().isZero()) {
|
|
904
|
+
return this.monoms[0]?.coefficient.value ?? 0
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return undefined
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
get variables(): string[] {
|
|
911
|
+
return [...new Set(this.#monoms.flatMap(m => m.variables))].sort()
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Set the polynom to zero.
|
|
916
|
+
* @returns {this}
|
|
917
|
+
*/
|
|
918
|
+
zero(): this {
|
|
919
|
+
this.#monoms = []
|
|
920
|
+
this.#monoms.push(new Monom().zero())
|
|
921
|
+
this.#invalidateCache()
|
|
922
|
+
return this
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
get zeroes(): Solution[] {
|
|
926
|
+
return this.getZeroes()
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
#compare(P: Polynom, sign?: string): boolean {
|
|
930
|
+
sign ??= '='
|
|
931
|
+
|
|
932
|
+
// Create clone version to reduce them without altering the original polynoms.
|
|
933
|
+
const cP1 = this.clone().reduce().reorder()
|
|
934
|
+
const cP2 = P.clone().reduce().reorder()
|
|
935
|
+
|
|
936
|
+
switch (sign) {
|
|
937
|
+
case '=':
|
|
938
|
+
// They must have the isSame length and the isSame degree
|
|
939
|
+
if (cP1.length !== cP2.length || !cP1.degree().isEqual(cP2.degree())) {
|
|
940
|
+
return false
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Check if the coefficients are the isSame.
|
|
944
|
+
return cP1.monoms
|
|
945
|
+
.every((m1, index) => m1.isEqual(cP2.monoms[index]))
|
|
946
|
+
|
|
947
|
+
case 'same':
|
|
948
|
+
// They must have the same length and the same degree
|
|
949
|
+
if (cP1.length !== cP2.length || !cP1.degree().isEqual(cP2.degree())) {
|
|
950
|
+
return false
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
return cP1.monoms
|
|
954
|
+
.every((m1, index) => m1.isSameAs(cP2.monoms[index]))
|
|
955
|
+
|
|
956
|
+
default:
|
|
957
|
+
return false
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
#divideByFraction(F: Fraction): this {
|
|
962
|
+
for (const m of this.#monoms) {
|
|
963
|
+
m.coefficient.divide(F)
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
this.#invalidateCache()
|
|
967
|
+
return this
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
#divideByInteger(nb: number): this {
|
|
971
|
+
const nbF = new Fraction(nb)
|
|
972
|
+
for (const m of this.#monoms) {
|
|
973
|
+
m.coefficient.divide(nbF)
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
this.#invalidateCache()
|
|
977
|
+
return this
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
#evaluateAsNumeric(values: literalType<number | Fraction> | InputValue<Fraction>): number {
|
|
981
|
+
let r = 0
|
|
982
|
+
this.#monoms.forEach(monom => {
|
|
983
|
+
r += monom.evaluate(values, true) as number
|
|
984
|
+
})
|
|
985
|
+
|
|
986
|
+
return r
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
#genDisplay(output?: string, forceSign?: boolean, wrapParentheses?: boolean, withAllMultiplicationSign?: boolean): string {
|
|
990
|
+
let P = ''
|
|
991
|
+
|
|
992
|
+
for (const k of this.#monoms) {
|
|
993
|
+
if (k.coefficient.value === 0) {
|
|
994
|
+
continue
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// The monom to be displayed
|
|
998
|
+
let m
|
|
999
|
+
if (withAllMultiplicationSign) {
|
|
1000
|
+
m = k.plotFunction
|
|
1001
|
+
} else {
|
|
1002
|
+
m = (output === 'tex') ? k.tex : k.display
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
P += `${(k.coefficient.sign() === 1 && (P !== '' || forceSign === true)) ? '+' : ''}${m}`
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
if (wrapParentheses === true && this.length > 1) {
|
|
1009
|
+
if (output === 'tex') {
|
|
1010
|
+
P = `\\left( ${P} \\right)`
|
|
1011
|
+
} else {
|
|
1012
|
+
P = `(${P})`
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
if (P === '') {
|
|
1018
|
+
P = '0'
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
return P
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
#invalidateCache(): void {
|
|
1025
|
+
this.#rootsCache = false
|
|
1026
|
+
this.#factors = []
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
#multiplyByFraction(F: Fraction): this {
|
|
1030
|
+
for (const m of this.#monoms) {
|
|
1031
|
+
m.coefficient.multiply(F)
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
return this.reduce()
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
#multiplyByInteger(nb: number): this {
|
|
1038
|
+
return this.#multiplyByFraction(new Fraction(nb))
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
#multiplyByMonom(M: Monom): this {
|
|
1042
|
+
for (const m of this.#monoms) {
|
|
1043
|
+
m.multiply(M)
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
return this.reduce()
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
#multiplyByPolynom(P: Polynom): this {
|
|
1050
|
+
const M: Monom[] = []
|
|
1051
|
+
for (const m1 of this.#monoms) {
|
|
1052
|
+
for (const m2 of P.monoms) {
|
|
1053
|
+
M.push(Monom.xMultiply(m1, m2))
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
this.#monoms = M
|
|
1058
|
+
return this.reduce()
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
#parseString(inputStr: string, ...values: InputValue<Fraction>[]): this {
|
|
1062
|
+
if (values.length === 0) {
|
|
1063
|
+
// Parse the polynom using the shutting yard algorithm
|
|
1064
|
+
if (inputStr !== '' && !isNaN(Number(inputStr))) {
|
|
1065
|
+
this.empty()
|
|
1066
|
+
// It's a simple number.
|
|
1067
|
+
const m = new Monom(Number(inputStr))
|
|
1068
|
+
// m.coefficient = new Fraction(inputStr);
|
|
1069
|
+
// m.literalStr = '';
|
|
1070
|
+
this.add(m)
|
|
1071
|
+
return this
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// Parse the string.
|
|
1075
|
+
return this.#shutingYardToReducedPolynom(inputStr)
|
|
1076
|
+
} else if (/^[a-z]+$/.test(inputStr)) {
|
|
1077
|
+
// We assume the inputStr contains only letters.
|
|
1078
|
+
this.empty()
|
|
1079
|
+
|
|
1080
|
+
const fractions = values.map(x => new Fraction(x))
|
|
1081
|
+
|
|
1082
|
+
// Multiple setLetter version
|
|
1083
|
+
if (inputStr.length > 1) {
|
|
1084
|
+
const letters = inputStr.split('')
|
|
1085
|
+
|
|
1086
|
+
if (fractions.length > letters.length + 1) {
|
|
1087
|
+
throw new InvalidArgumentError(`Too many values: ${letters.length} letters but ${fractions.length} values provided`)
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
let i = 0
|
|
1091
|
+
|
|
1092
|
+
for (const F of fractions) {
|
|
1093
|
+
const m = new Monom()
|
|
1094
|
+
m.coefficient = F.clone()
|
|
1095
|
+
m.literalStr = letters[i] ?? ''
|
|
1096
|
+
this.add(m)
|
|
1097
|
+
i++
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
// Single setLetter version
|
|
1101
|
+
else {
|
|
1102
|
+
let n = fractions.length - 1
|
|
1103
|
+
for (const F of fractions) {
|
|
1104
|
+
const m = new Monom()
|
|
1105
|
+
m.coefficient = F.clone()
|
|
1106
|
+
m.literalStr = `${inputStr}^${n}`
|
|
1107
|
+
this.add(m)
|
|
1108
|
+
n--
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return this
|
|
1112
|
+
} else {
|
|
1113
|
+
return this.zero()
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
#shutingYardAddToken(stack: Polynom[], element: Token): void {
|
|
1119
|
+
switch (element.tokenType) {
|
|
1120
|
+
case ShutingyardType.COEFFICIENT:
|
|
1121
|
+
stack.push(new Polynom(element.token))
|
|
1122
|
+
break
|
|
1123
|
+
|
|
1124
|
+
case ShutingyardType.VARIABLE:
|
|
1125
|
+
stack.push(new Polynom().add(new Monom(element.token)))
|
|
1126
|
+
break
|
|
1127
|
+
|
|
1128
|
+
case ShutingyardType.CONSTANT:
|
|
1129
|
+
throw new ParseError('Unsupported CONSTANT token in Polynom parser')
|
|
1130
|
+
|
|
1131
|
+
case ShutingyardType.OPERATION:
|
|
1132
|
+
if (stack.length >= 2) {
|
|
1133
|
+
const b = stack.pop()
|
|
1134
|
+
const a = stack.pop()
|
|
1135
|
+
|
|
1136
|
+
// Check if the polynoms are not undefined.
|
|
1137
|
+
if (a === undefined || b === undefined) {
|
|
1138
|
+
throw new ParseError('Unexpected undefined operand in Polynom parser stack')
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
if (element.token === '+') {
|
|
1142
|
+
stack.push(a.add(b))
|
|
1143
|
+
} else if (element.token === '-') {
|
|
1144
|
+
stack.push(a.subtract(b))
|
|
1145
|
+
} else if (element.token === '*') {
|
|
1146
|
+
stack.push(a.multiply(b))
|
|
1147
|
+
} else if (element.token === '/') {
|
|
1148
|
+
if (b.degree().isStrictlyPositive()) {
|
|
1149
|
+
throw new MathError('Cannot divide a Polynom by another Polynom of degree > 0')
|
|
1150
|
+
} else {
|
|
1151
|
+
// a.divide(b.monoms[0].coefficient)
|
|
1152
|
+
stack.push(a.divide(b.monoms[0].coefficient))
|
|
1153
|
+
}
|
|
1154
|
+
} else if (element.token === '^') {
|
|
1155
|
+
if (b.degree().isStrictlyPositive()) {
|
|
1156
|
+
throw new MathError('Cannot elevate a polynom with another polynom !')
|
|
1157
|
+
} else if (b.monoms[0].coefficient.isNatural())
|
|
1158
|
+
// Natural (positive) power
|
|
1159
|
+
{
|
|
1160
|
+
stack.push(a.pow(b.monoms[0].coefficient.value))
|
|
1161
|
+
} else {
|
|
1162
|
+
// Only allow power if the previous polynom is only a monom, without coefficient.
|
|
1163
|
+
if (a.monoms.length === 1 && a.monoms[0].coefficient.isOne()) {
|
|
1164
|
+
for (const letter in a.monoms[0].literal) {
|
|
1165
|
+
a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient)
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
stack.push(a)
|
|
1169
|
+
} else {
|
|
1170
|
+
throw new MathError('Cannot raise a multi-monom Polynom to a fractional power')
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
} else if (element.token === '-') {
|
|
1176
|
+
const a = stack.pop()
|
|
1177
|
+
if (a) {
|
|
1178
|
+
stack.push(a.opposite())
|
|
1179
|
+
}
|
|
1180
|
+
} else {
|
|
1181
|
+
throw new ParseError("Error parsing the polynom")
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
break
|
|
1186
|
+
|
|
1187
|
+
case ShutingyardType.MONOM:
|
|
1188
|
+
// Should never appear.
|
|
1189
|
+
throw new ParseError('Unexpected MONOM token in polynom parser')
|
|
1190
|
+
|
|
1191
|
+
case ShutingyardType.FUNCTION:
|
|
1192
|
+
// Should never appear.
|
|
1193
|
+
throw new ParseError(`Unsupported function token "${element.token}" in polynom parser`)
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Main parse using a shutting yard class
|
|
1201
|
+
* @param inputStr
|
|
1202
|
+
*/
|
|
1203
|
+
#shutingYardToReducedPolynom(inputStr: string): this {
|
|
1204
|
+
// Get the RPN array of the current expression
|
|
1205
|
+
let SY: ShutingYard
|
|
1206
|
+
try {
|
|
1207
|
+
SY = new ShutingYard().parse(inputStr)
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
throw new ParseError(`Cannot parse "${inputStr}" as a Polynom`, {cause: e})
|
|
1210
|
+
}
|
|
1211
|
+
const rpn: { token: string, tokenType: ShutingyardType }[] = SY.rpn
|
|
1212
|
+
|
|
1213
|
+
// New version for reducing shuting yard.
|
|
1214
|
+
this.zero()
|
|
1215
|
+
|
|
1216
|
+
const stack: Polynom[] = []
|
|
1217
|
+
|
|
1218
|
+
// Loop through the each element of the RPN
|
|
1219
|
+
for (const element of rpn) {
|
|
1220
|
+
this.#shutingYardAddToken(stack, element)
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
if (stack.length === 1) {
|
|
1225
|
+
this.add(stack[0])
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
return this.reorder()
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
}
|