pimath 0.0.120 → 0.0.122

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/.idea/PI.iml +7 -1
  2. package/.idea/shelf/Uncommitted_changes_before_Update_at_24_07_2023_15_31_[Default_Changelist]/shelved.patch +90 -0
  3. package/.idea/shelf/Uncommitted_changes_before_Update_at_24_07_2023_15_31_[Default_Changelist]1/shelved.patch +107 -0
  4. package/.idea/shelf/Uncommitted_changes_before_Update_at_24_07_2023_15_31__Default_Changelist_.xml +4 -0
  5. package/.idea/shelf/Uncommitted_changes_before_Update_at_24_07_2023_15_31__Default_Changelist_1.xml +4 -0
  6. package/LICENSE.md +1 -1
  7. package/dev/pimath.js +7929 -0
  8. package/dev/pimath.js.map +1 -0
  9. package/dist/{pi.js → pimath.js} +7613 -7840
  10. package/dist/pimath.js.map +1 -0
  11. package/dist/pimath.min.js +2 -0
  12. package/dist/pimath.min.js.map +1 -0
  13. package/docs/assets/main.js +58 -58
  14. package/docs/assets/search.js +1 -1
  15. package/docs/assets/style.css +1367 -1280
  16. package/docs/classes/Logicalset.Logicalset.html +221 -212
  17. package/docs/classes/Polynom.Rational.html +391 -388
  18. package/docs/classes/Vector-1.Vector.html +494 -448
  19. package/docs/classes/Vector.Point.html +341 -342
  20. package/docs/classes/algebra_equation.Equation.html +796 -753
  21. package/docs/classes/algebra_linearSystem.LinearSystem.html +408 -397
  22. package/docs/classes/algebra_monom.Monom.html +967 -910
  23. package/docs/classes/algebra_polynom.Polynom.html +1281 -1260
  24. package/docs/classes/coefficients_fraction.Fraction.html +939 -931
  25. package/docs/classes/geometry_circle.Circle.html +476 -476
  26. package/docs/classes/geometry_line.Line.html +779 -719
  27. package/docs/classes/geometry_triangle.Triangle.html +429 -420
  28. package/docs/classes/numeric.Numeric.html +269 -263
  29. package/docs/classes/shutingyard.Shutingyard.html +259 -248
  30. package/docs/enums/algebra_equation.PARTICULAR_SOLUTION.html +89 -88
  31. package/docs/enums/geometry_line.LinePropriety.html +102 -102
  32. package/docs/enums/shutingyard.ShutingyardMode.html +106 -102
  33. package/docs/enums/shutingyard.ShutingyardType.html +120 -116
  34. package/docs/index.html +63 -65
  35. package/docs/interfaces/algebra_equation.ISolution.html +111 -109
  36. package/docs/interfaces/algebra_polynom.IEuclidian.html +93 -92
  37. package/docs/interfaces/geometry_triangle.remarquableLines.html +150 -150
  38. package/docs/modules/Logicalset.html +69 -74
  39. package/docs/modules/Polynom.html +69 -74
  40. package/docs/modules/Vector-1.html +69 -74
  41. package/docs/modules/Vector.html +69 -74
  42. package/docs/modules/algebra_equation.html +75 -81
  43. package/docs/modules/algebra_linearSystem.html +65 -71
  44. package/docs/modules/algebra_monom.html +70 -76
  45. package/docs/modules/algebra_polynom.html +75 -81
  46. package/docs/modules/coefficients_fraction.html +70 -76
  47. package/docs/modules/geometry_circle.html +65 -71
  48. package/docs/modules/geometry_line.html +70 -76
  49. package/docs/modules/geometry_triangle.html +70 -76
  50. package/docs/modules/numeric.html +65 -71
  51. package/docs/modules/shutingyard.html +84 -90
  52. package/docs/types/algebra_monom.literalType.html +66 -70
  53. package/docs/types/algebra_polynom.PolynomParsingType.html +62 -66
  54. package/docs/types/coefficients_fraction.FractionParsingType.html +61 -65
  55. package/docs/types/shutingyard.Token.html +72 -76
  56. package/docs/types/shutingyard.tokenType.html +77 -81
  57. package/docs/variables/shutingyard.tokenConstant.html +70 -74
  58. package/esm/index.d.ts +38 -41
  59. package/esm/index.js +43 -46
  60. package/esm/index.js.map +1 -1
  61. package/esm/maths/algebra/equation.d.ts +119 -117
  62. package/esm/maths/algebra/equation.js +796 -785
  63. package/esm/maths/algebra/equation.js.map +1 -1
  64. package/esm/maths/algebra/linearSystem.d.ts +39 -38
  65. package/esm/maths/algebra/linearSystem.js +278 -262
  66. package/esm/maths/algebra/linearSystem.js.map +1 -1
  67. package/esm/maths/algebra/logicalset.d.ts +28 -28
  68. package/esm/maths/algebra/logicalset.js +157 -157
  69. package/esm/maths/algebra/monom.d.ts +206 -206
  70. package/esm/maths/algebra/monom.js +908 -908
  71. package/esm/maths/algebra/monom.js.map +1 -1
  72. package/esm/maths/algebra/polynom.d.ts +157 -157
  73. package/esm/maths/algebra/polynom.js +1277 -1277
  74. package/esm/maths/algebra/rational.d.ts +45 -45
  75. package/esm/maths/algebra/rational.js +183 -183
  76. package/esm/maths/algebra/study/rationalStudy.d.ts +28 -28
  77. package/esm/maths/algebra/study/rationalStudy.js +243 -243
  78. package/esm/maths/algebra/study.d.ts +143 -142
  79. package/esm/maths/algebra/study.js +378 -377
  80. package/esm/maths/algebra/study.js.map +1 -1
  81. package/esm/maths/coefficients/fraction.d.ts +90 -90
  82. package/esm/maths/coefficients/fraction.js +516 -516
  83. package/esm/maths/coefficients/fraction.js.map +1 -1
  84. package/esm/maths/coefficients/nthRoot.d.ts +23 -23
  85. package/esm/maths/coefficients/nthRoot.js +136 -136
  86. package/esm/maths/geometry/circle.d.ts +45 -45
  87. package/esm/maths/geometry/circle.js +323 -323
  88. package/esm/maths/geometry/line.d.ts +99 -99
  89. package/esm/maths/geometry/line.js +481 -481
  90. package/esm/maths/geometry/line.js.map +1 -1
  91. package/esm/maths/geometry/point.d.ts +34 -34
  92. package/esm/maths/geometry/point.js +166 -166
  93. package/esm/maths/geometry/point.js.map +1 -1
  94. package/esm/maths/geometry/triangle.d.ts +85 -85
  95. package/esm/maths/geometry/triangle.js +268 -268
  96. package/esm/maths/geometry/vector.d.ts +41 -41
  97. package/esm/maths/geometry/vector.js +197 -197
  98. package/esm/maths/geometry/vector.js.map +1 -1
  99. package/esm/maths/numeric.d.ts +28 -28
  100. package/esm/maths/numeric.js +180 -180
  101. package/esm/maths/numexp.d.ts +19 -0
  102. package/esm/maths/numexp.js +186 -0
  103. package/esm/maths/numexp.js.map +1 -0
  104. package/esm/maths/randomization/random.d.ts +23 -23
  105. package/esm/maths/randomization/random.js +78 -78
  106. package/esm/maths/randomization/random.js.map +1 -1
  107. package/esm/maths/randomization/randomCore.d.ts +7 -7
  108. package/esm/maths/randomization/randomCore.js +21 -21
  109. package/esm/maths/randomization/rndFraction.d.ts +12 -12
  110. package/esm/maths/randomization/rndFraction.js +43 -43
  111. package/esm/maths/randomization/rndGeometryLine.d.ts +12 -12
  112. package/esm/maths/randomization/rndGeometryLine.js +45 -45
  113. package/esm/maths/randomization/rndGeometryPoint.d.ts +12 -12
  114. package/esm/maths/randomization/rndGeometryPoint.js +60 -60
  115. package/esm/maths/randomization/rndHelpers.d.ts +23 -23
  116. package/esm/maths/randomization/rndHelpers.js +76 -76
  117. package/esm/maths/randomization/rndMonom.d.ts +12 -12
  118. package/esm/maths/randomization/rndMonom.js +52 -52
  119. package/esm/maths/randomization/rndPolynom.d.ts +13 -13
  120. package/esm/maths/randomization/rndPolynom.js +74 -74
  121. package/esm/maths/randomization/rndTypes.d.ts +34 -34
  122. package/esm/maths/randomization/rndTypes.js +2 -2
  123. package/esm/maths/shutingyard.d.ts +59 -59
  124. package/esm/maths/shutingyard.js +442 -442
  125. package/esm/maths/shutingyard.js.map +1 -1
  126. package/package.json +11 -11
  127. package/public/index.html +50 -81
  128. package/public/playground.html +7 -8
  129. package/src/index.ts +1 -4
  130. package/src/maths/algebra/equation.ts +16 -0
  131. package/src/maths/algebra/linearSystem.ts +20 -0
  132. package/src/maths/algebra/study.ts +12 -10
  133. package/src/maths/{expressions/numexp.ts → numexp.ts} +2 -2
  134. package/tests/algebra/equation.test.ts +19 -5
  135. package/tests/algebra/linear.test.ts +3 -11
  136. package/tests/algebra/polynom.test.ts +7 -8
  137. package/tests/algebra/rationnal.test.ts +1 -1
  138. package/tests/algebra/study.test.ts +2 -9
  139. package/tests/coefficients/fraction.test.ts +8 -8
  140. package/tests/custom.test.ts +33 -37
  141. package/tests/numeric.test.ts +1 -2
  142. package/tests/numexp.test.ts +13 -5
  143. package/tests/shutingyard.test.ts +3 -3
  144. package/webpack-production-min.config.js +1 -1
  145. package/webpack-production.config.js +1 -1
  146. package/webpack.config.js +1 -1
  147. package/dist/pi.js.map +0 -1
  148. package/dist/pi.min.js +0 -2
  149. package/dist/pi.min.js.map +0 -1
  150. package/docs/classes/expressions_numexp.NumExp.html +0 -236
  151. package/docs/classes/expressions_polynomexp.PolynomExpFactor.html +0 -317
  152. package/docs/classes/expressions_polynomexp.PolynomExpProduct.html +0 -285
  153. package/docs/modules/expressions_numexp.html +0 -71
  154. package/docs/modules/expressions_polynomexp.html +0 -73
  155. package/docs/modules.html +0 -76
  156. package/graph.svg +0 -1033
  157. package/src/maths/expressions/ExpressionTree.ts +0 -172
  158. package/src/maths/expressions/expression.ts +0 -286
  159. package/src/maths/expressions/expressionFactor.ts +0 -190
  160. package/src/maths/expressions/expressionMember.ts +0 -233
  161. package/src/maths/expressions/expressionOperators.ts +0 -49
  162. package/src/maths/expressions/expressionParser.ts +0 -295
  163. package/src/maths/expressions/factors/ExpFactor.ts +0 -39
  164. package/src/maths/expressions/factors/ExpFactorConstant.ts +0 -60
  165. package/src/maths/expressions/factors/ExpFactorExponential.ts +0 -26
  166. package/src/maths/expressions/factors/ExpFactorNumber.ts +0 -72
  167. package/src/maths/expressions/factors/ExpFactorPower.ts +0 -42
  168. package/src/maths/expressions/factors/ExpFactorTrigo.ts +0 -53
  169. package/src/maths/expressions/factors/ExpFactorVariable.ts +0 -45
  170. package/src/maths/expressions/internals.ts +0 -14
  171. package/src/maths/expressions/polynomexp.bkp.ts +0 -221
  172. package/src/maths/expressions/polynomexp.ts +0 -310
  173. package/tests/expressions/expressions.test.ts +0 -145
  174. package/tests/expressions/expressiontree.test.ts +0 -11
  175. package/tests/polynomexp.test.ts +0 -12
