pimath 0.2.3 → 0.2.4
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 +730 -695
- package/dist/pimath.js.map +1 -1
- package/package.json +1 -1
- package/src/algebra/equation.ts +1 -1
- package/src/algebra/monom.ts +89 -144
- package/src/algebra/polynom.ts +165 -189
- package/src/coefficients/fraction.ts +71 -42
- package/src/coefficients/root.ts +5 -4
- package/src/index.ts +1 -0
- package/src/numeric.ts +6 -0
- package/src/randomization/algebra/rndPolynom.ts +7 -4
- package/types/algebra/monom.d.ts +1 -1
- package/types/algebra/monom.d.ts.map +1 -1
- package/types/algebra/polynom.d.ts +39 -41
- package/types/algebra/polynom.d.ts.map +1 -1
- package/types/coefficients/fraction.d.ts +5 -6
- package/types/coefficients/fraction.d.ts.map +1 -1
- package/types/coefficients/root.d.ts.map +1 -1
- package/types/index.d.ts +10 -9
- package/types/index.d.ts.map +1 -1
- package/types/numeric.d.ts.map +1 -1
- package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
package/src/algebra/polynom.ts
CHANGED
|
@@ -69,13 +69,14 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
69
69
|
* @param inputStr
|
|
70
70
|
* @param values
|
|
71
71
|
*/
|
|
72
|
-
public parse
|
|
72
|
+
public parse(inputStr: PolynomParsingType, ...values: InputAlgebra<Monom>[]): this {
|
|
73
73
|
// Reset the main variables.
|
|
74
74
|
this.#monoms = []
|
|
75
75
|
this.#factors = []
|
|
76
|
+
this.#invalidateCache()
|
|
76
77
|
|
|
77
78
|
if (typeof inputStr === 'string') {
|
|
78
|
-
return this.#parseString(inputStr, ...values)
|
|
79
|
+
return this.#parseString(inputStr, ...values as InputValue<Fraction>[])
|
|
79
80
|
} else if (
|
|
80
81
|
(typeof inputStr === 'number' || inputStr instanceof Fraction || inputStr instanceof Monom)
|
|
81
82
|
&& (values.length === 0)
|
|
@@ -99,15 +100,15 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
99
100
|
/**
|
|
100
101
|
* Clone the polynom
|
|
101
102
|
*/
|
|
102
|
-
public clone
|
|
103
|
+
public clone(): Polynom {
|
|
103
104
|
const P = new Polynom()
|
|
104
105
|
const M: Monom[] = []
|
|
106
|
+
P.#defaultVariable = this.#defaultVariable
|
|
105
107
|
|
|
106
108
|
for (const m of this.#monoms) {
|
|
107
109
|
M.push(m.clone())
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
|
|
111
112
|
P.monoms = M
|
|
112
113
|
|
|
113
114
|
return P
|
|
@@ -131,11 +132,11 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
131
132
|
return result
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
public add
|
|
135
|
+
public add(...values: InputAlgebra<Polynom>[]): this {
|
|
135
136
|
|
|
136
137
|
for (const value of values) {
|
|
137
138
|
if (value instanceof Polynom) {
|
|
138
|
-
this.#monoms = this.#monoms.concat(value.monoms)
|
|
139
|
+
this.#monoms = this.#monoms.concat(value.monoms.map(m=>m.clone()))
|
|
139
140
|
} else if (value instanceof Monom) {
|
|
140
141
|
this.#monoms.push(value.clone())
|
|
141
142
|
} else if (typeof value === "number" && Number.isSafeInteger(value)) {
|
|
@@ -149,16 +150,15 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
149
150
|
return this.reduce()
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
public commonMonom
|
|
153
|
+
public commonMonom(): Monom {
|
|
153
154
|
const M = new Monom().one()
|
|
154
155
|
const numerator: number = this.gcdNumerator()
|
|
155
156
|
const denominator: number = this.gcdDenominator()
|
|
156
|
-
const degree = this.degree()
|
|
157
157
|
|
|
158
158
|
M.coefficient = new Fraction(numerator, denominator)
|
|
159
159
|
for (const L of this.variables) {
|
|
160
160
|
// Initialize the setLetter with the max degree
|
|
161
|
-
M.setLetter(L, degree)
|
|
161
|
+
M.setLetter(L, this.degree(L))
|
|
162
162
|
for (const m of this.#monoms) {
|
|
163
163
|
M.setLetter(L, Fraction.min(m.degree(L), M.degree(L)))
|
|
164
164
|
if (M.degree(L).isZero()) {
|
|
@@ -170,7 +170,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
170
170
|
return M
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
public degree
|
|
173
|
+
public degree(letter?: string): Fraction {
|
|
174
174
|
let d: Fraction = new Fraction().zero()
|
|
175
175
|
for (const m of this.#monoms) {
|
|
176
176
|
d = Fraction.max(m.degree(letter).value, d)
|
|
@@ -179,7 +179,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
179
179
|
return d
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
public derivative
|
|
182
|
+
public derivative(letter?: string): Polynom {
|
|
183
183
|
const dP = new Polynom()
|
|
184
184
|
|
|
185
185
|
for (const m of this.#monoms) {
|
|
@@ -189,7 +189,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
189
189
|
return dP.reduce()
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
public divide
|
|
192
|
+
public divide(value: InputAlgebra<Polynom>): this {
|
|
193
193
|
|
|
194
194
|
if (value instanceof Fraction) {
|
|
195
195
|
return this.#divideByFraction(value)
|
|
@@ -204,6 +204,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
204
204
|
const {quotient, reminder} = this.euclidean(value)
|
|
205
205
|
if (reminder.isZero()) {
|
|
206
206
|
this.#monoms = quotient.monoms
|
|
207
|
+
this.#invalidateCache()
|
|
207
208
|
return this
|
|
208
209
|
}
|
|
209
210
|
}
|
|
@@ -214,8 +215,9 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
214
215
|
throw new Error(`Cannot divide by ${value as unknown as string}`)
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
public empty
|
|
218
|
+
public empty(): this {
|
|
218
219
|
this.#monoms = []
|
|
220
|
+
this.#invalidateCache()
|
|
219
221
|
return this
|
|
220
222
|
}
|
|
221
223
|
|
|
@@ -224,8 +226,8 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
224
226
|
* @param P
|
|
225
227
|
* returns {quotient: Polynom, reminder: Polynom}
|
|
226
228
|
*/
|
|
227
|
-
public euclidean
|
|
228
|
-
const letter: string = P.variables[0]
|
|
229
|
+
public euclidean(P: Polynom): IEuclidean {
|
|
230
|
+
const letter: string | undefined = P.variables[0]
|
|
229
231
|
const quotient: Polynom = new Polynom().zero()
|
|
230
232
|
const reminder: Polynom = this.clone().reorder(letter)
|
|
231
233
|
|
|
@@ -239,6 +241,10 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
239
241
|
}
|
|
240
242
|
}
|
|
241
243
|
|
|
244
|
+
if (!this.degree(letter).isNatural() || !P.degree(letter).isNatural()) {
|
|
245
|
+
throw new Error('Euclidean division requires integer degrees')
|
|
246
|
+
}
|
|
247
|
+
|
|
242
248
|
// Get at least a letter
|
|
243
249
|
const maxMP: Monom = P.monomByDegree(undefined, letter)
|
|
244
250
|
const degreeP: Fraction = P.degree(letter)
|
|
@@ -246,7 +252,8 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
246
252
|
let newM: Monom
|
|
247
253
|
|
|
248
254
|
// Make the Euclidean division of the two polynoms.
|
|
249
|
-
let MaxIteration = this.degree(letter).value
|
|
255
|
+
let MaxIteration = this.degree(letter).value - degreeP.value + 1
|
|
256
|
+
|
|
250
257
|
while (reminder.degree(letter).isGeq(degreeP) && MaxIteration > 0) {
|
|
251
258
|
MaxIteration--
|
|
252
259
|
|
|
@@ -272,7 +279,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
272
279
|
return {quotient, reminder}
|
|
273
280
|
}
|
|
274
281
|
|
|
275
|
-
public evaluate
|
|
282
|
+
public evaluate(values: literalType<Fraction | number> | InputValue<Fraction>, asNumeric?: boolean): Fraction | number {
|
|
276
283
|
// Return the numeric value, without using Fraction
|
|
277
284
|
if (asNumeric) {
|
|
278
285
|
return this.#evaluateAsNumeric(values)
|
|
@@ -281,7 +288,6 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
281
288
|
// Build the evaluated fraction
|
|
282
289
|
const r = new Fraction().zero()
|
|
283
290
|
this.#monoms.forEach(monom => {
|
|
284
|
-
//console.log('Evaluate polynom: ', monom.display, values, monom.evaluate(values).display);
|
|
285
291
|
r.add(monom.evaluate(values, asNumeric))
|
|
286
292
|
})
|
|
287
293
|
|
|
@@ -291,10 +297,10 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
291
297
|
// -------------------------------------
|
|
292
298
|
/**
|
|
293
299
|
* Factorize a polynom and store the best results in factors.
|
|
294
|
-
* @param
|
|
300
|
+
* @param _letter
|
|
295
301
|
* TODO: Handle other letter than 'x'.
|
|
296
302
|
*/
|
|
297
|
-
public factorize(
|
|
303
|
+
public factorize(_letter?: string): Polynom[] {
|
|
298
304
|
this.#factors = []
|
|
299
305
|
|
|
300
306
|
let P = this.clone().reorder()
|
|
@@ -314,7 +320,13 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
314
320
|
const solutions = new EquationSolver(P).solve()
|
|
315
321
|
|
|
316
322
|
if (solutions.length === 0) {
|
|
317
|
-
this.#factors
|
|
323
|
+
if (this.#factors.length === 0) {
|
|
324
|
+
// No common monom was extracted: the whole polynomial is irreducible
|
|
325
|
+
this.#factors = [this.clone()]
|
|
326
|
+
} else {
|
|
327
|
+
// Common monom was extracted: P is the irreducible remaining part
|
|
328
|
+
this.#factors.push(P)
|
|
329
|
+
}
|
|
318
330
|
return this.#factors
|
|
319
331
|
}
|
|
320
332
|
|
|
@@ -352,7 +364,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
352
364
|
return this.#factors
|
|
353
365
|
}
|
|
354
366
|
|
|
355
|
-
public fromCoefficients(...values: InputValue<Fraction>[]) {
|
|
367
|
+
public fromCoefficients(...values: InputValue<Fraction>[]): this {
|
|
356
368
|
|
|
357
369
|
this.#monoms = []
|
|
358
370
|
const letter = this.#defaultVariable ?? 'x'
|
|
@@ -364,35 +376,39 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
364
376
|
this.#monoms.push(monom)
|
|
365
377
|
})
|
|
366
378
|
|
|
379
|
+
this.#invalidateCache()
|
|
367
380
|
return this.reorder()
|
|
368
381
|
}
|
|
369
382
|
|
|
370
|
-
public gcdDenominator
|
|
383
|
+
public gcdDenominator(): number {
|
|
371
384
|
return Numeric.gcd(...this.getDenominators())
|
|
372
385
|
}
|
|
373
386
|
|
|
374
|
-
public gcdNumerator
|
|
387
|
+
public gcdNumerator(): number {
|
|
375
388
|
return Numeric.gcd(...this.getNumerators())
|
|
376
389
|
}
|
|
377
390
|
|
|
378
391
|
public getCoefficients(): Fraction[] {
|
|
392
|
+
if (!this.degree().isNatural()) {
|
|
393
|
+
throw new Error('getCoefficients() requires a polynomial with integer degrees')
|
|
394
|
+
}
|
|
395
|
+
|
|
379
396
|
// Assume there is only one letter.
|
|
380
397
|
const orderedPolynom = this.clone().reorder()
|
|
381
398
|
|
|
382
399
|
const length = this.degree().value + 1
|
|
383
|
-
const coeffs =
|
|
400
|
+
const coeffs = Array.from({length}, ()=>new Fraction(0))
|
|
384
401
|
|
|
385
402
|
orderedPolynom.monoms.forEach(monom => {
|
|
386
403
|
const index = length - monom.degree().value - 1
|
|
387
404
|
coeffs[index] = monom.coefficient.clone()
|
|
388
405
|
})
|
|
389
406
|
|
|
390
|
-
// return orderedPolynom.monoms.map(x=>x.coefficient)
|
|
391
407
|
return coeffs
|
|
392
408
|
}
|
|
393
409
|
|
|
394
410
|
// Next functions are used for for commonMonom, which is used in the factorize method.
|
|
395
|
-
public getDenominators
|
|
411
|
+
public getDenominators(): number[] {
|
|
396
412
|
const denominators: number[] = []
|
|
397
413
|
for (const m of this.#monoms) {
|
|
398
414
|
denominators.push(m.coefficient.denominator)
|
|
@@ -401,7 +417,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
401
417
|
return denominators
|
|
402
418
|
}
|
|
403
419
|
|
|
404
|
-
public getNumerators
|
|
420
|
+
public getNumerators(): number[] {
|
|
405
421
|
const numerators: number[] = []
|
|
406
422
|
for (const m of this.#monoms) {
|
|
407
423
|
numerators.push(m.coefficient.numerator)
|
|
@@ -410,7 +426,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
410
426
|
return numerators
|
|
411
427
|
}
|
|
412
428
|
|
|
413
|
-
public getZeroes
|
|
429
|
+
public getZeroes(): Solution[] {
|
|
414
430
|
if (this.degree().isZero()) {
|
|
415
431
|
return []
|
|
416
432
|
}
|
|
@@ -423,7 +439,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
423
439
|
return this.variables.includes(letter)
|
|
424
440
|
}
|
|
425
441
|
|
|
426
|
-
public integrate
|
|
442
|
+
public integrate(a: InputValue<Fraction>, b: InputValue<Fraction>, letter = 'x'): Fraction {
|
|
427
443
|
const primitive = this.primitive(letter)
|
|
428
444
|
|
|
429
445
|
const valuesA: literalType<Fraction> = {},
|
|
@@ -439,7 +455,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
439
455
|
return undefined
|
|
440
456
|
}
|
|
441
457
|
|
|
442
|
-
public isDeveloped
|
|
458
|
+
public isDeveloped(polynomString: string): boolean {
|
|
443
459
|
let P: Polynom
|
|
444
460
|
|
|
445
461
|
// Start by removing the parenthesis after a "power"
|
|
@@ -469,7 +485,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
469
485
|
return true
|
|
470
486
|
}
|
|
471
487
|
|
|
472
|
-
public isDividableBy
|
|
488
|
+
public isDividableBy(div: Polynom): boolean {
|
|
473
489
|
// Quick evaluation.
|
|
474
490
|
if (div.degree().isOne()) {
|
|
475
491
|
const zero = div.getZeroes()[0]
|
|
@@ -486,7 +502,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
486
502
|
}
|
|
487
503
|
}
|
|
488
504
|
|
|
489
|
-
public isEqual
|
|
505
|
+
public isEqual(P: Polynom): boolean {
|
|
490
506
|
return this.#compare(P, '=')
|
|
491
507
|
}
|
|
492
508
|
|
|
@@ -499,11 +515,11 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
499
515
|
return this.#monoms.length === 1 && this.#monoms[0].coefficient.isOne() && this.degree().isZero()
|
|
500
516
|
}
|
|
501
517
|
|
|
502
|
-
public isOppositeAt
|
|
518
|
+
public isOppositeAt(P: Polynom): boolean {
|
|
503
519
|
return this.#compare(P.clone().opposite(), '=')
|
|
504
520
|
}
|
|
505
521
|
|
|
506
|
-
public isSameAs
|
|
522
|
+
public isSameAs(P: Polynom): boolean {
|
|
507
523
|
return this.#compare(P, 'same')
|
|
508
524
|
}
|
|
509
525
|
|
|
@@ -511,11 +527,11 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
511
527
|
return (this.#monoms.length === 1 && this.#monoms[0].coefficient.isZero()) || this.#monoms.length === 0
|
|
512
528
|
}
|
|
513
529
|
|
|
514
|
-
public lcmDenominator
|
|
530
|
+
public lcmDenominator(): number {
|
|
515
531
|
return Numeric.lcm(...this.getDenominators())
|
|
516
532
|
}
|
|
517
533
|
|
|
518
|
-
public lcmNumerator
|
|
534
|
+
public lcmNumerator(): number {
|
|
519
535
|
return Numeric.lcm(...this.getNumerators())
|
|
520
536
|
}
|
|
521
537
|
|
|
@@ -523,57 +539,49 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
523
539
|
return this.#monoms.length
|
|
524
540
|
}
|
|
525
541
|
|
|
526
|
-
public
|
|
527
|
-
|
|
542
|
+
public limitTo(value: InputValue<Fraction>, letter?: string): Fraction {
|
|
543
|
+
const f = new Fraction(value)
|
|
528
544
|
|
|
529
|
-
|
|
530
|
-
|
|
545
|
+
// Finite value: evaluate directly
|
|
546
|
+
if (f.isFinite()) {
|
|
547
|
+
const l = letter ?? this.variables[0] ?? 'x'
|
|
548
|
+
return this.evaluate({[l]: f}) as Fraction
|
|
531
549
|
}
|
|
532
550
|
|
|
551
|
+
const M = this.monomByDegree(undefined, letter)
|
|
552
|
+
const sign = M.coefficient.sign()
|
|
553
|
+
const degree = M.degree(letter)
|
|
533
554
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
public limitToInfinity = (letter?: string): Fraction => {
|
|
538
|
-
const M = this.monomByDegree(undefined, letter),
|
|
539
|
-
sign = M.coefficient.sign(),
|
|
540
|
-
degree = M.degree(letter)
|
|
541
|
-
|
|
542
|
-
if (degree.isStrictlyPositive()) {
|
|
543
|
-
return sign === 1 ? (new Fraction()).infinite() : (new Fraction()).infinite().opposite()
|
|
544
|
-
} else if (degree.isZero()) {
|
|
545
|
-
return M.coefficient
|
|
555
|
+
// Constant polynomial
|
|
556
|
+
if (degree.isZero()) {
|
|
557
|
+
return M.coefficient.clone()
|
|
546
558
|
}
|
|
547
559
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
return (new Fraction()).zero()
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
public limitToNegativeInfinity = (letter?: string): Fraction => {
|
|
554
|
-
const M = this.monomByDegree(undefined, letter),
|
|
555
|
-
sign = M.coefficient.sign(),
|
|
556
|
-
degree = M.degree(letter)
|
|
557
|
-
|
|
558
|
-
if (degree.isStrictlyPositive()) {
|
|
559
|
-
return sign === -1 ? (new Fraction()).infinite() : (new Fraction()).infinite().opposite()
|
|
560
|
-
} else if (degree.isZero()) {
|
|
561
|
-
return M.coefficient
|
|
560
|
+
if (!degree.isStrictlyPositive()) {
|
|
561
|
+
return new Fraction().zero()
|
|
562
562
|
}
|
|
563
563
|
|
|
564
|
+
// Limit at +∞: determined by the leading coefficient sign
|
|
565
|
+
if (f.isPositive()) {
|
|
566
|
+
return sign === 1
|
|
567
|
+
? new Fraction().infinite()
|
|
568
|
+
: new Fraction().infinite().opposite()
|
|
569
|
+
}
|
|
564
570
|
|
|
565
|
-
//
|
|
566
|
-
|
|
571
|
+
// Limit at -∞: accounts for the parity of the degree
|
|
572
|
+
const degreeIsEven = degree.value % 2 === 0
|
|
573
|
+
const limitSign = degreeIsEven ? sign : -sign
|
|
574
|
+
return limitSign === 1
|
|
575
|
+
? new Fraction().infinite()
|
|
576
|
+
: new Fraction().infinite().opposite()
|
|
567
577
|
}
|
|
568
578
|
|
|
569
|
-
public monomByDegree
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
{
|
|
579
|
+
public monomByDegree(degree?: Fraction | number, letter?: string): Monom {
|
|
580
|
+
// return the highest degree monom.
|
|
581
|
+
if (degree === undefined) {
|
|
573
582
|
return this.monomByDegree(this.degree(letter), letter)
|
|
574
583
|
}
|
|
575
584
|
|
|
576
|
-
|
|
577
585
|
// Reduce the polynom.
|
|
578
586
|
const M = this.clone().reduce()
|
|
579
587
|
for (const m of M.#monoms) {
|
|
@@ -582,13 +590,12 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
582
590
|
}
|
|
583
591
|
}
|
|
584
592
|
|
|
585
|
-
|
|
586
593
|
// Nothing was found - return the null monom.
|
|
587
594
|
return new Monom().zero()
|
|
588
595
|
}
|
|
589
596
|
|
|
590
597
|
// Used in LinearSystem.tex
|
|
591
|
-
public monomByLetter
|
|
598
|
+
public monomByLetter(letter: string): Monom {
|
|
592
599
|
const M = this.clone().reduce()
|
|
593
600
|
for (const m of M.#monoms) {
|
|
594
601
|
if (m.hasVariable(letter)) {
|
|
@@ -596,7 +603,6 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
596
603
|
}
|
|
597
604
|
}
|
|
598
605
|
|
|
599
|
-
|
|
600
606
|
return new Monom().zero()
|
|
601
607
|
}
|
|
602
608
|
|
|
@@ -607,13 +613,13 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
607
613
|
|
|
608
614
|
public set monoms(M: Monom[]) {
|
|
609
615
|
this.#monoms = M
|
|
616
|
+
this.#invalidateCache()
|
|
610
617
|
}
|
|
611
618
|
|
|
612
|
-
public monomsByDegree
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
return this.monomsByDegree(this.degree(letter))
|
|
619
|
+
public monomsByDegree(degree?: number | Fraction, letter?: string): Monom[] {
|
|
620
|
+
// return the highest degree monom.
|
|
621
|
+
if (degree === undefined) {
|
|
622
|
+
return this.monomsByDegree(this.degree(letter), letter)
|
|
617
623
|
}
|
|
618
624
|
|
|
619
625
|
// Reduce the polynom.
|
|
@@ -626,12 +632,10 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
626
632
|
}
|
|
627
633
|
}
|
|
628
634
|
|
|
629
|
-
|
|
630
635
|
return Ms
|
|
631
|
-
// Nothing was found - return
|
|
632
636
|
}
|
|
633
637
|
|
|
634
|
-
public multiply
|
|
638
|
+
public multiply(value: InputAlgebra<Polynom>): this {
|
|
635
639
|
|
|
636
640
|
if (value instanceof Polynom) {
|
|
637
641
|
return this.#multiplyByPolynom(value)
|
|
@@ -666,15 +670,17 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
666
670
|
return this.variables.length
|
|
667
671
|
}
|
|
668
672
|
|
|
669
|
-
public one
|
|
673
|
+
public one(): this {
|
|
670
674
|
this.#monoms = []
|
|
671
675
|
this.#monoms.push(new Monom().one())
|
|
676
|
+
this.#invalidateCache()
|
|
672
677
|
return this
|
|
673
678
|
}
|
|
674
679
|
|
|
675
680
|
// ------------------------------------------
|
|
676
|
-
public opposite
|
|
681
|
+
public opposite(): this {
|
|
677
682
|
this.#monoms = this.#monoms.map(m => m.opposite())
|
|
683
|
+
this.#invalidateCache()
|
|
678
684
|
return this
|
|
679
685
|
}
|
|
680
686
|
|
|
@@ -682,11 +688,11 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
682
688
|
return this.#genDisplay('tex', false, false, true)
|
|
683
689
|
}
|
|
684
690
|
|
|
685
|
-
public pow
|
|
691
|
+
public pow(nb: number): Polynom {
|
|
686
692
|
return operation_pow(this as Polynom, nb).reduce()
|
|
687
693
|
}
|
|
688
694
|
|
|
689
|
-
public primitive
|
|
695
|
+
public primitive(letter?: string): Polynom {
|
|
690
696
|
const dP = new Polynom()
|
|
691
697
|
|
|
692
698
|
for (const m of this.#monoms) {
|
|
@@ -696,7 +702,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
696
702
|
return dP
|
|
697
703
|
}
|
|
698
704
|
|
|
699
|
-
public reduce
|
|
705
|
+
public reduce(): this {
|
|
700
706
|
// Reduce the polynom
|
|
701
707
|
|
|
702
708
|
// Group the monoms by similarity
|
|
@@ -714,7 +720,6 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
714
720
|
}
|
|
715
721
|
}
|
|
716
722
|
|
|
717
|
-
|
|
718
723
|
i++
|
|
719
724
|
}
|
|
720
725
|
|
|
@@ -728,16 +733,15 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
728
733
|
m.coefficient.reduce()
|
|
729
734
|
}
|
|
730
735
|
|
|
731
|
-
|
|
732
736
|
if (this.length === 0) {
|
|
733
|
-
return
|
|
737
|
+
return this.zero()
|
|
734
738
|
}
|
|
735
739
|
|
|
736
|
-
|
|
740
|
+
this.#invalidateCache()
|
|
737
741
|
return this.reorder()
|
|
738
742
|
}
|
|
739
743
|
|
|
740
|
-
public reorder
|
|
744
|
+
public reorder(letter = 'x', revert = false): this {
|
|
741
745
|
const otherLetters = this.variables.filter(x => x !== letter)
|
|
742
746
|
this.#monoms.sort(function (a, b) {
|
|
743
747
|
const da = a.degree(letter).value,
|
|
@@ -773,7 +777,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
773
777
|
* @param letter
|
|
774
778
|
* @param P
|
|
775
779
|
*/
|
|
776
|
-
public replaceBy
|
|
780
|
+
public replaceBy(letter: string, P: Polynom): this {
|
|
777
781
|
let pow: Fraction
|
|
778
782
|
const resultPolynom: Polynom = new Polynom().zero()
|
|
779
783
|
|
|
@@ -790,13 +794,17 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
790
794
|
m.removeVariable(letter)
|
|
791
795
|
|
|
792
796
|
// Add the new monom to the result polynom
|
|
793
|
-
|
|
797
|
+
if (pow.isStrictlyNegative()) {
|
|
798
|
+
throw new Error(`Cannot replace variable "${letter}" with negative power in a Polynom`)
|
|
799
|
+
}
|
|
800
|
+
resultPolynom.add(P.clone().pow(pow.numerator).multiply(m))
|
|
794
801
|
}
|
|
795
802
|
}
|
|
796
803
|
|
|
797
804
|
|
|
798
805
|
// Reduce the monoms
|
|
799
806
|
this.#monoms = resultPolynom.reduce().monoms
|
|
807
|
+
this.#invalidateCache()
|
|
800
808
|
return this
|
|
801
809
|
}
|
|
802
810
|
|
|
@@ -825,7 +833,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
825
833
|
throw new Error('Cannot take the square root from a polynom')
|
|
826
834
|
}
|
|
827
835
|
|
|
828
|
-
public subtract
|
|
836
|
+
public subtract(...values: InputAlgebra<Polynom>[]): this {
|
|
829
837
|
for (const value of values) {
|
|
830
838
|
if (value instanceof Polynom) {
|
|
831
839
|
this.add(value.clone().opposite())
|
|
@@ -878,7 +886,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
878
886
|
]
|
|
879
887
|
|
|
880
888
|
testingRoots.forEach((test, index) => {
|
|
881
|
-
const sign = this.evaluate({x: test}, true) as number
|
|
889
|
+
const sign = this.evaluate({[this.variables[0] ?? 'x']: test}, true) as number
|
|
882
890
|
signs[index * 2] = sign > 0 ? '+' : '-'
|
|
883
891
|
})
|
|
884
892
|
}
|
|
@@ -895,26 +903,17 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
895
903
|
}
|
|
896
904
|
|
|
897
905
|
public get variables(): string[] {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
for (const m of this.#monoms) {
|
|
901
|
-
V = V.concat(m.variables)
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
// Remove duplicates.
|
|
906
|
-
V = [...new Set(V)]
|
|
907
|
-
V.sort()
|
|
908
|
-
return V
|
|
906
|
+
return [...new Set(this.#monoms.flatMap(m => m.variables))].sort()
|
|
909
907
|
}
|
|
910
908
|
|
|
911
909
|
/**
|
|
912
910
|
* Set the polynom to zero.
|
|
913
911
|
* @returns {this}
|
|
914
912
|
*/
|
|
915
|
-
public zero
|
|
913
|
+
public zero(): this {
|
|
916
914
|
this.#monoms = []
|
|
917
915
|
this.#monoms.push(new Monom().zero())
|
|
916
|
+
this.#invalidateCache()
|
|
918
917
|
return this
|
|
919
918
|
}
|
|
920
919
|
|
|
@@ -922,7 +921,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
922
921
|
return this.getZeroes()
|
|
923
922
|
}
|
|
924
923
|
|
|
925
|
-
#compare
|
|
924
|
+
#compare(P: Polynom, sign?: string): boolean {
|
|
926
925
|
sign ??= '='
|
|
927
926
|
|
|
928
927
|
// Create clone version to reduce them without altering the original polynoms.
|
|
@@ -954,25 +953,26 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
954
953
|
}
|
|
955
954
|
}
|
|
956
955
|
|
|
957
|
-
|
|
958
|
-
#divideByFraction = (F: Fraction): this => {
|
|
956
|
+
#divideByFraction(F: Fraction): this {
|
|
959
957
|
for (const m of this.#monoms) {
|
|
960
958
|
m.coefficient.divide(F)
|
|
961
959
|
}
|
|
962
960
|
|
|
961
|
+
this.#invalidateCache()
|
|
963
962
|
return this
|
|
964
963
|
}
|
|
965
964
|
|
|
966
|
-
#divideByInteger
|
|
965
|
+
#divideByInteger(nb: number): this {
|
|
967
966
|
const nbF = new Fraction(nb)
|
|
968
967
|
for (const m of this.#monoms) {
|
|
969
968
|
m.coefficient.divide(nbF)
|
|
970
969
|
}
|
|
971
970
|
|
|
971
|
+
this.#invalidateCache()
|
|
972
972
|
return this
|
|
973
973
|
}
|
|
974
974
|
|
|
975
|
-
#evaluateAsNumeric
|
|
975
|
+
#evaluateAsNumeric(values: literalType<number | Fraction> | InputValue<Fraction>): number {
|
|
976
976
|
let r = 0
|
|
977
977
|
this.#monoms.forEach(monom => {
|
|
978
978
|
r += monom.evaluate(values, true) as number
|
|
@@ -981,7 +981,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
981
981
|
return r
|
|
982
982
|
}
|
|
983
983
|
|
|
984
|
-
#genDisplay
|
|
984
|
+
#genDisplay(output?: string, forceSign?: boolean, wrapParentheses?: boolean, withAllMultiplicationSign?: boolean): string {
|
|
985
985
|
let P = ''
|
|
986
986
|
|
|
987
987
|
for (const k of this.#monoms) {
|
|
@@ -989,7 +989,6 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
989
989
|
continue
|
|
990
990
|
}
|
|
991
991
|
|
|
992
|
-
|
|
993
992
|
// The monom to be displayed
|
|
994
993
|
let m
|
|
995
994
|
if (withAllMultiplicationSign) {
|
|
@@ -1017,42 +1016,24 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1017
1016
|
return P
|
|
1018
1017
|
}
|
|
1019
1018
|
|
|
1020
|
-
#
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
const allDividers: Polynom[] = []
|
|
1025
|
-
m1.forEach(m1d => {
|
|
1026
|
-
// Get only polynom that has a degree less than a specific value
|
|
1027
|
-
if (m1d.degree(letter).isLeq(maxDegree)) {
|
|
1028
|
-
m2.forEach(m2d => {
|
|
1029
|
-
if (m1d.degree(letter).isNotEqual(m2d.degree(letter))) {
|
|
1030
|
-
allDividers.push(new Polynom(m1d, m2d))
|
|
1031
|
-
allDividers.push(new Polynom(m1d, m2d.clone().opposite()))
|
|
1032
|
-
}
|
|
1033
|
-
})
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
})
|
|
1038
|
-
|
|
1039
|
-
return allDividers
|
|
1019
|
+
#invalidateCache(): void {
|
|
1020
|
+
this.#rootsCache = false
|
|
1021
|
+
this.#factors = []
|
|
1040
1022
|
}
|
|
1041
1023
|
|
|
1042
|
-
#multiplyByFraction
|
|
1024
|
+
#multiplyByFraction(F: Fraction): this {
|
|
1043
1025
|
for (const m of this.#monoms) {
|
|
1044
1026
|
m.coefficient.multiply(F)
|
|
1045
1027
|
}
|
|
1046
1028
|
|
|
1047
|
-
|
|
1048
1029
|
return this.reduce()
|
|
1049
1030
|
}
|
|
1050
1031
|
|
|
1051
|
-
#multiplyByInteger
|
|
1032
|
+
#multiplyByInteger(nb: number): this {
|
|
1052
1033
|
return this.#multiplyByFraction(new Fraction(nb))
|
|
1053
1034
|
}
|
|
1054
1035
|
|
|
1055
|
-
#multiplyByMonom
|
|
1036
|
+
#multiplyByMonom(M: Monom): this {
|
|
1056
1037
|
for (const m of this.#monoms) {
|
|
1057
1038
|
m.multiply(M)
|
|
1058
1039
|
}
|
|
@@ -1060,7 +1041,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1060
1041
|
return this.reduce()
|
|
1061
1042
|
}
|
|
1062
1043
|
|
|
1063
|
-
#multiplyByPolynom
|
|
1044
|
+
#multiplyByPolynom(P: Polynom): this {
|
|
1064
1045
|
const M: Monom[] = []
|
|
1065
1046
|
for (const m1 of this.#monoms) {
|
|
1066
1047
|
for (const m2 of P.monoms) {
|
|
@@ -1068,12 +1049,11 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1068
1049
|
}
|
|
1069
1050
|
}
|
|
1070
1051
|
|
|
1071
|
-
|
|
1072
1052
|
this.#monoms = M
|
|
1073
1053
|
return this.reduce()
|
|
1074
1054
|
}
|
|
1075
1055
|
|
|
1076
|
-
#parseString(inputStr: string, ...values:
|
|
1056
|
+
#parseString(inputStr: string, ...values: InputValue<Fraction>[]): this {
|
|
1077
1057
|
if (values.length === 0) {
|
|
1078
1058
|
// Parse the polynom using the shutting yard algorithm
|
|
1079
1059
|
if (inputStr !== '' && !isNaN(Number(inputStr))) {
|
|
@@ -1088,18 +1068,18 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1088
1068
|
|
|
1089
1069
|
// Parse the string.
|
|
1090
1070
|
return this.#shutingYardToReducedPolynom(inputStr)
|
|
1091
|
-
} else if (/^[a-z]
|
|
1071
|
+
} else if (/^[a-z]+$/.test(inputStr)) {
|
|
1092
1072
|
// We assume the inputStr contains only letters.
|
|
1093
1073
|
this.empty()
|
|
1094
1074
|
|
|
1095
|
-
const fractions = values.map(x => new Fraction(x
|
|
1075
|
+
const fractions = values.map(x => new Fraction(x))
|
|
1096
1076
|
|
|
1097
1077
|
// Multiple setLetter version
|
|
1098
1078
|
if (inputStr.length > 1) {
|
|
1099
1079
|
const letters = inputStr.split('')
|
|
1100
1080
|
|
|
1101
|
-
if (
|
|
1102
|
-
throw new Error(
|
|
1081
|
+
if (fractions.length > letters.length + 1) {
|
|
1082
|
+
throw new Error(`Too many values: ${letters.length} letters but ${fractions.length} values provided`)
|
|
1103
1083
|
}
|
|
1104
1084
|
|
|
1105
1085
|
let i = 0
|
|
@@ -1107,7 +1087,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1107
1087
|
for (const F of fractions) {
|
|
1108
1088
|
const m = new Monom()
|
|
1109
1089
|
m.coefficient = F.clone()
|
|
1110
|
-
m.literalStr = letters[i]
|
|
1090
|
+
m.literalStr = letters[i] ?? ''
|
|
1111
1091
|
this.add(m)
|
|
1112
1092
|
i++
|
|
1113
1093
|
}
|
|
@@ -1130,35 +1110,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1130
1110
|
|
|
1131
1111
|
}
|
|
1132
1112
|
|
|
1133
|
-
|
|
1134
|
-
* Main parse using a shutting yard class
|
|
1135
|
-
* @param inputStr
|
|
1136
|
-
*/
|
|
1137
|
-
#shutingYardToReducedPolynom = (inputStr: string): this => {
|
|
1138
|
-
// Get the RPN array of the current expression
|
|
1139
|
-
const SY: ShutingYard = new ShutingYard().parse(inputStr)
|
|
1140
|
-
const rpn: { token: string, tokenType: ShutingyardType }[] = SY.rpn
|
|
1141
|
-
|
|
1142
|
-
// New version for reducing shuting yard.
|
|
1143
|
-
this.zero()
|
|
1144
|
-
|
|
1145
|
-
const stack: Polynom[] = []
|
|
1146
|
-
|
|
1147
|
-
// Loop through the each element of the RPN
|
|
1148
|
-
for (const element of rpn) {
|
|
1149
|
-
this.#shutingYard_addToken(stack, element)
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
if (stack.length === 1) {
|
|
1154
|
-
this.add(stack[0])
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
return this.reorder()
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
#shutingYard_addToken = (stack: Polynom[], element: Token): void => {
|
|
1113
|
+
#shutingYardAddToken(stack: Polynom[], element: Token): void {
|
|
1162
1114
|
switch (element.tokenType) {
|
|
1163
1115
|
case ShutingyardType.COEFFICIENT:
|
|
1164
1116
|
stack.push(new Polynom(element.token))
|
|
@@ -1169,9 +1121,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1169
1121
|
break
|
|
1170
1122
|
|
|
1171
1123
|
case ShutingyardType.CONSTANT:
|
|
1172
|
-
|
|
1173
|
-
console.log('Actually, not supported - will be added later !')
|
|
1174
|
-
break
|
|
1124
|
+
throw new Error('Unsupported CONSTANT token in Polynom parser')
|
|
1175
1125
|
|
|
1176
1126
|
case ShutingyardType.OPERATION:
|
|
1177
1127
|
if (stack.length >= 2) {
|
|
@@ -1180,7 +1130,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1180
1130
|
|
|
1181
1131
|
// Check if the polynoms are not undefined.
|
|
1182
1132
|
if (a === undefined || b === undefined) {
|
|
1183
|
-
|
|
1133
|
+
throw new Error('Unexpected undefined operand in Polynom parser stack')
|
|
1184
1134
|
}
|
|
1185
1135
|
|
|
1186
1136
|
if (element.token === '+') {
|
|
@@ -1191,7 +1141,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1191
1141
|
stack.push(a.multiply(b))
|
|
1192
1142
|
} else if (element.token === '/') {
|
|
1193
1143
|
if (b.degree().isStrictlyPositive()) {
|
|
1194
|
-
|
|
1144
|
+
throw new Error('Cannot divide a Polynom by another Polynom of degree > 0')
|
|
1195
1145
|
} else {
|
|
1196
1146
|
// a.divide(b.monoms[0].coefficient)
|
|
1197
1147
|
stack.push(a.divide(b.monoms[0].coefficient))
|
|
@@ -1212,7 +1162,7 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1212
1162
|
|
|
1213
1163
|
stack.push(a)
|
|
1214
1164
|
} else {
|
|
1215
|
-
|
|
1165
|
+
throw new Error('Cannot raise a multi-monom Polynom to a fractional power')
|
|
1216
1166
|
}
|
|
1217
1167
|
}
|
|
1218
1168
|
}
|
|
@@ -1231,16 +1181,42 @@ export class Polynom implements IPiMathObject<Polynom>,
|
|
|
1231
1181
|
|
|
1232
1182
|
case ShutingyardType.MONOM:
|
|
1233
1183
|
// Should never appear.
|
|
1234
|
-
|
|
1235
|
-
break
|
|
1184
|
+
throw new Error('Unexpected MONOM token in polynom parser')
|
|
1236
1185
|
|
|
1237
1186
|
case ShutingyardType.FUNCTION:
|
|
1238
1187
|
// Should never appear.
|
|
1239
|
-
|
|
1240
|
-
|
|
1188
|
+
throw new Error(`Unsupported function token "${element.token}" in polynom parser`)
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Main parse using a shutting yard class
|
|
1196
|
+
* @param inputStr
|
|
1197
|
+
*/
|
|
1198
|
+
#shutingYardToReducedPolynom(inputStr: string): this {
|
|
1199
|
+
// Get the RPN array of the current expression
|
|
1200
|
+
const SY: ShutingYard = new ShutingYard().parse(inputStr)
|
|
1201
|
+
const rpn: { token: string, tokenType: ShutingyardType }[] = SY.rpn
|
|
1202
|
+
|
|
1203
|
+
// New version for reducing shuting yard.
|
|
1204
|
+
this.zero()
|
|
1205
|
+
|
|
1206
|
+
const stack: Polynom[] = []
|
|
1207
|
+
|
|
1208
|
+
// Loop through the each element of the RPN
|
|
1209
|
+
for (const element of rpn) {
|
|
1210
|
+
this.#shutingYardAddToken(stack, element)
|
|
1241
1211
|
}
|
|
1242
1212
|
|
|
1243
1213
|
|
|
1214
|
+
if (stack.length === 1) {
|
|
1215
|
+
this.add(stack[0])
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
return this.reorder()
|
|
1244
1220
|
}
|
|
1245
1221
|
|
|
1246
1222
|
|