pimath 0.0.39 → 0.0.42

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 (36) hide show
  1. package/dist/pi.js +293 -94
  2. package/dist/pi.js.map +1 -1
  3. package/dist/pi.min.js +1 -1
  4. package/dist/pi.min.js.map +1 -1
  5. package/docs/assets/search.js +1 -1
  6. package/esm/index.d.ts +2 -2
  7. package/esm/index.js +2 -2
  8. package/esm/maths/algebra/equation.d.ts +7 -2
  9. package/esm/maths/algebra/equation.js +52 -9
  10. package/esm/maths/algebra/equation.js.map +1 -1
  11. package/esm/maths/algebra/polynom.d.ts +2 -1
  12. package/esm/maths/algebra/polynom.js +98 -62
  13. package/esm/maths/algebra/polynom.js.map +1 -1
  14. package/esm/maths/algebra/rational.d.ts +10 -0
  15. package/esm/maths/algebra/rational.js +102 -11
  16. package/esm/maths/algebra/rational.js.map +1 -1
  17. package/esm/maths/coefficients/fraction.d.ts +3 -1
  18. package/esm/maths/coefficients/fraction.js +34 -5
  19. package/esm/maths/coefficients/fraction.js.map +1 -1
  20. package/esm/maths/coefficients/{nthroot.d.ts → nthRoot.d.ts} +5 -5
  21. package/esm/maths/coefficients/{nthroot.js → nthRoot.js} +5 -5
  22. package/esm/maths/coefficients/{nthroot.js.map → nthRoot.js.map} +1 -1
  23. package/esm/maths/geometry/line.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/index.ts +2 -2
  26. package/src/maths/algebra/equation.ts +61 -12
  27. package/src/maths/algebra/polynom.ts +100 -68
  28. package/src/maths/algebra/rational.ts +137 -21
  29. package/src/maths/coefficients/fraction.ts +40 -6
  30. package/src/maths/coefficients/{nthroot.ts → nthRoot.ts} +5 -5
  31. package/src/maths/geometry/line.ts +0 -1
  32. package/tests/algebra/equation.test.ts +38 -0
  33. package/tests/algebra/monom.test.ts +1 -4
  34. package/tests/algebra/rationnal.test.ts +29 -5
  35. package/tests/coefficients/fraction.test.ts +43 -1
  36. package/tests/geometry/circle.test.ts +4 -2
@@ -6,7 +6,7 @@
6
6
  import {Polynom} from "./polynom";
7
7
  import {Fraction} from "../coefficients/fraction";
8
8
  import {literalType} from "./monom";
9
- import {log} from "util";
9
+ import {Equation, ISolution, PARTICULAR_SOLUTION} from "./equation";
10
10
 