@@ -1,1278 +1,1278 @@
1
- "use strict";
2
- /**
3
- * Polynom module contains everything necessary to handle polynoms.*
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Polynom = void 0;
7
- const monom_1 = require("./monom");
8
- const shutingyard_1 = require("../shutingyard");
9
- const numeric_1 = require("../numeric");
10
- const fraction_1 = require("../coefficients/fraction");
11
- const equation_1 = require("./equation");
12
- /**
13
- * Polynom class can handle polynoms, reorder, resolve, ...
14
- * ```
15
- * let P = new Polynom('3x-4')
16
- * ```
17
- */
18
- class Polynom {
19
- /**
20
- *
21
- * @param {string} polynomString (optional) Default polynom to parse on class creation
22
- * @param values
23
- */
24
- constructor(polynomString, ...values) {
25
- this.mark_as_dirty = () => {
26
- this.dirty_factors = true;
27
- this.dirty_zeroes = true;
28
- this.euclidianCache = {};
29
- };
30
- this.addToken = (stack, element) => {
31
- switch (element.tokenType) {
32
- case shutingyard_1.ShutingyardType.COEFFICIENT:
33
- stack.push(new Polynom(element.token));
34
- break;
35
- case shutingyard_1.ShutingyardType.VARIABLE:
36
- stack.push(new Polynom().add(new monom_1.Monom(element.token)));
37
- break;
38
- case shutingyard_1.ShutingyardType.CONSTANT:
39
- // TODO: add constant support to Polynom parsing.
40
- console.log('Actually, not supported - will be added later !');
41
- break;
42
- case shutingyard_1.ShutingyardType.OPERATION:
43
- if (stack.length >= 2) {
44
- const b = stack.pop(), a = stack.pop();
45
- if (element.token === '+') {
46
- stack.push(a.add(b));
47
- }
48
- else if (element.token === '-') {
49
- stack.push(a.subtract(b));
50
- }
51
- else if (element.token === '*') {
52
- stack.push(a.multiply(b));
53
- }
54
- else if (element.token === '/') {
55
- if (b.degree().isStrictlyPositive()) {
56
- console.log('divide by a polynom -> should create a rational polynom !');
57
- }
58
- else {
59
- stack.push(a.divide(b.monoms[0].coefficient));
60
- }
61
- }
62
- else if (element.token === '^') {
63
- if (b.degree().isStrictlyPositive()) {
64
- console.error('Cannot elevate a polynom with another polynom !', a.tex, b.tex);
65
- }
66
- else {
67
- if (b.monoms[0].coefficient.isRelative()) {
68
- // Integer power
69
- stack.push(a.pow(b.monoms[0].coefficient.value));
70
- }
71
- else {
72
- // Only allow power if the previous polynom is only a monom, without coefficient.
73
- if (a.monoms.length === 1 && a.monoms[0].coefficient.isOne()) {
74
- for (let letter in a.monoms[0].literal) {
75
- a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient);
76
- }
77
- stack.push(a);
78
- }
79
- else {
80
- console.error('Cannot have power with fraction');
81
- }
82
- }
83
- }
84
- }
85
- }
86
- else {
87
- if (element.token === '-') {
88
- stack.push(stack.pop().opposed());
89
- }
90
- else {
91
- throw "Error parsing the polynom " + this._rawString;
92
- }
93
- }
94
- break;
95
- case shutingyard_1.ShutingyardType.MONOM:
96
- // Should never appear.
97
- console.error('The monom token should not appear here');
98
- break;
99
- case shutingyard_1.ShutingyardType.FUNCTION:
100
- // Should never appear.
101
- console.error('The function token should not appear here - might be introduced later.');
102
- break;
103
- }
104
- };
105
- // ------------------------------------------
106
- // Creation / parsing functions
107
- // ------------------------------------------
108
- /**
109
- * Parse a string to a polynom.
110
- * @param inputStr
111
- * @param values: as string, numbers or fractions
112
- */
113
- this.parse = (inputStr, ...values) => {
114
- // Reset the main variables.
115
- this._monoms = [];
116
- this._factors = [];
117
- this.mark_as_dirty();
118
- // TODO: allow to enter a liste of Fraction (a, b, c, ...) to make a polynom ax^n + bx^(n-1) + cx^(n-2) + ...
119
- if (typeof inputStr === 'string') {
120
- return this._parseString(inputStr, ...values);
121
- }
122
- else if ((typeof inputStr === 'number' || inputStr instanceof fraction_1.Fraction || inputStr instanceof monom_1.Monom)
123
- && (values === undefined || values.length === 0)) {
124
- this._monoms.push(new monom_1.Monom(inputStr));
125
- }
126
- else if (inputStr instanceof monom_1.Monom && values.length > 0) {
127
- this._monoms.push(new monom_1.Monom(inputStr));
128
- values.forEach(m => {
129
- this._monoms.push(new monom_1.Monom(m));
130
- });
131
- }
132
- else if (inputStr instanceof Polynom) {
133
- for (const m of inputStr.monoms) {
134
- this._monoms.push(m.clone());
135
- }
136
- }
137
- return this;
138
- };
139
- /**
140
- * Clone the polynom
141
- */
142
- this.clone = () => {
143
- const P = new Polynom();
144
- const M = [];
145
- for (const m of this._monoms) {
146
- M.push(m.clone());
147
- }
148
- P.monoms = M;
149
- return P;
150
- };
151
- /**
152
- * Set the polynom to zero.
153
- * @returns {this}
154
- */
155
- this.zero = () => {
156
- this._monoms = [];
157
- this._monoms.push(new monom_1.Monom().zero());
158
- this._rawString = '0';
159
- this.mark_as_dirty();
160
- return this;
161
- };
162
- this.one = () => {
163
- this._monoms = [];
164
- this._monoms.push(new monom_1.Monom().one());
165
- this._rawString = '1';
166
- this.mark_as_dirty();
167
- return this;
168
- };
169
- this.empty = () => {
170
- this._monoms = [];
171
- this._rawString = '';
172
- this.mark_as_dirty();
173
- return this;
174
- };
175
- // ------------------------------------------
176
- this.opposed = () => {
177
- this._monoms = this._monoms.map(m => m.opposed());
178
- this.mark_as_dirty();
179
- return this;
180
- };
181
- // ------------------------------------------
182
- // Mathematical operations
183
- this.add = (...values) => {
184
- this.mark_as_dirty();
185
- // @ts-ignore
186
- for (let value of values) {
187
- if (value instanceof Polynom) {
188
- this._monoms = this._monoms.concat(value.monoms);
189
- }
190
- else if (value instanceof monom_1.Monom) {
191
- this._monoms.push(value.clone());
192
- }
193
- else if (Number.isSafeInteger(value)) {
194
- this._monoms.push(new monom_1.Monom(value.toString()));
195
- }
196
- else {
197
- this._monoms.push(new monom_1.Monom(value));
198
- }
199
- }
200
- return this.reduce();
201
- };
202
- this.subtract = (...values) => {
203
- this.mark_as_dirty();
204
- for (let value of values) {
205
- if (value instanceof Polynom) {
206
- this._monoms = this._monoms.concat(value.clone().opposed().monoms);
207
- }
208
- else if (value instanceof monom_1.Monom) {
209
- this._monoms.push(value.clone().opposed());
210
- }
211
- else if (Number.isSafeInteger(value)) {
212
- this._monoms.push(new monom_1.Monom(value.toString()).opposed());
213
- }
214
- else {
215
- this._monoms.push(new monom_1.Monom(value).opposed());
216
- }
217
- }
218
- return this.reduce();
219
- };
220
- this.multiply = (value) => {
221
- this.mark_as_dirty();
222
- if (value instanceof Polynom) {
223
- return this.multiplyByPolynom(value);
224
- }
225
- else if (value instanceof fraction_1.Fraction) {
226
- return this.multiplyByFraction(value);
227
- }
228
- else if (value instanceof monom_1.Monom) {
229
- return this.multiplyByMonom(value);
230
- }
231
- else if (Number.isSafeInteger(value) && typeof value === 'number') {
232
- return this.multiplyByInteger(value);
233
- }
234
- // Something went wrong...
235
- return this;
236
- };
237
- /**
238
- * Divide the current polynom by another polynom.
239
- * @param P
240
- * returns {quotient: Polynom, reminder: Polynom}
241
- */
242
- this.euclidian = (P) => {
243
- if (this.euclidianCache[P.tex] !== undefined) {
244
- return this.euclidianCache[P.tex];
245
- }
246
- const letter = P.variables[0];
247
- const quotient = new Polynom().zero();
248
- const reminder = this.clone().reorder(letter);
249
- // There is no variable - means it's a number
250
- if (P.variables.length === 0) {
251
- let q = this.clone().divide(P);
252
- return {
253
- quotient: this.clone().divide(P),
254
- reminder: new Polynom().zero()
255
- };
256
- }
257
- // Get at least a letter
258
- const maxMP = P.monomByDegree(undefined, letter);
259
- const degreeP = P.degree(letter);
260
- let newM;
261
- // Make the euclidian division of the two polynoms.
262
- let MaxIteration = this.degree(letter).clone().multiply(2);
263
- while (reminder.degree(letter).geq(degreeP) && MaxIteration.isPositive()) {
264
- MaxIteration.subtract(1);
265
- // Get the greatest monom divided by the max monom of the divider
266
- newM = reminder.monomByDegree(undefined, letter).clone().divide(maxMP);
267
- if (newM.isZero()) {
268
- break;
269
- }
270
- // Get the new quotient and reminder.
271
- quotient.add(newM);
272
- reminder.subtract(P.clone().multiply(newM));
273
- }
274
- quotient.reduce();
275
- reminder.reduce();
276
- return { quotient, reminder };
277
- };
278
- this.divide = (value) => {
279
- this.mark_as_dirty();
280
- if (value instanceof fraction_1.Fraction) {
281
- return this.divideByFraction(value);
282
- }
283
- else if (typeof value === 'number' && Number.isSafeInteger(value)) {
284
- return this.divideByInteger(value);
285
- }
286
- else if (value instanceof monom_1.Monom) {
287
- return this.divide(new Polynom(value));
288
- }
289
- else if (value instanceof Polynom) {
290
- if (value.monoms.length === 1 && value.variables.length === 0) {
291
- return this.divideByFraction(value.monoms[0].coefficient);
292
- }
293
- else {
294
- let { quotient, reminder } = this.euclidian(value);
295
- if (reminder.isZero()) {
296
- return quotient;
297
- }
298
- else {
299
- console.log(`${this.tex} is not divideable by ${value.tex}`);
300
- return new Polynom().zero();
301
- }
302
- }
303
- }
304
- };
305
- this.pow = (nb) => {
306
- this.mark_as_dirty();
307
- if (!Number.isSafeInteger(nb)) {
308
- return this.zero();
309
- }
310
- if (nb < 0) {
311
- return this.zero();
312
- }
313
- if (nb === 0) {
314
- return new Polynom();
315
- }
316
- const P = this.clone();
317
- for (let i = 1; i < nb; i++) {
318
- this.multiply(P);
319
- }
320
- return this.reduce();
321
- };
322
- // ------------------------------------------
323
- /**
324
- * Compare the current coefficient with another coefficient
325
- * @param P
326
- * @param sign (string| default is =): authorized values: =, <, <=, >, >= with some variations.
327
- */
328
- this.compare = (P, sign) => {
329
- if (sign === undefined) {
330
- sign = '=';
331
- }
332
- // Create clone version to reduce them without altering the original polynoms.
333
- const cP1 = this.clone().reduce().reorder();
334
- const cP2 = P.clone().reduce().reorder();
335
- switch (sign) {
336
- case '=':
337
- // They must have the isSame length and the isSame degree
338
- if (cP1.length !== cP2.length || cP1.degree().isNotEqual(cP2.degree())) {
339
- return false;
340
- }
341
- // Check if the coefficients are the isSame.
342
- for (const i in cP1.monoms) {
343
- if (!cP1.monoms[i].isEqual(cP2.monoms[i])) {
344
- return false;
345
- }
346
- }
347
- return true;
348
- case 'same':
349
- // They must have the isSame length and the isSame degree
350
- if (cP1.length !== cP2.length || cP1.degree() !== cP2.degree()) {
351
- return false;
352
- }
353
- for (const i in cP1.monoms) {
354
- if (!cP1.monoms[i].isSameAs(cP2.monoms[i])) {
355
- return false;
356
- }
357
- }
358
- return true;
359
- default:
360
- return false;
361
- }
362
- };
363
- this.isEqual = (P) => {
364
- return this.compare(P, '=');
365
- };
366
- this.isSameAs = (P) => {
367
- return this.compare(P, 'same');
368
- };
369
- this.isOpposedAt = (P) => {
370
- return this.compare(P.clone().opposed(), '=');
371
- };
372
- this.isFactorized = (polynomString, soft) => {
373
- let P;
374
- // Check if polynom is complete...
375
- if (polynomString.split('(').length !== polynomString.split(')').length) {
376
- return false;
377
- }
378
- // Try to build the polynom
379
- try {
380
- P = new Polynom(polynomString);
381
- }
382
- catch (e) {
383
- return false;
384
- }
385
- // Both polynom aren't the same (once developed and reduced => they cannot be equivalent)
386
- if (!this.isEqual(P)) {
387
- return false;
388
- }
389
- // Check if the provided (string) version is fully factorized.
390
- // Run a regex on the string.
391
- let polynomStringNormalized = polynomString.replaceAll('*', ''), polynomStringReduced = '' + polynomStringNormalized, factors = [];
392
- for (let x of polynomStringNormalized.matchAll(/\(([a-z0-9+\-]+)\)(\^[0-9]*)?/g)) {
393
- if (x[2] !== undefined) {
394
- // if there is an exponential value, add it multiple times
395
- for (let i = 0; i < +x[2].substring(1); i++) {
396
- factors.push(x[1]);
397
- }
398
- }
399
- else {
400
- // no power - add it once.
401
- factors.push(x[1]);
402
- }
403
- // Remove the current polynom
404
- polynomStringReduced = polynomStringReduced.replaceAll(x[0], '');
405
- }
406
- if (polynomStringReduced !== '') {
407
- factors.push(polynomStringReduced);
408
- }
409
- let polyFactors = factors.map(x => new Polynom(x));
410
- // polyFactors contain all polynoms.
411
- let checkPolyFactors = polyFactors.filter(x => x.degree().geq(1) && !x.commonMonom().isOne());
412
- // Some polynoms are not completely factorized.
413
- if (checkPolyFactors.length > 0 && !soft) {
414
- return false;
415
- }
416
- if (checkPolyFactors.length > 0 && soft) {
417
- polyFactors = polyFactors.filter(x => x.commonMonom().isOne());
418
- let FactorizedConstant = new fraction_1.Fraction().one();
419
- for (let p of checkPolyFactors) {
420
- let k = p.commonMonom(), pFactor = p.clone().divide(k);
421
- if (k.degree().isZero()) {
422
- FactorizedConstant.multiply(k.coefficient);
423
- polyFactors.push(pFactor.clone());
424
- }
425
- }
426
- }
427
- // Factorize the current polynom.
428
- this.factorize();
429
- // Compare the given factors with the generated factors
430
- let sign = 1, notFoundedFactors = [];
431
- for (let f of this.factors) {
432
- // The factor is just a coefficient. Might be opposed
433
- if (f.degree().isZero()) {
434
- if (f.monoms[0].coefficient.isNegativeOne()) {
435
- sign = -sign;
436
- }
437
- }
438
- let factorFound = false;
439
- for (let i = 0; i < polyFactors.length; i++) {
440
- if (f.isEqual(polyFactors[i])) {
441
- polyFactors.splice(i, 1);
442
- factorFound = true;
443
- break;
444
- }
445
- else if (f.isOpposedAt(polyFactors[i])) {
446
- polyFactors.splice(i, 1);
447
- sign = -sign;
448
- factorFound = true;
449
- break;
450
- }
451
- }
452
- if (!factorFound) {
453
- notFoundedFactors.push(f.clone());
454
- }
455
- }
456
- // The polyfactors must be empty and the cumulative opposite factors must be 1.
457
- return (polyFactors.length === 0 && sign === 1);
458
- };
459
- // ------------------------------------------
460
- // Compare functions
461
- this.isReduced = (polynomString) => {
462
- // The polynom must be developed to be reduced.
463
- if (!this.isDeveloped(polynomString)) {
464
- return false;
465
- }
466
- let P = new Polynom(polynomString);
467
- if (P.monoms.length > this.monoms.length) {
468
- return false;
469
- }
470
- // TODO: Not ur the reduced systme checking is working properly !
471
- for (let m of P.monoms) {
472
- if (!m.coefficient.isReduced()) {
473
- return false;
474
- }
475
- }
476
- return false;
477
- };
478
- this.isDeveloped = (polynomString) => {
479
- let P;
480
- // There is at least one parenthese - it is not developed.
481
- if (polynomString.split('(').length + polynomString.split(')').length > 0) {
482
- return false;
483
- }
484
- // Try to build the polynom
485
- try {
486
- // Build the polynom
487
- P = new Polynom(polynomString);
488
- }
489
- catch (e) {
490
- return false;
491
- }
492
- // Both polynom aren't the same (once developed and reduced => they cannot be equivalent)
493
- if (!this.isEqual(P)) {
494
- return false;
495
- }
496
- // Check that everything is completely developed. Actually, there are no parentheses... so it is fully developed
497
- // maybe it wasn't reduced and not ordered...
498
- // compare polynom string.
499
- // normalize the string
500
- let polynomStringNormalized = polynomString.replaceAll('[*\s]', '');
501
- // Determine if it's the exact same string.
502
- // TODO: Maybe it's enough to just make this test !
503
- return polynomStringNormalized === P.reduce().reorder().display;
504
- };
505
- // -------------------------------------
506
- this.reduce = () => {
507
- // Reduce the polynom
508
- let values = [...this._monoms], vars = [...this.variables];
509
- this._monoms = [];
510
- let coeffs = values.filter(x => x.variables.length === 0);
511
- if (coeffs.length > 0) {
512
- this._monoms.push(coeffs.reduce((a, b) => a.add(b)));
513
- }
514
- // Build the new monoms
515
- for (let letter of vars) {
516
- // Monom with same letters, but might be of different degrees
517
- let M = values.filter(x => x.hasLetter(letter));
518
- while (M.length > 0) {
519
- // Take the first element
520
- const m = M.shift(), degree = m.degree(letter);
521
- for (let a of M.filter(x => x.degree(letter).isEqual(degree))) {
522
- m.add(a);
523
- }
524
- this._monoms.push(m);
525
- // Make the new array.
526
- M = M.filter(x => x.degree(letter).isNotEqual(degree));
527
- }
528
- // reduce the monom
529
- }
530
- // Remove all null monoms
531
- this._monoms = this._monoms.filter((m) => {
532
- return m.coefficient.value !== 0;
533
- });
534
- // Reduce all monoms coefficient.
535
- for (const m of this._monoms) {
536
- m.coefficient.reduce();
537
- }
538
- if (this.length === 0) {
539
- return new Polynom().zero();
540
- }
541
- return this.reorder();
542
- };
543
- this.reorder = (letter = 'x', revert) => {
544
- if (revert === undefined) {
545
- revert = false;
546
- }
547
- // TODO: Must handle multiple setLetter reorder system
548
- let otherLetters = this.variables.filter(x => x !== letter);
549
- this._monoms.sort(function (a, b) {
550
- let da = a.degree(letter).value, db = b.degree(letter).value;
551
- // Values are different
552
- if (da !== db)
553
- return revert ? da - db : db - da;
554
- // if values are equals, check other letters - it must be revert in that case !
555
- if (otherLetters.length > 0) {
556
- for (let L of otherLetters) {
557
- let da = a.degree(L).value, db = b.degree(L).value;
558
- // Values are different
559
- if (da !== db)
560
- return revert ? da - db : db - da;
561
- }
562
- }
563
- return 0;
564
- // return b.degree(letter).clone().subtract(a.degree(letter)).value
565
- });
566
- return this;
567
- };
568
- this.degree = (letter) => {
569
- let d = new fraction_1.Fraction().zero();
570
- for (const m of this._monoms) {
571
- d = fraction_1.Fraction.max(m.degree(letter).value, d);
572
- }
573
- return d;
574
- };
575
- this.letters = () => {
576
- let L = [], S = new Set();
577
- for (let m of this._monoms) {
578
- S = new Set([...S, ...m.variables]);
579
- }
580
- // @ts-ignore
581
- return [...S];
582
- };
583
- /**
584
- * Replace a variable (letter) by a polynom.
585
- * @param letter
586
- * @param P
587
- */
588
- this.replaceBy = (letter, P) => {
589
- this.mark_as_dirty();
590
- let pow;
591
- const resultPolynom = new Polynom().zero();
592
- for (const m of this.monoms) {
593
- if (m.literal[letter] === undefined || m.literal[letter].isZero()) {
594
- resultPolynom.add(m.clone());
595
- }
596
- else {
597
- // We have found a setLetter.
598
- // Get the power and reset it.
599
- pow = m.literal[letter].clone();
600
- delete m.literal[letter];
601
- // TODO: replaceBy works only with positive and natural pow
602
- resultPolynom.add(P.clone().pow(Math.abs(pow.numerator)).multiply(m));
603
- }
604
- }
605
- this._monoms = resultPolynom.reduce().reorder().monoms;
606
- return this;
607
- };
608
- // Evaluate a polynom.
609
- this.evaluate = (values) => {
610
- const r = new fraction_1.Fraction().zero();
611
- this._monoms.forEach(monom => {
612
- //console.log('Evaluate polynom: ', monom.display, values, monom.evaluate(values).display);
613
- r.add(monom.evaluate(values));
614
- });
615
- return r;
616
- };
617
- this.evaluateAsNumeric = (values) => {
618
- let r = 0;
619
- this._monoms.forEach(monom => {
620
- r += monom.evaluateAsNumeric(values);
621
- });
622
- return r;
623
- };
624
- this.derivative = (letter) => {
625
- let dP = new Polynom();
626
- for (let m of this._monoms) {
627
- dP.add(m.derivative(letter));
628
- }
629
- return dP;
630
- };
631
- // ------------------------------------------
632
- // Misc polynoms functions
633
- this.primitive = (letter) => {
634
- let dP = new Polynom();
635
- for (let m of this._monoms) {
636
- dP.add(m.primitive(letter));
637
- }
638
- return dP;
639
- };
640
- this.integrate = (a, b, letter) => {
641
- const primitive = this.primitive(letter);
642
- if (letter === undefined) {
643
- letter = 'x';
644
- }
645
- let valuesA = {}, valuesB = {};
646
- valuesA[letter] = new fraction_1.Fraction(a);
647
- valuesB[letter] = new fraction_1.Fraction(b);
648
- return primitive.evaluate(valuesB).subtract(primitive.evaluate(valuesA));
649
- };
650
- // -------------------------------------
651
- /**
652
- * Factorize a polynom and store the best results in factors.
653
- * @param maxValue Defines the greatest value to search to (default is 20).
654
- */
655
- this.factorize = (letter) => {
656
- if (!this.dirty_factors) {
657
- return this._factors;
658
- }
659
- let factors = [];
660
- let P = this.clone().reorder();
661
- // Extract the common monom
662
- // 2x^3+6x^2 => 2x^2
663
- let M = P.commonMonom();
664
- // If the polynom starts with a negative monom, factorize it.
665
- if (P.monomByDegree().coefficient.isStrictlyNegative() && M.coefficient.isStrictlyPositive() && !M.isOne()) {
666
- M.opposed();
667
- }
668
- if (!M.isOne()) {
669
- let tempPolynom = new Polynom(M);
670
- factors = [tempPolynom.clone()];
671
- P = P.euclidian(tempPolynom).quotient;
672
- }
673
- // Main loop
674
- let securityLoop = P.degree().clone().multiply(2).value, maxDegree = 1;
675
- while (securityLoop >= 0) {
676
- securityLoop--;
677
- if (P.monoms.length < 2) {
678
- // The polynom has only one monom => 7x^2
679
- // No need to continue.
680
- if (!P.isOne()) {
681
- factors.push(P.clone());
682
- P.one();
683
- }
684
- break;
685
- }
686
- else if (P.degree(letter).isOne()) {
687
- // The polynom is a first degree polynom => 3x-5
688
- // No need to continue
689
- factors.push(P.clone());
690
- P.one();
691
- break;
692
- }
693
- else {
694
- // Create the list of all "potential" polynom dividers.
695
- let allDividers = this._getAllPotentialFactors(P, maxDegree, letter);
696
- maxDegree = P.degree(letter).value;
697
- // Actually: 100ms
698
- while (allDividers.length > 0) {
699
- let div = allDividers[0];
700
- if (!P.isDividableBy(div)) {
701
- // Not dividable. Remove it from the list
702
- allDividers.shift();
703
- }
704
- else {
705
- // It's dividable - so make the division
706
- let result = P.euclidian(div);
707
- // Add the factor
708
- factors.push(div);
709
- // As it's dividable, get the quotient.
710
- P = result.quotient.clone();
711
- // filter all dividers that are no more suitable.
712
- allDividers = allDividers.filter(x => {
713
- let pX = P.monoms[0], pC = P.monoms[P.monoms.length - 1], dX = x.monoms[0], dC = x.monoms[x.monoms.length - 1];
714
- // Check last item (degree zero)
715
- if (!pC.isDivisible(dC)) {
716
- return false;
717
- }
718
- // Check the first item (degree max)
719
- if (!pX.isDivisible(dX)) {
720
- return false;
721
- }
722
- return true;
723
- });
724
- }
725
- }
726
- }
727
- }
728
- // Maybe there is still something in the Polynom (not everything was possible to factorize)
729
- if (!P.isOne()) {
730
- factors.push(P.clone());
731
- }
732
- // Save the factors
733
- this._factors = factors;
734
- // The factors list is no more dirty
735
- this.dirty_factors = false;
736
- return this._factors;
737
- };
738
- this.isDividableBy = (div) => {
739
- // Quick evaluation.
740
- if (div.degree().isOne()) {
741
- let zero = div.getZeroes()[0];
742
- if (zero.exact instanceof fraction_1.Fraction) {
743
- return this.evaluate(zero.exact).isZero();
744
- }
745
- else {
746
- return false;
747
- }
748
- }
749
- else {
750
- this.euclidianCache[div.tex] = this.euclidian(div);
751
- return this.euclidianCache[div.tex].reminder.isZero();
752
- }
753
- };
754
- // TODO: get zeroes for more than first degree and for more than natural degrees
755
- this.getZeroes = () => {
756
- if (this.dirty_zeroes) {
757
- let equ = new equation_1.Equation(this.clone(), 0);
758
- equ.solve();
759
- this._zeroes = equ.solutions;
760
- this.dirty_zeroes = false;
761
- }
762
- return this._zeroes;
763
- };
764
- // TODO: analyse the next functions to determine if they are useful or not...
765
- this.monomByDegree = (degree, letter) => {
766
- if (degree === undefined) {
767
- // return the highest degree monom.
768
- return this.monomByDegree(this.degree(letter), letter);
769
- }
770
- // Reduce the polynom.
771
- const M = this.clone().reduce();
772
- for (const m of M._monoms) {
773
- if (m.degree(letter).isEqual(degree)) {
774
- return m.clone();
775
- }
776
- }
777
- // Nothing was found - return the null monom.
778
- return new monom_1.Monom().zero();
779
- };
780
- this.monomsByDegree = (degree, letter) => {
781
- if (degree === undefined) {
782
- // return the highest degree monom.
783
- return this.monomsByDegree(this.degree(letter));
784
- }
785
- // Reduce the polynom.
786
- let Ms = [];
787
- const M = this.clone().reduce();
788
- for (const m of M._monoms) {
789
- if (m.degree(letter) === degree) {
790
- Ms.push(m.clone());
791
- }
792
- }
793
- return Ms;
794
- // Nothing was found - retur
795
- };
796
- // Used in LinearSystem.tex
797
- this.monomByLetter = (letter) => {
798
- const M = this.clone().reduce();
799
- for (const m of M._monoms) {
800
- if (m.hasLetter(letter)) {
801
- return m.clone();
802
- }
803
- }
804
- return new monom_1.Monom().zero();
805
- };
806
- // Next functions are used for for commonMonom, which is used in the factorize method.
807
- this.getDenominators = () => {
808
- const denominators = [];
809
- for (const m of this._monoms) {
810
- denominators.push(m.coefficient.denominator);
811
- }
812
- return denominators;
813
- };
814
- this.getNumerators = () => {
815
- const numerators = [];
816
- for (const m of this._monoms) {
817
- numerators.push(m.coefficient.numerator);
818
- }
819
- return numerators;
820
- };
821
- this.lcmDenominator = () => {
822
- return numeric_1.Numeric.lcm(...this.getDenominators());
823
- };
824
- // ------------------------------------------
825
- // Polynoms factorization functions
826
- this.gcdDenominator = () => {
827
- return numeric_1.Numeric.gcd(...this.getDenominators());
828
- };
829
- this.lcmNumerator = () => {
830
- return numeric_1.Numeric.lcm(...this.getNumerators());
831
- };
832
- this.gcdNumerator = () => {
833
- return numeric_1.Numeric.gcd(...this.getNumerators());
834
- };
835
- // ------------------------------------------
836
- // Polynoms helpers functions
837
- // -------------------------------------
838
- this.commonMonom = () => {
839
- let M = new monom_1.Monom().one(), numerator, denominator, degree = this.degree();
840
- numerator = this.gcdNumerator();
841
- denominator = this.gcdDenominator();
842
- M.coefficient = new fraction_1.Fraction(numerator, denominator);
843
- for (let L of this.variables) {
844
- // Initialize the setLetter with the max degree
845
- M.setLetter(L, degree);
846
- for (let m of this._monoms) {
847
- M.setLetter(L, fraction_1.Fraction.min(m.degree(L), M.degree(L)));
848
- if (M.degree(L).isZero()) {
849
- break;
850
- }
851
- }
852
- }
853
- return M;
854
- };
855
- this.limitToInfinity = (letter) => {
856
- const M = this.monomByDegree(undefined, letter), sign = M.coefficient.sign(), degree = M.degree(letter);
857
- if (degree.isStrictlyPositive()) {
858
- return sign === 1 ? (new fraction_1.Fraction()).infinite() : (new fraction_1.Fraction()).infinite().opposed();
859
- }
860
- else if (degree.isZero()) {
861
- return M.coefficient;
862
- }
863
- // Any other cases
864
- return (new fraction_1.Fraction()).zero();
865
- };
866
- this.limitToNegativeInfinity = (letter) => {
867
- const M = this.monomByDegree(undefined, letter), sign = M.coefficient.sign(), degree = M.degree(letter);
868
- if (degree.isStrictlyPositive()) {
869
- return sign === -1 ? (new fraction_1.Fraction()).infinite() : (new fraction_1.Fraction()).infinite().opposed();
870
- }
871
- else if (degree.isZero()) {
872
- return M.coefficient;
873
- }
874
- // Any other cases
875
- return (new fraction_1.Fraction()).zero();
876
- };
877
- this._getAllPotentialFactors = (P, maxDegree, letter) => {
878
- let m1 = P.monoms[0].dividers, m2 = P.monoms[P.monoms.length - 1].dividers;
879
- let allDividers = [];
880
- m1.forEach(m1d => {
881
- // Get only polynom that has a degree less than a specific value
882
- if (m1d.degree(letter).leq(maxDegree)) {
883
- m2.forEach(m2d => {
884
- if (m1d.degree(letter).isNotEqual(m2d.degree(letter))) {
885
- allDividers.push(new Polynom(m1d, m2d));
886
- allDividers.push(new Polynom(m1d, m2d.clone().opposed()));
887
- }
888
- });
889
- }
890
- });
891
- return allDividers;
892
- };
893
- this.genDisplay = (output, forceSign, wrapParentheses, withAllMultSign) => {
894
- let P = '';
895
- for (const k of this._monoms) {
896
- if (k.coefficient.value === 0) {
897
- continue;
898
- }
899
- // The monom to be displayed
900
- let m;
901
- if (withAllMultSign) {
902
- m = k.plotFunction;
903
- }
904
- else {
905
- m = (output === 'tex') ? k.tex : k.display;
906
- }
907
- P += `${(k.coefficient.sign() === 1 && (P !== '' || forceSign === true)) ? '+' : ''}${m}`;
908
- }
909
- if (wrapParentheses === true && this.length > 1) {
910
- if (output === 'tex') {
911
- P = `\\left( ${P} \\right)`;
912
- }
913
- else {
914
- P = `(${P})`;
915
- }
916
- }
917
- if (P === '') {
918
- P = '0';
919
- }
920
- return P;
921
- };
922
- /**
923
- * Main parse using a shutting yard class
924
- * @param inputStr
925
- */
926
- this.shutingYardToReducedPolynom = (inputStr) => {
927
- // Get the RPN array of the current expression
928
- const SY = new shutingyard_1.Shutingyard().parse(inputStr);
929
- const rpn = SY.rpn;
930
- // New version for reducing shuting yard.
931
- this.zero();
932
- let stack = [], monom = new monom_1.Monom();
933
- // Loop through the
934
- for (const element of rpn) {
935
- this.addToken(stack, element);
936
- }
937
- if (stack.length === 1) {
938
- this.add(stack[0]);
939
- }
940
- return this.reorder();
941
- };
942
- this.multiplyByPolynom = (P) => {
943
- const M = [];
944
- for (const m1 of this._monoms) {
945
- for (const m2 of P.monoms) {
946
- M.push(monom_1.Monom.xmultiply(m1, m2));
947
- }
948
- }
949
- this._monoms = M;
950
- return this.reduce();
951
- };
952
- this.multiplyByFraction = (F) => {
953
- for (const m of this._monoms) {
954
- m.coefficient.multiply(F);
955
- }
956
- return this.reduce();
957
- };
958
- this.multiplyByInteger = (nb) => {
959
- return this.multiplyByFraction(new fraction_1.Fraction(nb));
960
- };
961
- this.multiplyByMonom = (M) => {
962
- for (const m of this._monoms) {
963
- m.multiply(M);
964
- }
965
- return this.reduce();
966
- };
967
- this.divideByInteger = (nb) => {
968
- const nbF = new fraction_1.Fraction(nb);
969
- for (const m of this._monoms) {
970
- m.coefficient.divide(nbF);
971
- }
972
- return this;
973
- };
974
- this.divideByFraction = (F) => {
975
- for (const m of this._monoms) {
976
- m.coefficient.divide(F);
977
- }
978
- return this;
979
- };
980
- this._factorize2ndDegree = (letter) => {
981
- let P1, P2, a, b, c, delta, x1, x2, factor;
982
- // One variable only
983
- if (this.numberOfVars === 1) {
984
- a = this.monomByDegree(2, letter).coefficient;
985
- b = this.monomByDegree(1, letter).coefficient;
986
- c = this.monomByDegree(0, letter).coefficient;
987
- delta = b.clone().pow(2).subtract(a.clone().multiply(c).multiply(4));
988
- if (delta.isZero()) {
989
- x1 = b.clone().opposed().divide(a.clone().multiply(2));
990
- P1 = new Polynom(letter).subtract(x1.display).multiply(x1.denominator);
991
- P2 = new Polynom(letter).subtract(x1.display).multiply(x1.denominator);
992
- factor = a.divide(x1.denominator).divide(x1.denominator);
993
- if (!factor.isOne()) {
994
- // TODO: Update new Polynom to accept anything...
995
- return [new Polynom(factor.display), P1, P2];
996
- }
997
- else {
998
- return [P1, P2];
999
- }
1000
- }
1001
- else if (delta.isPositive() && delta.isSquare()) {
1002
- x1 = b.clone().opposed()
1003
- .add(delta.clone().sqrt())
1004
- .divide(a.clone().multiply(2));
1005
- x2 = b.clone().opposed()
1006
- .subtract(delta.clone().sqrt())
1007
- .divide(a.clone().multiply(2));
1008
- // (2x+5)(3x-2)
1009
- // 6x^2+11x-10
1010
- // a = 6, b = 11, c = -10
1011
- // delta = 121-4*6*(-10) = 361= 19^2
1012
- // x1 = (-11 + 19) / 12 = 8/12 = 2/3
1013
- // x2 = (-11 - 19) / 12 = -30/12 = -5/2
1014
- factor = a.divide(x1.denominator).divide(x2.denominator);
1015
- if (factor.isOne()) {
1016
- return [
1017
- new Polynom(letter).subtract(x1.display).multiply(x1.denominator),
1018
- new Polynom(letter).subtract(x2.display).multiply(x2.denominator),
1019
- ];
1020
- }
1021
- else {
1022
- return [
1023
- new Polynom(factor.display),
1024
- new Polynom(letter).subtract(x1.display).multiply(x1.denominator),
1025
- new Polynom(letter).subtract(x2.display).multiply(x2.denominator),
1026
- ];
1027
- }
1028
- }
1029
- else {
1030
- // No solution possible - return the complete value.
1031
- return [this.clone()];
1032
- }
1033
- }
1034
- else {
1035
- // If multiple variables, only handle perfect squares...
1036
- a = this.monomByDegree(2, letter);
1037
- b = this.monomByDegree(1, letter);
1038
- c = this.monomByDegree(0, letter);
1039
- if (a.isLiteralSquare() && c.isLiteralSquare()) {
1040
- // Check the middle item is same as...
1041
- if (b.clone().pow(2).isSameAs(a.clone().multiply(c))) {
1042
- // Determine if the coefficient values matches.
1043
- // Search 4 values (r, s, t, u) that matches:
1044
- // (r X + s Y)(t X + u Y) = rt X^2 + (ru + st) XY + su Y^2
1045
- let xPolynom = new Polynom('x', a.coefficient, b.coefficient, c.coefficient);
1046
- let xFactors = xPolynom._factorize2ndDegree('x');
1047
- let factors = [], xyzPolynom;
1048
- if (xFactors.length >= 2) {
1049
- for (let p of xFactors) {
1050
- if (p.degree().isZero()) {
1051
- factors.push(p.clone());
1052
- }
1053
- else {
1054
- xyzPolynom = p.clone();
1055
- xyzPolynom.monoms[0].literal = a.literalSqrt;
1056
- xyzPolynom.monoms[1].literal = c.literalSqrt;
1057
- factors.push(xyzPolynom.clone());
1058
- }
1059
- }
1060
- return factors;
1061
- }
1062
- }
1063
- }
1064
- return [this.clone()];
1065
- }
1066
- };
1067
- this._factorizeByGroups = () => {
1068
- // TODO: Factorize by groups.
1069
- return [];
1070
- };
1071
- this._monoms = [];
1072
- this._factors = [];
1073
- this.mark_as_dirty();
1074
- if (polynomString !== undefined) {
1075
- this.parse(polynomString, ...values);
1076
- }
1077
- return this;
1078
- }
1079
- get euclidianCache() {
1080
- return this._euclidianCache;
1081
- }
1082
- set euclidianCache(value) {
1083
- this._euclidianCache = value;
1084
- }
1085
- get dirty_zeroes() {
1086
- return this._dirty_zeroes;
1087
- }
1088
- set dirty_zeroes(value) {
1089
- this._dirty_zeroes = value;
1090
- }
1091
- // ------------------------------------------
1092
- get dirty_factors() {
1093
- return this._dirty_factors;
1094
- }
1095
- set dirty_factors(value) {
1096
- this._dirty_factors = value;
1097
- }
1098
- // ------------------------------------------
1099
- get monoms() {
1100
- return this._monoms;
1101
- }
1102
- set monoms(M) {
1103
- this._monoms = M;
1104
- }
1105
- get zeroes() {
1106
- return this.getZeroes();
1107
- }
1108
- get factors() {
1109
- return this.factorize();
1110
- }
1111
- set factors(value) {
1112
- this.mark_as_dirty();
1113
- this._factors = value;
1114
- }
1115
- get texString() {
1116
- return this._texString;
1117
- }
1118
- get texFactors() {
1119
- this.factorize();
1120
- if (this.factors.length <= 1) {
1121
- return this.tex;
1122
- }
1123
- // Build an array of texFactors with the number of similar items.
1124
- let factorsCount = {};
1125
- for (let f of this.factors) {
1126
- if (factorsCount[f.tex] !== undefined) {
1127
- factorsCount[f.tex].degree++;
1128
- }
1129
- else {
1130
- factorsCount[f.tex] = {
1131
- degree: 1,
1132
- factor: f
1133
- };
1134
- }
1135
- }
1136
- // First round to put the 'monom' first
1137
- let simpleFactor = new Polynom().one();
1138
- for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length === 1)) {
1139
- simpleFactor.multiply(item.factor);
1140
- }
1141
- let tex = simpleFactor.isOne() ? '' : simpleFactor.tex;
1142
- // Loop through all factors that contains at least 2 monoms.
1143
- for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length > 1)) {
1144
- if (item.factor.length > 1) {
1145
- tex += `\\left( ${item.factor.tex} \\right)${item.degree > 1 ? '^{ ' + item.degree + ' }' : ''}`;
1146
- }
1147
- }
1148
- return tex;
1149
- }
1150
- get displayFactors() {
1151
- this.factorize();
1152
- if (this.factors.length <= 1) {
1153
- return this.display;
1154
- }
1155
- // Build an array of texFactors with the number of similar items.
1156
- let factorsCount = {};
1157
- for (let f of this.factors) {
1158
- if (factorsCount[f.display] !== undefined) {
1159
- factorsCount[f.display].degree++;
1160
- }
1161
- else {
1162
- factorsCount[f.display] = {
1163
- degree: 1,
1164
- factor: f
1165
- };
1166
- }
1167
- }
1168
- // First round to put the 'monom' first
1169
- let simpleFactor = new Polynom().one();
1170
- for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length === 1)) {
1171
- simpleFactor.multiply(item.factor);
1172
- }
1173
- let display = simpleFactor.isOne() ? '' : simpleFactor.display;
1174
- // Loop through all factors that contains at least 2 monoms.
1175
- for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length > 1)) {
1176
- if (item.factor.length > 1) {
1177
- display += `(${item.factor.display})${item.degree > 1 ? '^(' + item.degree + ')' : ''}`;
1178
- }
1179
- }
1180
- return display;
1181
- }
1182
- get length() {
1183
- // TODO: Must reduce the monoms list to remove the zero coefficient.
1184
- return this._monoms.length;
1185
- }
1186
- get display() {
1187
- return this.genDisplay();
1188
- }
1189
- get raw() {
1190
- return this._rawString;
1191
- }
1192
- get tex() {
1193
- return this.genDisplay('tex');
1194
- }
1195
- get isMultiVariable() {
1196
- const B = false;
1197
- for (const m of this._monoms) {
1198
- if (m.variables.length > 1) {
1199
- return true;
1200
- }
1201
- }
1202
- return B;
1203
- }
1204
- get variables() {
1205
- let V = [];
1206
- for (const m of this._monoms) {
1207
- V = V.concat(m.variables);
1208
- }
1209
- // Remove duplicates.
1210
- V = [...new Set(V)];
1211
- V.sort();
1212
- return V;
1213
- }
1214
- get numberOfVars() {
1215
- return this.variables.length;
1216
- }
1217
- get plotFunction() {
1218
- return this.genDisplay('tex', false, false, true);
1219
- }
1220
- isZero() {
1221
- return (this._monoms.length === 1 && this._monoms[0].coefficient.isZero()) || this._monoms.length === 0;
1222
- }
1223
- isOne() {
1224
- return this._monoms.length === 1 && this._monoms[0].coefficient.isOne();
1225
- }
1226
- _parseString(inputStr, ...values) {
1227
- if (values === undefined || values.length === 0) {
1228
- inputStr = '' + inputStr;
1229
- this._rawString = inputStr.trim().replaceAll(' ', '');
1230
- // Parse the polynom using the shutting yard algorithm
1231
- if (inputStr !== '' && !isNaN(Number(inputStr))) {
1232
- this.empty();
1233
- // It's a simple number.
1234
- let m = new monom_1.Monom(inputStr);
1235
- // m.coefficient = new Fraction(inputStr);
1236
- // m.literalStr = '';
1237
- this.add(m);
1238
- return this;
1239
- }
1240
- // Parse the string.
1241
- return this.shutingYardToReducedPolynom(inputStr);
1242
- }
1243
- else if (/^[a-z]/.test(inputStr)) {
1244
- // We assume the inputStr contains only letters.
1245
- this.empty();
1246
- let fractions = values.map(x => new fraction_1.Fraction(x));
1247
- // Multiple setLetter version
1248
- if (inputStr.length > 1) {
1249
- // TODO: check that the number of values given correspond to the letters (+1 eventually)
1250
- let letters = inputStr.split(''), i = 0;
1251
- for (let F of fractions) {
1252
- let m = new monom_1.Monom();
1253
- m.coefficient = F.clone();
1254
- m.literalStr = letters[i] || '';
1255
- this.add(m);
1256
- i++;
1257
- }
1258
- }
1259
- // Single setLetter version
1260
- else {
1261
- let n = fractions.length - 1;
1262
- for (let F of fractions) {
1263
- let m = new monom_1.Monom();
1264
- m.coefficient = F.clone();
1265
- m.literalStr = `${inputStr}^${n}`;
1266
- this.add(m);
1267
- n--;
1268
- }
1269
- }
1270
- return this;
1271
- }
1272
- else {
1273
- return this.zero();
1274
- }
1275
- }
1276
- }
1277
- exports.Polynom = Polynom;
1
+ "use strict";
2
+ /**
3
+ * Polynom module contains everything necessary to handle polynoms.*
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Polynom = void 0;
7
+ const monom_1 = require("./monom");
8
+ const shutingyard_1 = require("../shutingyard");
9
+ const numeric_1 = require("../numeric");
10
+ const fraction_1 = require("../coefficients/fraction");
11
+ const equation_1 = require("./equation");
12
+ /**
13
+ * Polynom class can handle polynoms, reorder, resolve, ...
14
+ * ```
15
+ * let P = new Polynom('3x-4')
16
+ * ```
17
+ */
18
+ class Polynom {
19
+ /**
20
+ *
21
+ * @param {string} polynomString (optional) Default polynom to parse on class creation
22
+ * @param values
23
+ */
24
+ constructor(polynomString, ...values) {
25
+ this.mark_as_dirty = () => {
26
+ this.dirty_factors = true;
27
+ this.dirty_zeroes = true;
28
+ this.euclidianCache = {};
29
+ };
30
+ this.addToken = (stack, element) => {
31
+ switch (element.tokenType) {
32
+ case shutingyard_1.ShutingyardType.COEFFICIENT:
33
+ stack.push(new Polynom(element.token));
34
+ break;
35
+ case shutingyard_1.ShutingyardType.VARIABLE:
36
+ stack.push(new Polynom().add(new monom_1.Monom(element.token)));
37
+ break;
38
+ case shutingyard_1.ShutingyardType.CONSTANT:
39
+ // TODO: add constant support to Polynom parsing.
40
+ console.log('Actually, not supported - will be added later !');
41
+ break;
42
+ case shutingyard_1.ShutingyardType.OPERATION:
43
+ if (stack.length >= 2) {
44
+ const b = stack.pop(), a = stack.pop();
45
+ if (element.token === '+') {
46
+ stack.push(a.add(b));
47
+ }
48
+ else if (element.token === '-') {
49
+ stack.push(a.subtract(b));
50
+ }
51
+ else if (element.token === '*') {
52
+ stack.push(a.multiply(b));
53
+ }
54
+ else if (element.token === '/') {
55
+ if (b.degree().isStrictlyPositive()) {
56
+ console.log('divide by a polynom -> should create a rational polynom !');
57
+ }
58
+ else {
59
+ stack.push(a.divide(b.monoms[0].coefficient));
60
+ }
61
+ }
62
+ else if (element.token === '^') {
63
+ if (b.degree().isStrictlyPositive()) {
64
+ console.error('Cannot elevate a polynom with another polynom !', a.tex, b.tex);
65
+ }
66
+ else {
67
+ if (b.monoms[0].coefficient.isRelative()) {
68
+ // Integer power
69
+ stack.push(a.pow(b.monoms[0].coefficient.value));
70
+ }
71
+ else {
72
+ // Only allow power if the previous polynom is only a monom, without coefficient.
73
+ if (a.monoms.length === 1 && a.monoms[0].coefficient.isOne()) {
74
+ for (let letter in a.monoms[0].literal) {
75
+ a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient);
76
+ }
77
+ stack.push(a);
78
+ }
79
+ else {
80
+ console.error('Cannot have power with fraction');
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ else {
87
+ if (element.token === '-') {
88
+ stack.push(stack.pop().opposed());
89
+ }
90
+ else {
91
+ throw "Error parsing the polynom " + this._rawString;
92
+ }
93
+ }
94
+ break;
95
+ case shutingyard_1.ShutingyardType.MONOM:
96
+ // Should never appear.
97
+ console.error('The monom token should not appear here');
98
+ break;
99
+ case shutingyard_1.ShutingyardType.FUNCTION:
100
+ // Should never appear.
101
+ console.error('The function token should not appear here - might be introduced later.');
102
+ break;
103
+ }
104
+ };
105
+ // ------------------------------------------
106
+ // Creation / parsing functions
107
+ // ------------------------------------------
108
+ /**
109
+ * Parse a string to a polynom.
110
+ * @param inputStr
111
+ * @param values: as string, numbers or fractions
112
+ */
113
+ this.parse = (inputStr, ...values) => {
114
+ // Reset the main variables.
115
+ this._monoms = [];
116
+ this._factors = [];
117
+ this.mark_as_dirty();
118
+ // TODO: allow to enter a liste of Fraction (a, b, c, ...) to make a polynom ax^n + bx^(n-1) + cx^(n-2) + ...
119
+ if (typeof inputStr === 'string') {
120
+ return this._parseString(inputStr, ...values);
121
+ }
122
+ else if ((typeof inputStr === 'number' || inputStr instanceof fraction_1.Fraction || inputStr instanceof monom_1.Monom)
123
+ && (values === undefined || values.length === 0)) {
124
+ this._monoms.push(new monom_1.Monom(inputStr));
125
+ }
126
+ else if (inputStr instanceof monom_1.Monom && values.length > 0) {
127
+ this._monoms.push(new monom_1.Monom(inputStr));
128
+ values.forEach(m => {
129
+ this._monoms.push(new monom_1.Monom(m));
130
+ });
131
+ }
132
+ else if (inputStr instanceof Polynom) {
133
+ for (const m of inputStr.monoms) {
134
+ this._monoms.push(m.clone());
135
+ }
136
+ }
137
+ return this;
138
+ };
139
+ /**
140
+ * Clone the polynom
141
+ */
142
+ this.clone = () => {
143
+ const P = new Polynom();
144
+ const M = [];
145
+ for (const m of this._monoms) {
146
+ M.push(m.clone());
147
+ }
148
+ P.monoms = M;
149
+ return P;
150
+ };
151
+ /**
152
+ * Set the polynom to zero.
153
+ * @returns {this}
154
+ */
155
+ this.zero = () => {
156
+ this._monoms = [];
157
+ this._monoms.push(new monom_1.Monom().zero());
158
+ this._rawString = '0';
159
+ this.mark_as_dirty();
160
+ return this;
161
+ };
162
+ this.one = () => {
163
+ this._monoms = [];
164
+ this._monoms.push(new monom_1.Monom().one());
165
+ this._rawString = '1';
166
+ this.mark_as_dirty();
167
+ return this;
168
+ };
169
+ this.empty = () => {
170
+ this._monoms = [];
171
+ this._rawString = '';
172
+ this.mark_as_dirty();
173
+ return this;
174
+ };
175
+ // ------------------------------------------
176
+ this.opposed = () => {
177
+ this._monoms = this._monoms.map(m => m.opposed());
178
+ this.mark_as_dirty();
179
+ return this;
180
+ };
181
+ // ------------------------------------------
182
+ // Mathematical operations
183
+ this.add = (...values) => {
184
+ this.mark_as_dirty();
185
+ // @ts-ignore
186
+ for (let value of values) {
187
+ if (value instanceof Polynom) {
188
+ this._monoms = this._monoms.concat(value.monoms);
189
+ }
190
+ else if (value instanceof monom_1.Monom) {
191
+ this._monoms.push(value.clone());
192
+ }
193
+ else if (Number.isSafeInteger(value)) {
194
+ this._monoms.push(new monom_1.Monom(value.toString()));
195
+ }
196
+ else {
197
+ this._monoms.push(new monom_1.Monom(value));
198
+ }
199
+ }
200
+ return this.reduce();
201
+ };
202
+ this.subtract = (...values) => {
203
+ this.mark_as_dirty();
204
+ for (let value of values) {
205
+ if (value instanceof Polynom) {
206
+ this._monoms = this._monoms.concat(value.clone().opposed().monoms);
207
+ }
208
+ else if (value instanceof monom_1.Monom) {
209
+ this._monoms.push(value.clone().opposed());
210
+ }
211
+ else if (Number.isSafeInteger(value)) {
212
+ this._monoms.push(new monom_1.Monom(value.toString()).opposed());
213
+ }
214
+ else {
215
+ this._monoms.push(new monom_1.Monom(value).opposed());
216
+ }
217
+ }
218
+ return this.reduce();
219
+ };
220
+ this.multiply = (value) => {
221
+ this.mark_as_dirty();
222
+ if (value instanceof Polynom) {
223
+ return this.multiplyByPolynom(value);
224
+ }
225
+ else if (value instanceof fraction_1.Fraction) {
226
+ return this.multiplyByFraction(value);
227
+ }
228
+ else if (value instanceof monom_1.Monom) {
229
+ return this.multiplyByMonom(value);
230
+ }
231
+ else if (Number.isSafeInteger(value) && typeof value === 'number') {
232
+ return this.multiplyByInteger(value);
233
+ }
234
+ // Something went wrong...
235
+ return this;
236
+ };
237
+ /**
238
+ * Divide the current polynom by another polynom.
239
+ * @param P
240
+ * returns {quotient: Polynom, reminder: Polynom}
241
+ */
242
+ this.euclidian = (P) => {
243
+ if (this.euclidianCache[P.tex] !== undefined) {
244
+ return this.euclidianCache[P.tex];
245
+ }
246
+ const letter = P.variables[0];
247
+ const quotient = new Polynom().zero();
248
+ const reminder = this.clone().reorder(letter);
249
+ // There is no variable - means it's a number
250
+ if (P.variables.length === 0) {
251
+ let q = this.clone().divide(P);
252
+ return {
253
+ quotient: this.clone().divide(P),
254
+ reminder: new Polynom().zero()
255
+ };
256
+ }
257
+ // Get at least a letter
258
+ const maxMP = P.monomByDegree(undefined, letter);
259
+ const degreeP = P.degree(letter);
260
+ let newM;
261
+ // Make the euclidian division of the two polynoms.
262
+ let MaxIteration = this.degree(letter).clone().multiply(2);
263
+ while (reminder.degree(letter).geq(degreeP) && MaxIteration.isPositive()) {
264
+ MaxIteration.subtract(1);
265
+ // Get the greatest monom divided by the max monom of the divider
266
+ newM = reminder.monomByDegree(undefined, letter).clone().divide(maxMP);
267
+ if (newM.isZero()) {
268
+ break;
269
+ }
270
+ // Get the new quotient and reminder.
271
+ quotient.add(newM);
272
+ reminder.subtract(P.clone().multiply(newM));
273
+ }
274
+ quotient.reduce();
275
+ reminder.reduce();
276
+ return { quotient, reminder };
277
+ };
278
+ this.divide = (value) => {
279
+ this.mark_as_dirty();
280
+ if (value instanceof fraction_1.Fraction) {
281
+ return this.divideByFraction(value);
282
+ }
283
+ else if (typeof value === 'number' && Number.isSafeInteger(value)) {
284
+ return this.divideByInteger(value);
285
+ }
286
+ else if (value instanceof monom_1.Monom) {
287
+ return this.divide(new Polynom(value));
288
+ }
289
+ else if (value instanceof Polynom) {
290
+ if (value.monoms.length === 1 && value.variables.length === 0) {
291
+ return this.divideByFraction(value.monoms[0].coefficient);
292
+ }
293
+ else {
294
+ let { quotient, reminder } = this.euclidian(value);
295
+ if (reminder.isZero()) {
296
+ return quotient;
297
+ }
298
+ else {
299
+ console.log(`${this.tex} is not divideable by ${value.tex}`);
300
+ return new Polynom().zero();
301
+ }
302
+ }
303
+ }
304
+ };
305
+ this.pow = (nb) => {
306
+ this.mark_as_dirty();
307
+ if (!Number.isSafeInteger(nb)) {
308
+ return this.zero();
309
+ }
310
+ if (nb < 0) {
311
+ return this.zero();
312
+ }
313
+ if (nb === 0) {
314
+ return new Polynom();
315
+ }
316
+ const P = this.clone();
317
+ for (let i = 1; i < nb; i++) {
318
+ this.multiply(P);
319
+ }
320
+ return this.reduce();
321
+ };
322
+ // ------------------------------------------
323
+ /**
324
+ * Compare the current coefficient with another coefficient
325
+ * @param P
326
+ * @param sign (string| default is =): authorized values: =, <, <=, >, >= with some variations.
327
+ */
328
+ this.compare = (P, sign) => {
329
+ if (sign === undefined) {
330
+ sign = '=';
331
+ }
332
+ // Create clone version to reduce them without altering the original polynoms.
333
+ const cP1 = this.clone().reduce().reorder();
334
+ const cP2 = P.clone().reduce().reorder();
335
+ switch (sign) {
336
+ case '=':
337
+ // They must have the isSame length and the isSame degree
338
+ if (cP1.length !== cP2.length || cP1.degree().isNotEqual(cP2.degree())) {
339
+ return false;
340
+ }
341
+ // Check if the coefficients are the isSame.
342
+ for (const i in cP1.monoms) {
343
+ if (!cP1.monoms[i].isEqual(cP2.monoms[i])) {
344
+ return false;
345
+ }
346
+ }
347
+ return true;
348
+ case 'same':
349
+ // They must have the isSame length and the isSame degree
350
+ if (cP1.length !== cP2.length || cP1.degree() !== cP2.degree()) {
351
+ return false;
352
+ }
353
+ for (const i in cP1.monoms) {
354
+ if (!cP1.monoms[i].isSameAs(cP2.monoms[i])) {
355
+ return false;
356
+ }
357
+ }
358
+ return true;
359
+ default:
360
+ return false;
361
+ }
362
+ };
363
+ this.isEqual = (P) => {
364
+ return this.compare(P, '=');
365
+ };
366
+ this.isSameAs = (P) => {
367
+ return this.compare(P, 'same');
368
+ };
369
+ this.isOpposedAt = (P) => {
370
+ return this.compare(P.clone().opposed(), '=');
371
+ };
372
+ this.isFactorized = (polynomString, soft) => {
373
+ let P;
374
+ // Check if polynom is complete...
375
+ if (polynomString.split('(').length !== polynomString.split(')').length) {
376
+ return false;
377
+ }
378
+ // Try to build the polynom
379
+ try {
380
+ P = new Polynom(polynomString);
381
+ }
382
+ catch (e) {
383
+ return false;
384
+ }
385
+ // Both polynom aren't the same (once developed and reduced => they cannot be equivalent)
386
+ if (!this.isEqual(P)) {
387
+ return false;
388
+ }
389
+ // Check if the provided (string) version is fully factorized.
390
+ // Run a regex on the string.
391
+ let polynomStringNormalized = polynomString.replaceAll('*', ''), polynomStringReduced = '' + polynomStringNormalized, factors = [];
392
+ for (let x of polynomStringNormalized.matchAll(/\(([a-z0-9+\-]+)\)(\^[0-9]*)?/g)) {
393
+ if (x[2] !== undefined) {
394
+ // if there is an exponential value, add it multiple times
395
+ for (let i = 0; i < +x[2].substring(1); i++) {
396
+ factors.push(x[1]);
397
+ }
398
+ }
399
+ else {
400
+ // no power - add it once.
401
+ factors.push(x[1]);
402
+ }
403
+ // Remove the current polynom
404
+ polynomStringReduced = polynomStringReduced.replaceAll(x[0], '');
405
+ }
406
+ if (polynomStringReduced !== '') {
407
+ factors.push(polynomStringReduced);
408
+ }
409
+ let polyFactors = factors.map(x => new Polynom(x));
410
+ // polyFactors contain all polynoms.
411
+ let checkPolyFactors = polyFactors.filter(x => x.degree().geq(1) && !x.commonMonom().isOne());
412
+ // Some polynoms are not completely factorized.
413
+ if (checkPolyFactors.length > 0 && !soft) {
414
+ return false;
415
+ }
416
+ if (checkPolyFactors.length > 0 && soft) {
417
+ polyFactors = polyFactors.filter(x => x.commonMonom().isOne());
418
+ let FactorizedConstant = new fraction_1.Fraction().one();
419
+ for (let p of checkPolyFactors) {
420
+ let k = p.commonMonom(), pFactor = p.clone().divide(k);
421
+ if (k.degree().isZero()) {
422
+ FactorizedConstant.multiply(k.coefficient);
423
+ polyFactors.push(pFactor.clone());
424
+ }
425
+ }
426
+ }
427
+ // Factorize the current polynom.
428
+ this.factorize();
429
+ // Compare the given factors with the generated factors
430
+ let sign = 1, notFoundedFactors = [];
431
+ for (let f of this.factors) {
432
+ // The factor is just a coefficient. Might be opposed
433
+ if (f.degree().isZero()) {
434
+ if (f.monoms[0].coefficient.isNegativeOne()) {
435
+ sign = -sign;
436
+ }
437
+ }
438
+ let factorFound = false;
439
+ for (let i = 0; i < polyFactors.length; i++) {
440
+ if (f.isEqual(polyFactors[i])) {
441
+ polyFactors.splice(i, 1);
442
+ factorFound = true;
443
+ break;
444
+ }
445
+ else if (f.isOpposedAt(polyFactors[i])) {
446
+ polyFactors.splice(i, 1);
447
+ sign = -sign;
448
+ factorFound = true;
449
+ break;
450
+ }
451
+ }
452
+ if (!factorFound) {
453
+ notFoundedFactors.push(f.clone());
454
+ }
455
+ }
456
+ // The polyfactors must be empty and the cumulative opposite factors must be 1.
457
+ return (polyFactors.length === 0 && sign === 1);
458
+ };
459
+ // ------------------------------------------
460
+ // Compare functions
461
+ this.isReduced = (polynomString) => {
462
+ // The polynom must be developed to be reduced.
463
+ if (!this.isDeveloped(polynomString)) {
464
+ return false;
465
+ }
466
+ let P = new Polynom(polynomString);
467
+ if (P.monoms.length > this.monoms.length) {
468
+ return false;
469
+ }
470
+ // TODO: Not ur the reduced systme checking is working properly !
471
+ for (let m of P.monoms) {
472
+ if (!m.coefficient.isReduced()) {
473
+ return false;
474
+ }
475
+ }
476
+ return false;
477
+ };
478
+ this.isDeveloped = (polynomString) => {
479
+ let P;
480
+ // There is at least one parenthese - it is not developed.
481
+ if (polynomString.split('(').length + polynomString.split(')').length > 0) {
482
+ return false;
483
+ }
484
+ // Try to build the polynom
485
+ try {
486
+ // Build the polynom
487
+ P = new Polynom(polynomString);
488
+ }
489
+ catch (e) {
490
+ return false;
491
+ }
492
+ // Both polynom aren't the same (once developed and reduced => they cannot be equivalent)
493
+ if (!this.isEqual(P)) {
494
+ return false;
495
+ }
496
+ // Check that everything is completely developed. Actually, there are no parentheses... so it is fully developed
497
+ // maybe it wasn't reduced and not ordered...
498
+ // compare polynom string.
499
+ // normalize the string
500
+ let polynomStringNormalized = polynomString.replaceAll('[*\s]', '');
501
+ // Determine if it's the exact same string.
502
+ // TODO: Maybe it's enough to just make this test !
503
+ return polynomStringNormalized === P.reduce().reorder().display;
504
+ };
505
+ // -------------------------------------
506
+ this.reduce = () => {
507
+ // Reduce the polynom
508
+ let values = [...this._monoms], vars = [...this.variables];
509
+ this._monoms = [];
510
+ let coeffs = values.filter(x => x.variables.length === 0);
511
+ if (coeffs.length > 0) {
512
+ this._monoms.push(coeffs.reduce((a, b) => a.add(b)));
513
+ }
514
+ // Build the new monoms
515
+ for (let letter of vars) {
516
+ // Monom with same letters, but might be of different degrees
517
+ let M = values.filter(x => x.hasLetter(letter));
518
+ while (M.length > 0) {
519
+ // Take the first element
520
+ const m = M.shift(), degree = m.degree(letter);
521
+ for (let a of M.filter(x => x.degree(letter).isEqual(degree))) {
522
+ m.add(a);
523
+ }
524
+ this._monoms.push(m);
525
+ // Make the new array.
526
+ M = M.filter(x => x.degree(letter).isNotEqual(degree));
527
+ }
528
+ // reduce the monom
529
+ }
530
+ // Remove all null monoms
531
+ this._monoms = this._monoms.filter((m) => {
532
+ return m.coefficient.value !== 0;
533
+ });
534
+ // Reduce all monoms coefficient.
535
+ for (const m of this._monoms) {
536
+ m.coefficient.reduce();
537
+ }
538
+ if (this.length === 0) {
539
+ return new Polynom().zero();
540
+ }
541
+ return this.reorder();
542
+ };
543
+ this.reorder = (letter = 'x', revert) => {
544
+ if (revert === undefined) {
545
+ revert = false;
546
+ }
547
+ // TODO: Must handle multiple setLetter reorder system
548
+ let otherLetters = this.variables.filter(x => x !== letter);
549
+ this._monoms.sort(function (a, b) {
550
+ let da = a.degree(letter).value, db = b.degree(letter).value;
551
+ // Values are different
552
+ if (da !== db)
553
+ return revert ? da - db : db - da;
554
+ // if values are equals, check other letters - it must be revert in that case !
555
+ if (otherLetters.length > 0) {
556
+ for (let L of otherLetters) {
557
+ let da = a.degree(L).value, db = b.degree(L).value;
558
+ // Values are different
559
+ if (da !== db)
560
+ return revert ? da - db : db - da;
561
+ }
562
+ }
563
+ return 0;
564
+ // return b.degree(letter).clone().subtract(a.degree(letter)).value
565
+ });
566
+ return this;
567
+ };
568
+ this.degree = (letter) => {
569
+ let d = new fraction_1.Fraction().zero();
570
+ for (const m of this._monoms) {
571
+ d = fraction_1.Fraction.max(m.degree(letter).value, d);
572
+ }
573
+ return d;
574
+ };
575
+ this.letters = () => {
576
+ let L = [], S = new Set();
577
+ for (let m of this._monoms) {
578
+ S = new Set([...S, ...m.variables]);
579
+ }
580
+ // @ts-ignore
581
+ return [...S];
582
+ };
583
+ /**
584
+ * Replace a variable (letter) by a polynom.
585
+ * @param letter
586
+ * @param P
587
+ */
588
+ this.replaceBy = (letter, P) => {
589
+ this.mark_as_dirty();
590
+ let pow;
591
+ const resultPolynom = new Polynom().zero();
592
+ for (const m of this.monoms) {
593
+ if (m.literal[letter] === undefined || m.literal[letter].isZero()) {
594
+ resultPolynom.add(m.clone());
595
+ }
596
+ else {
597
+ // We have found a setLetter.
598
+ // Get the power and reset it.
599
+ pow = m.literal[letter].clone();
600
+ delete m.literal[letter];
601
+ // TODO: replaceBy works only with positive and natural pow
602
+ resultPolynom.add(P.clone().pow(Math.abs(pow.numerator)).multiply(m));
603
+ }
604
+ }
605
+ this._monoms = resultPolynom.reduce().reorder().monoms;
606
+ return this;
607
+ };
608
+ // Evaluate a polynom.
609
+ this.evaluate = (values) => {
610
+ const r = new fraction_1.Fraction().zero();
611
+ this._monoms.forEach(monom => {
612
+ //console.log('Evaluate polynom: ', monom.display, values, monom.evaluate(values).display);
613
+ r.add(monom.evaluate(values));
614
+ });
615
+ return r;
616
+ };
617
+ this.evaluateAsNumeric = (values) => {
618
+ let r = 0;
619
+ this._monoms.forEach(monom => {
620
+ r += monom.evaluateAsNumeric(values);
621
+ });
622
+ return r;
623
+ };
624
+ this.derivative = (letter) => {
625
+ let dP = new Polynom();
626
+ for (let m of this._monoms) {
627
+ dP.add(m.derivative(letter));
628
+ }
629
+ return dP;
630
+ };
631
+ // ------------------------------------------
632
+ // Misc polynoms functions
633
+ this.primitive = (letter) => {
634
+ let dP = new Polynom();
635
+ for (let m of this._monoms) {
636
+ dP.add(m.primitive(letter));
637
+ }
638
+ return dP;
639
+ };
640
+ this.integrate = (a, b, letter) => {
641
+ const primitive = this.primitive(letter);
642
+ if (letter === undefined) {
643
+ letter = 'x';
644
+ }
645
+ let valuesA = {}, valuesB = {};
646
+ valuesA[letter] = new fraction_1.Fraction(a);
647
+ valuesB[letter] = new fraction_1.Fraction(b);
648
+ return primitive.evaluate(valuesB).subtract(primitive.evaluate(valuesA));
649
+ };
650
+ // -------------------------------------
651
+ /**
652
+ * Factorize a polynom and store the best results in factors.
653
+ * @param maxValue Defines the greatest value to search to (default is 20).
654
+ */
655
+ this.factorize = (letter) => {
656
+ if (!this.dirty_factors) {
657
+ return this._factors;
658
+ }
659
+ let factors = [];
660
+ let P = this.clone().reorder();
661
+ // Extract the common monom
662
+ // 2x^3+6x^2 => 2x^2
663
+ let M = P.commonMonom();
664
+ // If the polynom starts with a negative monom, factorize it.
665
+ if (P.monomByDegree().coefficient.isStrictlyNegative() && M.coefficient.isStrictlyPositive() && !M.isOne()) {
666
+ M.opposed();
667
+ }
668
+ if (!M.isOne()) {
669
+ let tempPolynom = new Polynom(M);
670
+ factors = [tempPolynom.clone()];
671
+ P = P.euclidian(tempPolynom).quotient;
672
+ }
673
+ // Main loop
674
+ let securityLoop = P.degree().clone().multiply(2).value, maxDegree = 1;
675
+ while (securityLoop >= 0) {
676
+ securityLoop--;
677
+ if (P.monoms.length < 2) {
678
+ // The polynom has only one monom => 7x^2
679
+ // No need to continue.
680
+ if (!P.isOne()) {
681
+ factors.push(P.clone());
682
+ P.one();
683
+ }
684
+ break;
685
+ }
686
+ else if (P.degree(letter).isOne()) {
687
+ // The polynom is a first degree polynom => 3x-5
688
+ // No need to continue
689
+ factors.push(P.clone());
690
+ P.one();
691
+ break;
692
+ }
693
+ else {
694
+ // Create the list of all "potential" polynom dividers.
695
+ let allDividers = this._getAllPotentialFactors(P, maxDegree, letter);
696
+ maxDegree = P.degree(letter).value;
697
+ // Actually: 100ms
698
+ while (allDividers.length > 0) {
699
+ let div = allDividers[0];
700
+ if (!P.isDividableBy(div)) {
701
+ // Not dividable. Remove it from the list
702
+ allDividers.shift();
703
+ }
704
+ else {
705
+ // It's dividable - so make the division
706
+ let result = P.euclidian(div);
707
+ // Add the factor
708
+ factors.push(div);
709
+ // As it's dividable, get the quotient.
710
+ P = result.quotient.clone();
711
+ // filter all dividers that are no more suitable.
712
+ allDividers = allDividers.filter(x => {
713
+ let pX = P.monoms[0], pC = P.monoms[P.monoms.length - 1], dX = x.monoms[0], dC = x.monoms[x.monoms.length - 1];
714
+ // Check last item (degree zero)
715
+ if (!pC.isDivisible(dC)) {
716
+ return false;
717
+ }
718
+ // Check the first item (degree max)
719
+ if (!pX.isDivisible(dX)) {
720
+ return false;
721
+ }
722
+ return true;
723
+ });
724
+ }
725
+ }
726
+ }
727
+ }
728
+ // Maybe there is still something in the Polynom (not everything was possible to factorize)
729
+ if (!P.isOne()) {
730
+ factors.push(P.clone());
731
+ }
732
+ // Save the factors
733
+ this._factors = factors;
734
+ // The factors list is no more dirty
735
+ this.dirty_factors = false;
736
+ return this._factors;
737
+ };
738
+ this.isDividableBy = (div) => {
739
+ // Quick evaluation.
740
+ if (div.degree().isOne()) {
741
+ let zero = div.getZeroes()[0];
742
+ if (zero.exact instanceof fraction_1.Fraction) {
743
+ return this.evaluate(zero.exact).isZero();
744
+ }
745
+ else {
746
+ return false;
747
+ }
748
+ }
749
+ else {
750
+ this.euclidianCache[div.tex] = this.euclidian(div);
751
+ return this.euclidianCache[div.tex].reminder.isZero();
752
+ }
753
+ };
754
+ // TODO: get zeroes for more than first degree and for more than natural degrees
755
+ this.getZeroes = () => {
756
+ if (this.dirty_zeroes) {
757
+ let equ = new equation_1.Equation(this.clone(), 0);
758
+ equ.solve();
759
+ this._zeroes = equ.solutions;
760
+ this.dirty_zeroes = false;
761
+ }
762
+ return this._zeroes;
763
+ };
764
+ // TODO: analyse the next functions to determine if they are useful or not...
765
+ this.monomByDegree = (degree, letter) => {
766
+ if (degree === undefined) {
767
+ // return the highest degree monom.
768
+ return this.monomByDegree(this.degree(letter), letter);
769
+ }
770
+ // Reduce the polynom.
771
+ const M = this.clone().reduce();
772
+ for (const m of M._monoms) {
773
+ if (m.degree(letter).isEqual(degree)) {
774
+ return m.clone();
775
+ }
776
+ }
777
+ // Nothing was found - return the null monom.
778
+ return new monom_1.Monom().zero();
779
+ };
780
+ this.monomsByDegree = (degree, letter) => {
781
+ if (degree === undefined) {
782
+ // return the highest degree monom.
783
+ return this.monomsByDegree(this.degree(letter));
784
+ }
785
+ // Reduce the polynom.
786
+ let Ms = [];
787
+ const M = this.clone().reduce();
788
+ for (const m of M._monoms) {
789
+ if (m.degree(letter) === degree) {
790
+ Ms.push(m.clone());
791
+ }
792
+ }
793
+ return Ms;
794
+ // Nothing was found - retur
795
+ };
796
+ // Used in LinearSystem.tex
797
+ this.monomByLetter = (letter) => {
798
+ const M = this.clone().reduce();
799
+ for (const m of M._monoms) {
800
+ if (m.hasLetter(letter)) {
801
+ return m.clone();
802
+ }
803
+ }
804
+ return new monom_1.Monom().zero();
805
+ };
806
+ // Next functions are used for for commonMonom, which is used in the factorize method.
807
+ this.getDenominators = () => {
808
+ const denominators = [];
809
+ for (const m of this._monoms) {
810
+ denominators.push(m.coefficient.denominator);
811
+ }
812
+ return denominators;
813
+ };
814
+ this.getNumerators = () => {
815
+ const numerators = [];
816
+ for (const m of this._monoms) {
817
+ numerators.push(m.coefficient.numerator);
818
+ }
819
+ return numerators;
820
+ };
821
+ this.lcmDenominator = () => {
822
+ return numeric_1.Numeric.lcm(...this.getDenominators());
823
+ };
824
+ // ------------------------------------------
825
+ // Polynoms factorization functions
826
+ this.gcdDenominator = () => {
827
+ return numeric_1.Numeric.gcd(...this.getDenominators());
828
+ };
829
+ this.lcmNumerator = () => {
830
+ return numeric_1.Numeric.lcm(...this.getNumerators());
831
+ };
832
+ this.gcdNumerator = () => {
833
+ return numeric_1.Numeric.gcd(...this.getNumerators());
834
+ };
835
+ // ------------------------------------------
836
+ // Polynoms helpers functions
837
+ // -------------------------------------
838
+ this.commonMonom = () => {
839
+ let M = new monom_1.Monom().one(), numerator, denominator, degree = this.degree();
840
+ numerator = this.gcdNumerator();
841
+ denominator = this.gcdDenominator();
842
+ M.coefficient = new fraction_1.Fraction(numerator, denominator);
843
+ for (let L of this.variables) {
844
+ // Initialize the setLetter with the max degree
845
+ M.setLetter(L, degree);
846
+ for (let m of this._monoms) {
847
+ M.setLetter(L, fraction_1.Fraction.min(m.degree(L), M.degree(L)));
848
+ if (M.degree(L).isZero()) {
849
+ break;
850
+ }
851
+ }
852
+ }
853
+ return M;
854
+ };
855
+ this.limitToInfinity = (letter) => {
856
+ const M = this.monomByDegree(undefined, letter), sign = M.coefficient.sign(), degree = M.degree(letter);
857
+ if (degree.isStrictlyPositive()) {
858
+ return sign === 1 ? (new fraction_1.Fraction()).infinite() : (new fraction_1.Fraction()).infinite().opposed();
859
+ }
860
+ else if (degree.isZero()) {
861
+ return M.coefficient;
862
+ }
863
+ // Any other cases
864
+ return (new fraction_1.Fraction()).zero();
865
+ };
866
+ this.limitToNegativeInfinity = (letter) => {
867
+ const M = this.monomByDegree(undefined, letter), sign = M.coefficient.sign(), degree = M.degree(letter);
868
+ if (degree.isStrictlyPositive()) {
869
+ return sign === -1 ? (new fraction_1.Fraction()).infinite() : (new fraction_1.Fraction()).infinite().opposed();
870
+ }
871
+ else if (degree.isZero()) {
872
+ return M.coefficient;
873
+ }
874
+ // Any other cases
875
+ return (new fraction_1.Fraction()).zero();
876
+ };
877
+ this._getAllPotentialFactors = (P, maxDegree, letter) => {
878
+ let m1 = P.monoms[0].dividers, m2 = P.monoms[P.monoms.length - 1].dividers;
879
+ let allDividers = [];
880
+ m1.forEach(m1d => {
881
+ // Get only polynom that has a degree less than a specific value
882
+ if (m1d.degree(letter).leq(maxDegree)) {
883
+ m2.forEach(m2d => {
884
+ if (m1d.degree(letter).isNotEqual(m2d.degree(letter))) {
885
+ allDividers.push(new Polynom(m1d, m2d));
886
+ allDividers.push(new Polynom(m1d, m2d.clone().opposed()));
887
+ }
888
+ });
889
+ }
890
+ });
891
+ return allDividers;
892
+ };
893
+ this.genDisplay = (output, forceSign, wrapParentheses, withAllMultSign) => {
894
+ let P = '';
895
+ for (const k of this._monoms) {
896
+ if (k.coefficient.value === 0) {
897
+ continue;
898
+ }
899
+ // The monom to be displayed
900
+ let m;
901
+ if (withAllMultSign) {
902
+ m = k.plotFunction;
903
+ }
904
+ else {
905
+ m = (output === 'tex') ? k.tex : k.display;
906
+ }
907
+ P += `${(k.coefficient.sign() === 1 && (P !== '' || forceSign === true)) ? '+' : ''}${m}`;
908
+ }
909
+ if (wrapParentheses === true && this.length > 1) {
910
+ if (output === 'tex') {
911
+ P = `\\left( ${P} \\right)`;
912
+ }
913
+ else {
914
+ P = `(${P})`;
915
+ }
916
+ }
917
+ if (P === '') {
918
+ P = '0';
919
+ }
920
+ return P;
921
+ };
922
+ /**
923
+ * Main parse using a shutting yard class
924
+ * @param inputStr
925
+ */
926
+ this.shutingYardToReducedPolynom = (inputStr) => {
927
+ // Get the RPN array of the current expression
928
+ const SY = new shutingyard_1.Shutingyard().parse(inputStr);
929
+ const rpn = SY.rpn;
930
+ // New version for reducing shuting yard.
931
+ this.zero();
932
+ let stack = [], monom = new monom_1.Monom();
933
+ // Loop through the
934
+ for (const element of rpn) {
935
+ this.addToken(stack, element);
936
+ }
937
+ if (stack.length === 1) {
938
+ this.add(stack[0]);
939
+ }
940
+ return this.reorder();
941
+ };
942
+ this.multiplyByPolynom = (P) => {
943
+ const M = [];
944
+ for (const m1 of this._monoms) {
945
+ for (const m2 of P.monoms) {
946
+ M.push(monom_1.Monom.xmultiply(m1, m2));
947
+ }
948
+ }
949
+ this._monoms = M;
950
+ return this.reduce();
951
+ };
952
+ this.multiplyByFraction = (F) => {
953
+ for (const m of this._monoms) {
954
+ m.coefficient.multiply(F);
955
+ }
956
+ return this.reduce();
957
+ };
958
+ this.multiplyByInteger = (nb) => {
959
+ return this.multiplyByFraction(new fraction_1.Fraction(nb));
960
+ };
961
+ this.multiplyByMonom = (M) => {
962
+ for (const m of this._monoms) {
963
+ m.multiply(M);
964
+ }
965
+ return this.reduce();
966
+ };
967
+ this.divideByInteger = (nb) => {
968
+ const nbF = new fraction_1.Fraction(nb);
969
+ for (const m of this._monoms) {
970
+ m.coefficient.divide(nbF);
971
+ }
972
+ return this;
973
+ };
974
+ this.divideByFraction = (F) => {
975
+ for (const m of this._monoms) {
976
+ m.coefficient.divide(F);
977
+ }
978
+ return this;
979
+ };
980
+ this._factorize2ndDegree = (letter) => {
981
+ let P1, P2, a, b, c, delta, x1, x2, factor;
982
+ // One variable only
983
+ if (this.numberOfVars === 1) {
984
+ a = this.monomByDegree(2, letter).coefficient;
985
+ b = this.monomByDegree(1, letter).coefficient;
986
+ c = this.monomByDegree(0, letter).coefficient;
987
+ delta = b.clone().pow(2).subtract(a.clone().multiply(c).multiply(4));
988
+ if (delta.isZero()) {
989
+ x1 = b.clone().opposed().divide(a.clone().multiply(2));
990
+ P1 = new Polynom(letter).subtract(x1.display).multiply(x1.denominator);
991
+ P2 = new Polynom(letter).subtract(x1.display).multiply(x1.denominator);
992
+ factor = a.divide(x1.denominator).divide(x1.denominator);
993
+ if (!factor.isOne()) {
994
+ // TODO: Update new Polynom to accept anything...
995
+ return [new Polynom(factor.display), P1, P2];
996
+ }
997
+ else {
998
+ return [P1, P2];
999
+ }
1000
+ }
1001
+ else if (delta.isPositive() && delta.isSquare()) {
1002
+ x1 = b.clone().opposed()
1003
+ .add(delta.clone().sqrt())
1004
+ .divide(a.clone().multiply(2));
1005
+ x2 = b.clone().opposed()
1006
+ .subtract(delta.clone().sqrt())
1007
+ .divide(a.clone().multiply(2));
1008
+ // (2x+5)(3x-2)
1009
+ // 6x^2+11x-10
1010
+ // a = 6, b = 11, c = -10
1011
+ // delta = 121-4*6*(-10) = 361= 19^2
1012
+ // x1 = (-11 + 19) / 12 = 8/12 = 2/3
1013
+ // x2 = (-11 - 19) / 12 = -30/12 = -5/2
1014
+ factor = a.divide(x1.denominator).divide(x2.denominator);
1015
+ if (factor.isOne()) {
1016
+ return [
1017
+ new Polynom(letter).subtract(x1.display).multiply(x1.denominator),
1018
+ new Polynom(letter).subtract(x2.display).multiply(x2.denominator),
1019
+ ];
1020
+ }
1021
+ else {
1022
+ return [
1023
+ new Polynom(factor.display),
1024
+ new Polynom(letter).subtract(x1.display).multiply(x1.denominator),
1025
+ new Polynom(letter).subtract(x2.display).multiply(x2.denominator),
1026
+ ];
1027
+ }
1028
+ }
1029
+ else {
1030
+ // No solution possible - return the complete value.
1031
+ return [this.clone()];
1032
+ }
1033
+ }
1034
+ else {
1035
+ // If multiple variables, only handle perfect squares...
1036
+ a = this.monomByDegree(2, letter);
1037
+ b = this.monomByDegree(1, letter);
1038
+ c = this.monomByDegree(0, letter);
1039
+ if (a.isLiteralSquare() && c.isLiteralSquare()) {
1040
+ // Check the middle item is same as...
1041
+ if (b.clone().pow(2).isSameAs(a.clone().multiply(c))) {
1042
+ // Determine if the coefficient values matches.
1043
+ // Search 4 values (r, s, t, u) that matches:
1044
+ // (r X + s Y)(t X + u Y) = rt X^2 + (ru + st) XY + su Y^2
1045
+ let xPolynom = new Polynom('x', a.coefficient, b.coefficient, c.coefficient);
1046
+ let xFactors = xPolynom._factorize2ndDegree('x');
1047
+ let factors = [], xyzPolynom;
1048
+ if (xFactors.length >= 2) {
1049
+ for (let p of xFactors) {
1050
+ if (p.degree().isZero()) {
1051
+ factors.push(p.clone());
1052
+ }
1053
+ else {
1054
+ xyzPolynom = p.clone();
1055
+ xyzPolynom.monoms[0].literal = a.literalSqrt;
1056
+ xyzPolynom.monoms[1].literal = c.literalSqrt;
1057
+ factors.push(xyzPolynom.clone());
1058
+ }
1059
+ }
1060
+ return factors;
1061
+ }
1062
+ }
1063
+ }
1064
+ return [this.clone()];
1065
+ }
1066
+ };
1067
+ this._factorizeByGroups = () => {
1068
+ // TODO: Factorize by groups.
1069
+ return [];
1070
+ };
1071
+ this._monoms = [];
1072
+ this._factors = [];
1073
+ this.mark_as_dirty();
1074
+ if (polynomString !== undefined) {
1075
+ this.parse(polynomString, ...values);
1076
+ }
1077
+ return this;
1078
+ }
1079
+ get euclidianCache() {
1080
+ return this._euclidianCache;
1081
+ }
1082
+ set euclidianCache(value) {
1083
+ this._euclidianCache = value;
1084
+ }
1085
+ get dirty_zeroes() {
1086
+ return this._dirty_zeroes;
1087
+ }
1088
+ set dirty_zeroes(value) {
1089
+ this._dirty_zeroes = value;
1090
+ }
1091
+ // ------------------------------------------
1092
+ get dirty_factors() {
1093
+ return this._dirty_factors;
1094
+ }
1095
+ set dirty_factors(value) {
1096
+ this._dirty_factors = value;
1097
+ }
1098
+ // ------------------------------------------
1099
+ get monoms() {
1100
+ return this._monoms;
1101
+ }
1102
+ set monoms(M) {
1103
+ this._monoms = M;
1104
+ }
1105
+ get zeroes() {
1106
+ return this.getZeroes();
1107
+ }
1108
+ get factors() {
1109
+ return this.factorize();
1110
+ }
1111
+ set factors(value) {
1112
+ this.mark_as_dirty();
1113
+ this._factors = value;
1114
+ }
1115
+ get texString() {
1116
+ return this._texString;
1117
+ }
1118
+ get texFactors() {
1119
+ this.factorize();
1120
+ if (this.factors.length <= 1) {
1121
+ return this.tex;
1122
+ }
1123
+ // Build an array of texFactors with the number of similar items.
1124
+ let factorsCount = {};
1125
+ for (let f of this.factors) {
1126
+ if (factorsCount[f.tex] !== undefined) {
1127
+ factorsCount[f.tex].degree++;
1128
+ }
1129
+ else {
1130
+ factorsCount[f.tex] = {
1131
+ degree: 1,
1132
+ factor: f
1133
+ };
1134
+ }
1135
+ }
1136
+ // First round to put the 'monom' first
1137
+ let simpleFactor = new Polynom().one();
1138
+ for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length === 1)) {
1139
+ simpleFactor.multiply(item.factor);
1140
+ }
1141
+ let tex = simpleFactor.isOne() ? '' : simpleFactor.tex;
1142
+ // Loop through all factors that contains at least 2 monoms.
1143
+ for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length > 1)) {
1144
+ if (item.factor.length > 1) {
1145
+ tex += `\\left( ${item.factor.tex} \\right)${item.degree > 1 ? '^{ ' + item.degree + ' }' : ''}`;
1146
+ }
1147
+ }
1148
+ return tex;
1149
+ }
1150
+ get displayFactors() {
1151
+ this.factorize();
1152
+ if (this.factors.length <= 1) {
1153
+ return this.display;
1154
+ }
1155
+ // Build an array of texFactors with the number of similar items.
1156
+ let factorsCount = {};
1157
+ for (let f of this.factors) {
1158
+ if (factorsCount[f.display] !== undefined) {
1159
+ factorsCount[f.display].degree++;
1160
+ }
1161
+ else {
1162
+ factorsCount[f.display] = {
1163
+ degree: 1,
1164
+ factor: f
1165
+ };
1166
+ }
1167
+ }
1168
+ // First round to put the 'monom' first
1169
+ let simpleFactor = new Polynom().one();
1170
+ for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length === 1)) {
1171
+ simpleFactor.multiply(item.factor);
1172
+ }
1173
+ let display = simpleFactor.isOne() ? '' : simpleFactor.display;
1174
+ // Loop through all factors that contains at least 2 monoms.
1175
+ for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length > 1)) {
1176
+ if (item.factor.length > 1) {
1177
+ display += `(${item.factor.display})${item.degree > 1 ? '^(' + item.degree + ')' : ''}`;
1178
+ }
1179
+ }
1180
+ return display;
1181
+ }
1182
+ get length() {
1183
+ // TODO: Must reduce the monoms list to remove the zero coefficient.
1184
+ return this._monoms.length;
1185
+ }
1186
+ get display() {
1187
+ return this.genDisplay();
1188
+ }
1189
+ get raw() {
1190
+ return this._rawString;
1191
+ }
1192
+ get tex() {
1193
+ return this.genDisplay('tex');
1194
+ }
1195
+ get isMultiVariable() {
1196
+ const B = false;
1197
+ for (const m of this._monoms) {
1198
+ if (m.variables.length > 1) {
1199
+ return true;
1200
+ }
1201
+ }
1202
+ return B;
1203
+ }
1204
+ get variables() {
1205
+ let V = [];
1206
+ for (const m of this._monoms) {
1207
+ V = V.concat(m.variables);
1208
+ }
1209
+ // Remove duplicates.
1210
+ V = [...new Set(V)];
1211
+ V.sort();
1212
+ return V;
1213
+ }
1214
+ get numberOfVars() {
1215
+ return this.variables.length;
1216
+ }
1217
+ get plotFunction() {
1218
+ return this.genDisplay('tex', false, false, true);
1219
+ }
1220
+ isZero() {
1221
+ return (this._monoms.length === 1 && this._monoms[0].coefficient.isZero()) || this._monoms.length === 0;
1222
+ }
1223
+ isOne() {
1224
+ return this._monoms.length === 1 && this._monoms[0].coefficient.isOne();
1225
+ }
1226
+ _parseString(inputStr, ...values) {
1227
+ if (values === undefined || values.length === 0) {
1228
+ inputStr = '' + inputStr;
1229
+ this._rawString = inputStr.trim().replaceAll(' ', '');
1230
+ // Parse the polynom using the shutting yard algorithm
1231
+ if (inputStr !== '' && !isNaN(Number(inputStr))) {
1232
+ this.empty();
1233
+ // It's a simple number.
1234
+ let m = new monom_1.Monom(inputStr);
1235
+ // m.coefficient = new Fraction(inputStr);
1236
+ // m.literalStr = '';
1237
+ this.add(m);
1238
+ return this;
1239
+ }
1240
+ // Parse the string.
1241
+ return this.shutingYardToReducedPolynom(inputStr);
1242
+ }
1243
+ else if (/^[a-z]/.test(inputStr)) {
1244
+ // We assume the inputStr contains only letters.
1245
+ this.empty();
1246
+ let fractions = values.map(x => new fraction_1.Fraction(x));
1247
+ // Multiple setLetter version
1248
+ if (inputStr.length > 1) {
1249
+ // TODO: check that the number of values given correspond to the letters (+1 eventually)
1250
+ let letters = inputStr.split(''), i = 0;
1251
+ for (let F of fractions) {
1252
+ let m = new monom_1.Monom();
1253
+ m.coefficient = F.clone();
1254
+ m.literalStr = letters[i] || '';
1255
+ this.add(m);
1256
+ i++;
1257
+ }
1258
+ }
1259
+ // Single setLetter version
1260
+ else {
1261
+ let n = fractions.length - 1;
1262
+ for (let F of fractions) {
1263
+ let m = new monom_1.Monom();
1264
+ m.coefficient = F.clone();
1265
+ m.literalStr = `${inputStr}^${n}`;
1266
+ this.add(m);
1267
+ n--;
1268
+ }
1269
+ }
1270
+ return this;
1271
+ }
1272
+ else {
1273
+ return this.zero();
1274
+ }
1275
+ }
1276
+ }
1277
+ exports.Polynom = Polynom;
1278
1278
  //# sourceMappingURL=polynom.js.map