pimath 0.0.25 → 0.0.29

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 (70) hide show
  1. package/dev/index.html +10 -7
  2. package/dev/pi.js +251 -98
  3. package/dev/pi.js.map +1 -1
  4. package/dist/pi.js +1 -1
  5. package/dist/pi.js.map +1 -1
  6. package/docs/assets/search.js +1 -1
  7. package/docs/classes/algebra.Equation.html +9 -9
  8. package/docs/classes/algebra.LinearSystem.html +1 -1
  9. package/docs/classes/algebra.Logicalset.html +2 -2
  10. package/docs/classes/algebra.Monom.html +45 -44
  11. package/docs/classes/algebra.Polynom.html +9 -9
  12. package/docs/classes/algebra.Rational.html +2 -2
  13. package/docs/classes/coefficients.Fraction.html +6 -6
  14. package/docs/classes/coefficients.Nthroot.html +1 -1
  15. package/docs/classes/geometry.Circle.html +1 -1
  16. package/docs/classes/geometry.Line.html +2 -2
  17. package/docs/classes/geometry.Point.html +1 -1
  18. package/docs/classes/geometry.Triangle.html +5 -5
  19. package/docs/classes/geometry.Vector.html +1 -1
  20. package/docs/classes/numeric.Numeric.html +5 -5
  21. package/docs/classes/shutingyard.Shutingyard.html +5 -5
  22. package/docs/interfaces/geometry.remarquableLines.html +1 -1
  23. package/docs/modules/algebra.html +1 -1
  24. package/docs/modules/random.Random.html +1 -1
  25. package/docs/modules/random.html +1 -1
  26. package/esm/main.js +2 -0
  27. package/esm/main.js.map +1 -1
  28. package/esm/maths/algebra/logicalset.js +1 -1
  29. package/esm/maths/algebra/logicalset.js.map +1 -1
  30. package/esm/maths/algebra/monom.d.ts +2 -1
  31. package/esm/maths/algebra/monom.js +7 -1
  32. package/esm/maths/algebra/monom.js.map +1 -1
  33. package/esm/maths/algebra/polynom.js +1 -1
  34. package/esm/maths/algebra/polynom.js.map +1 -1
  35. package/esm/maths/algebra/rational.d.ts +1 -1
  36. package/esm/maths/algebra/rational.js +2 -2
  37. package/esm/maths/algebra/rational.js.map +1 -1
  38. package/esm/maths/coefficients/fraction.js.map +1 -1
  39. package/esm/maths/geometry/line.d.ts +1 -0
  40. package/esm/maths/geometry/line.js +3 -0
  41. package/esm/maths/geometry/line.js.map +1 -1
  42. package/esm/maths/geometry/vector.js +7 -2
  43. package/esm/maths/geometry/vector.js.map +1 -1
  44. package/esm/maths/numexp.d.ts +16 -0
  45. package/esm/maths/numexp.js +119 -0
  46. package/esm/maths/numexp.js.map +1 -0
  47. package/esm/maths/shutingyard.d.ts +21 -4
  48. package/esm/maths/shutingyard.js +76 -76
  49. package/esm/maths/shutingyard.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/main.ts +2 -0
  52. package/src/maths/algebra/logicalset.ts +2 -2
  53. package/src/maths/algebra/monom.ts +35 -22
  54. package/src/maths/algebra/polynom.ts +1 -1
  55. package/src/maths/algebra/rational.ts +1 -1
  56. package/src/maths/geometry/line.ts +3 -0
  57. package/src/maths/geometry/vector.ts +10 -2
  58. package/src/maths/numexp.ts +138 -0
  59. package/src/maths/shutingyard.ts +94 -97
  60. package/tests/algebra/monom.test.ts +1 -1
  61. package/tests/algebra/polynom.test.ts +10 -1
  62. package/tests/numexp.test.ts +14 -0
  63. package/tests/shutingyard.test.ts +3 -3
  64. package/tsconfig.json +0 -1
  65. package/esm/docs.d.ts +0 -6
  66. package/esm/docs.js +0 -7
  67. package/esm/docs.js.map +0 -1
  68. package/esm/maths/random/random.d.ts +0 -13
  69. package/esm/maths/random/random.js +0 -27
  70. package/esm/maths/random/random.js.map +0 -1
