pimath 0.1.39 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pimath.js +188 -159
- package/dist/pimath.js.map +1 -1
- package/package.json +4 -2
- package/src/algebra/equation.ts +556 -0
- package/src/algebra/equationSolver.ts +539 -0
- package/src/algebra/factor.ts +339 -0
- package/src/algebra/index.ts +11 -0
- package/src/algebra/linearSystem.ts +388 -0
- package/src/algebra/logicalset.ts +256 -0
- package/src/algebra/matrix.ts +474 -0
- package/src/algebra/monom.ts +1015 -0
- package/src/algebra/operations.ts +24 -0
- package/src/algebra/polyFactor.ts +668 -0
- package/src/algebra/polynom.ts +1394 -0
- package/src/analyze/solution.ts +115 -0
- package/src/analyze/tableOfSigns.ts +30 -0
- package/src/coefficients/fraction.ts +678 -0
- package/src/coefficients/index.ts +4 -0
- package/src/coefficients/nthRoot.ts +149 -0
- package/src/coefficients/root.ts +299 -0
- package/src/geometry/circle.ts +386 -0
- package/src/geometry/geomMath.ts +70 -0
- package/src/geometry/index.ts +10 -0
- package/src/geometry/line.ts +677 -0
- package/src/geometry/line3.ts +206 -0
- package/src/geometry/plane3.ts +170 -0
- package/src/geometry/point.ts +66 -0
- package/src/geometry/sphere3.ts +214 -0
- package/src/geometry/triangle.ts +354 -0
- package/src/geometry/vector.ts +341 -0
- package/src/helpers.ts +35 -0
- package/src/index.ts +60 -0
- package/src/numeric.ts +199 -0
- package/src/pimath.interface.ts +160 -0
- package/src/randomization/algebra/rndEquation.ts +41 -0
- package/src/randomization/algebra/rndMonom.ts +39 -0
- package/src/randomization/algebra/rndPolynom.ts +86 -0
- package/src/randomization/coefficient/rndFraction.ts +38 -0
- package/src/randomization/geometry/rndCircle.ts +27 -0
- package/src/randomization/geometry/rndLine.ts +37 -0
- package/src/randomization/geometry/rndLine3.ts +27 -0
- package/src/randomization/geometry/rndVector.ts +63 -0
- package/src/randomization/random.ts +91 -0
- package/src/randomization/rndHelpers.ts +102 -0
- package/src/randomization/rndTypes.ts +63 -0
- package/types/algebra/equationSolver.d.ts +3 -0
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +5 -0
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/analyze/solution.d.ts +21 -0
- package/types/analyze/solution.d.ts.map +1 -0
- package/types/analyze/tableOfSigns.d.ts +9 -0
- package/types/analyze/tableOfSigns.d.ts.map +1 -0
- package/types/coefficients/root.d.ts +38 -0
- package/types/coefficients/root.d.ts.map +1 -0
- package/types/geometry/point.d.ts +1 -1
- package/types/geometry/point.d.ts.map +1 -1
- package/types/helpers.d.ts +1 -0
- package/types/helpers.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/numeric.d.ts +2 -0
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +26 -26
- package/types/pimath.interface.d.ts.map +1 -1
|
@@ -0,0 +1,1015 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Monom class
|
|
3
|
+
*/
|
|
4
|
+
import type {
|
|
5
|
+
IAlgebra,
|
|
6
|
+
IAnalyse,
|
|
7
|
+
IExpression,
|
|
8
|
+
InputAlgebra,
|
|
9
|
+
InputValue,
|
|
10
|
+
IPiMathObject,
|
|
11
|
+
literalType
|
|
12
|
+
} from "../pimath.interface"
|
|
13
|
+
import {Fraction} from "../coefficients/fraction"
|
|
14
|
+
import {NthRoot} from "../coefficients/nthRoot"
|
|
15
|
+
import {Numeric} from "../numeric"
|
|
16
|
+
|
|
17
|
+
import {ShutingYard, ShutingyardType, type Token} from "piexpression"
|
|
18
|
+
|
|
19
|
+
export class Monom implements IPiMathObject<Monom>, IExpression<Monom>, IAnalyse<Monom>, IAlgebra<Monom> {
|
|
20
|
+
#coefficient: Fraction
|
|
21
|
+
#literal: literalType<Fraction>
|
|
22
|
+
|
|
23
|
+
constructor(value?: InputValue<Fraction>)
|
|
24
|
+
constructor(value?: Monom)
|
|
25
|
+
constructor(value?: InputAlgebra<Fraction>) {
|
|
26
|
+
this.#coefficient = new Fraction().zero()
|
|
27
|
+
this.#literal = {}
|
|
28
|
+
|
|
29
|
+
if (value !== undefined) {
|
|
30
|
+
// A string is given - try to parse the value.
|
|
31
|
+
this.parse(value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// -----------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Parse a string to a monom. The string may include fraction.
|
|
40
|
+
* @param inputStr
|
|
41
|
+
*/
|
|
42
|
+
public parse(inputStr: InputAlgebra<Monom>): this {
|
|
43
|
+
// Initialize the monom
|
|
44
|
+
this.#coefficient = new Fraction()
|
|
45
|
+
this.#literal = {}
|
|
46
|
+
|
|
47
|
+
if (typeof inputStr === 'string') {
|
|
48
|
+
if(!isNaN(Number(inputStr))){
|
|
49
|
+
this.#coefficient = new Fraction(Number(inputStr))
|
|
50
|
+
}else {
|
|
51
|
+
this.#shutingYardToReducedMonom(inputStr)
|
|
52
|
+
}
|
|
53
|
+
} else if (typeof inputStr === 'number') {
|
|
54
|
+
this.#coefficient = new Fraction(inputStr)
|
|
55
|
+
} else if (inputStr instanceof Fraction) {
|
|
56
|
+
this.#coefficient = inputStr.clone()
|
|
57
|
+
} else if (inputStr instanceof Monom) {
|
|
58
|
+
this.#coefficient = inputStr.#coefficient.clone()
|
|
59
|
+
|
|
60
|
+
// Copy the literal parts
|
|
61
|
+
this.#cloneLiteral(inputStr)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return this
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Clone the current Monom.
|
|
69
|
+
*/
|
|
70
|
+
public clone = (): Monom => {
|
|
71
|
+
const F: Monom = new Monom()
|
|
72
|
+
|
|
73
|
+
F.coefficient = this.#coefficient.clone()
|
|
74
|
+
|
|
75
|
+
// Copy the literal parts.
|
|
76
|
+
for (const k in this.#literal) {
|
|
77
|
+
F.setLetter(k, this.#literal[k].clone())
|
|
78
|
+
}
|
|
79
|
+
return F
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get the tex output of the monom
|
|
84
|
+
*/
|
|
85
|
+
public get tex(): string {
|
|
86
|
+
// TODO: display with square root !
|
|
87
|
+
// TODO: Refactor to make it more readable
|
|
88
|
+
let L = ''
|
|
89
|
+
const letters = Object.keys(this.#literal).sort()
|
|
90
|
+
|
|
91
|
+
for (const letter of letters) {
|
|
92
|
+
if (this.#literal[letter].isNotZero()) {
|
|
93
|
+
L += letter
|
|
94
|
+
if (this.#literal[letter].isNotEqual(1)) {
|
|
95
|
+
L += `^{ ${this.#literal[letter].tfrac.tex } }`
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (L === '') {
|
|
101
|
+
// No setLetter - means it's only a number !
|
|
102
|
+
if (this.#coefficient.value != 0) {
|
|
103
|
+
return this.#coefficient.frac.tex
|
|
104
|
+
} else {
|
|
105
|
+
return '0'
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
if (this.#coefficient.value === 1) {
|
|
109
|
+
return L
|
|
110
|
+
} else if (this.#coefficient.value === -1) {
|
|
111
|
+
return `-${L}`
|
|
112
|
+
} else if (this.#coefficient.value === 0) {
|
|
113
|
+
return '0'
|
|
114
|
+
} else {
|
|
115
|
+
return `${this.#coefficient.frac.tex}${L}`
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Display getter
|
|
121
|
+
/**
|
|
122
|
+
* This display getter is to be used in the polynom display getter
|
|
123
|
+
*/
|
|
124
|
+
public get display(): string {
|
|
125
|
+
let L = ''
|
|
126
|
+
const letters = Object.keys(this.#literal).sort()
|
|
127
|
+
for (const letter of letters) {
|
|
128
|
+
if (this.#literal[letter].isNotZero()) {
|
|
129
|
+
L += letter
|
|
130
|
+
if (this.#literal[letter].isNotEqual(1)) {
|
|
131
|
+
L += `^(${this.#literal[letter].display})`
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (L === '') {
|
|
137
|
+
// No setLetter - means it's only a number !
|
|
138
|
+
if (this.#coefficient.value != 0) {
|
|
139
|
+
return this.#coefficient.display
|
|
140
|
+
} else {
|
|
141
|
+
return ''
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
if (this.#coefficient.value === 1) {
|
|
145
|
+
return L
|
|
146
|
+
} else if (this.#coefficient.value === -1) {
|
|
147
|
+
return `-${L}`
|
|
148
|
+
} else if (this.#coefficient.value === 0) {
|
|
149
|
+
return '0'
|
|
150
|
+
} else {
|
|
151
|
+
return `${this.#coefficient.display}${L}`
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public static gcd = (...monoms: Monom[]): Monom => {
|
|
157
|
+
// All the monoms must be with natural powers...
|
|
158
|
+
for (const m of monoms) {
|
|
159
|
+
if (m.containsRationalPower()) {
|
|
160
|
+
return new Monom().zero()
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const M = new Monom(),
|
|
165
|
+
n: number = Numeric.gcd(...monoms.map(value => value.coefficient.numerator)),
|
|
166
|
+
d: number = Numeric.lcm(...monoms.map(value => value.coefficient.denominator))
|
|
167
|
+
|
|
168
|
+
// Get the coefficient.
|
|
169
|
+
M.coefficient = new Fraction(n, d).reduce()
|
|
170
|
+
|
|
171
|
+
// Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.
|
|
172
|
+
for (const m of monoms) {
|
|
173
|
+
// Remove the inexistant letters from the resulting monom
|
|
174
|
+
for (const letter in M.literal) {
|
|
175
|
+
if (!(letter in m.literal)) {
|
|
176
|
+
M.literal[letter].zero()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const letter in m.literal) {
|
|
180
|
+
if (!M.hasVariable(letter) && m.literal[letter].isStrictlyPositive()) {
|
|
181
|
+
M.literal[letter] = m.literal[letter].clone()
|
|
182
|
+
} else {
|
|
183
|
+
M.literal[letter] = new Fraction(Math.min(m.literal[letter].value, M.literal[letter].value))
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return M
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Multiply two monoms and return a NEW monom.
|
|
193
|
+
* @param monoms
|
|
194
|
+
*/
|
|
195
|
+
public static xMultiply = (...monoms: Monom[]): Monom => {
|
|
196
|
+
const M = new Monom().one()
|
|
197
|
+
|
|
198
|
+
for (const m of monoms) {
|
|
199
|
+
M.multiply(m)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return M
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Add all similar monoms. If they aren't similar, they are simply skipped.
|
|
207
|
+
* @param M (Monom[]) The monoms to add.
|
|
208
|
+
*/
|
|
209
|
+
public add = (...M: InputAlgebra<Fraction>[]): this => {
|
|
210
|
+
for (const m of M) {
|
|
211
|
+
// If the value given is not a monom, create it.
|
|
212
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
213
|
+
|
|
214
|
+
if (this.isSameAs(mAsMonom)) {
|
|
215
|
+
if (this.isZero()) {
|
|
216
|
+
this.#cloneLiteral(mAsMonom)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.#coefficient.add(mAsMonom.coefficient)
|
|
220
|
+
} else {
|
|
221
|
+
console.log('Add monom: ' + this.display + ' is not similar with ', mAsMonom.display)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return this
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get the coefficient \\(k\\) of the Monom \\(k\\cdot x^{n}\\)
|
|
229
|
+
* @returns {Fraction}
|
|
230
|
+
*/
|
|
231
|
+
public get coefficient(): Fraction {
|
|
232
|
+
return this.#coefficient
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Set the coefficient \\(k\\) value of the monom
|
|
237
|
+
* @param {Fraction | number | string} F
|
|
238
|
+
*/
|
|
239
|
+
public set coefficient(F: InputValue<Fraction>) {
|
|
240
|
+
this.#coefficient = new Fraction(F)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
public containsRationalPower = (): boolean => {
|
|
244
|
+
return Object.values(this.#literal).some((value) => value.isRational())
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get the degree of a monom. If no setLetter is given, the result will be the global degree.
|
|
249
|
+
* @param letter (string) Letter to get to degree (power)
|
|
250
|
+
*/
|
|
251
|
+
public degree = (letter?: string): Fraction => {
|
|
252
|
+
if (this.variables.length === 0) {
|
|
253
|
+
return new Fraction().zero()
|
|
254
|
+
}
|
|
255
|
+
if (letter === undefined) {
|
|
256
|
+
// Not setLetter given -> we get the global monom degree (sum of all the letters).
|
|
257
|
+
return Object.values(this.#literal).reduce((t, n) => t.clone().add(n))
|
|
258
|
+
} else {
|
|
259
|
+
// A setLetter is given -> get the corresponding power.
|
|
260
|
+
return !this.hasVariable(letter) ? new Fraction().zero() : this.#literal[letter].clone()
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Derivative the monom
|
|
266
|
+
* @param letter
|
|
267
|
+
*/
|
|
268
|
+
public derivative = (letter?: string): Monom => {
|
|
269
|
+
// No setLetter given - assume it's the setLetter 'x'
|
|
270
|
+
if (letter === undefined) {
|
|
271
|
+
letter = 'x'
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (this.hasVariable(letter)) {
|
|
275
|
+
const d = this.#literal[letter].clone(),
|
|
276
|
+
dM = this.clone()
|
|
277
|
+
|
|
278
|
+
// Subtract one to the degree.
|
|
279
|
+
dM.#literal[letter].subtract(1)
|
|
280
|
+
|
|
281
|
+
// Multiply the coefficient by the previous degree
|
|
282
|
+
dM.#coefficient.multiply(new Fraction(d.clone()))
|
|
283
|
+
return dM
|
|
284
|
+
} else {
|
|
285
|
+
return new Monom().zero()
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Divide the current monoms by multiple monoms
|
|
291
|
+
* @param M (Monom[])
|
|
292
|
+
*/
|
|
293
|
+
public divide = (...M: InputAlgebra<Fraction>[]): this => {
|
|
294
|
+
// Depending on the given value, choose the current item
|
|
295
|
+
for (const m of M) {
|
|
296
|
+
// If the value given is not a monom, create it.
|
|
297
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
298
|
+
|
|
299
|
+
// Divide the coefficient
|
|
300
|
+
this.#coefficient.divide(mAsMonom.coefficient)
|
|
301
|
+
|
|
302
|
+
// Subtract the power values
|
|
303
|
+
for (const letter in mAsMonom.literal) {
|
|
304
|
+
|
|
305
|
+
this.#literal[letter] = this.hasVariable(letter) ?
|
|
306
|
+
this.#literal[letter].subtract(mAsMonom.literal[letter]) :
|
|
307
|
+
mAsMonom.literal[letter].clone().opposite()
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
// If the power of a particular setLetter is zero, delete it from the literal part..
|
|
311
|
+
if (this.#literal[letter].isZero()) {
|
|
312
|
+
this.removeVariable(letter)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return this
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
public get dividers(): Monom[] {
|
|
320
|
+
// Decompose only if the coefficient is a natural number
|
|
321
|
+
if (!this.coefficient.isRelative()) {
|
|
322
|
+
return [this.clone()]
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Decompose only if the power values are natural numbers.
|
|
326
|
+
if (this.containsRationalPower()) {
|
|
327
|
+
return [this.clone()]
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Security : do not do this if greater than 10000
|
|
331
|
+
if (this.coefficient.numerator > 1000000) {
|
|
332
|
+
return [this.clone()]
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))
|
|
336
|
+
|
|
337
|
+
// Decompose the literals parts.
|
|
338
|
+
let literals: literalType<Fraction>[] = []
|
|
339
|
+
for (const L in this.literal) {
|
|
340
|
+
// L is the letter.
|
|
341
|
+
literals = this._getLiteralDividers(literals, L)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const monomDividers: Monom[] = []
|
|
345
|
+
if (literals.length > 0 && dividers.length > 0) {
|
|
346
|
+
for (const N of dividers) {
|
|
347
|
+
for (const L of literals) {
|
|
348
|
+
const M = new Monom()
|
|
349
|
+
M.coefficient = new Fraction(N)
|
|
350
|
+
M.literal = L
|
|
351
|
+
monomDividers.push(M)
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
} else if (dividers.length === 0) {
|
|
355
|
+
for (const L of literals) {
|
|
356
|
+
const M = new Monom()
|
|
357
|
+
M.coefficient = new Fraction().one()
|
|
358
|
+
M.literal = L
|
|
359
|
+
monomDividers.push(M)
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
for (const N of dividers) {
|
|
363
|
+
const M = new Monom()
|
|
364
|
+
M.coefficient = new Fraction(N)
|
|
365
|
+
monomDividers.push(M)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return monomDividers.length === 0 ? [new Monom().one()] : monomDividers
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Evaluate a monom. Each setLetter must be assigned to a Fraction.
|
|
374
|
+
* @param values Dictionary of <setLetter: Fraction>
|
|
375
|
+
* @param asNumeric
|
|
376
|
+
*/
|
|
377
|
+
public evaluate = (values: literalType<number | Fraction> | InputValue<Fraction>, asNumeric?: boolean): Fraction | number => {
|
|
378
|
+
// If as numeric return the numeric value
|
|
379
|
+
if (asNumeric === true) {
|
|
380
|
+
// Convert all values to numeric
|
|
381
|
+
// If the value is a Fraction, convert it to a number
|
|
382
|
+
if (values instanceof Fraction) {
|
|
383
|
+
return this.#evaluateAsNumeric(values.value)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// If the value is a NthRoot, return undefined
|
|
387
|
+
if (values instanceof NthRoot) {
|
|
388
|
+
return new Fraction().invalid()
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// If the value is a number, return the numeric value
|
|
392
|
+
if (typeof values === 'number') {
|
|
393
|
+
return this.#evaluateAsNumeric(values)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// If the value is an object, return the numeric value
|
|
397
|
+
if (typeof values === 'object') {
|
|
398
|
+
// Convert {[key:string]:Fraction} to {[key:string]:number}
|
|
399
|
+
const tmpValues: literalType<number> = {}
|
|
400
|
+
for (const L in values) {
|
|
401
|
+
tmpValues[L] = new Fraction(values[L]).value
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return this.#evaluateAsNumeric(tmpValues)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// The answer must be a Fraction
|
|
409
|
+
const r = this.coefficient.clone()
|
|
410
|
+
|
|
411
|
+
if (typeof values === 'number' || values instanceof Fraction) {
|
|
412
|
+
const tmpValues: literalType<Fraction> = {}
|
|
413
|
+
tmpValues[this.variables[0]] = new Fraction(values)
|
|
414
|
+
return this.evaluate(tmpValues)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (values instanceof NthRoot) {
|
|
418
|
+
return new Fraction().invalid()
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (typeof values === 'object') {
|
|
422
|
+
if (this.variables.length === 0) {
|
|
423
|
+
return this.coefficient
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
for (const L in this.#literal) {
|
|
427
|
+
const value = new Fraction(values[L])
|
|
428
|
+
|
|
429
|
+
r.multiply(value.pow(this.#literal[L]))
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return r
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// -------------------------------------
|
|
437
|
+
/**
|
|
438
|
+
* Determine if a monom contains a setLetter in it's literal part
|
|
439
|
+
* @param letter
|
|
440
|
+
*/
|
|
441
|
+
public hasVariable = (letter?: string): boolean => {
|
|
442
|
+
// The letter was not found
|
|
443
|
+
return Object.hasOwn(this.#literal, letter ?? 'x')
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
public integrate(a: InputValue<Fraction>, b: InputValue<Fraction>, letter?: string ): Fraction {
|
|
447
|
+
const primitive = this.primitive(letter)
|
|
448
|
+
|
|
449
|
+
return (primitive.evaluate(b) as Fraction)
|
|
450
|
+
.subtract(primitive.evaluate(a) as Fraction)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
public inverse = (): this => {
|
|
454
|
+
this.#coefficient.opposite()
|
|
455
|
+
for (const letter in this.#literal) {
|
|
456
|
+
this.#literal[letter].opposite()
|
|
457
|
+
}
|
|
458
|
+
return this
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
public isDivisible = (div: Monom): boolean => {
|
|
462
|
+
// For all variables (letters), the current monom must have a degree higher than the divider
|
|
463
|
+
if (div.degree().isStrictlyPositive()) {
|
|
464
|
+
for (const letter of div.variables) {
|
|
465
|
+
if (!this.degree(letter).isGeq(div.degree(letter))) {
|
|
466
|
+
return false
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// If the coefficient is rational, we suppose we don't need to check the division by the coefficient.
|
|
472
|
+
if (this.coefficient.isRational() || div.coefficient.isRational()) {
|
|
473
|
+
return true
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return this.coefficient.clone().divide(div.coefficient).isRelative()
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Determine if two monoms are equals
|
|
481
|
+
* @param M
|
|
482
|
+
*/
|
|
483
|
+
public isEqual = (M: Monom): boolean => {
|
|
484
|
+
return this.isSameAs(M) && this.#coefficient.isEqual(M.coefficient)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
public isLiteralSquare = (): boolean => {
|
|
488
|
+
for (const letter in this.literal) {
|
|
489
|
+
// A literal square must have a natural power
|
|
490
|
+
if (this.literal[letter].isRational()) {
|
|
491
|
+
return false
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// The natural power must be be even
|
|
495
|
+
if (this.literal[letter].isEven()) {
|
|
496
|
+
return false
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return true
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Determine if the monom is one
|
|
505
|
+
*/
|
|
506
|
+
public isOne = (): boolean => {
|
|
507
|
+
return this.#coefficient.value === 1 && this.variables.length === 0
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Determine if two monoms are similar
|
|
512
|
+
* @param M
|
|
513
|
+
*/
|
|
514
|
+
public isSameAs = (M: Monom): boolean => {
|
|
515
|
+
// Get the list of all variables from both monoms.
|
|
516
|
+
const M1: string[] = this.variables
|
|
517
|
+
const M2: string[] = M.variables
|
|
518
|
+
|
|
519
|
+
// Get the list of all variables from both monoms.
|
|
520
|
+
const K: string[] = M1.concat(M2.filter((item) => !M1.includes(item)))
|
|
521
|
+
|
|
522
|
+
// If one of the monom is zero, it is the same than the other.
|
|
523
|
+
if (this.isZero() || M.isZero()) {
|
|
524
|
+
return true
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Both monoms has no literal part.
|
|
528
|
+
if (M1.length === 0 && M2.length === 0) {
|
|
529
|
+
return true
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Both monoms must have the same variables
|
|
533
|
+
if (M1.length !== M2.length) {
|
|
534
|
+
return false
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// To _compare, both must be different from zero.
|
|
538
|
+
if (!this.isZero() && !M.isZero()) {
|
|
539
|
+
for (const key of K) {
|
|
540
|
+
// The variable is not available in one of the monom
|
|
541
|
+
if (!this.hasVariable(key) || !M.hasVariable(key)) {
|
|
542
|
+
return false
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// The variable does not have the same power in each monoms.
|
|
546
|
+
if (!this.#literal[key].isEqual(M.literal[key])) {
|
|
547
|
+
return false
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// All are positive check - the monoms are the sames.
|
|
553
|
+
return true
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
public isSquare = (): boolean => {
|
|
557
|
+
if (!this.coefficient.isSquare()) {
|
|
558
|
+
return false
|
|
559
|
+
}
|
|
560
|
+
return this.isLiteralSquare()
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Determine if the monom is null
|
|
565
|
+
*/
|
|
566
|
+
public isZero = (): boolean => {
|
|
567
|
+
return this.#coefficient.value === 0
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Get the literal part of \\(x^{n_1}y^{n_2}\\) as dictionary \\[\\begin{array}{ll}x&=n_1\\\\y&=n_2\\end{array}\\]
|
|
572
|
+
* @returns {literalType}
|
|
573
|
+
*/
|
|
574
|
+
public get literal(): literalType<Fraction> {
|
|
575
|
+
return this.#literal
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}
|
|
580
|
+
* @param {literalType<Fraction>} L
|
|
581
|
+
*/
|
|
582
|
+
public set literal(L: literalType<Fraction>) {
|
|
583
|
+
this.#literal = L
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Get the literal square roots of the Monom.
|
|
588
|
+
* @returns {literalType<Fraction>}
|
|
589
|
+
*/
|
|
590
|
+
public get literalSqrt(): literalType<Fraction> {
|
|
591
|
+
// TODO: used in Polynom._factorize2ndDegree : remove it from here ?
|
|
592
|
+
if (this.isLiteralSquare()) {
|
|
593
|
+
const L: literalType<Fraction> = {}
|
|
594
|
+
for (const key in this.#literal) {
|
|
595
|
+
L[key] = this.#literal[key].clone().sqrt()
|
|
596
|
+
}
|
|
597
|
+
return L
|
|
598
|
+
} else {
|
|
599
|
+
return this.#literal
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Set the literal part of the monom from a string
|
|
605
|
+
* @param inputStr String like x^2y^3
|
|
606
|
+
*/
|
|
607
|
+
public set literalStr(inputStr: string) {
|
|
608
|
+
// TODO : parse using ShutingYard tree !
|
|
609
|
+
|
|
610
|
+
// Match all x^n
|
|
611
|
+
for (const v of [...inputStr.matchAll(/([a-z])\^([+-]?[0-9]+)/g)]) {
|
|
612
|
+
// Create the default letter entry if necessary.
|
|
613
|
+
if (!(v[1] in this.#literal)) {
|
|
614
|
+
this.#literal[v[1]] = new Fraction().zero()
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Add the new value.
|
|
618
|
+
// TODO: actually, it adds only numeric value
|
|
619
|
+
this.#literal[v[1]].add(+v[2])
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Match all x
|
|
623
|
+
for (const v of [...inputStr.matchAll(/([a-z](?!\^))/g)]) {
|
|
624
|
+
// Match all single letters
|
|
625
|
+
if (!(v[1] in this.#literal)) {
|
|
626
|
+
this.#literal[v[1]] = new Fraction().zero()
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Add one to the value.
|
|
630
|
+
this.#literal[v[1]].add(1)
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Multiple multiple monoms to the current monom
|
|
636
|
+
* @param M (Monom[]) The monoms to multiply to.
|
|
637
|
+
*/
|
|
638
|
+
public multiply = (...M: InputAlgebra<Fraction>[]): this => {
|
|
639
|
+
for (const m of M) {
|
|
640
|
+
// If the value given is not a monom, create it.
|
|
641
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
642
|
+
|
|
643
|
+
// Multiply the coefficient.
|
|
644
|
+
this.#coefficient.multiply(mAsMonom.coefficient)
|
|
645
|
+
|
|
646
|
+
// Multiply the literal parts.
|
|
647
|
+
for (const letter in mAsMonom.literal) {
|
|
648
|
+
if (!this.hasVariable(letter)) {
|
|
649
|
+
this.#literal[letter] = mAsMonom.literal[letter].clone()
|
|
650
|
+
} else {
|
|
651
|
+
this.#literal[letter].add(mAsMonom.literal[letter])
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return this
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Create a one value monom
|
|
660
|
+
*/
|
|
661
|
+
public one = (): this => {
|
|
662
|
+
this.#coefficient = new Fraction().one()
|
|
663
|
+
this.#literal = {}
|
|
664
|
+
return this
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Get the opposite
|
|
669
|
+
* Returns a monom.
|
|
670
|
+
*/
|
|
671
|
+
public opposite = (): this => {
|
|
672
|
+
this.#coefficient.opposite()
|
|
673
|
+
return this
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
public get plotFunction(): string {
|
|
677
|
+
let L = ''
|
|
678
|
+
const letters = Object.keys(this.#literal).sort()
|
|
679
|
+
|
|
680
|
+
for (const letter of letters) {
|
|
681
|
+
if (this.#literal[letter].isNotZero()) {
|
|
682
|
+
L += (L === '' ? "" : "*") + letter
|
|
683
|
+
if (this.#literal[letter].isNotEqual(1)) {
|
|
684
|
+
L += `^(${this.#literal[letter].display})`
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// No literal part
|
|
690
|
+
if (L === '') {
|
|
691
|
+
// No setLetter - means it's only a number !
|
|
692
|
+
if (this.#coefficient.value != 0) {
|
|
693
|
+
return this.#coefficient.display
|
|
694
|
+
} else {
|
|
695
|
+
return ''
|
|
696
|
+
}
|
|
697
|
+
} else {
|
|
698
|
+
if (this.#coefficient.value === 1) {
|
|
699
|
+
return L
|
|
700
|
+
} else if (this.#coefficient.value === -1) {
|
|
701
|
+
return `-${L}`
|
|
702
|
+
} else if (this.#coefficient.value === 0) {
|
|
703
|
+
return '0'
|
|
704
|
+
} else {
|
|
705
|
+
return `${this.#coefficient.display}*${L}`
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Get the pow of a monom.
|
|
712
|
+
* @param nb (number) : Mathematical pow
|
|
713
|
+
*/
|
|
714
|
+
public pow = (nb: number | Fraction): this => {
|
|
715
|
+
this.#coefficient.pow(nb)
|
|
716
|
+
for (const letter in this.#literal) {
|
|
717
|
+
this.#literal[letter].multiply(nb)
|
|
718
|
+
}
|
|
719
|
+
return this
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
public primitive = (letter?: string): Monom => {
|
|
723
|
+
// TODO: derivative including the ln value => implies creating different monom system ?
|
|
724
|
+
if (letter === undefined) {
|
|
725
|
+
letter = 'x'
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Zero monom
|
|
729
|
+
const M = this.clone()
|
|
730
|
+
let degree: Fraction
|
|
731
|
+
|
|
732
|
+
if (M.hasVariable(letter)) {
|
|
733
|
+
degree = M.degree(letter).clone().add(1)
|
|
734
|
+
M.coefficient = M.coefficient.clone().divide(degree)
|
|
735
|
+
M.setLetter(letter, degree)
|
|
736
|
+
} else {
|
|
737
|
+
// There is no letter.
|
|
738
|
+
|
|
739
|
+
// The coefficient might be zero (=> x) or a number a (=> ax)
|
|
740
|
+
if (M.coefficient.isZero()) {
|
|
741
|
+
M.coefficient = new Fraction().one()
|
|
742
|
+
}
|
|
743
|
+
M.setLetter(letter, 1)
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return M
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
public reduce = (): this => {
|
|
750
|
+
// Reduce the coefficient
|
|
751
|
+
this.coefficient.reduce()
|
|
752
|
+
|
|
753
|
+
// Reduce the literal parts (removing null powers)
|
|
754
|
+
for (const letter in this.#literal) {
|
|
755
|
+
if (this.#literal[letter].isZero()) {
|
|
756
|
+
this.removeVariable(letter)
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return this
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
public removeVariable(letter: string) {
|
|
763
|
+
/* eslint-disable */
|
|
764
|
+
delete this.#literal[letter]
|
|
765
|
+
/* eslint-enable */
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Get the nth-root of the monom
|
|
770
|
+
*/
|
|
771
|
+
public root = (): this => {
|
|
772
|
+
throw new Error('Method not implemented.')
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Set the power of a particular setLetter
|
|
777
|
+
* @param letter (string) Letter to change
|
|
778
|
+
* @param pow (number) Power of the setLetter (must be positive integer.
|
|
779
|
+
*/
|
|
780
|
+
public setLetter = (letter: string, pow: InputValue<Fraction>): this => {
|
|
781
|
+
if (!(pow instanceof Fraction)) {
|
|
782
|
+
return this.setLetter(letter, new Fraction(pow))
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Set the power of the letter to zero => remove it
|
|
786
|
+
if (this.hasVariable(letter) && pow.isZero()) {
|
|
787
|
+
this.removeVariable(letter)
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
this.#literal[letter] = pow.clone()
|
|
792
|
+
|
|
793
|
+
return this
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Return the square root of a monom
|
|
798
|
+
*/
|
|
799
|
+
public sqrt = (): this => {
|
|
800
|
+
if (this.isSquare()) {
|
|
801
|
+
this.#coefficient.sqrt()
|
|
802
|
+
for (const letter in this.#literal) {
|
|
803
|
+
this.#literal[letter].clone().divide(2)
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return this
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Subtract multiple monoms
|
|
812
|
+
* @param M (Monom[]) The monoms to subtract
|
|
813
|
+
*/
|
|
814
|
+
public subtract = (...M: InputAlgebra<Fraction>[]): this => {
|
|
815
|
+
for (const m of M) {
|
|
816
|
+
// If the value given is not a monom, create it.
|
|
817
|
+
const mAsMonom = (!(m instanceof Monom)) ? new Monom(m) : m
|
|
818
|
+
|
|
819
|
+
if (this.isSameAs(mAsMonom)) {
|
|
820
|
+
if (this.isZero()) {
|
|
821
|
+
this.#cloneLiteral(mAsMonom)
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
this.#coefficient.add(mAsMonom.clone().coefficient.opposite())
|
|
825
|
+
} else {
|
|
826
|
+
console.log('Subtract: Is not similar: ', mAsMonom.display)
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return this
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Getter helpers.
|
|
833
|
+
/**
|
|
834
|
+
* Get the variables letters
|
|
835
|
+
*/
|
|
836
|
+
public get variables(): string[] {
|
|
837
|
+
// const M = this.clone().clean()
|
|
838
|
+
|
|
839
|
+
const L: string[] = []
|
|
840
|
+
Object.entries(this.literal).forEach(
|
|
841
|
+
([key, value]) => {
|
|
842
|
+
if (!value.isZero()) {
|
|
843
|
+
L.push(key)
|
|
844
|
+
}
|
|
845
|
+
})
|
|
846
|
+
L.sort()
|
|
847
|
+
return L
|
|
848
|
+
// return Object.keys(M.literal)
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Create a zero value monom
|
|
853
|
+
*/
|
|
854
|
+
public zero = (): this => {
|
|
855
|
+
this.#coefficient = new Fraction().zero()
|
|
856
|
+
this.#literal = {}
|
|
857
|
+
return this
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
#cloneLiteral(inputStr: Monom) {
|
|
861
|
+
for (const k in inputStr.literal) {
|
|
862
|
+
this.#literal[k] = inputStr.literal[k].clone()
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
#evaluateAsNumeric = (values: literalType<number | Fraction> | InputValue<Fraction>): number => {
|
|
867
|
+
let r = this.coefficient.value
|
|
868
|
+
|
|
869
|
+
if (typeof values === "number") {
|
|
870
|
+
const tmpValues: literalType<number> = {}
|
|
871
|
+
const key = this.variables[0]
|
|
872
|
+
tmpValues[key] = values
|
|
873
|
+
|
|
874
|
+
return this.#evaluateAsNumeric(tmpValues)
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (values instanceof Fraction) {
|
|
878
|
+
const tmpValues: literalType<number> = {}
|
|
879
|
+
tmpValues[this.variables[0]] = new Fraction(values).value
|
|
880
|
+
return this.#evaluateAsNumeric(tmpValues)
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (values instanceof NthRoot) {
|
|
884
|
+
return NaN
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
if (typeof values === 'object') {
|
|
888
|
+
if (this.variables.length === 0) {
|
|
889
|
+
return this.coefficient.value
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
for (const L in this.#literal) {
|
|
893
|
+
const v = values[L]
|
|
894
|
+
|
|
895
|
+
if (v instanceof Fraction) {
|
|
896
|
+
r *= v.value ** (this.#literal[L].value)
|
|
897
|
+
} else {
|
|
898
|
+
r *= v ** (this.#literal[L].value)
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return r
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
#shutingYardToReducedMonom = (inputStr: string): this => {
|
|
907
|
+
// Get the RPN array of the current expression
|
|
908
|
+
const SY: ShutingYard = new ShutingYard().parse(inputStr)
|
|
909
|
+
const rpn: { token: string, tokenType: ShutingyardType }[] = SY.rpn
|
|
910
|
+
|
|
911
|
+
const stack: Monom[] = []
|
|
912
|
+
|
|
913
|
+
if (rpn.length === 0) {
|
|
914
|
+
this.zero()
|
|
915
|
+
return this
|
|
916
|
+
} else if (rpn.length === 1) {
|
|
917
|
+
const element = rpn[0]
|
|
918
|
+
|
|
919
|
+
this.one()
|
|
920
|
+
if (element.tokenType === ShutingyardType.COEFFICIENT) {
|
|
921
|
+
this.coefficient = new Fraction(element.token)
|
|
922
|
+
} else if (element.tokenType === ShutingyardType.VARIABLE) {
|
|
923
|
+
this.setLetter(element.token, 1)
|
|
924
|
+
}
|
|
925
|
+
return this
|
|
926
|
+
} else {
|
|
927
|
+
// Reset the monom
|
|
928
|
+
for (const element of rpn) {
|
|
929
|
+
this.#shutingYard_AddToken(stack, element)
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
this.one()
|
|
934
|
+
this.multiply(stack[0])
|
|
935
|
+
return this
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
#shutingYard_AddToken = (stack: Monom[], element: Token): void => {
|
|
939
|
+
let q1: Monom, q2: Monom, m: Monom, letter: string, pow: Fraction
|
|
940
|
+
|
|
941
|
+
if (element.tokenType === ShutingyardType.COEFFICIENT) {
|
|
942
|
+
stack.push(new Monom(new Fraction(element.token)))
|
|
943
|
+
|
|
944
|
+
} else if (element.tokenType === ShutingyardType.VARIABLE) {
|
|
945
|
+
const M = new Monom().one()
|
|
946
|
+
M.setLetter(element.token, 1)
|
|
947
|
+
stack.push(M.clone())
|
|
948
|
+
|
|
949
|
+
} else if (element.tokenType === ShutingyardType.OPERATION) {
|
|
950
|
+
switch (element.token) {
|
|
951
|
+
case '-':
|
|
952
|
+
// this should only happen for negative powers or for negative coefficient.
|
|
953
|
+
q2 = (stack.pop()) ?? new Monom().zero()
|
|
954
|
+
q1 = (stack.pop()) ?? new Monom().zero()
|
|
955
|
+
|
|
956
|
+
stack.push(q1.subtract(q2))
|
|
957
|
+
|
|
958
|
+
break
|
|
959
|
+
case '*':
|
|
960
|
+
// Get the last element in the stack
|
|
961
|
+
q2 = (stack.pop()) ?? new Monom().one()
|
|
962
|
+
q1 = (stack.pop()) ?? new Monom().one()
|
|
963
|
+
|
|
964
|
+
stack.push(q1.multiply(q2))
|
|
965
|
+
break
|
|
966
|
+
case '/':
|
|
967
|
+
// Get the last element in the stack
|
|
968
|
+
q2 = (stack.pop()) ?? new Monom().one()
|
|
969
|
+
q1 = (stack.pop()) ?? new Monom().one()
|
|
970
|
+
|
|
971
|
+
stack.push(q1.divide(q2))
|
|
972
|
+
break
|
|
973
|
+
case '^': {
|
|
974
|
+
// get the two last elements in the stack
|
|
975
|
+
const poppedCoefficient = stack.pop()?.coefficient
|
|
976
|
+
pow = poppedCoefficient ?? new Fraction().one()
|
|
977
|
+
m = stack.pop() ?? new Monom().one()
|
|
978
|
+
|
|
979
|
+
letter = m.variables[0]
|
|
980
|
+
|
|
981
|
+
if (letter) {
|
|
982
|
+
m.setLetter(letter, pow)
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
stack.push(m)
|
|
986
|
+
// this.multiply(m.clone())
|
|
987
|
+
break
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
private _getLiteralDividers(arr: literalType<Fraction>[], letter: string): literalType<Fraction>[] {
|
|
994
|
+
const tmpList: Record<string, Fraction>[] = []
|
|
995
|
+
|
|
996
|
+
// Be default, this.literal[letter] should be a rational number.
|
|
997
|
+
for (let d = 0; d <= this.literal[letter].value; d++) {
|
|
998
|
+
if (arr.length === 0) {
|
|
999
|
+
const litt: literalType<Fraction> = {}
|
|
1000
|
+
litt[letter] = new Fraction(d)
|
|
1001
|
+
tmpList.push(litt)
|
|
1002
|
+
} else {
|
|
1003
|
+
for (const item of arr) {
|
|
1004
|
+
const litt: literalType<Fraction> = {}
|
|
1005
|
+
for (const currentLetter in item) {
|
|
1006
|
+
litt[currentLetter] = item[currentLetter]
|
|
1007
|
+
}
|
|
1008
|
+
litt[letter] = new Fraction(d)
|
|
1009
|
+
tmpList.push(litt)
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return tmpList
|
|
1014
|
+
}
|
|
1015
|
+
}
|