pimath 0.0.60 → 0.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/pi.js CHANGED
@@ -1760,6 +1760,21 @@ class Monom {
1760
1760
  // All checks passed.
1761
1761
  return true;
1762
1762
  };
1763
+ this.isDivisible = (div) => {
1764
+ // For all variables (letters), the current monom must have a degree higher than the divider
1765
+ if (div.degree().isStrictlyPositive()) {
1766
+ for (let letter of div.variables) {
1767
+ if (!this.degree(letter).geq(div.degree(letter))) {
1768
+ return false;
1769
+ }
1770
+ }
1771
+ }
1772
+ // If the coefficient is rational, we suppose we don't need to check the division by the coefficient.
1773
+ if (this.coefficient.isRational() || div.coefficient.isRational()) {
1774
+ return true;
1775
+ }
1776
+ return this.coefficient.clone().divide(div.coefficient).isRelative();
1777
+ };
1763
1778
  this.zero();
1764
1779
  if (value !== undefined) {
1765
1780
  // A string is given - try to parse the value.
@@ -2135,6 +2150,11 @@ class Polynom {
2135
2150
  * @param values
2136
2151
  */
2137
2152
  constructor(polynomString, ...values) {
2153
+ this.mark_as_dirty = () => {
2154
+ this.dirty_factors = true;
2155
+ this.dirty_zeroes = true;
2156
+ this.euclidianCache = {};
2157
+ };
2138
2158
  this.addToken = (stack, element) => {
2139
2159
  switch (element.tokenType) {
2140
2160
  case shutingyard_1.ShutingyardType.COEFFICIENT:
@@ -2222,6 +2242,7 @@ class Polynom {
2222
2242
  // Reset the main variables.
2223
2243
  this._monoms = [];
2224
2244
  this._factors = [];
2245
+ this.mark_as_dirty();
2225
2246
  if (typeof inputStr === 'string') {
2226
2247
  return this._parseString(inputStr, ...values);
2227
2248
  }
@@ -2262,88 +2283,32 @@ class Polynom {
2262
2283
  this._monoms = [];
2263
2284
  this._monoms.push(new monom_1.Monom().zero());
2264
2285
  this._rawString = '0';
2286
+ this.mark_as_dirty();
2265
2287
  return this;
2266
2288
  };
2267
2289
  this.one = () => {
2268
2290
  this._monoms = [];
2269
2291
  this._monoms.push(new monom_1.Monom().one());
2270
2292
  this._rawString = '1';
2293
+ this.mark_as_dirty();
2271
2294
  return this;
2272
2295
  };
2273
2296
  this.empty = () => {
2274
2297
  this._monoms = [];
2275
2298
  this._rawString = '';
2299
+ this.mark_as_dirty();
2276
2300
  return this;
2277
2301
  };
2278
2302
  // ------------------------------------------
2279
2303
  this.opposed = () => {
2280
2304
  this._monoms = this._monoms.map(m => m.opposed());
2305
+ this.mark_as_dirty();
2281
2306
  return this;
2282
2307
  };
2283
- // // -----------------------------------------------
2284
- // // Polynom generators and randomizers
2285
- // // -----------------------------------------------
2286
- // random(config?: randomPolynomConfig) {
2287
- // return Random.polynom(config);
2288
- // }
2289
- //
2290
- // private _randomizeDefaults: { [key: string]: number | string | boolean } = {
2291
- // degree: 2,
2292
- // unit: true,
2293
- // fractions: false,
2294
- // factorable: false,
2295
- // letters: 'x',
2296
- // allowNullMonom: false,
2297
- // numberOfMonoms: false
2298
- // };
2299
- // get randomizeDefaults(): { [key: string]: number | string | boolean } {
2300
- // return this._randomizeDefaults;
2301
- // }
2302
- //
2303
- // set randomizeDefaults(value) {
2304
- // this._randomizeDefaults = value;
2305
- // }
2306
- //
2307
- // randomize = (config: { [key: string]: number | string | boolean }): Polynom => {
2308
- // let P = new Polynom();
2309
- //
2310
- // // Check the config file and use the default values.
2311
- // if (config === undefined) {
2312
- // config = {};
2313
- // }
2314
- // for (let k in this._randomizeDefaults) {
2315
- // if (config[k] === undefined) {
2316
- // config[k] = this._randomizeDefaults[k];
2317
- // }
2318
- // }
2319
- //
2320
- // // TODO: Build a more robust randomize function
2321
- // return P;
2322
- // }
2323
- //
2324
- // rndFactorable = (degree: number = 2, unit: boolean | number = false, letters: string = 'x'): Polynom => {
2325
- // // TODO: Make rndFactorable polynom generator more user friendly
2326
- // this._factors = [];
2327
- // for (let i = 0; i < degree; i++) {
2328
- // let factorUnit = unit === true || i >= unit,
2329
- // p = Random.polynom({
2330
- // degree: 1,
2331
- // unit: factorUnit,
2332
- // fraction: false,
2333
- // letters
2334
- // });
2335
- // this._factors.push(p);
2336
- // }
2337
- //
2338
- // this.empty().monoms = this._factors[0].monoms;
2339
- // for (let i = 1; i < this._factors.length; i++) {
2340
- // this.multiply(this._factors[i]);
2341
- // }
2342
- // return this;
2343
- // };
2344
2308
  // ------------------------------------------
2345
2309
  // Mathematical operations
2346
2310
  this.add = (...values) => {
2311
+ this.mark_as_dirty();
2347
2312
  for (let value of values) {
2348
2313
  if (value instanceof Polynom) {
2349
2314
  this._monoms = this._monoms.concat(value.monoms);
@@ -2361,6 +2326,7 @@ class Polynom {
2361
2326
  return this.reduce();
2362
2327
  };
2363
2328
  this.subtract = (...values) => {
2329
+ this.mark_as_dirty();
2364
2330
  for (let value of values) {
2365
2331
  if (value instanceof Polynom) {
2366
2332
  this._monoms = this._monoms.concat(value.clone().opposed().monoms);
@@ -2378,6 +2344,7 @@ class Polynom {
2378
2344
  return this.reduce();
2379
2345
  };
2380
2346
  this.multiply = (value) => {
2347
+ this.mark_as_dirty();
2381
2348
  if (value instanceof Polynom) {
2382
2349
  return this.multiplyByPolynom(value);
2383
2350
  }
@@ -2399,6 +2366,9 @@ class Polynom {
2399
2366
  * returns {quotient: Polynom, reminder: Polynom}
2400
2367
  */
2401
2368
  this.euclidian = (P) => {
2369
+ if (this.euclidianCache[P.tex] !== undefined) {
2370
+ return this.euclidianCache[P.tex];
2371
+ }
2402
2372
  const letter = P.variables[0];
2403
2373
  const quotient = new Polynom().zero();
2404
2374
  const reminder = this.clone().reorder(letter);
@@ -2432,6 +2402,7 @@ class Polynom {
2432
2402
  return { quotient, reminder };
2433
2403
  };
2434
2404
  this.divide = (value) => {
2405
+ this.mark_as_dirty();
2435
2406
  if (value instanceof fraction_1.Fraction) {
2436
2407
  return this.divideByFraction(value);
2437
2408
  }
@@ -2445,6 +2416,7 @@ class Polynom {
2445
2416
  }
2446
2417
  };
2447
2418
  this.pow = (nb) => {
2419
+ this.mark_as_dirty();
2448
2420
  if (!Number.isSafeInteger(nb)) {
2449
2421
  return this.zero();
2450
2422
  }
@@ -2645,6 +2617,7 @@ class Polynom {
2645
2617
  * @param P
2646
2618
  */
2647
2619
  this.replaceBy = (letter, P) => {
2620
+ this.mark_as_dirty();
2648
2621
  let pow;
2649
2622
  const resultPolynom = new Polynom().zero();
2650
2623
  for (const m of this.monoms) {
@@ -2704,146 +2677,108 @@ class Polynom {
2704
2677
  * @param maxValue Defines the greatest value to search to (default is 20).
2705
2678
  */
2706
2679
  this.factorize = (letter) => {
2707
- let factors = [];
2708
- // Extract the common monom
2709
- let P = this.clone().reorder(), M = P.commonMonom(), tempPolynom;
2710
- // It has a common monom.
2711
- if (!M.isOne()) {
2712
- tempPolynom = new Polynom(M);
2713
- factors = [tempPolynom.clone()];
2714
- P = P.euclidian(tempPolynom).quotient;
2715
- }
2716
- let securityLoop = P.degree().clone().multiply(2).value;
2717
- let result;
2718
- // securityLoop = 0
2719
- while (securityLoop >= 0) {
2720
- securityLoop--;
2721
- if (P.monoms.length < 2) {
2722
- if (!P.isOne()) {
2680
+ if (this.dirty_factors) {
2681
+ let factors = [];
2682
+ let P = this.clone().reorder();
2683
+ // Extract the common monom
2684
+ // 2x^3+6x^2 => 2x^2
2685
+ let M = P.commonMonom();
2686
+ if (!M.isOne()) {
2687
+ let tempPolynom = new Polynom(M);
2688
+ factors = [tempPolynom.clone()];
2689
+ P = P.euclidian(tempPolynom).quotient;
2690
+ }
2691
+ // Main loop
2692
+ let securityLoop = P.degree().clone().multiply(2).value, maxDegree = 1;
2693
+ while (securityLoop >= 0) {
2694
+ securityLoop--;
2695
+ if (P.monoms.length < 2) {
2696
+ // The polynom has only one monom => 7x^2
2697
+ // No need to continue.
2698
+ if (!P.isOne()) {
2699
+ factors.push(P.clone());
2700
+ P.one();
2701
+ }
2702
+ break;
2703
+ }
2704
+ else if (P.degree(letter).isOne()) {
2705
+ // The polynom is a first degree polynom => 3x-5
2706
+ // No need to continue
2723
2707
  factors.push(P.clone());
2724
2708
  P.one();
2709
+ break;
2710
+ }
2711
+ else {
2712
+ // Create the list of all "potential" polynom dividers.
2713
+ let allDividers = this._getAllPotentialFactors(P, maxDegree, letter);
2714
+ maxDegree = P.degree(letter).value;
2715
+ // Actually: 100ms
2716
+ while (allDividers.length > 0) {
2717
+ let div = allDividers[0];
2718
+ if (!P.isDividableBy(div)) {
2719
+ // Not dividable. Remove it from the list
2720
+ allDividers.shift();
2721
+ }
2722
+ else {
2723
+ // Add the factor
2724
+ factors.push(div);
2725
+ // It's dividable - so make the division
2726
+ let result = P.euclidian(div);
2727
+ // As it's dividable, get the quotient.
2728
+ P = result.quotient.clone();
2729
+ // filter all dividers that are no more suitable.
2730
+ allDividers = allDividers.filter(x => {
2731
+ let pX = P.monoms[0], pC = P.monoms[P.monoms.length - 1], dX = x.monoms[0], dC = x.monoms[x.monoms.length - 1];
2732
+ // Check last item (degree zero)
2733
+ if (!pC.isDivisible(dC)) {
2734
+ return false;
2735
+ }
2736
+ // Check the first item (degree max)
2737
+ if (!pX.isDivisible(dX)) {
2738
+ return false;
2739
+ }
2740
+ return true;
2741
+ });
2742
+ }
2743
+ }
2725
2744
  }
2726
- break;
2727
2745
  }
2728
- else if (P.degree(letter).isOne()) {
2746
+ // Maybe there is still something in the Polynom (not everything was possible to factorize)
2747
+ if (!P.isOne()) {
2729
2748
  factors.push(P.clone());
2730
- P.one();
2731
- break;
2749
+ }
2750
+ // Save the factors
2751
+ this.factors = factors;
2752
+ // The factors list is no more dirty
2753
+ this.dirty_factors = false;
2754
+ }
2755
+ return this.factors;
2756
+ };
2757
+ this.isDividableBy = (div) => {
2758
+ // Quick evaluation.
2759
+ if (div.degree().isOne()) {
2760
+ let zero = div.getZeroes()[0];
2761
+ if (zero.exact instanceof fraction_1.Fraction) {
2762
+ return this.evaluate(zero.exact).isZero();
2732
2763
  }
2733
2764
  else {
2734
- // Get the first and last monom and build all their dividers.
2735
- // let m1 = P.monoms[0].dividers,
2736
- // m2 = P.monoms[P.monoms.length - 1].dividers
2737
- // Create the list of all "potential" polynom dividers.
2738
- let allDividers = this._getAllPotentialFactors(P, letter);
2739
- allDividers.every(div => {
2740
- result = P.euclidian(div);
2741
- if (result.reminder.isZero()) {
2742
- P = result.quotient.clone();
2743
- factors.push(div);
2744
- return false;
2745
- }
2746
- return true;
2747
- });
2765
+ return false;
2748
2766
  }
2749
2767
  }
2750
- if (!P.isOne()) {
2751
- factors.push(P.clone());
2768
+ else {
2769
+ this.euclidianCache[div.tex] = this.euclidian(div);
2770
+ return this.euclidianCache[div.tex].reminder.isZero();
2752
2771
  }
2753
- this.factors = factors;
2754
- return factors;
2755
2772
  };
2756
2773
  // TODO: get zeroes for more than first degree and for more than natural degrees
2757
2774
  this.getZeroes = () => {
2758
- let equ = new equation_1.Equation(this.clone(), 0);
2759
- equ.solve();
2760
- return equ.solutions;
2761
- //
2762
- // const Z: Fraction[] = [];
2763
- //
2764
- // // ISolution: {tex: string, value: number, exact: boolean|Fraction|...}
2765
- //
2766
- // switch (this.degree().value) {
2767
- // case 0:
2768
- // if (this._monoms[0].coefficient.value === 0) {
2769
- // return [{
2770
- // tex: '\\mathbb{R}',
2771
- // value: NaN,
2772
- // exact: false
2773
- // }];
2774
- // } else {
2775
- // return [{
2776
- // tex: '\\varnothing',
2777
- // value: NaN,
2778
- // exact: false
2779
- // }];
2780
- // }
2781
- // case 1:
2782
- // // There is only one monoms,
2783
- // if (this._monoms.length === 1) {
2784
- // return [{
2785
- // tex: '0',
2786
- // value: 0,
2787
- // exact: new Fraction().zero()
2788
- // }];
2789
- // } else {
2790
- // const P = this.clone().reduce().reorder();
2791
- // const coeff = P.monoms[1].coefficient.opposed().divide(P.monoms[0].coefficient)
2792
- // return [{
2793
- // tex: coeff.tex,
2794
- // value: coeff.value,
2795
- // exact: coeff
2796
- // }];
2797
- // }
2798
- // // TODO: Determine the zeros of an equation of second degree.
2799
- // //case 2:
2800
- // default:
2801
- // // Make sure the polynom is factorized.
2802
- // if (this._factors.length === 0) {
2803
- // this.factorize()
2804
- // }
2805
- //
2806
- // let zeroes:Fraction[] = [], zeroesAsTex = [];
2807
- // for (let P of this._factors) {
2808
- // if (P.degree().greater(2)) {
2809
- // // TODO: get zeroes of polynom with a degree greater than 2.
2810
- //
2811
- // } else if (P.degree().value === 2) {
2812
- // let A = P.monomByDegree(2).coefficient,
2813
- // B = P.monomByDegree(1).coefficient,
2814
- // C = P.monomByDegree(0).coefficient,
2815
- // D = B.clone().pow(2).subtract(A.clone().multiply(C).multiply(4));
2816
- //
2817
- // if (D.value > 0) {
2818
- // /*console.log('Two zeroes for ', P.tex); */
2819
- // let x1 = (-(B.value) + Math.sqrt(D.value)) / (2 * A.value),
2820
- // x2 = (-(B.value) - Math.sqrt(D.value)) / (2 * A.value);
2821
- //
2822
- // zeroes.push(new Fraction(x1.toFixed(3)).reduce());
2823
- // zeroes.push(new Fraction(x2.toFixed(3)).reduce());
2824
- // } else if (D.value === 0) {
2825
- // /*console.log('One zero for ', P.tex); */
2826
- // } else {
2827
- // console.log('No zero for ', P.tex);
2828
- // }
2829
- // } else {
2830
- // for (let z of P.getZeroes()) {
2831
- // // Check if the zero is already in the list.
2832
- // // if (z === false || z === true) {
2833
- // // continue;
2834
- // // }
2835
- // if (zeroesAsTex.indexOf(z.frac) === -1) {
2836
- // zeroes.push(z);
2837
- // zeroesAsTex.push(z.frac);
2838
- // }
2839
- // }
2840
- // }
2841
- // }
2842
- //
2843
- //
2844
- // return zeroes;
2845
- // }
2846
- // return Z;
2775
+ if (this.dirty_zeroes) {
2776
+ let equ = new equation_1.Equation(this.clone(), 0);
2777
+ equ.solve();
2778
+ this._zeroes = equ.solutions;
2779
+ this.dirty_zeroes = false;
2780
+ }
2781
+ return this._zeroes;
2847
2782
  };
2848
2783
  // TODO: analyse the next functions to determine if they are useful or not...
2849
2784
  this.monomByDegree = (degree, letter) => {
@@ -2958,16 +2893,19 @@ class Polynom {
2958
2893
  // Any other cases
2959
2894
  return (new fraction_1.Fraction()).zero();
2960
2895
  };
2961
- this._getAllPotentialFactors = (P, letter) => {
2896
+ this._getAllPotentialFactors = (P, maxDegree, letter) => {
2962
2897
  let m1 = P.monoms[0].dividers, m2 = P.monoms[P.monoms.length - 1].dividers;
2963
2898
  let allDividers = [];
2964
2899
  m1.forEach(m1d => {
2965
- m2.forEach(m2d => {
2966
- if (m1d.degree(letter).isNotEqual(m2d.degree(letter))) {
2967
- allDividers.push(new Polynom(m1d, m2d));
2968
- allDividers.push(new Polynom(m1d, m2d.clone().opposed()));
2969
- }
2970
- });
2900
+ // Get only polynom that has a degree less than a specific value
2901
+ if (m1d.degree(letter).leq(maxDegree)) {
2902
+ m2.forEach(m2d => {
2903
+ if (m1d.degree(letter).isNotEqual(m2d.degree(letter))) {
2904
+ allDividers.push(new Polynom(m1d, m2d));
2905
+ allDividers.push(new Polynom(m1d, m2d.clone().opposed()));
2906
+ }
2907
+ });
2908
+ }
2971
2909
  });
2972
2910
  return allDividers;
2973
2911
  };
@@ -3019,41 +2957,6 @@ class Polynom {
3019
2957
  this.add(stack[0]);
3020
2958
  }
3021
2959
  return this;
3022
- /**
3023
- let m1: Polynom;
3024
- let m2: Polynom;
3025
-
3026
- let stack: Polynom[] = [],
3027
- previousToken: string = null,
3028
- tempPolynom
3029
-
3030
- for (const element of rpn) {
3031
- if (element.tokenType === 'coefficient' || element.tokenType === 'variable') {
3032
- tempPolynom = new Polynom().zero();
3033
- tempPolynom.monoms = [new Monom(element.token)]
3034
- stack.push(tempPolynom.clone())
3035
- } else if (element.tokenType === 'operation') {
3036
- m2 = (stack.pop()) || new Polynom().zero();
3037
- m1 = (stack.pop()) || new Polynom().zero();
3038
- switch (element.token) {
3039
- case '+':
3040
- stack.push(m1.add(m2))
3041
- break;
3042
- case '-':
3043
- stack.push(m1.subtract(m2))
3044
- break;
3045
- case '*':
3046
- stack.push(m1.multiply(m2))
3047
- break;
3048
- case '^':
3049
- stack.push(m1.pow(+previousToken))
3050
- }
3051
- }
3052
- previousToken = element.token;
3053
- }
3054
-
3055
- this._monoms = stack[0].monoms;
3056
- return this;*/
3057
2960
  };
3058
2961
  this.multiplyByPolynom = (P) => {
3059
2962
  const M = [];
@@ -3178,33 +3081,6 @@ class Polynom {
3178
3081
  }
3179
3082
  }
3180
3083
  return [this.clone()];
3181
- //
3182
- // console.log(a.tex, b.tex, c.tex)
3183
- // if (a.isSquare() && c.isSquare()) {
3184
- // console.log('A C squares')
3185
- // if (a.clone().sqrt().multiply(c.clone().sqrt()).multiplyByNumber(2).isSameAs(b)) {
3186
- // console.log('HERE')
3187
- // if (a.coefficient.sign() === b.coefficient.sign()) {
3188
- // return []
3189
- // }else{
3190
- // return []
3191
- // }
3192
- // }
3193
- // } else if(a.isLiteralSquare() && c.isLiteralSquare()) {
3194
- // console.log('A C litteral SQUARES')
3195
- // // Check that the middle element is the product of a and c.
3196
- //
3197
- // if(b.clone().pow(2).isSameAs(a.clone().multiply(c))){
3198
- // console.log('SAME')
3199
- //
3200
- // }else{
3201
- // console.log('NOT SAME')
3202
- // }
3203
- //
3204
- // return [this.clone()]
3205
- // } else {
3206
- // console.log('NOT SQUARES AT ALL !!!!')
3207
- // }
3208
3084
  }
3209
3085
  };
3210
3086
  this._factorizeByGroups = () => {
@@ -3213,11 +3089,31 @@ class Polynom {
3213
3089
  };
3214
3090
  this._monoms = [];
3215
3091
  this._factors = [];
3092
+ this.mark_as_dirty();
3216
3093
  if (polynomString !== undefined) {
3217
3094
  this.parse(polynomString, ...values);
3218
3095
  }
3219
3096
  return this;
3220
3097
  }
3098
+ get euclidianCache() {
3099
+ return this._euclidianCache;
3100
+ }
3101
+ set euclidianCache(value) {
3102
+ this._euclidianCache = value;
3103
+ }
3104
+ get dirty_zeroes() {
3105
+ return this._dirty_zeroes;
3106
+ }
3107
+ set dirty_zeroes(value) {
3108
+ this._dirty_zeroes = value;
3109
+ }
3110
+ // ------------------------------------------
3111
+ get dirty_factors() {
3112
+ return this._dirty_factors;
3113
+ }
3114
+ set dirty_factors(value) {
3115
+ this._dirty_factors = value;
3116
+ }
3221
3117
  // ------------------------------------------
3222
3118
  get monoms() {
3223
3119
  return this._monoms;
@@ -3225,10 +3121,14 @@ class Polynom {
3225
3121
  set monoms(M) {
3226
3122
  this._monoms = M;
3227
3123
  }
3124
+ get zeroes() {
3125
+ return this.getZeroes();
3126
+ }
3228
3127
  get factors() {
3229
3128
  return this._factors;
3230
3129
  }
3231
3130
  set factors(value) {
3131
+ this.mark_as_dirty();
3232
3132
  this._factors = value;
3233
3133
  }
3234
3134
  get texString() {