@@ -1,7 +1,5 @@
1
1
  /***
2
2
  * Monom class
3
- * Defined as coefficient * literal
4
- * Examples: 3x^2, 3/5x^2, ...
5
3
  */
6
4
  import {Fraction} from "../coefficients";
7
5
  import {Numeric} from "../numeric";
@@ -16,8 +14,10 @@ export class Monom {
16
14
  private _literal: literalType;
17
15
 
18
16
  /**
19
- * Create the monom object.
20
- * @param value (optional) string
17
+ * Create a Monom
18
+ * Defined as \\(k \\cdot x^{n}\\), where \\( k,n \in \\mathbb{Q}\\).
19
+ * Examples: \\(3x^2\\) or \\(3/5x^2\\)
20
+ * @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).
21
21
  */
22
22
  constructor(value?: unknown) {
23
23
  this.zero();
@@ -34,29 +34,35 @@ export class Monom {
34
34
  // Getter and setter
35
35
  // ------------------------------------------
36
36
  /**
37
- * Get the coefficient as fraction
37
+ * Get the coefficient \\(k\\) of the Monom \\(k\\cdot x^{n}\\)
38
+ * @returns {Fraction}
38
39
  */
39
40
  get coefficient(): Fraction {
40
41
  return this._coefficient;
41
42
  }
42
43
 
43
44
  /**
44
- * Set the coefficient value of the monom
45
- * @param F Fraction
45
+ * Set the coefficient \\(k\\) value of the monom
46
+ * @param {Fraction | number | string} F
46
47
  */
47
- set coefficient(F: Fraction) {
48
- this._coefficient = F;
48
+ set coefficient(F: Fraction | number | string) {
49
+ this._coefficient = new Fraction(F);
49
50
  }
50
51
 
51
52
  /**
52
- * Get the literal part, as dictionary
53
+ * Get the literal part of \\(x^{n_1}y^{n_2}\\) as dictionary \\[\\begin{array}{ll}x&=n_1\\\\y&=n_2\\end{array}\\]
54
+ * @returns {literalType}
53
55
  */
54
56
  get literal(): literalType {
55
57
  return this._literal;
56
58
  }
57
59
 
60
+ /**
61
+ * Get the literal square roots of the Monom.
62
+ * TODO: remove this getter ? Is it used and is it correct ?
63
+ * @returns {literalType}
64
+ */
58
65
  get literalSqrt(): literalType {
59
-
60
66
  if (this.isLiteralSquare()) {
61
67
  let L: literalType = {}
62
68
  for (let key in this._literal) {
@@ -69,8 +75,8 @@ export class Monom {
69
75
  }
70
76
 
71
77
  /**
72
- * Set the literal part of the monom
73
- * @param L Literal part as dictionary: <setLetter: exposant>
78
+ * Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}
79
+ * @param {literalType} L
74
80
  */
75
81
  set literal(L: literalType) {
76
82
  this._literal = L;
@@ -230,11 +236,18 @@ export class Monom {
230
236
  * Display the monom, forcing the '+' sign to appear
231
237
  */
232
238
  get displayWithSign(): string {
233
- // TODO: Rename or remove this getter ?
234
239
  let d: String = this.display;
235
240
  return (d[0] !== '-' ? '+' : '') + d;
236
241
  }
237
242
 
243
+ get texWithSign(): string {
244
+ if (this.coefficient.isStrictlyPositive()) {
245
+ return '+' + this.tex
246
+ }
247
+
248
+ return this.tex
249
+ }
250
+
238
251
  /**
239
252
  * Get the tex output of the monom
240
253
  */
@@ -281,15 +294,15 @@ export class Monom {
281
294
  */
282
295
  parse = (inputStr: unknown): Monom => {
283
296
 
284
- if(typeof inputStr === 'string') {
297
+ if (typeof inputStr === 'string') {
285
298
  this._shutingYardToReducedMonom(inputStr)
286
- }else if(typeof inputStr ==='number') {
299
+ } else if (typeof inputStr === 'number') {
287
300
  this._coefficient = new Fraction(inputStr)
288
301
  this._literal = {}
289
- }else if(inputStr instanceof Fraction) {
302
+ } else if (inputStr instanceof Fraction) {
290
303
  this._coefficient = inputStr.clone()
291
304
  this._literal = {}
292
- }else if(inputStr instanceof Monom){
305
+ } else if (inputStr instanceof Monom) {
293
306
  this._coefficient = inputStr._coefficient.clone()
294
307
  this._literal = this.copyLiterals(inputStr.literal)
295
308
  }
@@ -384,7 +397,7 @@ export class Monom {
384
397
  };
385
398
 
386
399
  copyLiterals = (literal: literalType): literalType => {
387
- let L:literalType = {}
400
+ let L: literalType = {}
388
401
 
389
402
  for (let k in literal) {
390
403
  L[k] = literal[k].clone()
@@ -392,7 +405,7 @@ export class Monom {
392
405
  return L
393
406
  }
394
407
 
395
- makeSame = (M: Monom):Monom => {
408
+ makeSame = (M: Monom): Monom => {
396
409
  // Copy the literal parts.
397
410
  for (let k in M._literal) {
398
411
  this.setLetter(k, M._literal[k].clone());
@@ -451,7 +464,7 @@ export class Monom {
451
464
  add = (...M: Monom[]): Monom => {
452
465
  for (let m of M) {
453
466
  if (this.isSameAs(m)) {
454
- if(this.isZero()){
467
+ if (this.isZero()) {
455
468
  this.makeSame(m)
456
469
  }
457
470
  this._coefficient.add(m.coefficient);
@@ -469,7 +482,7 @@ export class Monom {
469
482
  subtract = (...M: Monom[]): Monom => {
470
483
  for (let m of M) {
471
484
  if (this.isSameAs(m)) {
472
- if(this.isZero()){
485
+ if (this.isZero()) {
473
486
  this.makeSame(m)
474
487
  }
475
488
  this._coefficient.add(m.clone().coefficient.opposed());
@@ -461,7 +461,7 @@ export class Polynom {
461
461
 
462
462
  // Make the euclidian division of the two polynoms.
463
463
  let MaxIteration = this.degree(letter).clone().multiply(2);
464
- while (reminder.degree(letter) >= degreeP && MaxIteration.isPositive()) {
464
+ while (reminder.degree(letter).geq(degreeP) && MaxIteration.isPositive()) {
465
465
  MaxIteration.subtract(1)
466
466
 
467
467
  // Get the greatest monom divided by the max monom of the divider
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import {Polynom} from "./polynom";
7
- import {Fraction} from "../coefficients/fraction";
7
+ import {Fraction} from "../coefficients";
8
8
 
9
9
  /**
10
10
  * Rational class can handle rational polynoms
@@ -312,6 +312,9 @@ export class Line {
312
312
  isSameAs = (line: Line): Boolean => {
313
313
  return this.slope.isEqual(line.slope) && this.height.isEqual(line.height);
314
314
  }
315
+ isVertical = (): Boolean => {
316
+ return this.slope.isInfinity()
317
+ }
315
318
  simplify = (): Line => {
316
319
  let lcm = Numeric.lcm(this._a.denominator, this._b.denominator, this._c.denominator),
317
320
  gcd = Numeric.gcd(this._a.numerator, this._b.numerator, this._c.numerator);
@@ -81,12 +81,20 @@ export class Vector {
81
81
  }
82
82
 
83
83
  // Fractions or a number are give
84
- if (values[0].isFraction || !isNaN(values[0])) {
84
+ if (values[0] instanceof Fraction || !isNaN(values[0])) {
85
85
  this._x = new Fraction(values[0])
86
86
  }
87
- if (values[1].isFraction || !isNaN(values[1])) {
87
+ if (values[1] instanceof Fraction || !isNaN(values[1])) {
88
88
  this._y = new Fraction(values[1])
89
89
  }
90
+
91
+ if(
92
+ (typeof values[0] === 'object' && !isNaN(values[0].x) && !isNaN(values[0].x)) &&
93
+ (typeof values[1] === 'object' && !isNaN(values[1].x) && !isNaN(values[1].x))
94
+ ){
95
+ this._x = new Fraction(+values[1].x-values[0].x)
96
+ this._y = new Fraction(+values[1].y-values[0].y)
97
+ }
90
98
  }
91
99
 
92
100
  return this;
@@ -0,0 +1,138 @@
1
+ import {Shutingyard, ShutingyardMode, ShutingyardType, tokenConstant} from "./shutingyard";
2
+ import {Fraction} from "./coefficients";
3
+
4
+ export class NumExp {
5
+ private _rpn: { token: string, tokenType: string }[]
6
+ private _expression: string
7
+
8
+ constructor(value: string) {
9
+ this._expression = value
10
+ this._rpn = new Shutingyard(ShutingyardMode.NUMERIC).parse(value).rpn
11
+ }
12
+
13
+ get rpn(): { token: string; tokenType: string }[] {
14
+ return this._rpn;
15
+ }
16
+
17
+ get expression(): string {
18
+ return this._expression;
19
+ }
20
+
21
+ private _extractDecimalPart(value: number): string {
22
+ let decimal = value.toString()
23
+
24
+ if (!decimal.includes('.')) {
25
+ return ''
26
+ }
27
+
28
+ decimal = decimal.split('.')[1]
29
+
30
+ return decimal.substring(0, decimal.length - 2)
31
+ }
32
+
33
+ private _numberCorrection(value: number): number {
34
+ // Must modify the number if it's like:
35
+ // a: 3.0000000000000003
36
+ // b: 3.9999999999999994
37
+ // remove the last character
38
+ // check if around n last characters are either 0 or 9
39
+ // if it is, 'round' the number.
40
+
41
+ const epsilon = 0.00000000000001,
42
+ number_of_digits = 6
43
+
44
+ let decimal = this._extractDecimalPart(value)
45
+ if(decimal===''){return value}
46
+
47
+ const n9 = decimal.match(/9+$/g)
48
+ const n0 = decimal.match(/0+$/g)
49
+
50
+ if (n9 && n9[0].length >= number_of_digits) {
51
+ // New tested values.
52
+ let mod = this._extractDecimalPart(value + epsilon),
53
+ mod0 = mod.match(/0+$/g)
54
+
55
+ if(mod0 && mod0[0].length>= number_of_digits){
56
+ // The value can be changed. Remove all zeros!
57
+ return +((value+epsilon).toString().split(mod0[0])[0])
58
+ }
59
+ }
60
+
61
+ if (n0 && n0[0].length >= number_of_digits) {
62
+ // New tested values.
63
+ let mod = this._extractDecimalPart(value - epsilon),
64
+ mod9 = mod.match(/9+$/g)
65
+
66
+ if(mod9 && mod9[0].length>= number_of_digits){
67
+ // The value can be changed. Remove all nines!
68
+ return +(value.toString().split(n0[0])[0])
69
+ }
70
+ }
71
+
72
+ return value
73
+ }
74
+
75
+ private _addToStack(stack:number[], value: number): void {
76
+ stack.push(this._numberCorrection(value))
77
+ }
78
+
79
+ evaluate(values: { [Key: string]: number }): number {
80
+ let stack: number[] = []
81
+ for (const element of this._rpn) {
82
+ if (element.tokenType === ShutingyardType.COEFFICIENT) {
83
+ // May be a numeric value or a Fraction.
84
+ if (!isNaN(+element.token)) {
85
+ this._addToStack(stack, +element.token)
86
+ } else {
87
+ this._addToStack(stack, new Fraction(element.token).value)
88
+ }
89
+ } else if (element.tokenType === ShutingyardType.VARIABLE) {
90
+ if (values[element.token] !== undefined) {
91
+ this._addToStack(stack, +values[element.token])
92
+ }
93
+ } else if (element.tokenType === ShutingyardType.CONSTANT) {
94
+ this._addToStack(stack, tokenConstant[element.token])
95
+ } else if (element.tokenType === ShutingyardType.OPERATION) {
96
+ if (element.token === '*') {
97
+ const b = +stack.pop(),
98
+ a = +stack.pop()
99
+ this._addToStack(stack, a * b)
100
+ } else if (element.token === '/') {
101
+ const b = +stack.pop(),
102
+ a = +stack.pop()
103
+ this._addToStack(stack, a / b)
104
+ } else if (element.token === '+') {
105
+ const b = +stack.pop(),
106
+ a = +stack.pop()
107
+ this._addToStack(stack, a + b)
108
+ } else if (element.token === '-') {
109
+ const b = +stack.pop(),
110
+ a = +stack.pop()
111
+ this._addToStack(stack, a - b)
112
+ } else if (element.token === '^') {
113
+ const b = +stack.pop(),
114
+ a = +stack.pop()
115
+ this._addToStack(stack, Math.pow(a, b))
116
+ }
117
+ } else if (element.tokenType === ShutingyardType.FUNCTION) {
118
+ const a = +stack.pop()
119
+ if (element.token === 'sin') {
120
+ this._addToStack(stack, Math.sin(a))
121
+ } else if (element.token === 'cos') {
122
+ this._addToStack(stack, Math.cos(a))
123
+ } else if (element.token === 'tan') {
124
+ this._addToStack(stack, Math.tan(a))
125
+ } else if(element.token === 'sqrt') {
126
+ this._addToStack(stack, Math.sqrt(a))
127
+ }
128
+ }
129
+ }
130
+
131
+ if (stack.length === 1) {
132
+ return stack[0]
133
+ } else {
134
+ console.error('There was a problem parsing', this._expression, '. The RPN array is', this._rpn)
135
+ return 0
136
+ }
137
+ }
138
+ }
@@ -1,20 +1,42 @@
1
1
  import {loadHighlighter} from "typedoc/dist/lib/utils/highlighter";
2
+ import exp = require("constants");
2
3
 
3
4
  type tokenType = {
4
5
  [key: string]: {
5
6
  precedence: number,
6
- associative: string
7
+ associative: string,
8
+ type: string
7
9
  }
8
10
  }
9
11
 
12
+ export const tokenConstant:{[Key:string]:number} = {
13
+ pi: Math.PI,
14
+ e: Math.exp(1)
15
+ }
16
+ export enum ShutingyardType {
17
+ VARIABLE='variable',
18
+ COEFFICIENT='coefficient',
19
+ OPERATION = 'operation',
20
+ CONSTANT = 'constant',
21
+ FUNCTION = 'function',
22
+ MONOM = 'monom'
23
+ }
24
+ export enum ShutingyardMode {
25
+ POLYNOM= 'polynom',
26
+ SET = 'set',
27
+ NUMERIC = 'numeric'
28
+ }
29
+
10
30
  export class Shutingyard {
11
31
  private _rpn: { token: string, tokenType: string }[] = [];
12
- readonly _mode: 'polynom' | 'set';
32
+ readonly _mode: ShutingyardMode;
13
33
  private _tokenConfig: tokenType;
34
+ private _tokenConstant: {[Key:string]: number}
14
35
  private _uniformize: boolean;
36
+ private _tokenKeys: string[]
15
37
 
16
- constructor(mode?: 'polynom' | 'set') {
17
- this._mode = typeof mode === 'undefined' ? 'polynom' : mode;
38
+ constructor(mode?: ShutingyardMode ) {
39
+ this._mode = typeof mode === 'undefined' ? ShutingyardMode.POLYNOM : mode;
18
40
  this.tokenConfigInitialization()
19
41
  }
20
42
 
@@ -23,41 +45,57 @@ export class Shutingyard {
23
45
  * Defined operations: + - * / ^ sin cos tan
24
46
  * @param token
25
47
  */
26
- isOperation(token: string): boolean {
27
- if (token[0].match(/[+\-*/^]/g)) {
28
- return true;
29
- }
30
- //
31
- // if (token.match(/^sin|cos|tan/g)) {
32
- // return true;
33
- // }
34
-
35
- return false;
36
- }
48
+ // isOperation(token: string): boolean {
49
+ // if (token[0].match(/[+\-*/^]/g)) {
50
+ // return true;
51
+ // }
52
+ // //
53
+ // // if (token.match(/^sin|cos|tan/g)) {
54
+ // // return true;
55
+ // // }
56
+ //
57
+ // return false;
58
+ // }
37
59
 
38
60
  tokenConfigInitialization(): tokenType {
39
- if (this._mode === 'set') {
61
+ if (this._mode === ShutingyardMode.SET) {
40
62
  this._tokenConfig = {
41
- '&': {precedence: 3, associative: 'left'},
42
- '|': {precedence: 3, associative: 'left'},
43
- '!': {precedence: 4, associative: 'right'},
44
- '-': {precedence: 2, associative: 'left'}
63
+ '&': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
64
+ '|': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
65
+ '!': {precedence: 4, associative: 'right', type: ShutingyardType.OPERATION},
66
+ '-': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION}
45
67
  }
46
68
  this._uniformize = false;
69
+ }else if (this._mode === ShutingyardMode.NUMERIC){
70
+ this._tokenConfig = {
71
+ '^': {precedence: 4, associative: 'right', type: ShutingyardType.OPERATION},
72
+ '*': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
73
+ '/': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
74
+ '+': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION},
75
+ '-': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION},
76
+ '%': {precedence: 3, associative: 'right', type: ShutingyardType.OPERATION},
77
+ 'sin': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
78
+ 'cos': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
79
+ 'tan': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
80
+ 'sqrt': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
81
+ }
82
+ this._uniformize = false
47
83
  } else {
48
84
  this._tokenConfig = {
49
- '^': {precedence: 4, associative: 'right'},
50
- '*': {precedence: 3, associative: 'left'},
51
- '/': {precedence: 3, associative: 'left'},
52
- '+': {precedence: 2, associative: 'left'},
53
- '-': {precedence: 2, associative: 'left'},
54
- '%': {precedence: 3, associative: 'right'},
55
- 'sin': {precedence: 4, associative: 'right'},
56
- 'cos': {precedence: 4, associative: 'right'},
57
- 'tab': {precedence: 4, associative: 'right'},
85
+ '^': {precedence: 4, associative: 'right', type: ShutingyardType.OPERATION},
86
+ '*': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
87
+ '/': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
88
+ '+': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION},
89
+ '-': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION},
90
+ '%': {precedence: 3, associative: 'right', type: ShutingyardType.OPERATION},
91
+ 'sin': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
92
+ 'cos': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
93
+ 'tan': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
58
94
  }
59
95
  this._uniformize = true
60
96
  }
97
+
98
+ this._tokenKeys = Object.keys(this._tokenConfig).sort((a,b)=>b.length-a.length)
61
99
  return this._tokenConfig
62
100
  }
63
101
 
@@ -66,7 +104,7 @@ export class Shutingyard {
66
104
  * @param expr (string) Expression to analyse
67
105
  * @param start (number) CUrrent position in the expr string.
68
106
  */
69
- NextToken2(expr: string, start: number): [string, number, string] {
107
+ NextToken(expr: string, start: number): [string, number, string] {
70
108
  let token: string, tokenType: string;
71
109
  token = '';
72
110
  tokenType = '';
@@ -86,12 +124,23 @@ export class Shutingyard {
86
124
  tokenType = 'function-argument';
87
125
  } else{
88
126
  // Order token keys by token characters length (descending)
89
- const keys = Object.keys(this._tokenConfig).sort((a,b)=>b.length-a.length)
127
+ // TODO: this is done each time ! SHould be done once !
128
+ // const keys = Object.keys(this._tokenConfig).sort((a,b)=>b.length-a.length)
129
+
130
+ // Extract operation and function tokens
131
+ for(let key of this._tokenKeys){
132
+ if(expr.substring(start, start+key.length) === key){
133
+ token += key;
134
+ tokenType = this._tokenConfig[key].type
135
+ break
136
+ }
137
+ }
90
138
 
91
- for(let key of keys){
92
- if(expr.substr(start, key.length) === key){
139
+ // Extract constant
140
+ for(let key in tokenConstant){
141
+ if(expr.substring(start, start+key.length) === key){
93
142
  token += key;
94
- tokenType = 'operation'
143
+ tokenType = ShutingyardType.CONSTANT
95
144
  break
96
145
  }
97
146
  }
@@ -99,77 +148,24 @@ export class Shutingyard {
99
148
  if(token===''){
100
149
  // No function found ! Might be a coefficient !
101
150
  if( expr[start].match(/[0-9]/) ) {
102
- token = expr.substr(start).match(/^([0-9.,/]+)/)[0]
103
- tokenType = 'coefficient'
151
+ if(this._mode === ShutingyardMode.POLYNOM) {
152
+ token = expr.substring(start).match(/^([0-9.,/]+)/)[0]
153
+ }else{
154
+ token = expr.substring(start).match(/^([0-9.,]+)/)[0]
155
+ }
156
+ tokenType = ShutingyardType.COEFFICIENT
104
157
  }else if (expr[start].match(/[a-zA-Z]/)) {
105
- token = expr.substr(start).match(/^([a-zA-Z])/)[0]
106
- tokenType = 'variable'
158
+ token = expr.substring(start).match(/^([a-zA-Z])/)[0]
159
+ tokenType = ShutingyardType.VARIABLE
107
160
  }else{
108
161
  console.log('Unidentified token', expr[start], expr, start)
109
162
  token = expr[start]
110
- tokenType = 'monom'
163
+ tokenType = ShutingyardType.MONOM
111
164
  }
112
165
 
113
166
  }
114
167
  }
115
168
 
116
-
117
- // console.log(token, tokenType)
118
- return [token, start + token.length, tokenType];
119
- }
120
-
121
- NextToken(expr: string, start: number): [string, number, string] {
122
- let tokenMatch: string[], token: string, tokenType: string;
123
-
124
- this.NextToken2(expr, start)
125
- // Detect a fraction monoms or return empty array
126
- tokenMatch = (expr.substr(start).match(/^[0-9/a-zA-Z^]+/g)) || [];
127
-
128
- if (expr.substr(start, start + 3).match(/^(sin|cos|tan)/g)) {
129
- token = expr.substr(start, 3)
130
- tokenType = 'function'
131
- } else if (tokenMatch.length > 0) {
132
- token = tokenMatch[0];
133
- tokenType = 'monom';
134
- }
135
- // It's an operation !
136
- else if (expr[start].match(/[+\-*/^]/g)) {
137
- token = expr[start];
138
- tokenType = 'operation';
139
- } else if (expr[start].match(/[&|!]/g)) {
140
- token = expr[start];
141
- tokenType = 'operation';
142
- }
143
- // It's an opening parenthese
144
- else if (expr[start] === '(') {
145
- token = '(';
146
- tokenType = '(';
147
- }
148
- // It's a closing parenthese
149
- else if (expr[start] === ')') {
150
- token = ')';
151
- tokenType = ')';
152
- }
153
- // It's an argument separator for a function
154
- else if (expr[start] === ',') {
155
- token = ',';
156
- tokenType = 'function-argument';
157
- }
158
- // It's a monom.
159
- else {
160
- // TODO: Actually, negative exposant aren't supported.
161
- // token = (expr.substr(start).match(/^[\da-z\^]+/g)[0])||'';
162
- token = tokenMatch[0];
163
- tokenType = 'monom';
164
-
165
- if (token === '') {
166
- token = expr[start];
167
- tokenType = 'monom';
168
- console.log('SHUTING YARD - NEXT TOKEN: error at ', start);
169
- }
170
- }
171
-
172
- // console.log(token, start + token.length, tokenType);
173
169
  return [token, start + token.length, tokenType];
174
170
  }
175
171
 
@@ -241,12 +237,13 @@ export class Shutingyard {
241
237
  }
242
238
 
243
239
  // Get the next token and the corresponding new (ending) position
244
- [token, tokenPos, tokenType] = this.NextToken2(expr, tokenPos);
240
+ [token, tokenPos, tokenType] = this.NextToken(expr, tokenPos);
245
241
 
246
242
  switch (tokenType) {
247
243
  case 'monom':
248
244
  case 'coefficient':
249
245
  case 'variable':
246
+ case 'constant':
250
247
  outQueue.push({
251
248
  token,
252
249
  tokenType
@@ -66,7 +66,7 @@ describe('Monom tests', () => {
66
66
  });
67
67
  })
68
68
 
69
- describe('Monom as numerical expression', () => {
69
+ describe('Monom as numerical expression WIP', () => {
70
70
  it('should create a numerical expression', () => {
71
71
  let M = new Monom()
72
72
 
@@ -46,8 +46,17 @@ describe('Polynom tests', () => {
46
46
  }
47
47
  })
48
48
 
49
- console.log(P.tex)
50
49
  expect(P.length).to.be.equal(3)
51
50
  expect(P.degree().value).to.be.equal(6)
52
51
  });
52
+
53
+ it('should calculate correctly the quotient and reminder', function () {
54
+ let P = new Polynom('(x-3)(x^2+5x-4)+12'),
55
+ D = new Polynom('x-3')
56
+
57
+ let euclidian = P.euclidian(D);
58
+
59
+ expect(euclidian.quotient.tex).to.be.equal('x^{2}+5x-4')
60
+ expect(euclidian.reminder.tex).to.be.equal('12')
61
+ });
53
62
  })
@@ -0,0 +1,14 @@
1
+ import {expect} from 'chai';
2
+ import {NumExp} from "../esm/maths/numexp";
3
+
4
+ describe('Numerical expression', () => { // the tests container
5
+ it('RPN for numerical expression', () => {
6
+ const RPN = new NumExp('3*x+5').rpn
7
+ expect(RPN.map(x => x.token)).to.have.all.members(['3', 'x', '*', '5', '+'])
8
+ })
9
+
10
+ it('Evaluation simple mathematical functions', () => {
11
+ const expr = new NumExp('sqrt(x)')
12
+ expect(expr.evaluate({x: 9})).to.be.equal(3)
13
+ })
14
+ });
@@ -1,5 +1,5 @@
1
1
  import {expect} from 'chai';
2
- import {Shutingyard} from "../src/maths/shutingyard";
2
+ import {Shutingyard, ShutingyardMode} from "../src/maths/shutingyard";
3
3
 
4
4
  describe('Shuting yard', () => { // the tests container
5
5
  it('RPN for polynom', () => {
@@ -28,8 +28,8 @@ describe('Shuting yard', () => { // the tests container
28
28
  })
29
29
 
30
30
  it('Custom RPN', () => {
31
- const SY1: Shutingyard = new Shutingyard('set').parse('(A|B)&C');
32
- const SY2: Shutingyard = new Shutingyard('set').parse('(A-B)&!C');
31
+ const SY1: Shutingyard = new Shutingyard(ShutingyardMode.SET).parse('(A|B)&C');
32
+ const SY2: Shutingyard = new Shutingyard(ShutingyardMode.SET).parse('(A-B)&!C');
33
33
  expect(SY1.rpn.map(x=>x.token)).to.have.all.members(['A', 'B', '|', 'C', '&'])
34
34
  expect(SY2.rpn.map(x=>x.token)).to.have.all.members(['A', 'B', '-', 'C', '!', '&'])
35
35
  })