pimath 0.0.28 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dev/pi.js +864 -487
- package/dev/pi.js.map +1 -1
- package/dist/pi.js +1 -1
- package/dist/pi.js.map +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/algebra.Equation.html +9 -9
- package/docs/classes/algebra.LinearSystem.html +1 -1
- package/docs/classes/algebra.Logicalset.html +2 -2
- package/docs/classes/algebra.Monom.html +42 -40
- package/docs/classes/algebra.Polynom.html +10 -10
- package/docs/classes/algebra.PolynomExpFactor.html +1 -0
- package/docs/classes/algebra.PolynomExpProduct.html +1 -0
- package/docs/classes/algebra.Rational.html +2 -2
- package/docs/classes/coefficients.Fraction.html +4 -4
- package/docs/classes/coefficients.Nthroot.html +1 -1
- package/docs/classes/geometry.Circle.html +2 -2
- package/docs/classes/geometry.Line.html +2 -2
- package/docs/classes/geometry.Point.html +1 -1
- package/docs/classes/geometry.Triangle.html +6 -6
- package/docs/classes/geometry.Vector.html +1 -1
- package/docs/classes/numeric.Numeric.html +5 -5
- package/docs/classes/shutingyard.Shutingyard.html +7 -8
- package/docs/enums/shutingyard.ShutingyardMode.html +1 -0
- package/docs/enums/shutingyard.ShutingyardType.html +1 -0
- package/docs/index.html +1 -1
- package/docs/interfaces/geometry.remarquableLines.html +1 -1
- package/docs/modules/algebra.html +1 -1
- package/docs/modules/coefficients.html +1 -1
- package/docs/modules/geometry.html +1 -1
- package/docs/modules/numeric.html +1 -1
- package/docs/modules/random.Random.html +1 -1
- package/docs/modules/random.html +1 -1
- package/docs/modules/shutingyard.html +1 -1
- package/docs/modules.html +1 -1
- package/esm/main.js +3 -1
- package/esm/main.js.map +1 -1
- package/esm/maths/algebra/equation.js +1 -1
- package/esm/maths/algebra/equation.js.map +1 -1
- package/esm/maths/algebra/index.d.ts +1 -0
- package/esm/maths/algebra/index.js +1 -0
- package/esm/maths/algebra/index.js.map +1 -1
- package/esm/maths/algebra/monom.d.ts +4 -1
- package/esm/maths/algebra/monom.js +52 -37
- package/esm/maths/algebra/monom.js.map +1 -1
- package/esm/maths/algebra/polynom.d.ts +19 -15
- package/esm/maths/algebra/polynom.js +242 -174
- package/esm/maths/algebra/polynom.js.map +1 -1
- package/esm/maths/coefficients/fraction.d.ts +3 -0
- package/esm/maths/coefficients/fraction.js +21 -8
- package/esm/maths/coefficients/fraction.js.map +1 -1
- package/esm/maths/{numexp.d.ts → expressions/numexp.d.ts} +3 -0
- package/esm/maths/{numexp.js → expressions/numexp.js} +46 -15
- package/esm/maths/expressions/numexp.js.map +1 -0
- package/esm/maths/expressions/polynomexp.bkp.d.ts +33 -0
- package/esm/maths/expressions/polynomexp.bkp.js +186 -0
- package/esm/maths/expressions/polynomexp.bkp.js.map +1 -0
- package/esm/maths/expressions/polynomexp.d.ts +52 -0
- package/esm/maths/expressions/polynomexp.js +233 -0
- package/esm/maths/expressions/polynomexp.js.map +1 -0
- package/esm/maths/geometry/line.d.ts +4 -2
- package/esm/maths/geometry/line.js +6 -2
- package/esm/maths/geometry/line.js.map +1 -1
- package/esm/maths/geometry/vector.js +7 -2
- package/esm/maths/geometry/vector.js.map +1 -1
- package/esm/maths/shutingyard.d.ts +7 -7
- package/esm/maths/shutingyard.js +5 -7
- package/esm/maths/shutingyard.js.map +1 -1
- package/package.json +1 -1
- package/{dev → public}/demo.css +0 -0
- package/{dev → public}/index.html +48 -14
- package/{dev → public}/playground.html +1 -1
- package/src/main.ts +13 -2
- package/src/maths/algebra/equation.ts +1 -1
- package/src/maths/algebra/index.ts +2 -1
- package/src/maths/algebra/monom.ts +71 -49
- package/src/maths/algebra/polynom.ts +432 -309
- package/src/maths/coefficients/fraction.ts +28 -11
- package/src/maths/{numexp.ts → expressions/numexp.ts} +42 -20
- package/src/maths/expressions/polynomexp.bkp.ts +223 -0
- package/src/maths/expressions/polynomexp.ts +309 -0
- package/src/maths/geometry/line.ts +7 -2
- package/src/maths/geometry/vector.ts +10 -2
- package/src/maths/shutingyard.ts +15 -64
- package/tests/algebra/monom.test.ts +12 -8
- package/tests/algebra/polynom.test.ts +28 -2
- package/tests/numexp.test.ts +34 -0
- package/tests/polynomexp.test.ts +15 -0
- package/tests/shutingyard.test.ts +4 -4
- package/tsconfig.json +0 -1
- package/esm/docs.d.ts +0 -6
- package/esm/docs.js +0 -7
- package/esm/docs.js.map +0 -1
- package/esm/maths/numexp.js.map +0 -1
- package/esm/maths/random/random.d.ts +0 -13
- package/esm/maths/random/random.js +0 -27
- package/esm/maths/random/random.js.map +0 -1
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import {Polynom, PolynomParsingType} from "../algebra";
|
|
2
|
+
import {Fraction, FractionParsingType} from "../coefficients";
|
|
3
|
+
|
|
4
|
+
type PolynomExpMathFunctionType = { name: string; fn: Function, tex: string }
|
|
5
|
+
|
|
6
|
+
export class PolynomExpFactor {
|
|
7
|
+
constructor(polynom: PolynomParsingType, degree?: FractionParsingType, mathFunction?: PolynomExpMathFunctionType) {
|
|
8
|
+
this._polynom = new Polynom(polynom)
|
|
9
|
+
this._degree = new Fraction(degree === undefined ? 1 : degree)
|
|
10
|
+
this._fn = mathFunction
|
|
11
|
+
this._powerAsInteger = true
|
|
12
|
+
this._forceParenthesis = true
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private _forceParenthesis: boolean
|
|
16
|
+
|
|
17
|
+
get forceParenthesis(): boolean {
|
|
18
|
+
return this._forceParenthesis;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
set forceParenthesis(value: boolean) {
|
|
22
|
+
this._forceParenthesis = value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private _fn: PolynomExpMathFunctionType
|
|
26
|
+
|
|
27
|
+
get fn(): PolynomExpMathFunctionType {
|
|
28
|
+
return this._fn;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
set fn(value: PolynomExpMathFunctionType) {
|
|
32
|
+
this._fn = value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private _powerAsInteger: boolean
|
|
36
|
+
|
|
37
|
+
get powerAsInteger(): boolean {
|
|
38
|
+
return this._powerAsInteger;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
set powerAsInteger(value: boolean) {
|
|
42
|
+
this._powerAsInteger = value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private _polynom: Polynom
|
|
46
|
+
|
|
47
|
+
get polynom(): Polynom {
|
|
48
|
+
return this._polynom;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
set polynom(value: Polynom) {
|
|
52
|
+
this._polynom = value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private _degree: Fraction
|
|
56
|
+
|
|
57
|
+
get degree(): Fraction {
|
|
58
|
+
return this._degree;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
set degree(value: Fraction) {
|
|
62
|
+
this._degree = value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get tex(): string {
|
|
66
|
+
let tex
|
|
67
|
+
|
|
68
|
+
if (this._degree.isOne() && (this._fn !== undefined || !this._forceParenthesis)) {
|
|
69
|
+
// If degree is one, no need to add the parenthesis.
|
|
70
|
+
tex = this._polynom.tex
|
|
71
|
+
} else {
|
|
72
|
+
// the degree is not one, add the parenthesis.
|
|
73
|
+
if (this._powerAsInteger && !this._degree.isRelative()) {
|
|
74
|
+
// the degree is a fraction and we want natural powers => use sqrt.
|
|
75
|
+
tex = `\\sqrt${this._degree.denominator !== 2 ? `[ ${this._degree.denominator} ]` : ''}{ ${this._polynom.tex} }^{ ${this._degree.numerator} }`
|
|
76
|
+
} else if (this.isCoefficient && this.firstCoefficient.isNatural()) {
|
|
77
|
+
// the value is a natural number (eg 3, 7, ...)
|
|
78
|
+
tex = this._polynom.tex + this._texDegree
|
|
79
|
+
} else {
|
|
80
|
+
// In any other case, add the parenthesis by default
|
|
81
|
+
tex = `\\left( ${this._polynom.tex} \\right)${this._texDegree}`
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this._fn !== undefined && this._fn.tex !== undefined) {
|
|
86
|
+
tex = `${this._fn.tex}\\left( ${tex} \\right)`
|
|
87
|
+
}
|
|
88
|
+
return tex
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get isCoefficient(): boolean {
|
|
92
|
+
// TODO: Maybe reduce the coefficient if it isn't of degree one.
|
|
93
|
+
return this._polynom.degree().isZero();
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get firstCoefficient(): Fraction {
|
|
98
|
+
return this._polynom.monomByDegree().coefficient
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private get _texDegree(): string {
|
|
102
|
+
if (this._degree.isOne()) {
|
|
103
|
+
return ''
|
|
104
|
+
} else {
|
|
105
|
+
return `^{ ${this._degree.tfrac} }`
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
setForceParenthesis(value?: boolean): PolynomExpFactor {
|
|
110
|
+
this._forceParenthesis = value === undefined || value
|
|
111
|
+
return this
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
derivative(letter?: string): PolynomExpProduct {
|
|
115
|
+
if (this._degree.isOne()) {
|
|
116
|
+
return new PolynomExpProduct(
|
|
117
|
+
new PolynomExpFactor(this._polynom.clone().derivative(letter))
|
|
118
|
+
)
|
|
119
|
+
} else {
|
|
120
|
+
return new PolynomExpProduct(
|
|
121
|
+
new PolynomExpFactor(this._degree.clone()),
|
|
122
|
+
new PolynomExpFactor(this._polynom.clone().derivative(letter)),
|
|
123
|
+
new PolynomExpFactor(this._polynom.clone(), this._degree.clone().subtract(1))
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class PolynomExpProduct {
|
|
130
|
+
constructor(...values: PolynomExpFactor[]) {
|
|
131
|
+
this._factors = values || []
|
|
132
|
+
this._positive = true
|
|
133
|
+
this._asPositiveDegree = true
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private _fn: PolynomExpMathFunctionType
|
|
137
|
+
|
|
138
|
+
get fn(): PolynomExpMathFunctionType {
|
|
139
|
+
return this._fn;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
set fn(value: PolynomExpMathFunctionType) {
|
|
143
|
+
this._fn = value;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private _factors: PolynomExpFactor[]
|
|
147
|
+
|
|
148
|
+
get factors(): PolynomExpFactor[] {
|
|
149
|
+
return this._factors;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
set factors(value: PolynomExpFactor[]) {
|
|
153
|
+
this._factors = value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private _positive: boolean
|
|
157
|
+
|
|
158
|
+
get positive(): boolean {
|
|
159
|
+
return this._positive;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
set positive(value: boolean) {
|
|
163
|
+
this._positive = value;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private _asPositiveDegree: boolean
|
|
167
|
+
|
|
168
|
+
get asPositiveDegree(): boolean {
|
|
169
|
+
return this._asPositiveDegree;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
set asPositiveDegree(value: boolean) {
|
|
173
|
+
this._asPositiveDegree = value;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get tex(): string {
|
|
177
|
+
let parenthesis = this._factors.length>1
|
|
178
|
+
// Default value
|
|
179
|
+
let tex = this._factors.map(factor => factor.setForceParenthesis(parenthesis).tex).join(' \\cdot ')
|
|
180
|
+
|
|
181
|
+
// Change the value in some cases...
|
|
182
|
+
if (this._asPositiveDegree) {
|
|
183
|
+
const numerators = this._factors.filter(x => x.degree.isPositive()),
|
|
184
|
+
denominators = this._factors.filter(x => x.degree.isNegative())
|
|
185
|
+
|
|
186
|
+
let numeratorsAsTex, denominatorsAsTex
|
|
187
|
+
|
|
188
|
+
if (denominators.length > 0) {
|
|
189
|
+
if (numerators.length === 0) {
|
|
190
|
+
numeratorsAsTex = [1]
|
|
191
|
+
} else if (numerators.length === 1) {
|
|
192
|
+
numeratorsAsTex = [numerators[0].setForceParenthesis(false).tex]
|
|
193
|
+
} else {
|
|
194
|
+
parenthesis = numerators.length>1
|
|
195
|
+
numeratorsAsTex = numerators.map(factor => factor.setForceParenthesis(parenthesis).tex)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Change all denominators degrees to positive.
|
|
199
|
+
denominators.map(x => x.degree.opposed())
|
|
200
|
+
if (denominators.length === 1) {
|
|
201
|
+
denominatorsAsTex = [denominators[0].setForceParenthesis(false).tex]
|
|
202
|
+
} else {
|
|
203
|
+
parenthesis = denominators.length>1
|
|
204
|
+
denominatorsAsTex = denominators.map(factor => factor.setForceParenthesis(parenthesis).tex)
|
|
205
|
+
}
|
|
206
|
+
// restore all degrees to negative again.
|
|
207
|
+
denominators.map(x => x.degree.opposed())
|
|
208
|
+
|
|
209
|
+
tex = `\\dfrac{ ${numeratorsAsTex.join(' \\cdot ')} }{ ${denominatorsAsTex.join(' \\cdot ')} }`
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Apply the modification
|
|
214
|
+
if (this._fn !== undefined && this._fn.name !== undefined && this._fn.name !== '') {
|
|
215
|
+
tex = `${this._fn.tex}\\left( ${tex} \\right)`
|
|
216
|
+
}
|
|
217
|
+
return tex
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
reduce(): PolynomExpProduct {
|
|
221
|
+
let coefficients = this._factors.filter(factor => factor.isCoefficient),
|
|
222
|
+
polynoms = this._factors.filter(factor => !factor.isCoefficient)
|
|
223
|
+
|
|
224
|
+
let result = new Fraction().one()
|
|
225
|
+
|
|
226
|
+
if (coefficients.length > 1) {
|
|
227
|
+
for (const factor of coefficients) {
|
|
228
|
+
if (factor.degree.isPositive()) {
|
|
229
|
+
result.multiply(factor.polynom.monoms[0].coefficient.pow(factor.degree))
|
|
230
|
+
} else {
|
|
231
|
+
result.divide(factor.polynom.monoms[0].coefficient.pow(factor.degree.clone().abs()))
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
} else if (coefficients.length === 1) {
|
|
235
|
+
result = coefficients[0].polynom.monoms[0].coefficient
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (result.isOne()) {
|
|
239
|
+
this._factors = [...polynoms]
|
|
240
|
+
} else if (!result.isRelative()) {
|
|
241
|
+
this._factors = [
|
|
242
|
+
new PolynomExpFactor(result.numerator),
|
|
243
|
+
new PolynomExpFactor(result.denominator, -1),
|
|
244
|
+
...polynoms
|
|
245
|
+
]
|
|
246
|
+
} else {
|
|
247
|
+
this._factors = [
|
|
248
|
+
new PolynomExpFactor(result),
|
|
249
|
+
...polynoms
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
return this
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
integrate(letter?: string): PolynomExpProduct {
|
|
256
|
+
// Handle this kind of case:
|
|
257
|
+
// A * f' * F^n
|
|
258
|
+
// A * f' / F^n, n != 1
|
|
259
|
+
// A * f_1 * f_2 * f_3, where (f_1 * f_2)' = f_3
|
|
260
|
+
if (this._factors.length === 2) {
|
|
261
|
+
// Check polynoms degree: one must of one degree less than the other.
|
|
262
|
+
let d1 = this._factors[0].polynom.degree(letter).value,
|
|
263
|
+
d2 = this._factors[1].polynom.degree(letter).value
|
|
264
|
+
|
|
265
|
+
if (d1 === d2 + 1) {
|
|
266
|
+
return this._integrateWithInternalDerivative(this._factors[0], this._factors[1], letter)
|
|
267
|
+
} else if (d1 + 1 === d2) {
|
|
268
|
+
return this._integrateWithInternalDerivative(this._factors[1], this._factors[0], letter)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public applyMathFunction(mathFn: PolynomExpMathFunctionType): PolynomExpProduct {
|
|
275
|
+
this._fn = mathFn
|
|
276
|
+
return this
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private _integrateWithInternalDerivative(P: PolynomExpFactor, Pinternal: PolynomExpFactor, letter?: string): PolynomExpProduct {
|
|
280
|
+
// Get the internal derivative
|
|
281
|
+
let internalDerivative: Polynom = P.polynom.clone().derivative(letter)
|
|
282
|
+
|
|
283
|
+
// Get the factor.
|
|
284
|
+
let {quotient, reminder} = Pinternal.polynom.clone().euclidian(internalDerivative)
|
|
285
|
+
|
|
286
|
+
if (reminder.isZero() && quotient.degree(letter).isZero()) {
|
|
287
|
+
// All the conditions are done. Actual situation is
|
|
288
|
+
// (4x-10)(x^2-5x+7)^9
|
|
289
|
+
// P1 = (x^2-5x+7), P2 = (2x-5)
|
|
290
|
+
// => 1/10 * quotient * (x^2-5x+7)^10
|
|
291
|
+
|
|
292
|
+
if (P.degree.isEqual(-1)) {
|
|
293
|
+
return (new PolynomExpProduct(
|
|
294
|
+
new PolynomExpFactor(quotient, 1),
|
|
295
|
+
new PolynomExpFactor(P.polynom.clone(), 1, {
|
|
296
|
+
name: 'ln', tex: '\\ln', fn: (x: number) => Math.log(x)
|
|
297
|
+
})
|
|
298
|
+
))
|
|
299
|
+
} else {
|
|
300
|
+
return new PolynomExpProduct(
|
|
301
|
+
new PolynomExpFactor(P.degree.clone().add(1).invert(), 1),
|
|
302
|
+
new PolynomExpFactor(quotient, 1),
|
|
303
|
+
new PolynomExpFactor(P.polynom.clone(), P.degree.clone().add(1))
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -10,8 +10,9 @@ import {Numeric} from "../numeric";
|
|
|
10
10
|
|
|
11
11
|
enum LinePropriety {
|
|
12
12
|
None,
|
|
13
|
-
Parallel,
|
|
14
|
-
Perpendicular
|
|
13
|
+
Parallel='parallel',
|
|
14
|
+
Perpendicular = 'perpendicular',
|
|
15
|
+
Tangent = 'tangent'
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export class Line {
|
|
@@ -312,6 +313,9 @@ export class Line {
|
|
|
312
313
|
isSameAs = (line: Line): Boolean => {
|
|
313
314
|
return this.slope.isEqual(line.slope) && this.height.isEqual(line.height);
|
|
314
315
|
}
|
|
316
|
+
isVertical = (): Boolean => {
|
|
317
|
+
return this.slope.isInfinity()
|
|
318
|
+
}
|
|
315
319
|
simplify = (): Line => {
|
|
316
320
|
let lcm = Numeric.lcm(this._a.denominator, this._b.denominator, this._c.denominator),
|
|
317
321
|
gcd = Numeric.gcd(this._a.numerator, this._b.numerator, this._c.numerator);
|
|
@@ -429,6 +433,7 @@ export class Line {
|
|
|
429
433
|
}
|
|
430
434
|
|
|
431
435
|
getValueAtX = (value: Fraction|number): Fraction => {
|
|
436
|
+
|
|
432
437
|
const equ = this.equation.clone().isolate('y'),
|
|
433
438
|
F = new Fraction(value)
|
|
434
439
|
|
|
@@ -81,12 +81,20 @@ export class Vector {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Fractions or a number are give
|
|
84
|
-
if (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]
|
|
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;
|
package/src/maths/shutingyard.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {loadHighlighter} from "typedoc/dist/lib/utils/highlighter";
|
|
2
2
|
import exp = require("constants");
|
|
3
3
|
|
|
4
|
-
type tokenType = {
|
|
4
|
+
export type tokenType = {
|
|
5
5
|
[key: string]: {
|
|
6
6
|
precedence: number,
|
|
7
7
|
associative: string,
|
|
@@ -13,6 +13,7 @@ export const tokenConstant:{[Key:string]:number} = {
|
|
|
13
13
|
pi: Math.PI,
|
|
14
14
|
e: Math.exp(1)
|
|
15
15
|
}
|
|
16
|
+
|
|
16
17
|
export enum ShutingyardType {
|
|
17
18
|
VARIABLE='variable',
|
|
18
19
|
COEFFICIENT='coefficient',
|
|
@@ -21,14 +22,17 @@ export enum ShutingyardType {
|
|
|
21
22
|
FUNCTION = 'function',
|
|
22
23
|
MONOM = 'monom'
|
|
23
24
|
}
|
|
25
|
+
|
|
24
26
|
export enum ShutingyardMode {
|
|
25
27
|
POLYNOM= 'polynom',
|
|
26
28
|
SET = 'set',
|
|
27
29
|
NUMERIC = 'numeric'
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
export type Token = { token: string, tokenType: string }
|
|
33
|
+
|
|
30
34
|
export class Shutingyard {
|
|
31
|
-
private _rpn:
|
|
35
|
+
private _rpn: Token[] = [];
|
|
32
36
|
readonly _mode: ShutingyardMode;
|
|
33
37
|
private _tokenConfig: tokenType;
|
|
34
38
|
private _tokenConstant: {[Key:string]: number}
|
|
@@ -77,7 +81,9 @@ export class Shutingyard {
|
|
|
77
81
|
'sin': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
78
82
|
'cos': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
79
83
|
'tan': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
84
|
+
'sqrt': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
80
85
|
}
|
|
86
|
+
this._uniformize = false
|
|
81
87
|
} else {
|
|
82
88
|
this._tokenConfig = {
|
|
83
89
|
'^': {precedence: 4, associative: 'right', type: ShutingyardType.OPERATION},
|
|
@@ -85,10 +91,10 @@ export class Shutingyard {
|
|
|
85
91
|
'/': {precedence: 3, associative: 'left', type: ShutingyardType.OPERATION},
|
|
86
92
|
'+': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION},
|
|
87
93
|
'-': {precedence: 2, associative: 'left', type: ShutingyardType.OPERATION},
|
|
88
|
-
'%': {precedence: 3, associative: 'right', type: ShutingyardType.OPERATION},
|
|
89
|
-
'sin': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
90
|
-
'cos': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
91
|
-
'tan': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
94
|
+
// '%': {precedence: 3, associative: 'right', type: ShutingyardType.OPERATION},
|
|
95
|
+
// 'sin': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
96
|
+
// 'cos': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
97
|
+
// 'tan': {precedence: 4, associative: 'right', type: ShutingyardType.FUNCTION},
|
|
92
98
|
}
|
|
93
99
|
this._uniformize = true
|
|
94
100
|
}
|
|
@@ -102,7 +108,7 @@ export class Shutingyard {
|
|
|
102
108
|
* @param expr (string) Expression to analyse
|
|
103
109
|
* @param start (number) CUrrent position in the expr string.
|
|
104
110
|
*/
|
|
105
|
-
|
|
111
|
+
NextToken(expr: string, start: number): [string, number, string] {
|
|
106
112
|
let token: string, tokenType: string;
|
|
107
113
|
token = '';
|
|
108
114
|
tokenType = '';
|
|
@@ -146,7 +152,7 @@ export class Shutingyard {
|
|
|
146
152
|
if(token===''){
|
|
147
153
|
// No function found ! Might be a coefficient !
|
|
148
154
|
if( expr[start].match(/[0-9]/) ) {
|
|
149
|
-
if(this._mode === ShutingyardMode.POLYNOM) {
|
|
155
|
+
if(this._mode === ShutingyardMode.POLYNOM && false) {
|
|
150
156
|
token = expr.substring(start).match(/^([0-9.,/]+)/)[0]
|
|
151
157
|
}else{
|
|
152
158
|
token = expr.substring(start).match(/^([0-9.,]+)/)[0]
|
|
@@ -167,61 +173,6 @@ export class Shutingyard {
|
|
|
167
173
|
return [token, start + token.length, tokenType];
|
|
168
174
|
}
|
|
169
175
|
|
|
170
|
-
// NextToken(expr: string, start: number): [string, number, string] {
|
|
171
|
-
// let tokenMatch: string[], token: string, tokenType: string;
|
|
172
|
-
//
|
|
173
|
-
// this.NextToken2(expr, start)
|
|
174
|
-
// // Detect a fraction monoms or return empty array
|
|
175
|
-
// tokenMatch = (expr.substring(start).match(/^[0-9/a-zA-Z^]+/g)) || [];
|
|
176
|
-
//
|
|
177
|
-
// if (expr.substring(start, start + 3).match(/^(sin|cos|tan)/g)) {
|
|
178
|
-
// token = expr.substring(start, start+3)
|
|
179
|
-
// tokenType = 'function'
|
|
180
|
-
// } else if (tokenMatch.length > 0) {
|
|
181
|
-
// token = tokenMatch[0];
|
|
182
|
-
// tokenType = 'monom';
|
|
183
|
-
// }
|
|
184
|
-
// // It's an operation !
|
|
185
|
-
// else if (expr[start].match(/[+\-*/^]/g)) {
|
|
186
|
-
// token = expr[start];
|
|
187
|
-
// tokenType = 'operation';
|
|
188
|
-
// } else if (expr[start].match(/[&|!]/g)) {
|
|
189
|
-
// token = expr[start];
|
|
190
|
-
// tokenType = 'operation';
|
|
191
|
-
// }
|
|
192
|
-
// // It's an opening parenthese
|
|
193
|
-
// else if (expr[start] === '(') {
|
|
194
|
-
// token = '(';
|
|
195
|
-
// tokenType = '(';
|
|
196
|
-
// }
|
|
197
|
-
// // It's a closing parenthese
|
|
198
|
-
// else if (expr[start] === ')') {
|
|
199
|
-
// token = ')';
|
|
200
|
-
// tokenType = ')';
|
|
201
|
-
// }
|
|
202
|
-
// // It's an argument separator for a function
|
|
203
|
-
// else if (expr[start] === ',') {
|
|
204
|
-
// token = ',';
|
|
205
|
-
// tokenType = 'function-argument';
|
|
206
|
-
// }
|
|
207
|
-
// // It's a monom.
|
|
208
|
-
// else {
|
|
209
|
-
// // TODO: Actually, negative exposant aren't supported.
|
|
210
|
-
// // token = (expr.substring(start).match(/^[\da-z\^]+/g)[0])||'';
|
|
211
|
-
// token = tokenMatch[0];
|
|
212
|
-
// tokenType = 'monom';
|
|
213
|
-
//
|
|
214
|
-
// if (token === '') {
|
|
215
|
-
// token = expr[start];
|
|
216
|
-
// tokenType = 'monom';
|
|
217
|
-
// console.log('SHUTING YARD - NEXT TOKEN: error at ', start);
|
|
218
|
-
// }
|
|
219
|
-
// }
|
|
220
|
-
//
|
|
221
|
-
// // console.log(token, start + token.length, tokenType);
|
|
222
|
-
// return [token, start + token.length, tokenType];
|
|
223
|
-
// }
|
|
224
|
-
|
|
225
176
|
/**
|
|
226
177
|
* Sanitize an expression by adding missing common operation (multiplication between parentheseses)
|
|
227
178
|
* @param expr
|
|
@@ -290,7 +241,7 @@ export class Shutingyard {
|
|
|
290
241
|
}
|
|
291
242
|
|
|
292
243
|
// Get the next token and the corresponding new (ending) position
|
|
293
|
-
[token, tokenPos, tokenType] = this.
|
|
244
|
+
[token, tokenPos, tokenType] = this.NextToken(expr, tokenPos);
|
|
294
245
|
|
|
295
246
|
switch (tokenType) {
|
|
296
247
|
case 'monom':
|
|
@@ -3,8 +3,10 @@ import {Monom} from "../../src/maths/algebra";
|
|
|
3
3
|
import {Random} from "../../src/maths/random";
|
|
4
4
|
import {describe} from "mocha";
|
|
5
5
|
import {Fraction} from "../../src/maths/coefficients";
|
|
6
|
+
import {Shutingyard} from "../../src/maths/shutingyard";
|
|
7
|
+
import {log} from "util";
|
|
6
8
|
|
|
7
|
-
describe('Monom
|
|
9
|
+
describe('Monom with integer power', () => {
|
|
8
10
|
it('parsing', () => {
|
|
9
11
|
const M0a = new Monom('3');
|
|
10
12
|
expect(M0a.tex).to.be.equal('3')
|
|
@@ -25,10 +27,10 @@ describe('Monom tests', () => {
|
|
|
25
27
|
expect(M3.tex).to.be.equal('-3x^{-2}')
|
|
26
28
|
|
|
27
29
|
const M4 = new Monom('3x^(2/3)')
|
|
28
|
-
expect(M4.tex).to.be.equal('3x^{2
|
|
30
|
+
expect(M4.tex).to.be.equal('3x^{\\tfrac{ 2 }{ 3 }}')
|
|
29
31
|
|
|
30
32
|
const M5 = new Monom('-3x^(-2/3)y^(-5)8x^3')
|
|
31
|
-
expect(M5.tex).to.be.equal('-24x^{7
|
|
33
|
+
expect(M5.tex).to.be.equal('-24x^{\\tfrac{ 7 }{ 3 }}y^{-5}')
|
|
32
34
|
})
|
|
33
35
|
|
|
34
36
|
it('basic operations', () => {
|
|
@@ -66,15 +68,17 @@ describe('Monom tests', () => {
|
|
|
66
68
|
});
|
|
67
69
|
})
|
|
68
70
|
|
|
69
|
-
describe('Monom
|
|
71
|
+
describe('Monom with fraction power', () => {
|
|
70
72
|
it('should create a numerical expression', () => {
|
|
71
|
-
|
|
73
|
+
const inputStr: string = '-1/5x^(2/3)'
|
|
74
|
+
const M = new Monom(inputStr),
|
|
75
|
+
N = new Monom('7x^(4/5)')
|
|
72
76
|
|
|
73
|
-
M.
|
|
74
|
-
M.setLetter('3', new Fraction(0.5).reduce())
|
|
77
|
+
M.multiply(N.clone())
|
|
75
78
|
|
|
76
79
|
console.log(M.tex)
|
|
80
|
+
|
|
77
81
|
// TODO: Problem while displaying numerical expression
|
|
78
|
-
|
|
82
|
+
expect(M.tex).to.be.equal('-\\dfrac{ 7 }{ 5 }x^{\\tfrac{ 22 }{ 15 }}')
|
|
79
83
|
})
|
|
80
84
|
})
|
|
@@ -3,6 +3,7 @@ import {Fraction} from "../../src/maths/coefficients";
|
|
|
3
3
|
import {Monom, Polynom} from "../../src/maths/algebra";
|
|
4
4
|
import {Random} from "../../src/maths/random";
|
|
5
5
|
import {describe} from "mocha";
|
|
6
|
+
import {Shutingyard} from "../../src/maths/shutingyard";
|
|
6
7
|
|
|
7
8
|
describe('Polynom tests', () => {
|
|
8
9
|
it('Parse polynom', () => {
|
|
@@ -11,6 +12,13 @@ describe('Polynom tests', () => {
|
|
|
11
12
|
expect(options.tex).to.be.equal('2x^{4}+10x^{3}+6x^{2}-18x');
|
|
12
13
|
});
|
|
13
14
|
|
|
15
|
+
it('Parse polynom with coefficient as fraction', ()=>{
|
|
16
|
+
const P = new Polynom('-3/5x-2')
|
|
17
|
+
|
|
18
|
+
console.log(P.tex)
|
|
19
|
+
expect(P.tex).to.be.equal('-\\dfrac{ 3 }{ 5 }x-2')
|
|
20
|
+
})
|
|
21
|
+
|
|
14
22
|
it('Tex display', () => {
|
|
15
23
|
const options = new Polynom('x^2-2x+1');
|
|
16
24
|
expect(options.tex).to.be.equal('x^{2}-2x+1');
|
|
@@ -36,7 +44,7 @@ describe('Polynom tests', () => {
|
|
|
36
44
|
expect(F.integrate(0, 2).value).to.be.equal(-4)
|
|
37
45
|
expect(G.integrate(-3, 3).display).to.be.equal('174/5')
|
|
38
46
|
})
|
|
39
|
-
it('Random Polynom of degree 5',
|
|
47
|
+
it('Random Polynom of degree 5', () => {
|
|
40
48
|
let P = Random.polynom({
|
|
41
49
|
degree: 6,
|
|
42
50
|
numberOfMonoms: 3,
|
|
@@ -50,7 +58,7 @@ describe('Polynom tests', () => {
|
|
|
50
58
|
expect(P.degree().value).to.be.equal(6)
|
|
51
59
|
});
|
|
52
60
|
|
|
53
|
-
it('should calculate correctly the quotient and reminder',
|
|
61
|
+
it('should calculate correctly the quotient and reminder', () => {
|
|
54
62
|
let P = new Polynom('(x-3)(x^2+5x-4)+12'),
|
|
55
63
|
D = new Polynom('x-3')
|
|
56
64
|
|
|
@@ -60,3 +68,21 @@ describe('Polynom tests', () => {
|
|
|
60
68
|
expect(euclidian.reminder.tex).to.be.equal('12')
|
|
61
69
|
});
|
|
62
70
|
})
|
|
71
|
+
|
|
72
|
+
describe('Polynom parsing with rational power', ()=>{
|
|
73
|
+
it('should parse with rational powers', ()=> {
|
|
74
|
+
const P = new Polynom('3x^(2/3)-5x+5/3');
|
|
75
|
+
|
|
76
|
+
expect(P.tex).to.be.equal('3x^{\\tfrac{ 2 }{ 3 }}-5x+\\dfrac{ 5 }{ 3 }')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// TODO: working with roots !
|
|
82
|
+
// describe('WIP : working with roots', ()=>{
|
|
83
|
+
// it('should parse with roots coefficient', ()=>{
|
|
84
|
+
// let P = new Polynom('sqrt(x)-5')
|
|
85
|
+
//
|
|
86
|
+
// expect(P.degree().value).to.be.equal(0.5)
|
|
87
|
+
// })
|
|
88
|
+
// })
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {NumExp} from "../src/maths/expressions/numexp";
|
|
3
|
+
import exp = require("constants");
|
|
4
|
+
|
|
5
|
+
describe('Numerical expression', () => { // the tests container
|
|
6
|
+
it('RPN for numerical expression', () => {
|
|
7
|
+
const RPN = new NumExp('3*x+5').rpn
|
|
8
|
+
expect(RPN.map(x => x.token)).to.have.all.members(['3', 'x', '*', '5', '+'])
|
|
9
|
+
|
|
10
|
+
const RPN2 = new NumExp('-3*x^2-5').rpn
|
|
11
|
+
expect(RPN2.map(x=>x.token)).to.have.all.members(['3', 'x', '2', '^', '*', '-', '5', '-'])
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Evaluate for numerical expression', () => {
|
|
15
|
+
const expr = new NumExp('3*x+5')
|
|
16
|
+
expect(expr.evaluate({x: 5})).to.be.equal(20)
|
|
17
|
+
|
|
18
|
+
const expr2 = new NumExp('-3*x^2-5')
|
|
19
|
+
expect(expr2.evaluate({x: -2})).to.be.equal(-17)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('Evaluation simple mathematical functions', () => {
|
|
23
|
+
const expr = new NumExp('sqrt(x)')
|
|
24
|
+
expect(expr.evaluate({x: 9})).to.be.equal(3)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should detect invalid rpn parsing', function () {
|
|
28
|
+
const exprValid = new NumExp('3*sin(x)'),
|
|
29
|
+
exprInvalid = new NumExp('3*sin')
|
|
30
|
+
|
|
31
|
+
expect(exprValid.isValid).to.be.true
|
|
32
|
+
expect(exprInvalid.isValid).to.be.false
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {describe} from "mocha";
|
|
2
|
+
import {PolynomExpFactor, PolynomExpProduct} from "../src/maths/expressions/polynomexp";
|
|
3
|
+
|
|
4
|
+
describe('PolynomExpression concepts', () => {
|
|
5
|
+
it('should display tex', function () {
|
|
6
|
+
const F1 = new PolynomExpFactor('2x-5', 2.5),
|
|
7
|
+
F2 = new PolynomExpFactor('2-x', 0.5),
|
|
8
|
+
PP = new PolynomExpProduct(F1, F2)
|
|
9
|
+
|
|
10
|
+
const D = F1.derivative()
|
|
11
|
+
|
|
12
|
+
console.log(D.tex)
|
|
13
|
+
console.log(D.reduce().tex)
|
|
14
|
+
});
|
|
15
|
+
})
|