11
11
  /**
12
12
  * Rational class can handle rational polynoms
@@ -41,9 +41,6 @@ export class Rational {
41
41
  }
42
42
 
43
43
  get texFactors(): string {
44
- this._numerator.factorize()
45
- this._denominator.factorize()
46
-
47
44
  return `\\dfrac{ ${this._numerator.texFactors} }{ ${this._denominator.texFactors} }`
48
45
  }
49
46
 
@@ -56,16 +53,13 @@ export class Rational {
56
53
 
57
54
  domain = (): string => {
58
55
  let zeroes = this._denominator.getZeroes();
59
- if (zeroes.length === 0 || zeroes[0] === false) {
60
- return '\\mathbb{R}'
61
- } else if (zeroes[0] === true) {
62
- return '\\varnothing'
56
+ if (zeroes.length === 0 || zeroes[0].tex === PARTICULAR_SOLUTION.real) {
57
+ return PARTICULAR_SOLUTION.real
58
+ } else if (zeroes[0].tex === PARTICULAR_SOLUTION.varnothing) {
59
+ return PARTICULAR_SOLUTION.varnothing
63
60
  } else {
64
- return '\\mathbb{R}\\setminus\\left{' +
65
- zeroes.map(x => {
66
- return (typeof x === 'boolean') ? '' : x.frac
67
- })
68
- .join(';') + '\\right}'
61
+ return '\\mathbb{R}\\setminus\\left\\{' +
62
+ zeroes.map(x => x.tex).join(';') + '\\right\\}'
69
63
  }
70
64
  }
71
65
 
@@ -76,6 +70,18 @@ export class Rational {
76
70
  return this;
77
71
  }
78
72
 
73
+ derivative = (letter?: string): Rational => {
74
+ let N = this._numerator.clone(),
75
+ D = this._denominator.clone(),
76
+ dN = N.clone().derivative(letter),
77
+ dD = D.clone().derivative(letter)
78
+
79
+ this._numerator = dN.clone().multiply(D).subtract(N.clone().multiply(dD))
80
+ this._denominator = D.clone().pow(2)
81
+
82
+ return this
83
+ }
84
+
79
85
  simplify = (P: Polynom): Rational => {
80
86
  let NumeratorEuclidien = this._numerator.euclidian(P);
81
87
  if (!NumeratorEuclidien.reminder.isZero()) {
@@ -131,14 +137,13 @@ export class Rational {
131
137
  let {quotient, reminder} = this._numerator.clone().euclidian(this._denominator)
132
138
 
133
139
  // quotient is positive => it will be infinite.
134
- if(quotient.degree(letter).isStrictlyPositive()){
135
- return value===Infinity ? quotient.limitToInfinity(letter):quotient.limitToNegativeInfinity(letter)
140
+ if (quotient.degree(letter).isStrictlyPositive()) {
141
+ return value === Infinity ? quotient.limitToInfinity(letter) : quotient.limitToNegativeInfinity(letter)
136
142
  // return quotient.monomByDegree(undefined, letter).coefficient.sign()===1?(new Fraction()).infinite():(new Fraction()).infinite().opposed()
137
- }else{
143
+ } else {
138
144
  return quotient.monomByDegree(undefined, letter).coefficient
139
145
  }
140
- }
141
- else {
146
+ } else {
142
147
  let evalValues: literalType = {},
143
148
  evalValuesOffset: literalType = {},
144
149
  theLimit: Fraction | number,
@@ -151,7 +156,7 @@ export class Rational {
151
156
  theLimit = FR._numerator.evaluate(evalValues)
152
157
  .divide(FR._denominator.evaluate(evalValues))
153
158
 
154
- return theLimit.isInfinity()?theLimit.abs():theLimit
159
+ return theLimit.isInfinity() ? theLimit.abs() : theLimit
155
160
  } else {
156
161
  if (offset === 'above') {
157
162
  evalValuesOffset[letter === undefined ? 'x' : letter] = (new Fraction(value)).add(0.000001)
@@ -165,11 +170,122 @@ export class Rational {
165
170
  .divide(FR._denominator.evaluate(evalValuesOffset)).sign()
166
171
 
167
172
  if (theLimit.isInfinity()) {
168
- return theSign===1?theLimit.abs():theLimit.abs().opposed()
169
- }else{
173
+ return theSign === 1 ? theLimit.abs() : theLimit.abs().opposed()
174
+ } else {
170
175
  return theLimit
171
176
  }
172
177
  }
173
178
  }
174
179
  }
180
+
181
+ makeTableOfSigns = (): { factors: Polynom[], zeroes: ISolution[], signs: (string[])[], tex: string } => {
182
+ // Factorize the numerator and the denominator
183
+ this._numerator.factorize()
184
+ this._denominator.factorize()
185
+
186
+ let zeroes = Equation.makeSolutionsUnique([...this._numerator.getZeroes(), ...this._denominator.getZeroes()], true),
187
+ NFactors = this._numerator.factors,
188
+ DFactors = this._denominator.factors
189
+
190
+ let tableOfSigns: (string[])[] = [],
191
+ result: string[] = []
192
+
193
+ NFactors.forEach(factor => {
194
+ tableOfSigns.push(this._makeOneLineOfTableOfSigns(factor, zeroes, 'z'))
195
+ })
196
+ DFactors.forEach(factor => {
197
+ tableOfSigns.push(this._makeOneLineOfTableOfSigns(factor, zeroes, 'd'))
198
+ })
199
+
200
+ // Empty line
201
+ tableOfSigns.push([])
202
+
203
+ // Add the final row as cumulative
204
+ let resultLine: string[] = tableOfSigns[0].map((x, index) => {
205
+ if (index === 0) {
206
+ return ''
207
+ }
208
+ if (index === tableOfSigns[0].length - 1) {
209
+ return ''
210
+ }
211
+ if (index % 2 === 0) {
212
+ return 't'
213
+ }
214
+ return '+'
215
+ })
216
+
217
+ for (let current of tableOfSigns) {
218
+ for (let i = 0; i < current.length; i++) {
219
+ if (i % 2 === 0) {
220
+ // t, z or d
221
+ if (resultLine[i] === 'd') {
222
+ continue
223
+ }
224
+ if (current[i] !== 't') {
225
+ resultLine[i] = current[i]
226
+ }
227
+ } else {
228
+ // + or -
229
+ if (current[i] === '-') {
230
+ resultLine[i] = resultLine[i] === '+' ? '-' : '+'
231
+ }
232
+ }
233
+ }
234
+ }
235
+
236
+ // Add the variation line.
237
+ // TODO: add the variation line.
238
+
239
+ tableOfSigns.push(resultLine)
240
+
241
+ let tos = {
242
+ factors: [...NFactors, ...DFactors],
243
+ zeroes: zeroes,
244
+ signs: tableOfSigns,
245
+ tex: ''
246
+ }
247
+
248
+ this._makeTexFromTableOfSigns(tos)
249
+
250
+ return tos
251
+ }
252
+
253
+ private _makeTexFromTableOfSigns = (tos: { factors: Polynom[], zeroes: ISolution[], signs: (string[])[], tex: string }): string => {
254
+
255
+ let tex = `\\begin{tikzpicture}
256
+ \\tkzTabInit[lgt=3,espcl=2,deltacl=0]{/1.2,\\(${tos.factors.map(x => x.tex).join('\\)/1,\\(')}\\)/1,/.1,\\(f(x)\\)/1.2}{{\\scriptsize \\hspace{1cm} \\(-\\infty\\)},\\(${tos.zeroes.map(x => x.tex).join('\\),\\(')}\\),{\\scriptsize \\hspace{-1cm} \\(+\\infty\\)}}`
257
+ tos.signs.forEach(list => {
258
+ tex += (`\n\\tkzTabLine{${list.join(',')}}`)
259
+ })
260
+ tex += `\n\\end{tikzpicture}`
261
+
262
+ tos.tex = tex
263
+
264
+ return tex
265
+ }
266
+ private _makeOneLineOfTableOfSigns = (factor: Polynom, zeroes: ISolution[], zeroSign: string): string[] => {
267
+ let oneLine: string[] = [],
268
+ // TODO : check if there is no zero ?
269
+ currentZero = factor.getZeroes().map(x=>x.tex)
270
+
271
+ // First +/- sign, before the first zero
272
+ oneLine.push('')
273
+ oneLine.push(factor.evaluate(zeroes[0].value - 1).sign() === 1 ? '+' : '-')
274
+
275
+ for (let i = 0; i < zeroes.length; i++) {
276
+ // Add the zero if it's the current one
277
+ oneLine.push(currentZero.includes(zeroes[i].tex) ? zeroSign : 't')
278
+
279
+ // + / - sign after the current zero
280
+ if (i < zeroes.length - 1) {
281
+ oneLine.push(factor.evaluate((zeroes[i].value + zeroes[i + 1].value) / 2).sign() === 1 ? '+' : '-')
282
+ } else if (i === zeroes.length - 1) {
283
+ oneLine.push(factor.evaluate(zeroes[i].value + 1).sign() === 1 ? '+' : '-')
284
+ }
285
+
286
+ }
287
+ oneLine.push('')
288
+
289
+ return oneLine
290
+ }
175
291
  }
@@ -21,10 +21,6 @@ export class Fraction {
21
21
  return this;
22
22
  }
23
23
 
24
- get isFraction() {
25
- return true;
26
- }
27
-
28
24
  // ------------------------------------------
29
25
  // Getter and setter
30
26
  // ------------------------------------------
@@ -350,6 +346,44 @@ export class Fraction {
350
346
  return M
351
347
  }
352
348
 
349
+ static average = (...fractions: (Fraction|number)[]): Fraction => {
350
+ let M = new Fraction().zero()
351
+
352
+ for(let f of fractions){
353
+ M.add(f)
354
+ }
355
+
356
+ M.divide(fractions.length)
357
+
358
+ return M
359
+ }
360
+
361
+ static unique = (fractions: Fraction[], sorted?: boolean): Fraction[] => {
362
+ // TODO: make sure it's wokring -> test !
363
+ let unique:{[Key:string]:boolean} = {},
364
+ distinct: Fraction[] = []
365
+ fractions.forEach(x => {
366
+ if(!unique[x.clone().reduce().tex]){
367
+ distinct.push(x.clone())
368
+ unique[x.tex]=true
369
+ }
370
+ })
371
+
372
+ if(sorted) {
373
+ return Fraction.sort(distinct)
374
+ }else{
375
+ return distinct
376
+ }
377
+ }
378
+ static sort = (fractions: Fraction[], reverse?:boolean): Fraction[] => {
379
+ // Todo make sure it's the correct order, not reverse -> make a test
380
+ let sorted = fractions.sort((a, b)=>a.value-b.value)
381
+
382
+ if(reverse){sorted.reverse()}
383
+
384
+ return sorted
385
+ }
386
+
353
387
  // ------------------------------------------
354
388
  // Mathematical operations specific to fractions
355
389
  // ------------------------------------------
@@ -467,10 +501,10 @@ export class Fraction {
467
501
  return isNaN(this._numerator);
468
502
  }
469
503
  isInfinity = (): boolean => {
470
- return this._numerator === Infinity;
504
+ return Math.abs(this._numerator) === Infinity;
471
505
  }
472
506
  isFinite = (): boolean => {
473
- return !this.isInfinity();
507
+ return !this.isInfinity() && !this.isNaN();
474
508
  }
475
509
  isSquare = (): boolean => {
476
510
  return Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Nthroot is something like "a+b\sqrt{3}
2
+ * NthRoot is something like "a+b\sqrt{3}
3
3
  */
