pimath 0.2.14 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pimath.js +850 -1879
- package/dist/pimath.js.map +1 -1
- package/package.json +1 -1
- package/src/algebra/equation.ts +562 -558
- package/src/algebra/equationSolver.ts +489 -489
- package/src/algebra/factor.ts +396 -392
- package/src/algebra/linearSystem.ts +446 -442
- package/src/algebra/matrix.ts +515 -511
- package/src/algebra/monom.ts +932 -928
- package/src/algebra/polyFactor.ts +724 -720
- package/src/algebra/polynom.ts +1233 -1229
- package/src/coefficients/fraction.ts +907 -748
- package/src/coefficients/root.ts +500 -359
- package/src/geometry/TupleN.ts +129 -129
- package/src/geometry/circle.ts +455 -455
- package/src/geometry/line.ts +658 -654
- package/src/geometry/point.ts +105 -105
- package/src/geometry/sphere3.ts +2 -2
- package/src/geometry/triangle.ts +488 -488
- package/src/geometry/vector.ts +230 -226
- package/src/numeric.ts +136 -51
- package/src/pimath.interface.ts +2 -0
- package/types/algebra/equation.d.ts +1 -0
- package/types/algebra/equation.d.ts.map +1 -1
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/factor.d.ts +1 -0
- package/types/algebra/factor.d.ts.map +1 -1
- package/types/algebra/linearSystem.d.ts +1 -0
- package/types/algebra/linearSystem.d.ts.map +1 -1
- package/types/algebra/matrix.d.ts +6 -5
- package/types/algebra/matrix.d.ts.map +1 -1
- package/types/algebra/monom.d.ts +1 -0
- package/types/algebra/monom.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +1 -0
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/algebra/polynom.d.ts +1 -0
- package/types/algebra/polynom.d.ts.map +1 -1
- package/types/coefficients/fraction.d.ts +62 -53
- package/types/coefficients/fraction.d.ts.map +1 -1
- package/types/coefficients/root.d.ts +3 -0
- package/types/coefficients/root.d.ts.map +1 -1
- package/types/geometry/TupleN.d.ts +1 -1
- package/types/geometry/TupleN.d.ts.map +1 -1
- package/types/geometry/circle.d.ts.map +1 -1
- package/types/geometry/line.d.ts +1 -0
- package/types/geometry/line.d.ts.map +1 -1
- package/types/geometry/point.d.ts.map +1 -1
- package/types/geometry/sphere3.d.ts +2 -2
- package/types/geometry/sphere3.d.ts.map +1 -1
- package/types/geometry/triangle.d.ts.map +1 -1
- package/types/geometry/vector.d.ts +1 -0
- package/types/geometry/vector.d.ts.map +1 -1
- package/types/index.d.ts +3 -3
- package/types/numeric.d.ts +4 -4
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +1 -0
- package/types/pimath.interface.d.ts.map +1 -1
- package/types/primes.data.d.ts +2 -0
- package/types/primes.data.d.ts.map +1 -0
|
@@ -1,442 +1,446 @@
|
|
|
1
|
-
import type {IAlgebra, IEquation, InputValue, IPiMathObject, literalType} from "../pimath.interface"
|
|
2
|
-
import {Fraction} from "../coefficients"
|
|
3
|
-
import {Equation} from "./equation"
|
|
4
|
-
import {Monom} from "./monom"
|
|
5
|
-
import {Polynom} from "./polynom"
|
|
6
|
-
import {Numeric} from "../numeric"
|
|
7
|
-
import {Solution} from "../analyze"
|
|
8
|
-
import {DimensionError, IndexError, MathError, NotImplementedError} from "../errors"
|
|
9
|
-
|
|
10
|
-
export class LinearSystem implements IPiMathObject<LinearSystem>,
|
|
11
|
-
IEquation<LinearSystem>,
|
|
12
|
-
IAlgebra<LinearSystem> {
|
|
13
|
-
|
|
14
|
-
#equations: Equation[]
|
|
15
|
-
|
|
16
|
-
// Determine the letters in the linear asSystem, usually ['x', 'y']
|
|
17
|
-
#variables: string[]
|
|
18
|
-
|
|
19
|
-
constructor(...values: (string | Equation)[]) {
|
|
20
|
-
this.#equations = []
|
|
21
|
-
this.#variables = []
|
|
22
|
-
|
|
23
|
-
if (values.length > 0) {
|
|
24
|
-
this.parse(...values)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return this
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// make the original equations
|
|
32
|
-
this.#equations = equations.map(value => new Equation(value))
|
|
33
|
-
|
|
34
|
-
// get the letters.
|
|
35
|
-
this.#findLetters()
|
|
36
|
-
return this
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
this.#equations
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
this.#equations
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return this.
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
this.#equations
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
//
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
//
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
this.#equations
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return this
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
this.#variables =
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
this.#variables.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
1
|
+
import type {IAlgebra, IEquation, InputValue, IPiMathObject, literalType} from "../pimath.interface"
|
|
2
|
+
import {Fraction} from "../coefficients"
|
|
3
|
+
import {Equation} from "./equation"
|
|
4
|
+
import {Monom} from "./monom"
|
|
5
|
+
import {Polynom} from "./polynom"
|
|
6
|
+
import {Numeric} from "../numeric"
|
|
7
|
+
import {Solution} from "../analyze"
|
|
8
|
+
import {DimensionError, IndexError, MathError, NotImplementedError} from "../errors"
|
|
9
|
+
|
|
10
|
+
export class LinearSystem implements IPiMathObject<LinearSystem>,
|
|
11
|
+
IEquation<LinearSystem>,
|
|
12
|
+
IAlgebra<LinearSystem> {
|
|
13
|
+
|
|
14
|
+
#equations: Equation[]
|
|
15
|
+
|
|
16
|
+
// Determine the letters in the linear asSystem, usually ['x', 'y']
|
|
17
|
+
#variables: string[]
|
|
18
|
+
|
|
19
|
+
constructor(...values: (string | Equation)[]) {
|
|
20
|
+
this.#equations = []
|
|
21
|
+
this.#variables = []
|
|
22
|
+
|
|
23
|
+
if (values.length > 0) {
|
|
24
|
+
this.parse(...values)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return this
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
parse = (...equations: (string | Equation)[]): this => {
|
|
31
|
+
// make the original equations
|
|
32
|
+
this.#equations = equations.map(value => new Equation(value))
|
|
33
|
+
|
|
34
|
+
// get the letters.
|
|
35
|
+
this.#findLetters()
|
|
36
|
+
return this
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
copy(): this {
|
|
40
|
+
throw new NotImplementedError("copy() is not yet implemented for LinearSystem")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
clone = (): LinearSystem => {
|
|
44
|
+
return new LinearSystem()
|
|
45
|
+
.parse(...this.#equations.map(equ => equ.clone()))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get tex(): string {
|
|
49
|
+
// Build the array of values.
|
|
50
|
+
// Reorder
|
|
51
|
+
// This clone the asSystem :!!!
|
|
52
|
+
//TODO: Avoid cloning this linear asSystem
|
|
53
|
+
const LS = this.clone().reorder()
|
|
54
|
+
|
|
55
|
+
return this.buildTex(LS.equations)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get display() {
|
|
59
|
+
// TODO : LinearSystem - display: implement the display of the linear asSystem
|
|
60
|
+
return this.tex + 'as display'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static fromMatrix(
|
|
64
|
+
matrix: InputValue<Fraction>[][],
|
|
65
|
+
letters = 'xyz'): LinearSystem {
|
|
66
|
+
// Check that each row has the same number of columns
|
|
67
|
+
const cols = matrix[0].length
|
|
68
|
+
if (matrix.some(row => row.length !== cols)) {
|
|
69
|
+
throw new DimensionError("All rows must have the same number of columns")
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Determine the default letters. The number of letters are cols-1
|
|
73
|
+
const vars = letters.split('')
|
|
74
|
+
.splice(0, cols - 1)
|
|
75
|
+
|
|
76
|
+
// Create a new LinearSystem
|
|
77
|
+
return new LinearSystem(
|
|
78
|
+
...matrix.map(row => {
|
|
79
|
+
const P = new Polynom(vars.join(''), ...row)
|
|
80
|
+
return new Equation(P, 0)
|
|
81
|
+
})
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static solutionAsDisplay(value: Solution[]): string {
|
|
87
|
+
return `(${value.map(x=>x.display).join(";")})`
|
|
88
|
+
}
|
|
89
|
+
static solutionAsTex(value: Solution[]): string {
|
|
90
|
+
return `\\left( ${value.map(x=>x.tex).join(" ; ")} \\right)`
|
|
91
|
+
}
|
|
92
|
+
add(value: InputValue<LinearSystem | Equation | Polynom>, index?: number): this {
|
|
93
|
+
if (value instanceof LinearSystem) {
|
|
94
|
+
const length = value.equations.length
|
|
95
|
+
if (length !== this.#equations.length) {
|
|
96
|
+
throw new DimensionError("The number of equations must be the same")
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < length; i++) {
|
|
100
|
+
this.#equations[i].add(value.equations[i])
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
if (index === undefined || index < 0 || index >= this.#equations.length) {
|
|
104
|
+
throw new IndexError("Index out of range")
|
|
105
|
+
}
|
|
106
|
+
const equ = new Equation(value)
|
|
107
|
+
this.#equations[index].add(equ)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return this
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
buildTex = (equations: Equation[], operators?: (string[])[]): string => {
|
|
114
|
+
let equStr: string[]
|
|
115
|
+
let m: Monom
|
|
116
|
+
let letters: string[] = []
|
|
117
|
+
const equArray: string[] = []
|
|
118
|
+
|
|
119
|
+
// Get the letters from the linear asSystem
|
|
120
|
+
for (const equ of equations) {
|
|
121
|
+
letters = letters.concat(equ.letters())
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
letters = [...new Set(letters)]
|
|
125
|
+
letters.sort()
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < equations.length; i++) {
|
|
128
|
+
const equ = equations[i]
|
|
129
|
+
|
|
130
|
+
equStr = []
|
|
131
|
+
for (const L of letters) {
|
|
132
|
+
m = equ.left.monomByLetter(L)
|
|
133
|
+
|
|
134
|
+
if (equStr.length === 0) {
|
|
135
|
+
equStr.push(m.isZero() ? '' : m.tex)
|
|
136
|
+
} else {
|
|
137
|
+
equStr.push(m.isZero() ? '' : ((m.coefficient.sign() === 1) ? '+' : '') + m.tex)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Add the equal sign
|
|
142
|
+
equStr.push('=')
|
|
143
|
+
|
|
144
|
+
// Add the right hand part of the equation (should be only a number, because it has been reordered)
|
|
145
|
+
equStr.push(equ.right.tex)
|
|
146
|
+
|
|
147
|
+
// Add the operations if existing
|
|
148
|
+
if (operators?.[i] !== undefined) {
|
|
149
|
+
// add extra space at the end of the equation
|
|
150
|
+
equStr[equStr.length - 1] = equStr[equStr.length - 1] + ' \\phantom{\\quad}'
|
|
151
|
+
for (const o of operators[i]) {
|
|
152
|
+
equStr.push(`\\ \\cdot\\ ${o.startsWith('-') ? "\\left(" + o + "\\right)" : o}`)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add to the list.
|
|
157
|
+
equArray.push(equStr.join('&'))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let operatorsColumns = 0
|
|
161
|
+
if (operators !== undefined && operators.length > 0) {
|
|
162
|
+
operatorsColumns = operators[0].length
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return `\\left\\{\\begin{array}{${"r".repeat(letters.length)}cl ${"|l".repeat(operatorsColumns)}}${equArray.join('\\\\ ')}\\end{array}\\right.`
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
degree(letter?: string): Fraction {
|
|
169
|
+
return Fraction.max(...this.#equations.map(equ => equ.degree(letter)))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ------------------------------------------
|
|
173
|
+
get equations(): Equation[] {
|
|
174
|
+
return this.#equations
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
set equations(value) {
|
|
178
|
+
this.#equations = value
|
|
179
|
+
|
|
180
|
+
// update the variables.
|
|
181
|
+
this.#findLetters()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
evaluate(values: InputValue<Fraction> | literalType<number | Fraction>, asNumeric?: boolean): number | Fraction {
|
|
185
|
+
throw new NotImplementedError("Method not implemented.")
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
hasVariable(letter: string): boolean {
|
|
189
|
+
return this.#variables.includes(letter)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
isEqual(value: LinearSystem): boolean {
|
|
193
|
+
return this.equations.every((equ, index) => equ.isEqual(value.equations[index]))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
get isSolvable(): boolean {
|
|
197
|
+
const V = this.variables
|
|
198
|
+
|
|
199
|
+
// TODO: in some case, it is possible to resolve systems if there isn't the isSame number of vars and equations
|
|
200
|
+
if (V.length !== this.#equations.length) {
|
|
201
|
+
return false
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
//TODO: Must check if two equations isn't a linear combination of the others ?
|
|
205
|
+
|
|
206
|
+
return true
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
get matrix(): [Fraction[][], Fraction[]] {
|
|
210
|
+
//TODO: use Matrix class
|
|
211
|
+
return this.#makeMatrix()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
mergeEquations(equation1: { id: number, factor: InputValue<Fraction> }, equation2: {
|
|
215
|
+
id: number,
|
|
216
|
+
factor: number
|
|
217
|
+
}): Equation {
|
|
218
|
+
// Set and clone the equations.
|
|
219
|
+
const eq1multiplied = this.equations[equation1.id].clone().multiply(equation1.factor)
|
|
220
|
+
const eq2multiplied = this.equations[equation2.id].clone().multiply(equation2.factor)
|
|
221
|
+
|
|
222
|
+
// Add both equations together.
|
|
223
|
+
return eq1multiplied.add(eq2multiplied)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
multiply(value: InputValue<Fraction> | InputValue<Fraction>[], index?: number): this {
|
|
227
|
+
// Multiply the asSystem by a number
|
|
228
|
+
// the value can be an array of numbers
|
|
229
|
+
// the value can be a number and the index of the equation to multiply
|
|
230
|
+
if (Array.isArray(value)) {
|
|
231
|
+
if (value.length !== this.#equations.length) {
|
|
232
|
+
throw new DimensionError("The number of values must be the same as the number of equations")
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (let i = 0; i < value.length; i++) {
|
|
236
|
+
this.#equations[i].multiply(value[i])
|
|
237
|
+
}
|
|
238
|
+
return this
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (index === undefined || index < 0 || index >= this.#equations.length) {
|
|
242
|
+
throw new IndexError("Index out of range")
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.#equations[index].multiply(value)
|
|
246
|
+
|
|
247
|
+
return this
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
reduce(): this {
|
|
251
|
+
// reduce all equations at once.
|
|
252
|
+
this.equations.forEach(equ => equ.reduce())
|
|
253
|
+
return this
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ------------------------------------------
|
|
257
|
+
reorder = (): this => {
|
|
258
|
+
for (const E of this.#equations) {
|
|
259
|
+
E.reorder()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return this
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
solve(): Solution[] {
|
|
266
|
+
const [matrix, vector] = this.matrix
|
|
267
|
+
// Solve the matrix
|
|
268
|
+
|
|
269
|
+
// Make the augmented matrix (matrix + vector)
|
|
270
|
+
const augmentedMatrix: Fraction[][] = matrix.map((row, index) => [...row, vector[index]])
|
|
271
|
+
|
|
272
|
+
// Reduce the matrix
|
|
273
|
+
for (let i = 0; i < matrix.length; i++) {
|
|
274
|
+
// Find the pivot (the first non-zero element in the row)
|
|
275
|
+
let pivot = augmentedMatrix[i][i].clone()
|
|
276
|
+
if (pivot.isZero()) {
|
|
277
|
+
// throw new Error('Divide by zero !')
|
|
278
|
+
// Search a line below that would add it.
|
|
279
|
+
const row_to_add = augmentedMatrix
|
|
280
|
+
.find((row, index) => {
|
|
281
|
+
return index > i && !row[i].isZero()
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
if (row_to_add) {
|
|
285
|
+
augmentedMatrix[i].forEach((value, index) => value.add(row_to_add[index]))
|
|
286
|
+
pivot = augmentedMatrix[i][i].clone()
|
|
287
|
+
} else {
|
|
288
|
+
throw new MathError('Unsolvable...')
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Normalize the row: divide all elements by the pivot
|
|
295
|
+
// the pivot is now 1
|
|
296
|
+
augmentedMatrix[i] = augmentedMatrix[i].map(x => x.divide(pivot))
|
|
297
|
+
|
|
298
|
+
// reduce the other rows using the pivot.
|
|
299
|
+
for (let j = 0; j < matrix.length; j++) {
|
|
300
|
+
if (j === i) {
|
|
301
|
+
continue
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const factor = augmentedMatrix[j][i].clone().opposite()
|
|
305
|
+
for (let k = 0; k < augmentedMatrix[j].length; k++) {
|
|
306
|
+
augmentedMatrix[j][k].add(augmentedMatrix[i][k].clone().multiply(factor))
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Check if the asSystem is undetermined (no solution or infinite solutions)
|
|
310
|
+
// the j line must not be all zeros
|
|
311
|
+
// the last element must be zero => the asSystem is undetermined
|
|
312
|
+
// the last element must not be zero => the asSystem is impossible
|
|
313
|
+
if (augmentedMatrix[j].slice(0, augmentedMatrix[j].length - 1).every(x => x.isZero())) {
|
|
314
|
+
if (augmentedMatrix[j][augmentedMatrix[j].length - 1].isZero()) {
|
|
315
|
+
// Infinite solution
|
|
316
|
+
return this.#mapMatrixSolutions()
|
|
317
|
+
} else {
|
|
318
|
+
// No solution
|
|
319
|
+
return []
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return this.#mapMatrixSolutions(augmentedMatrix)
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
solve_compute_factors(letter: string):
|
|
330
|
+
[{ id: number, factor: number }, { id: number, factor: number }][] {
|
|
331
|
+
// when solving, every monoms with a variable is on the left !
|
|
332
|
+
// and every coefficient are relative numbers.
|
|
333
|
+
const result: [{ id: number, factor: number }, { id: number, factor: number }][] = []
|
|
334
|
+
const coefficients = this.equations.map(equ => equ.left.monomByLetter(letter).coefficient.value)
|
|
335
|
+
|
|
336
|
+
// search for a factor
|
|
337
|
+
coefficients.forEach((reference, index) => {
|
|
338
|
+
for (let i = index + 1; i < coefficients.length; i++) {
|
|
339
|
+
const lcm = Numeric.lcm(reference, coefficients[i])
|
|
340
|
+
|
|
341
|
+
const sign = reference < 0 ? -1 : 1
|
|
342
|
+
result.push([
|
|
343
|
+
{
|
|
344
|
+
id: index, factor: sign * lcm / reference
|
|
345
|
+
}, {
|
|
346
|
+
id: i, factor: -sign * lcm / coefficients[i]
|
|
347
|
+
}])
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
// Sort the value: prefer the smallest absolute values (1/-1, 2/-2, ...)
|
|
352
|
+
return result.sort((a, b) => {
|
|
353
|
+
return (Math.abs(a[0].factor) + Math.abs(a[1].factor)) - (Math.abs(b[0].factor) + Math.abs(b[1].factor))
|
|
354
|
+
})
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
subtract(value: InputValue<LinearSystem | Equation | Polynom>, index?: number): this {
|
|
358
|
+
if (value instanceof LinearSystem) {
|
|
359
|
+
const length = value.equations.length
|
|
360
|
+
if (length !== this.#equations.length) {
|
|
361
|
+
throw new DimensionError("The number of equations must be the same")
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
for (let i = 0; i < length; i++) {
|
|
365
|
+
this.#equations[i].subtract(value.equations[i])
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
if (index === undefined || index < 0 || index >= this.#equations.length) {
|
|
369
|
+
throw new IndexError("Index out of range")
|
|
370
|
+
}
|
|
371
|
+
const equ = new Equation(value)
|
|
372
|
+
this.#equations[index].subtract(equ)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return this
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
get variables(): string[] {
|
|
379
|
+
return this.#variables
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
set variables(value: string | string[]) {
|
|
383
|
+
const vars = (typeof value === "string") ? value.split('') : [...value]
|
|
384
|
+
vars.sort()
|
|
385
|
+
this.#variables = vars
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
#findLetters = (): this => {
|
|
389
|
+
this.#variables = this.#equations.reduce((acc: string[], equ) => {
|
|
390
|
+
return [...new Set([...acc, ...equ.variables])]
|
|
391
|
+
}, [])
|
|
392
|
+
|
|
393
|
+
this.#variables.sort()
|
|
394
|
+
return this
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
#makeMatrix = (): [Fraction[][], Fraction[]] => {
|
|
398
|
+
// Make the matrix
|
|
399
|
+
const matrix: Fraction[][] = []
|
|
400
|
+
const vector: Fraction[] = []
|
|
401
|
+
|
|
402
|
+
for (const E of this.#equations) {
|
|
403
|
+
const row: Fraction[] = []
|
|
404
|
+
|
|
405
|
+
const equ = E.clone().reorder()
|
|
406
|
+
for (const L of this.variables) {
|
|
407
|
+
const m = equ.left.monomByLetter(L)
|
|
408
|
+
row.push(m.coefficient)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Add the "no letter part"
|
|
412
|
+
vector.push(equ.right.monoms[0].coefficient)
|
|
413
|
+
|
|
414
|
+
// Add to the matrix
|
|
415
|
+
matrix.push(row)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return [matrix, vector]
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
#mapMatrixSolutions(matrix?: Fraction[][]): Solution[] {
|
|
422
|
+
const result: Solution[] = []
|
|
423
|
+
|
|
424
|
+
if(!matrix){
|
|
425
|
+
// infinite solutions
|
|
426
|
+
this.variables.forEach(letter=>{
|
|
427
|
+
const sol = Solution.fromFraction(Infinity)
|
|
428
|
+
sol.variable = letter
|
|
429
|
+
result.push(sol)
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
return result
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
matrix.forEach((x, index) => {
|
|
436
|
+
|
|
437
|
+
const sol = Solution.fromFraction(x[x.length - 1])
|
|
438
|
+
sol.variable = this.variables[index]
|
|
439
|
+
|
|
440
|
+
result.push(sol)
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
return result
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
}
|