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/monom.ts
CHANGED
|
@@ -1,928 +1,932 @@
|
|
|
1
|
-
/***
|
|
2
|
-
* Monom class
|
|
3
|
-
*/
|
|
4
|
-
import type {
|
|
5
|
-
IAlgebra,
|
|
6
|
-
IAnalyse,
|
|
7
|
-
IExpression,
|
|
8
|
-
InputAlgebra,
|
|
9
|
-
InputValue,
|
|
10
|
-
IPiMathObject,
|
|
11
|
-
literalType
|
|
12
|
-
} from "../pimath.interface"
|
|
13
|
-
import {Fraction} from "../coefficients"
|
|
14
|
-
import {Numeric} from "../numeric"
|
|
15
|
-
|
|
16
|
-
import {ShutingYard, ShutingyardType, type Token} from "piexpression"
|
|
17
|
-
import {MathError, NotImplementedError, ParseError} from "../errors"
|
|
18
|
-
|
|
19
|
-
export class Monom implements IPiMathObject<Monom>, IExpression<Monom>, IAnalyse<Monom>, IAlgebra<Monom> {
|
|
20
|
-
#coefficient: Fraction
|
|
21
|
-
#literal: literalType<Fraction>
|
|
22
|
-
|
|
23
|
-
constructor(value?: InputValue<Fraction>)
|
|
24
|
-
constructor(value?: Monom)
|
|
25
|
-
constructor(value?: InputAlgebra<Fraction>) {
|
|
26
|
-
this.#coefficient = new Fraction().zero()
|
|
27
|
-
this.#literal = {}
|
|
28
|
-
|
|
29
|
-
if (value !== undefined) {
|
|
30
|
-
// A string is given - try to parse the value.
|
|
31
|
-
this.parse(value)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return this
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// -----------------------------------------
|
|
38
|
-
/**
|
|
39
|
-
* Parse a string to a monom. The string may include fraction.
|
|
40
|
-
* @param inputStr
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
// Initialize the monom
|
|
44
|
-
this.#coefficient = new Fraction()
|
|
45
|
-
this.#literal = {}
|
|
46
|
-
|
|
47
|
-
if (inputStr instanceof Monom) {
|
|
48
|
-
this.#coefficient = inputStr.#coefficient.clone()
|
|
49
|
-
|
|
50
|
-
// Copy the literal parts
|
|
51
|
-
this.#cloneLiteral(inputStr)
|
|
52
|
-
return this
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (inputStr instanceof Fraction) {
|
|
56
|
-
this.#coefficient = inputStr.clone()
|
|
57
|
-
return this
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (typeof inputStr === 'number') {
|
|
61
|
-
this.#coefficient = new Fraction(inputStr)
|
|
62
|
-
return this
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!isNaN(Number(inputStr))) {
|
|
67
|
-
this.#coefficient = new Fraction(Number(inputStr))
|
|
68
|
-
} else {
|
|
69
|
-
this.#shutingYardToReducedMonom(inputStr)
|
|
70
|
-
}
|
|
71
|
-
return this
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Clone the current Monom.
|
|
76
|
-
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this
|
|
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
|
-
return
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
// Get the list of all variables from both monoms.
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
-
return this
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
this
|
|
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
|
-
|
|
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
|
-
if (
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
litt
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
stack
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
stack
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
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
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
this
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1
|
+
/***
|
|
2
|
+
* Monom class
|
|
3
|
+
*/
|
|
4
|
+
import type {
|
|
5
|
+
IAlgebra,
|
|
6
|
+
IAnalyse,
|
|
7
|
+
IExpression,
|
|
8
|
+
InputAlgebra,
|
|
9
|
+
InputValue,
|
|
10
|
+
IPiMathObject,
|
|
11
|
+
literalType
|
|
12
|
+
} from "../pimath.interface"
|
|
13
|
+
import {Fraction} from "../coefficients"
|
|
14
|
+
import {Numeric} from "../numeric"
|
|
15
|
+
|
|
16
|
+
import {ShutingYard, ShutingyardType, type Token} from "piexpression"
|
|
17
|
+
import {MathError, NotImplementedError, ParseError} from "../errors"
|
|
18
|
+
|
|
19
|
+
export class Monom implements IPiMathObject<Monom>, IExpression<Monom>, IAnalyse<Monom>, IAlgebra<Monom> {
|
|
20
|
+
#coefficient: Fraction
|
|
21
|
+
#literal: literalType<Fraction>
|
|
22
|
+
|
|
23
|
+
constructor(value?: InputValue<Fraction>)
|
|
24
|
+
constructor(value?: Monom)
|
|
25
|
+
constructor(value?: InputAlgebra<Fraction>) {
|
|
26
|
+
this.#coefficient = new Fraction().zero()
|
|
27
|
+
this.#literal = {}
|
|
28
|
+
|
|
29
|
+
if (value !== undefined) {
|
|
30
|
+
// A string is given - try to parse the value.
|
|
31
|
+
this.parse(value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// -----------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Parse a string to a monom. The string may include fraction.
|
|
40
|
+
* @param inputStr
|
|
41
|
+
*/
|
|
42
|
+
parse(inputStr: InputAlgebra<Monom>): this {
|
|
43
|
+
// Initialize the monom
|
|
44
|
+
this.#coefficient = new Fraction()
|
|
45
|
+
this.#literal = {}
|
|
46
|
+
|
|
47
|
+
if (inputStr instanceof Monom) {
|
|
48
|
+
this.#coefficient = inputStr.#coefficient.clone()
|
|
49
|
+
|
|
50
|
+
// Copy the literal parts
|
|
51
|
+
this.#cloneLiteral(inputStr)
|
|
52
|
+
return this
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (inputStr instanceof Fraction) {
|
|
56
|
+
this.#coefficient = inputStr.clone()
|
|
57
|
+
return this
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof inputStr === 'number') {
|
|
61
|
+
this.#coefficient = new Fraction(inputStr)
|
|
62
|
+
return this
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if (!isNaN(Number(inputStr))) {
|
|
67
|
+
this.#coefficient = new Fraction(Number(inputStr))
|
|
68
|
+
} else {
|
|
69
|
+
this.#shutingYardToReducedMonom(inputStr)
|
|
70
|
+
}
|
|
71
|
+
return this
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Clone the current Monom.
|
|
76
|
+
*/
|
|
77
|
+
copy(): this {
|
|
78
|
+
throw new NotImplementedError("copy() is not yet implemented for Monom")
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
clone = (): Monom => {
|
|
82
|
+
const F: Monom = new Monom()
|
|
83
|
+
|
|
84
|
+
F.coefficient = this.#coefficient.clone()
|
|
85
|
+
|
|
86
|
+
// Copy the literal parts.
|
|
87
|
+
for (const k in this.#literal) {
|
|
88
|
+
F.setLetter(k, this.#literal[k].clone())
|
|
89
|
+
}
|
|
90
|
+
return F
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get the tex output of the monom
|
|
95
|
+
*/
|
|
96
|
+
get tex(): string {
|
|
97
|
+
return this.#format('tex')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Display getter
|
|
101
|
+
/**
|
|
102
|
+
* This display getter is to be used in the polynom display getter
|
|
103
|
+
*/
|
|
104
|
+
get display(): string {
|
|
105
|
+
return this.#format('display')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static gcd = (...monoms: Monom[]): Monom => {
|
|
109
|
+
// All the monoms must be with natural powers...
|
|
110
|
+
for (const m of monoms) {
|
|
111
|
+
if (m.containsRationalPower()) {
|
|
112
|
+
return new Monom().zero()
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const M = new Monom(),
|
|
117
|
+
n: number = Numeric.gcd(...monoms.map(value => value.coefficient.numerator)),
|
|
118
|
+
d: number = Numeric.lcm(...monoms.map(value => value.coefficient.denominator))
|
|
119
|
+
|
|
120
|
+
// Get the coefficient.
|
|
121
|
+
M.coefficient = new Fraction(n, d).reduce()
|
|
122
|
+
|
|
123
|
+
// Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.
|
|
124
|
+
for (const m of monoms) {
|
|
125
|
+
// Remove the inexistant letters from the resulting monom
|
|
126
|
+
for (const letter in M.literal) {
|
|
127
|
+
if (!(letter in m.literal)) {
|
|
128
|
+
M.removeVariable(letter)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const letter in m.literal) {
|
|
132
|
+
if (!M.hasVariable(letter) && m.literal[letter].isStrictlyPositive()) {
|
|
133
|
+
M.literal[letter] = m.literal[letter].clone()
|
|
134
|
+
} else {
|
|
135
|
+
M.literal[letter] = new Fraction(Math.min(m.literal[letter].value, M.literal[letter].value))
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return M
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Multiply two monoms and return a NEW monom.
|
|
145
|
+
* @param monoms
|
|
146
|
+
*/
|
|
147
|
+
static xMultiply = (...monoms: Monom[]): Monom => {
|
|
148
|
+
const M = new Monom().one()
|
|
149
|
+
|
|
150
|
+
for (const m of monoms) {
|
|
151
|
+
M.multiply(m)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return M
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Add all similar monoms. If they aren't similar, they are simply skipped.
|
|
159
|
+
* @param M (Monom[]) The monoms to add.
|
|
160
|
+
*/
|
|
161
|
+
add = (...M: InputAlgebra<Fraction>[]): this => {
|
|
162
|
+
for (const m of M) {
|
|
163
|
+
// If the value given is not a monom, create it.
|
|
164
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
165
|
+
|
|
166
|
+
if (this.isSameAs(mAsMonom)) {
|
|
167
|
+
if (this.isZero()) {
|
|
168
|
+
this.#cloneLiteral(mAsMonom)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.#coefficient.add(mAsMonom.coefficient)
|
|
172
|
+
} else {
|
|
173
|
+
throw new MathError('Add monom: ' + this.display + ' is not similar with ' + mAsMonom.display)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return this
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get the coefficient \\(k\\) of the Monom \\(k\\cdot x^{n}\\)
|
|
181
|
+
* @returns {Fraction}
|
|
182
|
+
*/
|
|
183
|
+
get coefficient(): Fraction {
|
|
184
|
+
return this.#coefficient
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Set the coefficient \\(k\\) value of the monom
|
|
189
|
+
* @param {Fraction | number | string} F
|
|
190
|
+
*/
|
|
191
|
+
set coefficient(F: InputValue<Fraction>) {
|
|
192
|
+
this.#coefficient = new Fraction(F)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
containsRationalPower = (): boolean => {
|
|
196
|
+
return Object.values(this.#literal).some((value) => value.hasFractionalPart())
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get the degree of a monom. If no setLetter is given, the result will be the global degree.
|
|
201
|
+
* @param letter (string) Letter to get to degree (power)
|
|
202
|
+
*/
|
|
203
|
+
degree = (letter?: string): Fraction => {
|
|
204
|
+
if (this.variables.length === 0) {
|
|
205
|
+
return new Fraction().zero()
|
|
206
|
+
}
|
|
207
|
+
if (letter === undefined) {
|
|
208
|
+
// Not setLetter given -> we get the global monom degree (sum of all the letters).
|
|
209
|
+
return Object.values(this.#literal).reduce((t, n) => t.clone().add(n))
|
|
210
|
+
} else {
|
|
211
|
+
// A setLetter is given -> get the corresponding power.
|
|
212
|
+
return !this.hasVariable(letter) ? new Fraction().zero() : this.#literal[letter].clone()
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Derivative the monom
|
|
218
|
+
* @param letter
|
|
219
|
+
*/
|
|
220
|
+
derivative = (letter = 'x'): Monom => {
|
|
221
|
+
// No setLetter given - assume it's the setLetter 'x'
|
|
222
|
+
if (this.hasVariable(letter)) {
|
|
223
|
+
const d = this.#literal[letter].clone(),
|
|
224
|
+
dM = this.clone()
|
|
225
|
+
|
|
226
|
+
// Subtract one to the degree.
|
|
227
|
+
dM.#literal[letter].subtract(1)
|
|
228
|
+
|
|
229
|
+
// Multiply the coefficient by the previous degree
|
|
230
|
+
dM.#coefficient.multiply(new Fraction(d.clone()))
|
|
231
|
+
return dM
|
|
232
|
+
} else {
|
|
233
|
+
return new Monom().zero()
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Divide the current monoms by multiple monoms
|
|
239
|
+
* @param M (Monom[])
|
|
240
|
+
*/
|
|
241
|
+
divide = (...M: InputAlgebra<Fraction>[]): this => {
|
|
242
|
+
// Depending on the given value, choose the current item
|
|
243
|
+
for (const m of M) {
|
|
244
|
+
// If the value given is not a monom, create it.
|
|
245
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
246
|
+
|
|
247
|
+
// Divide the coefficient
|
|
248
|
+
this.#coefficient.divide(mAsMonom.coefficient)
|
|
249
|
+
|
|
250
|
+
// Subtract the power values
|
|
251
|
+
for (const letter in mAsMonom.literal) {
|
|
252
|
+
|
|
253
|
+
this.#literal[letter] = this.hasVariable(letter) ?
|
|
254
|
+
this.#literal[letter].subtract(mAsMonom.literal[letter]) :
|
|
255
|
+
mAsMonom.literal[letter].clone().opposite()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
// If the power of a particular setLetter is zero, delete it from the literal part..
|
|
259
|
+
if (this.#literal[letter].isZero()) {
|
|
260
|
+
this.removeVariable(letter)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return this
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
get dividers(): Monom[] {
|
|
268
|
+
// Decompose only if the coefficient is a natural number
|
|
269
|
+
if (!this.coefficient.isRelative()) {
|
|
270
|
+
return [this.clone()]
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Decompose only if the power values are natural numbers.
|
|
274
|
+
if (this.containsRationalPower()) {
|
|
275
|
+
return [this.clone()]
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Security : do not do this if greater than 10000
|
|
279
|
+
if (this.coefficient.numerator > 1000000) {
|
|
280
|
+
return [this.clone()]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))
|
|
284
|
+
|
|
285
|
+
// Decompose the literals parts.
|
|
286
|
+
let literals: literalType<Fraction>[] = []
|
|
287
|
+
for (const L in this.literal) {
|
|
288
|
+
// L is the letter.
|
|
289
|
+
literals = this.#getLiteralDividers(literals, L)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const monomDividers: Monom[] = []
|
|
293
|
+
if (literals.length > 0 && dividers.length > 0) {
|
|
294
|
+
for (const N of dividers) {
|
|
295
|
+
for (const L of literals) {
|
|
296
|
+
const M = new Monom()
|
|
297
|
+
M.coefficient = new Fraction(N)
|
|
298
|
+
M.literal = L
|
|
299
|
+
monomDividers.push(M)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
} else if (dividers.length === 0) {
|
|
303
|
+
for (const L of literals) {
|
|
304
|
+
const M = new Monom()
|
|
305
|
+
M.coefficient = new Fraction().one()
|
|
306
|
+
M.literal = L
|
|
307
|
+
monomDividers.push(M)
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
for (const N of dividers) {
|
|
311
|
+
const M = new Monom()
|
|
312
|
+
M.coefficient = new Fraction(N)
|
|
313
|
+
monomDividers.push(M)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return monomDividers.length === 0 ? [new Monom().one()] : monomDividers
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Evaluate a monom. Each setLetter must be assigned to a Fraction.
|
|
322
|
+
* @param values Dictionary of <setLetter: Fraction>
|
|
323
|
+
* @param asNumeric
|
|
324
|
+
*/
|
|
325
|
+
evaluate = (values: literalType<number | Fraction> | InputValue<Fraction>, asNumeric?: boolean): Fraction | number => {
|
|
326
|
+
// If as numeric return the numeric value
|
|
327
|
+
if (asNumeric === true) {
|
|
328
|
+
// Convert all values to numeric
|
|
329
|
+
// If the value is a Fraction, convert it to a number
|
|
330
|
+
if (values instanceof Fraction) {
|
|
331
|
+
return this.#evaluateAsNumeric(values.value)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// If the value is a number, return the numeric value
|
|
335
|
+
if (typeof values === 'number') {
|
|
336
|
+
return this.#evaluateAsNumeric(values)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// If the value is an object, return the numeric value
|
|
340
|
+
if (typeof values === 'object') {
|
|
341
|
+
// Convert {[key:string]:Fraction} to {[key:string]:number}
|
|
342
|
+
const tmpValues: literalType<number> = {}
|
|
343
|
+
for (const L in values) {
|
|
344
|
+
tmpValues[L] = new Fraction(values[L]).value
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return this.#evaluateAsNumeric(tmpValues)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// The answer must be a Fraction
|
|
352
|
+
const r = this.coefficient.clone()
|
|
353
|
+
|
|
354
|
+
if (typeof values === 'number' || values instanceof Fraction) {
|
|
355
|
+
const tmpValues: literalType<Fraction> = {}
|
|
356
|
+
tmpValues[this.variables[0]] = new Fraction(values)
|
|
357
|
+
return this.evaluate(tmpValues)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (typeof values === 'object') {
|
|
361
|
+
if (this.variables.length === 0) {
|
|
362
|
+
return this.coefficient
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
for (const L in this.#literal) {
|
|
366
|
+
const value = new Fraction(values[L])
|
|
367
|
+
|
|
368
|
+
r.multiply(value.pow(this.#literal[L]))
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return r
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// -------------------------------------
|
|
376
|
+
/**
|
|
377
|
+
* Determine if a monom contains a setLetter in it's literal part
|
|
378
|
+
* @param letter
|
|
379
|
+
*/
|
|
380
|
+
hasVariable = (letter?: string): boolean => {
|
|
381
|
+
// The letter was not found
|
|
382
|
+
return Object.hasOwn(this.#literal, letter ?? 'x')
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
integrate(a: InputValue<Fraction>, b: InputValue<Fraction>, letter?: string): Fraction {
|
|
386
|
+
const primitive = this.primitive(letter)
|
|
387
|
+
|
|
388
|
+
return (primitive.evaluate(b, false) as Fraction)
|
|
389
|
+
.subtract(primitive.evaluate(a, false) as Fraction)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
inverse = (): this => {
|
|
393
|
+
this.#coefficient.inverse()
|
|
394
|
+
for (const letter in this.#literal) {
|
|
395
|
+
this.#literal[letter].opposite()
|
|
396
|
+
}
|
|
397
|
+
return this
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
isDivisible = (div: Monom): boolean => {
|
|
401
|
+
// For all variables (letters), the current monom must have a degree higher than the divider
|
|
402
|
+
if (div.degree().isStrictlyPositive()) {
|
|
403
|
+
for (const letter of div.variables) {
|
|
404
|
+
if (!this.degree(letter).isGeq(div.degree(letter))) {
|
|
405
|
+
return false
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// If the coefficient has a fractional part, we suppose we don't need to check the division by the coefficient.
|
|
411
|
+
if (this.coefficient.hasFractionalPart() || div.coefficient.hasFractionalPart()) {
|
|
412
|
+
return true
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return this.coefficient.clone().divide(div.coefficient).isRelative()
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Determine if two monoms are equals
|
|
420
|
+
* @param M
|
|
421
|
+
*/
|
|
422
|
+
isEqual = (M: Monom): boolean => {
|
|
423
|
+
return this.isSameAs(M) && this.#coefficient.isEqual(M.coefficient)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
isLiteralSquare = (): boolean => {
|
|
427
|
+
for (const letter in this.literal) {
|
|
428
|
+
// A literal square must have a natural power
|
|
429
|
+
if (this.literal[letter].hasFractionalPart()) {
|
|
430
|
+
return false
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// The natural power must be even - if it's odd, the monom is not a square.
|
|
434
|
+
if (this.literal[letter].isOdd()) {
|
|
435
|
+
return false
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return true
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Determine if the monom is one
|
|
444
|
+
*/
|
|
445
|
+
isOne = (): boolean => {
|
|
446
|
+
return this.#coefficient.value === 1 && this.variables.length === 0
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Determine if two monoms are similar
|
|
451
|
+
* @param M
|
|
452
|
+
*/
|
|
453
|
+
isSameAs = (M: Monom): boolean => {
|
|
454
|
+
// Get the list of all variables from both monoms.
|
|
455
|
+
const M1: string[] = this.variables
|
|
456
|
+
const M2: string[] = M.variables
|
|
457
|
+
|
|
458
|
+
// Get the list of all variables from both monoms.
|
|
459
|
+
const K: string[] = M1.concat(M2.filter((item) => !M1.includes(item)))
|
|
460
|
+
|
|
461
|
+
// If one of the monom is zero, it is the same than the other.
|
|
462
|
+
if (this.isZero() || M.isZero()) {
|
|
463
|
+
return true
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Both monoms has no literal part.
|
|
467
|
+
if (M1.length === 0 && M2.length === 0) {
|
|
468
|
+
return true
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Both monoms must have the same variables
|
|
472
|
+
if (M1.length !== M2.length) {
|
|
473
|
+
return false
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// To _compare, both must be different from zero.
|
|
477
|
+
if (!this.isZero() && !M.isZero()) {
|
|
478
|
+
for (const key of K) {
|
|
479
|
+
// The variable is not available in one of the monom
|
|
480
|
+
if (!this.hasVariable(key) || !M.hasVariable(key)) {
|
|
481
|
+
return false
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// The variable does not have the same power in each monoms.
|
|
485
|
+
if (!this.#literal[key].isEqual(M.literal[key])) {
|
|
486
|
+
return false
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// All are positive check - the monoms are the sames.
|
|
492
|
+
return true
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
isSquare = (): boolean => {
|
|
496
|
+
if (!this.coefficient.isSquare()) {
|
|
497
|
+
return false
|
|
498
|
+
}
|
|
499
|
+
return this.isLiteralSquare()
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Determine if the monom is null
|
|
504
|
+
*/
|
|
505
|
+
isZero = (): boolean => {
|
|
506
|
+
return this.#coefficient.value === 0
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Get the literal part of \\(x^{n_1}y^{n_2}\\) as dictionary \\[\\begin{array}{ll}x&=n_1\\\\y&=n_2\\end{array}\\]
|
|
511
|
+
* @returns {literalType}
|
|
512
|
+
*/
|
|
513
|
+
get literal(): literalType<Fraction> {
|
|
514
|
+
return this.#literal
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}
|
|
519
|
+
* @param {literalType<Fraction>} L
|
|
520
|
+
*/
|
|
521
|
+
set literal(L: literalType<Fraction>) {
|
|
522
|
+
this.#literal = L
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Set the literal part of the monom from a string
|
|
527
|
+
* @param inputStr String like x^2y^3
|
|
528
|
+
*/
|
|
529
|
+
set literalStr(inputStr: string) {
|
|
530
|
+
// Match all x^n
|
|
531
|
+
for (const v of [...inputStr.matchAll(/([a-z])\^([+-]?[0-9]+)/g)]) {
|
|
532
|
+
// Create the default letter entry if necessary.
|
|
533
|
+
if (!(v[1] in this.#literal)) {
|
|
534
|
+
this.#literal[v[1]] = new Fraction().zero()
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Add the new value.
|
|
538
|
+
this.#literal[v[1]].add(+v[2])
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Match all x
|
|
542
|
+
for (const v of [...inputStr.matchAll(/([a-z](?!\^))/g)]) {
|
|
543
|
+
// Match all single letters
|
|
544
|
+
if (!(v[1] in this.#literal)) {
|
|
545
|
+
this.#literal[v[1]] = new Fraction().zero()
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Add one to the value.
|
|
549
|
+
this.#literal[v[1]].add(1)
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Multiple multiple monoms to the current monom
|
|
555
|
+
* @param M (Monom[]) The monoms to multiply to.
|
|
556
|
+
*/
|
|
557
|
+
multiply = (...M: InputAlgebra<Fraction>[]): this => {
|
|
558
|
+
for (const m of M) {
|
|
559
|
+
// If the value given is not a monom, create it.
|
|
560
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
561
|
+
|
|
562
|
+
// Multiply the coefficient.
|
|
563
|
+
this.#coefficient.multiply(mAsMonom.coefficient)
|
|
564
|
+
|
|
565
|
+
// Multiply the literal parts.
|
|
566
|
+
for (const letter in mAsMonom.literal) {
|
|
567
|
+
if (!this.hasVariable(letter)) {
|
|
568
|
+
this.#literal[letter] = mAsMonom.literal[letter].clone()
|
|
569
|
+
} else {
|
|
570
|
+
this.#literal[letter].add(mAsMonom.literal[letter])
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return this
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Create a one value monom
|
|
579
|
+
*/
|
|
580
|
+
one = (): this => {
|
|
581
|
+
this.#coefficient = new Fraction().one()
|
|
582
|
+
this.#literal = {}
|
|
583
|
+
return this
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Get the opposite
|
|
588
|
+
* Returns a monom.
|
|
589
|
+
*/
|
|
590
|
+
opposite = (): this => {
|
|
591
|
+
this.#coefficient.opposite()
|
|
592
|
+
return this
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
get plotFunction(): string {
|
|
596
|
+
return this.#format('plot')
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Get the pow of a monom.
|
|
601
|
+
* @param nb (number) : Mathematical pow
|
|
602
|
+
*/
|
|
603
|
+
pow = (nb: number | Fraction): this => {
|
|
604
|
+
this.#coefficient.pow(nb)
|
|
605
|
+
for (const letter in this.#literal) {
|
|
606
|
+
this.#literal[letter].multiply(nb)
|
|
607
|
+
}
|
|
608
|
+
return this
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
primitive = (letter = 'x'): Monom => {
|
|
612
|
+
// Zero monom
|
|
613
|
+
const M = this.clone()
|
|
614
|
+
let degree: Fraction
|
|
615
|
+
|
|
616
|
+
if (M.hasVariable(letter)) {
|
|
617
|
+
degree = M.degree(letter).clone().add(1)
|
|
618
|
+
M.coefficient = M.coefficient.clone().divide(degree)
|
|
619
|
+
M.setLetter(letter, degree)
|
|
620
|
+
} else {
|
|
621
|
+
// There is no letter.
|
|
622
|
+
|
|
623
|
+
// The coefficient might be zero (=> x) or a number a (=> ax)
|
|
624
|
+
if (M.coefficient.isZero()) {
|
|
625
|
+
M.coefficient = new Fraction().one()
|
|
626
|
+
}
|
|
627
|
+
M.setLetter(letter, 1)
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return M
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
reduce = (): this => {
|
|
634
|
+
// Reduce the coefficient
|
|
635
|
+
this.coefficient.reduce()
|
|
636
|
+
|
|
637
|
+
// Reduce the literal parts (removing null powers)
|
|
638
|
+
for (const letter in this.#literal) {
|
|
639
|
+
if (this.#literal[letter].isZero()) {
|
|
640
|
+
this.removeVariable(letter)
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return this
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
removeVariable(letter: string) {
|
|
647
|
+
/* eslint-disable */
|
|
648
|
+
delete this.#literal[letter]
|
|
649
|
+
/* eslint-enable */
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Get the nth-root of the monom
|
|
654
|
+
* @todo Not yet implemented
|
|
655
|
+
*/
|
|
656
|
+
root = (): this => {
|
|
657
|
+
// TODO: implement nth-root for monoms
|
|
658
|
+
throw new NotImplementedError('Method not implemented.')
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Set the power of a particular setLetter
|
|
663
|
+
* @param letter (string) Letter to change
|
|
664
|
+
* @param pow (number) Power of the setLetter (must be positive integer.
|
|
665
|
+
*/
|
|
666
|
+
setLetter = (letter: string, pow: InputValue<Fraction>): this => {
|
|
667
|
+
if (!(pow instanceof Fraction)) {
|
|
668
|
+
return this.setLetter(letter, new Fraction(pow))
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Set the power of the letter to zero => remove it
|
|
672
|
+
if (this.hasVariable(letter) && pow.isZero()) {
|
|
673
|
+
this.removeVariable(letter)
|
|
674
|
+
return this
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
this.#literal[letter] = pow.clone()
|
|
679
|
+
|
|
680
|
+
return this
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Return the square root of a monom
|
|
685
|
+
*/
|
|
686
|
+
sqrt = (): this => {
|
|
687
|
+
if (this.isSquare()) {
|
|
688
|
+
this.#coefficient.sqrt()
|
|
689
|
+
for (const letter in this.#literal) {
|
|
690
|
+
this.#literal[letter].divide(2)
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// TODO: throw an error if the monom is not a square ? Or allow the result to be a monom with rational powers ?
|
|
695
|
+
return this
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Subtract multiple monoms
|
|
700
|
+
* @param M (Monom[]) The monoms to subtract
|
|
701
|
+
*/
|
|
702
|
+
subtract = (...M: InputAlgebra<Fraction>[]): this => {
|
|
703
|
+
for (const m of M) {
|
|
704
|
+
// If the value given is not a monom, create it.
|
|
705
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
706
|
+
|
|
707
|
+
if (this.isSameAs(mAsMonom)) {
|
|
708
|
+
if (this.isZero()) {
|
|
709
|
+
this.#cloneLiteral(mAsMonom)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
this.#coefficient.add(mAsMonom.clone().coefficient.opposite())
|
|
713
|
+
} else {
|
|
714
|
+
throw new MathError('Subtract: Is not similar: ' + mAsMonom.display)
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return this
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Getter helpers.
|
|
721
|
+
/**
|
|
722
|
+
* Get the variables letters
|
|
723
|
+
*/
|
|
724
|
+
get variables(): string[] {
|
|
725
|
+
// const M = this.clone().clean()
|
|
726
|
+
|
|
727
|
+
const L: string[] = []
|
|
728
|
+
Object.entries(this.literal).forEach(
|
|
729
|
+
([key, value]) => {
|
|
730
|
+
if (!value.isZero()) {
|
|
731
|
+
L.push(key)
|
|
732
|
+
}
|
|
733
|
+
})
|
|
734
|
+
L.sort()
|
|
735
|
+
return L
|
|
736
|
+
// return Object.keys(M.literal)
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Create a zero value monom
|
|
741
|
+
*/
|
|
742
|
+
zero = (): this => {
|
|
743
|
+
this.#coefficient = new Fraction().zero()
|
|
744
|
+
this.#literal = {}
|
|
745
|
+
return this
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
#cloneLiteral(inputStr: Monom) {
|
|
749
|
+
for (const k in inputStr.literal) {
|
|
750
|
+
this.#literal[k] = inputStr.literal[k].clone()
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
#evaluateAsNumeric = (values: literalType<number | Fraction> | InputValue<Fraction>): number => {
|
|
755
|
+
let r = this.coefficient.value
|
|
756
|
+
|
|
757
|
+
if (typeof values === "number") {
|
|
758
|
+
const tmpValues: literalType<number> = {}
|
|
759
|
+
const key = this.variables[0]
|
|
760
|
+
tmpValues[key] = values
|
|
761
|
+
|
|
762
|
+
return this.#evaluateAsNumeric(tmpValues)
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (values instanceof Fraction) {
|
|
766
|
+
const tmpValues: literalType<number> = {}
|
|
767
|
+
tmpValues[this.variables[0]] = new Fraction(values).value
|
|
768
|
+
return this.#evaluateAsNumeric(tmpValues)
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (typeof values === 'object') {
|
|
772
|
+
if (this.variables.length === 0) {
|
|
773
|
+
return this.coefficient.value
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
for (const L in this.#literal) {
|
|
777
|
+
const v = values[L]
|
|
778
|
+
|
|
779
|
+
if (v instanceof Fraction) {
|
|
780
|
+
r *= v.value ** (this.#literal[L].value)
|
|
781
|
+
} else {
|
|
782
|
+
r *= v ** (this.#literal[L].value)
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
return r
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
#format = (type: 'tex' | 'display' | 'plot'): string => {
|
|
791
|
+
let L = ''
|
|
792
|
+
const letters = Object.keys(this.#literal).sort()
|
|
793
|
+
|
|
794
|
+
for (const letter of letters) {
|
|
795
|
+
if (this.#literal[letter].isNotZero()) {
|
|
796
|
+
if (type === 'plot' && L !== '') { L += '*' }
|
|
797
|
+
L += letter
|
|
798
|
+
if (this.#literal[letter].isNotEqual(1)) {
|
|
799
|
+
L += type === 'tex'
|
|
800
|
+
? `^{ ${this.#literal[letter].asTfrac.tex} }`
|
|
801
|
+
: `^(${this.#literal[letter].display})`
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const coeffStr = type === 'tex' ? this.#coefficient.asFrac.tex : this.#coefficient.display
|
|
807
|
+
|
|
808
|
+
if (L === '') {
|
|
809
|
+
return this.#coefficient.value !== 0 ? coeffStr : '0'
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (this.#coefficient.value === 1) { return L }
|
|
813
|
+
if (this.#coefficient.value === -1) { return `-${L}` }
|
|
814
|
+
if (this.#coefficient.value === 0) { return '0' }
|
|
815
|
+
return type === 'plot' ? `${coeffStr}*${L}` : `${coeffStr}${L}`
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
#getLiteralDividers(arr: literalType<Fraction>[], letter: string): literalType<Fraction>[] {
|
|
819
|
+
const tmpList: Record<string, Fraction>[] = []
|
|
820
|
+
|
|
821
|
+
// Be default, this.literal[letter] should be a rational number.
|
|
822
|
+
for (let d = 0; d <= this.literal[letter].value; d++) {
|
|
823
|
+
if (arr.length === 0) {
|
|
824
|
+
const litt: literalType<Fraction> = {}
|
|
825
|
+
litt[letter] = new Fraction(d)
|
|
826
|
+
tmpList.push(litt)
|
|
827
|
+
} else {
|
|
828
|
+
for (const item of arr) {
|
|
829
|
+
const litt: literalType<Fraction> = {}
|
|
830
|
+
for (const currentLetter in item) {
|
|
831
|
+
litt[currentLetter] = item[currentLetter]
|
|
832
|
+
}
|
|
833
|
+
litt[letter] = new Fraction(d)
|
|
834
|
+
tmpList.push(litt)
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return tmpList
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
#shutingYardAddToken = (stack: Monom[], element: Token): void => {
|
|
842
|
+
let q1: Monom, q2: Monom, m: Monom, letter: string, pow: Fraction
|
|
843
|
+
|
|
844
|
+
if (element.tokenType === ShutingyardType.COEFFICIENT) {
|
|
845
|
+
stack.push(new Monom(new Fraction(element.token)))
|
|
846
|
+
|
|
847
|
+
} else if (element.tokenType === ShutingyardType.VARIABLE) {
|
|
848
|
+
const M = new Monom().one()
|
|
849
|
+
M.setLetter(element.token, 1)
|
|
850
|
+
stack.push(M.clone())
|
|
851
|
+
|
|
852
|
+
} else if (element.tokenType === ShutingyardType.OPERATION) {
|
|
853
|
+
switch (element.token) {
|
|
854
|
+
case '-':
|
|
855
|
+
// this should only happen for negative powers or for negative coefficient.
|
|
856
|
+
q2 = (stack.pop()) ?? new Monom().zero()
|
|
857
|
+
q1 = (stack.pop()) ?? new Monom().zero()
|
|
858
|
+
|
|
859
|
+
stack.push(q1.subtract(q2))
|
|
860
|
+
|
|
861
|
+
break
|
|
862
|
+
case '*':
|
|
863
|
+
// Get the last element in the stack
|
|
864
|
+
q2 = (stack.pop()) ?? new Monom().one()
|
|
865
|
+
q1 = (stack.pop()) ?? new Monom().one()
|
|
866
|
+
|
|
867
|
+
stack.push(q1.multiply(q2))
|
|
868
|
+
break
|
|
869
|
+
case '/':
|
|
870
|
+
// Get the last element in the stack
|
|
871
|
+
q2 = (stack.pop()) ?? new Monom().one()
|
|
872
|
+
q1 = (stack.pop()) ?? new Monom().one()
|
|
873
|
+
|
|
874
|
+
stack.push(q1.divide(q2))
|
|
875
|
+
break
|
|
876
|
+
case '^': {
|
|
877
|
+
// get the two last elements in the stack
|
|
878
|
+
const poppedCoefficient = stack.pop()?.coefficient
|
|
879
|
+
pow = poppedCoefficient ?? new Fraction().one()
|
|
880
|
+
m = stack.pop() ?? new Monom().one()
|
|
881
|
+
|
|
882
|
+
letter = m.variables[0]
|
|
883
|
+
|
|
884
|
+
if (letter) {
|
|
885
|
+
m.setLetter(letter, pow)
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
stack.push(m)
|
|
889
|
+
// this.multiply(m.clone())
|
|
890
|
+
break
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
#shutingYardToReducedMonom = (inputStr: string): this => {
|
|
897
|
+
// Get the RPN array of the current expression
|
|
898
|
+
let SY: ShutingYard
|
|
899
|
+
try {
|
|
900
|
+
SY = new ShutingYard().parse(inputStr)
|
|
901
|
+
} catch (e) {
|
|
902
|
+
throw new ParseError(`Cannot parse "${inputStr}" as a Monom`, {cause: e})
|
|
903
|
+
}
|
|
904
|
+
const rpn: { token: string, tokenType: ShutingyardType }[] = SY.rpn
|
|
905
|
+
|
|
906
|
+
const stack: Monom[] = []
|
|
907
|
+
|
|
908
|
+
if (rpn.length === 0) {
|
|
909
|
+
this.zero()
|
|
910
|
+
return this
|
|
911
|
+
} else if (rpn.length === 1) {
|
|
912
|
+
const element = rpn[0]
|
|
913
|
+
|
|
914
|
+
this.one()
|
|
915
|
+
if (element.tokenType === ShutingyardType.COEFFICIENT) {
|
|
916
|
+
this.coefficient = new Fraction(element.token)
|
|
917
|
+
} else if (element.tokenType === ShutingyardType.VARIABLE) {
|
|
918
|
+
this.setLetter(element.token, 1)
|
|
919
|
+
}
|
|
920
|
+
return this
|
|
921
|
+
} else {
|
|
922
|
+
// Reset the monom
|
|
923
|
+
for (const element of rpn) {
|
|
924
|
+
this.#shutingYardAddToken(stack, element)
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
this.one()
|
|
929
|
+
this.multiply(stack[0])
|
|
930
|
+
return this
|
|
931
|
+
}
|
|
932
|
+
}
|