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,24 @@
1
+ import type {IExpressionMultiply, IPiMathObject} from "../pimath.interface"
2
+
3
+ // TODO: create other operation_** to make things more generic !
4
+ export function operation_pow<T extends IPiMathObject<T> & IExpressionMultiply<T>>(item: T, value: number): T {
5
+ // TODO: Implement the operation_pow to other classes
6
+ if (!Number.isSafeInteger(value)) {
7
+ throw new Error('Can only raise item by an integer')
8
+ }
9
+
10
+ if (value < 0) {
11
+ throw new Error('Can only raise item by a positive integer')
12
+ }
13
+
14
+ if (value === 0) {
15
+ return item.one()
16
+ }
17
+
18
+ const P = item.clone()
19
+ for (let i = 1; i < value; i++) {
20
+ item.multiply(P)
21
+ }
22
+
23
+ return item
24
+ }
@@ -0,0 +1,668 @@
1
+ import type {
2
+ FACTOR_TABLE_OF_SIGNS,
3
+ IAlgebra,
4
+ IExpression,
5
+ InputAlgebra,
6
+ InputValue,
7
+ IPiMathObject,
8
+ ISolution,
9
+ literalType,
10
+ POLYFACTOR_TABLE_OF_SIGNS,
11
+ TABLE_OF_SIGNS_VALUES
12
+ } from "../pimath.interface"
13
+ import {Fraction} from "../coefficients"
14
+ import {Factor, FACTOR_DISPLAY} from "./factor"
15
+ import {Polynom} from "./polynom"
16
+ import type {Solution} from "../analyze/solution"
17
+
18
+
19
+ // PolyFactor is a class that represents a polynomial in factored form.
20
+ export class PolyFactor implements IPiMathObject<PolyFactor>,
21
+ IExpression<PolyFactor>,
22
+ IAlgebra<PolyFactor> {
23
+
24
+ #displayMode: FACTOR_DISPLAY = FACTOR_DISPLAY.POWER
25
+ #factors: Factor[] = []
26
+
27
+ constructor(...values: (Factor | PolyFactor)[]) {
28
+ this.parse(...values)
29
+ return this
30
+ }
31
+
32
+ public parse(...values: (Factor | PolyFactor)[]): this {
33
+ // Init the factors list
34
+ this.#factors = []
35
+
36
+ // Nothing to create
37
+ if (values.length === 0) {
38
+ return this
39
+ }
40
+
41
+ values.forEach(value => {
42
+ if (value instanceof PolyFactor) {
43
+ this.#factors.push(...value.factors.map(f => f.clone()))
44
+ } else {
45
+ this.#factors.push(new Factor(value))
46
+ }
47
+ })
48
+
49
+ return this
50
+ }
51
+
52
+ public clone(): PolyFactor {
53
+ return new PolyFactor(...this.#factors.map(f => f.clone()))
54
+ }
55
+
56
+ public get tex(): string {
57
+ const {num, den} = this.#extractNumeratorAndDenominator()
58
+
59
+ if (den.length === 0) {
60
+ if (num.length === 1) {
61
+ return num[0].asSingle.tex
62
+ }
63
+
64
+ return num.map(f => f.tex).join("")
65
+ }
66
+
67
+ // There is a numerator and a denominator
68
+ const numTeX = num.length === 1 ? num[0].asSingle.tex : num.map(f => f.tex).join("")
69
+ const denTeX = den.length === 1 ? den[0].asSingle.tex : den.map(f => f.tex).join("")
70
+
71
+ return `\\frac{ ${numTeX} }{ ${denTeX} }`
72
+
73
+ }
74
+
75
+ public get display(): string {
76
+ const {num, den} = this.#extractNumeratorAndDenominator()
77
+
78
+ if (den.length === 0) {
79
+ if (num.length === 1) {
80
+ return num[0].asSingle.display
81
+ }
82
+
83
+ return num.map((f, index) =>
84
+ index === 0 && f.polynom.monoms.length === 1 ? f.asSingle.display : f.display
85
+ ).join("")
86
+ }
87
+
88
+ // There is a numerator and a denominator
89
+ const numTeX = num.length === 1 ? num[0].asSingle.display : num.map(f => f.display).join("")
90
+ const denTeX = den.length === 1 ? den[0].asSingle.display : den.map(f => f.display).join("")
91
+
92
+ return `(${numTeX})/(${denTeX})`
93
+
94
+ }
95
+
96
+ static #gcdWith(PF1: PolyFactor, PF2: PolyFactor): PolyFactor {
97
+ // Get all factors of the two polynomials
98
+ // Find the common factors
99
+ const factors1 = keyFactors(PF1)
100
+
101
+ const factors2 = keyFactors(PF2)
102
+
103
+ const common = Object.keys(factors1).filter(k => Object.hasOwn(factors2, k))
104
+
105
+ // Find the minimum power of the common factors
106
+ const factors = common.map(k => {
107
+ const power = factors1[k].reduce((acc, f) => acc.add(f.power), new Fraction('0'))
108
+ const power2 = factors2[k].reduce((acc, f) => acc.add(f.power), new Fraction('0'))
109
+ return new Factor(k, Fraction.min(power, power2))
110
+ })
111
+
112
+ return new PolyFactor(...factors)
113
+ }
114
+
115
+ static #lcmWith(PF1: PolyFactor, PF2: PolyFactor): PolyFactor {
116
+
117
+ const factors1 = keyFactors(PF1)
118
+
119
+ const factors2 = keyFactors(PF2)
120
+
121
+ const common = [...new Set([...Object.keys(factors1), ...Object.keys(factors2)])]
122
+
123
+ // Find the maximum power of the common factors
124
+ const factors = common.map(k => {
125
+ const power =
126
+ Object.hasOwn(factors1, k) ?
127
+ factors1[k].reduce((acc, f) => acc.add(f.power), new Fraction('0')) :
128
+ new Fraction(0)
129
+ const power2 = Object.hasOwn(factors2, k) ?
130
+ factors2[k].reduce((acc, f) => acc.add(f.power), new Fraction('0')) :
131
+ new Fraction(0)
132
+ return new Factor(k, Fraction.max(power, power2))
133
+ })
134
+
135
+ return new PolyFactor(...factors)
136
+ }
137
+
138
+ public static gcd(...values: PolyFactor[]): PolyFactor {
139
+ if (values.length === 0) {
140
+ return new PolyFactor().one()
141
+ }
142
+ if (values.length === 1) {
143
+ return values[0]
144
+ }
145
+ if (values.length === 2) {
146
+ return PolyFactor.#gcdWith(values[0], values[1])
147
+ }
148
+
149
+ // values is not undefined,
150
+ let PF = values[0]
151
+ values.shift()
152
+ values.forEach(value => PF = PolyFactor.#gcdWith(PF, value))
153
+
154
+ return PF
155
+ }
156
+
157
+ public static lcm(...values: PolyFactor[]): PolyFactor {
158
+ if (values.length === 0) {
159
+ return new PolyFactor().one()
160
+ }
161
+ if (values.length === 1) {
162
+ return values[0]
163
+ }
164
+
165
+ let PF = values[0]
166
+ values.shift()
167
+ values.forEach(value => PF = PolyFactor.#lcmWith(PF, value))
168
+ return PF
169
+ }
170
+
171
+ public add(...values: PolyFactor[]): this {
172
+ // Adding two (or more) polyfactors:
173
+ // if both are numerators only, use the common polynom
174
+ // if there are denominators, multiply every polyfactors to match the lcm polyfactor.
175
+
176
+ const numerators: PolyFactor[] = [this.numerator, ...values.map(x => x.numerator)]
177
+ const denominators: PolyFactor[] = [this.denominator, ...values.map(x => x.denominator)]
178
+
179
+ let denominator: PolyFactor | undefined
180
+ if (denominators.some(d => d.factors.length > 0)) {
181
+ // At least one of the denominators is not empty.
182
+ const lcm = PolyFactor.lcm(...denominators)
183
+
184
+ // Multiply each numerators by the complementary.
185
+ numerators.forEach((n, index) => {
186
+ n.multiply(lcm.clone().divide(denominators[index]))
187
+ })
188
+
189
+ // Set the common denominator to the lcm PolyFctor
190
+ denominator = lcm
191
+ }
192
+
193
+ // Now, every polyfactor should have a common denominator. Just add the numerators.
194
+ const gcd = PolyFactor.gcd(...numerators)
195
+ const remainingPolynom = new Polynom(0)
196
+ .add(...numerators.map(pf => {
197
+ return pf
198
+ .divide(gcd).reduce()
199
+ .develop() // should be a polyfactor with one factor, with a power of 1
200
+ .factors[0]
201
+ .polynom
202
+ })
203
+ ).reduce()
204
+
205
+ this.#factors = [
206
+ ...gcd.factors,
207
+ new Factor(remainingPolynom)
208
+ ]
209
+
210
+ if (denominator) {
211
+ this.divide(denominator)
212
+ }
213
+
214
+ // Remove all factors with a power of zero
215
+ this.#factors = this.#factors.filter(x => !x.power.isZero())
216
+
217
+ return this
218
+ }
219
+
220
+ get asPower(): this {
221
+ this.#displayMode = FACTOR_DISPLAY.POWER
222
+ return this
223
+ }
224
+
225
+ get asRoot(): this {
226
+ this.#displayMode = FACTOR_DISPLAY.ROOT
227
+ return this
228
+ }
229
+
230
+ public degree(letter?: string): Fraction {
231
+ return this.#factors.reduce((acc, f) => acc.add(f.degree(letter)), new Fraction('0'))
232
+ }
233
+
234
+ get denominator(): PolyFactor {
235
+ return new PolyFactor(...this.#factors
236
+ .filter(f => f.power.isNegative())
237
+ .map(f => f.clone().inverse())
238
+ )
239
+ }
240
+
241
+ public derivative(): this {
242
+ // (fgh)' = f'gh+fg'h+fgh'
243
+ // dPF = [f'gh, fg'h, fgh']
244
+ const dPF: PolyFactor[] = []
245
+
246
+ const length = this.#factors.length
247
+
248
+ for (let i = 0; i < length; i++) {
249
+ // unchanged factors
250
+ const factors = this.#factors.slice()
251
+ // derivative factor
252
+ const derivativeFactor = factors.splice(i, 1)[0].derivative()
253
+ // Add the product of factors
254
+ dPF.push(
255
+ new PolyFactor(...factors, ...derivativeFactor))
256
+ }
257
+
258
+ // Reduce the polyFactors
259
+ dPF.forEach(pf => pf.reduce())
260
+
261
+ const first = dPF.shift()
262
+ if (first !== undefined) {
263
+ this.#factors = first.factors
264
+ }
265
+
266
+ // Add each factors together.
267
+ return this.add(...dPF)
268
+ }
269
+
270
+ public develop(): PolyFactor {
271
+ // Develop each factor and multiply them
272
+ const N = new Polynom('1')
273
+ const D = new Polynom('1')
274
+
275
+ this.numerator.factors.forEach(f => {
276
+ N.multiply(f.develop())
277
+ })
278
+ this.denominator.factors.forEach(f => {
279
+ D.multiply(f.develop())
280
+ })
281
+
282
+ return new PolyFactor().fromPolynom(N, D)
283
+ }
284
+
285
+ public divide(value: PolyFactor): this {
286
+ this.#factors = this.#factors.concat(value.clone().factors.map(f => f.inverse()))
287
+ return this
288
+ }
289
+
290
+ public evaluate(values: InputValue<Fraction> | literalType<number | Fraction>, asNumeric?: boolean): number | Fraction {
291
+ if (asNumeric) {
292
+ return this.#factors
293
+ .reduce((acc, f) => acc * (f.evaluate(values, asNumeric) as number), 1)
294
+ }
295
+
296
+ return this.#factors
297
+ .reduce((acc, f) => acc.multiply(f.evaluate(values)), new Fraction('1'))
298
+ }
299
+
300
+ public factorize(letter?: string): PolyFactor {
301
+ // Go through each factors.
302
+ // If it can be factorized, remove the factor (set its power to zero) and insert the new factors instead.
303
+ const newFactors: Factor[] = []
304
+
305
+ this.#factors.forEach(factor => {
306
+ const factors = factor.polynom.factorize(letter)
307
+ if (factors.length > 1) {
308
+ const pow = factor.power.clone()
309
+ newFactors.push(...factors.map(x => new Factor(x, pow)))
310
+ } else {
311
+ newFactors.push(factor.clone())
312
+ }
313
+ })
314
+
315
+ const result = new PolyFactor(...newFactors)
316
+ const numerator = result.numerator.reduce()
317
+ const denominator = result.denominator.reduce()
318
+
319
+ return numerator.divide(denominator)
320
+ }
321
+
322
+ public get factors(): Factor[] {
323
+ return this.#factors
324
+ }
325
+
326
+ public set factors(value: Factor[]) {
327
+ this.#factors = value
328
+ }
329
+
330
+ public fromPolynom(numerator: InputAlgebra<Polynom>, denominator?: InputAlgebra<Polynom>): this {
331
+ // fromPolynom loads the numerator and denominator as is, without factorizing !
332
+ this.#factors = [new Factor(new Polynom(numerator))]
333
+
334
+ if (denominator) {
335
+ const polynom = new Polynom(denominator)
336
+
337
+ if (polynom.isOne()) {
338
+ return this
339
+ }
340
+ if (polynom.isZero()) {
341
+ throw new Error("Cannot divide by zero")
342
+ }
343
+ this.#factors.push(new Factor(polynom, -1))
344
+ }
345
+ // // Find all factors from a polynom
346
+ // this.#factors = new Polynom(numerator)
347
+ // .factorize(letter)
348
+ // .map(value => new Factor(value))
349
+ //
350
+ // if (denominator) {
351
+ // new Polynom(denominator)
352
+ // .factorize(letter)
353
+ // .forEach(value => this.#factors.push(new Factor(value, -1)))
354
+ // }
355
+
356
+ return this
357
+ }
358
+
359
+ /**
360
+ * Get the roots of the PolyFactor.
361
+ */
362
+ public getRoots(): Solution[] {
363
+ return []
364
+ }
365
+
366
+ public getZeroes(): ISolution[] {
367
+ // Calculate the list of roots (ordered, unique)
368
+ const roots: ISolution[] = ([] as ISolution[])
369
+ .concat(...this.#factors.map(x => x.polynom.getZeroes()))
370
+ // .concat(...tos.map(x => x.roots))
371
+
372
+ // Sort the values.
373
+ roots.sort((a, b) => a.value - b.value)
374
+ // Remove duplicates.
375
+ return roots
376
+ .filter((value, index, self) =>
377
+ index === self.findIndex((t) =>
378
+ t.value === value.value
379
+ )
380
+ )
381
+ }
382
+
383
+ public hasVariable(letter: string): boolean {
384
+ return this.#factors.some(f => f.hasVariable(letter))
385
+ }
386
+
387
+ public inverse(): this {
388
+ this.#factors = this.#factors.map(f => f.inverse())
389
+ return this
390
+ }
391
+
392
+ public isEqual(value: PolyFactor): boolean {
393
+ const gcd = PolyFactor.gcd(this, value)
394
+
395
+ const PF1 = this.clone().divide(gcd).reduce()
396
+ const PF2 = value.clone().divide(gcd).reduce()
397
+
398
+ return PF1.isOne() && PF2.isOne()
399
+ }
400
+
401
+ public isOne(): boolean {
402
+ return this.#factors.every(f => f.isOne())
403
+ }
404
+
405
+ public isZero(): boolean {
406
+ return this.#factors.every(f => f.isZero())
407
+ }
408
+
409
+ public multiply(...values: PolyFactor[]): this {
410
+ values.forEach(value => {
411
+ this.#factors = this.#factors.concat(value.clone().factors)
412
+ })
413
+
414
+ return this
415
+ }
416
+
417
+ get numerator(): PolyFactor {
418
+ return new PolyFactor(...this.#factors.filter(f => f.power.isPositive()))
419
+ }
420
+
421
+ public one(): this {
422
+ this.#factors = [new Factor('1', '1')]
423
+ return this
424
+ }
425
+
426
+ public opposite(): this {
427
+ // Add the -1 factor or remove if it exists
428
+ const index = this.#factors.findIndex(f => f.display === '(-1)')
429
+
430
+ if (index >= 0) {
431
+ this.#factors.splice(index, 1)
432
+ } else {
433
+ this.#factors.push(new Factor('-1', '1'))
434
+ }
435
+
436
+ return this
437
+ }
438
+
439
+ public pow(value: number | Fraction): this {
440
+ this.#factors = this.#factors.map(f => f.pow(value))
441
+ return this
442
+ }
443
+
444
+ public primitive(): PolyFactor {
445
+ throw new Error("Method not implemented.")
446
+ }
447
+
448
+ public reduce(): this {
449
+ // Regroup the factors by their base
450
+ const factors = keyFactors(this)
451
+
452
+ // Multiply the factors of the same base
453
+ this.#factors = Object.values(factors)
454
+ .map(f => {
455
+ const base = f[0].polynom
456
+ const power = f.reduce((acc, f) => acc.add(f.power), new Fraction('0'))
457
+ return new Factor(base, power.reduce())
458
+ })
459
+ .filter(f => !f.power.isZero())
460
+
461
+ return this
462
+ }
463
+
464
+ public root(value: number): this {
465
+ this.#factors = this.#factors.map(f => f.root(value))
466
+ return this
467
+ }
468
+
469
+ /**
470
+ * Reoarder the factors using :
471
+ * 1. number of monoms
472
+ * 2. degree of polynom
473
+ * 3. power of polyfactor
474
+ */
475
+ public sort(letter?: string): this {
476
+ this.#factors.sort((a, b) => {
477
+ // If the compare powers are opposite, the negative power goes to the end.
478
+ const aPower = a.power.value
479
+ const bPower = b.power.value
480
+ if (aPower * bPower < 0) {
481
+ return -aPower
482
+ }
483
+
484
+
485
+ // Monom length
486
+ const aLength = a.polynom.monoms.length
487
+ const bLength = b.polynom.monoms.length
488
+ if (aLength !== bLength) {
489
+ return aLength - bLength
490
+ }
491
+
492
+ // The monom length are the same, check the polynom degree.
493
+ const aDegree = a.polynom.degree(letter).value
494
+ const bDegree = b.polynom.degree(letter).value
495
+ if (aDegree !== bDegree) {
496
+ return aDegree - bDegree
497
+ }
498
+
499
+ // The power of the PolyFactor
500
+ if (aPower !== bPower) {
501
+ return aPower - bPower
502
+ }
503
+
504
+ return a.degree().isLeq(b.degree()) ? -1 : 1
505
+ })
506
+
507
+ return this
508
+ }
509
+
510
+ public sqrt(): this {
511
+ this.#factors = this.#factors.map(f => f.sqrt())
512
+ return this
513
+ }
514
+
515
+ public subtract(...values: PolyFactor[]): this {
516
+ return this.add(...values.map(f => f.opposite()))
517
+ }
518
+
519
+ public tableOfSigns(): POLYFACTOR_TABLE_OF_SIGNS {
520
+ // Calculate the table of signs for each factor
521
+ const roots = this.getZeroes()
522
+ const roots_key = roots.map(x => x.value)
523
+
524
+ // Get the table of signs of every factors
525
+
526
+
527
+ // These signs are NOT aligned
528
+ const factors: FACTOR_TABLE_OF_SIGNS[] = this.factorize().factors
529
+ .map(factor => {
530
+ return {factor: new Factor(factor), ...factor.tableOfSigns()}
531
+ })
532
+
533
+ // Build the table of signs with extra roots for each factors.
534
+ factors.forEach(item => {
535
+ // Create the new signs row
536
+ const empty_signs: TABLE_OF_SIGNS_VALUES[] = new Array(2 * roots.length + 1).fill('') as unknown as TABLE_OF_SIGNS_VALUES[]
537
+
538
+ let sign = item.signs.shift() as unknown as TABLE_OF_SIGNS_VALUES
539
+ let root = item.roots.shift()
540
+
541
+ const aligned_signs = empty_signs.map((_sign, index) => {
542
+ if (index % 2 === 0) {
543
+ return sign
544
+ }
545
+
546
+ // The sign for this indexed root is a t(ab)
547
+ if (root === undefined || root.value !== roots_key[(index - 1) / 2]) {
548
+ return 't'
549
+ }
550
+
551
+ // The indexed root is the new root
552
+ const rootSign = item.signs.shift() as unknown as TABLE_OF_SIGNS_VALUES
553
+
554
+ // Make the new signs.
555
+ sign = item.signs.shift() as unknown as TABLE_OF_SIGNS_VALUES
556
+ root = item.roots.shift()
557
+ return rootSign
558
+ })
559
+
560
+ // Set the roots for this item to all roots
561
+ item.roots = roots
562
+ item.signs = aligned_signs
563
+ })
564
+
565
+ // Build the table of signs with extra roots : reault line
566
+ const signs: TABLE_OF_SIGNS_VALUES[] = factors
567
+ .map((item) => [...item.signs])
568
+ .reduce<TABLE_OF_SIGNS_VALUES[]>((a, b) => {
569
+ if (a.length === 0) {
570
+ return b
571
+ }
572
+
573
+ // a and b are "not aligned"
574
+ b.forEach((value, index) => {
575
+ // Case of a zero, invalid or tab value
576
+ // tab < zero < defence
577
+ switch (value) {
578
+ case "d":
579
+ a[index] = "d"
580
+ break
581
+ case "z":
582
+ a[index] = a[index] === "d" ? "d" : "z"
583
+ break
584
+ case "h":
585
+ a[index] = "h"
586
+ break
587
+ case "-":
588
+ a[index] = a[index] === "h" ? "h" : a[index] === "-" ? "+" : "-"
589
+ break
590
+ }
591
+ })
592
+
593
+ return a
594
+ }, [])
595
+
596
+ return {signs, roots, factors}
597
+ }
598
+
599
+ public get variables(): string[] {
600
+ return this.#factors
601
+ .reduce((acc: string[], f: Factor) => acc.concat(f.variables), [])
602
+ }
603
+
604
+ public zero(): this {
605
+ this.#factors = [new Factor('0', '1')]
606
+ return this
607
+ }
608
+
609
+ #extractNumeratorAndDenominator() {
610
+ let num: Factor[],
611
+ den: Factor[] = []
612
+
613
+ if (this.#displayMode === FACTOR_DISPLAY.ROOT) {
614
+ // the power are positive integers
615
+ num = this.numerator.factors
616
+ den = this.denominator.factors
617
+ } else {
618
+ num = this.#factors
619
+ }
620
+
621
+ // There is no factor
622
+ if (num.length === 0) {
623
+ num = [new Factor('1')]
624
+ }
625
+ return {num, den}
626
+ }
627
+
628
+ }
629
+
630
+ function keyFactors(value: PolyFactor): Record<string, Factor[]> {
631
+ const k_numerator = new Fraction().one()
632
+ const k_denominator = new Fraction().one()
633
+
634
+ const kF = value.factors
635
+ .reduce((acc: Record<string, Factor[]>, f) => {
636
+ // It's only a value
637
+ if (f.polynom.degree().isZero()) {
638
+ if (f.power.isPositive()) {
639
+ k_numerator.multiply(f.polynom.monoms[0].coefficient)
640
+ } else {
641
+ k_denominator.multiply(f.polynom.monoms[0].coefficient)
642
+ }
643
+
644
+ return acc
645
+ }
646
+
647
+ // It's a polynom
648
+ const base = f.polynom.display
649
+ if (Object.hasOwn(acc, base)) {
650
+ acc[base].push(f)
651
+ } else {
652
+ acc[base] = [f]
653
+ }
654
+
655
+ return acc
656
+ }, {})
657
+
658
+
659
+ const {numerator, denominator} = k_numerator.divide(k_denominator).reduce()
660
+ if(numerator!==1){
661
+ kF[numerator.toString()] = [new Factor(numerator, 1)]
662
+ }
663
+ if(denominator!==1){
664
+ kF[denominator.toString()] = [new Factor(denominator, -1)]
665
+ }
666
+
667
+ return kF
668
+ }