pimath 0.0.125 → 0.0.127

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 (84) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +5 -5
  2. package/.idea/shelf/Uncommitted_changes_before_Checkout_at_07_11_2023_08_30_[Default_Changelist]/shelved.patch +192 -192
  3. package/.idea/shelf/Uncommitted_changes_before_Checkout_at_09_11_2023_10_43_[Default_Changelist]/shelved.patch +2404 -2404
  4. package/.idea/shelf/Uncommitted_changes_before_Checkout_at_09_11_2023_11_01_[Default_Changelist]/shelved.patch +1362 -1362
  5. package/dev/pimath.js +7945 -0
  6. package/dev/pimath.js.map +1 -0
  7. package/dist/pimath.js +192 -221
  8. package/dist/pimath.js.map +1 -1
  9. package/dist/pimath.min.js +1 -1
  10. package/dist/pimath.min.js.map +1 -1
  11. package/docs/.nojekyll +1 -0
  12. package/docs/assets/highlight.css +78 -0
  13. package/docs/assets/main.js +59 -0
  14. package/docs/assets/navigation.js +1 -0
  15. package/docs/assets/search.js +1 -0
  16. package/docs/assets/style.css +1383 -0
  17. package/docs/classes/Logicalset.Logicalset.html +217 -0
  18. package/docs/classes/Polynom.Rational.html +397 -0
  19. package/docs/classes/Vector-1.Vector.html +490 -0
  20. package/docs/classes/Vector.Point.html +337 -0
  21. package/docs/classes/algebra_equation.Equation.html +790 -0
  22. package/docs/classes/algebra_linearSystem.LinearSystem.html +404 -0
  23. package/docs/classes/algebra_monom.Monom.html +962 -0
  24. package/docs/classes/algebra_polynom.Polynom.html +1275 -0
  25. package/docs/classes/coefficients_fraction.Fraction.html +934 -0
  26. package/docs/classes/geometry_circle.Circle.html +472 -0
  27. package/docs/classes/geometry_line.Line.html +774 -0
  28. package/docs/classes/geometry_triangle.Triangle.html +429 -0
  29. package/docs/classes/numeric.Numeric.html +265 -0
  30. package/docs/classes/shutingyard.Shutingyard.html +250 -0
  31. package/docs/enums/algebra_equation.PARTICULAR_SOLUTION.html +83 -0
  32. package/docs/enums/geometry_line.LinePropriety.html +97 -0
  33. package/docs/enums/shutingyard.ShutingyardMode.html +97 -0
  34. package/docs/enums/shutingyard.ShutingyardType.html +111 -0
  35. package/docs/index.html +63 -0
  36. package/docs/interfaces/algebra_equation.ISolution.html +105 -0
  37. package/docs/interfaces/algebra_polynom.IEuclidian.html +87 -0
  38. package/docs/interfaces/geometry_triangle.remarquableLines.html +163 -0
  39. package/docs/modules/Logicalset.html +65 -0
  40. package/docs/modules/Polynom.html +65 -0
  41. package/docs/modules/Vector-1.html +65 -0
  42. package/docs/modules/Vector.html +65 -0
  43. package/docs/modules/algebra_equation.html +69 -0
  44. package/docs/modules/algebra_linearSystem.html +61 -0
  45. package/docs/modules/algebra_monom.html +65 -0
  46. package/docs/modules/algebra_polynom.html +69 -0
  47. package/docs/modules/coefficients_fraction.html +65 -0
  48. package/docs/modules/geometry_circle.html +61 -0
  49. package/docs/modules/geometry_line.html +65 -0
  50. package/docs/modules/geometry_triangle.html +65 -0
  51. package/docs/modules/numeric.html +61 -0
  52. package/docs/modules/shutingyard.html +75 -0
  53. package/docs/types/algebra_monom.literalType.html +61 -0
  54. package/docs/types/algebra_polynom.PolynomParsingType.html +56 -0
  55. package/docs/types/coefficients_fraction.FractionParsingType.html +56 -0
  56. package/docs/types/shutingyard.Token.html +63 -0
  57. package/docs/types/shutingyard.tokenType.html +68 -0
  58. package/docs/variables/shutingyard.tokenConstant.html +61 -0
  59. package/esm/index.js +1 -1
  60. package/esm/index.js.map +1 -1
  61. package/esm/maths/algebra/monom.d.ts +19 -19
  62. package/esm/maths/algebra/monom.js +66 -66
  63. package/esm/maths/algebra/monom.js.map +1 -1
  64. package/esm/maths/algebra/polynom.d.ts +14 -14
  65. package/esm/maths/algebra/polynom.js +72 -50
  66. package/esm/maths/algebra/polynom.js.map +1 -1
  67. package/esm/maths/numeric.js +3 -48
  68. package/esm/maths/numeric.js.map +1 -1
  69. package/package.json +1 -1
  70. package/src/index.ts +1 -1
  71. package/src/maths/algebra/monom.ts +138 -130
  72. package/src/maths/algebra/polynom.ts +97 -82
  73. package/src/maths/geometry/line.ts +22 -25
  74. package/src/maths/geometry/point.ts +43 -29
  75. package/src/maths/numeric.ts +61 -90
  76. package/src/maths/randomization/random.ts +7 -0
  77. package/src/maths/randomization/rndGeometryCircle.ts +50 -0
  78. package/src/maths/randomization/rndTypes.ts +10 -4
  79. package/tests/algebra/linear.test.ts +1 -1
  80. package/tests/algebra/polynom.test.ts +162 -1
  81. package/tests/algebra/study.test.ts +1 -0
  82. package/tests/geometry/circle.test.ts +320 -115
  83. package/tests/geometry/line.test.ts +8 -17
  84. package/tests/numeric.test.ts +19 -3
