pimath 0.1.40 → 0.2.1

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 (99) hide show
  1. package/dist/pimath.js +3106 -2873
  2. package/dist/pimath.js.map +1 -1
  3. package/package.json +13 -11
  4. package/src/algebra/equation.ts +113 -111
  5. package/src/algebra/equationSolver.ts +69 -120
  6. package/src/algebra/factor.ts +6 -7
  7. package/src/algebra/linearSystem.ts +97 -46
  8. package/src/algebra/logicalset.ts +51 -52
  9. package/src/algebra/monom.ts +23 -61
  10. package/src/algebra/operations.ts +0 -1
  11. package/src/algebra/polyFactor.ts +5 -5
  12. package/src/algebra/polynom.ts +69 -216
  13. package/src/analyze/index.ts +4 -0
  14. package/src/analyze/solution.ts +92 -29
  15. package/src/analyze/tableOfSigns.ts +1 -1
  16. package/src/coefficients/fraction.ts +189 -149
  17. package/src/coefficients/index.ts +1 -1
  18. package/src/coefficients/root.ts +66 -19
  19. package/src/geometry/TupleN.ts +128 -0
  20. package/src/geometry/circle.ts +308 -238
  21. package/src/geometry/geomMath.ts +4 -3
  22. package/src/geometry/index.ts +1 -0
  23. package/src/geometry/line.ts +221 -245
  24. package/src/geometry/line3.ts +78 -73
  25. package/src/geometry/plane3.ts +64 -55
  26. package/src/geometry/point.ts +57 -19
  27. package/src/geometry/triangle.ts +376 -248
  28. package/src/geometry/vector.ts +113 -229
  29. package/src/index.ts +13 -12
  30. package/src/numeric.ts +6 -9
  31. package/src/pimath.interface.ts +30 -28
  32. package/src/randomization/algebra/rndPolynom.ts +29 -15
  33. package/src/randomization/coefficient/rndFraction.ts +3 -3
  34. package/src/randomization/geometry/rndLine.ts +8 -10
  35. package/src/randomization/random.ts +11 -13
  36. package/src/randomization/rndTypes.ts +16 -12
  37. package/types/algebra/equation.d.ts +18 -17
  38. package/types/algebra/equation.d.ts.map +1 -1
  39. package/types/algebra/equationSolver.d.ts +5 -4
  40. package/types/algebra/equationSolver.d.ts.map +1 -1
  41. package/types/algebra/factor.d.ts +1 -1
  42. package/types/algebra/factor.d.ts.map +1 -1
  43. package/types/algebra/linearSystem.d.ts +23 -6
  44. package/types/algebra/linearSystem.d.ts.map +1 -1
  45. package/types/algebra/logicalset.d.ts +1 -1
  46. package/types/algebra/logicalset.d.ts.map +1 -1
  47. package/types/algebra/monom.d.ts +1 -6
  48. package/types/algebra/monom.d.ts.map +1 -1
  49. package/types/algebra/operations.d.ts.map +1 -1
  50. package/types/algebra/polyFactor.d.ts +4 -4
  51. package/types/algebra/polyFactor.d.ts.map +1 -1
  52. package/types/algebra/polynom.d.ts +10 -7
  53. package/types/algebra/polynom.d.ts.map +1 -1
  54. package/types/analyze/index.d.ts +2 -0
  55. package/types/analyze/index.d.ts.map +1 -0
  56. package/types/analyze/solution.d.ts +14 -8
  57. package/types/analyze/solution.d.ts.map +1 -1
  58. package/types/coefficients/fraction.d.ts +14 -12
  59. package/types/coefficients/fraction.d.ts.map +1 -1
  60. package/types/coefficients/index.d.ts +1 -1
  61. package/types/coefficients/index.d.ts.map +1 -1
  62. package/types/coefficients/root.d.ts +3 -0
  63. package/types/coefficients/root.d.ts.map +1 -1
  64. package/types/geometry/TupleAbstract.d.ts +22 -0
  65. package/types/geometry/TupleAbstract.d.ts.map +1 -0
  66. package/types/geometry/TupleN.d.ts +24 -0
  67. package/types/geometry/TupleN.d.ts.map +1 -0
  68. package/types/geometry/circle.d.ts +26 -17
  69. package/types/geometry/circle.d.ts.map +1 -1
  70. package/types/geometry/geomMath.d.ts +2 -1
  71. package/types/geometry/geomMath.d.ts.map +1 -1
  72. package/types/geometry/index.d.ts.map +1 -1
  73. package/types/geometry/line.d.ts +21 -30
  74. package/types/geometry/line.d.ts.map +1 -1
  75. package/types/geometry/line3.d.ts +19 -19
  76. package/types/geometry/line3.d.ts.map +1 -1
  77. package/types/geometry/matrix.d.ts +11 -11
  78. package/types/geometry/plane3.d.ts +10 -10
  79. package/types/geometry/plane3.d.ts.map +1 -1
  80. package/types/geometry/point.d.ts +11 -6
  81. package/types/geometry/point.d.ts.map +1 -1
  82. package/types/geometry/triangle.d.ts +68 -23
  83. package/types/geometry/triangle.d.ts.map +1 -1
  84. package/types/geometry/vector.d.ts +24 -44
  85. package/types/geometry/vector.d.ts.map +1 -1
  86. package/types/index.d.ts +5 -4
  87. package/types/index.d.ts.map +1 -1
  88. package/types/numeric.d.ts.map +1 -1
  89. package/types/pimath.interface.d.ts +18 -24
  90. package/types/pimath.interface.d.ts.map +1 -1
  91. package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
  92. package/types/randomization/coefficient/rndFraction.d.ts +1 -1
  93. package/types/randomization/coefficient/rndFraction.d.ts.map +1 -1
  94. package/types/randomization/geometry/rndLine.d.ts.map +1 -1
  95. package/types/randomization/random.d.ts +3 -2
  96. package/types/randomization/random.d.ts.map +1 -1
  97. package/types/randomization/rndTypes.d.ts +15 -10
  98. package/types/randomization/rndTypes.d.ts.map +1 -1
  99. package/src/coefficients/nthRoot.ts +0 -149
