pimath 0.1.39 → 0.1.40

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