@@ -1,2404 +1,2404 @@
1
- Index: tests/algebra/monom.test.ts
2
- IDEA additional info:
3
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
4
- <+>import {expect} from 'chai';\r\nimport {Random} from \"../../src/maths/randomization/random\";\r\nimport {describe} from \"mocha\";\r\nimport {Monom, MonomE} from \"../../src/maths/algebra/monom\";\r\n\r\ndescribe('Monom with integer power', () => {\r\n it('parsing', () => {\r\n const M0a = new Monom('3');\r\n expect(M0a.tex).to.be.equal('3')\r\n\r\n const M0b = new Monom('x');\r\n expect(M0b.tex).to.be.equal('x')\r\n\r\n const M0c = new Monom('3x');\r\n expect(M0c.tex).to.be.equal('3x')\r\n\r\n const M1 = new Monom('3x^5');\r\n expect(M1.tex).to.be.equal('3x^{5}')\r\n\r\n const M2 = new Monom('2/3x^2yz^3y^4')\r\n expect(M2.display).to.be.equal('2/3x^(2)y^(5)z^(3)')\r\n\r\n const M3 = new Monom('-3x^(-2)')\r\n expect(M3.tex).to.be.equal('-3x^{-2}')\r\n\r\n const M4 = new Monom('3x^(2/3)')\r\n expect(M4.tex).to.be.equal('3x^{\\\\tfrac{ 2 }{ 3 }}')\r\n\r\n const M5 = new Monom('-3x^(-2/3)y^(-5)8x^3')\r\n expect(M5.tex).to.be.equal('-24x^{\\\\tfrac{ 7 }{ 3 }}y^{-5}')\r\n })\r\n\r\n it('basic operations', () => {\r\n const M1 = new Monom('3x'),\r\n M2 = new Monom('2x')\r\n\r\n expect(M1.clone().add(M2).isEqual(new Monom('5x'))).to.be.true\r\n expect(M1.clone().subtract(M2).isEqual(new Monom('x'))).to.be.true\r\n expect(M1.clone().multiply(M2).isEqual(new Monom('6x^2'))).to.be.true\r\n expect(M1.clone().divide(M2).isEqual(new Monom('3/2'))).to.be.true\r\n })\r\n\r\n it('derivative', () => { // the single test\r\n const options = new Monom('7x^3'); // this will be your class\r\n\r\n expect(options.tex).to.be.equal('7x^{3}')\r\n expect(options.derivative().tex).to.be.equal('21x^{2}');\r\n });\r\n\r\n it('integrate', () => { // the single test\r\n const options = new Monom('7x^3'); // this will be your class\r\n expect(options.primitive().display).to.be.equal('7/4x^(4)');\r\n });\r\n\r\n it('randomize', function () {\r\n const M = Random.monom({\r\n letters: 'xyz',\r\n degree: 5,\r\n fraction: false,\r\n zero: false\r\n });\r\n\r\n expect(M.coefficient.isZero()).to.be.false\r\n expect(M.degree().value).to.be.greaterThan(0)\r\n });\r\n})\r\n\r\ndescribe('Monom with fraction power', () => {\r\n it('should create a numerical expression', () => {\r\n const inputStr: string = '-1/5x^(2/3)'\r\n const M = new Monom(inputStr),\r\n N = new Monom('7x^(4/5)')\r\n\r\n M.multiply(N.clone())\r\n\r\n expect(M.tex).to.be.equal('-\\\\frac{ 7 }{ 5 }x^{\\\\tfrac{ 22 }{ 15 }}')\r\n })\r\n\r\n it('should show a monom with sqrt', function () {\r\n let m = new MonomE('3x^(1/2)')\r\n m.letters('x', '\\\\sqrt{2}')\r\n\r\n console.log(m.tex)\r\n });\r\n})
5
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
6
- <+>UTF-8
7
- ===================================================================
8
- diff --git a/tests/algebra/monom.test.ts b/tests/algebra/monom.test.ts
9
- --- a/tests/algebra/monom.test.ts
10
- +++ b/tests/algebra/monom.test.ts
11
- @@ -1,85 +1,9 @@
12
- -import {expect} from 'chai';
13
- -import {Random} from "../../src/maths/randomization/random";
14
- import {describe} from "mocha";
15
- -import {Monom, MonomE} from "../../src/maths/algebra/monom";
16
- -
17
- -describe('Monom with integer power', () => {
18
- - it('parsing', () => {
19
- - const M0a = new Monom('3');
20
- - expect(M0a.tex).to.be.equal('3')
21
- -
22
- - const M0b = new Monom('x');
23
- - expect(M0b.tex).to.be.equal('x')
24
- -
25
- - const M0c = new Monom('3x');
26
- - expect(M0c.tex).to.be.equal('3x')
27
- -
28
- - const M1 = new Monom('3x^5');
29
- - expect(M1.tex).to.be.equal('3x^{5}')
30
- +import {Monom} from "../../src/maths/algebra/monom";
31
-
32
- - const M2 = new Monom('2/3x^2yz^3y^4')
33
- - expect(M2.display).to.be.equal('2/3x^(2)y^(5)z^(3)')
34
- -
35
- - const M3 = new Monom('-3x^(-2)')
36
- - expect(M3.tex).to.be.equal('-3x^{-2}')
37
- -
38
- - const M4 = new Monom('3x^(2/3)')
39
- - expect(M4.tex).to.be.equal('3x^{\\tfrac{ 2 }{ 3 }}')
40
- -
41
- - const M5 = new Monom('-3x^(-2/3)y^(-5)8x^3')
42
- - expect(M5.tex).to.be.equal('-24x^{\\tfrac{ 7 }{ 3 }}y^{-5}')
43
- +describe('Monom tests', () => {
44
- + it('Monom can be parsed from a string', () => {
45
- + let m = new Monom()
46
- })
47
-
48
- - it('basic operations', () => {
49
- - const M1 = new Monom('3x'),
50
- - M2 = new Monom('2x')
51
- -
52
- - expect(M1.clone().add(M2).isEqual(new Monom('5x'))).to.be.true
53
- - expect(M1.clone().subtract(M2).isEqual(new Monom('x'))).to.be.true
54
- - expect(M1.clone().multiply(M2).isEqual(new Monom('6x^2'))).to.be.true
55
- - expect(M1.clone().divide(M2).isEqual(new Monom('3/2'))).to.be.true
56
- - })
57
- -
58
- - it('derivative', () => { // the single test
59
- - const options = new Monom('7x^3'); // this will be your class
60
- -
61
- - expect(options.tex).to.be.equal('7x^{3}')
62
- - expect(options.derivative().tex).to.be.equal('21x^{2}');
63
- - });
64
- -
65
- - it('integrate', () => { // the single test
66
- - const options = new Monom('7x^3'); // this will be your class
67
- - expect(options.primitive().display).to.be.equal('7/4x^(4)');
68
- - });
69
- -
70
- - it('randomize', function () {
71
- - const M = Random.monom({
72
- - letters: 'xyz',
73
- - degree: 5,
74
- - fraction: false,
75
- - zero: false
76
- - });
77
- -
78
- - expect(M.coefficient.isZero()).to.be.false
79
- - expect(M.degree().value).to.be.greaterThan(0)
80
- - });
81
- -})
82
- -
83
- -describe('Monom with fraction power', () => {
84
- - it('should create a numerical expression', () => {
85
- - const inputStr: string = '-1/5x^(2/3)'
86
- - const M = new Monom(inputStr),
87
- - N = new Monom('7x^(4/5)')
88
- -
89
- - M.multiply(N.clone())
90
- -
91
- - expect(M.tex).to.be.equal('-\\frac{ 7 }{ 5 }x^{\\tfrac{ 22 }{ 15 }}')
92
- - })
93
- -
94
- - it('should show a monom with sqrt', function () {
95
- - let m = new MonomE('3x^(1/2)')
96
- - m.letters('x', '\\sqrt{2}')
97
- -
98
- - console.log(m.tex)
99
- - });
100
- })
101
-
102
- Index: src/maths/coefficients/fraction.ts
103
- IDEA additional info:
104
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
105
- <+>import {CoefficientCore, FRACTION_FRAC} from \"./coefficientCore\";\r\n\r\n/**\r\n * The fraction class\r\n */\r\n\r\nexport class Fraction extends CoefficientCore<Fraction> {\r\n constructor(value?: number | string | Fraction, denominator?: number | string) {\r\n super()\r\n // Default values.\r\n this.numerator = 1;\r\n this.denominator = 1;\r\n\r\n this.fracType = FRACTION_FRAC.frac\r\n\r\n if (value !== undefined) {\r\n if (value instanceof Fraction) return this.parse(value)\r\n return this.parse(value, denominator)\r\n }\r\n\r\n return this;\r\n }\r\n\r\n get tex(): string {\r\n const frac = this.fracTeX\r\n // restore the frac type to default\r\n this.fracType = FRACTION_FRAC.frac\r\n\r\n if (this.isInfinity()) {\r\n return `${this.signTeX}\\\\infty`\r\n }\r\n\r\n if (this.isExact()) {\r\n if (this.denominator === 1) {\r\n return `${this.numerator}`;\r\n } else if (this.numerator < 0) {\r\n return `-${frac}{ ${-this.numerator} }{ ${this.denominator} }`;\r\n } else {\r\n return `${frac}{ ${this.numerator} }{ ${this.denominator} }`;\r\n }\r\n } else {\r\n return this.value.toFixed(3)\r\n }\r\n }\r\n\r\n get display(): string {\r\n if (this.isInfinity()) {\r\n return `${this.signTeX}\\\\infty`\r\n }\r\n\r\n if (this.isExact()) {\r\n if (this.denominator === 1) {\r\n return `${this.numerator}`;\r\n } else if (this.numerator < 0) {\r\n return `-${-this.numerator}/${this.denominator}`;\r\n } else {\r\n return `${this.numerator}/${this.denominator}`;\r\n }\r\n } else {\r\n return this.value.toFixed(3)\r\n }\r\n }\r\n\r\n createInstance(value?: string | number | Fraction): Fraction {\r\n return new Fraction(value)\r\n }\r\n\r\n clone = (): Fraction => {\r\n return new Fraction(this.numerator, this.denominator)\r\n };\r\n\r\n reduce = (): Fraction => {\r\n const {N, D} = this.getReducedCoefficient()\r\n this.numerator = N\r\n this.denominator = D\r\n return this;\r\n };\r\n\r\n add = (...values: (Fraction | number | string)[]): Fraction => {\r\n for (let F of values) {\r\n if (!(F instanceof Fraction)) F = new Fraction(F)\r\n\r\n let N: number = this.numerator,\r\n D: number = this.denominator;\r\n\r\n this.numerator = N * F.denominator + F.numerator * D;\r\n this.denominator = D * F.denominator;\r\n }\r\n\r\n return this.reduce();\r\n };\r\n\r\n multiply = (...values: (Fraction | number)[]): Fraction => {\r\n // Parse the value.\r\n // If it's a fraction, return a clone of it\r\n // If it's an integer, return the fraction F/1\r\n for (let F of values) {\r\n if (!(F instanceof Fraction)) {\r\n F = new Fraction(F)\r\n }\r\n\r\n this.numerator = this.numerator * F.numerator;\r\n this.denominator = this.denominator * F.denominator;\r\n }\r\n\r\n return this\r\n };\r\n\r\n invert = (): Fraction => {\r\n let n = +this.numerator, d = +this.denominator;\r\n this.numerator = d;\r\n this.denominator = n;\r\n\r\n return this;\r\n }\r\n\r\n root = (p: number): Fraction => {\r\n // TODO: index - root of a fraction => this will return another type of coefficient.\r\n\r\n // Check if they are perfect roots..\r\n if (p === 0) {\r\n return this;\r\n }\r\n\r\n // If negative, invert the fraction\r\n if (p < 0) {\r\n this.invert()\r\n }\r\n\r\n let n = Math.pow(this.numerator, Math.abs(1 / p)),\r\n d = Math.pow(this.denominator, Math.abs(1 / p));\r\n\r\n this.numerator = Math.pow(this.numerator, Math.abs(1 / p));\r\n this.denominator = Math.pow(this.denominator, Math.abs(1 / p));\r\n return this;\r\n }\r\n\r\n static decimalToFraction = (value: string | number | Fraction): [number, number] => {\r\n // Return the neutral element\r\n if (value === undefined) return [1, 1]\r\n\r\n // Return the numerator and denominator if it's already a fraction\r\n if (value instanceof Fraction) return [value.numerator, value.denominator]\r\n\r\n // Split the value into unit and decimal part\r\n let [unit, decimal] = (+value).toString().split('.')\r\n\r\n // Return the unit if there is no decimal part\r\n if (decimal === undefined) return [+unit, 1]\r\n\r\n let decimalLength = decimal.length\r\n\r\n return [+(unit + decimal), 10 ** decimalLength]\r\n }\r\n\r\n static average = (...fractions: (Fraction | number)[]): Fraction => {\r\n let M = new Fraction().zero()\r\n\r\n for (let f of fractions) {\r\n M.add(f)\r\n }\r\n\r\n M.divide(fractions.length)\r\n\r\n return M\r\n }\r\n\r\n /**\r\n * Parse the value to get the numerator and denominator\r\n * @param value : number or string to parse to get the fraction\r\n * @param denominatorOrPeriodic (optional|number) : length of the periodic part: 2.333333 => 1 or denominator value\r\n */\r\n parse(value: Fraction): Fraction\r\n\r\n parse(value: string | number): Fraction\r\n\r\n\r\n // pow = (p: number | Fraction): Fraction => {\r\n // // TODO: Fraction.pow with a value different than a safe integer !\r\n // if (p instanceof Fraction) {\r\n // return this.pow(p.value)\r\n // }\r\n //\r\n // this.reduce();\r\n // if (p < 0) {\r\n // this.invert()\r\n // }\r\n //\r\n // // Check if numerator and denominator are roots of...\r\n // // othervise, convert to numeric.\r\n // let controlNumerator = Math.floor(Math.pow(this.numerator, Math.abs(p))),\r\n // controlDenominator = Math.floor(Math.pow(this.denominator, Math.abs(p)))\r\n //\r\n // if (controlNumerator ** Math.abs(p) === this.numerator\r\n // &&\r\n // controlDenominator ** Math.abs(p) === this.denominator) {\r\n //\r\n // this.numerator = this.numerator ** Math.abs(p);\r\n // this.denominator = this.denominator ** Math.abs(p);\r\n // } else {\r\n // this.numerator = this.numerator ** Math.abs(p);\r\n // this.denominator = this.denominator ** Math.abs(p);\r\n // }\r\n //\r\n // return this;\r\n // };\r\n\r\n parse(value: string | number, denominator: string | number): Fraction\r\n\r\n parse(value: string | number | Fraction, denominator ?: string | number): Fraction {\r\n // Default values\r\n this.numerator = 0;\r\n this.denominator = 1;\r\n\r\n // A null value means a zero fraction.\r\n if (value === null || value === \"\") return this;\r\n\r\n // No denominator given\r\n if (denominator === undefined) {\r\n if (value instanceof Fraction) return value.clone()\r\n\r\n if (typeof value === \"number\") {\r\n return new Fraction(value, 1)\r\n }\r\n\r\n // a value of type string can be:\r\n // - an integer number 4\r\n // - a decimal number 4.12\r\n // - a fraction 4/5\r\n // - a decimal fraction 4.12/5.12\r\n if (typeof value === \"string\") {\r\n const [N, D] = value.split('/')\r\n return new Fraction(N, D === undefined ? 1 : D)\r\n }\r\n }\r\n\r\n // Denominator given\r\n if (+denominator === 0) {\r\n this.numerator = Infinity\r\n return this\r\n }\r\n\r\n const [N1, D1] = Fraction.decimalToFraction(value)\r\n const [N2, D2] = Fraction.decimalToFraction(denominator)\r\n\r\n this.numerator = N1 * D2\r\n this.denominator = D1 * N2\r\n\r\n if (D1 > 1 || D2 > 1) this.reduce()\r\n return this\r\n }\r\n\r\n amplify = (k: number): Fraction => {\r\n if (Number.isSafeInteger(k)) {\r\n this.numerator *= k;\r\n this.denominator *= k;\r\n }\r\n return this;\r\n };\r\n\r\n}
106
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
107
- <+>UTF-8
108
- ===================================================================
109
- diff --git a/src/maths/coefficients/fraction.ts b/src/maths/coefficients/fraction.ts
110
- --- a/src/maths/coefficients/fraction.ts
111
- +++ b/src/maths/coefficients/fraction.ts
112
- @@ -13,69 +13,50 @@
113
-
114
- this.fracType = FRACTION_FRAC.frac
115
-
116
- + this.exact = true
117
- +
118
- if (value !== undefined) {
119
- - if (value instanceof Fraction) return this.parse(value)
120
- - return this.parse(value, denominator)
121
- + if (value instanceof Fraction) return this._parse(value)
122
- + return this._parse(value, denominator)
123
- }
124
-
125
- return this;
126
- }
127
-
128
- - get tex(): string {
129
- - const frac = this.fracTeX
130
- - // restore the frac type to default
131
- - this.fracType = FRACTION_FRAC.frac
132
- + static decimalToFraction = (value: string | number | Fraction): [number, number] => {
133
- + // Return the neutral element
134
- + if (value === undefined) return [1, 1]
135
-
136
- - if (this.isInfinity()) {
137
- - return `${this.signTeX}\\infty`
138
- - }
139
- + // Return the numerator and denominator if it's already a fraction
140
- + if (value instanceof Fraction) return [value.numerator, value.denominator]
141
-
142
- - if (this.isExact()) {
143
- - if (this.denominator === 1) {
144
- - return `${this.numerator}`;
145
- - } else if (this.numerator < 0) {
146
- - return `-${frac}{ ${-this.numerator} }{ ${this.denominator} }`;
147
- - } else {
148
- - return `${frac}{ ${this.numerator} }{ ${this.denominator} }`;
149
- - }
150
- - } else {
151
- - return this.value.toFixed(3)
152
- - }
153
- - }
154
- + // Split the name into unit and decimal part
155
- + let [unit, decimal] = (+value).toString().split('.')
156
-
157
- - get display(): string {
158
- - if (this.isInfinity()) {
159
- - return `${this.signTeX}\\infty`
160
- - }
161
- + // Return the unit if there is no decimal part
162
- + if (decimal === undefined) return [+unit, 1]
163
- +
164
- + let decimalLength = decimal.length
165
-
166
- - if (this.isExact()) {
167
- - if (this.denominator === 1) {
168
- - return `${this.numerator}`;
169
- - } else if (this.numerator < 0) {
170
- - return `-${-this.numerator}/${this.denominator}`;
171
- - } else {
172
- - return `${this.numerator}/${this.denominator}`;
173
- - }
174
- - } else {
175
- - return this.value.toFixed(3)
176
- + return [+(unit + decimal), 10 ** decimalLength]
177
- + }
178
- +
179
- + static average = (...fractions: (Fraction | number)[]): Fraction => {
180
- + let M = new Fraction().zero()
181
- +
182
- + for (let f of fractions) {
183
- + M.add(f)
184
- }
185
- +
186
- + M.divide(fractions.length)
187
- +
188
- + return M
189
- }
190
-
191
- createInstance(value?: string | number | Fraction): Fraction {
192
- return new Fraction(value)
193
- }
194
-
195
- - clone = (): Fraction => {
196
- - return new Fraction(this.numerator, this.denominator)
197
- - };
198
- -
199
- - reduce = (): Fraction => {
200
- - const {N, D} = this.getReducedCoefficient()
201
- - this.numerator = N
202
- - this.denominator = D
203
- - return this;
204
- - };
205
- -
206
- add = (...values: (Fraction | number | string)[]): Fraction => {
207
- for (let F of values) {
208
- if (!(F instanceof Fraction)) F = new Fraction(F)
209
- @@ -91,7 +72,7 @@
210
- };
211
-
212
- multiply = (...values: (Fraction | number)[]): Fraction => {
213
- - // Parse the value.
214
- + // Parse the name.
215
- // If it's a fraction, return a clone of it
216
- // If it's an integer, return the fraction F/1
217
- for (let F of values) {
218
- @@ -115,104 +96,98 @@
219
- }
220
-
221
- root = (p: number): Fraction => {
222
- - // TODO: index - root of a fraction => this will return another type of coefficient.
223
- + // The indice cannot be negative.
224
- + if (p < 0) {
225
- + throw ("cannot make the root with a negative indice.")
226
- + }
227
-
228
- - // Check if they are perfect roots..
229
- + // Power of zero => return one.
230
- if (p === 0) {
231
- - return this;
232
- + return this.one();
233
- }
234
-
235
- - // If negative, invert the fraction
236
- - if (p < 0) {
237
- - this.invert()
238
- + // Power of one => return this
239
- + if (p === 1) {
240
- + return this
241
- }
242
- -
243
- - let n = Math.pow(this.numerator, Math.abs(1 / p)),
244
- - d = Math.pow(this.denominator, Math.abs(1 / p));
245
-
246
- this.numerator = Math.pow(this.numerator, Math.abs(1 / p));
247
- this.denominator = Math.pow(this.denominator, Math.abs(1 / p));
248
- +
249
- + if (!Number.isSafeInteger(this.numerator) || !Number.isSafeInteger(this.denominator)) {
250
- + this.exact = false
251
- + this.numerator = this.numerator / this.denominator
252
- + this.denominator = 1
253
- + }
254
- return this;
255
- }
256
-
257
- - static decimalToFraction = (value: string | number | Fraction): [number, number] => {
258
- - // Return the neutral element
259
- - if (value === undefined) return [1, 1]
260
- + reduce = (): Fraction => {
261
- + const {N, D} = this.getReducedCoefficient()
262
- + this.numerator = N
263
- + this.denominator = D
264
- + return this;
265
- + };
266
-
267
- - // Return the numerator and denominator if it's already a fraction
268
- - if (value instanceof Fraction) return [value.numerator, value.denominator]
269
- + clone = (): Fraction => {
270
- + return new Fraction(this.numerator, this.denominator)
271
- + };
272
-
273
- - // Split the value into unit and decimal part
274
- - let [unit, decimal] = (+value).toString().split('.')
275
- + get tex(): string {
276
- + const frac = this.fracTeX
277
- + // restore the frac type to default
278
- + this.fracType = FRACTION_FRAC.frac
279
-
280
- - // Return the unit if there is no decimal part
281
- - if (decimal === undefined) return [+unit, 1]
282
- + if (this.isInfinity()) {
283
- + return `${this.signTeX}\\infty`
284
- + }
285
-
286
- - let decimalLength = decimal.length
287
- -
288
- - return [+(unit + decimal), 10 ** decimalLength]
289
- + if (this.isExact()) {
290
- + if (this.denominator === 1) {
291
- + return `${this.numerator}`;
292
- + } else if (this.numerator < 0) {
293
- + return `-${frac}{ ${-this.numerator} }{ ${this.denominator} }`;
294
- + } else {
295
- + return `${frac}{ ${this.numerator} }{ ${this.denominator} }`;
296
- + }
297
- + } else {
298
- + return this.value.toFixed(3)
299
- + }
300
- }
301
-
302
- - static average = (...fractions: (Fraction | number)[]): Fraction => {
303
- - let M = new Fraction().zero()
304
- + get display(): string {
305
- + if (this.isInfinity()) return `${this.signTeX}oo`
306
-
307
- - for (let f of fractions) {
308
- - M.add(f)
309
- + if (this.isExact()) {
310
- + if (this.denominator === 1) {
311
- + return `${this.numerator}`;
312
- + } else if (this.numerator < 0) {
313
- + return `-${-this.numerator}/${this.denominator}`;
314
- + } else {
315
- + return `${this.numerator}/${this.denominator}`;
316
- + }
317
- + } else {
318
- + return this.value.toFixed(3)
319
- }
320
- -
321
- - M.divide(fractions.length)
322
- -
323
- - return M
324
- }
325
-
326
- /**
327
- - * Parse the value to get the numerator and denominator
328
- - * @param value : number or string to parse to get the fraction
329
- - * @param denominatorOrPeriodic (optional|number) : length of the periodic part: 2.333333 => 1 or denominator value
330
- + * Parse the name to get the numerator and denominator
331
- + * @param value : number or string to _parse to get the fraction
332
- + * @param denominatorOrPeriodic (optional|number) : length of the periodic part: 2.333333 => 1 or denominator name
333
- */
334
- - parse(value: Fraction): Fraction
335
- -
336
- - parse(value: string | number): Fraction
337
- + protected _parse(value: Fraction): Fraction
338
-
339
- + protected _parse(value: string | number): Fraction
340
-
341
- - // pow = (p: number | Fraction): Fraction => {
342
- - // // TODO: Fraction.pow with a value different than a safe integer !
343
- - // if (p instanceof Fraction) {
344
- - // return this.pow(p.value)
345
- - // }
346
- - //
347
- - // this.reduce();
348
- - // if (p < 0) {
349
- - // this.invert()
350
- - // }
351
- - //
352
- - // // Check if numerator and denominator are roots of...
353
- - // // othervise, convert to numeric.
354
- - // let controlNumerator = Math.floor(Math.pow(this.numerator, Math.abs(p))),
355
- - // controlDenominator = Math.floor(Math.pow(this.denominator, Math.abs(p)))
356
- - //
357
- - // if (controlNumerator ** Math.abs(p) === this.numerator
358
- - // &&
359
- - // controlDenominator ** Math.abs(p) === this.denominator) {
360
- - //
361
- - // this.numerator = this.numerator ** Math.abs(p);
362
- - // this.denominator = this.denominator ** Math.abs(p);
363
- - // } else {
364
- - // this.numerator = this.numerator ** Math.abs(p);
365
- - // this.denominator = this.denominator ** Math.abs(p);
366
- - // }
367
- - //
368
- - // return this;
369
- - // };
370
- + protected _parse(value: string | number, denominator: string | number): Fraction
371
-
372
- - parse(value: string | number, denominator: string | number): Fraction
373
- -
374
- - parse(value: string | number | Fraction, denominator ?: string | number): Fraction {
375
- + protected _parse(value: string | number | Fraction, denominator ?: string | number): Fraction {
376
- // Default values
377
- this.numerator = 0;
378
- this.denominator = 1;
379
-
380
- - // A null value means a zero fraction.
381
- + // A null name means a zero fraction.
382
- if (value === null || value === "") return this;
383
-
384
- // No denominator given
385
- @@ -223,7 +198,7 @@
386
- return new Fraction(value, 1)
387
- }
388
-
389
- - // a value of type string can be:
390
- + // a name of type string can be:
391
- // - an integer number 4
392
- // - a decimal number 4.12
393
- // - a fraction 4/5
394
- @@ -250,12 +225,4 @@
395
- return this
396
- }
397
-
398
- - amplify = (k: number): Fraction => {
399
- - if (Number.isSafeInteger(k)) {
400
- - this.numerator *= k;
401
- - this.denominator *= k;
402
- - }
403
- - return this;
404
- - };
405
- -
406
- }
407
-
408
- Index: src/maths/algebra/monom.ts
409
- IDEA additional info:
410
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
411
- <+>/***\r\n * Monom class\r\n * The monom class represents of monom of the form:\r\n * k * x^n * y^m * z^p\r\n * k: Coefficient\r\n * n, m, p: powers as Fraction\r\n * x, y, z: letters as string\r\n */\r\nimport {Numeric} from \"../numeric\";\r\nimport {Shutingyard, ShutingyardType, Token} from \"../shutingyard\";\r\nimport {COMPARESIGNS, literalType} from \"../types\";\r\nimport {RootFraction} from \"../coefficients/rootFraction\";\r\nimport {\r\n COEFFICIENT_MODE,\r\n CoefficientCore,\r\n CoefficientParserTypes,\r\n CoefficientTypes\r\n} from \"../coefficients/coefficientCore\";\r\nimport {Fraction} from \"../coefficients/fraction\";\r\n\r\n\r\nexport class Monom {\r\n private _coefficientMode: COEFFICIENT_MODE\r\n\r\n /**\r\n * Create a Monom\r\n * Defined as \\\\(k \\\\cdot x^{n}\\\\), where \\\\( k,n \\in \\\\mathbb{Q}\\\\).\r\n * Examples: \\\\(3x^2\\\\) or \\\\(3/5x^2\\\\)\r\n * @param value (optional) string The value that should be parse. Can be a Monom, a Fraction, a string or a number. If nothing is provided, it will return the trivial monom (0).\r\n */\r\n constructor(value?: unknown) {\r\n this.zero();\r\n\r\n if (value !== undefined) {\r\n // A string is given - try to parse the value.\r\n this.parse(value);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n // ------------------------------------------\r\n // Getter and setter\r\n\r\n private _coefficient: CoefficientCore<any>;\r\n\r\n // ------------------------------------------\r\n /**\r\n * Get the coefficient \\\\(k\\\\) of the Monom \\\\(k\\\\cdot x^{n}\\\\)\r\n * @returns {Fraction}\r\n */\r\n get coefficient(): CoefficientCore<any> {\r\n return this._coefficient;\r\n }\r\n\r\n /**\r\n * Set the coefficient \\\\(k\\\\) value of the monom\r\n * @param {Fraction | number | string} F\r\n */\r\n set coefficient(F: CoefficientParserTypes) {\r\n this._coefficient = this.makeCoefficient(F);\r\n }\r\n\r\n private _literal: literalType;\r\n\r\n /**\r\n * Get the literal part of \\\\(x^{n_1}y^{n_2}\\\\) as dictionary \\\\[\\\\begin{array}{ll}x&=n_1\\\\\\\\y&=n_2\\\\end{array}\\\\]\r\n * @returns {literalType}\r\n */\r\n get literal(): literalType {\r\n return this._literal;\r\n }\r\n\r\n /**\r\n * Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}\r\n * @param {literalType} L\r\n */\r\n set literal(L: literalType) {\r\n this._literal = L;\r\n }\r\n\r\n /**\r\n * Get the literal square roots of the Monom.\r\n * TODO: remove this getter ? Is it used and is it correct ?\r\n * @returns {literalType}\r\n */\r\n get literalSqrt(): literalType {\r\n if (this.isLiteralSquare()) {\r\n let L: literalType = {}\r\n for (let key in this._literal) {\r\n L[key] = this._literal[key].clone().sqrt()\r\n }\r\n return L;\r\n } else {\r\n return this._literal;\r\n }\r\n }\r\n\r\n /**\r\n * Set the literal part of the monom from a string\r\n * @param inputStr String like x^2y^3\r\n */\r\n set literalStr(inputStr: string) {\r\n // TODO : parse using shutingyard tree !\r\n\r\n // Match all x^n\r\n for (const v of [...inputStr.matchAll(/([a-z])\\^([+-]?[0-9]+)/g)]) {\r\n // Create the default letter entry if necessary.\r\n if (!(v[1] in this._literal)) {\r\n this._literal[v[1]] = this.makeCoefficient().zero();\r\n }\r\n\r\n // Add the new value.\r\n // TODO: actually, it adds only numeric value\r\n this._literal[v[1]].add(+v[2]);\r\n }\r\n\r\n // Match all x\r\n for (const v of [...inputStr.matchAll(/([a-z](?!\\^))/g)]) {\r\n // Match all single letters\r\n if (!(v[1] in this._literal)) {\r\n this._literal[v[1]] = this.makeCoefficient().zero();\r\n }\r\n\r\n // Add one to the value.\r\n this._literal[v[1]].add(1)\r\n }\r\n }\r\n\r\n // Getter helpers.\r\n /**\r\n * Get the variables letters\r\n */\r\n get variables(): string[] {\r\n let M = this.clone().clean();\r\n return Object.keys(M.literal)\r\n }\r\n\r\n // Display getter\r\n /**\r\n * This display getter is to be used in the polynom display getter\r\n */\r\n get display(): string {\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += `${letter}`;\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^(${this._literal[letter].display})`;\r\n }\r\n }\r\n }\r\n\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.display}`;\r\n } else {\r\n return '';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.display}${L}`;\r\n }\r\n }\r\n }\r\n\r\n get dividers(): Monom[] {\r\n // Decompose only if the coefficient is a natural number\r\n if (!this.coefficient.isRelative()) {\r\n return [this.clone()]\r\n }\r\n\r\n\r\n // Decompose only if the power values are natural numbers.\r\n if (this.hasFractionCoefficient()) {\r\n return [this.clone()]\r\n }\r\n\r\n // Security : do not do this if isGreaterThan than 10000\r\n if (this.coefficient.numerator > 1000000) {\r\n return [this.clone()]\r\n }\r\n\r\n const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))\r\n\r\n // Decompose the literals parts.\r\n let literals: literalType[] = [];\r\n for (let L in this.literal) {\r\n // L is the letter.\r\n literals = this._getLiteralDividers(literals, L)\r\n }\r\n\r\n const monomDividers: Monom[] = [];\r\n if (literals.length > 0 && dividers.length > 0) {\r\n for (let N of dividers) {\r\n for (let L of literals) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient(N)\r\n M.literal = L\r\n monomDividers.push(M)\r\n }\r\n }\r\n } else if (dividers.length === 0) {\r\n for (let L of literals) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient().one()\r\n M.literal = L\r\n monomDividers.push(M)\r\n }\r\n } else {\r\n for (let N of dividers) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient(N)\r\n monomDividers.push(M)\r\n }\r\n }\r\n\r\n return monomDividers.length === 0 ? [new Monom().one()] : monomDividers;\r\n }\r\n\r\n /**\r\n * Display the monom, forcing the '+' sign to appear\r\n */\r\n get displayWithSign(): string {\r\n let d: String = this.display;\r\n return (d[0] !== '-' ? '+' : '') + d;\r\n }\r\n\r\n get texWithSign(): string {\r\n if (this.coefficient.isStrictlyPositive()) {\r\n return '+' + this.tex\r\n }\r\n\r\n return this.tex\r\n }\r\n\r\n get plotFunction(): string {\r\n\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += (L === '' ? \"\" : \"*\") + `${letter}`\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^(${this._literal[letter].display})`;\r\n }\r\n }\r\n }\r\n\r\n // No literal part\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.display}`;\r\n } else {\r\n return '';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.display}*${L}`;\r\n }\r\n }\r\n }\r\n\r\n // ------------------------------------------\r\n // Creation / parsing functions\r\n\r\n /**\r\n * Get the tex output of the monom\r\n */\r\n get tex(): string {\r\n // TODO: display with square root !\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += `${letter}`;\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^{${this._literal[letter].asTopFraction().tex}}`;\r\n }\r\n }\r\n }\r\n\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.tex}`;\r\n } else {\r\n return '0';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.tex}${L}`;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get the least common multiple of monoms\r\n * @param monoms Array of monoms\r\n */\r\n static lcm = (...monoms: Monom[]): Monom => {\r\n // All the monoms must be with natural powers...\r\n for (let m of monoms) {\r\n if (m.hasFractionCoefficient()) {\r\n return new Monom().zero()\r\n }\r\n }\r\n\r\n\r\n let M = new Monom(),\r\n coeffN: number[] = monoms.map(value => value.coefficient.numerator),\r\n coeffD: number[] = monoms.map(value => value.coefficient.denominator),\r\n n = Numeric.gcd(...coeffN),\r\n d = Numeric.lcm(...coeffD);\r\n\r\n // Get the coefficient.\r\n M.coefficient = this.makeCoefficient(n, d).reduce();\r\n\r\n // Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.\r\n for (let m of monoms) {\r\n // Remove the inexistant letters from the resulting monom\r\n for (let letter in M.literal) {\r\n if (!(letter in m.literal)) {\r\n M.literal[letter].zero();\r\n }\r\n }\r\n for (let letter in m.literal) {\r\n if (M.literal[letter] === undefined && m.literal[letter].isStrictlyPositive()) {\r\n M.literal[letter] = m.literal[letter].clone();\r\n } else {\r\n M.literal[letter] = this.makeCoefficient(Math.min(m.literal[letter].value, M.literal[letter].value))\r\n }\r\n }\r\n }\r\n\r\n return M;\r\n };\r\n\r\n /**\r\n * Multiply two monoms and return a NEW monom.\r\n * @param monoms\r\n */\r\n static xmultiply = (...monoms: Monom[]): Monom => {\r\n let M = new Monom().one();\r\n\r\n for (let m of monoms) {\r\n M.multiply(m);\r\n }\r\n\r\n return M;\r\n };\r\n\r\n makeCoefficient = (...values: CoefficientParserTypes[]): CoefficientTypes => {\r\n if (this._coefficientMode === COEFFICIENT_MODE.FRACTION) {\r\n return new Fraction(...values as (Fraction | string | number)[])\r\n } else if (this._coefficientMode === COEFFICIENT_MODE.ROOT) {\r\n return new RootFraction(...values as (RootFraction | Fraction | string | number)[])\r\n }\r\n\r\n // TODO: add the other modes\r\n return new Fraction(...values as (Fraction | string | number)[])\r\n }\r\n\r\n// -----------------------------------------\r\n /**\r\n * Parse a string to a monom. The string may include fraction.\r\n * @param inputStr\r\n */\r\n parse = (inputStr: unknown): Monom => {\r\n\r\n if (typeof inputStr === 'string') {\r\n this._shutingYardToReducedMonom(inputStr)\r\n } else if (typeof inputStr === 'number') {\r\n this._coefficient = this.makeCoefficient(inputStr)\r\n this._literal = {}\r\n } else if (inputStr instanceof Fraction) {\r\n this._coefficient = inputStr.clone()\r\n this._literal = {}\r\n } else if (inputStr instanceof RootFraction) {\r\n this._coefficient = inputStr.clone()\r\n this._literal = {}\r\n } else if (inputStr instanceof Monom) {\r\n this._coefficient = inputStr._coefficient.clone()\r\n this._literal = this.copyLiterals(inputStr.literal)\r\n }\r\n\r\n return this;\r\n };\r\n\r\n addToken = (stack: Monom[], element: Token): void => {\r\n\r\n let q1: Monom, q2: Monom, m: Monom, letter: string, pow: CoefficientCore<any>\r\n\r\n if (element.tokenType === ShutingyardType.COEFFICIENT) {\r\n stack.push(new Monom(this.makeCoefficient(element.token)))\r\n\r\n } else if (element.tokenType === ShutingyardType.VARIABLE) {\r\n let M = new Monom().one()\r\n M.setLetter(element.token, 1)\r\n stack.push(M.clone())\r\n\r\n } else if (element.tokenType === ShutingyardType.OPERATION) {\r\n switch (element.token) {\r\n case '-':\r\n // this should only happen for negative powers or for negative coefficient.\r\n q2 = (stack.pop()) || new Monom().zero()\r\n q1 = (stack.pop()) || new Monom().zero()\r\n\r\n stack.push(q1.subtract(q2))\r\n\r\n break;\r\n case '*':\r\n // Get the last element in the stack\r\n q2 = (stack.pop()) || new Monom().one()\r\n q1 = (stack.pop()) || new Monom().one()\r\n\r\n stack.push(q1.multiply(q2))\r\n break\r\n case '/':\r\n // Get the last element in the stack\r\n q2 = (stack.pop()) || new Monom().one()\r\n q1 = (stack.pop()) || new Monom().one()\r\n\r\n stack.push(q1.divide(q2))\r\n break\r\n case '^':\r\n // get the two last elements in the stack\r\n pow = (stack.pop().coefficient) || this.makeCoefficient().one()\r\n m = (stack.pop()) || new Monom().one()\r\n\r\n letter = m.variables[0]\r\n\r\n if (letter !== undefined) {\r\n m.setLetter(letter, pow)\r\n }\r\n\r\n stack.push(m)\r\n // this.multiply(m.clone())\r\n break\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Clone the current Monom.\r\n */\r\n clone = (): Monom => {\r\n let F: Monom = new Monom();\r\n\r\n F.coefficient = this._coefficient.clone();\r\n\r\n // Copy the literal parts.\r\n for (let k in this._literal) {\r\n F.setLetter(k, this._literal[k].clone());\r\n }\r\n return F;\r\n };\r\n\r\n copyLiterals = (literal: literalType): literalType => {\r\n let L: literalType = {}\r\n\r\n for (let k in literal) {\r\n L[k] = literal[k].clone()\r\n }\r\n return L\r\n }\r\n\r\n makeSame = (M: Monom): Monom => {\r\n // Copy the literal parts.\r\n for (let k in M._literal) {\r\n this.setLetter(k, M._literal[k].clone());\r\n }\r\n return this\r\n }\r\n\r\n /**\r\n * Create a zero value monom\r\n */\r\n zero = (): Monom => {\r\n this._coefficient = this.makeCoefficient().zero();\r\n this._literal = {};\r\n return this;\r\n };\r\n\r\n /**\r\n * Create a one value monom\r\n */\r\n one = (): Monom => {\r\n this._coefficient = this.makeCoefficient().one();\r\n this._literal = {};\r\n return this;\r\n };\r\n\r\n// ------------------------------------------\r\n// Mathematical operations\r\n// ------------------------------------------\r\n\r\n /**\r\n * Clean the monom by removing each letters with a power of zero.\r\n */\r\n clean = (): Monom => {\r\n for (let letter in this._literal) {\r\n if (this._literal[letter].isZero()) {\r\n delete this._literal[letter];\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n reduce = (): Monom => {\r\n this.clean()\r\n this.coefficient.reduce()\r\n return this\r\n }\r\n\r\n /**\r\n * Get the opposite\r\n * Returns a monom.\r\n */\r\n opposed = (): Monom => {\r\n this._coefficient.opposite();\r\n return this;\r\n };\r\n\r\n /**\r\n * Add all similar monoms. If they aren't similar, they are simply skipped.\r\n * @param M (Monom[]) The monoms to add.\r\n */\r\n add = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n if (this.isSameAs(m)) {\r\n if (this.isZero()) {\r\n this.makeSame(m)\r\n }\r\n this._coefficient.add(m.coefficient);\r\n } else {\r\n console.log('Add monom: ' + this.display + ' is not similar with ', m.display);\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Subtract multiple monoms\r\n * @param M (Monom[]) The monoms to subtract\r\n */\r\n subtract = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n if (this.isSameAs(m)) {\r\n if (this.isZero()) {\r\n this.makeSame(m)\r\n }\r\n this._coefficient.add(m.clone().coefficient.opposite());\r\n } else {\r\n console.log('Subtract: Is not similar: ', m.display);\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Multiple multiple monoms to the current monom\r\n * @param M (Monom[]) The monoms to multiply to.\r\n */\r\n multiply = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n // Multiply the coefficient.\r\n this._coefficient.multiply(m.coefficient);\r\n\r\n // Multiply the literal parts.\r\n for (let letter in m.literal) {\r\n if (this._literal[letter] === undefined) {\r\n this._literal[letter] = m.literal[letter].clone()\r\n } else {\r\n this._literal[letter].add(m.literal[letter])\r\n }\r\n\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n multiplyByNumber = (F: Fraction | number): Monom => {\r\n this._coefficient.multiply(F);\r\n return this;\r\n }\r\n\r\n /**\r\n * Divide the current monoms by multiple monoms\r\n * @param M (Monom[])\r\n */\r\n divide = (...M: Monom[]): Monom => {\r\n // Depending on the given value, choose the current item\r\n for (let v of M) {\r\n // Divide the coefficient\r\n this._coefficient.divide(v.coefficient);\r\n\r\n // Subtract the power values\r\n for (let letter in v.literal) {\r\n this._literal[letter] = (this._literal[letter] === undefined) ? v.literal[letter].clone().opposite() : this._literal[letter].subtract(v.literal[letter])\r\n\r\n // If the power of a particular setLetter is zero, delete it from the literal part..\r\n if (this._literal[letter].isZero()) {\r\n delete this._literal[letter];\r\n }\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Get the pow of a monom.\r\n * @param nb (number) : Mathematical pow\r\n */\r\n pow = (nb: number | Fraction): Monom => {\r\n this._coefficient.pow(nb);\r\n for (let letter in this._literal) {\r\n this._literal[letter].multiply(nb)\r\n }\r\n return this;\r\n };\r\n\r\n// ------------------------------------------\r\n// Compare functions\r\n\r\n /**\r\n * Get the index-root of the monom\r\n * @param p\r\n */\r\n root = (p: number): Monom => {\r\n // TODO: determiner the index root of a monom\r\n return this;\r\n }\r\n\r\n /**\r\n * Return the square root of a monom\r\n */\r\n sqrt = (): Monom => {\r\n if (this.isSquare()) {\r\n this._coefficient.sqrt();\r\n for (let letter in this._literal) {\r\n this._literal[letter].clone().divide(2)\r\n }\r\n }\r\n return this.root(2);\r\n }\r\n\r\n// ------------------------------------------\r\n compare = (M: Monom, sign?: COMPARESIGNS): boolean => {\r\n // TODO: Build the compare systems.\r\n if (sign === undefined) {\r\n sign = COMPARESIGNS.EQUALS;\r\n }\r\n\r\n\r\n switch (sign) {\r\n case COMPARESIGNS.EQUALS:\r\n // To be equal, they must be the isSame\r\n if (!this.compare(M, COMPARESIGNS.SAME)) {\r\n return false;\r\n }\r\n\r\n // The literal parts are the isSame. The coefficient must be equal\r\n return this._coefficient.isEqualTo(M.coefficient);\r\n case COMPARESIGNS.SAME:\r\n // Get the list of all variables from both monoms.\r\n let M1: string[] = this.variables,\r\n M2: string[] = M.variables,\r\n K: string[] = M1.concat(M2.filter((item) => M1.indexOf(item) < 0));\r\n\r\n if (M1.length === 0 && M2.length === 0) {\r\n return true\r\n }\r\n // To compare, both must be different than zero.\r\n if (!this.isZero() && !M.isZero()) {\r\n for (let key of K) {\r\n // The setLetter is not available in one of the monom\r\n if (this._literal[key] === undefined || M.literal[key] === undefined) {\r\n return false;\r\n }\r\n // The setLetter does not have the isSame power in each monoms.\r\n if (!this._literal[key].isEqualTo(M.literal[key])) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n // All are positive check - the monoms are the sames.\r\n return true;\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Determine if the monom is null\r\n */\r\n isZero()\r\n :\r\n boolean {\r\n return this._coefficient.value === 0;\r\n }\r\n\r\n /**\r\n * Determine if the monom is one\r\n */\r\n isOne()\r\n :\r\n boolean {\r\n return this._coefficient.value === 1 && this.variables.length === 0;\r\n }\r\n\r\n /**\r\n * Determine if two monoms are equals\r\n * @param M\r\n */\r\n isEqual = (M: Monom): boolean => {\r\n return this.compare(M, COMPARESIGNS.EQUALS);\r\n };\r\n\r\n /**\r\n * Determine if two monoms are similar\r\n * @param M\r\n */\r\n isSameAs = (M: Monom): boolean => {\r\n return this.compare(M, COMPARESIGNS.SAME);\r\n };\r\n\r\n isSquare = (): boolean => {\r\n if (!this.coefficient.isSquare()) {\r\n return false;\r\n }\r\n return this.isLiteralSquare();\r\n }\r\n// ------------------------------------------\r\n// Misc monoms functions\r\n\r\n isLiteralSquare = (): boolean => {\r\n for (let letter in this.literal) {\r\n // A literal square must have a natural power\r\n if (this.literal[letter].isRational()) {\r\n return false\r\n }\r\n\r\n // The natural power must be be even\r\n if (this.literal[letter].isEven()) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n hasFractionCoefficient = (): boolean => {\r\n for (let letter in this._literal) {\r\n if (this._literal[letter].isRational()) {\r\n return true\r\n }\r\n }\r\n\r\n return false\r\n }\r\n\r\n// -------------------------------------\r\n /**\r\n * Determine if a monom contains a setLetter in it's literal part\r\n * @param letter\r\n */\r\n hasLetter = (letter?: string): boolean => {\r\n // The letter was not found\r\n if (this._literal[letter === undefined ? 'x' : letter] === undefined) {\r\n return false\r\n }\r\n\r\n // The letter is found and is not zero !\r\n return !this._literal[letter === undefined ? 'x' : letter].isZero();\r\n };\r\n\r\n /**\r\n * Set the power of a particular setLetter\r\n * @param letter (string) Letter to change\r\n * @param pow (number) Power of the setLetter (must be positive integer.\r\n */\r\n setLetter = (letter: string, pow: CoefficientCore<any> | number): void => {\r\n if (pow instanceof CoefficientCore) {\r\n // Set the power of the letter to zero => remove it\r\n if (this.hasLetter(letter) && pow.isZero()) {\r\n delete this._literal[letter]\r\n }\r\n\r\n this._literal[letter] = pow.clone()\r\n } else {\r\n this.setLetter(letter, this.makeCoefficient(pow))\r\n }\r\n };\r\n\r\n /**\r\n * Get the degree of a monom. If no setLetter is given, the result will be the global degree.\r\n * @param letter (string) Letter to get to degree (power)\r\n */\r\n degree = (letter?: string): CoefficientTypes => {\r\n if (this.variables.length === 0) {\r\n return this.makeCoefficient().zero();\r\n }\r\n if (letter === undefined) {\r\n // Not setLetter given -> we get the global monom degree (sum of all the letters).\r\n return Object.values(this._literal)\r\n .reduce(\r\n (t, n) => t.clone().add(n)\r\n );\r\n } else {\r\n // A setLetter is given -> get the corresponding power.\r\n return this._literal[letter] === undefined ? this.makeCoefficient().zero() : this._literal[letter].clone();\r\n }\r\n };\r\n\r\n /**\r\n * Evaluate a monom. Each setLetter must be assigned to a Fraction.\r\n * @param values Dictionary of <setLetter: Fraction>\r\n */\r\n evaluate = (values?: literalType | Fraction | number): CoefficientCore<any> => {\r\n let r = this.coefficient.clone();\r\n\r\n if (typeof values === 'number' || values instanceof Fraction) {\r\n let tmpValues: literalType = {}\r\n tmpValues[this.variables[0]] = this.makeCoefficient(values)\r\n return this.evaluate(tmpValues);\r\n }\r\n\r\n if (typeof values === 'object') {\r\n if (this.variables.length === 0) {\r\n return this.coefficient\r\n }\r\n for (let L in this._literal) {\r\n if (values[L] === undefined) {\r\n return this.makeCoefficient().zero();\r\n }\r\n\r\n let value = this.makeCoefficient(values[L])\r\n\r\n r.multiply(value.pow(this._literal[L]))\r\n }\r\n }\r\n\r\n return r;\r\n };\r\n\r\n evaluateAsNumeric = (values: { [Key: string]: number } | number): number => {\r\n let r = this.coefficient.value\r\n\r\n if (typeof values === 'number') {\r\n let tmpValues: { [Key: string]: number } = {}\r\n tmpValues[this.variables[0]] = values\r\n return this.evaluateAsNumeric(tmpValues);\r\n }\r\n\r\n if (typeof values === 'object') {\r\n if (this.variables.length === 0) {\r\n return this.coefficient.value\r\n }\r\n for (let L in this._literal) {\r\n if (values[L] === undefined) {\r\n return 0;\r\n }\r\n\r\n r *= values[L] ** (this._literal[L].value)\r\n }\r\n }\r\n\r\n return r\r\n }\r\n// ----------------------------------------\r\n// Static functions\r\n// ----------------------------------------\r\n\r\n /**\r\n * Derivative the monom\r\n * @param letter\r\n */\r\n derivative = (letter?: string): Monom => {\r\n // No setLetter given - assume it's the setLetter 'x'\r\n if (letter === undefined) {\r\n letter = 'x';\r\n }\r\n\r\n if (this.hasLetter(letter)) {\r\n let d = this._literal[letter].clone(),\r\n dM = this.clone();\r\n\r\n // Subtract one to the degree.\r\n dM._literal[letter].subtract(1)\r\n\r\n // Multiply the coefficient by the previous degree\r\n dM._coefficient.multiply(this.makeCoefficient(d.clone()));\r\n return dM;\r\n } else {\r\n return new Monom().zero();\r\n }\r\n };\r\n\r\n primitive = (letter?: string): Monom => {\r\n // TODO: derivative including the ln value => implies creating different monom system ?\r\n if (letter === undefined) {\r\n letter = 'x'\r\n }\r\n\r\n // Zero monom\r\n let M = this.clone(), degree\r\n\r\n if (M.hasLetter(letter)) {\r\n degree = M.degree(letter).clone().add(1)\r\n M.coefficient = M.coefficient.clone().divide(degree)\r\n M.setLetter(letter, degree)\r\n } else {\r\n // There is no letter.\r\n\r\n // The coefficient might be zero (=> x) or a number a (=> ax)\r\n if (M.coefficient.isZero()) {\r\n M.coefficient = this.makeCoefficient().one()\r\n }\r\n M.setLetter(letter, 1)\r\n }\r\n\r\n return M\r\n }\r\n\r\n// TODO: The rest of the functions are not used or unnecessary ?\r\n /**\r\n * Determine if multiple monoms are similar\r\n * @param M\r\n */\r\n areSameAs = (...M: Monom[]): boolean => {\r\n let result: boolean = true;\r\n\r\n // Check all monoms if they are the isSame as the \"this\" one.\r\n for (let i = 0; i < M.length; i++) {\r\n if (!this.isSameAs(M[i])) {\r\n return false;\r\n }\r\n }\r\n\r\n // All check passed -> all the monoms are similar.\r\n return result;\r\n };\r\n\r\n /**\r\n * Determine if multiple monoms are equals\r\n * @param M\r\n */\r\n areEquals = (...M: Monom[]): boolean => {\r\n // They are not similar.\r\n if (!this.areSameAs(...M)) {\r\n return false;\r\n }\r\n\r\n // Check all coefficient. They must be equals.\r\n for (let m of M) {\r\n if (!this._coefficient.isEqualTo(m.coefficient)) {\r\n return false;\r\n }\r\n }\r\n\r\n // All checks passed.\r\n return true;\r\n };\r\n\r\n isDivisible = (div: Monom): boolean => {\r\n // For all variables (letters), the current monom must have a degree higher than the divider\r\n if (div.degree().isStrictlyPositive()) {\r\n for (let letter of div.variables) {\r\n if (!this.degree(letter).isGreaterOrEqualTo(div.degree(letter))) {\r\n return false\r\n }\r\n }\r\n }\r\n\r\n // If the coefficient is rational, we suppose we don't need to check the division by the coefficient.\r\n if (this.coefficient.isRational() || div.coefficient.isRational()) {\r\n return true\r\n }\r\n\r\n return this.coefficient.clone().divide(div.coefficient).isRelative()\r\n }\r\n\r\n isInverted(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return this.clone().multiply(M).isOne();\r\n }\r\n\r\n isNegativeOne()\r\n :\r\n boolean {\r\n return this._coefficient.value === -1 && this.variables.length === 0;\r\n }\r\n\r\n isNotEqual(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return !this.isEqual(M);\r\n }\r\n\r\n isNotZero()\r\n :\r\n boolean {\r\n return !this.isZero();\r\n }\r\n\r\n isOpposed(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return this.clone().subtract(M).isZero();\r\n }\r\n\r\n isReduced()\r\n :\r\n boolean {\r\n // By construction, it is already reduced (litterals\r\n return this.coefficient.isReduced();\r\n }\r\n\r\n reset()\r\n :\r\n any {\r\n this._coefficient = this.makeCoefficient()\r\n this._literal = {}\r\n }\r\n\r\n _getLiteralDividers(arr: literalType[], letter: string):\r\n literalType[] {\r\n let tmpList: { [key: string]: CoefficientTypes }[] = [];\r\n\r\n // Be default, this.literal[letter] should be a rational number.\r\n for (let d = 0; d <= this.literal[letter].value; d++) {\r\n if (arr.length === 0) {\r\n let litt: literalType = {}\r\n litt[letter] = this.makeCoefficient(d)\r\n tmpList.push(litt)\r\n } else {\r\n for (let item of arr) {\r\n let litt: literalType = {}\r\n for (let currentLetter in item) {\r\n litt[currentLetter] = item[currentLetter]\r\n }\r\n litt[letter] = this.makeCoefficient(d)\r\n tmpList.push(litt)\r\n }\r\n }\r\n }\r\n return tmpList;\r\n }\r\n\r\n _shutingYardToReducedMonom = (inputStr: string): Monom => {\r\n // Get the RPN array of the current expression\r\n const SY: Shutingyard = new Shutingyard().parse(inputStr);\r\n const rpn: { token: string, tokenType: string }[] = SY.rpn;\r\n\r\n let stack: Monom[] = []\r\n\r\n if (rpn.length === 0) {\r\n this.zero()\r\n return this\r\n } else if (rpn.length === 1) {\r\n const element = rpn[0]\r\n\r\n this.one()\r\n if (element.tokenType === 'coefficient') {\r\n this.coefficient = this.makeCoefficient(element.token)\r\n } else if (element.tokenType === 'variable') {\r\n this.setLetter(element.token, 1)\r\n }\r\n return this\r\n } else {\r\n // Reset the monom\r\n for (const element of rpn) {\r\n this.addToken(stack, element)\r\n }\r\n }\r\n\r\n this.one()\r\n this.multiply(stack[0])\r\n return this\r\n }\r\n}\r\n
412
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
413
- <+>UTF-8
414
- ===================================================================
415
- diff --git a/src/maths/algebra/monom.ts b/src/maths/algebra/monom.ts
416
- --- a/src/maths/algebra/monom.ts
417
- +++ b/src/maths/algebra/monom.ts
418
- @@ -1,1113 +1,171 @@
419
- -/***
420
- - * Monom class
421
- - * The monom class represents of monom of the form:
422
- - * k * x^n * y^m * z^p
423
- - * k: Coefficient
424
- - * n, m, p: powers as Fraction
425
- - * x, y, z: letters as string
426
- - */
427
- -import {Numeric} from "../numeric";
428
- -import {Shutingyard, ShutingyardType, Token} from "../shutingyard";
429
- -import {COMPARESIGNS, literalType} from "../types";
430
- -import {RootFraction} from "../coefficients/rootFraction";
431
- import {
432
- - COEFFICIENT_MODE,
433
- - CoefficientCore,
434
- - CoefficientParserTypes,
435
- - CoefficientTypes
436
- -} from "../coefficients/coefficientCore";
437
- -import {Fraction} from "../coefficients/fraction";
438
- -
439
- -
440
- -export class Monom {
441
- - private _coefficientMode: COEFFICIENT_MODE
442
- -
443
- - /**
444
- - * Create a Monom
445
- - * Defined as \\(k \\cdot x^{n}\\), where \\( k,n \in \\mathbb{Q}\\).
446
- - * Examples: \\(3x^2\\) or \\(3/5x^2\\)
447
- - * @param value (optional) string The value that should be parse. Can be a Monom, a Fraction, a string or a number. If nothing is provided, it will return the trivial monom (0).
448
- - */
449
- - constructor(value?: unknown) {
450
- - this.zero();
451
- -
452
- - if (value !== undefined) {
453
- - // A string is given - try to parse the value.
454
- - this.parse(value);
455
- - }
456
- -
457
- - return this;
458
- - }
459
- -
460
- - // ------------------------------------------
461
- - // Getter and setter
462
- -
463
- - private _coefficient: CoefficientCore<any>;
464
- -
465
- - // ------------------------------------------
466
- - /**
467
- - * Get the coefficient \\(k\\) of the Monom \\(k\\cdot x^{n}\\)
468
- - * @returns {Fraction}
469
- - */
470
- - get coefficient(): CoefficientCore<any> {
471
- - return this._coefficient;
472
- - }
473
- -
474
- - /**
475
- - * Set the coefficient \\(k\\) value of the monom
476
- - * @param {Fraction | number | string} F
477
- - */
478
- - set coefficient(F: CoefficientParserTypes) {
479
- - this._coefficient = this.makeCoefficient(F);
480
- - }
481
- -
482
- - private _literal: literalType;
483
- -
484
- - /**
485
- - * Get the literal part of \\(x^{n_1}y^{n_2}\\) as dictionary \\[\\begin{array}{ll}x&=n_1\\\\y&=n_2\\end{array}\\]
486
- - * @returns {literalType}
487
- - */
488
- - get literal(): literalType {
489
- - return this._literal;
490
- - }
491
- -
492
- - /**
493
- - * Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}
494
- - * @param {literalType} L
495
- - */
496
- - set literal(L: literalType) {
497
- - this._literal = L;
498
- - }
499
- + coreInterface,
500
- + equalityInterface,
501
- + expressionElementInterface,
502
- + expressionInterface,
503
- + operationInterface
504
- +} from "../types";
505
- +import {Coefficient} from "../coefficients/coefficient";
506
-
507
- - /**
508
- - * Get the literal square roots of the Monom.
509
- - * TODO: remove this getter ? Is it used and is it correct ?
510
- - * @returns {literalType}
511
- - */
512
- - get literalSqrt(): literalType {
513
- - if (this.isLiteralSquare()) {
514
- - let L: literalType = {}
515
- - for (let key in this._literal) {
516
- - L[key] = this._literal[key].clone().sqrt()
517
- - }
518
- - return L;
519
- - } else {
520
- - return this._literal;
521
- - }
522
- - }
523
-
524
- - /**
525
- - * Set the literal part of the monom from a string
526
- - * @param inputStr String like x^2y^3
527
- - */
528
- - set literalStr(inputStr: string) {
529
- - // TODO : parse using shutingyard tree !
530
- -
531
- - // Match all x^n
532
- - for (const v of [...inputStr.matchAll(/([a-z])\^([+-]?[0-9]+)/g)]) {
533
- - // Create the default letter entry if necessary.
534
- - if (!(v[1] in this._literal)) {
535
- - this._literal[v[1]] = this.makeCoefficient().zero();
536
- - }
537
- +/**
538
- + * A polynom element is a coefficient with one or more variables and an exponent (which is a power and a root).
539
- + *
540
- + */
541
- +export class Monom implements coreInterface, operationInterface, equalityInterface, expressionInterface {
542
- + constructor(...values: unknown[]) {
543
-
544
- - // Add the new value.
545
- - // TODO: actually, it adds only numeric value
546
- - this._literal[v[1]].add(+v[2]);
547
- + if (values.length > 0) {
548
- + return this.parse(...values)
549
- }
550
- -
551
- - // Match all x
552
- - for (const v of [...inputStr.matchAll(/([a-z](?!\^))/g)]) {
553
- - // Match all single letters
554
- - if (!(v[1] in this._literal)) {
555
- - this._literal[v[1]] = this.makeCoefficient().zero();
556
- - }
557
- + return this
558
- + }
559
-
560
- - // Add one to the value.
561
- - this._literal[v[1]].add(1)
562
- - }
563
- - }
564
- + private _literal: expressionElementInterface = {}
565
-
566
- - // Getter helpers.
567
- - /**
568
- - * Get the variables letters
569
- - */
570
- get variables(): string[] {
571
- - let M = this.clone().clean();
572
- - return Object.keys(M.literal)
573
- + return Object.keys(this._literal).sort()
574
- }
575
- -
576
- - // Display getter
577
- - /**
578
- - * This display getter is to be used in the polynom display getter
579
- - */
580
- - get display(): string {
581
- - let L: string = '',
582
- - letters = Object.keys(this._literal).sort()
583
- - for (let letter of letters) {
584
- - if (!this._literal[letter].isZero()) {
585
- - L += `${letter}`;
586
- - if (!this._literal[letter].isEqualTo(1)) {
587
- - L += `^(${this._literal[letter].display})`;
588
- - }
589
- - }
590
- - }
591
- -
592
- - if (L === '') {
593
- - // No setLetter - means it's only a number !
594
- - if (this._coefficient.value != 0) {
595
- - return `${this._coefficient.display}`;
596
- - } else {
597
- - return '';
598
- - }
599
- - } else {
600
- - if (this._coefficient.value === 1) {
601
- - return L;
602
- - } else if (this._coefficient.value === -1) {
603
- - return `-${L}`;
604
- - } else if (this._coefficient.value === 0) {
605
- - return '0';
606
- - } else {
607
- - return `${this._coefficient.display}${L}`;
608
- - }
609
- - }
610
- - }
611
- -
612
- - get dividers(): Monom[] {
613
- - // Decompose only if the coefficient is a natural number
614
- - if (!this.coefficient.isRelative()) {
615
- - return [this.clone()]
616
- - }
617
- -
618
- -
619
- - // Decompose only if the power values are natural numbers.
620
- - if (this.hasFractionCoefficient()) {
621
- - return [this.clone()]
622
- - }
623
- -
624
- - // Security : do not do this if isGreaterThan than 10000
625
- - if (this.coefficient.numerator > 1000000) {
626
- - return [this.clone()]
627
- - }
628
- -
629
- - const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))
630
- -
631
- - // Decompose the literals parts.
632
- - let literals: literalType[] = [];
633
- - for (let L in this.literal) {
634
- - // L is the letter.
635
- - literals = this._getLiteralDividers(literals, L)
636
- - }
637
- -
638
- - const monomDividers: Monom[] = [];
639
- - if (literals.length > 0 && dividers.length > 0) {
640
- - for (let N of dividers) {
641
- - for (let L of literals) {
642
- - let M = new Monom();
643
- - M.coefficient = this.makeCoefficient(N)
644
- - M.literal = L
645
- - monomDividers.push(M)
646
- - }
647
- - }
648
- - } else if (dividers.length === 0) {
649
- - for (let L of literals) {
650
- - let M = new Monom();
651
- - M.coefficient = this.makeCoefficient().one()
652
- - M.literal = L
653
- - monomDividers.push(M)
654
- - }
655
- - } else {
656
- - for (let N of dividers) {
657
- - let M = new Monom();
658
- - M.coefficient = this.makeCoefficient(N)
659
- - monomDividers.push(M)
660
- - }
661
- - }
662
- -
663
- - return monomDividers.length === 0 ? [new Monom().one()] : monomDividers;
664
- - }
665
- -
666
- - /**
667
- - * Display the monom, forcing the '+' sign to appear
668
- - */
669
- - get displayWithSign(): string {
670
- - let d: String = this.display;
671
- - return (d[0] !== '-' ? '+' : '') + d;
672
- - }
673
- -
674
- - get texWithSign(): string {
675
- - if (this.coefficient.isStrictlyPositive()) {
676
- - return '+' + this.tex
677
- - }
678
- -
679
- - return this.tex
680
- - }
681
- -
682
- - get plotFunction(): string {
683
- -
684
- - let L: string = '',
685
- - letters = Object.keys(this._literal).sort()
686
- -
687
- - for (let letter of letters) {
688
- - if (!this._literal[letter].isZero()) {
689
- - L += (L === '' ? "" : "*") + `${letter}`
690
- - if (!this._literal[letter].isEqualTo(1)) {
691
- - L += `^(${this._literal[letter].display})`;
692
- - }
693
- - }
694
- - }
695
- -
696
- - // No literal part
697
- - if (L === '') {
698
- - // No setLetter - means it's only a number !
699
- - if (this._coefficient.value != 0) {
700
- - return `${this._coefficient.display}`;
701
- - } else {
702
- - return '';
703
- - }
704
- - } else {
705
- - if (this._coefficient.value === 1) {
706
- - return L;
707
- - } else if (this._coefficient.value === -1) {
708
- - return `-${L}`;
709
- - } else if (this._coefficient.value === 0) {
710
- - return '0';
711
- - } else {
712
- - return `${this._coefficient.display}*${L}`;
713
- - }
714
- - }
715
- - }
716
- -
717
- - // ------------------------------------------
718
- - // Creation / parsing functions
719
- -
720
- - /**
721
- - * Get the tex output of the monom
722
- - */
723
- - get tex(): string {
724
- - // TODO: display with square root !
725
- - let L: string = '',
726
- - letters = Object.keys(this._literal).sort()
727
- -
728
- - for (let letter of letters) {
729
- - if (!this._literal[letter].isZero()) {
730
- - L += `${letter}`;
731
- - if (!this._literal[letter].isEqualTo(1)) {
732
- - L += `^{${this._literal[letter].asTopFraction().tex}}`;
733
- - }
734
- - }
735
- - }
736
- -
737
- - if (L === '') {
738
- - // No setLetter - means it's only a number !
739
- - if (this._coefficient.value != 0) {
740
- - return `${this._coefficient.tex}`;
741
- - } else {
742
- - return '0';
743
- - }
744
- - } else {
745
- - if (this._coefficient.value === 1) {
746
- - return L;
747
- - } else if (this._coefficient.value === -1) {
748
- - return `-${L}`;
749
- - } else if (this._coefficient.value === 0) {
750
- - return '0';
751
- - } else {
752
- - return `${this._coefficient.tex}${L}`;
753
- - }
754
- - }
755
- - }
756
- -
757
- - /**
758
- - * Get the least common multiple of monoms
759
- - * @param monoms Array of monoms
760
- - */
761
- - static lcm = (...monoms: Monom[]): Monom => {
762
- - // All the monoms must be with natural powers...
763
- - for (let m of monoms) {
764
- - if (m.hasFractionCoefficient()) {
765
- - return new Monom().zero()
766
- - }
767
- - }
768
- -
769
- -
770
- - let M = new Monom(),
771
- - coeffN: number[] = monoms.map(value => value.coefficient.numerator),
772
- - coeffD: number[] = monoms.map(value => value.coefficient.denominator),
773
- - n = Numeric.gcd(...coeffN),
774
- - d = Numeric.lcm(...coeffD);
775
- -
776
- - // Get the coefficient.
777
- - M.coefficient = this.makeCoefficient(n, d).reduce();
778
- -
779
- - // Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.
780
- - for (let m of monoms) {
781
- - // Remove the inexistant letters from the resulting monom
782
- - for (let letter in M.literal) {
783
- - if (!(letter in m.literal)) {
784
- - M.literal[letter].zero();
785
- - }
786
- - }
787
- - for (let letter in m.literal) {
788
- - if (M.literal[letter] === undefined && m.literal[letter].isStrictlyPositive()) {
789
- - M.literal[letter] = m.literal[letter].clone();
790
- - } else {
791
- - M.literal[letter] = this.makeCoefficient(Math.min(m.literal[letter].value, M.literal[letter].value))
792
- - }
793
- - }
794
- - }
795
- -
796
- - return M;
797
- - };
798
- -
799
- - /**
800
- - * Multiply two monoms and return a NEW monom.
801
- - * @param monoms
802
- - */
803
- - static xmultiply = (...monoms: Monom[]): Monom => {
804
- - let M = new Monom().one();
805
- -
806
- - for (let m of monoms) {
807
- - M.multiply(m);
808
- - }
809
-
810
- - return M;
811
- - };
812
- -
813
- - makeCoefficient = (...values: CoefficientParserTypes[]): CoefficientTypes => {
814
- - if (this._coefficientMode === COEFFICIENT_MODE.FRACTION) {
815
- - return new Fraction(...values as (Fraction | string | number)[])
816
- - } else if (this._coefficientMode === COEFFICIENT_MODE.ROOT) {
817
- - return new RootFraction(...values as (RootFraction | Fraction | string | number)[])
818
- - }
819
- + get literal(): expressionElementInterface {
820
- + return this._literal;
821
- + }
822
-
823
- - // TODO: add the other modes
824
- - return new Fraction(...values as (Fraction | string | number)[])
825
- + set literal(value: expressionElementInterface) {
826
- + this._literal = value;
827
- }
828
-
829
- -// -----------------------------------------
830
- - /**
831
- - * Parse a string to a monom. The string may include fraction.
832
- - * @param inputStr
833
- - */
834
- - parse = (inputStr: unknown): Monom => {
835
- + private _coefficient: Coefficient = new Coefficient()
836
-
837
- - if (typeof inputStr === 'string') {
838
- - this._shutingYardToReducedMonom(inputStr)
839
- - } else if (typeof inputStr === 'number') {
840
- - this._coefficient = this.makeCoefficient(inputStr)
841
- - this._literal = {}
842
- - } else if (inputStr instanceof Fraction) {
843
- - this._coefficient = inputStr.clone()
844
- - this._literal = {}
845
- - } else if (inputStr instanceof RootFraction) {
846
- - this._coefficient = inputStr.clone()
847
- - this._literal = {}
848
- - } else if (inputStr instanceof Monom) {
849
- - this._coefficient = inputStr._coefficient.clone()
850
- - this._literal = this.copyLiterals(inputStr.literal)
851
- - }
852
- + get coefficient(): Coefficient {
853
- + return this._coefficient;
854
- + }
855
-
856
- - return this;
857
- - };
858
- -
859
- - addToken = (stack: Monom[], element: Token): void => {
860
- -
861
- - let q1: Monom, q2: Monom, m: Monom, letter: string, pow: CoefficientCore<any>
862
- -
863
- - if (element.tokenType === ShutingyardType.COEFFICIENT) {
864
- - stack.push(new Monom(this.makeCoefficient(element.token)))
865
- -
866
- - } else if (element.tokenType === ShutingyardType.VARIABLE) {
867
- - let M = new Monom().one()
868
- - M.setLetter(element.token, 1)
869
- - stack.push(M.clone())
870
- -
871
- - } else if (element.tokenType === ShutingyardType.OPERATION) {
872
- - switch (element.token) {
873
- - case '-':
874
- - // this should only happen for negative powers or for negative coefficient.
875
- - q2 = (stack.pop()) || new Monom().zero()
876
- - q1 = (stack.pop()) || new Monom().zero()
877
- -
878
- - stack.push(q1.subtract(q2))
879
- -
880
- - break;
881
- - case '*':
882
- - // Get the last element in the stack
883
- - q2 = (stack.pop()) || new Monom().one()
884
- - q1 = (stack.pop()) || new Monom().one()
885
- -
886
- - stack.push(q1.multiply(q2))
887
- - break
888
- - case '/':
889
- - // Get the last element in the stack
890
- - q2 = (stack.pop()) || new Monom().one()
891
- - q1 = (stack.pop()) || new Monom().one()
892
- -
893
- - stack.push(q1.divide(q2))
894
- - break
895
- - case '^':
896
- - // get the two last elements in the stack
897
- - pow = (stack.pop().coefficient) || this.makeCoefficient().one()
898
- - m = (stack.pop()) || new Monom().one()
899
- -
900
- - letter = m.variables[0]
901
- -
902
- - if (letter !== undefined) {
903
- - m.setLetter(letter, pow)
904
- - }
905
- -
906
- - stack.push(m)
907
- - // this.multiply(m.clone())
908
- - break
909
- - }
910
- - }
911
- + set coefficient(value: Coefficient) {
912
- + this._coefficient = value;
913
- }
914
-
915
- - /**
916
- - * Clone the current Monom.
917
- - */
918
- - clone = (): Monom => {
919
- - let F: Monom = new Monom();
920
- + add(...values: Monom[]): this {
921
- + if (values.length === 0) return this
922
-
923
- - F.coefficient = this._coefficient.clone();
924
- -
925
- - // Copy the literal parts.
926
- - for (let k in this._literal) {
927
- - F.setLetter(k, this._literal[k].clone());
928
- + // Check that all the monoms are similar.
929
- + if (!values.every(x => this.isSimilarTo(x))) {
930
- + throw new Error('The monoms are not similar.')
931
- }
932
- - return F;
933
- - };
934
-
935
- - copyLiterals = (literal: literalType): literalType => {
936
- - let L: literalType = {}
937
- + // Add the coefficients.
938
- + this._coefficient.add(...values.map(x => x.coefficient))
939
-
940
- - for (let k in literal) {
941
- - L[k] = literal[k].clone()
942
- - }
943
- - return L
944
- - }
945
- -
946
- - makeSame = (M: Monom): Monom => {
947
- - // Copy the literal parts.
948
- - for (let k in M._literal) {
949
- - this.setLetter(k, M._literal[k].clone());
950
- - }
951
- return this
952
- }
953
-
954
- - /**
955
- - * Create a zero value monom
956
- - */
957
- - zero = (): Monom => {
958
- - this._coefficient = this.makeCoefficient().zero();
959
- - this._literal = {};
960
- - return this;
961
- - };
962
- + subtract(...values: Monom[]): this {
963
- + return this.add(...values.map(x => x.opposite()))
964
- + }
965
- +
966
- + multiply(...values: Monom[]): this {
967
- + return this
968
- + }
969
- +
970
- + divide(value: Monom): this {
971
- + return this
972
- + }
973
-
974
- - /**
975
- - * Create a one value monom
976
- - */
977
- - one = (): Monom => {
978
- - this._coefficient = this.makeCoefficient().one();
979
- - this._literal = {};
980
- - return this;
981
- - };
982
- + opposite(): this {
983
- + this._coefficient.opposite()
984
- + return this
985
- + }
986
-
987
- -// ------------------------------------------
988
- -// Mathematical operations
989
- -// ------------------------------------------
990
- + invert(): this {
991
- + return this
992
- + }
993
-
994
- - /**
995
- - * Clean the monom by removing each letters with a power of zero.
996
- - */
997
- - clean = (): Monom => {
998
- - for (let letter in this._literal) {
999
- - if (this._literal[letter].isZero()) {
1000
- - delete this._literal[letter];
1001
- - }
1002
- - }
1003
- - return this;
1004
- - };
1005
- + pow(value: number): this {
1006
- + return this
1007
- + }
1008
- +
1009
- + root(value: number): this {
1010
- + return this
1011
- + }
1012
-
1013
- - reduce = (): Monom => {
1014
- - this.clean()
1015
- - this.coefficient.reduce()
1016
- + reduce(): this {
1017
- return this
1018
- }
1019
-
1020
- - /**
1021
- - * Get the opposite
1022
- - * Returns a monom.
1023
- - */
1024
- - opposed = (): Monom => {
1025
- - this._coefficient.opposite();
1026
- - return this;
1027
- - };
1028
- -
1029
- - /**
1030
- - * Add all similar monoms. If they aren't similar, they are simply skipped.
1031
- - * @param M (Monom[]) The monoms to add.
1032
- - */
1033
- - add = (...M: Monom[]): Monom => {
1034
- - for (let m of M) {
1035
- - if (this.isSameAs(m)) {
1036
- - if (this.isZero()) {
1037
- - this.makeSame(m)
1038
- - }
1039
- - this._coefficient.add(m.coefficient);
1040
- - } else {
1041
- - console.log('Add monom: ' + this.display + ' is not similar with ', m.display);
1042
- - }
1043
- - }
1044
- - return this;
1045
- - };
1046
- -
1047
- - /**
1048
- - * Subtract multiple monoms
1049
- - * @param M (Monom[]) The monoms to subtract
1050
- - */
1051
- - subtract = (...M: Monom[]): Monom => {
1052
- - for (let m of M) {
1053
- - if (this.isSameAs(m)) {
1054
- - if (this.isZero()) {
1055
- - this.makeSame(m)
1056
- - }
1057
- - this._coefficient.add(m.clone().coefficient.opposite());
1058
- - } else {
1059
- - console.log('Subtract: Is not similar: ', m.display);
1060
- - }
1061
- - }
1062
- - return this;
1063
- - };
1064
- -
1065
- - /**
1066
- - * Multiple multiple monoms to the current monom
1067
- - * @param M (Monom[]) The monoms to multiply to.
1068
- - */
1069
- - multiply = (...M: Monom[]): Monom => {
1070
- - for (let m of M) {
1071
- - // Multiply the coefficient.
1072
- - this._coefficient.multiply(m.coefficient);
1073
- -
1074
- - // Multiply the literal parts.
1075
- - for (let letter in m.literal) {
1076
- - if (this._literal[letter] === undefined) {
1077
- - this._literal[letter] = m.literal[letter].clone()
1078
- - } else {
1079
- - this._literal[letter].add(m.literal[letter])
1080
- - }
1081
- -
1082
- - }
1083
- - }
1084
- - return this;
1085
- - };
1086
- -
1087
- - multiplyByNumber = (F: Fraction | number): Monom => {
1088
- - this._coefficient.multiply(F);
1089
- - return this;
1090
- - }
1091
- -
1092
- - /**
1093
- - * Divide the current monoms by multiple monoms
1094
- - * @param M (Monom[])
1095
- - */
1096
- - divide = (...M: Monom[]): Monom => {
1097
- - // Depending on the given value, choose the current item
1098
- - for (let v of M) {
1099
- - // Divide the coefficient
1100
- - this._coefficient.divide(v.coefficient);
1101
- + isSimilarTo(value: Monom): boolean {
1102
- + // To be similar, the variables must be similar.
1103
- + // The coefficient can be different.
1104
-
1105
- - // Subtract the power values
1106
- - for (let letter in v.literal) {
1107
- - this._literal[letter] = (this._literal[letter] === undefined) ? v.literal[letter].clone().opposite() : this._literal[letter].subtract(v.literal[letter])
1108
- + // They must have the same number of variables.
1109
- + if (this.variables.length !== (value as Monom).variables.length) return false
1110
-
1111
- - // If the power of a particular setLetter is zero, delete it from the literal part..
1112
- - if (this._literal[letter].isZero()) {
1113
- - delete this._literal[letter];
1114
- - }
1115
- - }
1116
- - }
1117
- - return this;
1118
- - };
1119
- + // They must have the same variables.
1120
- + if (this.variables.every(x => (value as Monom).variables.includes(x))) return false
1121
-
1122
- - /**
1123
- - * Get the pow of a monom.
1124
- - * @param nb (number) : Mathematical pow
1125
- - */
1126
- - pow = (nb: number | Fraction): Monom => {
1127
- - this._coefficient.pow(nb);
1128
- - for (let letter in this._literal) {
1129
- - this._literal[letter].multiply(nb)
1130
- - }
1131
- - return this;
1132
- - };
1133
- -
1134
- -// ------------------------------------------
1135
- -// Compare functions
1136
- -
1137
- - /**
1138
- - * Get the index-root of the monom
1139
- - * @param p
1140
- - */
1141
- - root = (p: number): Monom => {
1142
- - // TODO: determiner the index root of a monom
1143
- - return this;
1144
- - }
1145
- -
1146
- - /**
1147
- - * Return the square root of a monom
1148
- - */
1149
- - sqrt = (): Monom => {
1150
- - if (this.isSquare()) {
1151
- - this._coefficient.sqrt();
1152
- - for (let letter in this._literal) {
1153
- - this._literal[letter].clone().divide(2)
1154
- - }
1155
- - }
1156
- - return this.root(2);
1157
- - }
1158
- -
1159
- -// ------------------------------------------
1160
- - compare = (M: Monom, sign?: COMPARESIGNS): boolean => {
1161
- - // TODO: Build the compare systems.
1162
- - if (sign === undefined) {
1163
- - sign = COMPARESIGNS.EQUALS;
1164
- - }
1165
- -
1166
- -
1167
- - switch (sign) {
1168
- - case COMPARESIGNS.EQUALS:
1169
- - // To be equal, they must be the isSame
1170
- - if (!this.compare(M, COMPARESIGNS.SAME)) {
1171
- - return false;
1172
- - }
1173
- -
1174
- - // The literal parts are the isSame. The coefficient must be equal
1175
- - return this._coefficient.isEqualTo(M.coefficient);
1176
- - case COMPARESIGNS.SAME:
1177
- - // Get the list of all variables from both monoms.
1178
- - let M1: string[] = this.variables,
1179
- - M2: string[] = M.variables,
1180
- - K: string[] = M1.concat(M2.filter((item) => M1.indexOf(item) < 0));
1181
- -
1182
- - if (M1.length === 0 && M2.length === 0) {
1183
- - return true
1184
- - }
1185
- - // To compare, both must be different than zero.
1186
- - if (!this.isZero() && !M.isZero()) {
1187
- - for (let key of K) {
1188
- - // The setLetter is not available in one of the monom
1189
- - if (this._literal[key] === undefined || M.literal[key] === undefined) {
1190
- - return false;
1191
- - }
1192
- - // The setLetter does not have the isSame power in each monoms.
1193
- - if (!this._literal[key].isEqualTo(M.literal[key])) {
1194
- - return false;
1195
- - }
1196
- - }
1197
- - }
1198
- -
1199
- - // All are positive check - the monoms are the sames.
1200
- - return true;
1201
- - default:
1202
- - return false;
1203
- - }
1204
- + return true
1205
- }
1206
- -
1207
- - /**
1208
- - * Determine if the monom is null
1209
- - */
1210
- - isZero()
1211
- - :
1212
- - boolean {
1213
- - return this._coefficient.value === 0;
1214
- - }
1215
- -
1216
- - /**
1217
- - * Determine if the monom is one
1218
- - */
1219
- - isOne()
1220
- - :
1221
- - boolean {
1222
- - return this._coefficient.value === 1 && this.variables.length === 0;
1223
- - }
1224
- -
1225
- - /**
1226
- - * Determine if two monoms are equals
1227
- - * @param M
1228
- - */
1229
- - isEqual = (M: Monom): boolean => {
1230
- - return this.compare(M, COMPARESIGNS.EQUALS);
1231
- - };
1232
-
1233
- - /**
1234
- - * Determine if two monoms are similar
1235
- - * @param M
1236
- - */
1237
- - isSameAs = (M: Monom): boolean => {
1238
- - return this.compare(M, COMPARESIGNS.SAME);
1239
- - };
1240
- -
1241
- - isSquare = (): boolean => {
1242
- - if (!this.coefficient.isSquare()) {
1243
- - return false;
1244
- - }
1245
- - return this.isLiteralSquare();
1246
- - }
1247
- -// ------------------------------------------
1248
- -// Misc monoms functions
1249
- -
1250
- - isLiteralSquare = (): boolean => {
1251
- - for (let letter in this.literal) {
1252
- - // A literal square must have a natural power
1253
- - if (this.literal[letter].isRational()) {
1254
- - return false
1255
- - }
1256
- + isEqualTo(value: unknown): boolean {
1257
- + return false
1258
- + }
1259
-
1260
- - // The natural power must be be even
1261
- - if (this.literal[letter].isEven()) {
1262
- - return false;
1263
- - }
1264
- - }
1265
- -
1266
- - return true;
1267
- - }
1268
- -
1269
- - hasFractionCoefficient = (): boolean => {
1270
- - for (let letter in this._literal) {
1271
- - if (this._literal[letter].isRational()) {
1272
- - return true
1273
- - }
1274
- - }
1275
- -
1276
- + isReduced(): boolean {
1277
- return false
1278
- }
1279
-
1280
- -// -------------------------------------
1281
- - /**
1282
- - * Determine if a monom contains a setLetter in it's literal part
1283
- - * @param letter
1284
- - */
1285
- - hasLetter = (letter?: string): boolean => {
1286
- - // The letter was not found
1287
- - if (this._literal[letter === undefined ? 'x' : letter] === undefined) {
1288
- - return false
1289
- - }
1290
- + isOne(): boolean {
1291
- + return false
1292
- + }
1293
-
1294
- - // The letter is found and is not zero !
1295
- - return !this._literal[letter === undefined ? 'x' : letter].isZero();
1296
- - };
1297
- -
1298
- - /**
1299
- - * Set the power of a particular setLetter
1300
- - * @param letter (string) Letter to change
1301
- - * @param pow (number) Power of the setLetter (must be positive integer.
1302
- - */
1303
- - setLetter = (letter: string, pow: CoefficientCore<any> | number): void => {
1304
- - if (pow instanceof CoefficientCore) {
1305
- - // Set the power of the letter to zero => remove it
1306
- - if (this.hasLetter(letter) && pow.isZero()) {
1307
- - delete this._literal[letter]
1308
- - }
1309
- -
1310
- - this._literal[letter] = pow.clone()
1311
- - } else {
1312
- - this.setLetter(letter, this.makeCoefficient(pow))
1313
- - }
1314
- - };
1315
- -
1316
- - /**
1317
- - * Get the degree of a monom. If no setLetter is given, the result will be the global degree.
1318
- - * @param letter (string) Letter to get to degree (power)
1319
- - */
1320
- - degree = (letter?: string): CoefficientTypes => {
1321
- - if (this.variables.length === 0) {
1322
- - return this.makeCoefficient().zero();
1323
- - }
1324
- - if (letter === undefined) {
1325
- - // Not setLetter given -> we get the global monom degree (sum of all the letters).
1326
- - return Object.values(this._literal)
1327
- - .reduce(
1328
- - (t, n) => t.clone().add(n)
1329
- - );
1330
- - } else {
1331
- - // A setLetter is given -> get the corresponding power.
1332
- - return this._literal[letter] === undefined ? this.makeCoefficient().zero() : this._literal[letter].clone();
1333
- - }
1334
- - };
1335
- -
1336
- - /**
1337
- - * Evaluate a monom. Each setLetter must be assigned to a Fraction.
1338
- - * @param values Dictionary of <setLetter: Fraction>
1339
- - */
1340
- - evaluate = (values?: literalType | Fraction | number): CoefficientCore<any> => {
1341
- - let r = this.coefficient.clone();
1342
- -
1343
- - if (typeof values === 'number' || values instanceof Fraction) {
1344
- - let tmpValues: literalType = {}
1345
- - tmpValues[this.variables[0]] = this.makeCoefficient(values)
1346
- - return this.evaluate(tmpValues);
1347
- - }
1348
- -
1349
- - if (typeof values === 'object') {
1350
- - if (this.variables.length === 0) {
1351
- - return this.coefficient
1352
- - }
1353
- - for (let L in this._literal) {
1354
- - if (values[L] === undefined) {
1355
- - return this.makeCoefficient().zero();
1356
- - }
1357
- -
1358
- - let value = this.makeCoefficient(values[L])
1359
- -
1360
- - r.multiply(value.pow(this._literal[L]))
1361
- - }
1362
- - }
1363
- -
1364
- - return r;
1365
- - };
1366
- -
1367
- - evaluateAsNumeric = (values: { [Key: string]: number } | number): number => {
1368
- - let r = this.coefficient.value
1369
- -
1370
- - if (typeof values === 'number') {
1371
- - let tmpValues: { [Key: string]: number } = {}
1372
- - tmpValues[this.variables[0]] = values
1373
- - return this.evaluateAsNumeric(tmpValues);
1374
- - }
1375
- -
1376
- - if (typeof values === 'object') {
1377
- - if (this.variables.length === 0) {
1378
- - return this.coefficient.value
1379
- - }
1380
- - for (let L in this._literal) {
1381
- - if (values[L] === undefined) {
1382
- - return 0;
1383
- - }
1384
- -
1385
- - r *= values[L] ** (this._literal[L].value)
1386
- - }
1387
- - }
1388
- -
1389
- - return r
1390
- - }
1391
- -// ----------------------------------------
1392
- -// Static functions
1393
- -// ----------------------------------------
1394
- -
1395
- - /**
1396
- - * Derivative the monom
1397
- - * @param letter
1398
- - */
1399
- - derivative = (letter?: string): Monom => {
1400
- - // No setLetter given - assume it's the setLetter 'x'
1401
- - if (letter === undefined) {
1402
- - letter = 'x';
1403
- - }
1404
- -
1405
- - if (this.hasLetter(letter)) {
1406
- - let d = this._literal[letter].clone(),
1407
- - dM = this.clone();
1408
- -
1409
- - // Subtract one to the degree.
1410
- - dM._literal[letter].subtract(1)
1411
- -
1412
- - // Multiply the coefficient by the previous degree
1413
- - dM._coefficient.multiply(this.makeCoefficient(d.clone()));
1414
- - return dM;
1415
- - } else {
1416
- - return new Monom().zero();
1417
- - }
1418
- - };
1419
- -
1420
- - primitive = (letter?: string): Monom => {
1421
- - // TODO: derivative including the ln value => implies creating different monom system ?
1422
- - if (letter === undefined) {
1423
- - letter = 'x'
1424
- - }
1425
- -
1426
- - // Zero monom
1427
- - let M = this.clone(), degree
1428
- -
1429
- - if (M.hasLetter(letter)) {
1430
- - degree = M.degree(letter).clone().add(1)
1431
- - M.coefficient = M.coefficient.clone().divide(degree)
1432
- - M.setLetter(letter, degree)
1433
- - } else {
1434
- - // There is no letter.
1435
- -
1436
- - // The coefficient might be zero (=> x) or a number a (=> ax)
1437
- - if (M.coefficient.isZero()) {
1438
- - M.coefficient = this.makeCoefficient().one()
1439
- - }
1440
- - M.setLetter(letter, 1)
1441
- - }
1442
- -
1443
- - return M
1444
- - }
1445
- -
1446
- -// TODO: The rest of the functions are not used or unnecessary ?
1447
- - /**
1448
- - * Determine if multiple monoms are similar
1449
- - * @param M
1450
- - */
1451
- - areSameAs = (...M: Monom[]): boolean => {
1452
- - let result: boolean = true;
1453
- -
1454
- - // Check all monoms if they are the isSame as the "this" one.
1455
- - for (let i = 0; i < M.length; i++) {
1456
- - if (!this.isSameAs(M[i])) {
1457
- - return false;
1458
- - }
1459
- - }
1460
- -
1461
- - // All check passed -> all the monoms are similar.
1462
- - return result;
1463
- - };
1464
- -
1465
- - /**
1466
- - * Determine if multiple monoms are equals
1467
- - * @param M
1468
- - */
1469
- - areEquals = (...M: Monom[]): boolean => {
1470
- - // They are not similar.
1471
- - if (!this.areSameAs(...M)) {
1472
- - return false;
1473
- - }
1474
- -
1475
- - // Check all coefficient. They must be equals.
1476
- - for (let m of M) {
1477
- - if (!this._coefficient.isEqualTo(m.coefficient)) {
1478
- - return false;
1479
- - }
1480
- - }
1481
- -
1482
- - // All checks passed.
1483
- - return true;
1484
- - };
1485
- -
1486
- - isDivisible = (div: Monom): boolean => {
1487
- - // For all variables (letters), the current monom must have a degree higher than the divider
1488
- - if (div.degree().isStrictlyPositive()) {
1489
- - for (let letter of div.variables) {
1490
- - if (!this.degree(letter).isGreaterOrEqualTo(div.degree(letter))) {
1491
- - return false
1492
- - }
1493
- - }
1494
- - }
1495
- -
1496
- - // If the coefficient is rational, we suppose we don't need to check the division by the coefficient.
1497
- - if (this.coefficient.isRational() || div.coefficient.isRational()) {
1498
- - return true
1499
- - }
1500
- -
1501
- - return this.coefficient.clone().divide(div.coefficient).isRelative()
1502
- + isMinusOne(): boolean {
1503
- + return false
1504
- }
1505
-
1506
- - isInverted(M
1507
- - :
1508
- - Monom
1509
- - ):
1510
- - boolean {
1511
- - return this.clone().multiply(M).isOne();
1512
- + isUnit(): boolean {
1513
- + return false
1514
- }
1515
-
1516
- - isNegativeOne()
1517
- - :
1518
- - boolean {
1519
- - return this._coefficient.value === -1 && this.variables.length === 0;
1520
- + isZero(): boolean {
1521
- + return false
1522
- }
1523
-
1524
- - isNotEqual(M
1525
- - :
1526
- - Monom
1527
- - ):
1528
- - boolean {
1529
- - return !this.isEqual(M);
1530
- - }
1531
- + clone(): Monom {
1532
-
1533
- - isNotZero()
1534
- - :
1535
- - boolean {
1536
- - return !this.isZero();
1537
- - }
1538
- + const m = new Monom()
1539
-
1540
- - isOpposed(M
1541
- - :
1542
- - Monom
1543
- - ):
1544
- - boolean {
1545
- - return this.clone().subtract(M).isZero();
1546
- - }
1547
- + m.coefficient = this.coefficient.clone()
1548
- + for (let v of this.variables) {
1549
- + m.literal[v] = this.literal[v]
1550
- + }
1551
-
1552
- - isReduced()
1553
- - :
1554
- - boolean {
1555
- - // By construction, it is already reduced (litterals
1556
- - return this.coefficient.isReduced();
1557
- + return m
1558
- }
1559
-
1560
- - reset()
1561
- - :
1562
- - any {
1563
- - this._coefficient = this.makeCoefficient()
1564
- + private reset() {
1565
- + this._coefficient = new Coefficient().zero()
1566
- this._literal = {}
1567
- }
1568
-
1569
- - _getLiteralDividers(arr: literalType[], letter: string):
1570
- - literalType[] {
1571
- - let tmpList: { [key: string]: CoefficientTypes }[] = [];
1572
- + private parse(...values: unknown[]): Monom {
1573
- + this.reset()
1574
-
1575
- - // Be default, this.literal[letter] should be a rational number.
1576
- - for (let d = 0; d <= this.literal[letter].value; d++) {
1577
- - if (arr.length === 0) {
1578
- - let litt: literalType = {}
1579
- - litt[letter] = this.makeCoefficient(d)
1580
- - tmpList.push(litt)
1581
- - } else {
1582
- - for (let item of arr) {
1583
- - let litt: literalType = {}
1584
- - for (let currentLetter in item) {
1585
- - litt[currentLetter] = item[currentLetter]
1586
- - }
1587
- - litt[letter] = this.makeCoefficient(d)
1588
- - tmpList.push(litt)
1589
- - }
1590
- + // Parse the values.
1591
- + if (values.length === 1) {
1592
- + if (values[0] instanceof Monom) {
1593
- + return values[0].clone()
1594
- }
1595
- - }
1596
- - return tmpList;
1597
- - }
1598
-
1599
- - _shutingYardToReducedMonom = (inputStr: string): Monom => {
1600
- - // Get the RPN array of the current expression
1601
- - const SY: Shutingyard = new Shutingyard().parse(inputStr);
1602
- - const rpn: { token: string, tokenType: string }[] = SY.rpn;
1603
- -
1604
- - let stack: Monom[] = []
1605
- -
1606
- - if (rpn.length === 0) {
1607
- - this.zero()
1608
- - return this
1609
- - } else if (rpn.length === 1) {
1610
- - const element = rpn[0]
1611
- -
1612
- - this.one()
1613
- - if (element.tokenType === 'coefficient') {
1614
- - this.coefficient = this.makeCoefficient(element.token)
1615
- - } else if (element.tokenType === 'variable') {
1616
- - this.setLetter(element.token, 1)
1617
- - }
1618
- - return this
1619
- - } else {
1620
- - // Reset the monom
1621
- - for (const element of rpn) {
1622
- - this.addToken(stack, element)
1623
- + if (typeof values[0] === "string") {
1624
- + // Parse the string to get the coefficient and the literal.
1625
- }
1626
- - }
1627
-
1628
- - this.one()
1629
- - this.multiply(stack[0])
1630
- - return this
1631
- - }
1632
- -}
1633
- + if (typeof values[0] === "number") {
1634
- + // Parse the number to get the coefficient and the literal.
1635
- + this._coefficient = new Coefficient(values[0])
1636
- + return this
1637
- + }
1638
- + }
1639
- +
1640
- + return this;
1641
- + }
1642
- +}
1643
-
1644
- Index: tests/coefficients/fraction.test.ts
1645
- IDEA additional info:
1646
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
1647
- <+>import {expect} from \"chai\";\r\nimport {Fraction} from \"../../src/maths/coefficients/fraction\";\r\nimport {describe} from \"mocha\";\r\nimport {Random} from \"../../src/maths/randomization/random\";\r\n\r\ndescribe('Fraction tests', () => { // the tests container\r\n it(\"should parse correctly\", () => {\r\n const F1 = new Fraction('1/2')\r\n expect(F1.display).to.be.equal('1/2')\r\n\r\n const F2 = new Fraction('1.5')\r\n expect(F2.display).to.be.equal('3/2')\r\n\r\n const F2n = new Fraction(1.5)\r\n expect(F2n.display).to.be.equal('3/2')\r\n\r\n const F3 = new Fraction('-1.5')\r\n expect(F3.display).to.be.equal('-3/2')\r\n\r\n const F4 = new Fraction('1.5/2')\r\n expect(F4.display).to.be.equal('3/4')\r\n\r\n const F5 = new Fraction('1.5/2.5')\r\n expect(F5.display).to.be.equal('3/5')\r\n\r\n const F6 = new Fraction(3, 5)\r\n expect(F6.display).to.be.equal('3/5')\r\n\r\n const F7 = new Fraction(0.5, 1.5)\r\n expect(F7.display).to.be.equal('1/3')\r\n })\r\n\r\n it('Tex display', () => { // the single test\r\n const options = new Fraction(2, 5); // this will be your class\r\n expect(options.tex).to.be.equal('\\\\frac{ 2 }{ 5 }');\r\n });\r\n\r\n it('Compare: equals', () => {\r\n let F = new Fraction(1, 3),\r\n Q = new Fraction(2, 6),\r\n P = new Fraction(2, 5);\r\n expect(F.isEqualTo(Q)).to.be.true;\r\n expect(F.isEqualTo(P)).to.be.false;\r\n })\r\n\r\n it('Operation: sum of two fraction', () => {\r\n let F = new Fraction(1, 3),\r\n Q = new Fraction(2, 7);\r\n\r\n F.add(Q);\r\n\r\n expect(F.numerator).to.be.equal(13);\r\n expect(F.denominator).to.be.equal(21);\r\n })\r\n\r\n it('Operation: subtract of two fraction', () => {\r\n let F = new Fraction(1, 3),\r\n Q = new Fraction(2, 7);\r\n\r\n F.subtract(Q);\r\n\r\n expect(F.numerator).to.be.equal(1);\r\n expect(F.denominator).to.be.equal(21);\r\n })\r\n\r\n it('Reduced', () => {\r\n let F = new Fraction(2, 5),\r\n Q = new Fraction(2, 6)\r\n\r\n expect(F.isReduced()).to.be.true\r\n expect(Q.isReduced()).to.be.false\r\n })\r\n\r\n // TODO: fix this test\r\n // it('Should parse a number with lots of decimals', () => {\r\n // let A = 3.45,\r\n // B = 3.3333333333333,\r\n // C = 5.314171717171717\r\n //\r\n // let FA = new Fraction(A),\r\n // FB = new Fraction(B, 1),\r\n // FC = new Fraction(C, 2)\r\n //\r\n // expect(FA.display).to.be.equal('69/20')\r\n // expect(FB.display).to.be.equal('10/3')\r\n // expect(FC.display).to.be.equal('526103/99000')\r\n // })\r\n})\r\n\r\ndescribe(\"Fraction static functions\", () => {\r\n it('should sort fractions', function () {\r\n let list = [\r\n new Fraction('3.5'),\r\n new Fraction('-2.5'),\r\n new Fraction('3.1'),\r\n new Fraction('3.54'),\r\n new Fraction('1.5')\r\n ]\r\n\r\n expect(Fraction.sort(list).map(x => x.value)).to.have.all.members([-2.5, 1.5, 3.1, 3.5, 3.54])\r\n });\r\n\r\n it('should make a list of fractions unique', function () {\r\n let list = [\r\n new Fraction('3.5'),\r\n new Fraction('-2.5'),\r\n new Fraction('7/2'),\r\n new Fraction('3.50'),\r\n new Fraction('1.5')\r\n ]\r\n\r\n expect(Fraction.unique(list, true).map(x => x.value)).to.have.ordered.members([-2.5, 1.5, 3.5])\r\n });\r\n\r\n it('should get the average of fractions', function () {\r\n let list = [\r\n new Fraction('3.5'),\r\n new Fraction('-2.5'),\r\n new Fraction('7/2'),\r\n new Fraction('3.50'),\r\n new Fraction('1.5')\r\n ]\r\n\r\n expect(Fraction.average(...list).tex).to.be.equal('\\\\frac{ 19 }{ 10 }')\r\n })\r\n\r\n it('should multiply and not reduce', function () {\r\n let list = [\r\n new Fraction('1/2'),\r\n new Fraction('4/3'),\r\n 2.5,\r\n 3\r\n ]\r\n\r\n expect(new Fraction().multiply(...list).display).to.be.equal(\"60/12\")\r\n });\r\n\r\n it('should divide', () => {\r\n const f1 = new Fraction('1/2'),\r\n f2 = new Fraction('4/3')\r\n\r\n expect(f1.divide(f2).display).to.be.equal('3/8')\r\n })\r\n})\r\n\r\ndescribe(\"Evaluate fraction\", () => {\r\n it('should evaluate and convert to decimal if not exact', function () {\r\n let F = new Fraction(Math.sqrt(2))\r\n\r\n expect(F.isApproximative()).to.be.true\r\n expect(F.isExact()).to.be.false\r\n\r\n let G = new Fraction('1/7')\r\n expect(G.isApproximative()).to.be.false\r\n expect(G.isExact()).to.be.true\r\n });\r\n})\r\n\r\ndescribe('Generate a random fraction', () => {\r\n it('should generate a non natural fraction', function () {\r\n let F, result = true\r\n\r\n for (let i = 0; i < 100; i++) {\r\n F = Random.fraction()\r\n if (!F.isRelative()) {\r\n result = false\r\n break\r\n }\r\n }\r\n expect(F.isNatural()).to.be.false;\r\n });\r\n})
1648
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
1649
- <+>UTF-8
1650
- ===================================================================
1651
- diff --git a/tests/coefficients/fraction.test.ts b/tests/coefficients/fraction.test.ts
1652
- --- a/tests/coefficients/fraction.test.ts
1653
- +++ b/tests/coefficients/fraction.test.ts
1654
- @@ -1,7 +1,6 @@
1655
- import {expect} from "chai";
1656
- import {Fraction} from "../../src/maths/coefficients/fraction";
1657
- import {describe} from "mocha";
1658
- -import {Random} from "../../src/maths/randomization/random";
1659
-
1660
- describe('Fraction tests', () => { // the tests container
1661
- it("should parse correctly", () => {
1662
- @@ -155,18 +154,18 @@
1663
- expect(G.isExact()).to.be.true
1664
- });
1665
- })
1666
- -
1667
- -describe('Generate a random fraction', () => {
1668
- - it('should generate a non natural fraction', function () {
1669
- - let F, result = true
1670
- -
1671
- - for (let i = 0; i < 100; i++) {
1672
- - F = Random.fraction()
1673
- - if (!F.isRelative()) {
1674
- - result = false
1675
- - break
1676
- - }
1677
- - }
1678
- - expect(F.isNatural()).to.be.false;
1679
- - });
1680
- -})
1681
-
1682
- +//
1683
- +// describe('Generate a random fraction', () => {
1684
- +// it('should generate a non natural fraction', function () {
1685
- +// let F, result = true
1686
- +//
1687
- +// for (let i = 0; i < 100; i++) {
1688
- +// F = Random.fraction()
1689
- +// if (!F.isRelative()) {
1690
- +// result = false
1691
- +// break
1692
- +// }
1693
- +// }
1694
- +// expect(F.isNatural()).to.be.false;
1695
- +// });
1696
- +// })
1697
-
1698
- Index: src/maths/coefficients/rootFraction.ts
1699
- ===================================================================
1700
- diff --git a/src/maths/coefficients/rootFraction.ts b/src/maths/coefficients/coefficientElement.ts
1701
- rename from src/maths/coefficients/rootFraction.ts
1702
- rename to src/maths/coefficients/coefficientElement.ts
1703
- --- a/src/maths/coefficients/rootFraction.ts
1704
- +++ b/src/maths/coefficients/coefficientElement.ts
1705
- @@ -1,26 +1,44 @@
1706
- import {Fraction} from "./fraction";
1707
- -import {CoefficientCore} from "./coefficientCore";
1708
- +import {COEFFICIENT_EXTRA, CoefficientCore, CoefficientParserTypes} from "./coefficientCore";
1709
-
1710
- /**
1711
- * RootFraction is something like "<coefficient>\sqrt[index]{<radical>}
1712
- */
1713
- -export class RootFraction extends CoefficientCore<RootFraction> {
1714
- - constructor(value?: number | string | Fraction | RootFraction, radical?: number | string, index?: number | string) {
1715
- +
1716
- +
1717
- +export class CoefficientElement extends CoefficientCore<CoefficientElement> {
1718
- + constructor(value?: CoefficientParserTypes, values?: { radical?: number, index?: number, extra?: string }) {
1719
- super();
1720
-
1721
- // Default values
1722
- this._index = 2;
1723
- this._radical = 1;
1724
- + this._extra = null
1725
-
1726
- - // Parse the value
1727
- + // Parse the name
1728
- if (value !== undefined) {
1729
- - if (value instanceof RootFraction) return this.parse(value)
1730
- - return this.parse(value, radical, index)
1731
- + if (value instanceof CoefficientElement) return this._parse(value)
1732
- + if (values === undefined) return this._parse(value)
1733
- + return this._parse(value,
1734
- + values.radical ?? 1,
1735
- + values.index ?? 2,
1736
- + values.extra ?? null
1737
- + )
1738
- }
1739
-
1740
- return this
1741
- }
1742
-
1743
- + private _extra: COEFFICIENT_EXTRA;
1744
- +
1745
- + get extra(): COEFFICIENT_EXTRA {
1746
- + return this._extra;
1747
- + }
1748
- +
1749
- + set extra(value: COEFFICIENT_EXTRA) {
1750
- + this._extra = value;
1751
- + }
1752
- +
1753
- private _index: number;
1754
-
1755
- get index(): number {
1756
- @@ -41,55 +59,56 @@
1757
- this._radical = value;
1758
- }
1759
-
1760
- - get value(): number {
1761
- - return this.numerator * Math.pow(this._radical, 1 / this._index) / this.denominator
1762
- + get fraction(): Fraction {
1763
- + return new Fraction(this.numerator, this.denominator)
1764
- }
1765
-
1766
- - get tex(): string {
1767
- - if (!this._hasRadical()) return this.fraction.tex
1768
- -
1769
- - const N = `${this.numerator} \\sqrt${this._index > 2 ? `[${this._index}]` : ''}{ ${this._radical} }`
1770
- -
1771
- - if (this.denominator === 1) return N
1772
- + set fraction(value: Fraction) {
1773
- + this.numerator = value.numerator
1774
- + this.denominator = value.denominator
1775
- + }
1776
-
1777
- - return `\\frac{ ${N} }{ ${this.denominator} }`
1778
- + get hasRadical(): boolean {
1779
- + return this._radical !== 1 && this._index > 1
1780
- + }
1781
-
1782
- + get key(): string {
1783
- + return this._index === 2 ? `sqrt(${this._radical})` : `root(${this._index})(${this._radical})`
1784
- }
1785
-
1786
- - get display(): string {
1787
- - if (!this._hasRadical()) return this.fraction.display
1788
- - const N = `${this.numerator}${this._index > 2 ? `root(${this._index})` : 'sqrt'}(${this._radical})`,
1789
- - D = this.denominator > 1 ? `/${this.denominator}` : ''
1790
- + get radicalDisplay(): string {
1791
- + return this.hasRadical ? this.key : ''
1792
- + }
1793
-
1794
- - return `${N}${D}`
1795
- + get radicalTex(): string {
1796
- + return this.hasRadical ? this._index === 2 ? `\\sqrt{ ${this._radical} }` : `\\sqrt[${this._index}]{ ${this._radical} }` : ''
1797
- }
1798
-
1799
- - createInstance(value?: string | number | Fraction | RootFraction): RootFraction {
1800
- - return new RootFraction(value)
1801
- + get extraDisplay(): string {
1802
- + return this._extra === COEFFICIENT_EXTRA.PI ? 'pi' : this._extra === COEFFICIENT_EXTRA.I ? 'i' : ''
1803
- }
1804
-
1805
- - clone = (): RootFraction => {
1806
- - return new RootFraction(this.fraction, this.radical, this.index)
1807
- + get extraTex(): string {
1808
- + return this._extra === COEFFICIENT_EXTRA.PI ? '\\pi' : this._extra === COEFFICIENT_EXTRA.I ? 'i' : ''
1809
- }
1810
-
1811
- - reduce = (): RootFraction => {
1812
- - // Reduce the radical
1813
- - this._extractRadical()
1814
- + static fromList(...values: CoefficientParserTypes[]): CoefficientElement[] {
1815
- + return values.map(x => new CoefficientElement(x))
1816
- + }
1817
-
1818
- - // Reduce the fraction
1819
- - this.fraction = this.fraction.reduce()
1820
- - return this
1821
- + createInstance(value?: CoefficientParserTypes): CoefficientElement {
1822
- + return new CoefficientElement(value)
1823
- }
1824
-
1825
- - one = (): RootFraction => {
1826
- + one = (): CoefficientElement => {
1827
- super.one()
1828
- this._resetRadical()
1829
- return this
1830
- }
1831
-
1832
- - add = (...values: (Fraction | number | string | RootFraction)[]): RootFraction => {
1833
- + add = (...values: CoefficientParserTypes[]): CoefficientElement => {
1834
- // Check that all values are similar
1835
- - const RF_list = values.map(x => new RootFraction(x))
1836
- + const RF_list = CoefficientElement.fromList(...values)
1837
-
1838
- const allAreSimilar = RF_list.every(x => this.isSimilarTo(x))
1839
- if (!allAreSimilar) throw new Error('All values must be similar')
1840
- @@ -98,67 +117,120 @@
1841
- return this
1842
- }
1843
-
1844
- - multiply = (...values: (Fraction | number | string | RootFraction)[]): RootFraction => {
1845
- - const RF_list = values.map(x => new RootFraction(x))
1846
- + multiply = (...values: CoefficientParserTypes[]): CoefficientElement => {
1847
- + const RF_list = CoefficientElement.fromList(...values)
1848
- +
1849
- + // Multiply the fraction
1850
- + this.fraction = this.fraction.multiply(...RF_list.map(x => x.fraction))
1851
- +
1852
- + // Multiply the extra (case of i)
1853
- + const i = [this, ...RF_list].filter(x => x.extra === COEFFICIENT_EXTRA.I).length
1854
- + this.extra = i % 2 === 0 ? null : COEFFICIENT_EXTRA.I
1855
- + this.numerator *= Math.floor(i / 2) % 2 === 0 ? 1 : -1
1856
-
1857
- // Check that all values has the same index
1858
- if (RF_list.every(x => x.index === this.index)) {
1859
- - // Multiply the fraction
1860
- - this.fraction = this.fraction.multiply(...RF_list.map(x => x.fraction))
1861
- -
1862
- // Multiply the radical
1863
- this.radical = RF_list.reduce((acc, x) => acc * x.radical, this.radical)
1864
- -
1865
- - return this
1866
- - }
1867
- -
1868
- - // Check that all values has the same radical
1869
- - if (RF_list.every(x => x.radical === this.radical)) {
1870
- - // Multiply the fraction
1871
- - this.fraction = this.fraction.multiply(...RF_list.map(x => x.fraction))
1872
- -
1873
- + } else if (RF_list.every(x => x.radical === this.radical)) {
1874
- // Add the index
1875
- const idx: Fraction = new Fraction(1, this.index)
1876
- .add(...RF_list.map(x => new Fraction(1, x.index)))
1877
-
1878
- this.radical = Math.pow(this.radical, idx.numerator)
1879
- this.index = idx.denominator
1880
- - return this
1881
- + } else {
1882
- + console.log('SOMETHING WENT WrONG ')
1883
- }
1884
- return this
1885
- }
1886
-
1887
- - invert = (): RootFraction => {
1888
- + invert = (): CoefficientElement => {
1889
- // 3sqrt(2)/7 -> 7/3sqrt(2) -> 7sqrt(2)/(3*2) -> 7sqrt(2)/6
1890
- // 3root(3)(2)/7 -> 7/3root(3)(2) -> 7root(3)(2^2)/(3*2) -> 7root(3)(4)/6
1891
- this.fraction = this.fraction.invert()
1892
- this.denominator = this.denominator * this.radical
1893
- this.radical = this.index - 1 > 1 ? Math.pow(this.radical, this.index - 1) : this.radical
1894
- +
1895
- return this
1896
- }
1897
-
1898
- - root(value: number | (Fraction | RootFraction)): RootFraction {
1899
- + root(value: number | (Fraction | CoefficientElement)): CoefficientElement {
1900
- throw new Error("Method not implemented.");
1901
- }
1902
-
1903
- - isSimilarTo = (value: Fraction | number | string | RootFraction): boolean => {
1904
- - let RF = new RootFraction(value).reduce()
1905
- + reduce = (): CoefficientElement => {
1906
- + // Reduce the radical
1907
- + this._extractRadical()
1908
- +
1909
- + // Reduce the fraction
1910
- + this.fraction = this.fraction.reduce()
1911
- + return this
1912
- + }
1913
- +
1914
- + isSimilarTo = (value: Fraction | number | string | CoefficientElement): boolean => {
1915
- + let RF = new CoefficientElement(value).reduce()
1916
-
1917
- // Check if the index and radical are the same
1918
- return this.index === RF.index && this.radical === RF.radical
1919
- }
1920
-
1921
- - get fraction(): Fraction {
1922
- - return new Fraction(this.numerator, this.denominator)
1923
- + get value(): number {
1924
- + if (this.hasRadical) {
1925
- + return this.numerator * Math.pow(this._radical, 1 / this._index) / this.denominator
1926
- + }
1927
- +
1928
- + return this.numerator / this.denominator
1929
- + }
1930
- +
1931
- + clone = (): CoefficientElement => {
1932
- + let result = new CoefficientElement(this.fraction, {
1933
- + radical: this._radical,
1934
- + index: this._index,
1935
- + extra: this._extra
1936
- + })
1937
- +
1938
- + return result
1939
- }
1940
-
1941
- - set fraction(value: Fraction) {
1942
- - this.numerator = value.numerator
1943
- - this.denominator = value.denominator
1944
- + get tex(): string {
1945
- + if (!this.hasRadical) return this.fraction.tex + this.extraTex
1946
- +
1947
- + const N = `${this.numerator} \\sqrt${this._index > 2 ? `[${this._index}]` : ''}{ ${this._radical} }`
1948
- +
1949
- + if (this.denominator === 1) return N
1950
- +
1951
- + return `\\frac{ ${N} }{ ${this.denominator} }${this.extraTex}`
1952
- +
1953
- }
1954
-
1955
- - parse = (value: number | string | Fraction | RootFraction, radical?: number | string, index?: number | string): RootFraction => {
1956
- - if (value instanceof RootFraction) return value.clone()
1957
- + get display(): string {
1958
- + let result = ''
1959
- +
1960
- + if (this.isInfinity()) return this.signTeX + 'oo'
1961
- + if (this.isNaN()) return 'NaN'
1962
- +
1963
- + let N = [`${this.numerator}`, this.radicalDisplay, this.extraDisplay]
1964
- + .filter(x => x !== '')
1965
- +
1966
- + if (N.length > 1) {
1967
- + N = N.map((x, index) => {
1968
- + if (index === 0 && Math.abs(+x) === 1) return +x === -1 ? '-' : ''
1969
- + return x
1970
- + })
1971
- + }
1972
- +
1973
- +
1974
- + const D = this.denominator > 1 ? `/${this.denominator}` : ''
1975
- +
1976
- + return `${N.join('')}${D}`
1977
- + }
1978
- +
1979
- + protected _parse = (value: CoefficientParserTypes, radical?: number | string, index?: number | string, extra?: string): CoefficientElement => {
1980
- + if (value instanceof CoefficientElement) return value.clone()
1981
- +
1982
- + this.radical = 1
1983
- + this.index = 2
1984
-
1985
- if (value instanceof Fraction) {
1986
- this.numerator = value.numerator
1987
- @@ -167,28 +239,53 @@
1988
- this.numerator = value
1989
- this.denominator = 1
1990
- } else if (typeof value === "string") {
1991
- - this.fraction = new Fraction(value)
1992
- - // TODO parse a string with root code....
1993
- + this._extra = value.includes('pi') ? COEFFICIENT_EXTRA.PI : value.includes('i') ? COEFFICIENT_EXTRA.I : null
1994
- + if (this._extra !== null) {
1995
- + value = value.replaceAll('pi', '')
1996
- + .replaceAll('i', '')
1997
- +
1998
- + value = (value === '' ? "1" : value) as string
1999
- + value = (value === '-' ? "-1" : value) as string
2000
- + }
2001
- +
2002
- + // Parse the string asqrt(b)/c
2003
- + if (value.includes('sqrt')) {
2004
- + const match = value.match(/^([0-9]+)?sqrt\(([0-9]+)\)?(\/([0-9]+))?/)
2005
- + if (match) {
2006
- + const [, num, rad, , den] = match
2007
- + this.numerator = num === undefined ? 1 : +num
2008
- + this.radical = rad === undefined ? 1 : +rad
2009
- + this.denominator = den === undefined ? 1 : +den
2010
- + }
2011
- + } else if (value.includes('root')) {
2012
- + const match = value.match(/^([0-9]*)root\(([0-9+])\)\(([0-9]+)\)?(\/([0-9]+))?/)
2013
- + if (match) {
2014
- + const [, num, index, rad, , den] = match
2015
- + this.numerator = num === undefined ? 1 : +num
2016
- + this.radical = rad === undefined ? 1 : +rad
2017
- + this.index = index === undefined ? 2 : +index
2018
- + this.denominator = den === undefined ? 1 : +den
2019
- + }
2020
- + } else {
2021
- + this.fraction = new Fraction(value)
2022
- + }
2023
- }
2024
-
2025
- if (radical !== undefined) this.radical = +radical
2026
- if (index !== undefined) this.index = +index
2027
- + if (extra !== undefined) this.extra = extra as COEFFICIENT_EXTRA
2028
-
2029
- return this
2030
- }
2031
-
2032
- - private _resetRadical = (): RootFraction => {
2033
- + private _resetRadical = (): CoefficientElement => {
2034
- this._index = 2
2035
- this._radical = 1
2036
- return this
2037
- }
2038
-
2039
- - private _hasRadical = (): boolean => {
2040
- - return this._radical !== 1 && this._index > 1
2041
- - }
2042
- -
2043
- private _extractRadical = (): { extracted: number, radical: number } => {
2044
- - // Maximal value to test for extracting the radical
2045
- + // Maximal name to test for extracting the radical
2046
- let extracted = Math.floor(Math.pow(this._radical, 1 / this._index))
2047
-
2048
- while (extracted > 1) {
2049
- Index: src/maths/types.ts
2050
- IDEA additional info:
2051
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
2052
- <+>import {Monom} from \"./algebra/monom\";\r\nimport {Polynom} from \"./algebra/polynom\";\r\nimport {Rational} from \"./algebra/rational\";\r\nimport {CoefficientTypes} from \"./coefficients/coefficientCore\";\r\n\r\ninterface coreInterface {\r\n parse: (...values: unknown[]) => ThisType<this>,\r\n clone: () => ThisType<this>,\r\n\r\n readonly tex: string,\r\n readonly display: string\r\n}\r\n\r\ninterface operationInterface {\r\n add: (...values: unknown[]) => ThisType<this>,\r\n subtract: (...values: unknown[]) => ThisType<this>,\r\n multiply: (...values: unknown[]) => ThisType<this>,\r\n divide: (value: unknown) => ThisType<this>,\r\n opposite: () => ThisType<this>,\r\n invert: () => ThisType<this>,\r\n pow: (value: unknown) => ThisType<this>,\r\n root: (value: unknown) => ThisType<this>,\r\n reduce: () => ThisType<this>,\r\n}\r\n\r\ninterface compareInterface {\r\n compare: (value: unknown, sign: COMPARESIGNS) => boolean,\r\n isEqualTo: (value: unknown) => boolean,\r\n isReduced: () => boolean,\r\n isOne: () => boolean,\r\n isMinusOne: () => boolean,\r\n isUnit: () => boolean,\r\n isZero: () => boolean,\r\n}\r\n\r\nexport interface coefficientInterface extends coreInterface, operationInterface, compareInterface {\r\n isGreaterOrEqualTo: (value: unknown) => boolean,\r\n isGreaterThan: (value: unknown) => boolean,\r\n isLesserOrEqualTo: (value: unknown) => boolean,\r\n isLesserThan: (value: unknown) => boolean,\r\n isNaN: () => boolean,\r\n isPositive: () => boolean,\r\n isNegative: () => boolean,\r\n isStrictlyNegative: () => boolean,\r\n isStrictlyPositive: () => boolean,\r\n isOpposedTo: (value: unknown) => boolean,\r\n isInvertedTo: (value: unknown) => boolean,\r\n isNatural: () => boolean,\r\n isRelative: () => boolean,\r\n isRational: () => boolean,\r\n isReal: () => boolean,\r\n isComplex: () => boolean,\r\n isInfinity: () => boolean,\r\n isEven: () => boolean,\r\n isOdd: () => boolean,\r\n readonly value: number,\r\n}\r\n\r\nexport interface coefficientStaticTypes {\r\n average: (...values: unknown[]) => coefficientInterface,\r\n max: (...values: unknown[]) => coefficientInterface,\r\n min: (...values: unknown[]) => coefficientInterface,\r\n sort: (...values: unknown[]) => coefficientInterface[],\r\n unique: (...values: unknown[]) => coefficientInterface[],\r\n}\r\n\r\nexport interface expressionInterface extends coreInterface, operationInterface, compareInterface {\r\n // variables getter\r\n readonly variables: string[],\r\n hasLetter: (letter?: string) => boolean\r\n\r\n // Evaluate\r\n evaluate: (value?: evaluateType) => numericType,\r\n\r\n // Helpers\r\n isDivisible?: (value: unknown) => boolean,\r\n}\r\n\r\n\r\nexport type literalType = { [Key: string]: CoefficientTypes }\r\nexport type numericType = number | string | CoefficientTypes\r\nexport type expressionType = Monom | Polynom | Rational\r\nexport type evaluateType = numericType | { [key: string]: numericType }\r\n\r\nexport enum COMPARESIGNS {\r\n \"EQUALS\" = \"=\",\r\n \"SAME\" = \"same\",\r\n \"GREATER\" = \">\",\r\n \"GEQ\" = \">=\",\r\n \"LESSER\" = \"<\",\r\n \"LEQ\" = \"<=\",\r\n \"DIFFERENT\" = \"<>\"\r\n}
2053
- ===================================================================
2054
- diff --git a/src/maths/types.ts b/src/maths/types.ts
2055
- --- a/src/maths/types.ts
2056
- +++ b/src/maths/types.ts
2057
- @@ -1,17 +1,14 @@
2058
- -import {Monom} from "./algebra/monom";
2059
- -import {Polynom} from "./algebra/polynom";
2060
- -import {Rational} from "./algebra/rational";
2061
- import {CoefficientTypes} from "./coefficients/coefficientCore";
2062
-
2063
- -interface coreInterface {
2064
- - parse: (...values: unknown[]) => ThisType<this>,
2065
- +export interface coreInterface {
2066
- + // parse: (...values: unknown[]) => ThisType<this>,
2067
- clone: () => ThisType<this>,
2068
-
2069
- readonly tex: string,
2070
- readonly display: string
2071
- }
2072
-
2073
- -interface operationInterface {
2074
- +export interface operationInterface {
2075
- add: (...values: unknown[]) => ThisType<this>,
2076
- subtract: (...values: unknown[]) => ThisType<this>,
2077
- multiply: (...values: unknown[]) => ThisType<this>,
2078
- @@ -23,8 +20,8 @@
2079
- reduce: () => ThisType<this>,
2080
- }
2081
-
2082
- -interface compareInterface {
2083
- - compare: (value: unknown, sign: COMPARESIGNS) => boolean,
2084
- +export interface equalityInterface {
2085
- + isSimilarTo: (value: unknown) => boolean,
2086
- isEqualTo: (value: unknown) => boolean,
2087
- isReduced: () => boolean,
2088
- isOne: () => boolean,
2089
- @@ -33,7 +30,7 @@
2090
- isZero: () => boolean,
2091
- }
2092
-
2093
- -export interface coefficientInterface extends coreInterface, operationInterface, compareInterface {
2094
- +export interface compareInterface {
2095
- isGreaterOrEqualTo: (value: unknown) => boolean,
2096
- isGreaterThan: (value: unknown) => boolean,
2097
- isLesserOrEqualTo: (value: unknown) => boolean,
2098
- @@ -56,19 +53,29 @@
2099
- readonly value: number,
2100
- }
2101
-
2102
- -export interface coefficientStaticTypes {
2103
- - average: (...values: unknown[]) => coefficientInterface,
2104
- - max: (...values: unknown[]) => coefficientInterface,
2105
- - min: (...values: unknown[]) => coefficientInterface,
2106
- - sort: (...values: unknown[]) => coefficientInterface[],
2107
- - unique: (...values: unknown[]) => coefficientInterface[],
2108
- +// export interface coefficientStaticTypes {
2109
- +// average: (...values: unknown[]) => coefficientInterface,
2110
- +// max: (...values: unknown[]) => coefficientInterface,
2111
- +// min: (...values: unknown[]) => coefficientInterface,
2112
- +// sort: (...values: unknown[]) => coefficientInterface[],
2113
- +// unique: (...values: unknown[]) => coefficientInterface[],
2114
- +// }
2115
- +
2116
- +export interface expressionElementInterface {
2117
- + [name: string]: {
2118
- + exponent: number,
2119
- + root: number,
2120
- + }
2121
- }
2122
-
2123
- -export interface expressionInterface extends coreInterface, operationInterface, compareInterface {
2124
- +
2125
- +export interface expressionInterface {
2126
- // variables getter
2127
- readonly variables: string[],
2128
- + readonly literal: expressionElementInterface
2129
- hasLetter: (letter?: string) => boolean
2130
-
2131
- +
2132
- // Evaluate
2133
- evaluate: (value?: evaluateType) => numericType,
2134
-
2135
- @@ -79,7 +86,6 @@
2136
-
2137
- export type literalType = { [Key: string]: CoefficientTypes }
2138
- export type numericType = number | string | CoefficientTypes
2139
- -export type expressionType = Monom | Polynom | Rational
2140
- export type evaluateType = numericType | { [key: string]: numericType }
2141
-
2142
- export enum COMPARESIGNS {
2143
- Index: src/maths/coefficients/coefficientCore.ts
2144
- IDEA additional info:
2145
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
2146
- <+>import {Fraction} from \"./fraction\";\r\nimport {RootFraction} from \"./rootFraction\";\r\nimport {Numeric} from \"../numeric\";\r\n\r\n\r\nexport type CoefficientTypes = Fraction | RootFraction\r\nexport type CoefficientParserTypes = CoefficientTypes | number | string\r\n\r\nexport enum COEFFICIENT_MODE {\r\n \"FRACTION\",\r\n \"ROOT\",\r\n \"RADIAN\",\r\n \"COMPLEX\"\r\n}\r\n\r\nexport enum FRACTION_FRAC {\r\n \"frac\",\r\n \"dfrac\",\r\n \"tfrac\",\r\n}\r\n\r\nexport abstract class CoefficientCore<T extends CoefficientTypes> {\r\n private _fracType: FRACTION_FRAC\r\n\r\n get fracType(): FRACTION_FRAC {\r\n return this._fracType;\r\n }\r\n\r\n set fracType(value: FRACTION_FRAC) {\r\n this._fracType = value;\r\n }\r\n\r\n private _numerator: number\r\n\r\n get numerator(): number {\r\n return this._numerator;\r\n }\r\n\r\n set numerator(value: number) {\r\n this._numerator = value;\r\n }\r\n\r\n private _denominator: number\r\n\r\n get denominator(): number {\r\n return this._denominator;\r\n }\r\n\r\n set denominator(value: number) {\r\n this._denominator = value;\r\n }\r\n\r\n get value(): number {\r\n return this._numerator / this._denominator\r\n }\r\n\r\n get sign(): number {\r\n return (this.numerator * this.denominator >= 0) ? 1 : -1;\r\n };\r\n\r\n get signTeX(): string {\r\n return this.sign === 1 ? '+' : '-'\r\n }\r\n\r\n get fracTeX(): string {\r\n return this._fracType === FRACTION_FRAC.frac ? '\\\\frac' : this._fracType === FRACTION_FRAC.dfrac ? '\\\\dfrac' : '\\\\tfrac'\r\n }\r\n\r\n abstract get tex(): string\r\n\r\n abstract get display(): string\r\n\r\n static max = <T extends CoefficientTypes>(...values: T[]): T => {\r\n const [first, ...rest] = values\r\n return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? acc : cur, first)\r\n }\r\n\r\n static min = <T extends CoefficientTypes>(...values: T[]): T => {\r\n const [first, ...rest] = values\r\n return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? cur : acc, first)\r\n }\r\n\r\n static unique = <T extends CoefficientTypes>(values: T[], sort?: boolean): T[] => {\r\n let uniqueObjects: T[] = [],\r\n uniqueValues: number[] = []\r\n\r\n values.forEach((value, index) => {\r\n if (!uniqueValues.includes(value.value)) {\r\n uniqueValues.push(value.value)\r\n uniqueObjects.push(value)\r\n }\r\n })\r\n\r\n if (sort) return CoefficientCore.sort(uniqueObjects)\r\n\r\n return uniqueObjects\r\n }\r\n\r\n static sort = <T extends CoefficientTypes>(values: T[], reverse?: boolean): T[] => {\r\n let sorted = values.sort((a, b) => a.value - b.value)\r\n\r\n if (reverse) sorted = sorted.reverse()\r\n\r\n return sorted\r\n }\r\n\r\n abstract createInstance(value?: number | string | T): T\r\n\r\n abstract clone(): T\r\n\r\n abstract reduce(): T\r\n\r\n getReducedCoefficient = (): { N: number, D: number } => {\r\n if (this.numerator === 1 || this.denominator === 1) return {N: this.numerator, D: this.denominator}\r\n\r\n let g = Numeric.gcd(this.numerator, this.denominator);\r\n let [N, D] = [this.numerator, this.denominator]\r\n\r\n N = N / g;\r\n D = D / g;\r\n\r\n if (D < 0) {\r\n D = -D;\r\n N = -N;\r\n }\r\n\r\n return {N, D}\r\n };\r\n\r\n zero = (): T => {\r\n this.numerator = 0;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n one = (): T => {\r\n this.numerator = 1;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n infinite = (): T => {\r\n this.numerator = Infinity;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n invalid = (): T => {\r\n this.numerator = NaN;\r\n this.denominator = 1;\r\n return this as unknown as T\r\n };\r\n\r\n abstract add(...coefficients: (T | number | string)[]): T\r\n\r\n opposite = (): T => {\r\n this.numerator = -this.numerator;\r\n return this as unknown as T;\r\n }\r\n\r\n subtract = (...coefficients: (T | number | string)[]): T => this.add(...coefficients.map(c => this.createInstance(c).opposite() as T))\r\n\r\n abstract multiply(...coefficients: (T | number | string)[]): T\r\n\r\n abstract invert(): T\r\n\r\n divide = (F: T | number): T => this.multiply(this.createInstance(F).invert() as T);\r\n\r\n abs = (): T => {\r\n this.numerator = Math.abs(this.numerator);\r\n return this as unknown as T;\r\n }\r\n\r\n pow = (value: number | CoefficientTypes): T => {\r\n if (Number.isSafeInteger(value)) {\r\n const factor = this.clone(),\r\n abs = Math.abs(value as number)\r\n for (let i = abs; i <= abs; i++) {\r\n this.multiply(factor)\r\n }\r\n\r\n if ((value as number) < 0) this.invert()\r\n } else {\r\n throw new Error('Cannot raise a coefficient to a non-integer power')\r\n }\r\n return this as unknown as T\r\n }\r\n\r\n abstract root(value: number | CoefficientTypes): T\r\n\r\n sqrt = (): T => this.root(2)\r\n\r\n asTopFraction = (): T => {\r\n this.fracType = FRACTION_FRAC.tfrac\r\n return this as unknown as T\r\n }\r\n\r\n asDisplayFraction = (): T => {\r\n this.fracType = FRACTION_FRAC.dfrac\r\n return this as unknown as T\r\n }\r\n\r\n\r\n /**\r\n * All the is* methods without argument\r\n */\r\n\r\n isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1\r\n\r\n isOne = (): boolean => this._numerator === 1 && this._denominator === 1\r\n\r\n isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1\r\n\r\n isUnit = (): boolean => this.isOne() || this.isMinusOne()\r\n\r\n isZero = (): boolean => this._numerator === 0\r\n\r\n isFinite = (): boolean => !this.isInfinity() && !this.isNaN()\r\n\r\n isSquare = (): boolean => Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0\r\n\r\n isNaN = (): boolean => isNaN(this.value)\r\n\r\n isPositive = (): boolean => this.sign === 1\r\n\r\n isNegative = (): boolean => this.sign === -1\r\n\r\n isStrictlyNegative = (): boolean => this.value < 0\r\n\r\n isStrictlyPositive = (): boolean => this.value > 0\r\n\r\n isNatural = (): boolean => this.isRelative() && this.isPositive()\r\n\r\n isRelative = (): boolean => {\r\n const {N, D} = this.getReducedCoefficient()\r\n return D === 1\r\n }\r\n\r\n isRational = (): boolean => !this.isRelative()\r\n\r\n isReal = (): boolean => true\r\n\r\n isComplex = (): boolean => false\r\n\r\n isInfinity = (): boolean => Math.abs(this.value) === Infinity\r\n\r\n isEven = (): boolean => this.isRelative() && this.value % 2 === 0\r\n\r\n isOdd = (): boolean => this.isRelative() && this.value % 2 === 1\r\n\r\n isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15\r\n\r\n isExact = (): boolean => !this.isApproximative()\r\n\r\n isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;\r\n\r\n isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;\r\n\r\n isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;\r\n\r\n isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;\r\n\r\n isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;\r\n\r\n isEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value === this.createInstance(than as T).value\r\n\r\n isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())\r\n\r\n isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())\r\n\r\n}\r\n
2147
- ===================================================================
2148
- diff --git a/src/maths/coefficients/coefficientCore.ts b/src/maths/coefficients/coefficientCore.ts
2149
- --- a/src/maths/coefficients/coefficientCore.ts
2150
- +++ b/src/maths/coefficients/coefficientCore.ts
2151
- @@ -1,9 +1,11 @@
2152
- import {Fraction} from "./fraction";
2153
- -import {RootFraction} from "./rootFraction";
2154
- +import {CoefficientElement} from "./coefficientElement";
2155
- import {Numeric} from "../numeric";
2156
- +import {compareInterface, coreInterface, equalityInterface, operationInterface} from "../types";
2157
- +import {Coefficient} from "./coefficient";
2158
-
2159
-
2160
- -export type CoefficientTypes = Fraction | RootFraction
2161
- +export type CoefficientTypes = Fraction | CoefficientElement | Coefficient
2162
- export type CoefficientParserTypes = CoefficientTypes | number | string
2163
-
2164
- export enum COEFFICIENT_MODE {
2165
- @@ -13,13 +15,28 @@
2166
- "COMPLEX"
2167
- }
2168
-
2169
- +export enum COEFFICIENT_EXTRA {
2170
- + 'I' = "i",
2171
- + 'PI' = "pi"
2172
- +}
2173
- +
2174
- export enum FRACTION_FRAC {
2175
- "frac",
2176
- "dfrac",
2177
- "tfrac",
2178
- }
2179
-
2180
- -export abstract class CoefficientCore<T extends CoefficientTypes> {
2181
- +export abstract class CoefficientCore<T extends CoefficientTypes> implements coreInterface, operationInterface, equalityInterface, compareInterface {
2182
- + private _exact: boolean
2183
- +
2184
- + get exact(): boolean {
2185
- + return this._exact;
2186
- + }
2187
- +
2188
- + set exact(value: boolean) {
2189
- + this._exact = value;
2190
- + }
2191
- +
2192
- private _fracType: FRACTION_FRAC
2193
-
2194
- get fracType(): FRACTION_FRAC {
2195
- @@ -50,10 +67,6 @@
2196
- this._denominator = value;
2197
- }
2198
-
2199
- - get value(): number {
2200
- - return this._numerator / this._denominator
2201
- - }
2202
- -
2203
- get sign(): number {
2204
- return (this.numerator * this.denominator >= 0) ? 1 : -1;
2205
- };
2206
- @@ -66,10 +79,6 @@
2207
- return this._fracType === FRACTION_FRAC.frac ? '\\frac' : this._fracType === FRACTION_FRAC.dfrac ? '\\dfrac' : '\\tfrac'
2208
- }
2209
-
2210
- - abstract get tex(): string
2211
- -
2212
- - abstract get display(): string
2213
- -
2214
- static max = <T extends CoefficientTypes>(...values: T[]): T => {
2215
- const [first, ...rest] = values
2216
- return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? acc : cur, first)
2217
- @@ -106,9 +115,13 @@
2218
-
2219
- abstract createInstance(value?: number | string | T): T
2220
-
2221
- - abstract clone(): T
2222
- -
2223
- - abstract reduce(): T
2224
- + amplify = (k: number): T => {
2225
- + if (Number.isSafeInteger(k)) {
2226
- + this.numerator *= k;
2227
- + this.denominator *= k;
2228
- + }
2229
- + return this as unknown as T;
2230
- + };
2231
-
2232
- getReducedCoefficient = (): { N: number, D: number } => {
2233
- if (this.numerator === 1 || this.denominator === 1) return {N: this.numerator, D: this.denominator}
2234
- @@ -153,25 +166,28 @@
2235
-
2236
- abstract add(...coefficients: (T | number | string)[]): T
2237
-
2238
- - opposite = (): T => {
2239
- - this.numerator = -this.numerator;
2240
- - return this as unknown as T;
2241
- - }
2242
- -
2243
- subtract = (...coefficients: (T | number | string)[]): T => this.add(...coefficients.map(c => this.createInstance(c).opposite() as T))
2244
-
2245
- abstract multiply(...coefficients: (T | number | string)[]): T
2246
-
2247
- - abstract invert(): T
2248
- -
2249
- divide = (F: T | number): T => this.multiply(this.createInstance(F).invert() as T);
2250
-
2251
- - abs = (): T => {
2252
- - this.numerator = Math.abs(this.numerator);
2253
- + opposite = (): T => {
2254
- + this.numerator = -this.numerator;
2255
- return this as unknown as T;
2256
- }
2257
-
2258
- - pow = (value: number | CoefficientTypes): T => {
2259
- + abstract invert(): T
2260
- +
2261
- + pow = (value: number | Fraction): T => {
2262
- + // It's a fraction - numerator = power, denoinator = root
2263
- + if (value instanceof Fraction) {
2264
- + this.pow(this.numerator)
2265
- + this.root(this.denominator)
2266
- + return this as unknown as T
2267
- + }
2268
- +
2269
- + // It's a number
2270
- if (Number.isSafeInteger(value)) {
2271
- const factor = this.clone(),
2272
- abs = Math.abs(value as number)
2273
- @@ -188,6 +204,13 @@
2274
-
2275
- abstract root(value: number | CoefficientTypes): T
2276
-
2277
- + abstract reduce(): T
2278
- +
2279
- + abs = (): T => {
2280
- + this.numerator = Math.abs(this.numerator);
2281
- + return this as unknown as T;
2282
- + }
2283
- +
2284
- sqrt = (): T => this.root(2)
2285
-
2286
- asTopFraction = (): T => {
2287
- @@ -200,25 +223,24 @@
2288
- return this as unknown as T
2289
- }
2290
-
2291
- -
2292
- - /**
2293
- - * All the is* methods without argument
2294
- - */
2295
- -
2296
- - isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1
2297
- -
2298
- - isOne = (): boolean => this._numerator === 1 && this._denominator === 1
2299
- -
2300
- - isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1
2301
- -
2302
- - isUnit = (): boolean => this.isOne() || this.isMinusOne()
2303
- -
2304
- - isZero = (): boolean => this._numerator === 0
2305
- -
2306
- isFinite = (): boolean => !this.isInfinity() && !this.isNaN()
2307
-
2308
- isSquare = (): boolean => Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0
2309
-
2310
- + isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15
2311
- +
2312
- + isExact = (): boolean => !this.isApproximative()
2313
- +
2314
- + isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;
2315
- +
2316
- + isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;
2317
- +
2318
- + isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;
2319
- +
2320
- + isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;
2321
- +
2322
- + isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;
2323
- +
2324
- isNaN = (): boolean => isNaN(this.value)
2325
-
2326
- isPositive = (): boolean => this.sign === 1
2327
- @@ -229,6 +251,10 @@
2328
-
2329
- isStrictlyPositive = (): boolean => this.value > 0
2330
-
2331
- + isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())
2332
- +
2333
- + isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())
2334
- +
2335
- isNatural = (): boolean => this.isRelative() && this.isPositive()
2336
-
2337
- isRelative = (): boolean => {
2338
- @@ -248,24 +274,32 @@
2339
-
2340
- isOdd = (): boolean => this.isRelative() && this.value % 2 === 1
2341
-
2342
- - isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15
2343
- -
2344
- - isExact = (): boolean => !this.isApproximative()
2345
- -
2346
- - isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;
2347
- -
2348
- - isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;
2349
- -
2350
- - isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;
2351
- -
2352
- - isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;
2353
- -
2354
- - isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;
2355
- + get value(): number {
2356
- + return this._numerator / this._denominator
2357
- + }
2358
-
2359
- isEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value === this.createInstance(than as T).value
2360
-
2361
- - isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())
2362
- + /**
2363
- + * All the is* methods without argument
2364
- + */
2365
- +
2366
- + isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1
2367
- +
2368
- + isOne = (): boolean => this._numerator === 1 && this._denominator === 1
2369
- +
2370
- + isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1
2371
- +
2372
- + isUnit = (): boolean => this.isOne() || this.isMinusOne()
2373
- +
2374
- + isZero = (): boolean => this._numerator === 0
2375
- +
2376
- + abstract clone(): T
2377
- +
2378
- + abstract get tex(): string
2379
-
2380
- - isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())
2381
- + abstract get display(): string
2382
- +
2383
- + protected abstract _parse(value: unknown): T
2384
-
2385
- }
2386
- Index: tests/geometry/radian.test.ts
2387
- IDEA additional info:
2388
- Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
2389
- <+>import {describe} from \"mocha\";\r\nimport {expect} from \"chai\";\r\nimport {Radian} from \"../../src/maths/geometry/radian\";\r\ndescribe('Random tests', () => {\r\n it('should create a radian value', () => {\r\n let r = new Radian('3/2')\r\n\r\n expect(r.tex).to.be.equal('\\\\frac{ 3\\\\pi }{ 2 }')\r\n expect(r.display).to.be.equal('3pi/2')\r\n\r\n let rp = new Radian('3/2', '1/2')\r\n\r\n expect(rp.tex).to.be.equal('\\\\frac{ 3\\\\pi }{ 2 }+k\\\\frac{ \\\\pi }{ 2 }')\r\n expect(rp.display).to.be.equal('3pi/2+kpi/2')\r\n })\r\n})
2390
- ===================================================================
2391
- diff --git a/tests/geometry/radian.test.ts b/tests/geometry/radian.test.ts
2392
- --- a/tests/geometry/radian.test.ts
2393
- +++ b/tests/geometry/radian.test.ts
2394
- @@ -1,8 +1,9 @@
2395
- import {describe} from "mocha";
2396
- import {expect} from "chai";
2397
- import {Radian} from "../../src/maths/geometry/radian";
2398
- +
2399
- describe('Random tests', () => {
2400
- - it('should create a radian value', () => {
2401
- + it('should create a radian name', () => {
2402
- let r = new Radian('3/2')
2403
-
2404
- expect(r.tex).to.be.equal('\\frac{ 3\\pi }{ 2 }')
1
+ Index: tests/algebra/monom.test.ts
2
+ IDEA additional info:
3
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
4
+ <+>import {expect} from 'chai';\r\nimport {Random} from \"../../src/maths/randomization/random\";\r\nimport {describe} from \"mocha\";\r\nimport {Monom, MonomE} from \"../../src/maths/algebra/monom\";\r\n\r\ndescribe('Monom with integer power', () => {\r\n it('parsing', () => {\r\n const M0a = new Monom('3');\r\n expect(M0a.tex).to.be.equal('3')\r\n\r\n const M0b = new Monom('x');\r\n expect(M0b.tex).to.be.equal('x')\r\n\r\n const M0c = new Monom('3x');\r\n expect(M0c.tex).to.be.equal('3x')\r\n\r\n const M1 = new Monom('3x^5');\r\n expect(M1.tex).to.be.equal('3x^{5}')\r\n\r\n const M2 = new Monom('2/3x^2yz^3y^4')\r\n expect(M2.display).to.be.equal('2/3x^(2)y^(5)z^(3)')\r\n\r\n const M3 = new Monom('-3x^(-2)')\r\n expect(M3.tex).to.be.equal('-3x^{-2}')\r\n\r\n const M4 = new Monom('3x^(2/3)')\r\n expect(M4.tex).to.be.equal('3x^{\\\\tfrac{ 2 }{ 3 }}')\r\n\r\n const M5 = new Monom('-3x^(-2/3)y^(-5)8x^3')\r\n expect(M5.tex).to.be.equal('-24x^{\\\\tfrac{ 7 }{ 3 }}y^{-5}')\r\n })\r\n\r\n it('basic operations', () => {\r\n const M1 = new Monom('3x'),\r\n M2 = new Monom('2x')\r\n\r\n expect(M1.clone().add(M2).isEqual(new Monom('5x'))).to.be.true\r\n expect(M1.clone().subtract(M2).isEqual(new Monom('x'))).to.be.true\r\n expect(M1.clone().multiply(M2).isEqual(new Monom('6x^2'))).to.be.true\r\n expect(M1.clone().divide(M2).isEqual(new Monom('3/2'))).to.be.true\r\n })\r\n\r\n it('derivative', () => { // the single test\r\n const options = new Monom('7x^3'); // this will be your class\r\n\r\n expect(options.tex).to.be.equal('7x^{3}')\r\n expect(options.derivative().tex).to.be.equal('21x^{2}');\r\n });\r\n\r\n it('integrate', () => { // the single test\r\n const options = new Monom('7x^3'); // this will be your class\r\n expect(options.primitive().display).to.be.equal('7/4x^(4)');\r\n });\r\n\r\n it('randomize', function () {\r\n const M = Random.monom({\r\n letters: 'xyz',\r\n degree: 5,\r\n fraction: false,\r\n zero: false\r\n });\r\n\r\n expect(M.coefficient.isZero()).to.be.false\r\n expect(M.degree().value).to.be.greaterThan(0)\r\n });\r\n})\r\n\r\ndescribe('Monom with fraction power', () => {\r\n it('should create a numerical expression', () => {\r\n const inputStr: string = '-1/5x^(2/3)'\r\n const M = new Monom(inputStr),\r\n N = new Monom('7x^(4/5)')\r\n\r\n M.multiply(N.clone())\r\n\r\n expect(M.tex).to.be.equal('-\\\\frac{ 7 }{ 5 }x^{\\\\tfrac{ 22 }{ 15 }}')\r\n })\r\n\r\n it('should show a monom with sqrt', function () {\r\n let m = new MonomE('3x^(1/2)')\r\n m.letters('x', '\\\\sqrt{2}')\r\n\r\n console.log(m.tex)\r\n });\r\n})
5
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
6
+ <+>UTF-8
7
+ ===================================================================
8
+ diff --git a/tests/algebra/monom.test.ts b/tests/algebra/monom.test.ts
9
+ --- a/tests/algebra/monom.test.ts
10
+ +++ b/tests/algebra/monom.test.ts
11
+ @@ -1,85 +1,9 @@
12
+ -import {expect} from 'chai';
13
+ -import {Random} from "../../src/maths/randomization/random";
14
+ import {describe} from "mocha";
15
+ -import {Monom, MonomE} from "../../src/maths/algebra/monom";
16
+ -
17
+ -describe('Monom with integer power', () => {
18
+ - it('parsing', () => {
19
+ - const M0a = new Monom('3');
20
+ - expect(M0a.tex).to.be.equal('3')
21
+ -
22
+ - const M0b = new Monom('x');
23
+ - expect(M0b.tex).to.be.equal('x')
24
+ -
25
+ - const M0c = new Monom('3x');
26
+ - expect(M0c.tex).to.be.equal('3x')
27
+ -
28
+ - const M1 = new Monom('3x^5');
29
+ - expect(M1.tex).to.be.equal('3x^{5}')
30
+ +import {Monom} from "../../src/maths/algebra/monom";
31
+
32
+ - const M2 = new Monom('2/3x^2yz^3y^4')
33
+ - expect(M2.display).to.be.equal('2/3x^(2)y^(5)z^(3)')
34
+ -
35
+ - const M3 = new Monom('-3x^(-2)')
36
+ - expect(M3.tex).to.be.equal('-3x^{-2}')
37
+ -
38
+ - const M4 = new Monom('3x^(2/3)')
39
+ - expect(M4.tex).to.be.equal('3x^{\\tfrac{ 2 }{ 3 }}')
40
+ -
41
+ - const M5 = new Monom('-3x^(-2/3)y^(-5)8x^3')
42
+ - expect(M5.tex).to.be.equal('-24x^{\\tfrac{ 7 }{ 3 }}y^{-5}')
43
+ +describe('Monom tests', () => {
44
+ + it('Monom can be parsed from a string', () => {
45
+ + let m = new Monom()
46
+ })
47
+
48
+ - it('basic operations', () => {
49
+ - const M1 = new Monom('3x'),
50
+ - M2 = new Monom('2x')
51
+ -
52
+ - expect(M1.clone().add(M2).isEqual(new Monom('5x'))).to.be.true
53
+ - expect(M1.clone().subtract(M2).isEqual(new Monom('x'))).to.be.true
54
+ - expect(M1.clone().multiply(M2).isEqual(new Monom('6x^2'))).to.be.true
55
+ - expect(M1.clone().divide(M2).isEqual(new Monom('3/2'))).to.be.true
56
+ - })
57
+ -
58
+ - it('derivative', () => { // the single test
59
+ - const options = new Monom('7x^3'); // this will be your class
60
+ -
61
+ - expect(options.tex).to.be.equal('7x^{3}')
62
+ - expect(options.derivative().tex).to.be.equal('21x^{2}');
63
+ - });
64
+ -
65
+ - it('integrate', () => { // the single test
66
+ - const options = new Monom('7x^3'); // this will be your class
67
+ - expect(options.primitive().display).to.be.equal('7/4x^(4)');
68
+ - });
69
+ -
70
+ - it('randomize', function () {
71
+ - const M = Random.monom({
72
+ - letters: 'xyz',
73
+ - degree: 5,
74
+ - fraction: false,
75
+ - zero: false
76
+ - });
77
+ -
78
+ - expect(M.coefficient.isZero()).to.be.false
79
+ - expect(M.degree().value).to.be.greaterThan(0)
80
+ - });
81
+ -})
82
+ -
83
+ -describe('Monom with fraction power', () => {
84
+ - it('should create a numerical expression', () => {
85
+ - const inputStr: string = '-1/5x^(2/3)'
86
+ - const M = new Monom(inputStr),
87
+ - N = new Monom('7x^(4/5)')
88
+ -
89
+ - M.multiply(N.clone())
90
+ -
91
+ - expect(M.tex).to.be.equal('-\\frac{ 7 }{ 5 }x^{\\tfrac{ 22 }{ 15 }}')
92
+ - })
93
+ -
94
+ - it('should show a monom with sqrt', function () {
95
+ - let m = new MonomE('3x^(1/2)')
96
+ - m.letters('x', '\\sqrt{2}')
97
+ -
98
+ - console.log(m.tex)
99
+ - });
100
+ })
101
+
102
+ Index: src/maths/coefficients/fraction.ts
103
+ IDEA additional info:
104
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
105
+ <+>import {CoefficientCore, FRACTION_FRAC} from \"./coefficientCore\";\r\n\r\n/**\r\n * The fraction class\r\n */\r\n\r\nexport class Fraction extends CoefficientCore<Fraction> {\r\n constructor(value?: number | string | Fraction, denominator?: number | string) {\r\n super()\r\n // Default values.\r\n this.numerator = 1;\r\n this.denominator = 1;\r\n\r\n this.fracType = FRACTION_FRAC.frac\r\n\r\n if (value !== undefined) {\r\n if (value instanceof Fraction) return this.parse(value)\r\n return this.parse(value, denominator)\r\n }\r\n\r\n return this;\r\n }\r\n\r\n get tex(): string {\r\n const frac = this.fracTeX\r\n // restore the frac type to default\r\n this.fracType = FRACTION_FRAC.frac\r\n\r\n if (this.isInfinity()) {\r\n return `${this.signTeX}\\\\infty`\r\n }\r\n\r\n if (this.isExact()) {\r\n if (this.denominator === 1) {\r\n return `${this.numerator}`;\r\n } else if (this.numerator < 0) {\r\n return `-${frac}{ ${-this.numerator} }{ ${this.denominator} }`;\r\n } else {\r\n return `${frac}{ ${this.numerator} }{ ${this.denominator} }`;\r\n }\r\n } else {\r\n return this.value.toFixed(3)\r\n }\r\n }\r\n\r\n get display(): string {\r\n if (this.isInfinity()) {\r\n return `${this.signTeX}\\\\infty`\r\n }\r\n\r\n if (this.isExact()) {\r\n if (this.denominator === 1) {\r\n return `${this.numerator}`;\r\n } else if (this.numerator < 0) {\r\n return `-${-this.numerator}/${this.denominator}`;\r\n } else {\r\n return `${this.numerator}/${this.denominator}`;\r\n }\r\n } else {\r\n return this.value.toFixed(3)\r\n }\r\n }\r\n\r\n createInstance(value?: string | number | Fraction): Fraction {\r\n return new Fraction(value)\r\n }\r\n\r\n clone = (): Fraction => {\r\n return new Fraction(this.numerator, this.denominator)\r\n };\r\n\r\n reduce = (): Fraction => {\r\n const {N, D} = this.getReducedCoefficient()\r\n this.numerator = N\r\n this.denominator = D\r\n return this;\r\n };\r\n\r\n add = (...values: (Fraction | number | string)[]): Fraction => {\r\n for (let F of values) {\r\n if (!(F instanceof Fraction)) F = new Fraction(F)\r\n\r\n let N: number = this.numerator,\r\n D: number = this.denominator;\r\n\r\n this.numerator = N * F.denominator + F.numerator * D;\r\n this.denominator = D * F.denominator;\r\n }\r\n\r\n return this.reduce();\r\n };\r\n\r\n multiply = (...values: (Fraction | number)[]): Fraction => {\r\n // Parse the value.\r\n // If it's a fraction, return a clone of it\r\n // If it's an integer, return the fraction F/1\r\n for (let F of values) {\r\n if (!(F instanceof Fraction)) {\r\n F = new Fraction(F)\r\n }\r\n\r\n this.numerator = this.numerator * F.numerator;\r\n this.denominator = this.denominator * F.denominator;\r\n }\r\n\r\n return this\r\n };\r\n\r\n invert = (): Fraction => {\r\n let n = +this.numerator, d = +this.denominator;\r\n this.numerator = d;\r\n this.denominator = n;\r\n\r\n return this;\r\n }\r\n\r\n root = (p: number): Fraction => {\r\n // TODO: index - root of a fraction => this will return another type of coefficient.\r\n\r\n // Check if they are perfect roots..\r\n if (p === 0) {\r\n return this;\r\n }\r\n\r\n // If negative, invert the fraction\r\n if (p < 0) {\r\n this.invert()\r\n }\r\n\r\n let n = Math.pow(this.numerator, Math.abs(1 / p)),\r\n d = Math.pow(this.denominator, Math.abs(1 / p));\r\n\r\n this.numerator = Math.pow(this.numerator, Math.abs(1 / p));\r\n this.denominator = Math.pow(this.denominator, Math.abs(1 / p));\r\n return this;\r\n }\r\n\r\n static decimalToFraction = (value: string | number | Fraction): [number, number] => {\r\n // Return the neutral element\r\n if (value === undefined) return [1, 1]\r\n\r\n // Return the numerator and denominator if it's already a fraction\r\n if (value instanceof Fraction) return [value.numerator, value.denominator]\r\n\r\n // Split the value into unit and decimal part\r\n let [unit, decimal] = (+value).toString().split('.')\r\n\r\n // Return the unit if there is no decimal part\r\n if (decimal === undefined) return [+unit, 1]\r\n\r\n let decimalLength = decimal.length\r\n\r\n return [+(unit + decimal), 10 ** decimalLength]\r\n }\r\n\r\n static average = (...fractions: (Fraction | number)[]): Fraction => {\r\n let M = new Fraction().zero()\r\n\r\n for (let f of fractions) {\r\n M.add(f)\r\n }\r\n\r\n M.divide(fractions.length)\r\n\r\n return M\r\n }\r\n\r\n /**\r\n * Parse the value to get the numerator and denominator\r\n * @param value : number or string to parse to get the fraction\r\n * @param denominatorOrPeriodic (optional|number) : length of the periodic part: 2.333333 => 1 or denominator value\r\n */\r\n parse(value: Fraction): Fraction\r\n\r\n parse(value: string | number): Fraction\r\n\r\n\r\n // pow = (p: number | Fraction): Fraction => {\r\n // // TODO: Fraction.pow with a value different than a safe integer !\r\n // if (p instanceof Fraction) {\r\n // return this.pow(p.value)\r\n // }\r\n //\r\n // this.reduce();\r\n // if (p < 0) {\r\n // this.invert()\r\n // }\r\n //\r\n // // Check if numerator and denominator are roots of...\r\n // // othervise, convert to numeric.\r\n // let controlNumerator = Math.floor(Math.pow(this.numerator, Math.abs(p))),\r\n // controlDenominator = Math.floor(Math.pow(this.denominator, Math.abs(p)))\r\n //\r\n // if (controlNumerator ** Math.abs(p) === this.numerator\r\n // &&\r\n // controlDenominator ** Math.abs(p) === this.denominator) {\r\n //\r\n // this.numerator = this.numerator ** Math.abs(p);\r\n // this.denominator = this.denominator ** Math.abs(p);\r\n // } else {\r\n // this.numerator = this.numerator ** Math.abs(p);\r\n // this.denominator = this.denominator ** Math.abs(p);\r\n // }\r\n //\r\n // return this;\r\n // };\r\n\r\n parse(value: string | number, denominator: string | number): Fraction\r\n\r\n parse(value: string | number | Fraction, denominator ?: string | number): Fraction {\r\n // Default values\r\n this.numerator = 0;\r\n this.denominator = 1;\r\n\r\n // A null value means a zero fraction.\r\n if (value === null || value === \"\") return this;\r\n\r\n // No denominator given\r\n if (denominator === undefined) {\r\n if (value instanceof Fraction) return value.clone()\r\n\r\n if (typeof value === \"number\") {\r\n return new Fraction(value, 1)\r\n }\r\n\r\n // a value of type string can be:\r\n // - an integer number 4\r\n // - a decimal number 4.12\r\n // - a fraction 4/5\r\n // - a decimal fraction 4.12/5.12\r\n if (typeof value === \"string\") {\r\n const [N, D] = value.split('/')\r\n return new Fraction(N, D === undefined ? 1 : D)\r\n }\r\n }\r\n\r\n // Denominator given\r\n if (+denominator === 0) {\r\n this.numerator = Infinity\r\n return this\r\n }\r\n\r\n const [N1, D1] = Fraction.decimalToFraction(value)\r\n const [N2, D2] = Fraction.decimalToFraction(denominator)\r\n\r\n this.numerator = N1 * D2\r\n this.denominator = D1 * N2\r\n\r\n if (D1 > 1 || D2 > 1) this.reduce()\r\n return this\r\n }\r\n\r\n amplify = (k: number): Fraction => {\r\n if (Number.isSafeInteger(k)) {\r\n this.numerator *= k;\r\n this.denominator *= k;\r\n }\r\n return this;\r\n };\r\n\r\n}
106
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
107
+ <+>UTF-8
108
+ ===================================================================
109
+ diff --git a/src/maths/coefficients/fraction.ts b/src/maths/coefficients/fraction.ts
110
+ --- a/src/maths/coefficients/fraction.ts
111
+ +++ b/src/maths/coefficients/fraction.ts
112
+ @@ -13,69 +13,50 @@
113
+
114
+ this.fracType = FRACTION_FRAC.frac
115
+
116
+ + this.exact = true
117
+ +
118
+ if (value !== undefined) {
119
+ - if (value instanceof Fraction) return this.parse(value)
120
+ - return this.parse(value, denominator)
121
+ + if (value instanceof Fraction) return this._parse(value)
122
+ + return this._parse(value, denominator)
123
+ }
124
+
125
+ return this;
126
+ }
127
+
128
+ - get tex(): string {
129
+ - const frac = this.fracTeX
130
+ - // restore the frac type to default
131
+ - this.fracType = FRACTION_FRAC.frac
132
+ + static decimalToFraction = (value: string | number | Fraction): [number, number] => {
133
+ + // Return the neutral element
134
+ + if (value === undefined) return [1, 1]
135
+
136
+ - if (this.isInfinity()) {
137
+ - return `${this.signTeX}\\infty`
138
+ - }
139
+ + // Return the numerator and denominator if it's already a fraction
140
+ + if (value instanceof Fraction) return [value.numerator, value.denominator]
141
+
142
+ - if (this.isExact()) {
143
+ - if (this.denominator === 1) {
144
+ - return `${this.numerator}`;
145
+ - } else if (this.numerator < 0) {
146
+ - return `-${frac}{ ${-this.numerator} }{ ${this.denominator} }`;
147
+ - } else {
148
+ - return `${frac}{ ${this.numerator} }{ ${this.denominator} }`;
149
+ - }
150
+ - } else {
151
+ - return this.value.toFixed(3)
152
+ - }
153
+ - }
154
+ + // Split the name into unit and decimal part
155
+ + let [unit, decimal] = (+value).toString().split('.')
156
+
157
+ - get display(): string {
158
+ - if (this.isInfinity()) {
159
+ - return `${this.signTeX}\\infty`
160
+ - }
161
+ + // Return the unit if there is no decimal part
162
+ + if (decimal === undefined) return [+unit, 1]
163
+ +
164
+ + let decimalLength = decimal.length
165
+
166
+ - if (this.isExact()) {
167
+ - if (this.denominator === 1) {
168
+ - return `${this.numerator}`;
169
+ - } else if (this.numerator < 0) {
170
+ - return `-${-this.numerator}/${this.denominator}`;
171
+ - } else {
172
+ - return `${this.numerator}/${this.denominator}`;
173
+ - }
174
+ - } else {
175
+ - return this.value.toFixed(3)
176
+ + return [+(unit + decimal), 10 ** decimalLength]
177
+ + }
178
+ +
179
+ + static average = (...fractions: (Fraction | number)[]): Fraction => {
180
+ + let M = new Fraction().zero()
181
+ +
182
+ + for (let f of fractions) {
183
+ + M.add(f)
184
+ }
185
+ +
186
+ + M.divide(fractions.length)
187
+ +
188
+ + return M
189
+ }
190
+
191
+ createInstance(value?: string | number | Fraction): Fraction {
192
+ return new Fraction(value)
193
+ }
194
+
195
+ - clone = (): Fraction => {
196
+ - return new Fraction(this.numerator, this.denominator)
197
+ - };
198
+ -
199
+ - reduce = (): Fraction => {
200
+ - const {N, D} = this.getReducedCoefficient()
201
+ - this.numerator = N
202
+ - this.denominator = D
203
+ - return this;
204
+ - };
205
+ -
206
+ add = (...values: (Fraction | number | string)[]): Fraction => {
207
+ for (let F of values) {
208
+ if (!(F instanceof Fraction)) F = new Fraction(F)
209
+ @@ -91,7 +72,7 @@
210
+ };
211
+
212
+ multiply = (...values: (Fraction | number)[]): Fraction => {
213
+ - // Parse the value.
214
+ + // Parse the name.
215
+ // If it's a fraction, return a clone of it
216
+ // If it's an integer, return the fraction F/1
217
+ for (let F of values) {
218
+ @@ -115,104 +96,98 @@
219
+ }
220
+
221
+ root = (p: number): Fraction => {
222
+ - // TODO: index - root of a fraction => this will return another type of coefficient.
223
+ + // The indice cannot be negative.
224
+ + if (p < 0) {
225
+ + throw ("cannot make the root with a negative indice.")
226
+ + }
227
+
228
+ - // Check if they are perfect roots..
229
+ + // Power of zero => return one.
230
+ if (p === 0) {
231
+ - return this;
232
+ + return this.one();
233
+ }
234
+
235
+ - // If negative, invert the fraction
236
+ - if (p < 0) {
237
+ - this.invert()
238
+ + // Power of one => return this
239
+ + if (p === 1) {
240
+ + return this
241
+ }
242
+ -
243
+ - let n = Math.pow(this.numerator, Math.abs(1 / p)),
244
+ - d = Math.pow(this.denominator, Math.abs(1 / p));
245
+
246
+ this.numerator = Math.pow(this.numerator, Math.abs(1 / p));
247
+ this.denominator = Math.pow(this.denominator, Math.abs(1 / p));
248
+ +
249
+ + if (!Number.isSafeInteger(this.numerator) || !Number.isSafeInteger(this.denominator)) {
250
+ + this.exact = false
251
+ + this.numerator = this.numerator / this.denominator
252
+ + this.denominator = 1
253
+ + }
254
+ return this;
255
+ }
256
+
257
+ - static decimalToFraction = (value: string | number | Fraction): [number, number] => {
258
+ - // Return the neutral element
259
+ - if (value === undefined) return [1, 1]
260
+ + reduce = (): Fraction => {
261
+ + const {N, D} = this.getReducedCoefficient()
262
+ + this.numerator = N
263
+ + this.denominator = D
264
+ + return this;
265
+ + };
266
+
267
+ - // Return the numerator and denominator if it's already a fraction
268
+ - if (value instanceof Fraction) return [value.numerator, value.denominator]
269
+ + clone = (): Fraction => {
270
+ + return new Fraction(this.numerator, this.denominator)
271
+ + };
272
+
273
+ - // Split the value into unit and decimal part
274
+ - let [unit, decimal] = (+value).toString().split('.')
275
+ + get tex(): string {
276
+ + const frac = this.fracTeX
277
+ + // restore the frac type to default
278
+ + this.fracType = FRACTION_FRAC.frac
279
+
280
+ - // Return the unit if there is no decimal part
281
+ - if (decimal === undefined) return [+unit, 1]
282
+ + if (this.isInfinity()) {
283
+ + return `${this.signTeX}\\infty`
284
+ + }
285
+
286
+ - let decimalLength = decimal.length
287
+ -
288
+ - return [+(unit + decimal), 10 ** decimalLength]
289
+ + if (this.isExact()) {
290
+ + if (this.denominator === 1) {
291
+ + return `${this.numerator}`;
292
+ + } else if (this.numerator < 0) {
293
+ + return `-${frac}{ ${-this.numerator} }{ ${this.denominator} }`;
294
+ + } else {
295
+ + return `${frac}{ ${this.numerator} }{ ${this.denominator} }`;
296
+ + }
297
+ + } else {
298
+ + return this.value.toFixed(3)
299
+ + }
300
+ }
301
+
302
+ - static average = (...fractions: (Fraction | number)[]): Fraction => {
303
+ - let M = new Fraction().zero()
304
+ + get display(): string {
305
+ + if (this.isInfinity()) return `${this.signTeX}oo`
306
+
307
+ - for (let f of fractions) {
308
+ - M.add(f)
309
+ + if (this.isExact()) {
310
+ + if (this.denominator === 1) {
311
+ + return `${this.numerator}`;
312
+ + } else if (this.numerator < 0) {
313
+ + return `-${-this.numerator}/${this.denominator}`;
314
+ + } else {
315
+ + return `${this.numerator}/${this.denominator}`;
316
+ + }
317
+ + } else {
318
+ + return this.value.toFixed(3)
319
+ }
320
+ -
321
+ - M.divide(fractions.length)
322
+ -
323
+ - return M
324
+ }
325
+
326
+ /**
327
+ - * Parse the value to get the numerator and denominator
328
+ - * @param value : number or string to parse to get the fraction
329
+ - * @param denominatorOrPeriodic (optional|number) : length of the periodic part: 2.333333 => 1 or denominator value
330
+ + * Parse the name to get the numerator and denominator
331
+ + * @param value : number or string to _parse to get the fraction
332
+ + * @param denominatorOrPeriodic (optional|number) : length of the periodic part: 2.333333 => 1 or denominator name
333
+ */
334
+ - parse(value: Fraction): Fraction
335
+ -
336
+ - parse(value: string | number): Fraction
337
+ + protected _parse(value: Fraction): Fraction
338
+
339
+ + protected _parse(value: string | number): Fraction
340
+
341
+ - // pow = (p: number | Fraction): Fraction => {
342
+ - // // TODO: Fraction.pow with a value different than a safe integer !
343
+ - // if (p instanceof Fraction) {
344
+ - // return this.pow(p.value)
345
+ - // }
346
+ - //
347
+ - // this.reduce();
348
+ - // if (p < 0) {
349
+ - // this.invert()
350
+ - // }
351
+ - //
352
+ - // // Check if numerator and denominator are roots of...
353
+ - // // othervise, convert to numeric.
354
+ - // let controlNumerator = Math.floor(Math.pow(this.numerator, Math.abs(p))),
355
+ - // controlDenominator = Math.floor(Math.pow(this.denominator, Math.abs(p)))
356
+ - //
357
+ - // if (controlNumerator ** Math.abs(p) === this.numerator
358
+ - // &&
359
+ - // controlDenominator ** Math.abs(p) === this.denominator) {
360
+ - //
361
+ - // this.numerator = this.numerator ** Math.abs(p);
362
+ - // this.denominator = this.denominator ** Math.abs(p);
363
+ - // } else {
364
+ - // this.numerator = this.numerator ** Math.abs(p);
365
+ - // this.denominator = this.denominator ** Math.abs(p);
366
+ - // }
367
+ - //
368
+ - // return this;
369
+ - // };
370
+ + protected _parse(value: string | number, denominator: string | number): Fraction
371
+
372
+ - parse(value: string | number, denominator: string | number): Fraction
373
+ -
374
+ - parse(value: string | number | Fraction, denominator ?: string | number): Fraction {
375
+ + protected _parse(value: string | number | Fraction, denominator ?: string | number): Fraction {
376
+ // Default values
377
+ this.numerator = 0;
378
+ this.denominator = 1;
379
+
380
+ - // A null value means a zero fraction.
381
+ + // A null name means a zero fraction.
382
+ if (value === null || value === "") return this;
383
+
384
+ // No denominator given
385
+ @@ -223,7 +198,7 @@
386
+ return new Fraction(value, 1)
387
+ }
388
+
389
+ - // a value of type string can be:
390
+ + // a name of type string can be:
391
+ // - an integer number 4
392
+ // - a decimal number 4.12
393
+ // - a fraction 4/5
394
+ @@ -250,12 +225,4 @@
395
+ return this
396
+ }
397
+
398
+ - amplify = (k: number): Fraction => {
399
+ - if (Number.isSafeInteger(k)) {
400
+ - this.numerator *= k;
401
+ - this.denominator *= k;
402
+ - }
403
+ - return this;
404
+ - };
405
+ -
406
+ }
407
+
408
+ Index: src/maths/algebra/monom.ts
409
+ IDEA additional info:
410
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
411
+ <+>/***\r\n * Monom class\r\n * The monom class represents of monom of the form:\r\n * k * x^n * y^m * z^p\r\n * k: Coefficient\r\n * n, m, p: powers as Fraction\r\n * x, y, z: letters as string\r\n */\r\nimport {Numeric} from \"../numeric\";\r\nimport {Shutingyard, ShutingyardType, Token} from \"../shutingyard\";\r\nimport {COMPARESIGNS, literalType} from \"../types\";\r\nimport {RootFraction} from \"../coefficients/rootFraction\";\r\nimport {\r\n COEFFICIENT_MODE,\r\n CoefficientCore,\r\n CoefficientParserTypes,\r\n CoefficientTypes\r\n} from \"../coefficients/coefficientCore\";\r\nimport {Fraction} from \"../coefficients/fraction\";\r\n\r\n\r\nexport class Monom {\r\n private _coefficientMode: COEFFICIENT_MODE\r\n\r\n /**\r\n * Create a Monom\r\n * Defined as \\\\(k \\\\cdot x^{n}\\\\), where \\\\( k,n \\in \\\\mathbb{Q}\\\\).\r\n * Examples: \\\\(3x^2\\\\) or \\\\(3/5x^2\\\\)\r\n * @param value (optional) string The value that should be parse. Can be a Monom, a Fraction, a string or a number. If nothing is provided, it will return the trivial monom (0).\r\n */\r\n constructor(value?: unknown) {\r\n this.zero();\r\n\r\n if (value !== undefined) {\r\n // A string is given - try to parse the value.\r\n this.parse(value);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n // ------------------------------------------\r\n // Getter and setter\r\n\r\n private _coefficient: CoefficientCore<any>;\r\n\r\n // ------------------------------------------\r\n /**\r\n * Get the coefficient \\\\(k\\\\) of the Monom \\\\(k\\\\cdot x^{n}\\\\)\r\n * @returns {Fraction}\r\n */\r\n get coefficient(): CoefficientCore<any> {\r\n return this._coefficient;\r\n }\r\n\r\n /**\r\n * Set the coefficient \\\\(k\\\\) value of the monom\r\n * @param {Fraction | number | string} F\r\n */\r\n set coefficient(F: CoefficientParserTypes) {\r\n this._coefficient = this.makeCoefficient(F);\r\n }\r\n\r\n private _literal: literalType;\r\n\r\n /**\r\n * Get the literal part of \\\\(x^{n_1}y^{n_2}\\\\) as dictionary \\\\[\\\\begin{array}{ll}x&=n_1\\\\\\\\y&=n_2\\\\end{array}\\\\]\r\n * @returns {literalType}\r\n */\r\n get literal(): literalType {\r\n return this._literal;\r\n }\r\n\r\n /**\r\n * Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}\r\n * @param {literalType} L\r\n */\r\n set literal(L: literalType) {\r\n this._literal = L;\r\n }\r\n\r\n /**\r\n * Get the literal square roots of the Monom.\r\n * TODO: remove this getter ? Is it used and is it correct ?\r\n * @returns {literalType}\r\n */\r\n get literalSqrt(): literalType {\r\n if (this.isLiteralSquare()) {\r\n let L: literalType = {}\r\n for (let key in this._literal) {\r\n L[key] = this._literal[key].clone().sqrt()\r\n }\r\n return L;\r\n } else {\r\n return this._literal;\r\n }\r\n }\r\n\r\n /**\r\n * Set the literal part of the monom from a string\r\n * @param inputStr String like x^2y^3\r\n */\r\n set literalStr(inputStr: string) {\r\n // TODO : parse using shutingyard tree !\r\n\r\n // Match all x^n\r\n for (const v of [...inputStr.matchAll(/([a-z])\\^([+-]?[0-9]+)/g)]) {\r\n // Create the default letter entry if necessary.\r\n if (!(v[1] in this._literal)) {\r\n this._literal[v[1]] = this.makeCoefficient().zero();\r\n }\r\n\r\n // Add the new value.\r\n // TODO: actually, it adds only numeric value\r\n this._literal[v[1]].add(+v[2]);\r\n }\r\n\r\n // Match all x\r\n for (const v of [...inputStr.matchAll(/([a-z](?!\\^))/g)]) {\r\n // Match all single letters\r\n if (!(v[1] in this._literal)) {\r\n this._literal[v[1]] = this.makeCoefficient().zero();\r\n }\r\n\r\n // Add one to the value.\r\n this._literal[v[1]].add(1)\r\n }\r\n }\r\n\r\n // Getter helpers.\r\n /**\r\n * Get the variables letters\r\n */\r\n get variables(): string[] {\r\n let M = this.clone().clean();\r\n return Object.keys(M.literal)\r\n }\r\n\r\n // Display getter\r\n /**\r\n * This display getter is to be used in the polynom display getter\r\n */\r\n get display(): string {\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += `${letter}`;\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^(${this._literal[letter].display})`;\r\n }\r\n }\r\n }\r\n\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.display}`;\r\n } else {\r\n return '';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.display}${L}`;\r\n }\r\n }\r\n }\r\n\r\n get dividers(): Monom[] {\r\n // Decompose only if the coefficient is a natural number\r\n if (!this.coefficient.isRelative()) {\r\n return [this.clone()]\r\n }\r\n\r\n\r\n // Decompose only if the power values are natural numbers.\r\n if (this.hasFractionCoefficient()) {\r\n return [this.clone()]\r\n }\r\n\r\n // Security : do not do this if isGreaterThan than 10000\r\n if (this.coefficient.numerator > 1000000) {\r\n return [this.clone()]\r\n }\r\n\r\n const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))\r\n\r\n // Decompose the literals parts.\r\n let literals: literalType[] = [];\r\n for (let L in this.literal) {\r\n // L is the letter.\r\n literals = this._getLiteralDividers(literals, L)\r\n }\r\n\r\n const monomDividers: Monom[] = [];\r\n if (literals.length > 0 && dividers.length > 0) {\r\n for (let N of dividers) {\r\n for (let L of literals) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient(N)\r\n M.literal = L\r\n monomDividers.push(M)\r\n }\r\n }\r\n } else if (dividers.length === 0) {\r\n for (let L of literals) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient().one()\r\n M.literal = L\r\n monomDividers.push(M)\r\n }\r\n } else {\r\n for (let N of dividers) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient(N)\r\n monomDividers.push(M)\r\n }\r\n }\r\n\r\n return monomDividers.length === 0 ? [new Monom().one()] : monomDividers;\r\n }\r\n\r\n /**\r\n * Display the monom, forcing the '+' sign to appear\r\n */\r\n get displayWithSign(): string {\r\n let d: String = this.display;\r\n return (d[0] !== '-' ? '+' : '') + d;\r\n }\r\n\r\n get texWithSign(): string {\r\n if (this.coefficient.isStrictlyPositive()) {\r\n return '+' + this.tex\r\n }\r\n\r\n return this.tex\r\n }\r\n\r\n get plotFunction(): string {\r\n\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += (L === '' ? \"\" : \"*\") + `${letter}`\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^(${this._literal[letter].display})`;\r\n }\r\n }\r\n }\r\n\r\n // No literal part\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.display}`;\r\n } else {\r\n return '';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.display}*${L}`;\r\n }\r\n }\r\n }\r\n\r\n // ------------------------------------------\r\n // Creation / parsing functions\r\n\r\n /**\r\n * Get the tex output of the monom\r\n */\r\n get tex(): string {\r\n // TODO: display with square root !\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += `${letter}`;\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^{${this._literal[letter].asTopFraction().tex}}`;\r\n }\r\n }\r\n }\r\n\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.tex}`;\r\n } else {\r\n return '0';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.tex}${L}`;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get the least common multiple of monoms\r\n * @param monoms Array of monoms\r\n */\r\n static lcm = (...monoms: Monom[]): Monom => {\r\n // All the monoms must be with natural powers...\r\n for (let m of monoms) {\r\n if (m.hasFractionCoefficient()) {\r\n return new Monom().zero()\r\n }\r\n }\r\n\r\n\r\n let M = new Monom(),\r\n coeffN: number[] = monoms.map(value => value.coefficient.numerator),\r\n coeffD: number[] = monoms.map(value => value.coefficient.denominator),\r\n n = Numeric.gcd(...coeffN),\r\n d = Numeric.lcm(...coeffD);\r\n\r\n // Get the coefficient.\r\n M.coefficient = this.makeCoefficient(n, d).reduce();\r\n\r\n // Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.\r\n for (let m of monoms) {\r\n // Remove the inexistant letters from the resulting monom\r\n for (let letter in M.literal) {\r\n if (!(letter in m.literal)) {\r\n M.literal[letter].zero();\r\n }\r\n }\r\n for (let letter in m.literal) {\r\n if (M.literal[letter] === undefined && m.literal[letter].isStrictlyPositive()) {\r\n M.literal[letter] = m.literal[letter].clone();\r\n } else {\r\n M.literal[letter] = this.makeCoefficient(Math.min(m.literal[letter].value, M.literal[letter].value))\r\n }\r\n }\r\n }\r\n\r\n return M;\r\n };\r\n\r\n /**\r\n * Multiply two monoms and return a NEW monom.\r\n * @param monoms\r\n */\r\n static xmultiply = (...monoms: Monom[]): Monom => {\r\n let M = new Monom().one();\r\n\r\n for (let m of monoms) {\r\n M.multiply(m);\r\n }\r\n\r\n return M;\r\n };\r\n\r\n makeCoefficient = (...values: CoefficientParserTypes[]): CoefficientTypes => {\r\n if (this._coefficientMode === COEFFICIENT_MODE.FRACTION) {\r\n return new Fraction(...values as (Fraction | string | number)[])\r\n } else if (this._coefficientMode === COEFFICIENT_MODE.ROOT) {\r\n return new RootFraction(...values as (RootFraction | Fraction | string | number)[])\r\n }\r\n\r\n // TODO: add the other modes\r\n return new Fraction(...values as (Fraction | string | number)[])\r\n }\r\n\r\n// -----------------------------------------\r\n /**\r\n * Parse a string to a monom. The string may include fraction.\r\n * @param inputStr\r\n */\r\n parse = (inputStr: unknown): Monom => {\r\n\r\n if (typeof inputStr === 'string') {\r\n this._shutingYardToReducedMonom(inputStr)\r\n } else if (typeof inputStr === 'number') {\r\n this._coefficient = this.makeCoefficient(inputStr)\r\n this._literal = {}\r\n } else if (inputStr instanceof Fraction) {\r\n this._coefficient = inputStr.clone()\r\n this._literal = {}\r\n } else if (inputStr instanceof RootFraction) {\r\n this._coefficient = inputStr.clone()\r\n this._literal = {}\r\n } else if (inputStr instanceof Monom) {\r\n this._coefficient = inputStr._coefficient.clone()\r\n this._literal = this.copyLiterals(inputStr.literal)\r\n }\r\n\r\n return this;\r\n };\r\n\r\n addToken = (stack: Monom[], element: Token): void => {\r\n\r\n let q1: Monom, q2: Monom, m: Monom, letter: string, pow: CoefficientCore<any>\r\n\r\n if (element.tokenType === ShutingyardType.COEFFICIENT) {\r\n stack.push(new Monom(this.makeCoefficient(element.token)))\r\n\r\n } else if (element.tokenType === ShutingyardType.VARIABLE) {\r\n let M = new Monom().one()\r\n M.setLetter(element.token, 1)\r\n stack.push(M.clone())\r\n\r\n } else if (element.tokenType === ShutingyardType.OPERATION) {\r\n switch (element.token) {\r\n case '-':\r\n // this should only happen for negative powers or for negative coefficient.\r\n q2 = (stack.pop()) || new Monom().zero()\r\n q1 = (stack.pop()) || new Monom().zero()\r\n\r\n stack.push(q1.subtract(q2))\r\n\r\n break;\r\n case '*':\r\n // Get the last element in the stack\r\n q2 = (stack.pop()) || new Monom().one()\r\n q1 = (stack.pop()) || new Monom().one()\r\n\r\n stack.push(q1.multiply(q2))\r\n break\r\n case '/':\r\n // Get the last element in the stack\r\n q2 = (stack.pop()) || new Monom().one()\r\n q1 = (stack.pop()) || new Monom().one()\r\n\r\n stack.push(q1.divide(q2))\r\n break\r\n case '^':\r\n // get the two last elements in the stack\r\n pow = (stack.pop().coefficient) || this.makeCoefficient().one()\r\n m = (stack.pop()) || new Monom().one()\r\n\r\n letter = m.variables[0]\r\n\r\n if (letter !== undefined) {\r\n m.setLetter(letter, pow)\r\n }\r\n\r\n stack.push(m)\r\n // this.multiply(m.clone())\r\n break\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Clone the current Monom.\r\n */\r\n clone = (): Monom => {\r\n let F: Monom = new Monom();\r\n\r\n F.coefficient = this._coefficient.clone();\r\n\r\n // Copy the literal parts.\r\n for (let k in this._literal) {\r\n F.setLetter(k, this._literal[k].clone());\r\n }\r\n return F;\r\n };\r\n\r\n copyLiterals = (literal: literalType): literalType => {\r\n let L: literalType = {}\r\n\r\n for (let k in literal) {\r\n L[k] = literal[k].clone()\r\n }\r\n return L\r\n }\r\n\r\n makeSame = (M: Monom): Monom => {\r\n // Copy the literal parts.\r\n for (let k in M._literal) {\r\n this.setLetter(k, M._literal[k].clone());\r\n }\r\n return this\r\n }\r\n\r\n /**\r\n * Create a zero value monom\r\n */\r\n zero = (): Monom => {\r\n this._coefficient = this.makeCoefficient().zero();\r\n this._literal = {};\r\n return this;\r\n };\r\n\r\n /**\r\n * Create a one value monom\r\n */\r\n one = (): Monom => {\r\n this._coefficient = this.makeCoefficient().one();\r\n this._literal = {};\r\n return this;\r\n };\r\n\r\n// ------------------------------------------\r\n// Mathematical operations\r\n// ------------------------------------------\r\n\r\n /**\r\n * Clean the monom by removing each letters with a power of zero.\r\n */\r\n clean = (): Monom => {\r\n for (let letter in this._literal) {\r\n if (this._literal[letter].isZero()) {\r\n delete this._literal[letter];\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n reduce = (): Monom => {\r\n this.clean()\r\n this.coefficient.reduce()\r\n return this\r\n }\r\n\r\n /**\r\n * Get the opposite\r\n * Returns a monom.\r\n */\r\n opposed = (): Monom => {\r\n this._coefficient.opposite();\r\n return this;\r\n };\r\n\r\n /**\r\n * Add all similar monoms. If they aren't similar, they are simply skipped.\r\n * @param M (Monom[]) The monoms to add.\r\n */\r\n add = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n if (this.isSameAs(m)) {\r\n if (this.isZero()) {\r\n this.makeSame(m)\r\n }\r\n this._coefficient.add(m.coefficient);\r\n } else {\r\n console.log('Add monom: ' + this.display + ' is not similar with ', m.display);\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Subtract multiple monoms\r\n * @param M (Monom[]) The monoms to subtract\r\n */\r\n subtract = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n if (this.isSameAs(m)) {\r\n if (this.isZero()) {\r\n this.makeSame(m)\r\n }\r\n this._coefficient.add(m.clone().coefficient.opposite());\r\n } else {\r\n console.log('Subtract: Is not similar: ', m.display);\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Multiple multiple monoms to the current monom\r\n * @param M (Monom[]) The monoms to multiply to.\r\n */\r\n multiply = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n // Multiply the coefficient.\r\n this._coefficient.multiply(m.coefficient);\r\n\r\n // Multiply the literal parts.\r\n for (let letter in m.literal) {\r\n if (this._literal[letter] === undefined) {\r\n this._literal[letter] = m.literal[letter].clone()\r\n } else {\r\n this._literal[letter].add(m.literal[letter])\r\n }\r\n\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n multiplyByNumber = (F: Fraction | number): Monom => {\r\n this._coefficient.multiply(F);\r\n return this;\r\n }\r\n\r\n /**\r\n * Divide the current monoms by multiple monoms\r\n * @param M (Monom[])\r\n */\r\n divide = (...M: Monom[]): Monom => {\r\n // Depending on the given value, choose the current item\r\n for (let v of M) {\r\n // Divide the coefficient\r\n this._coefficient.divide(v.coefficient);\r\n\r\n // Subtract the power values\r\n for (let letter in v.literal) {\r\n this._literal[letter] = (this._literal[letter] === undefined) ? v.literal[letter].clone().opposite() : this._literal[letter].subtract(v.literal[letter])\r\n\r\n // If the power of a particular setLetter is zero, delete it from the literal part..\r\n if (this._literal[letter].isZero()) {\r\n delete this._literal[letter];\r\n }\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Get the pow of a monom.\r\n * @param nb (number) : Mathematical pow\r\n */\r\n pow = (nb: number | Fraction): Monom => {\r\n this._coefficient.pow(nb);\r\n for (let letter in this._literal) {\r\n this._literal[letter].multiply(nb)\r\n }\r\n return this;\r\n };\r\n\r\n// ------------------------------------------\r\n// Compare functions\r\n\r\n /**\r\n * Get the index-root of the monom\r\n * @param p\r\n */\r\n root = (p: number): Monom => {\r\n // TODO: determiner the index root of a monom\r\n return this;\r\n }\r\n\r\n /**\r\n * Return the square root of a monom\r\n */\r\n sqrt = (): Monom => {\r\n if (this.isSquare()) {\r\n this._coefficient.sqrt();\r\n for (let letter in this._literal) {\r\n this._literal[letter].clone().divide(2)\r\n }\r\n }\r\n return this.root(2);\r\n }\r\n\r\n// ------------------------------------------\r\n compare = (M: Monom, sign?: COMPARESIGNS): boolean => {\r\n // TODO: Build the compare systems.\r\n if (sign === undefined) {\r\n sign = COMPARESIGNS.EQUALS;\r\n }\r\n\r\n\r\n switch (sign) {\r\n case COMPARESIGNS.EQUALS:\r\n // To be equal, they must be the isSame\r\n if (!this.compare(M, COMPARESIGNS.SAME)) {\r\n return false;\r\n }\r\n\r\n // The literal parts are the isSame. The coefficient must be equal\r\n return this._coefficient.isEqualTo(M.coefficient);\r\n case COMPARESIGNS.SAME:\r\n // Get the list of all variables from both monoms.\r\n let M1: string[] = this.variables,\r\n M2: string[] = M.variables,\r\n K: string[] = M1.concat(M2.filter((item) => M1.indexOf(item) < 0));\r\n\r\n if (M1.length === 0 && M2.length === 0) {\r\n return true\r\n }\r\n // To compare, both must be different than zero.\r\n if (!this.isZero() && !M.isZero()) {\r\n for (let key of K) {\r\n // The setLetter is not available in one of the monom\r\n if (this._literal[key] === undefined || M.literal[key] === undefined) {\r\n return false;\r\n }\r\n // The setLetter does not have the isSame power in each monoms.\r\n if (!this._literal[key].isEqualTo(M.literal[key])) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n // All are positive check - the monoms are the sames.\r\n return true;\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Determine if the monom is null\r\n */\r\n isZero()\r\n :\r\n boolean {\r\n return this._coefficient.value === 0;\r\n }\r\n\r\n /**\r\n * Determine if the monom is one\r\n */\r\n isOne()\r\n :\r\n boolean {\r\n return this._coefficient.value === 1 && this.variables.length === 0;\r\n }\r\n\r\n /**\r\n * Determine if two monoms are equals\r\n * @param M\r\n */\r\n isEqual = (M: Monom): boolean => {\r\n return this.compare(M, COMPARESIGNS.EQUALS);\r\n };\r\n\r\n /**\r\n * Determine if two monoms are similar\r\n * @param M\r\n */\r\n isSameAs = (M: Monom): boolean => {\r\n return this.compare(M, COMPARESIGNS.SAME);\r\n };\r\n\r\n isSquare = (): boolean => {\r\n if (!this.coefficient.isSquare()) {\r\n return false;\r\n }\r\n return this.isLiteralSquare();\r\n }\r\n// ------------------------------------------\r\n// Misc monoms functions\r\n\r\n isLiteralSquare = (): boolean => {\r\n for (let letter in this.literal) {\r\n // A literal square must have a natural power\r\n if (this.literal[letter].isRational()) {\r\n return false\r\n }\r\n\r\n // The natural power must be be even\r\n if (this.literal[letter].isEven()) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n hasFractionCoefficient = (): boolean => {\r\n for (let letter in this._literal) {\r\n if (this._literal[letter].isRational()) {\r\n return true\r\n }\r\n }\r\n\r\n return false\r\n }\r\n\r\n// -------------------------------------\r\n /**\r\n * Determine if a monom contains a setLetter in it's literal part\r\n * @param letter\r\n */\r\n hasLetter = (letter?: string): boolean => {\r\n // The letter was not found\r\n if (this._literal[letter === undefined ? 'x' : letter] === undefined) {\r\n return false\r\n }\r\n\r\n // The letter is found and is not zero !\r\n return !this._literal[letter === undefined ? 'x' : letter].isZero();\r\n };\r\n\r\n /**\r\n * Set the power of a particular setLetter\r\n * @param letter (string) Letter to change\r\n * @param pow (number) Power of the setLetter (must be positive integer.\r\n */\r\n setLetter = (letter: string, pow: CoefficientCore<any> | number): void => {\r\n if (pow instanceof CoefficientCore) {\r\n // Set the power of the letter to zero => remove it\r\n if (this.hasLetter(letter) && pow.isZero()) {\r\n delete this._literal[letter]\r\n }\r\n\r\n this._literal[letter] = pow.clone()\r\n } else {\r\n this.setLetter(letter, this.makeCoefficient(pow))\r\n }\r\n };\r\n\r\n /**\r\n * Get the degree of a monom. If no setLetter is given, the result will be the global degree.\r\n * @param letter (string) Letter to get to degree (power)\r\n */\r\n degree = (letter?: string): CoefficientTypes => {\r\n if (this.variables.length === 0) {\r\n return this.makeCoefficient().zero();\r\n }\r\n if (letter === undefined) {\r\n // Not setLetter given -> we get the global monom degree (sum of all the letters).\r\n return Object.values(this._literal)\r\n .reduce(\r\n (t, n) => t.clone().add(n)\r\n );\r\n } else {\r\n // A setLetter is given -> get the corresponding power.\r\n return this._literal[letter] === undefined ? this.makeCoefficient().zero() : this._literal[letter].clone();\r\n }\r\n };\r\n\r\n /**\r\n * Evaluate a monom. Each setLetter must be assigned to a Fraction.\r\n * @param values Dictionary of <setLetter: Fraction>\r\n */\r\n evaluate = (values?: literalType | Fraction | number): CoefficientCore<any> => {\r\n let r = this.coefficient.clone();\r\n\r\n if (typeof values === 'number' || values instanceof Fraction) {\r\n let tmpValues: literalType = {}\r\n tmpValues[this.variables[0]] = this.makeCoefficient(values)\r\n return this.evaluate(tmpValues);\r\n }\r\n\r\n if (typeof values === 'object') {\r\n if (this.variables.length === 0) {\r\n return this.coefficient\r\n }\r\n for (let L in this._literal) {\r\n if (values[L] === undefined) {\r\n return this.makeCoefficient().zero();\r\n }\r\n\r\n let value = this.makeCoefficient(values[L])\r\n\r\n r.multiply(value.pow(this._literal[L]))\r\n }\r\n }\r\n\r\n return r;\r\n };\r\n\r\n evaluateAsNumeric = (values: { [Key: string]: number } | number): number => {\r\n let r = this.coefficient.value\r\n\r\n if (typeof values === 'number') {\r\n let tmpValues: { [Key: string]: number } = {}\r\n tmpValues[this.variables[0]] = values\r\n return this.evaluateAsNumeric(tmpValues);\r\n }\r\n\r\n if (typeof values === 'object') {\r\n if (this.variables.length === 0) {\r\n return this.coefficient.value\r\n }\r\n for (let L in this._literal) {\r\n if (values[L] === undefined) {\r\n return 0;\r\n }\r\n\r\n r *= values[L] ** (this._literal[L].value)\r\n }\r\n }\r\n\r\n return r\r\n }\r\n// ----------------------------------------\r\n// Static functions\r\n// ----------------------------------------\r\n\r\n /**\r\n * Derivative the monom\r\n * @param letter\r\n */\r\n derivative = (letter?: string): Monom => {\r\n // No setLetter given - assume it's the setLetter 'x'\r\n if (letter === undefined) {\r\n letter = 'x';\r\n }\r\n\r\n if (this.hasLetter(letter)) {\r\n let d = this._literal[letter].clone(),\r\n dM = this.clone();\r\n\r\n // Subtract one to the degree.\r\n dM._literal[letter].subtract(1)\r\n\r\n // Multiply the coefficient by the previous degree\r\n dM._coefficient.multiply(this.makeCoefficient(d.clone()));\r\n return dM;\r\n } else {\r\n return new Monom().zero();\r\n }\r\n };\r\n\r\n primitive = (letter?: string): Monom => {\r\n // TODO: derivative including the ln value => implies creating different monom system ?\r\n if (letter === undefined) {\r\n letter = 'x'\r\n }\r\n\r\n // Zero monom\r\n let M = this.clone(), degree\r\n\r\n if (M.hasLetter(letter)) {\r\n degree = M.degree(letter).clone().add(1)\r\n M.coefficient = M.coefficient.clone().divide(degree)\r\n M.setLetter(letter, degree)\r\n } else {\r\n // There is no letter.\r\n\r\n // The coefficient might be zero (=> x) or a number a (=> ax)\r\n if (M.coefficient.isZero()) {\r\n M.coefficient = this.makeCoefficient().one()\r\n }\r\n M.setLetter(letter, 1)\r\n }\r\n\r\n return M\r\n }\r\n\r\n// TODO: The rest of the functions are not used or unnecessary ?\r\n /**\r\n * Determine if multiple monoms are similar\r\n * @param M\r\n */\r\n areSameAs = (...M: Monom[]): boolean => {\r\n let result: boolean = true;\r\n\r\n // Check all monoms if they are the isSame as the \"this\" one.\r\n for (let i = 0; i < M.length; i++) {\r\n if (!this.isSameAs(M[i])) {\r\n return false;\r\n }\r\n }\r\n\r\n // All check passed -> all the monoms are similar.\r\n return result;\r\n };\r\n\r\n /**\r\n * Determine if multiple monoms are equals\r\n * @param M\r\n */\r\n areEquals = (...M: Monom[]): boolean => {\r\n // They are not similar.\r\n if (!this.areSameAs(...M)) {\r\n return false;\r\n }\r\n\r\n // Check all coefficient. They must be equals.\r\n for (let m of M) {\r\n if (!this._coefficient.isEqualTo(m.coefficient)) {\r\n return false;\r\n }\r\n }\r\n\r\n // All checks passed.\r\n return true;\r\n };\r\n\r\n isDivisible = (div: Monom): boolean => {\r\n // For all variables (letters), the current monom must have a degree higher than the divider\r\n if (div.degree().isStrictlyPositive()) {\r\n for (let letter of div.variables) {\r\n if (!this.degree(letter).isGreaterOrEqualTo(div.degree(letter))) {\r\n return false\r\n }\r\n }\r\n }\r\n\r\n // If the coefficient is rational, we suppose we don't need to check the division by the coefficient.\r\n if (this.coefficient.isRational() || div.coefficient.isRational()) {\r\n return true\r\n }\r\n\r\n return this.coefficient.clone().divide(div.coefficient).isRelative()\r\n }\r\n\r\n isInverted(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return this.clone().multiply(M).isOne();\r\n }\r\n\r\n isNegativeOne()\r\n :\r\n boolean {\r\n return this._coefficient.value === -1 && this.variables.length === 0;\r\n }\r\n\r\n isNotEqual(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return !this.isEqual(M);\r\n }\r\n\r\n isNotZero()\r\n :\r\n boolean {\r\n return !this.isZero();\r\n }\r\n\r\n isOpposed(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return this.clone().subtract(M).isZero();\r\n }\r\n\r\n isReduced()\r\n :\r\n boolean {\r\n // By construction, it is already reduced (litterals\r\n return this.coefficient.isReduced();\r\n }\r\n\r\n reset()\r\n :\r\n any {\r\n this._coefficient = this.makeCoefficient()\r\n this._literal = {}\r\n }\r\n\r\n _getLiteralDividers(arr: literalType[], letter: string):\r\n literalType[] {\r\n let tmpList: { [key: string]: CoefficientTypes }[] = [];\r\n\r\n // Be default, this.literal[letter] should be a rational number.\r\n for (let d = 0; d <= this.literal[letter].value; d++) {\r\n if (arr.length === 0) {\r\n let litt: literalType = {}\r\n litt[letter] = this.makeCoefficient(d)\r\n tmpList.push(litt)\r\n } else {\r\n for (let item of arr) {\r\n let litt: literalType = {}\r\n for (let currentLetter in item) {\r\n litt[currentLetter] = item[currentLetter]\r\n }\r\n litt[letter] = this.makeCoefficient(d)\r\n tmpList.push(litt)\r\n }\r\n }\r\n }\r\n return tmpList;\r\n }\r\n\r\n _shutingYardToReducedMonom = (inputStr: string): Monom => {\r\n // Get the RPN array of the current expression\r\n const SY: Shutingyard = new Shutingyard().parse(inputStr);\r\n const rpn: { token: string, tokenType: string }[] = SY.rpn;\r\n\r\n let stack: Monom[] = []\r\n\r\n if (rpn.length === 0) {\r\n this.zero()\r\n return this\r\n } else if (rpn.length === 1) {\r\n const element = rpn[0]\r\n\r\n this.one()\r\n if (element.tokenType === 'coefficient') {\r\n this.coefficient = this.makeCoefficient(element.token)\r\n } else if (element.tokenType === 'variable') {\r\n this.setLetter(element.token, 1)\r\n }\r\n return this\r\n } else {\r\n // Reset the monom\r\n for (const element of rpn) {\r\n this.addToken(stack, element)\r\n }\r\n }\r\n\r\n this.one()\r\n this.multiply(stack[0])\r\n return this\r\n }\r\n}\r\n
412
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
413
+ <+>UTF-8
414
+ ===================================================================
415
+ diff --git a/src/maths/algebra/monom.ts b/src/maths/algebra/monom.ts
416
+ --- a/src/maths/algebra/monom.ts
417
+ +++ b/src/maths/algebra/monom.ts
418
+ @@ -1,1113 +1,171 @@
419
+ -/***
420
+ - * Monom class
421
+ - * The monom class represents of monom of the form:
422
+ - * k * x^n * y^m * z^p
423
+ - * k: Coefficient
424
+ - * n, m, p: powers as Fraction
425
+ - * x, y, z: letters as string
426
+ - */
427
+ -import {Numeric} from "../numeric";
428
+ -import {Shutingyard, ShutingyardType, Token} from "../shutingyard";
429
+ -import {COMPARESIGNS, literalType} from "../types";
430
+ -import {RootFraction} from "../coefficients/rootFraction";
431
+ import {
432
+ - COEFFICIENT_MODE,
433
+ - CoefficientCore,
434
+ - CoefficientParserTypes,
435
+ - CoefficientTypes
436
+ -} from "../coefficients/coefficientCore";
437
+ -import {Fraction} from "../coefficients/fraction";
438
+ -
439
+ -
440
+ -export class Monom {
441
+ - private _coefficientMode: COEFFICIENT_MODE
442
+ -
443
+ - /**
444
+ - * Create a Monom
445
+ - * Defined as \\(k \\cdot x^{n}\\), where \\( k,n \in \\mathbb{Q}\\).
446
+ - * Examples: \\(3x^2\\) or \\(3/5x^2\\)
447
+ - * @param value (optional) string The value that should be parse. Can be a Monom, a Fraction, a string or a number. If nothing is provided, it will return the trivial monom (0).
448
+ - */
449
+ - constructor(value?: unknown) {
450
+ - this.zero();
451
+ -
452
+ - if (value !== undefined) {
453
+ - // A string is given - try to parse the value.
454
+ - this.parse(value);
455
+ - }
456
+ -
457
+ - return this;
458
+ - }
459
+ -
460
+ - // ------------------------------------------
461
+ - // Getter and setter
462
+ -
463
+ - private _coefficient: CoefficientCore<any>;
464
+ -
465
+ - // ------------------------------------------
466
+ - /**
467
+ - * Get the coefficient \\(k\\) of the Monom \\(k\\cdot x^{n}\\)
468
+ - * @returns {Fraction}
469
+ - */
470
+ - get coefficient(): CoefficientCore<any> {
471
+ - return this._coefficient;
472
+ - }
473
+ -
474
+ - /**
475
+ - * Set the coefficient \\(k\\) value of the monom
476
+ - * @param {Fraction | number | string} F
477
+ - */
478
+ - set coefficient(F: CoefficientParserTypes) {
479
+ - this._coefficient = this.makeCoefficient(F);
480
+ - }
481
+ -
482
+ - private _literal: literalType;
483
+ -
484
+ - /**
485
+ - * Get the literal part of \\(x^{n_1}y^{n_2}\\) as dictionary \\[\\begin{array}{ll}x&=n_1\\\\y&=n_2\\end{array}\\]
486
+ - * @returns {literalType}
487
+ - */
488
+ - get literal(): literalType {
489
+ - return this._literal;
490
+ - }
491
+ -
492
+ - /**
493
+ - * Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}
494
+ - * @param {literalType} L
495
+ - */
496
+ - set literal(L: literalType) {
497
+ - this._literal = L;
498
+ - }
499
+ + coreInterface,
500
+ + equalityInterface,
501
+ + expressionElementInterface,
502
+ + expressionInterface,
503
+ + operationInterface
504
+ +} from "../types";
505
+ +import {Coefficient} from "../coefficients/coefficient";
506
+
507
+ - /**
508
+ - * Get the literal square roots of the Monom.
509
+ - * TODO: remove this getter ? Is it used and is it correct ?
510
+ - * @returns {literalType}
511
+ - */
512
+ - get literalSqrt(): literalType {
513
+ - if (this.isLiteralSquare()) {
514
+ - let L: literalType = {}
515
+ - for (let key in this._literal) {
516
+ - L[key] = this._literal[key].clone().sqrt()
517
+ - }
518
+ - return L;
519
+ - } else {
520
+ - return this._literal;
521
+ - }
522
+ - }
523
+
524
+ - /**
525
+ - * Set the literal part of the monom from a string
526
+ - * @param inputStr String like x^2y^3
527
+ - */
528
+ - set literalStr(inputStr: string) {
529
+ - // TODO : parse using shutingyard tree !
530
+ -
531
+ - // Match all x^n
532
+ - for (const v of [...inputStr.matchAll(/([a-z])\^([+-]?[0-9]+)/g)]) {
533
+ - // Create the default letter entry if necessary.
534
+ - if (!(v[1] in this._literal)) {
535
+ - this._literal[v[1]] = this.makeCoefficient().zero();
536
+ - }
537
+ +/**
538
+ + * A polynom element is a coefficient with one or more variables and an exponent (which is a power and a root).
539
+ + *
540
+ + */
541
+ +export class Monom implements coreInterface, operationInterface, equalityInterface, expressionInterface {
542
+ + constructor(...values: unknown[]) {
543
+
544
+ - // Add the new value.
545
+ - // TODO: actually, it adds only numeric value
546
+ - this._literal[v[1]].add(+v[2]);
547
+ + if (values.length > 0) {
548
+ + return this.parse(...values)
549
+ }
550
+ -
551
+ - // Match all x
552
+ - for (const v of [...inputStr.matchAll(/([a-z](?!\^))/g)]) {
553
+ - // Match all single letters
554
+ - if (!(v[1] in this._literal)) {
555
+ - this._literal[v[1]] = this.makeCoefficient().zero();
556
+ - }
557
+ + return this
558
+ + }
559
+
560
+ - // Add one to the value.
561
+ - this._literal[v[1]].add(1)
562
+ - }
563
+ - }
564
+ + private _literal: expressionElementInterface = {}
565
+
566
+ - // Getter helpers.
567
+ - /**
568
+ - * Get the variables letters
569
+ - */
570
+ get variables(): string[] {
571
+ - let M = this.clone().clean();
572
+ - return Object.keys(M.literal)
573
+ + return Object.keys(this._literal).sort()
574
+ }
575
+ -
576
+ - // Display getter
577
+ - /**
578
+ - * This display getter is to be used in the polynom display getter
579
+ - */
580
+ - get display(): string {
581
+ - let L: string = '',
582
+ - letters = Object.keys(this._literal).sort()
583
+ - for (let letter of letters) {
584
+ - if (!this._literal[letter].isZero()) {
585
+ - L += `${letter}`;
586
+ - if (!this._literal[letter].isEqualTo(1)) {
587
+ - L += `^(${this._literal[letter].display})`;
588
+ - }
589
+ - }
590
+ - }
591
+ -
592
+ - if (L === '') {
593
+ - // No setLetter - means it's only a number !
594
+ - if (this._coefficient.value != 0) {
595
+ - return `${this._coefficient.display}`;
596
+ - } else {
597
+ - return '';
598
+ - }
599
+ - } else {
600
+ - if (this._coefficient.value === 1) {
601
+ - return L;
602
+ - } else if (this._coefficient.value === -1) {
603
+ - return `-${L}`;
604
+ - } else if (this._coefficient.value === 0) {
605
+ - return '0';
606
+ - } else {
607
+ - return `${this._coefficient.display}${L}`;
608
+ - }
609
+ - }
610
+ - }
611
+ -
612
+ - get dividers(): Monom[] {
613
+ - // Decompose only if the coefficient is a natural number
614
+ - if (!this.coefficient.isRelative()) {
615
+ - return [this.clone()]
616
+ - }
617
+ -
618
+ -
619
+ - // Decompose only if the power values are natural numbers.
620
+ - if (this.hasFractionCoefficient()) {
621
+ - return [this.clone()]
622
+ - }
623
+ -
624
+ - // Security : do not do this if isGreaterThan than 10000
625
+ - if (this.coefficient.numerator > 1000000) {
626
+ - return [this.clone()]
627
+ - }
628
+ -
629
+ - const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))
630
+ -
631
+ - // Decompose the literals parts.
632
+ - let literals: literalType[] = [];
633
+ - for (let L in this.literal) {
634
+ - // L is the letter.
635
+ - literals = this._getLiteralDividers(literals, L)
636
+ - }
637
+ -
638
+ - const monomDividers: Monom[] = [];
639
+ - if (literals.length > 0 && dividers.length > 0) {
640
+ - for (let N of dividers) {
641
+ - for (let L of literals) {
642
+ - let M = new Monom();
643
+ - M.coefficient = this.makeCoefficient(N)
644
+ - M.literal = L
645
+ - monomDividers.push(M)
646
+ - }
647
+ - }
648
+ - } else if (dividers.length === 0) {
649
+ - for (let L of literals) {
650
+ - let M = new Monom();
651
+ - M.coefficient = this.makeCoefficient().one()
652
+ - M.literal = L
653
+ - monomDividers.push(M)
654
+ - }
655
+ - } else {
656
+ - for (let N of dividers) {
657
+ - let M = new Monom();
658
+ - M.coefficient = this.makeCoefficient(N)
659
+ - monomDividers.push(M)
660
+ - }
661
+ - }
662
+ -
663
+ - return monomDividers.length === 0 ? [new Monom().one()] : monomDividers;
664
+ - }
665
+ -
666
+ - /**
667
+ - * Display the monom, forcing the '+' sign to appear
668
+ - */
669
+ - get displayWithSign(): string {
670
+ - let d: String = this.display;
671
+ - return (d[0] !== '-' ? '+' : '') + d;
672
+ - }
673
+ -
674
+ - get texWithSign(): string {
675
+ - if (this.coefficient.isStrictlyPositive()) {
676
+ - return '+' + this.tex
677
+ - }
678
+ -
679
+ - return this.tex
680
+ - }
681
+ -
682
+ - get plotFunction(): string {
683
+ -
684
+ - let L: string = '',
685
+ - letters = Object.keys(this._literal).sort()
686
+ -
687
+ - for (let letter of letters) {
688
+ - if (!this._literal[letter].isZero()) {
689
+ - L += (L === '' ? "" : "*") + `${letter}`
690
+ - if (!this._literal[letter].isEqualTo(1)) {
691
+ - L += `^(${this._literal[letter].display})`;
692
+ - }
693
+ - }
694
+ - }
695
+ -
696
+ - // No literal part
697
+ - if (L === '') {
698
+ - // No setLetter - means it's only a number !
699
+ - if (this._coefficient.value != 0) {
700
+ - return `${this._coefficient.display}`;
701
+ - } else {
702
+ - return '';
703
+ - }
704
+ - } else {
705
+ - if (this._coefficient.value === 1) {
706
+ - return L;
707
+ - } else if (this._coefficient.value === -1) {
708
+ - return `-${L}`;
709
+ - } else if (this._coefficient.value === 0) {
710
+ - return '0';
711
+ - } else {
712
+ - return `${this._coefficient.display}*${L}`;
713
+ - }
714
+ - }
715
+ - }
716
+ -
717
+ - // ------------------------------------------
718
+ - // Creation / parsing functions
719
+ -
720
+ - /**
721
+ - * Get the tex output of the monom
722
+ - */
723
+ - get tex(): string {
724
+ - // TODO: display with square root !
725
+ - let L: string = '',
726
+ - letters = Object.keys(this._literal).sort()
727
+ -
728
+ - for (let letter of letters) {
729
+ - if (!this._literal[letter].isZero()) {
730
+ - L += `${letter}`;
731
+ - if (!this._literal[letter].isEqualTo(1)) {
732
+ - L += `^{${this._literal[letter].asTopFraction().tex}}`;
733
+ - }
734
+ - }
735
+ - }
736
+ -
737
+ - if (L === '') {
738
+ - // No setLetter - means it's only a number !
739
+ - if (this._coefficient.value != 0) {
740
+ - return `${this._coefficient.tex}`;
741
+ - } else {
742
+ - return '0';
743
+ - }
744
+ - } else {
745
+ - if (this._coefficient.value === 1) {
746
+ - return L;
747
+ - } else if (this._coefficient.value === -1) {
748
+ - return `-${L}`;
749
+ - } else if (this._coefficient.value === 0) {
750
+ - return '0';
751
+ - } else {
752
+ - return `${this._coefficient.tex}${L}`;
753
+ - }
754
+ - }
755
+ - }
756
+ -
757
+ - /**
758
+ - * Get the least common multiple of monoms
759
+ - * @param monoms Array of monoms
760
+ - */
761
+ - static lcm = (...monoms: Monom[]): Monom => {
762
+ - // All the monoms must be with natural powers...
763
+ - for (let m of monoms) {
764
+ - if (m.hasFractionCoefficient()) {
765
+ - return new Monom().zero()
766
+ - }
767
+ - }
768
+ -
769
+ -
770
+ - let M = new Monom(),
771
+ - coeffN: number[] = monoms.map(value => value.coefficient.numerator),
772
+ - coeffD: number[] = monoms.map(value => value.coefficient.denominator),
773
+ - n = Numeric.gcd(...coeffN),
774
+ - d = Numeric.lcm(...coeffD);
775
+ -
776
+ - // Get the coefficient.
777
+ - M.coefficient = this.makeCoefficient(n, d).reduce();
778
+ -
779
+ - // Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.
780
+ - for (let m of monoms) {
781
+ - // Remove the inexistant letters from the resulting monom
782
+ - for (let letter in M.literal) {
783
+ - if (!(letter in m.literal)) {
784
+ - M.literal[letter].zero();
785
+ - }
786
+ - }
787
+ - for (let letter in m.literal) {
788
+ - if (M.literal[letter] === undefined && m.literal[letter].isStrictlyPositive()) {
789
+ - M.literal[letter] = m.literal[letter].clone();
790
+ - } else {
791
+ - M.literal[letter] = this.makeCoefficient(Math.min(m.literal[letter].value, M.literal[letter].value))
792
+ - }
793
+ - }
794
+ - }
795
+ -
796
+ - return M;
797
+ - };
798
+ -
799
+ - /**
800
+ - * Multiply two monoms and return a NEW monom.
801
+ - * @param monoms
802
+ - */
803
+ - static xmultiply = (...monoms: Monom[]): Monom => {
804
+ - let M = new Monom().one();
805
+ -
806
+ - for (let m of monoms) {
807
+ - M.multiply(m);
808
+ - }
809
+
810
+ - return M;
811
+ - };
812
+ -
813
+ - makeCoefficient = (...values: CoefficientParserTypes[]): CoefficientTypes => {
814
+ - if (this._coefficientMode === COEFFICIENT_MODE.FRACTION) {
815
+ - return new Fraction(...values as (Fraction | string | number)[])
816
+ - } else if (this._coefficientMode === COEFFICIENT_MODE.ROOT) {
817
+ - return new RootFraction(...values as (RootFraction | Fraction | string | number)[])
818
+ - }
819
+ + get literal(): expressionElementInterface {
820
+ + return this._literal;
821
+ + }
822
+
823
+ - // TODO: add the other modes
824
+ - return new Fraction(...values as (Fraction | string | number)[])
825
+ + set literal(value: expressionElementInterface) {
826
+ + this._literal = value;
827
+ }
828
+
829
+ -// -----------------------------------------
830
+ - /**
831
+ - * Parse a string to a monom. The string may include fraction.
832
+ - * @param inputStr
833
+ - */
834
+ - parse = (inputStr: unknown): Monom => {
835
+ + private _coefficient: Coefficient = new Coefficient()
836
+
837
+ - if (typeof inputStr === 'string') {
838
+ - this._shutingYardToReducedMonom(inputStr)
839
+ - } else if (typeof inputStr === 'number') {
840
+ - this._coefficient = this.makeCoefficient(inputStr)
841
+ - this._literal = {}
842
+ - } else if (inputStr instanceof Fraction) {
843
+ - this._coefficient = inputStr.clone()
844
+ - this._literal = {}
845
+ - } else if (inputStr instanceof RootFraction) {
846
+ - this._coefficient = inputStr.clone()
847
+ - this._literal = {}
848
+ - } else if (inputStr instanceof Monom) {
849
+ - this._coefficient = inputStr._coefficient.clone()
850
+ - this._literal = this.copyLiterals(inputStr.literal)
851
+ - }
852
+ + get coefficient(): Coefficient {
853
+ + return this._coefficient;
854
+ + }
855
+
856
+ - return this;
857
+ - };
858
+ -
859
+ - addToken = (stack: Monom[], element: Token): void => {
860
+ -
861
+ - let q1: Monom, q2: Monom, m: Monom, letter: string, pow: CoefficientCore<any>
862
+ -
863
+ - if (element.tokenType === ShutingyardType.COEFFICIENT) {
864
+ - stack.push(new Monom(this.makeCoefficient(element.token)))
865
+ -
866
+ - } else if (element.tokenType === ShutingyardType.VARIABLE) {
867
+ - let M = new Monom().one()
868
+ - M.setLetter(element.token, 1)
869
+ - stack.push(M.clone())
870
+ -
871
+ - } else if (element.tokenType === ShutingyardType.OPERATION) {
872
+ - switch (element.token) {
873
+ - case '-':
874
+ - // this should only happen for negative powers or for negative coefficient.
875
+ - q2 = (stack.pop()) || new Monom().zero()
876
+ - q1 = (stack.pop()) || new Monom().zero()
877
+ -
878
+ - stack.push(q1.subtract(q2))
879
+ -
880
+ - break;
881
+ - case '*':
882
+ - // Get the last element in the stack
883
+ - q2 = (stack.pop()) || new Monom().one()
884
+ - q1 = (stack.pop()) || new Monom().one()
885
+ -
886
+ - stack.push(q1.multiply(q2))
887
+ - break
888
+ - case '/':
889
+ - // Get the last element in the stack
890
+ - q2 = (stack.pop()) || new Monom().one()
891
+ - q1 = (stack.pop()) || new Monom().one()
892
+ -
893
+ - stack.push(q1.divide(q2))
894
+ - break
895
+ - case '^':
896
+ - // get the two last elements in the stack
897
+ - pow = (stack.pop().coefficient) || this.makeCoefficient().one()
898
+ - m = (stack.pop()) || new Monom().one()
899
+ -
900
+ - letter = m.variables[0]
901
+ -
902
+ - if (letter !== undefined) {
903
+ - m.setLetter(letter, pow)
904
+ - }
905
+ -
906
+ - stack.push(m)
907
+ - // this.multiply(m.clone())
908
+ - break
909
+ - }
910
+ - }
911
+ + set coefficient(value: Coefficient) {
912
+ + this._coefficient = value;
913
+ }
914
+
915
+ - /**
916
+ - * Clone the current Monom.
917
+ - */
918
+ - clone = (): Monom => {
919
+ - let F: Monom = new Monom();
920
+ + add(...values: Monom[]): this {
921
+ + if (values.length === 0) return this
922
+
923
+ - F.coefficient = this._coefficient.clone();
924
+ -
925
+ - // Copy the literal parts.
926
+ - for (let k in this._literal) {
927
+ - F.setLetter(k, this._literal[k].clone());
928
+ + // Check that all the monoms are similar.
929
+ + if (!values.every(x => this.isSimilarTo(x))) {
930
+ + throw new Error('The monoms are not similar.')
931
+ }
932
+ - return F;
933
+ - };
934
+
935
+ - copyLiterals = (literal: literalType): literalType => {
936
+ - let L: literalType = {}
937
+ + // Add the coefficients.
938
+ + this._coefficient.add(...values.map(x => x.coefficient))
939
+
940
+ - for (let k in literal) {
941
+ - L[k] = literal[k].clone()
942
+ - }
943
+ - return L
944
+ - }
945
+ -
946
+ - makeSame = (M: Monom): Monom => {
947
+ - // Copy the literal parts.
948
+ - for (let k in M._literal) {
949
+ - this.setLetter(k, M._literal[k].clone());
950
+ - }
951
+ return this
952
+ }
953
+
954
+ - /**
955
+ - * Create a zero value monom
956
+ - */
957
+ - zero = (): Monom => {
958
+ - this._coefficient = this.makeCoefficient().zero();
959
+ - this._literal = {};
960
+ - return this;
961
+ - };
962
+ + subtract(...values: Monom[]): this {
963
+ + return this.add(...values.map(x => x.opposite()))
964
+ + }
965
+ +
966
+ + multiply(...values: Monom[]): this {
967
+ + return this
968
+ + }
969
+ +
970
+ + divide(value: Monom): this {
971
+ + return this
972
+ + }
973
+
974
+ - /**
975
+ - * Create a one value monom
976
+ - */
977
+ - one = (): Monom => {
978
+ - this._coefficient = this.makeCoefficient().one();
979
+ - this._literal = {};
980
+ - return this;
981
+ - };
982
+ + opposite(): this {
983
+ + this._coefficient.opposite()
984
+ + return this
985
+ + }
986
+
987
+ -// ------------------------------------------
988
+ -// Mathematical operations
989
+ -// ------------------------------------------
990
+ + invert(): this {
991
+ + return this
992
+ + }
993
+
994
+ - /**
995
+ - * Clean the monom by removing each letters with a power of zero.
996
+ - */
997
+ - clean = (): Monom => {
998
+ - for (let letter in this._literal) {
999
+ - if (this._literal[letter].isZero()) {
1000
+ - delete this._literal[letter];
1001
+ - }
1002
+ - }
1003
+ - return this;
1004
+ - };
1005
+ + pow(value: number): this {
1006
+ + return this
1007
+ + }
1008
+ +
1009
+ + root(value: number): this {
1010
+ + return this
1011
+ + }
1012
+
1013
+ - reduce = (): Monom => {
1014
+ - this.clean()
1015
+ - this.coefficient.reduce()
1016
+ + reduce(): this {
1017
+ return this
1018
+ }
1019
+
1020
+ - /**
1021
+ - * Get the opposite
1022
+ - * Returns a monom.
1023
+ - */
1024
+ - opposed = (): Monom => {
1025
+ - this._coefficient.opposite();
1026
+ - return this;
1027
+ - };
1028
+ -
1029
+ - /**
1030
+ - * Add all similar monoms. If they aren't similar, they are simply skipped.
1031
+ - * @param M (Monom[]) The monoms to add.
1032
+ - */
1033
+ - add = (...M: Monom[]): Monom => {
1034
+ - for (let m of M) {
1035
+ - if (this.isSameAs(m)) {
1036
+ - if (this.isZero()) {
1037
+ - this.makeSame(m)
1038
+ - }
1039
+ - this._coefficient.add(m.coefficient);
1040
+ - } else {
1041
+ - console.log('Add monom: ' + this.display + ' is not similar with ', m.display);
1042
+ - }
1043
+ - }
1044
+ - return this;
1045
+ - };
1046
+ -
1047
+ - /**
1048
+ - * Subtract multiple monoms
1049
+ - * @param M (Monom[]) The monoms to subtract
1050
+ - */
1051
+ - subtract = (...M: Monom[]): Monom => {
1052
+ - for (let m of M) {
1053
+ - if (this.isSameAs(m)) {
1054
+ - if (this.isZero()) {
1055
+ - this.makeSame(m)
1056
+ - }
1057
+ - this._coefficient.add(m.clone().coefficient.opposite());
1058
+ - } else {
1059
+ - console.log('Subtract: Is not similar: ', m.display);
1060
+ - }
1061
+ - }
1062
+ - return this;
1063
+ - };
1064
+ -
1065
+ - /**
1066
+ - * Multiple multiple monoms to the current monom
1067
+ - * @param M (Monom[]) The monoms to multiply to.
1068
+ - */
1069
+ - multiply = (...M: Monom[]): Monom => {
1070
+ - for (let m of M) {
1071
+ - // Multiply the coefficient.
1072
+ - this._coefficient.multiply(m.coefficient);
1073
+ -
1074
+ - // Multiply the literal parts.
1075
+ - for (let letter in m.literal) {
1076
+ - if (this._literal[letter] === undefined) {
1077
+ - this._literal[letter] = m.literal[letter].clone()
1078
+ - } else {
1079
+ - this._literal[letter].add(m.literal[letter])
1080
+ - }
1081
+ -
1082
+ - }
1083
+ - }
1084
+ - return this;
1085
+ - };
1086
+ -
1087
+ - multiplyByNumber = (F: Fraction | number): Monom => {
1088
+ - this._coefficient.multiply(F);
1089
+ - return this;
1090
+ - }
1091
+ -
1092
+ - /**
1093
+ - * Divide the current monoms by multiple monoms
1094
+ - * @param M (Monom[])
1095
+ - */
1096
+ - divide = (...M: Monom[]): Monom => {
1097
+ - // Depending on the given value, choose the current item
1098
+ - for (let v of M) {
1099
+ - // Divide the coefficient
1100
+ - this._coefficient.divide(v.coefficient);
1101
+ + isSimilarTo(value: Monom): boolean {
1102
+ + // To be similar, the variables must be similar.
1103
+ + // The coefficient can be different.
1104
+
1105
+ - // Subtract the power values
1106
+ - for (let letter in v.literal) {
1107
+ - this._literal[letter] = (this._literal[letter] === undefined) ? v.literal[letter].clone().opposite() : this._literal[letter].subtract(v.literal[letter])
1108
+ + // They must have the same number of variables.
1109
+ + if (this.variables.length !== (value as Monom).variables.length) return false
1110
+
1111
+ - // If the power of a particular setLetter is zero, delete it from the literal part..
1112
+ - if (this._literal[letter].isZero()) {
1113
+ - delete this._literal[letter];
1114
+ - }
1115
+ - }
1116
+ - }
1117
+ - return this;
1118
+ - };
1119
+ + // They must have the same variables.
1120
+ + if (this.variables.every(x => (value as Monom).variables.includes(x))) return false
1121
+
1122
+ - /**
1123
+ - * Get the pow of a monom.
1124
+ - * @param nb (number) : Mathematical pow
1125
+ - */
1126
+ - pow = (nb: number | Fraction): Monom => {
1127
+ - this._coefficient.pow(nb);
1128
+ - for (let letter in this._literal) {
1129
+ - this._literal[letter].multiply(nb)
1130
+ - }
1131
+ - return this;
1132
+ - };
1133
+ -
1134
+ -// ------------------------------------------
1135
+ -// Compare functions
1136
+ -
1137
+ - /**
1138
+ - * Get the index-root of the monom
1139
+ - * @param p
1140
+ - */
1141
+ - root = (p: number): Monom => {
1142
+ - // TODO: determiner the index root of a monom
1143
+ - return this;
1144
+ - }
1145
+ -
1146
+ - /**
1147
+ - * Return the square root of a monom
1148
+ - */
1149
+ - sqrt = (): Monom => {
1150
+ - if (this.isSquare()) {
1151
+ - this._coefficient.sqrt();
1152
+ - for (let letter in this._literal) {
1153
+ - this._literal[letter].clone().divide(2)
1154
+ - }
1155
+ - }
1156
+ - return this.root(2);
1157
+ - }
1158
+ -
1159
+ -// ------------------------------------------
1160
+ - compare = (M: Monom, sign?: COMPARESIGNS): boolean => {
1161
+ - // TODO: Build the compare systems.
1162
+ - if (sign === undefined) {
1163
+ - sign = COMPARESIGNS.EQUALS;
1164
+ - }
1165
+ -
1166
+ -
1167
+ - switch (sign) {
1168
+ - case COMPARESIGNS.EQUALS:
1169
+ - // To be equal, they must be the isSame
1170
+ - if (!this.compare(M, COMPARESIGNS.SAME)) {
1171
+ - return false;
1172
+ - }
1173
+ -
1174
+ - // The literal parts are the isSame. The coefficient must be equal
1175
+ - return this._coefficient.isEqualTo(M.coefficient);
1176
+ - case COMPARESIGNS.SAME:
1177
+ - // Get the list of all variables from both monoms.
1178
+ - let M1: string[] = this.variables,
1179
+ - M2: string[] = M.variables,
1180
+ - K: string[] = M1.concat(M2.filter((item) => M1.indexOf(item) < 0));
1181
+ -
1182
+ - if (M1.length === 0 && M2.length === 0) {
1183
+ - return true
1184
+ - }
1185
+ - // To compare, both must be different than zero.
1186
+ - if (!this.isZero() && !M.isZero()) {
1187
+ - for (let key of K) {
1188
+ - // The setLetter is not available in one of the monom
1189
+ - if (this._literal[key] === undefined || M.literal[key] === undefined) {
1190
+ - return false;
1191
+ - }
1192
+ - // The setLetter does not have the isSame power in each monoms.
1193
+ - if (!this._literal[key].isEqualTo(M.literal[key])) {
1194
+ - return false;
1195
+ - }
1196
+ - }
1197
+ - }
1198
+ -
1199
+ - // All are positive check - the monoms are the sames.
1200
+ - return true;
1201
+ - default:
1202
+ - return false;
1203
+ - }
1204
+ + return true
1205
+ }
1206
+ -
1207
+ - /**
1208
+ - * Determine if the monom is null
1209
+ - */
1210
+ - isZero()
1211
+ - :
1212
+ - boolean {
1213
+ - return this._coefficient.value === 0;
1214
+ - }
1215
+ -
1216
+ - /**
1217
+ - * Determine if the monom is one
1218
+ - */
1219
+ - isOne()
1220
+ - :
1221
+ - boolean {
1222
+ - return this._coefficient.value === 1 && this.variables.length === 0;
1223
+ - }
1224
+ -
1225
+ - /**
1226
+ - * Determine if two monoms are equals
1227
+ - * @param M
1228
+ - */
1229
+ - isEqual = (M: Monom): boolean => {
1230
+ - return this.compare(M, COMPARESIGNS.EQUALS);
1231
+ - };
1232
+
1233
+ - /**
1234
+ - * Determine if two monoms are similar
1235
+ - * @param M
1236
+ - */
1237
+ - isSameAs = (M: Monom): boolean => {
1238
+ - return this.compare(M, COMPARESIGNS.SAME);
1239
+ - };
1240
+ -
1241
+ - isSquare = (): boolean => {
1242
+ - if (!this.coefficient.isSquare()) {
1243
+ - return false;
1244
+ - }
1245
+ - return this.isLiteralSquare();
1246
+ - }
1247
+ -// ------------------------------------------
1248
+ -// Misc monoms functions
1249
+ -
1250
+ - isLiteralSquare = (): boolean => {
1251
+ - for (let letter in this.literal) {
1252
+ - // A literal square must have a natural power
1253
+ - if (this.literal[letter].isRational()) {
1254
+ - return false
1255
+ - }
1256
+ + isEqualTo(value: unknown): boolean {
1257
+ + return false
1258
+ + }
1259
+
1260
+ - // The natural power must be be even
1261
+ - if (this.literal[letter].isEven()) {
1262
+ - return false;
1263
+ - }
1264
+ - }
1265
+ -
1266
+ - return true;
1267
+ - }
1268
+ -
1269
+ - hasFractionCoefficient = (): boolean => {
1270
+ - for (let letter in this._literal) {
1271
+ - if (this._literal[letter].isRational()) {
1272
+ - return true
1273
+ - }
1274
+ - }
1275
+ -
1276
+ + isReduced(): boolean {
1277
+ return false
1278
+ }
1279
+
1280
+ -// -------------------------------------
1281
+ - /**
1282
+ - * Determine if a monom contains a setLetter in it's literal part
1283
+ - * @param letter
1284
+ - */
1285
+ - hasLetter = (letter?: string): boolean => {
1286
+ - // The letter was not found
1287
+ - if (this._literal[letter === undefined ? 'x' : letter] === undefined) {
1288
+ - return false
1289
+ - }
1290
+ + isOne(): boolean {
1291
+ + return false
1292
+ + }
1293
+
1294
+ - // The letter is found and is not zero !
1295
+ - return !this._literal[letter === undefined ? 'x' : letter].isZero();
1296
+ - };
1297
+ -
1298
+ - /**
1299
+ - * Set the power of a particular setLetter
1300
+ - * @param letter (string) Letter to change
1301
+ - * @param pow (number) Power of the setLetter (must be positive integer.
1302
+ - */
1303
+ - setLetter = (letter: string, pow: CoefficientCore<any> | number): void => {
1304
+ - if (pow instanceof CoefficientCore) {
1305
+ - // Set the power of the letter to zero => remove it
1306
+ - if (this.hasLetter(letter) && pow.isZero()) {
1307
+ - delete this._literal[letter]
1308
+ - }
1309
+ -
1310
+ - this._literal[letter] = pow.clone()
1311
+ - } else {
1312
+ - this.setLetter(letter, this.makeCoefficient(pow))
1313
+ - }
1314
+ - };
1315
+ -
1316
+ - /**
1317
+ - * Get the degree of a monom. If no setLetter is given, the result will be the global degree.
1318
+ - * @param letter (string) Letter to get to degree (power)
1319
+ - */
1320
+ - degree = (letter?: string): CoefficientTypes => {
1321
+ - if (this.variables.length === 0) {
1322
+ - return this.makeCoefficient().zero();
1323
+ - }
1324
+ - if (letter === undefined) {
1325
+ - // Not setLetter given -> we get the global monom degree (sum of all the letters).
1326
+ - return Object.values(this._literal)
1327
+ - .reduce(
1328
+ - (t, n) => t.clone().add(n)
1329
+ - );
1330
+ - } else {
1331
+ - // A setLetter is given -> get the corresponding power.
1332
+ - return this._literal[letter] === undefined ? this.makeCoefficient().zero() : this._literal[letter].clone();
1333
+ - }
1334
+ - };
1335
+ -
1336
+ - /**
1337
+ - * Evaluate a monom. Each setLetter must be assigned to a Fraction.
1338
+ - * @param values Dictionary of <setLetter: Fraction>
1339
+ - */
1340
+ - evaluate = (values?: literalType | Fraction | number): CoefficientCore<any> => {
1341
+ - let r = this.coefficient.clone();
1342
+ -
1343
+ - if (typeof values === 'number' || values instanceof Fraction) {
1344
+ - let tmpValues: literalType = {}
1345
+ - tmpValues[this.variables[0]] = this.makeCoefficient(values)
1346
+ - return this.evaluate(tmpValues);
1347
+ - }
1348
+ -
1349
+ - if (typeof values === 'object') {
1350
+ - if (this.variables.length === 0) {
1351
+ - return this.coefficient
1352
+ - }
1353
+ - for (let L in this._literal) {
1354
+ - if (values[L] === undefined) {
1355
+ - return this.makeCoefficient().zero();
1356
+ - }
1357
+ -
1358
+ - let value = this.makeCoefficient(values[L])
1359
+ -
1360
+ - r.multiply(value.pow(this._literal[L]))
1361
+ - }
1362
+ - }
1363
+ -
1364
+ - return r;
1365
+ - };
1366
+ -
1367
+ - evaluateAsNumeric = (values: { [Key: string]: number } | number): number => {
1368
+ - let r = this.coefficient.value
1369
+ -
1370
+ - if (typeof values === 'number') {
1371
+ - let tmpValues: { [Key: string]: number } = {}
1372
+ - tmpValues[this.variables[0]] = values
1373
+ - return this.evaluateAsNumeric(tmpValues);
1374
+ - }
1375
+ -
1376
+ - if (typeof values === 'object') {
1377
+ - if (this.variables.length === 0) {
1378
+ - return this.coefficient.value
1379
+ - }
1380
+ - for (let L in this._literal) {
1381
+ - if (values[L] === undefined) {
1382
+ - return 0;
1383
+ - }
1384
+ -
1385
+ - r *= values[L] ** (this._literal[L].value)
1386
+ - }
1387
+ - }
1388
+ -
1389
+ - return r
1390
+ - }
1391
+ -// ----------------------------------------
1392
+ -// Static functions
1393
+ -// ----------------------------------------
1394
+ -
1395
+ - /**
1396
+ - * Derivative the monom
1397
+ - * @param letter
1398
+ - */
1399
+ - derivative = (letter?: string): Monom => {
1400
+ - // No setLetter given - assume it's the setLetter 'x'
1401
+ - if (letter === undefined) {
1402
+ - letter = 'x';
1403
+ - }
1404
+ -
1405
+ - if (this.hasLetter(letter)) {
1406
+ - let d = this._literal[letter].clone(),
1407
+ - dM = this.clone();
1408
+ -
1409
+ - // Subtract one to the degree.
1410
+ - dM._literal[letter].subtract(1)
1411
+ -
1412
+ - // Multiply the coefficient by the previous degree
1413
+ - dM._coefficient.multiply(this.makeCoefficient(d.clone()));
1414
+ - return dM;
1415
+ - } else {
1416
+ - return new Monom().zero();
1417
+ - }
1418
+ - };
1419
+ -
1420
+ - primitive = (letter?: string): Monom => {
1421
+ - // TODO: derivative including the ln value => implies creating different monom system ?
1422
+ - if (letter === undefined) {
1423
+ - letter = 'x'
1424
+ - }
1425
+ -
1426
+ - // Zero monom
1427
+ - let M = this.clone(), degree
1428
+ -
1429
+ - if (M.hasLetter(letter)) {
1430
+ - degree = M.degree(letter).clone().add(1)
1431
+ - M.coefficient = M.coefficient.clone().divide(degree)
1432
+ - M.setLetter(letter, degree)
1433
+ - } else {
1434
+ - // There is no letter.
1435
+ -
1436
+ - // The coefficient might be zero (=> x) or a number a (=> ax)
1437
+ - if (M.coefficient.isZero()) {
1438
+ - M.coefficient = this.makeCoefficient().one()
1439
+ - }
1440
+ - M.setLetter(letter, 1)
1441
+ - }
1442
+ -
1443
+ - return M
1444
+ - }
1445
+ -
1446
+ -// TODO: The rest of the functions are not used or unnecessary ?
1447
+ - /**
1448
+ - * Determine if multiple monoms are similar
1449
+ - * @param M
1450
+ - */
1451
+ - areSameAs = (...M: Monom[]): boolean => {
1452
+ - let result: boolean = true;
1453
+ -
1454
+ - // Check all monoms if they are the isSame as the "this" one.
1455
+ - for (let i = 0; i < M.length; i++) {
1456
+ - if (!this.isSameAs(M[i])) {
1457
+ - return false;
1458
+ - }
1459
+ - }
1460
+ -
1461
+ - // All check passed -> all the monoms are similar.
1462
+ - return result;
1463
+ - };
1464
+ -
1465
+ - /**
1466
+ - * Determine if multiple monoms are equals
1467
+ - * @param M
1468
+ - */
1469
+ - areEquals = (...M: Monom[]): boolean => {
1470
+ - // They are not similar.
1471
+ - if (!this.areSameAs(...M)) {
1472
+ - return false;
1473
+ - }
1474
+ -
1475
+ - // Check all coefficient. They must be equals.
1476
+ - for (let m of M) {
1477
+ - if (!this._coefficient.isEqualTo(m.coefficient)) {
1478
+ - return false;
1479
+ - }
1480
+ - }
1481
+ -
1482
+ - // All checks passed.
1483
+ - return true;
1484
+ - };
1485
+ -
1486
+ - isDivisible = (div: Monom): boolean => {
1487
+ - // For all variables (letters), the current monom must have a degree higher than the divider
1488
+ - if (div.degree().isStrictlyPositive()) {
1489
+ - for (let letter of div.variables) {
1490
+ - if (!this.degree(letter).isGreaterOrEqualTo(div.degree(letter))) {
1491
+ - return false
1492
+ - }
1493
+ - }
1494
+ - }
1495
+ -
1496
+ - // If the coefficient is rational, we suppose we don't need to check the division by the coefficient.
1497
+ - if (this.coefficient.isRational() || div.coefficient.isRational()) {
1498
+ - return true
1499
+ - }
1500
+ -
1501
+ - return this.coefficient.clone().divide(div.coefficient).isRelative()
1502
+ + isMinusOne(): boolean {
1503
+ + return false
1504
+ }
1505
+
1506
+ - isInverted(M
1507
+ - :
1508
+ - Monom
1509
+ - ):
1510
+ - boolean {
1511
+ - return this.clone().multiply(M).isOne();
1512
+ + isUnit(): boolean {
1513
+ + return false
1514
+ }
1515
+
1516
+ - isNegativeOne()
1517
+ - :
1518
+ - boolean {
1519
+ - return this._coefficient.value === -1 && this.variables.length === 0;
1520
+ + isZero(): boolean {
1521
+ + return false
1522
+ }
1523
+
1524
+ - isNotEqual(M
1525
+ - :
1526
+ - Monom
1527
+ - ):
1528
+ - boolean {
1529
+ - return !this.isEqual(M);
1530
+ - }
1531
+ + clone(): Monom {
1532
+
1533
+ - isNotZero()
1534
+ - :
1535
+ - boolean {
1536
+ - return !this.isZero();
1537
+ - }
1538
+ + const m = new Monom()
1539
+
1540
+ - isOpposed(M
1541
+ - :
1542
+ - Monom
1543
+ - ):
1544
+ - boolean {
1545
+ - return this.clone().subtract(M).isZero();
1546
+ - }
1547
+ + m.coefficient = this.coefficient.clone()
1548
+ + for (let v of this.variables) {
1549
+ + m.literal[v] = this.literal[v]
1550
+ + }
1551
+
1552
+ - isReduced()
1553
+ - :
1554
+ - boolean {
1555
+ - // By construction, it is already reduced (litterals
1556
+ - return this.coefficient.isReduced();
1557
+ + return m
1558
+ }
1559
+
1560
+ - reset()
1561
+ - :
1562
+ - any {
1563
+ - this._coefficient = this.makeCoefficient()
1564
+ + private reset() {
1565
+ + this._coefficient = new Coefficient().zero()
1566
+ this._literal = {}
1567
+ }
1568
+
1569
+ - _getLiteralDividers(arr: literalType[], letter: string):
1570
+ - literalType[] {
1571
+ - let tmpList: { [key: string]: CoefficientTypes }[] = [];
1572
+ + private parse(...values: unknown[]): Monom {
1573
+ + this.reset()
1574
+
1575
+ - // Be default, this.literal[letter] should be a rational number.
1576
+ - for (let d = 0; d <= this.literal[letter].value; d++) {
1577
+ - if (arr.length === 0) {
1578
+ - let litt: literalType = {}
1579
+ - litt[letter] = this.makeCoefficient(d)
1580
+ - tmpList.push(litt)
1581
+ - } else {
1582
+ - for (let item of arr) {
1583
+ - let litt: literalType = {}
1584
+ - for (let currentLetter in item) {
1585
+ - litt[currentLetter] = item[currentLetter]
1586
+ - }
1587
+ - litt[letter] = this.makeCoefficient(d)
1588
+ - tmpList.push(litt)
1589
+ - }
1590
+ + // Parse the values.
1591
+ + if (values.length === 1) {
1592
+ + if (values[0] instanceof Monom) {
1593
+ + return values[0].clone()
1594
+ }
1595
+ - }
1596
+ - return tmpList;
1597
+ - }
1598
+
1599
+ - _shutingYardToReducedMonom = (inputStr: string): Monom => {
1600
+ - // Get the RPN array of the current expression
1601
+ - const SY: Shutingyard = new Shutingyard().parse(inputStr);
1602
+ - const rpn: { token: string, tokenType: string }[] = SY.rpn;
1603
+ -
1604
+ - let stack: Monom[] = []
1605
+ -
1606
+ - if (rpn.length === 0) {
1607
+ - this.zero()
1608
+ - return this
1609
+ - } else if (rpn.length === 1) {
1610
+ - const element = rpn[0]
1611
+ -
1612
+ - this.one()
1613
+ - if (element.tokenType === 'coefficient') {
1614
+ - this.coefficient = this.makeCoefficient(element.token)
1615
+ - } else if (element.tokenType === 'variable') {
1616
+ - this.setLetter(element.token, 1)
1617
+ - }
1618
+ - return this
1619
+ - } else {
1620
+ - // Reset the monom
1621
+ - for (const element of rpn) {
1622
+ - this.addToken(stack, element)
1623
+ + if (typeof values[0] === "string") {
1624
+ + // Parse the string to get the coefficient and the literal.
1625
+ }
1626
+ - }
1627
+
1628
+ - this.one()
1629
+ - this.multiply(stack[0])
1630
+ - return this
1631
+ - }
1632
+ -}
1633
+ + if (typeof values[0] === "number") {
1634
+ + // Parse the number to get the coefficient and the literal.
1635
+ + this._coefficient = new Coefficient(values[0])
1636
+ + return this
1637
+ + }
1638
+ + }
1639
+ +
1640
+ + return this;
1641
+ + }
1642
+ +}
1643
+
1644
+ Index: tests/coefficients/fraction.test.ts
1645
+ IDEA additional info:
1646
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
1647
+ <+>import {expect} from \"chai\";\r\nimport {Fraction} from \"../../src/maths/coefficients/fraction\";\r\nimport {describe} from \"mocha\";\r\nimport {Random} from \"../../src/maths/randomization/random\";\r\n\r\ndescribe('Fraction tests', () => { // the tests container\r\n it(\"should parse correctly\", () => {\r\n const F1 = new Fraction('1/2')\r\n expect(F1.display).to.be.equal('1/2')\r\n\r\n const F2 = new Fraction('1.5')\r\n expect(F2.display).to.be.equal('3/2')\r\n\r\n const F2n = new Fraction(1.5)\r\n expect(F2n.display).to.be.equal('3/2')\r\n\r\n const F3 = new Fraction('-1.5')\r\n expect(F3.display).to.be.equal('-3/2')\r\n\r\n const F4 = new Fraction('1.5/2')\r\n expect(F4.display).to.be.equal('3/4')\r\n\r\n const F5 = new Fraction('1.5/2.5')\r\n expect(F5.display).to.be.equal('3/5')\r\n\r\n const F6 = new Fraction(3, 5)\r\n expect(F6.display).to.be.equal('3/5')\r\n\r\n const F7 = new Fraction(0.5, 1.5)\r\n expect(F7.display).to.be.equal('1/3')\r\n })\r\n\r\n it('Tex display', () => { // the single test\r\n const options = new Fraction(2, 5); // this will be your class\r\n expect(options.tex).to.be.equal('\\\\frac{ 2 }{ 5 }');\r\n });\r\n\r\n it('Compare: equals', () => {\r\n let F = new Fraction(1, 3),\r\n Q = new Fraction(2, 6),\r\n P = new Fraction(2, 5);\r\n expect(F.isEqualTo(Q)).to.be.true;\r\n expect(F.isEqualTo(P)).to.be.false;\r\n })\r\n\r\n it('Operation: sum of two fraction', () => {\r\n let F = new Fraction(1, 3),\r\n Q = new Fraction(2, 7);\r\n\r\n F.add(Q);\r\n\r\n expect(F.numerator).to.be.equal(13);\r\n expect(F.denominator).to.be.equal(21);\r\n })\r\n\r\n it('Operation: subtract of two fraction', () => {\r\n let F = new Fraction(1, 3),\r\n Q = new Fraction(2, 7);\r\n\r\n F.subtract(Q);\r\n\r\n expect(F.numerator).to.be.equal(1);\r\n expect(F.denominator).to.be.equal(21);\r\n })\r\n\r\n it('Reduced', () => {\r\n let F = new Fraction(2, 5),\r\n Q = new Fraction(2, 6)\r\n\r\n expect(F.isReduced()).to.be.true\r\n expect(Q.isReduced()).to.be.false\r\n })\r\n\r\n // TODO: fix this test\r\n // it('Should parse a number with lots of decimals', () => {\r\n // let A = 3.45,\r\n // B = 3.3333333333333,\r\n // C = 5.314171717171717\r\n //\r\n // let FA = new Fraction(A),\r\n // FB = new Fraction(B, 1),\r\n // FC = new Fraction(C, 2)\r\n //\r\n // expect(FA.display).to.be.equal('69/20')\r\n // expect(FB.display).to.be.equal('10/3')\r\n // expect(FC.display).to.be.equal('526103/99000')\r\n // })\r\n})\r\n\r\ndescribe(\"Fraction static functions\", () => {\r\n it('should sort fractions', function () {\r\n let list = [\r\n new Fraction('3.5'),\r\n new Fraction('-2.5'),\r\n new Fraction('3.1'),\r\n new Fraction('3.54'),\r\n new Fraction('1.5')\r\n ]\r\n\r\n expect(Fraction.sort(list).map(x => x.value)).to.have.all.members([-2.5, 1.5, 3.1, 3.5, 3.54])\r\n });\r\n\r\n it('should make a list of fractions unique', function () {\r\n let list = [\r\n new Fraction('3.5'),\r\n new Fraction('-2.5'),\r\n new Fraction('7/2'),\r\n new Fraction('3.50'),\r\n new Fraction('1.5')\r\n ]\r\n\r\n expect(Fraction.unique(list, true).map(x => x.value)).to.have.ordered.members([-2.5, 1.5, 3.5])\r\n });\r\n\r\n it('should get the average of fractions', function () {\r\n let list = [\r\n new Fraction('3.5'),\r\n new Fraction('-2.5'),\r\n new Fraction('7/2'),\r\n new Fraction('3.50'),\r\n new Fraction('1.5')\r\n ]\r\n\r\n expect(Fraction.average(...list).tex).to.be.equal('\\\\frac{ 19 }{ 10 }')\r\n })\r\n\r\n it('should multiply and not reduce', function () {\r\n let list = [\r\n new Fraction('1/2'),\r\n new Fraction('4/3'),\r\n 2.5,\r\n 3\r\n ]\r\n\r\n expect(new Fraction().multiply(...list).display).to.be.equal(\"60/12\")\r\n });\r\n\r\n it('should divide', () => {\r\n const f1 = new Fraction('1/2'),\r\n f2 = new Fraction('4/3')\r\n\r\n expect(f1.divide(f2).display).to.be.equal('3/8')\r\n })\r\n})\r\n\r\ndescribe(\"Evaluate fraction\", () => {\r\n it('should evaluate and convert to decimal if not exact', function () {\r\n let F = new Fraction(Math.sqrt(2))\r\n\r\n expect(F.isApproximative()).to.be.true\r\n expect(F.isExact()).to.be.false\r\n\r\n let G = new Fraction('1/7')\r\n expect(G.isApproximative()).to.be.false\r\n expect(G.isExact()).to.be.true\r\n });\r\n})\r\n\r\ndescribe('Generate a random fraction', () => {\r\n it('should generate a non natural fraction', function () {\r\n let F, result = true\r\n\r\n for (let i = 0; i < 100; i++) {\r\n F = Random.fraction()\r\n if (!F.isRelative()) {\r\n result = false\r\n break\r\n }\r\n }\r\n expect(F.isNatural()).to.be.false;\r\n });\r\n})
1648
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
1649
+ <+>UTF-8
1650
+ ===================================================================
1651
+ diff --git a/tests/coefficients/fraction.test.ts b/tests/coefficients/fraction.test.ts
1652
+ --- a/tests/coefficients/fraction.test.ts
1653
+ +++ b/tests/coefficients/fraction.test.ts
1654
+ @@ -1,7 +1,6 @@
1655
+ import {expect} from "chai";
1656
+ import {Fraction} from "../../src/maths/coefficients/fraction";
1657
+ import {describe} from "mocha";
1658
+ -import {Random} from "../../src/maths/randomization/random";
1659
+
1660
+ describe('Fraction tests', () => { // the tests container
1661
+ it("should parse correctly", () => {
1662
+ @@ -155,18 +154,18 @@
1663
+ expect(G.isExact()).to.be.true
1664
+ });
1665
+ })
1666
+ -
1667
+ -describe('Generate a random fraction', () => {
1668
+ - it('should generate a non natural fraction', function () {
1669
+ - let F, result = true
1670
+ -
1671
+ - for (let i = 0; i < 100; i++) {
1672
+ - F = Random.fraction()
1673
+ - if (!F.isRelative()) {
1674
+ - result = false
1675
+ - break
1676
+ - }
1677
+ - }
1678
+ - expect(F.isNatural()).to.be.false;
1679
+ - });
1680
+ -})
1681
+
1682
+ +//
1683
+ +// describe('Generate a random fraction', () => {
1684
+ +// it('should generate a non natural fraction', function () {
1685
+ +// let F, result = true
1686
+ +//
1687
+ +// for (let i = 0; i < 100; i++) {
1688
+ +// F = Random.fraction()
1689
+ +// if (!F.isRelative()) {
1690
+ +// result = false
1691
+ +// break
1692
+ +// }
1693
+ +// }
1694
+ +// expect(F.isNatural()).to.be.false;
1695
+ +// });
1696
+ +// })
1697
+
1698
+ Index: src/maths/coefficients/rootFraction.ts
1699
+ ===================================================================
1700
+ diff --git a/src/maths/coefficients/rootFraction.ts b/src/maths/coefficients/coefficientElement.ts
1701
+ rename from src/maths/coefficients/rootFraction.ts
1702
+ rename to src/maths/coefficients/coefficientElement.ts
1703
+ --- a/src/maths/coefficients/rootFraction.ts
1704
+ +++ b/src/maths/coefficients/coefficientElement.ts
1705
+ @@ -1,26 +1,44 @@
1706
+ import {Fraction} from "./fraction";
1707
+ -import {CoefficientCore} from "./coefficientCore";
1708
+ +import {COEFFICIENT_EXTRA, CoefficientCore, CoefficientParserTypes} from "./coefficientCore";
1709
+
1710
+ /**
1711
+ * RootFraction is something like "<coefficient>\sqrt[index]{<radical>}
1712
+ */
1713
+ -export class RootFraction extends CoefficientCore<RootFraction> {
1714
+ - constructor(value?: number | string | Fraction | RootFraction, radical?: number | string, index?: number | string) {
1715
+ +
1716
+ +
1717
+ +export class CoefficientElement extends CoefficientCore<CoefficientElement> {
1718
+ + constructor(value?: CoefficientParserTypes, values?: { radical?: number, index?: number, extra?: string }) {
1719
+ super();
1720
+
1721
+ // Default values
1722
+ this._index = 2;
1723
+ this._radical = 1;
1724
+ + this._extra = null
1725
+
1726
+ - // Parse the value
1727
+ + // Parse the name
1728
+ if (value !== undefined) {
1729
+ - if (value instanceof RootFraction) return this.parse(value)
1730
+ - return this.parse(value, radical, index)
1731
+ + if (value instanceof CoefficientElement) return this._parse(value)
1732
+ + if (values === undefined) return this._parse(value)
1733
+ + return this._parse(value,
1734
+ + values.radical ?? 1,
1735
+ + values.index ?? 2,
1736
+ + values.extra ?? null
1737
+ + )
1738
+ }
1739
+
1740
+ return this
1741
+ }
1742
+
1743
+ + private _extra: COEFFICIENT_EXTRA;
1744
+ +
1745
+ + get extra(): COEFFICIENT_EXTRA {
1746
+ + return this._extra;
1747
+ + }
1748
+ +
1749
+ + set extra(value: COEFFICIENT_EXTRA) {
1750
+ + this._extra = value;
1751
+ + }
1752
+ +
1753
+ private _index: number;
1754
+
1755
+ get index(): number {
1756
+ @@ -41,55 +59,56 @@
1757
+ this._radical = value;
1758
+ }
1759
+
1760
+ - get value(): number {
1761
+ - return this.numerator * Math.pow(this._radical, 1 / this._index) / this.denominator
1762
+ + get fraction(): Fraction {
1763
+ + return new Fraction(this.numerator, this.denominator)
1764
+ }
1765
+
1766
+ - get tex(): string {
1767
+ - if (!this._hasRadical()) return this.fraction.tex
1768
+ -
1769
+ - const N = `${this.numerator} \\sqrt${this._index > 2 ? `[${this._index}]` : ''}{ ${this._radical} }`
1770
+ -
1771
+ - if (this.denominator === 1) return N
1772
+ + set fraction(value: Fraction) {
1773
+ + this.numerator = value.numerator
1774
+ + this.denominator = value.denominator
1775
+ + }
1776
+
1777
+ - return `\\frac{ ${N} }{ ${this.denominator} }`
1778
+ + get hasRadical(): boolean {
1779
+ + return this._radical !== 1 && this._index > 1
1780
+ + }
1781
+
1782
+ + get key(): string {
1783
+ + return this._index === 2 ? `sqrt(${this._radical})` : `root(${this._index})(${this._radical})`
1784
+ }
1785
+
1786
+ - get display(): string {
1787
+ - if (!this._hasRadical()) return this.fraction.display
1788
+ - const N = `${this.numerator}${this._index > 2 ? `root(${this._index})` : 'sqrt'}(${this._radical})`,
1789
+ - D = this.denominator > 1 ? `/${this.denominator}` : ''
1790
+ + get radicalDisplay(): string {
1791
+ + return this.hasRadical ? this.key : ''
1792
+ + }
1793
+
1794
+ - return `${N}${D}`
1795
+ + get radicalTex(): string {
1796
+ + return this.hasRadical ? this._index === 2 ? `\\sqrt{ ${this._radical} }` : `\\sqrt[${this._index}]{ ${this._radical} }` : ''
1797
+ }
1798
+
1799
+ - createInstance(value?: string | number | Fraction | RootFraction): RootFraction {
1800
+ - return new RootFraction(value)
1801
+ + get extraDisplay(): string {
1802
+ + return this._extra === COEFFICIENT_EXTRA.PI ? 'pi' : this._extra === COEFFICIENT_EXTRA.I ? 'i' : ''
1803
+ }
1804
+
1805
+ - clone = (): RootFraction => {
1806
+ - return new RootFraction(this.fraction, this.radical, this.index)
1807
+ + get extraTex(): string {
1808
+ + return this._extra === COEFFICIENT_EXTRA.PI ? '\\pi' : this._extra === COEFFICIENT_EXTRA.I ? 'i' : ''
1809
+ }
1810
+
1811
+ - reduce = (): RootFraction => {
1812
+ - // Reduce the radical
1813
+ - this._extractRadical()
1814
+ + static fromList(...values: CoefficientParserTypes[]): CoefficientElement[] {
1815
+ + return values.map(x => new CoefficientElement(x))
1816
+ + }
1817
+
1818
+ - // Reduce the fraction
1819
+ - this.fraction = this.fraction.reduce()
1820
+ - return this
1821
+ + createInstance(value?: CoefficientParserTypes): CoefficientElement {
1822
+ + return new CoefficientElement(value)
1823
+ }
1824
+
1825
+ - one = (): RootFraction => {
1826
+ + one = (): CoefficientElement => {
1827
+ super.one()
1828
+ this._resetRadical()
1829
+ return this
1830
+ }
1831
+
1832
+ - add = (...values: (Fraction | number | string | RootFraction)[]): RootFraction => {
1833
+ + add = (...values: CoefficientParserTypes[]): CoefficientElement => {
1834
+ // Check that all values are similar
1835
+ - const RF_list = values.map(x => new RootFraction(x))
1836
+ + const RF_list = CoefficientElement.fromList(...values)
1837
+
1838
+ const allAreSimilar = RF_list.every(x => this.isSimilarTo(x))
1839
+ if (!allAreSimilar) throw new Error('All values must be similar')
1840
+ @@ -98,67 +117,120 @@
1841
+ return this
1842
+ }
1843
+
1844
+ - multiply = (...values: (Fraction | number | string | RootFraction)[]): RootFraction => {
1845
+ - const RF_list = values.map(x => new RootFraction(x))
1846
+ + multiply = (...values: CoefficientParserTypes[]): CoefficientElement => {
1847
+ + const RF_list = CoefficientElement.fromList(...values)
1848
+ +
1849
+ + // Multiply the fraction
1850
+ + this.fraction = this.fraction.multiply(...RF_list.map(x => x.fraction))
1851
+ +
1852
+ + // Multiply the extra (case of i)
1853
+ + const i = [this, ...RF_list].filter(x => x.extra === COEFFICIENT_EXTRA.I).length
1854
+ + this.extra = i % 2 === 0 ? null : COEFFICIENT_EXTRA.I
1855
+ + this.numerator *= Math.floor(i / 2) % 2 === 0 ? 1 : -1
1856
+
1857
+ // Check that all values has the same index
1858
+ if (RF_list.every(x => x.index === this.index)) {
1859
+ - // Multiply the fraction
1860
+ - this.fraction = this.fraction.multiply(...RF_list.map(x => x.fraction))
1861
+ -
1862
+ // Multiply the radical
1863
+ this.radical = RF_list.reduce((acc, x) => acc * x.radical, this.radical)
1864
+ -
1865
+ - return this
1866
+ - }
1867
+ -
1868
+ - // Check that all values has the same radical
1869
+ - if (RF_list.every(x => x.radical === this.radical)) {
1870
+ - // Multiply the fraction
1871
+ - this.fraction = this.fraction.multiply(...RF_list.map(x => x.fraction))
1872
+ -
1873
+ + } else if (RF_list.every(x => x.radical === this.radical)) {
1874
+ // Add the index
1875
+ const idx: Fraction = new Fraction(1, this.index)
1876
+ .add(...RF_list.map(x => new Fraction(1, x.index)))
1877
+
1878
+ this.radical = Math.pow(this.radical, idx.numerator)
1879
+ this.index = idx.denominator
1880
+ - return this
1881
+ + } else {
1882
+ + console.log('SOMETHING WENT WrONG ')
1883
+ }
1884
+ return this
1885
+ }
1886
+
1887
+ - invert = (): RootFraction => {
1888
+ + invert = (): CoefficientElement => {
1889
+ // 3sqrt(2)/7 -> 7/3sqrt(2) -> 7sqrt(2)/(3*2) -> 7sqrt(2)/6
1890
+ // 3root(3)(2)/7 -> 7/3root(3)(2) -> 7root(3)(2^2)/(3*2) -> 7root(3)(4)/6
1891
+ this.fraction = this.fraction.invert()
1892
+ this.denominator = this.denominator * this.radical
1893
+ this.radical = this.index - 1 > 1 ? Math.pow(this.radical, this.index - 1) : this.radical
1894
+ +
1895
+ return this
1896
+ }
1897
+
1898
+ - root(value: number | (Fraction | RootFraction)): RootFraction {
1899
+ + root(value: number | (Fraction | CoefficientElement)): CoefficientElement {
1900
+ throw new Error("Method not implemented.");
1901
+ }
1902
+
1903
+ - isSimilarTo = (value: Fraction | number | string | RootFraction): boolean => {
1904
+ - let RF = new RootFraction(value).reduce()
1905
+ + reduce = (): CoefficientElement => {
1906
+ + // Reduce the radical
1907
+ + this._extractRadical()
1908
+ +
1909
+ + // Reduce the fraction
1910
+ + this.fraction = this.fraction.reduce()
1911
+ + return this
1912
+ + }
1913
+ +
1914
+ + isSimilarTo = (value: Fraction | number | string | CoefficientElement): boolean => {
1915
+ + let RF = new CoefficientElement(value).reduce()
1916
+
1917
+ // Check if the index and radical are the same
1918
+ return this.index === RF.index && this.radical === RF.radical
1919
+ }
1920
+
1921
+ - get fraction(): Fraction {
1922
+ - return new Fraction(this.numerator, this.denominator)
1923
+ + get value(): number {
1924
+ + if (this.hasRadical) {
1925
+ + return this.numerator * Math.pow(this._radical, 1 / this._index) / this.denominator
1926
+ + }
1927
+ +
1928
+ + return this.numerator / this.denominator
1929
+ + }
1930
+ +
1931
+ + clone = (): CoefficientElement => {
1932
+ + let result = new CoefficientElement(this.fraction, {
1933
+ + radical: this._radical,
1934
+ + index: this._index,
1935
+ + extra: this._extra
1936
+ + })
1937
+ +
1938
+ + return result
1939
+ }
1940
+
1941
+ - set fraction(value: Fraction) {
1942
+ - this.numerator = value.numerator
1943
+ - this.denominator = value.denominator
1944
+ + get tex(): string {
1945
+ + if (!this.hasRadical) return this.fraction.tex + this.extraTex
1946
+ +
1947
+ + const N = `${this.numerator} \\sqrt${this._index > 2 ? `[${this._index}]` : ''}{ ${this._radical} }`
1948
+ +
1949
+ + if (this.denominator === 1) return N
1950
+ +
1951
+ + return `\\frac{ ${N} }{ ${this.denominator} }${this.extraTex}`
1952
+ +
1953
+ }
1954
+
1955
+ - parse = (value: number | string | Fraction | RootFraction, radical?: number | string, index?: number | string): RootFraction => {
1956
+ - if (value instanceof RootFraction) return value.clone()
1957
+ + get display(): string {
1958
+ + let result = ''
1959
+ +
1960
+ + if (this.isInfinity()) return this.signTeX + 'oo'
1961
+ + if (this.isNaN()) return 'NaN'
1962
+ +
1963
+ + let N = [`${this.numerator}`, this.radicalDisplay, this.extraDisplay]
1964
+ + .filter(x => x !== '')
1965
+ +
1966
+ + if (N.length > 1) {
1967
+ + N = N.map((x, index) => {
1968
+ + if (index === 0 && Math.abs(+x) === 1) return +x === -1 ? '-' : ''
1969
+ + return x
1970
+ + })
1971
+ + }
1972
+ +
1973
+ +
1974
+ + const D = this.denominator > 1 ? `/${this.denominator}` : ''
1975
+ +
1976
+ + return `${N.join('')}${D}`
1977
+ + }
1978
+ +
1979
+ + protected _parse = (value: CoefficientParserTypes, radical?: number | string, index?: number | string, extra?: string): CoefficientElement => {
1980
+ + if (value instanceof CoefficientElement) return value.clone()
1981
+ +
1982
+ + this.radical = 1
1983
+ + this.index = 2
1984
+
1985
+ if (value instanceof Fraction) {
1986
+ this.numerator = value.numerator
1987
+ @@ -167,28 +239,53 @@
1988
+ this.numerator = value
1989
+ this.denominator = 1
1990
+ } else if (typeof value === "string") {
1991
+ - this.fraction = new Fraction(value)
1992
+ - // TODO parse a string with root code....
1993
+ + this._extra = value.includes('pi') ? COEFFICIENT_EXTRA.PI : value.includes('i') ? COEFFICIENT_EXTRA.I : null
1994
+ + if (this._extra !== null) {
1995
+ + value = value.replaceAll('pi', '')
1996
+ + .replaceAll('i', '')
1997
+ +
1998
+ + value = (value === '' ? "1" : value) as string
1999
+ + value = (value === '-' ? "-1" : value) as string
2000
+ + }
2001
+ +
2002
+ + // Parse the string asqrt(b)/c
2003
+ + if (value.includes('sqrt')) {
2004
+ + const match = value.match(/^([0-9]+)?sqrt\(([0-9]+)\)?(\/([0-9]+))?/)
2005
+ + if (match) {
2006
+ + const [, num, rad, , den] = match
2007
+ + this.numerator = num === undefined ? 1 : +num
2008
+ + this.radical = rad === undefined ? 1 : +rad
2009
+ + this.denominator = den === undefined ? 1 : +den
2010
+ + }
2011
+ + } else if (value.includes('root')) {
2012
+ + const match = value.match(/^([0-9]*)root\(([0-9+])\)\(([0-9]+)\)?(\/([0-9]+))?/)
2013
+ + if (match) {
2014
+ + const [, num, index, rad, , den] = match
2015
+ + this.numerator = num === undefined ? 1 : +num
2016
+ + this.radical = rad === undefined ? 1 : +rad
2017
+ + this.index = index === undefined ? 2 : +index
2018
+ + this.denominator = den === undefined ? 1 : +den
2019
+ + }
2020
+ + } else {
2021
+ + this.fraction = new Fraction(value)
2022
+ + }
2023
+ }
2024
+
2025
+ if (radical !== undefined) this.radical = +radical
2026
+ if (index !== undefined) this.index = +index
2027
+ + if (extra !== undefined) this.extra = extra as COEFFICIENT_EXTRA
2028
+
2029
+ return this
2030
+ }
2031
+
2032
+ - private _resetRadical = (): RootFraction => {
2033
+ + private _resetRadical = (): CoefficientElement => {
2034
+ this._index = 2
2035
+ this._radical = 1
2036
+ return this
2037
+ }
2038
+
2039
+ - private _hasRadical = (): boolean => {
2040
+ - return this._radical !== 1 && this._index > 1
2041
+ - }
2042
+ -
2043
+ private _extractRadical = (): { extracted: number, radical: number } => {
2044
+ - // Maximal value to test for extracting the radical
2045
+ + // Maximal name to test for extracting the radical
2046
+ let extracted = Math.floor(Math.pow(this._radical, 1 / this._index))
2047
+
2048
+ while (extracted > 1) {
2049
+ Index: src/maths/types.ts
2050
+ IDEA additional info:
2051
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
2052
+ <+>import {Monom} from \"./algebra/monom\";\r\nimport {Polynom} from \"./algebra/polynom\";\r\nimport {Rational} from \"./algebra/rational\";\r\nimport {CoefficientTypes} from \"./coefficients/coefficientCore\";\r\n\r\ninterface coreInterface {\r\n parse: (...values: unknown[]) => ThisType<this>,\r\n clone: () => ThisType<this>,\r\n\r\n readonly tex: string,\r\n readonly display: string\r\n}\r\n\r\ninterface operationInterface {\r\n add: (...values: unknown[]) => ThisType<this>,\r\n subtract: (...values: unknown[]) => ThisType<this>,\r\n multiply: (...values: unknown[]) => ThisType<this>,\r\n divide: (value: unknown) => ThisType<this>,\r\n opposite: () => ThisType<this>,\r\n invert: () => ThisType<this>,\r\n pow: (value: unknown) => ThisType<this>,\r\n root: (value: unknown) => ThisType<this>,\r\n reduce: () => ThisType<this>,\r\n}\r\n\r\ninterface compareInterface {\r\n compare: (value: unknown, sign: COMPARESIGNS) => boolean,\r\n isEqualTo: (value: unknown) => boolean,\r\n isReduced: () => boolean,\r\n isOne: () => boolean,\r\n isMinusOne: () => boolean,\r\n isUnit: () => boolean,\r\n isZero: () => boolean,\r\n}\r\n\r\nexport interface coefficientInterface extends coreInterface, operationInterface, compareInterface {\r\n isGreaterOrEqualTo: (value: unknown) => boolean,\r\n isGreaterThan: (value: unknown) => boolean,\r\n isLesserOrEqualTo: (value: unknown) => boolean,\r\n isLesserThan: (value: unknown) => boolean,\r\n isNaN: () => boolean,\r\n isPositive: () => boolean,\r\n isNegative: () => boolean,\r\n isStrictlyNegative: () => boolean,\r\n isStrictlyPositive: () => boolean,\r\n isOpposedTo: (value: unknown) => boolean,\r\n isInvertedTo: (value: unknown) => boolean,\r\n isNatural: () => boolean,\r\n isRelative: () => boolean,\r\n isRational: () => boolean,\r\n isReal: () => boolean,\r\n isComplex: () => boolean,\r\n isInfinity: () => boolean,\r\n isEven: () => boolean,\r\n isOdd: () => boolean,\r\n readonly value: number,\r\n}\r\n\r\nexport interface coefficientStaticTypes {\r\n average: (...values: unknown[]) => coefficientInterface,\r\n max: (...values: unknown[]) => coefficientInterface,\r\n min: (...values: unknown[]) => coefficientInterface,\r\n sort: (...values: unknown[]) => coefficientInterface[],\r\n unique: (...values: unknown[]) => coefficientInterface[],\r\n}\r\n\r\nexport interface expressionInterface extends coreInterface, operationInterface, compareInterface {\r\n // variables getter\r\n readonly variables: string[],\r\n hasLetter: (letter?: string) => boolean\r\n\r\n // Evaluate\r\n evaluate: (value?: evaluateType) => numericType,\r\n\r\n // Helpers\r\n isDivisible?: (value: unknown) => boolean,\r\n}\r\n\r\n\r\nexport type literalType = { [Key: string]: CoefficientTypes }\r\nexport type numericType = number | string | CoefficientTypes\r\nexport type expressionType = Monom | Polynom | Rational\r\nexport type evaluateType = numericType | { [key: string]: numericType }\r\n\r\nexport enum COMPARESIGNS {\r\n \"EQUALS\" = \"=\",\r\n \"SAME\" = \"same\",\r\n \"GREATER\" = \">\",\r\n \"GEQ\" = \">=\",\r\n \"LESSER\" = \"<\",\r\n \"LEQ\" = \"<=\",\r\n \"DIFFERENT\" = \"<>\"\r\n}
2053
+ ===================================================================
2054
+ diff --git a/src/maths/types.ts b/src/maths/types.ts
2055
+ --- a/src/maths/types.ts
2056
+ +++ b/src/maths/types.ts
2057
+ @@ -1,17 +1,14 @@
2058
+ -import {Monom} from "./algebra/monom";
2059
+ -import {Polynom} from "./algebra/polynom";
2060
+ -import {Rational} from "./algebra/rational";
2061
+ import {CoefficientTypes} from "./coefficients/coefficientCore";
2062
+
2063
+ -interface coreInterface {
2064
+ - parse: (...values: unknown[]) => ThisType<this>,
2065
+ +export interface coreInterface {
2066
+ + // parse: (...values: unknown[]) => ThisType<this>,
2067
+ clone: () => ThisType<this>,
2068
+
2069
+ readonly tex: string,
2070
+ readonly display: string
2071
+ }
2072
+
2073
+ -interface operationInterface {
2074
+ +export interface operationInterface {
2075
+ add: (...values: unknown[]) => ThisType<this>,
2076
+ subtract: (...values: unknown[]) => ThisType<this>,
2077
+ multiply: (...values: unknown[]) => ThisType<this>,
2078
+ @@ -23,8 +20,8 @@
2079
+ reduce: () => ThisType<this>,
2080
+ }
2081
+
2082
+ -interface compareInterface {
2083
+ - compare: (value: unknown, sign: COMPARESIGNS) => boolean,
2084
+ +export interface equalityInterface {
2085
+ + isSimilarTo: (value: unknown) => boolean,
2086
+ isEqualTo: (value: unknown) => boolean,
2087
+ isReduced: () => boolean,
2088
+ isOne: () => boolean,
2089
+ @@ -33,7 +30,7 @@
2090
+ isZero: () => boolean,
2091
+ }
2092
+
2093
+ -export interface coefficientInterface extends coreInterface, operationInterface, compareInterface {
2094
+ +export interface compareInterface {
2095
+ isGreaterOrEqualTo: (value: unknown) => boolean,
2096
+ isGreaterThan: (value: unknown) => boolean,
2097
+ isLesserOrEqualTo: (value: unknown) => boolean,
2098
+ @@ -56,19 +53,29 @@
2099
+ readonly value: number,
2100
+ }
2101
+
2102
+ -export interface coefficientStaticTypes {
2103
+ - average: (...values: unknown[]) => coefficientInterface,
2104
+ - max: (...values: unknown[]) => coefficientInterface,
2105
+ - min: (...values: unknown[]) => coefficientInterface,
2106
+ - sort: (...values: unknown[]) => coefficientInterface[],
2107
+ - unique: (...values: unknown[]) => coefficientInterface[],
2108
+ +// export interface coefficientStaticTypes {
2109
+ +// average: (...values: unknown[]) => coefficientInterface,
2110
+ +// max: (...values: unknown[]) => coefficientInterface,
2111
+ +// min: (...values: unknown[]) => coefficientInterface,
2112
+ +// sort: (...values: unknown[]) => coefficientInterface[],
2113
+ +// unique: (...values: unknown[]) => coefficientInterface[],
2114
+ +// }
2115
+ +
2116
+ +export interface expressionElementInterface {
2117
+ + [name: string]: {
2118
+ + exponent: number,
2119
+ + root: number,
2120
+ + }
2121
+ }
2122
+
2123
+ -export interface expressionInterface extends coreInterface, operationInterface, compareInterface {
2124
+ +
2125
+ +export interface expressionInterface {
2126
+ // variables getter
2127
+ readonly variables: string[],
2128
+ + readonly literal: expressionElementInterface
2129
+ hasLetter: (letter?: string) => boolean
2130
+
2131
+ +
2132
+ // Evaluate
2133
+ evaluate: (value?: evaluateType) => numericType,
2134
+
2135
+ @@ -79,7 +86,6 @@
2136
+
2137
+ export type literalType = { [Key: string]: CoefficientTypes }
2138
+ export type numericType = number | string | CoefficientTypes
2139
+ -export type expressionType = Monom | Polynom | Rational
2140
+ export type evaluateType = numericType | { [key: string]: numericType }
2141
+
2142
+ export enum COMPARESIGNS {
2143
+ Index: src/maths/coefficients/coefficientCore.ts
2144
+ IDEA additional info:
2145
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
2146
+ <+>import {Fraction} from \"./fraction\";\r\nimport {RootFraction} from \"./rootFraction\";\r\nimport {Numeric} from \"../numeric\";\r\n\r\n\r\nexport type CoefficientTypes = Fraction | RootFraction\r\nexport type CoefficientParserTypes = CoefficientTypes | number | string\r\n\r\nexport enum COEFFICIENT_MODE {\r\n \"FRACTION\",\r\n \"ROOT\",\r\n \"RADIAN\",\r\n \"COMPLEX\"\r\n}\r\n\r\nexport enum FRACTION_FRAC {\r\n \"frac\",\r\n \"dfrac\",\r\n \"tfrac\",\r\n}\r\n\r\nexport abstract class CoefficientCore<T extends CoefficientTypes> {\r\n private _fracType: FRACTION_FRAC\r\n\r\n get fracType(): FRACTION_FRAC {\r\n return this._fracType;\r\n }\r\n\r\n set fracType(value: FRACTION_FRAC) {\r\n this._fracType = value;\r\n }\r\n\r\n private _numerator: number\r\n\r\n get numerator(): number {\r\n return this._numerator;\r\n }\r\n\r\n set numerator(value: number) {\r\n this._numerator = value;\r\n }\r\n\r\n private _denominator: number\r\n\r\n get denominator(): number {\r\n return this._denominator;\r\n }\r\n\r\n set denominator(value: number) {\r\n this._denominator = value;\r\n }\r\n\r\n get value(): number {\r\n return this._numerator / this._denominator\r\n }\r\n\r\n get sign(): number {\r\n return (this.numerator * this.denominator >= 0) ? 1 : -1;\r\n };\r\n\r\n get signTeX(): string {\r\n return this.sign === 1 ? '+' : '-'\r\n }\r\n\r\n get fracTeX(): string {\r\n return this._fracType === FRACTION_FRAC.frac ? '\\\\frac' : this._fracType === FRACTION_FRAC.dfrac ? '\\\\dfrac' : '\\\\tfrac'\r\n }\r\n\r\n abstract get tex(): string\r\n\r\n abstract get display(): string\r\n\r\n static max = <T extends CoefficientTypes>(...values: T[]): T => {\r\n const [first, ...rest] = values\r\n return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? acc : cur, first)\r\n }\r\n\r\n static min = <T extends CoefficientTypes>(...values: T[]): T => {\r\n const [first, ...rest] = values\r\n return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? cur : acc, first)\r\n }\r\n\r\n static unique = <T extends CoefficientTypes>(values: T[], sort?: boolean): T[] => {\r\n let uniqueObjects: T[] = [],\r\n uniqueValues: number[] = []\r\n\r\n values.forEach((value, index) => {\r\n if (!uniqueValues.includes(value.value)) {\r\n uniqueValues.push(value.value)\r\n uniqueObjects.push(value)\r\n }\r\n })\r\n\r\n if (sort) return CoefficientCore.sort(uniqueObjects)\r\n\r\n return uniqueObjects\r\n }\r\n\r\n static sort = <T extends CoefficientTypes>(values: T[], reverse?: boolean): T[] => {\r\n let sorted = values.sort((a, b) => a.value - b.value)\r\n\r\n if (reverse) sorted = sorted.reverse()\r\n\r\n return sorted\r\n }\r\n\r\n abstract createInstance(value?: number | string | T): T\r\n\r\n abstract clone(): T\r\n\r\n abstract reduce(): T\r\n\r\n getReducedCoefficient = (): { N: number, D: number } => {\r\n if (this.numerator === 1 || this.denominator === 1) return {N: this.numerator, D: this.denominator}\r\n\r\n let g = Numeric.gcd(this.numerator, this.denominator);\r\n let [N, D] = [this.numerator, this.denominator]\r\n\r\n N = N / g;\r\n D = D / g;\r\n\r\n if (D < 0) {\r\n D = -D;\r\n N = -N;\r\n }\r\n\r\n return {N, D}\r\n };\r\n\r\n zero = (): T => {\r\n this.numerator = 0;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n one = (): T => {\r\n this.numerator = 1;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n infinite = (): T => {\r\n this.numerator = Infinity;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n invalid = (): T => {\r\n this.numerator = NaN;\r\n this.denominator = 1;\r\n return this as unknown as T\r\n };\r\n\r\n abstract add(...coefficients: (T | number | string)[]): T\r\n\r\n opposite = (): T => {\r\n this.numerator = -this.numerator;\r\n return this as unknown as T;\r\n }\r\n\r\n subtract = (...coefficients: (T | number | string)[]): T => this.add(...coefficients.map(c => this.createInstance(c).opposite() as T))\r\n\r\n abstract multiply(...coefficients: (T | number | string)[]): T\r\n\r\n abstract invert(): T\r\n\r\n divide = (F: T | number): T => this.multiply(this.createInstance(F).invert() as T);\r\n\r\n abs = (): T => {\r\n this.numerator = Math.abs(this.numerator);\r\n return this as unknown as T;\r\n }\r\n\r\n pow = (value: number | CoefficientTypes): T => {\r\n if (Number.isSafeInteger(value)) {\r\n const factor = this.clone(),\r\n abs = Math.abs(value as number)\r\n for (let i = abs; i <= abs; i++) {\r\n this.multiply(factor)\r\n }\r\n\r\n if ((value as number) < 0) this.invert()\r\n } else {\r\n throw new Error('Cannot raise a coefficient to a non-integer power')\r\n }\r\n return this as unknown as T\r\n }\r\n\r\n abstract root(value: number | CoefficientTypes): T\r\n\r\n sqrt = (): T => this.root(2)\r\n\r\n asTopFraction = (): T => {\r\n this.fracType = FRACTION_FRAC.tfrac\r\n return this as unknown as T\r\n }\r\n\r\n asDisplayFraction = (): T => {\r\n this.fracType = FRACTION_FRAC.dfrac\r\n return this as unknown as T\r\n }\r\n\r\n\r\n /**\r\n * All the is* methods without argument\r\n */\r\n\r\n isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1\r\n\r\n isOne = (): boolean => this._numerator === 1 && this._denominator === 1\r\n\r\n isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1\r\n\r\n isUnit = (): boolean => this.isOne() || this.isMinusOne()\r\n\r\n isZero = (): boolean => this._numerator === 0\r\n\r\n isFinite = (): boolean => !this.isInfinity() && !this.isNaN()\r\n\r\n isSquare = (): boolean => Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0\r\n\r\n isNaN = (): boolean => isNaN(this.value)\r\n\r\n isPositive = (): boolean => this.sign === 1\r\n\r\n isNegative = (): boolean => this.sign === -1\r\n\r\n isStrictlyNegative = (): boolean => this.value < 0\r\n\r\n isStrictlyPositive = (): boolean => this.value > 0\r\n\r\n isNatural = (): boolean => this.isRelative() && this.isPositive()\r\n\r\n isRelative = (): boolean => {\r\n const {N, D} = this.getReducedCoefficient()\r\n return D === 1\r\n }\r\n\r\n isRational = (): boolean => !this.isRelative()\r\n\r\n isReal = (): boolean => true\r\n\r\n isComplex = (): boolean => false\r\n\r\n isInfinity = (): boolean => Math.abs(this.value) === Infinity\r\n\r\n isEven = (): boolean => this.isRelative() && this.value % 2 === 0\r\n\r\n isOdd = (): boolean => this.isRelative() && this.value % 2 === 1\r\n\r\n isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15\r\n\r\n isExact = (): boolean => !this.isApproximative()\r\n\r\n isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;\r\n\r\n isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;\r\n\r\n isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;\r\n\r\n isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;\r\n\r\n isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;\r\n\r\n isEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value === this.createInstance(than as T).value\r\n\r\n isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())\r\n\r\n isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())\r\n\r\n}\r\n
2147
+ ===================================================================
2148
+ diff --git a/src/maths/coefficients/coefficientCore.ts b/src/maths/coefficients/coefficientCore.ts
2149
+ --- a/src/maths/coefficients/coefficientCore.ts
2150
+ +++ b/src/maths/coefficients/coefficientCore.ts
2151
+ @@ -1,9 +1,11 @@
2152
+ import {Fraction} from "./fraction";
2153
+ -import {RootFraction} from "./rootFraction";
2154
+ +import {CoefficientElement} from "./coefficientElement";
2155
+ import {Numeric} from "../numeric";
2156
+ +import {compareInterface, coreInterface, equalityInterface, operationInterface} from "../types";
2157
+ +import {Coefficient} from "./coefficient";
2158
+
2159
+
2160
+ -export type CoefficientTypes = Fraction | RootFraction
2161
+ +export type CoefficientTypes = Fraction | CoefficientElement | Coefficient
2162
+ export type CoefficientParserTypes = CoefficientTypes | number | string
2163
+
2164
+ export enum COEFFICIENT_MODE {
2165
+ @@ -13,13 +15,28 @@
2166
+ "COMPLEX"
2167
+ }
2168
+
2169
+ +export enum COEFFICIENT_EXTRA {
2170
+ + 'I' = "i",
2171
+ + 'PI' = "pi"
2172
+ +}
2173
+ +
2174
+ export enum FRACTION_FRAC {
2175
+ "frac",
2176
+ "dfrac",
2177
+ "tfrac",
2178
+ }
2179
+
2180
+ -export abstract class CoefficientCore<T extends CoefficientTypes> {
2181
+ +export abstract class CoefficientCore<T extends CoefficientTypes> implements coreInterface, operationInterface, equalityInterface, compareInterface {
2182
+ + private _exact: boolean
2183
+ +
2184
+ + get exact(): boolean {
2185
+ + return this._exact;
2186
+ + }
2187
+ +
2188
+ + set exact(value: boolean) {
2189
+ + this._exact = value;
2190
+ + }
2191
+ +
2192
+ private _fracType: FRACTION_FRAC
2193
+
2194
+ get fracType(): FRACTION_FRAC {
2195
+ @@ -50,10 +67,6 @@
2196
+ this._denominator = value;
2197
+ }
2198
+
2199
+ - get value(): number {
2200
+ - return this._numerator / this._denominator
2201
+ - }
2202
+ -
2203
+ get sign(): number {
2204
+ return (this.numerator * this.denominator >= 0) ? 1 : -1;
2205
+ };
2206
+ @@ -66,10 +79,6 @@
2207
+ return this._fracType === FRACTION_FRAC.frac ? '\\frac' : this._fracType === FRACTION_FRAC.dfrac ? '\\dfrac' : '\\tfrac'
2208
+ }
2209
+
2210
+ - abstract get tex(): string
2211
+ -
2212
+ - abstract get display(): string
2213
+ -
2214
+ static max = <T extends CoefficientTypes>(...values: T[]): T => {
2215
+ const [first, ...rest] = values
2216
+ return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? acc : cur, first)
2217
+ @@ -106,9 +115,13 @@
2218
+
2219
+ abstract createInstance(value?: number | string | T): T
2220
+
2221
+ - abstract clone(): T
2222
+ -
2223
+ - abstract reduce(): T
2224
+ + amplify = (k: number): T => {
2225
+ + if (Number.isSafeInteger(k)) {
2226
+ + this.numerator *= k;
2227
+ + this.denominator *= k;
2228
+ + }
2229
+ + return this as unknown as T;
2230
+ + };
2231
+
2232
+ getReducedCoefficient = (): { N: number, D: number } => {
2233
+ if (this.numerator === 1 || this.denominator === 1) return {N: this.numerator, D: this.denominator}
2234
+ @@ -153,25 +166,28 @@
2235
+
2236
+ abstract add(...coefficients: (T | number | string)[]): T
2237
+
2238
+ - opposite = (): T => {
2239
+ - this.numerator = -this.numerator;
2240
+ - return this as unknown as T;
2241
+ - }
2242
+ -
2243
+ subtract = (...coefficients: (T | number | string)[]): T => this.add(...coefficients.map(c => this.createInstance(c).opposite() as T))
2244
+
2245
+ abstract multiply(...coefficients: (T | number | string)[]): T
2246
+
2247
+ - abstract invert(): T
2248
+ -
2249
+ divide = (F: T | number): T => this.multiply(this.createInstance(F).invert() as T);
2250
+
2251
+ - abs = (): T => {
2252
+ - this.numerator = Math.abs(this.numerator);
2253
+ + opposite = (): T => {
2254
+ + this.numerator = -this.numerator;
2255
+ return this as unknown as T;
2256
+ }
2257
+
2258
+ - pow = (value: number | CoefficientTypes): T => {
2259
+ + abstract invert(): T
2260
+ +
2261
+ + pow = (value: number | Fraction): T => {
2262
+ + // It's a fraction - numerator = power, denoinator = root
2263
+ + if (value instanceof Fraction) {
2264
+ + this.pow(this.numerator)
2265
+ + this.root(this.denominator)
2266
+ + return this as unknown as T
2267
+ + }
2268
+ +
2269
+ + // It's a number
2270
+ if (Number.isSafeInteger(value)) {
2271
+ const factor = this.clone(),
2272
+ abs = Math.abs(value as number)
2273
+ @@ -188,6 +204,13 @@
2274
+
2275
+ abstract root(value: number | CoefficientTypes): T
2276
+
2277
+ + abstract reduce(): T
2278
+ +
2279
+ + abs = (): T => {
2280
+ + this.numerator = Math.abs(this.numerator);
2281
+ + return this as unknown as T;
2282
+ + }
2283
+ +
2284
+ sqrt = (): T => this.root(2)
2285
+
2286
+ asTopFraction = (): T => {
2287
+ @@ -200,25 +223,24 @@
2288
+ return this as unknown as T
2289
+ }
2290
+
2291
+ -
2292
+ - /**
2293
+ - * All the is* methods without argument
2294
+ - */
2295
+ -
2296
+ - isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1
2297
+ -
2298
+ - isOne = (): boolean => this._numerator === 1 && this._denominator === 1
2299
+ -
2300
+ - isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1
2301
+ -
2302
+ - isUnit = (): boolean => this.isOne() || this.isMinusOne()
2303
+ -
2304
+ - isZero = (): boolean => this._numerator === 0
2305
+ -
2306
+ isFinite = (): boolean => !this.isInfinity() && !this.isNaN()
2307
+
2308
+ isSquare = (): boolean => Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0
2309
+
2310
+ + isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15
2311
+ +
2312
+ + isExact = (): boolean => !this.isApproximative()
2313
+ +
2314
+ + isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;
2315
+ +
2316
+ + isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;
2317
+ +
2318
+ + isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;
2319
+ +
2320
+ + isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;
2321
+ +
2322
+ + isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;
2323
+ +
2324
+ isNaN = (): boolean => isNaN(this.value)
2325
+
2326
+ isPositive = (): boolean => this.sign === 1
2327
+ @@ -229,6 +251,10 @@
2328
+
2329
+ isStrictlyPositive = (): boolean => this.value > 0
2330
+
2331
+ + isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())
2332
+ +
2333
+ + isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())
2334
+ +
2335
+ isNatural = (): boolean => this.isRelative() && this.isPositive()
2336
+
2337
+ isRelative = (): boolean => {
2338
+ @@ -248,24 +274,32 @@
2339
+
2340
+ isOdd = (): boolean => this.isRelative() && this.value % 2 === 1
2341
+
2342
+ - isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15
2343
+ -
2344
+ - isExact = (): boolean => !this.isApproximative()
2345
+ -
2346
+ - isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;
2347
+ -
2348
+ - isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;
2349
+ -
2350
+ - isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;
2351
+ -
2352
+ - isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;
2353
+ -
2354
+ - isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;
2355
+ + get value(): number {
2356
+ + return this._numerator / this._denominator
2357
+ + }
2358
+
2359
+ isEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value === this.createInstance(than as T).value
2360
+
2361
+ - isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())
2362
+ + /**
2363
+ + * All the is* methods without argument
2364
+ + */
2365
+ +
2366
+ + isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1
2367
+ +
2368
+ + isOne = (): boolean => this._numerator === 1 && this._denominator === 1
2369
+ +
2370
+ + isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1
2371
+ +
2372
+ + isUnit = (): boolean => this.isOne() || this.isMinusOne()
2373
+ +
2374
+ + isZero = (): boolean => this._numerator === 0
2375
+ +
2376
+ + abstract clone(): T
2377
+ +
2378
+ + abstract get tex(): string
2379
+
2380
+ - isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())
2381
+ + abstract get display(): string
2382
+ +
2383
+ + protected abstract _parse(value: unknown): T
2384
+
2385
+ }
2386
+ Index: tests/geometry/radian.test.ts
2387
+ IDEA additional info:
2388
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
2389
+ <+>import {describe} from \"mocha\";\r\nimport {expect} from \"chai\";\r\nimport {Radian} from \"../../src/maths/geometry/radian\";\r\ndescribe('Random tests', () => {\r\n it('should create a radian value', () => {\r\n let r = new Radian('3/2')\r\n\r\n expect(r.tex).to.be.equal('\\\\frac{ 3\\\\pi }{ 2 }')\r\n expect(r.display).to.be.equal('3pi/2')\r\n\r\n let rp = new Radian('3/2', '1/2')\r\n\r\n expect(rp.tex).to.be.equal('\\\\frac{ 3\\\\pi }{ 2 }+k\\\\frac{ \\\\pi }{ 2 }')\r\n expect(rp.display).to.be.equal('3pi/2+kpi/2')\r\n })\r\n})
2390
+ ===================================================================
2391
+ diff --git a/tests/geometry/radian.test.ts b/tests/geometry/radian.test.ts
2392
+ --- a/tests/geometry/radian.test.ts
2393
+ +++ b/tests/geometry/radian.test.ts
2394
+ @@ -1,8 +1,9 @@
2395
+ import {describe} from "mocha";
2396
+ import {expect} from "chai";
2397
+ import {Radian} from "../../src/maths/geometry/radian";
2398
+ +
2399
+ describe('Random tests', () => {
2400
+ - it('should create a radian value', () => {
2401
+ + it('should create a radian name', () => {
2402
+ let r = new Radian('3/2')
2403
+
2404
+ expect(r.tex).to.be.equal('\\frac{ 3\\pi }{ 2 }')