@@ -1,11 +1,12 @@
1
- import type {InputValue, ISolution} from "../pimath.interface"
1
+ import type {InputValue} from "../pimath.interface"
2
2
  import type {Polynom} from "./polynom"
3
3
  import {Fraction} from "../coefficients"
4
4
  import {Numeric} from "../numeric"
5
5
  import type {Equation} from "./equation"
6
+ import {Solution} from "../analyze"
6
7
 
7
8
  export class EquationSolver {
8
- #bissectionCompexityCounter: number
9
+ _: number
9
10
  #bissectionDeltaX: number
10
11
  readonly #leftPolynom: Polynom
11
12
  readonly #variable: string
@@ -13,18 +14,21 @@ export class EquationSolver {
13
14
  constructor(left: Polynom | Equation, right?: Polynom, variable = "x") {
14
15
  this.#variable = variable
15
16
  this.#bissectionDeltaX = 1e-4
16
- this.#bissectionCompexityCounter = 0
17
+ this._ = 0
17
18
 
19
+ // do this to avoid importing Polynom or Equation
18
20
  if (Object.hasOwn(left, 'moveLeft')) {
19
21
  const equ = left as Equation
20
22
  this.#leftPolynom = equ.left.clone().subtract(equ.right)
21
23
  } else {
22
24
  this.#leftPolynom = (left as Polynom).clone().subtract(right ?? 0)
23
25
  }
26
+
27
+ return this
24
28
  }
25
29
 
26
- get bissectionCompexityCounter(){
27
- return this.#bissectionCompexityCounter
30
+ get bissectionComplexityCounter() {
31
+ return this._
28
32
  }
29
33
 
30
34
  get bissectionDeltaX() {
@@ -35,7 +39,7 @@ export class EquationSolver {
35
39
  this.#bissectionDeltaX = value
36
40
  }
37
41
 
38
- public solve(): ISolution[] {
42
+ public solve(): Solution[] {
39
43
  const degree = this.#leftPolynom.degree().value
40
44
 
41
45
  if (degree === 0) {
@@ -51,63 +55,58 @@ export class EquationSolver {
51
55
  }
52
56
 
53
57
  // Try to solve by factorization -> exact solutions.
54
- const {solutions, polynom} = this.#solveByFactorization()
58
+ const {solutions, reminder} = this.#solveByFactorization()
55
59
 
56
60
  // The remaining polynom is of degree zero. No more solutions available.
57
- if (polynom.degree().isZero()) {
61
+ if (reminder.degree().isZero()) {
58
62
  return solutions
59
63
  }
60
64
 
61
65
  // The remaining polyno is of degree one or two, but cannot be solved by factorization (!).
62
- if (polynom.degree().value <= 2) {
66
+ if (reminder.degree().value <= 2) {
63
67
  return solutions.concat(
64
- new EquationSolver(polynom.clone()).solve()
68
+ new EquationSolver(reminder.clone()).solve()
65
69
  )
66
70
  }
67
71
 
68
72
  // Use approximative solutions, using bissection algorithm.
69
- // TODO: doit gérer le fait que si on a trouvé des solutions, on peut réduire avant de faire la bissection
70
- this.#bissectionCompexityCounter = 0
73
+ this._ = 0
71
74
  return solutions.concat(
72
- this.#solveByBissection(polynom)
75
+ this.#solveByBissection(reminder)
73
76
  ).sort((a, b) => a.value - b.value)
74
77
  }
75
78
 
76
- public solveAsCardan(): ISolution[] {
79
+ public solveAsCardan(): Solution[] {
77
80
  if (this.#leftPolynom.degree().value !== 3) {
78
81
  throw new Error("The equation is not cubic.")
79
82
  }
80
83
  return this.#solveCubic_CardanFormula()
81
84
  }
82
85
 
83
- #makeApproximativeSolution(value: number, output?: { tex: string, display: string }): ISolution {
84
- return {
85
- variable: this.#variable,
86
- exact: false,
87
- value: +value.toFixed(10),
88
- tex: output?.tex ?? '',
89
- display: output?.display ?? ''
90
- }
86
+ #makeApproximativeSolution(value: number, output?: { tex: string, display: string }): Solution {
87
+ const sol = new Solution()
88
+
89
+ sol.exact = false
90
+ sol.tex = output?.tex ?? null
91
+ sol.display = output?.display ?? null
92
+ sol.fraction = new Fraction(value)
93
+ sol.fraction.exact = false
94
+ sol.variable = this.#variable
95
+
96
+ return sol
91
97
  }
92
98
 
93
- #makeSolution(value: InputValue<Fraction>): ISolution {
94
- if (value instanceof Fraction && value.isApproximative()) {
99
+ #makeSolution(value: InputValue<Fraction>): Solution {
100
+ if (value instanceof Fraction && !value.exact) {
95
101
  return this.#makeApproximativeSolution(value.value)
96
102
  }
97
103
 
98
- const fraction = new Fraction(value)
99
- return {
100
- variable: this.#variable,
101
- exact: fraction,
102
- value: fraction.value,
103
- tex: fraction.tex,
104
- display: fraction.display
105
- }
104
+ return Solution.fromFraction(value)
106
105
  }
107
106
 
108
107
  // Solve using bissection algorithm (approximative solution)
109
- #solveByBissection(polynom: Polynom): ISolution[] {
110
- const solutions: ISolution[] = []
108
+ #solveByBissection(polynom: Polynom): Solution[] {
109
+ const solutions: Solution[] = []
111
110
  const degree = polynom.degree().value
112
111
 
113
112
  // Calculate the Cauchy Bounds.
@@ -138,7 +137,6 @@ export class EquationSolver {
138
137
  }
139
138
  })
140
139
 
141
- console.log('COMPLEXITY: ', this.#bissectionCompexityCounter)
142
140
  return solutions
143
141
  }
144
142
 
@@ -153,7 +151,7 @@ export class EquationSolver {
153
151
 
154
152
  let mid: number
155
153
  while ((b - a) / 2 > this.#bissectionDeltaX) {
156
- this.#bissectionCompexityCounter++
154
+ this._++
157
155
 
158
156
  mid = (a + b) / 2
159
157
  const fmid = polynom.evaluate(mid, true) as number
@@ -216,14 +214,14 @@ export class EquationSolver {
216
214
  return couples
217
215
  }
218
216
 
219
- #solveByFactorization(): { solutions: ISolution[], polynom: Polynom } {
217
+ #solveByFactorization(): { solutions: Solution[], reminder: Polynom } {
220
218
  // Move everything to the left.
221
219
 
222
220
  // Get the polynom on the left (on the right, it's zero)
223
221
  const left = this.#leftPolynom.clone()
224
222
 
225
223
  // The solutions of the equation
226
- const solutions: ISolution[] = []
224
+ const solutions: Solution[] = []
227
225
 
228
226
  // multiply by the lcm of the denominators
229
227
  // to get rid of the fractions
@@ -275,24 +273,21 @@ export class EquationSolver {
275
273
  for (const s of solutions) {
276
274
  // all solutions are exact solutions.
277
275
  // skip the zero solutions if it exists.
278
- if ((s.exact as Fraction).isZero()) {
276
+ if (s.isZero()) {
279
277
  continue
280
278
  }
281
279
 
282
- // // if the solution is exact and is zero, it's already divided: skip it !
283
- // if (s.exact !== false && (s.exact as Fraction).isZero()) {
284
- // continue
285
- // }
280
+ // The divider polynom
281
+ const p = left.clone()
282
+ .fromCoefficients(s.fraction.denominator, -s.fraction.numerator)
286
283
 
287
- const p = left.clone().fromCoefficients(
288
- (s.exact as Fraction).denominator,
289
- -(s.exact as Fraction).numerator
290
- )
291
-
292
- // const p = this.#equation.clone().parse('x', (s.exact as Fraction).denominator, -(s.exact as Fraction).numerator)
284
+ // Reset the count
285
+ s.count = 0
293
286
 
287
+ // Divide as long it's dividable.
294
288
  while (left.isDividableBy(p)) {
295
289
  left.divide(p)
290
+ s.count++
296
291
  }
297
292
  }
298
293
 
@@ -301,7 +296,7 @@ export class EquationSolver {
301
296
  if (left.degree().isZero() || left.degree().value > 3) {
302
297
  // Tri des réponses
303
298
  solutions.sort((a, b) => a.value - b.value)
304
- return {solutions, polynom: left}
299
+ return {solutions, reminder: left}
305
300
  }
306
301
 
307
302
  // if the reduced polynom is of degree 1 or 2, we can solve it
@@ -312,11 +307,11 @@ export class EquationSolver {
312
307
  solutions: solutions
313
308
  .concat(solver.solve())
314
309
  .sort((a, b) => a.value - b.value),
315
- polynom: zeroPolynom
310
+ reminder: zeroPolynom
316
311
  }
317
312
  }
318
313
 
319
- #solveCubic_CardanFormula(): ISolution[] {
314
+ #solveCubic_CardanFormula(): Solution[] {
320
315
  // get the coefficients of the equation
321
316
  const left = this.#leftPolynom
322
317
 
@@ -353,10 +348,6 @@ export class EquationSolver {
353
348
  // delta = 0 : 2 real solutions
354
349
  // delta > 0 : 3 real solutions
355
350
  const delta = S.clone().pow(2).subtract(P.clone().multiply(4)).opposite()
356
- // console.log('an=', an.display, 'bn=', bn.display, 'cn=', cn.display)
357
- // console.log('p=', p.display, 'q=', q.display)
358
- // console.log('S=', S.display, 'P=', P.display)
359
- // console.log('delta=', delta.display)
360
351
 
361
352
  // if delta is negative, there is one real solution
362
353
  if (delta.isNegative()) {
@@ -406,7 +397,7 @@ export class EquationSolver {
406
397
  return []
407
398
  }
408
399
 
409
- #solveLinear(): ISolution[] {
400
+ #solveLinear(): Solution[] {
410
401
  // The equation is linear.
411
402
  const [a, b] = this.#leftPolynom.getCoefficients()
412
403
 
@@ -418,7 +409,7 @@ export class EquationSolver {
418
409
  ]
419
410
  }
420
411
 
421
- #solveQuadratic(): ISolution[] {
412
+ #solveQuadratic(): Solution[] {
422
413
 
423
414
  // The equation is quadratic.
424
415
  // We can solve it by isolating the variable.
@@ -453,7 +444,9 @@ export class EquationSolver {
453
444
 
454
445
  // Delta is zero, there is only one solution
455
446
  if (delta.isZero()) {
456
- return [this.#makeSolution(f1)]
447
+ const sol = this.#makeSolution(f1)
448
+ sol.count = 2
449
+ return [sol]
457
450
  }
458
451
 
459
452
  // delta is positive, there are two solutions
@@ -472,68 +465,24 @@ export class EquationSolver {
472
465
  return this.#solveQuadratic_Output(a, b, delta2)
473
466
  }
474
467
 
475
- #solveQuadratic_Output(a: Fraction, b: Fraction, delta: Fraction): ISolution[] {
468
+ #solveQuadratic_Output(a: Fraction, b: Fraction, delta: Fraction): Solution[] {
476
469
  // -b +/- sqrt(delta) / 2a
477
470
  // reduce the sqrt - extract pow.
478
-
479
- // Get the greatest square factor
480
- const deltaFactor: number = Numeric
481
- .dividers(delta.value)
482
- .filter(x => Math.sqrt(x) % 1 === 0)
483
- .map(x => Math.sqrt(x)).pop() ?? 1
484
-
485
- // Get the GCD of a, b, and the greatest delta factor.
486
- const gcd = Numeric.gcd(2 * a.value, b.value, deltaFactor) * (a.isNegative() ? -1 : 1)
487
-
488
- // Calculate the various values and transforming
489
- const b2 = b.clone().divide(gcd).opposite()
490
- const a2 = a.clone().divide(gcd).multiply(2)
491
- const deltaGcd = Math.abs(deltaFactor / gcd)
492
- const deltaTex = `${deltaFactor === 1 ? '' : deltaGcd + ' '}\\sqrt{ ${delta.clone().divide(deltaFactor ** 2).tex} }`
493
- const deltaDisplay = `${deltaFactor === 1 ? '' : deltaGcd}sqrt(${delta.clone().divide(deltaFactor ** 2).display})`
494
- // const deltaK1 = deltaFactor === 1 ? '-' : `-${deltaGcd} `
495
- // const deltaK2 = deltaFactor === 1 ? '+' : `+${deltaGcd} `
496
-
497
- function texOutput(a: string, b: string, sign: string, delta: string) {
498
- // (B+D)/A
499
- const B = b === '0' ? '' : b
500
- const S = (sign === '-' || B !== '') ? ` ${sign} ` : ''
501
-
502
- if (a === "1") {
503
- return `${B}${S}${delta}`
504
- }
505
- return `\\frac{ ${S}${S}${delta} }{ ${a} }`
506
- }
507
-
508
- function displayOutput(a: string, b: string, sign: string, delta: string) {
509
- // (B+D)/A
510
- const B = b === '0' ? '' : b
511
- const S = (sign === '-' || B !== '') ? sign : ''
512
-
513
-
514
- if (a === "1") {
515
- return `${B}${S}${delta}`
516
- }
517
- return `(${B}${S}${delta})/${a}`
518
- }
519
-
520
- const d = delta.value ** 0.5
521
- const f1 = (-b.value - d) / (2 * a.value)
522
- const f2 = (-b.value + d) / (2 * a.value)
523
-
524
- return [
525
- this.#makeApproximativeSolution(f1,
526
- {
527
- tex: texOutput(a2.tex, b2.tex, '-', deltaTex),
528
- display: displayOutput(a2.display, b2.display, '-', deltaDisplay),
529
- }
530
- ),
531
- this.#makeApproximativeSolution(f2,
532
- {
533
- tex: texOutput(a2.tex, b2.tex, '+', deltaTex),
534
- display: displayOutput(a2.display, b2.display, '+', deltaDisplay),
535
- }
536
- )
537
- ].sort((a, b) => a.value - b.value)
471
+ const a2 = a.clone().multiply(2)
472
+
473
+ const sol1 = new Solution()
474
+ sol1.fraction = b.clone().opposite().divide(a2.clone())
475
+ sol1.root.radical = delta.clone()
476
+ sol1.root.factor = new Fraction().one().divide(a2.clone())
477
+ sol1.exact = true
478
+
479
+ const sol2 = new Solution()
480
+ sol2.fraction = b.clone().opposite().divide(a2.clone())
481
+ sol2.root.radical = delta.clone()
482
+ sol2.root.factor = new Fraction().one().divide(a2.clone()).opposite()
483
+ sol2.exact = true
484
+
485
+ return [sol1, sol2]
486
+ .sort((a, b) => a.value - b.value)
538
487
  }
539
488
  }
@@ -4,7 +4,6 @@ import type {
4
4
  InputAlgebra,
5
5
  InputValue,
6
6
  IPiMathObject,
7
- ISolution,
8
7
  literalType,
9
8
  TABLE_OF_SIGNS
10
9
  } from "../pimath.interface"
@@ -22,7 +21,6 @@ export class Factor implements IPiMathObject<Factor>,
22
21
 
23
22
  constructor(value?: InputAlgebra<Polynom> | Factor, power?: InputValue<Fraction>) {
24
23
 
25
-
26
24
  if (value instanceof Factor) {
27
25
  this.#polynom = value.polynom.clone()
28
26
  this.#power = value.power.clone()
@@ -51,11 +49,6 @@ export class Factor implements IPiMathObject<Factor>,
51
49
  return new Factor(this)
52
50
  }
53
51
 
54
- public fromPolynom(polynom: InputValue<Polynom>): this {
55
- this.#polynom = new Polynom(polynom)
56
- this.#power = new Fraction(1)
57
- return this
58
- }
59
52
  public get tex(): string {
60
53
  const num = this.power.numerator
61
54
  const den = this.power.denominator
@@ -178,6 +171,12 @@ export class Factor implements IPiMathObject<Factor>,
178
171
  return (this.polynom.evaluate(values) as Fraction).pow(this.power)
179
172
  }
180
173
 
174
+ public fromPolynom(polynom: InputValue<Polynom>): this {
175
+ this.#polynom = new Polynom(polynom)
176
+ this.#power = new Fraction(1)
177
+ return this
178
+ }
179
+
181
180
  public hasVariable(letter: string): boolean {
182
181
  return this.polynom.hasVariable(letter)
183
182
  }
@@ -1,16 +1,19 @@
1
- import type {IAlgebra, IEquation, InputValue, IPiMathObject, ISolution, literalType} from "../pimath.interface"
1
+ import type {IAlgebra, IEquation, InputValue, IPiMathObject, literalType} from "../pimath.interface"
2
2
  import {Fraction} from "../coefficients"
3
3
  import {Equation} from "./equation"
4
4
  import {Monom} from "./monom"
5
5
  import {Polynom} from "./polynom"
6
+ import {Numeric} from "../numeric"
7
+ import type {Solution} from "../analyze/solution"
6
8
 
7
9
  export class LinearSystem implements IPiMathObject<LinearSystem>,
8
10
  IEquation<LinearSystem>,
9
11
  IAlgebra<LinearSystem> {
10
12
 
11
13
  #equations: Equation[]
12
-
13
- // Determine the letters in the linear system, usually ['x', 'y']
14
+ // Solve steps for TeX output.
15
+ #steps: string[] = []
16
+ // Determine the letters in the linear asSystem, usually ['x', 'y']
14
17
  #variables: string[]
15
18
 
16
19
  constructor(...values: (string | Equation)[]) {
@@ -38,6 +41,21 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
38
41
  .parse(...this.#equations.map(equ => equ.clone()))
39
42
  }
40
43
 
44
+ public get tex(): string {
45
+ // Build the array of values.
46
+ // Reorder
47
+ // This clone the asSystem :!!!
48
+ //TODO: Avoid cloning this linear asSystem
49
+ const LS = this.clone().reorder()
50
+
51
+ return this.buildTex(LS.equations)
52
+ }
53
+
54
+ get display() {
55
+ // TODO : LinearSystem - display: implement the display of the linear asSystem
56
+ return this.tex + 'as display'
57
+ }
58
+
41
59
  public static fromMatrix(
42
60
  matrix: InputValue<Fraction>[][],
43
61
  letters = 'xyz'): LinearSystem {
@@ -88,7 +106,7 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
88
106
  let letters: string[] = []
89
107
  const equArray: string[] = []
90
108
 
91
- // Get the letters from the linear system
109
+ // Get the letters from the linear asSystem
92
110
  for (const equ of equations) {
93
111
  letters = letters.concat(equ.letters())
94
112
  }
@@ -141,11 +159,6 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
141
159
  return Fraction.max(...this.#equations.map(equ => equ.degree(letter)))
142
160
  }
143
161
 
144
- get display() {
145
- // TODO : LinearSystem - display: implement the display of the linear system
146
- return this.tex + 'as display'
147
- }
148
-
149
162
  // ------------------------------------------
150
163
  public get equations(): Equation[] {
151
164
  return this.#equations
@@ -153,6 +166,9 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
153
166
 
154
167
  public set equations(value) {
155
168
  this.#equations = value
169
+
170
+ // update the variables.
171
+ this.#findLetters()
156
172
  }
157
173
 
158
174
  public evaluate(values: InputValue<Fraction> | literalType<number | Fraction>, asNumeric?: boolean): number | Fraction {
@@ -185,21 +201,20 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
185
201
  return this.#makeMatrix()
186
202
  }
187
203
 
188
- public mergeEquations = (eq1: Equation, eq2: Equation, factor1: Fraction, factor2: Fraction): Equation => {
204
+ public mergeEquations(equation1: { id: number, factor: InputValue<Fraction> }, equation2: {
205
+ id: number,
206
+ factor: number
207
+ }): Equation {
189
208
  // Set and clone the equations.
190
-
191
- const eq1multiplied = eq1.clone().multiply(new Fraction(factor1)),
192
- eq2multiplied = eq2.clone().multiply(new Fraction(factor2))
209
+ const eq1multiplied = this.equations[equation1.id].clone().multiply(equation1.factor)
210
+ const eq2multiplied = this.equations[equation2.id].clone().multiply(equation2.factor)
193
211
 
194
212
  // Add both equations together.
195
- eq1multiplied.left.add(eq2multiplied.left)
196
- eq1multiplied.right.add(eq2multiplied.right)
197
-
198
- return eq1multiplied
213
+ return eq1multiplied.add(eq2multiplied)
199
214
  }
200
215
 
201
216
  public multiply(value: InputValue<Fraction> | InputValue<Fraction>[], index?: number): this {
202
- // Multiply the system by a number
217
+ // Multiply the asSystem by a number
203
218
  // the value can be an array of numbers
204
219
  // the value can be a number and the index of the equation to multiply
205
220
  if (Array.isArray(value)) {
@@ -222,8 +237,10 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
222
237
  return this
223
238
  }
224
239
 
225
- public reduce(): LinearSystem {
226
- throw new Error("Method not implemented.")
240
+ public reduce(): this {
241
+ // reduce all equations at once.
242
+ this.equations.forEach(equ=>equ.reduce())
243
+ return this
227
244
  }
228
245
 
229
246
  // ------------------------------------------
@@ -235,7 +252,34 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
235
252
  return this
236
253
  }
237
254
 
238
- solve(): ISolution[] {
255
+ solve(): Solution[] {
256
+ // TODO : à retravailler, car ce n'est ni l'endroit, ni l'intérêt de l'avoir ici.
257
+ // 1. search in the equations if a variable has two same or opposite value = candidate for merging
258
+ // 2. if 1 is false, search for a variable that has coefficient one
259
+ // 3. if 2 is false, search for a variable that has a coefficient multiple of another.
260
+ // 4. if 3 is false, multiply both lines.
261
+ // => merge the equations and cycle.
262
+ const output: string[] = [this.tex]
263
+
264
+ const LS = this.clone()
265
+
266
+ while (LS.variables.length>1){
267
+ const letter = LS.variables[LS.variables.length-1]
268
+ const emptyLS = new LinearSystem()
269
+ const factors = LS.solve_compute_factors(letter).slice(0, LS.variables.length-1)
270
+ factors.forEach(factor=> {
271
+ emptyLS.equations.push(LS.mergeEquations(...factor))
272
+ })
273
+
274
+ LS.equations = emptyLS.equations
275
+
276
+ output.push(LS.tex)
277
+
278
+ // add the same but with a reduced value.
279
+ LS.reduce()
280
+ output.push(LS.tex)
281
+ }
282
+
239
283
  return []
240
284
  }
241
285
 
@@ -243,9 +287,6 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
243
287
  const [matrix, vector] = this.matrix
244
288
  // Solve the matrix
245
289
 
246
- // console.log(matrix.map(row=>row.map(x=>x.display)))
247
- // console.log(vector.map(x=>x.display))
248
-
249
290
  // Make the augmented matrix (matrix + vector)
250
291
  const augmentedMatrix: Fraction[][] = matrix.map((row, index) => [...row, vector[index]])
251
292
 
@@ -286,10 +327,10 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
286
327
  augmentedMatrix[j][k].add(augmentedMatrix[i][k].clone().multiply(factor))
287
328
  }
288
329
 
289
- // Check if the system is undetermined (no solution or infinite solutions)
330
+ // Check if the asSystem is undetermined (no solution or infinite solutions)
290
331
  // the j line must not be all zeros
291
- // the last element must be zero => the system is undetermined
292
- // the last element must not be zero => the system is impossible
332
+ // the last element must be zero => the asSystem is undetermined
333
+ // the last element must not be zero => the asSystem is impossible
293
334
  if (augmentedMatrix[j].slice(0, augmentedMatrix[j].length - 1).every(x => x.isZero())) {
294
335
  if (augmentedMatrix[j][augmentedMatrix[j].length - 1].isZero()) {
295
336
  return [new Fraction().infinite()]
@@ -303,6 +344,34 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
303
344
  return augmentedMatrix.map(x => x[x.length - 1])
304
345
  }
305
346
 
347
+ solve_compute_factors(letter: string):
348
+ [{ id: number, factor: number }, { id: number, factor: number }][] {
349
+ // when solving, every monoms with a variable is on the left !
350
+ // and every coefficient are relative numbers.
351
+ const result: [{ id: number, factor: number }, { id: number, factor: number }][] = []
352
+ const coefficients = this.equations.map(equ => equ.left.monomByLetter(letter).coefficient.value)
353
+
354
+ // search for a factor
355
+ coefficients.forEach((reference, index) => {
356
+ for (let i = index + 1; i < coefficients.length; i++) {
357
+ const lcm = Numeric.lcm(reference, coefficients[i])
358
+
359
+ const sign = reference < 0 ? -1 : 1
360
+ result.push([
361
+ {
362
+ id: index, factor: sign * lcm / reference
363
+ }, {
364
+ id: i, factor: -sign * lcm / coefficients[i]
365
+ }])
366
+ }
367
+ })
368
+
369
+ // Sort the value: prefer the smallest absolute values (1/-1, 2/-2, ...)
370
+ return result.sort((a, b) => {
371
+ return (Math.abs(a[0].factor) + Math.abs(a[1].factor)) - (Math.abs(b[0].factor) + Math.abs(b[1].factor))
372
+ })
373
+ }
374
+
306
375
  public subtract(value: InputValue<LinearSystem | Equation | Polynom>, index?: number): this {
307
376
  if (value instanceof LinearSystem) {
308
377
  const length = value.equations.length
@@ -324,16 +393,6 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
324
393
  return this
325
394
  }
326
395
 
327
- public get tex(): string {
328
- // Build the array of values.
329
- // Reorder
330
- // This clone the system :!!!
331
- //TODO: Avoid cloning this linear system
332
- const LS = this.clone().reorder()
333
-
334
- return this.buildTex(LS.equations)
335
- }
336
-
337
396
  public get variables(): string[] {
338
397
  return this.#variables
339
398
  }
@@ -348,15 +407,7 @@ export class LinearSystem implements IPiMathObject<LinearSystem>,
348
407
  this.#variables = this.#equations.reduce((acc: string[], equ) => {
349
408
  return [...new Set([...acc, ...equ.variables])]
350
409
  }, [])
351
- //
352
- // // Find all letters used.
353
- // let variables = new Set<string>()
354
- //
355
- // for (const equ of this.#equations) {
356
- // variables = new Set([...variables, ...equ.variables])
357
- // }
358
- //
359
- // this.#variables = [...variables]
410
+
360
411
  this.#variables.sort()
361
412
  return this
362
413
  }