4
- export class Nthroot {
4
+ export class NthRoot {
5
5
  private _radical: number;
6
6
  private _nth: number;
7
7
  private _coefficient: number;
@@ -80,7 +80,7 @@ export class Nthroot {
80
80
  // ------------------------------------------
81
81
  // Creation / parsing functions
82
82
  // ------------------------------------------
83
- parse = (radical: number, nthroot?: number, coefficient?: number): Nthroot => {
83
+ parse = (radical: number, nthroot?: number, coefficient?: number): NthRoot => {
84
84
  this._coefficient = (coefficient === undefined) ? 1 : coefficient;
85
85
  this._nth = (nthroot === undefined) ? 2 : nthroot;
86
86
  this._radical = (radical === undefined) ? 1 : radical;
@@ -94,7 +94,7 @@ export class Nthroot {
94
94
  // ------------------------------------------
95
95
  // Mathematical operations
96
96
  // ------------------------------------------
97
- reduce = (): Nthroot => {
97
+ reduce = (): NthRoot => {
98
98
  // Max value to test.
99
99
  let V = Math.floor(Math.pow(this._radical, 1 / this._nth));
100
100
  while (V > 1) {
@@ -112,7 +112,7 @@ export class Nthroot {
112
112
  return this;
113
113
  };
114
114
 
115
- multiply = (N: Nthroot): Nthroot => {
115
+ multiply = (N: NthRoot): NthRoot => {
116
116
  this._radical *= N.radical;
117
117
  return this.reduce();
118
118
  };
@@ -440,7 +440,6 @@ export class Line {
440
440
  }
441
441
 
442
442
  getValueAtX = (value: Fraction|number): Fraction => {
443
-
444
443
  const equ = this.equation.clone().isolate('y'),
445
444
  F = new Fraction(value)
446
445
 
@@ -0,0 +1,38 @@
1
+ import {describe} from "mocha";
2
+ import {Rational} from "../../src/maths/algebra/rational";
3
+ import {Polynom} from "../../src/maths/algebra/polynom";
4
+ import {expect} from "chai";
5
+ import {Equation} from "../../src/maths/algebra/equation";
6
+
7
+ describe('Equations tests', () => {
8
+ it('should get the solutions', () => {
9
+
10
+ let E1 = new Equation('3x+8', '0')
11
+ E1.solve()
12
+ expect(E1.solutions[0].tex).to.be.equal('-\\frac{ 8 }{ 3 }')
13
+
14
+ let E2 = new Equation('x^2+5x+6', '0')
15
+ E2.solve()
16
+ expect(E2.solutions.map(x=>x.tex)).to.have.all.members(['-3', '-2'])
17
+
18
+ let E3 = new Equation('(x-3)(x+2)(3x-5)', '0')
19
+ E3.solve()
20
+ expect(E3.solutions.map(x=>x.tex)).to.have.all.members([ '-2', '3', '\\frac{ 5 }{ 3 }' ])
21
+
22
+ let E4 = new Equation('x^2+x+10', '0')
23
+ E4.solve()
24
+ expect(E4.solutions.map(x=>x.tex)).to.have.all.members([ '\\varnothing' ])
25
+
26
+ let E5 = new Equation('(x-3)(x+2)(x-5)(x-7)(x+2)', 0)
27
+ E5.solve()
28
+ expect(E5.solutions.map(x=>x.tex)).to.have.all.members([ '-2', '3', '5', '7' ] )
29
+
30
+
31
+ let E6 = new Equation('5x^2+7x-31', 0)
32
+ E6.solve()
33
+ expect(E6.solutions.map(x=>x.tex)).to.have.all.members([
34
+ '\\dfrac{-7 - \\sqrt{669} }{ 10 }',
35
+ '\\dfrac{-7 + \\sqrt{669} }{ 10 }'
36
+ ] )
37
+ })
38
+ })
@@ -1,10 +1,7 @@
1
1
  import {expect} from 'chai';
2
- import {Monom} from "../../src/maths/algebra";
3
2
  import {Random} from "../../src/maths/randomization/random";
4
3
  import {describe} from "mocha";
5
- import {Fraction} from "../../src/maths/coefficients";
6
- import {Shutingyard} from "../../src/maths/shutingyard";
7
- import {log} from "util";
4
+ import {Monom} from "../../src/maths/algebra/monom";
8
5
 
9
6
  describe('Monom with integer power', () => {
10
7
  it('parsing', () => {
@@ -1,7 +1,6 @@
1
1
  import {describe} from "mocha";
2
2
  import {Rational} from "../../src/maths/algebra/rational";
3
3
  import {Polynom} from "../../src/maths/algebra/polynom";
4
- import {Fraction} from "../../src/maths/coefficients/fraction";
5
4
  import {expect} from "chai";
6
5
 
7
6
  describe('Rational tests', () => {
@@ -12,12 +11,12 @@ describe('Rational tests', () => {
12
11
  new Polynom('(x-4)(x+2)')
13
12
  )
14
13
 
15
- expect(FR.limits(4).tex).to.be.equal("Infinity")
16
- expect(FR.limits(4, 'below').tex).to.be.equal("-Infinity")
17
- expect(FR.limits(4, 'above').tex).to.be.equal("Infinity")
14
+ expect(FR.limits(4).tex).to.be.equal("+\\infty")
15
+ expect(FR.limits(4, 'below').tex).to.be.equal("-\\infty")
16
+ expect(FR.limits(4, 'above').tex).to.be.equal("+\\infty")
18
17
  expect(FR.limits(-2).tex).to.be.equal("-\\frac{ 1 }{ 6 }")
19
18
  })
20
- it('should calculate the limits to Infinity', ()=>{
19
+ it('should calculate the limits to Infinity', () => {
21
20
  const FR0 = new Rational(
22
21
  new Polynom('3'),
23
22
  new Polynom('x-5')
@@ -41,4 +40,29 @@ describe('Rational tests', () => {
41
40
  expect(FR3.limits(Infinity).value).to.be.equal(Infinity)
42
41
  expect(FR3.limits(-Infinity).value).to.be.equal(-Infinity)
43
42
  })
43
+
44
+ it('should make a table of signs', function () {
45
+
46
+ // const FR = new Rational(
47
+ // new Polynom('(x-2)'),
48
+ // new Polynom('(x+2)')
49
+ // )
50
+ // let tos = FR.makeTableOfSigns()
51
+ // expect(tos.zeroes.map(x => x.tex)).to.have.all.members(['-2', '2'])
52
+ // expect(tos.signs).to.be.eql([['', '-', 't', '-', 'z', '+', ''], ['', '-', 'd', '+', 't', '+', ''], [], ['', '+', 'd', '-', 'z', '+', '']])
53
+ const FR2 = new Rational(
54
+ new Polynom('(x-2)(x+5)(x^2+5x-31'),
55
+ new Polynom('(x+2)')
56
+ )
57
+ let tos2 = FR2.makeTableOfSigns()
58
+ });
59
+
60
+ it('should calculate the derivative', function () {
61
+ const FR = new Rational(
62
+ new Polynom('x^2+5x+6'),
63
+ new Polynom('x-3')
64
+ )
65
+
66
+ FR.derivative()
67
+ });
44
68
  })
@@ -1,5 +1,6 @@
1
1
  import {expect} from "chai";
2
- import {Fraction} from "../../src/maths/coefficients";
2
+ import {Fraction} from "../../src/maths/coefficients/fraction";
3
+ import {describe} from "mocha";
3
4
 
4
5
  describe('Fraction tests', () => { // the tests container
5
6
 
@@ -33,4 +34,45 @@ describe('Fraction tests', () => { // the tests container
33
34
  expect(F.isReduced()).to.be.true
34
35
  expect(Q.isReduced()).to.be.false
35
36
  })
37
+
38
+
39
+ })
40
+
41
+ describe("Fraction static functions", ()=>{
42
+ it('should sort fractions', function () {
43
+ let list = [
44
+ new Fraction('3.5'),
45
+ new Fraction('-2.5'),
46
+ new Fraction('3.1'),
47
+ new Fraction('3.54'),
48
+ new Fraction('1.5')
49
+ ]
50
+
51
+ expect(Fraction.sort(list).map(x=>x.value)).to.eql([ -2.5, 1.5, 3.1, 3.5, 3.54 ])
52
+ });
53
+
54
+ it('should make a list of fractions unique', function () {
55
+ let list = [
56
+ new Fraction('3.5'),
57
+ new Fraction('-2.5'),
58
+ new Fraction('7/2'),
59
+ new Fraction('3.50'),
60
+ new Fraction('1.5')
61
+ ]
62
+
63
+ expect(Fraction.unique(list, true).map(x=>x.value)).to.be.eql([ -2.5, 1.5, 3.5 ])
64
+
65
+ });
66
+
67
+ it('shoudl get the average of fractions', function() {
68
+ let list = [
69
+ new Fraction('3.5'),
70
+ new Fraction('-2.5'),
71
+ new Fraction('7/2'),
72
+ new Fraction('3.50'),
73
+ new Fraction('1.5')
74
+ ]
75
+
76
+ expect(Fraction.average(...list).tex).to.be.equal('\\frac{ 19 }{ 10 }')
77
+ })
36
78
  })
@@ -1,7 +1,9 @@
1
1
  import {describe} from "mocha";
2
- import {Circle, Line, Point} from "../../src/maths/geometry";
3
- import {Fraction} from "../../src/maths/coefficients";
4
2
  import {expect} from "chai";
3
+ import {Circle} from "../../src/maths/geometry/circle";
4
+ import {Line} from "../../src/maths/geometry/line";
5
+ import {Point} from "../../src/maths/geometry/point";
6
+ import {Fraction} from "../../src/maths/coefficients/fraction";
5
7
 
6
8
  describe('Circle', function () {
7
9
  it('should calculate the intersection of a circle and a line', function () {