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.
- package/dist/pimath.js +3106 -2873
- package/dist/pimath.js.map +1 -1
- package/package.json +13 -11
- package/src/algebra/equation.ts +113 -111
- package/src/algebra/equationSolver.ts +69 -120
- package/src/algebra/factor.ts +6 -7
- package/src/algebra/linearSystem.ts +97 -46
- package/src/algebra/logicalset.ts +51 -52
- package/src/algebra/monom.ts +23 -61
- package/src/algebra/operations.ts +0 -1
- package/src/algebra/polyFactor.ts +5 -5
- package/src/algebra/polynom.ts +69 -216
- package/src/analyze/index.ts +4 -0
- package/src/analyze/solution.ts +92 -29
- package/src/analyze/tableOfSigns.ts +1 -1
- package/src/coefficients/fraction.ts +189 -149
- package/src/coefficients/index.ts +1 -1
- package/src/coefficients/root.ts +66 -19
- package/src/geometry/TupleN.ts +128 -0
- package/src/geometry/circle.ts +308 -238
- package/src/geometry/geomMath.ts +4 -3
- package/src/geometry/index.ts +1 -0
- package/src/geometry/line.ts +221 -245
- package/src/geometry/line3.ts +78 -73
- package/src/geometry/plane3.ts +64 -55
- package/src/geometry/point.ts +57 -19
- package/src/geometry/triangle.ts +376 -248
- package/src/geometry/vector.ts +113 -229
- package/src/index.ts +13 -12
- package/src/numeric.ts +6 -9
- package/src/pimath.interface.ts +30 -28
- package/src/randomization/algebra/rndPolynom.ts +29 -15
- package/src/randomization/coefficient/rndFraction.ts +3 -3
- package/src/randomization/geometry/rndLine.ts +8 -10
- package/src/randomization/random.ts +11 -13
- package/src/randomization/rndTypes.ts +16 -12
- package/types/algebra/equation.d.ts +18 -17
- package/types/algebra/equation.d.ts.map +1 -1
- package/types/algebra/equationSolver.d.ts +5 -4
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/factor.d.ts +1 -1
- package/types/algebra/factor.d.ts.map +1 -1
- package/types/algebra/linearSystem.d.ts +23 -6
- package/types/algebra/linearSystem.d.ts.map +1 -1
- package/types/algebra/logicalset.d.ts +1 -1
- package/types/algebra/logicalset.d.ts.map +1 -1
- package/types/algebra/monom.d.ts +1 -6
- package/types/algebra/monom.d.ts.map +1 -1
- package/types/algebra/operations.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +4 -4
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/algebra/polynom.d.ts +10 -7
- package/types/algebra/polynom.d.ts.map +1 -1
- package/types/analyze/index.d.ts +2 -0
- package/types/analyze/index.d.ts.map +1 -0
- package/types/analyze/solution.d.ts +14 -8
- package/types/analyze/solution.d.ts.map +1 -1
- package/types/coefficients/fraction.d.ts +14 -12
- package/types/coefficients/fraction.d.ts.map +1 -1
- package/types/coefficients/index.d.ts +1 -1
- package/types/coefficients/index.d.ts.map +1 -1
- package/types/coefficients/root.d.ts +3 -0
- package/types/coefficients/root.d.ts.map +1 -1
- package/types/geometry/TupleAbstract.d.ts +22 -0
- package/types/geometry/TupleAbstract.d.ts.map +1 -0
- package/types/geometry/TupleN.d.ts +24 -0
- package/types/geometry/TupleN.d.ts.map +1 -0
- package/types/geometry/circle.d.ts +26 -17
- package/types/geometry/circle.d.ts.map +1 -1
- package/types/geometry/geomMath.d.ts +2 -1
- package/types/geometry/geomMath.d.ts.map +1 -1
- package/types/geometry/index.d.ts.map +1 -1
- package/types/geometry/line.d.ts +21 -30
- package/types/geometry/line.d.ts.map +1 -1
- package/types/geometry/line3.d.ts +19 -19
- package/types/geometry/line3.d.ts.map +1 -1
- package/types/geometry/matrix.d.ts +11 -11
- package/types/geometry/plane3.d.ts +10 -10
- package/types/geometry/plane3.d.ts.map +1 -1
- package/types/geometry/point.d.ts +11 -6
- package/types/geometry/point.d.ts.map +1 -1
- package/types/geometry/triangle.d.ts +68 -23
- package/types/geometry/triangle.d.ts.map +1 -1
- package/types/geometry/vector.d.ts +24 -44
- package/types/geometry/vector.d.ts.map +1 -1
- package/types/index.d.ts +5 -4
- package/types/index.d.ts.map +1 -1
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +18 -24
- package/types/pimath.interface.d.ts.map +1 -1
- package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
- package/types/randomization/coefficient/rndFraction.d.ts +1 -1
- package/types/randomization/coefficient/rndFraction.d.ts.map +1 -1
- package/types/randomization/geometry/rndLine.d.ts.map +1 -1
- package/types/randomization/random.d.ts +3 -2
- package/types/randomization/random.d.ts.map +1 -1
- package/types/randomization/rndTypes.d.ts +15 -10
- package/types/randomization/rndTypes.d.ts.map +1 -1
- package/src/coefficients/nthRoot.ts +0 -149
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type {InputValue
|
|
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
|
-
|
|
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
|
|
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
|
|
27
|
-
return this
|
|
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():
|
|
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,
|
|
58
|
+
const {solutions, reminder} = this.#solveByFactorization()
|
|
55
59
|
|
|
56
60
|
// The remaining polynom is of degree zero. No more solutions available.
|
|
57
|
-
if (
|
|
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 (
|
|
66
|
+
if (reminder.degree().value <= 2) {
|
|
63
67
|
return solutions.concat(
|
|
64
|
-
new EquationSolver(
|
|
68
|
+
new EquationSolver(reminder.clone()).solve()
|
|
65
69
|
)
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// Use approximative solutions, using bissection algorithm.
|
|
69
|
-
|
|
70
|
-
this.#bissectionCompexityCounter = 0
|
|
73
|
+
this._ = 0
|
|
71
74
|
return solutions.concat(
|
|
72
|
-
this.#solveByBissection(
|
|
75
|
+
this.#solveByBissection(reminder)
|
|
73
76
|
).sort((a, b) => a.value - b.value)
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
public solveAsCardan():
|
|
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 }):
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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>):
|
|
94
|
-
if (value instanceof Fraction && value.
|
|
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
|
-
|
|
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):
|
|
110
|
-
const solutions:
|
|
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
|
|
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:
|
|
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:
|
|
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 (
|
|
276
|
+
if (s.isZero()) {
|
|
279
277
|
continue
|
|
280
278
|
}
|
|
281
279
|
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
// }
|
|
280
|
+
// The divider polynom
|
|
281
|
+
const p = left.clone()
|
|
282
|
+
.fromCoefficients(s.fraction.denominator, -s.fraction.numerator)
|
|
286
283
|
|
|
287
|
-
|
|
288
|
-
|
|
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,
|
|
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
|
-
|
|
310
|
+
reminder: zeroPolynom
|
|
316
311
|
}
|
|
317
312
|
}
|
|
318
313
|
|
|
319
|
-
#solveCubic_CardanFormula():
|
|
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():
|
|
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():
|
|
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
|
-
|
|
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):
|
|
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
|
-
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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
|
}
|
package/src/algebra/factor.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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():
|
|
226
|
-
|
|
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():
|
|
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
|
|
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
|
|
292
|
-
// the last element must not be zero => the
|
|
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
|
}
|