pimath 0.1.39 → 0.1.40

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 (65) hide show
  1. package/dist/pimath.js +188 -159
  2. package/dist/pimath.js.map +1 -1
  3. package/package.json +4 -2
  4. package/src/algebra/equation.ts +556 -0
  5. package/src/algebra/equationSolver.ts +539 -0
  6. package/src/algebra/factor.ts +339 -0
  7. package/src/algebra/index.ts +11 -0
  8. package/src/algebra/linearSystem.ts +388 -0
  9. package/src/algebra/logicalset.ts +256 -0
  10. package/src/algebra/matrix.ts +474 -0
  11. package/src/algebra/monom.ts +1015 -0
  12. package/src/algebra/operations.ts +24 -0
  13. package/src/algebra/polyFactor.ts +668 -0
  14. package/src/algebra/polynom.ts +1394 -0
  15. package/src/analyze/solution.ts +115 -0
  16. package/src/analyze/tableOfSigns.ts +30 -0
  17. package/src/coefficients/fraction.ts +678 -0
  18. package/src/coefficients/index.ts +4 -0
  19. package/src/coefficients/nthRoot.ts +149 -0
  20. package/src/coefficients/root.ts +299 -0
  21. package/src/geometry/circle.ts +386 -0
  22. package/src/geometry/geomMath.ts +70 -0
  23. package/src/geometry/index.ts +10 -0
  24. package/src/geometry/line.ts +677 -0
  25. package/src/geometry/line3.ts +206 -0
  26. package/src/geometry/plane3.ts +170 -0
  27. package/src/geometry/point.ts +66 -0
  28. package/src/geometry/sphere3.ts +214 -0
  29. package/src/geometry/triangle.ts +354 -0
  30. package/src/geometry/vector.ts +341 -0
  31. package/src/helpers.ts +35 -0
  32. package/src/index.ts +60 -0
  33. package/src/numeric.ts +199 -0
  34. package/src/pimath.interface.ts +160 -0
  35. package/src/randomization/algebra/rndEquation.ts +41 -0
  36. package/src/randomization/algebra/rndMonom.ts +39 -0
  37. package/src/randomization/algebra/rndPolynom.ts +86 -0
  38. package/src/randomization/coefficient/rndFraction.ts +38 -0
  39. package/src/randomization/geometry/rndCircle.ts +27 -0
  40. package/src/randomization/geometry/rndLine.ts +37 -0
  41. package/src/randomization/geometry/rndLine3.ts +27 -0
  42. package/src/randomization/geometry/rndVector.ts +63 -0
  43. package/src/randomization/random.ts +91 -0
  44. package/src/randomization/rndHelpers.ts +102 -0
  45. package/src/randomization/rndTypes.ts +63 -0
  46. package/types/algebra/equationSolver.d.ts +3 -0
  47. package/types/algebra/equationSolver.d.ts.map +1 -1
  48. package/types/algebra/polyFactor.d.ts +5 -0
  49. package/types/algebra/polyFactor.d.ts.map +1 -1
  50. package/types/analyze/solution.d.ts +21 -0
  51. package/types/analyze/solution.d.ts.map +1 -0
  52. package/types/analyze/tableOfSigns.d.ts +9 -0
  53. package/types/analyze/tableOfSigns.d.ts.map +1 -0
  54. package/types/coefficients/root.d.ts +38 -0
  55. package/types/coefficients/root.d.ts.map +1 -0
  56. package/types/geometry/point.d.ts +1 -1
  57. package/types/geometry/point.d.ts.map +1 -1
  58. package/types/helpers.d.ts +1 -0
  59. package/types/helpers.d.ts.map +1 -1
  60. package/types/index.d.ts +1 -0
  61. package/types/index.d.ts.map +1 -1
  62. package/types/numeric.d.ts +2 -0
  63. package/types/numeric.d.ts.map +1 -1
  64. package/types/pimath.interface.d.ts +26 -26
  65. package/types/pimath.interface.d.ts.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pimath",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "description": "A math library for teacher :)",
5
5
  "type": "module",
6
6
  "main": "dist/pimath.js",
@@ -13,9 +13,11 @@
13
13
  "require": "./dist/pimath.js"
14
14
  }
15
15
  },
16
+ "./types/index.d.ts": "./types/index.d.ts",
16
17
  "files": [
17
18
  "dist",
18
- "types"
19
+ "types",
20
+ "src"
19
21
  ],
20
22
  "scripts": {
21
23
  "dev": "vite serve",
@@ -0,0 +1,556 @@
1
+ import type {
2
+ EQUATION_SIGN,
3
+ IAlgebra,
4
+ IEquation,
5
+ InputAlgebra,
6
+ InputValue,
7
+ IPiMathObject,
8
+ ISolution,
9
+ literalType
10
+ } from "../pimath.interface"
11
+ import { Fraction } from "../coefficients/fraction"
12
+ import { Numeric } from "../numeric"
13
+ import { EquationSolver } from "./equationSolver"
14
+ import { Monom } from "./monom"
15
+ import { Polynom } from "./polynom"
16
+
17
+ export class Equation implements
18
+ IPiMathObject<Equation>,
19
+ IEquation<Equation>,
20
+ IAlgebra<Equation> {
21
+
22
+ // Left part of the equation
23
+ #left: Polynom
24
+ // Right part of the equation
25
+ #right: Polynom
26
+ // Signe of the equation
27
+ #sign: EQUATION_SIGN
28
+
29
+
30
+ constructor(equation: InputAlgebra<Polynom> | Equation)
31
+ constructor(left: InputAlgebra<Polynom>, right: InputAlgebra<Polynom>, sign?: EQUATION_SIGN)
32
+ constructor(left?: InputAlgebra<Polynom> | Equation, right?: InputAlgebra<Polynom>, sign?: EQUATION_SIGN) {
33
+ // Default equation
34
+ this.#left = new Polynom().zero()
35
+ this.#right = new Polynom().zero()
36
+ this.#sign = '='
37
+
38
+ // Only one value, it's an equation
39
+ if (left !== undefined && right === undefined) {
40
+ if (left instanceof Equation) {
41
+ return left.clone()
42
+ } else if (typeof left === 'string') {
43
+ // Parse the equation as a string.
44
+ this.parse(left)
45
+ }
46
+
47
+ } else if (left !== undefined && right !== undefined) {
48
+ // Two values, it's an equation with left and right polynoms.
49
+ this.left = new Polynom(left as InputAlgebra<Polynom>)
50
+ this.right = new Polynom(right)
51
+ }
52
+
53
+ if (sign !== undefined) {
54
+ this.sign = sign
55
+ }
56
+
57
+ return this
58
+ }
59
+
60
+ // ------------------------------------------
61
+ public parse = (equationString: string): this => {
62
+ // Find the string separator
63
+ const strSign: string | false = this.#findSign(equationString)
64
+
65
+ if (strSign === false) {
66
+ throw new Error('The equation is not valid (no sign found)')
67
+ }
68
+
69
+ // The StrSign is found
70
+ const pStr: string[] = equationString.split(strSign)
71
+
72
+ return this.create(new Polynom(pStr[0]), new Polynom(pStr[1]), this.#formatSign(strSign))
73
+ }
74
+
75
+ public create = (left: Polynom, right: Polynom, sign?: string): this => {
76
+ this.#left = left
77
+ this.#right = right
78
+ this.#sign = this.#formatSign(sign ?? "=")
79
+ return this
80
+ }
81
+
82
+ public clone = (): Equation => {
83
+ return new Equation(this.#left.clone(), this.#right.clone(), this.#sign)
84
+ }
85
+
86
+ /**
87
+ * Add a value to the equation
88
+ * if value is an equation, add the left part to the left part of the equation
89
+ * and the right part to the right part of the equation
90
+ * if value is a string, try to create an equation
91
+ * if it fails, create a polynom and add it to the left and right part of the equation
92
+ * @param value | Polynom | Monom | Fraction | string | monom
93
+ */
94
+ public add(value: InputValue<Equation | Polynom>): this {
95
+ if (value instanceof Equation) {
96
+ // add the left part of the equation
97
+ this.#left.add(value.left)
98
+ // add the right part of the equation
99
+ this.#right.add(value.right)
100
+
101
+ return this
102
+ }
103
+
104
+ if (typeof value === 'string' &&
105
+ !Equation.isEquationString(value)) {
106
+
107
+ return this.add(new Equation(value))
108
+ }
109
+
110
+ const p = new Polynom(value)
111
+ this.#left.add(p)
112
+ this.#right.add(p)
113
+
114
+ return this
115
+ }
116
+
117
+ /**
118
+ * Get the degree of the equation
119
+ * @param letter
120
+ */
121
+ public degree = (letter?: string): Fraction => {
122
+ return Fraction.max(this.#left.degree(letter), this.#right.degree(letter))
123
+ }
124
+
125
+ /**
126
+ * divide an equation by a given value (transformed as a fraction)
127
+ *
128
+ * ```
129
+ * 8x+10=6x \vert 2
130
+ * 4x+5=3x
131
+ * ```
132
+ *
133
+ * |>Alternatively with $3x-4$ maybe it's working ?
134
+ * $$\frac{3x}{5}$$
135
+ *
136
+ * @param value
137
+ * @returns {Equation}
138
+ */
139
+ public divide = (value: InputValue<Fraction>): this => {
140
+ // Make sure we have a fraction.
141
+ const F: Fraction = new Fraction(value)
142
+
143
+ if (F.isZero()) {
144
+ return this
145
+ } else {
146
+ return this.multiply(F.inverse())
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Create an Equation using two polynoms.
152
+ * Markdown *support* is cool
153
+ * @param values
154
+ * @param asNumeric
155
+ */
156
+ public evaluate(values: InputValue<Fraction> | literalType<number | Fraction>, asNumeric?: boolean ): boolean {
157
+ // Evaluate the left and right part of the equation.
158
+ // compare the results.
159
+
160
+ // Evaluate the left and right part of the equation.
161
+ const left = this.#left.evaluate(values, asNumeric),
162
+ right = this.#right.evaluate(values, asNumeric)
163
+
164
+ // compare the results.
165
+ if (asNumeric) {
166
+ return left === right
167
+ }
168
+
169
+ return (left as Fraction).isEqual(right as Fraction)
170
+ }
171
+
172
+ /**
173
+ * Determine if the equation contains a variable.
174
+ * @param letter
175
+ */
176
+ public hasVariable = (letter: string): boolean => {
177
+ return this.variables.includes(letter)
178
+ }
179
+
180
+
181
+ public isEqual(value: InputValue<Equation>): boolean {
182
+ const equ = new Equation(value)
183
+ return equ.left.isEqual(this.#left) && equ.right.isEqual(this.#right)
184
+ }
185
+
186
+ public isLinearTo = (equ: Equation): boolean => {
187
+ // Move all left.
188
+ const p1 = equ.clone().moveLeft().simplify().left,
189
+ p2 = this.clone().moveLeft().simplify().left
190
+
191
+ // They are the same.
192
+ return p1.isEqual(p2) || p1.isOppositeAt(p2)
193
+ }
194
+
195
+ /**
196
+ * Determine if the equation contains more than one letter/variable.
197
+ */
198
+ public isMultiVariable = (): boolean => {
199
+ return this.#left.isMultiVariable || this.#right.isMultiVariable
200
+ }
201
+
202
+ // -----------------------------------------------
203
+ // Equations helpers
204
+ public isEqualTo = (equ: Equation): boolean => {
205
+ const p1 = equ.clone().moveLeft().left,
206
+ p2 = this.clone().moveLeft().left
207
+
208
+ // They are the same.
209
+ return p1.isEqual(p2) || p1.isOppositeAt(p2)
210
+ }
211
+
212
+ /**
213
+ * Reorder the polynom to have only one letter on the left, the rest on the right.
214
+ * @param letter
215
+ */
216
+ public isolate = (letter?: string): this | false => {
217
+ // Determine if we can isolate the variables.
218
+
219
+ // Both part of the equations must be of the first degree.
220
+ if (!this.degree(letter).isOne()) {
221
+ return false
222
+ }
223
+
224
+ // Modify the equation to isolate the asked variable.
225
+ if (this.isMultiVariable()) {
226
+ return false
227
+ }
228
+
229
+ // Isolate the letter.
230
+ let mMove: Monom
231
+ // Start by moving everything to the left.
232
+ this.#left.subtract(this.#right)
233
+ this.#right.zero()
234
+ const values = [...this.#left.monoms]
235
+ for (const m of values) {
236
+ if (!m.hasVariable(letter)) {
237
+ mMove = m.clone()
238
+ this.#left.subtract(mMove)
239
+ this.#right.subtract(mMove)
240
+ }
241
+ }
242
+
243
+ // In theory, we should have only one item on the left.
244
+ if (this.#left.length !== 1) {
245
+ return false
246
+ }
247
+
248
+ const cMove: Fraction = this.#left.monoms[0].coefficient.clone()
249
+ this.#left.divide(cMove)
250
+ this.#right.divide(cMove)
251
+ return this
252
+ }
253
+
254
+ // -----------------------------------------------
255
+ // Equations operations
256
+
257
+ // -----------------------------------------------
258
+ public letters = (): string[] => {
259
+ return [...new Set([...this.#left.letters(), ...this.#right.letters()])]
260
+ }
261
+
262
+ // -----------------------------------------------
263
+ /**
264
+ * Reorder will move all monoms containing a letter on the left, all the other on the right.
265
+ */
266
+ public moveLeft = (): this => {
267
+ this.#left.subtract(this.#right)
268
+ this.#right.zero()
269
+ return this
270
+ }
271
+
272
+ /**
273
+ * Multiple an equation by a fraction value.
274
+ * @param value
275
+ */
276
+ public multiply = (value: InputValue<Fraction>): this => {
277
+ // Make sure we have a fraction.
278
+ const F: Fraction = new Fraction(value)
279
+
280
+ // Multiply each part of the equation by the fraction
281
+ this.#left.multiply(F)
282
+ this.#right.multiply(F)
283
+
284
+ // The sign of the inequality must be changed.
285
+ if (this.#sign !== '=' && F.sign() === -1) {
286
+ this.#reverseSign()
287
+ }
288
+
289
+ return this
290
+ }
291
+
292
+ public pow(value: number): this {
293
+ this.#left.pow(value)
294
+ this.#right.pow(value)
295
+ return this
296
+ }
297
+ public opposite = (): this => {
298
+ this.#left = this.#left.opposite()
299
+ this.#right = this.#right.opposite()
300
+ return this
301
+ }
302
+
303
+ public reduce(): this {
304
+ // reduce means moving everything to the left
305
+ // remove the fractions
306
+ // simplify the equation
307
+ // reorder the equation
308
+ // start with a positive left part
309
+
310
+ // Move all left. The right part is now zero.
311
+ this.moveLeft()
312
+
313
+ // Reduce the equation: simplify and reorder.
314
+ this.#left.reduce()
315
+
316
+ // Simplify the equation.
317
+ this.simplify()
318
+
319
+ // Make sure the first part is positive.
320
+ if (this.#left.monoms[0].coefficient.isNegative()) {
321
+ this.multiply(-1)
322
+ }
323
+
324
+ return this
325
+ }
326
+
327
+ public reorder = (allLeft?: boolean): this => {
328
+ // Move all monoms of degree greater than 0 to the left.
329
+ // and all zero degree monoms to the right.
330
+ this.#left.subtract(this.#right)
331
+ this.#right.zero()
332
+ this.#left.reorder()
333
+
334
+ // we have all left (so equal zero) : it's done !
335
+ if (allLeft) {
336
+ return this
337
+ }
338
+
339
+ // Fetch all zero degree monoms.
340
+ this.#left.monoms
341
+ .filter(m => m.degree().isZero())
342
+ .forEach(m => {
343
+ const move = m.clone()
344
+ this.#left.subtract(move)
345
+ this.#right.subtract(move)
346
+ })
347
+
348
+ // Reorder the left and right polynoms
349
+ this.#left.reorder()
350
+ this.#right.reorder()
351
+ return this
352
+ }
353
+
354
+ // ------------------------------------------
355
+ public replaceBy = (letter: string, P: Polynom): this => {
356
+ this.#left.replaceBy(letter, P)
357
+ this.#right.replaceBy(letter, P)
358
+ return this
359
+ }
360
+
361
+ /**
362
+ * Multiply by the lcm denominator and divide by the gcm numerators.
363
+ */
364
+ public simplify = (): this => {
365
+ this.multiply(Numeric.lcm(...this.#left.getDenominators(), ...this.#right.getDenominators()))
366
+ this.divide(Numeric.gcd(...this.#left.getNumerators(), ...this.#right.getNumerators()))
367
+ return this
368
+ }
369
+
370
+ // -----------------------------------------------
371
+ public solve = (): ISolution[] => {
372
+ const solver = new EquationSolver(this.clone())
373
+ return solver.solve()
374
+ }
375
+
376
+ public split(): [Polynom, Polynom] {
377
+ return [this.#left.clone(), this.#right.clone()]
378
+ }
379
+
380
+ public subtract(value: InputValue<Equation | Polynom>): this {
381
+ if (value instanceof Equation) {
382
+ this.#left.subtract(value.left)
383
+ this.#right.subtract(value.right)
384
+
385
+ return this
386
+ }
387
+
388
+ if (typeof value === 'string' &&
389
+ !Equation.isEquationString(value)) {
390
+ return this.subtract(new Equation(value))
391
+ }
392
+
393
+ const p = new Polynom(value)
394
+ this.#left.subtract(p)
395
+ this.#right.subtract(p)
396
+
397
+ return this
398
+ }
399
+
400
+ public test = (values: literalType<Fraction>): boolean => {
401
+ return (this.left.evaluate(values) as Fraction).isEqual(this.right.evaluate(values))
402
+ }
403
+
404
+ public static isEquationString(equationString: string): boolean {
405
+ // The equation sign can be one of the following:
406
+ // =, <, >, <=, >=
407
+
408
+ return equationString.includes('=') ||
409
+ equationString.includes('<') ||
410
+ equationString.includes('>') ||
411
+ equationString.includes('<=') ||
412
+ equationString.includes('>=')
413
+ }
414
+
415
+ public static makeSolutionsUnique(solutions: ISolution[], sorted?: boolean): ISolution[] {
416
+ const solutionAsTex: string[] = [],
417
+ uniqueSolutions = solutions.filter(sol => {
418
+ if (!solutionAsTex.includes(sol.tex)) {
419
+ solutionAsTex.push(sol.tex)
420
+ return true
421
+ } else {
422
+ return false
423
+ }
424
+ })
425
+
426
+ if (sorted === true) {
427
+ uniqueSolutions.sort((a, b) => a.value - b.value)
428
+ }
429
+
430
+ return uniqueSolutions
431
+ }
432
+
433
+ public get display(): string {
434
+ return `${this.#left.display}${this.signAsTex}${this.#right.display}`
435
+ }
436
+
437
+ // Getter and setter
438
+ public get left(): Polynom {
439
+ return this.#left
440
+ }
441
+
442
+ public set left(value: Polynom) {
443
+ this.#left = value
444
+ }
445
+
446
+ public get numberOfVars(): number {
447
+ return this.variables.length
448
+ }
449
+
450
+ public get right(): Polynom {
451
+ return this.#right
452
+ }
453
+
454
+ public set right(value: Polynom) {
455
+ this.#right = value
456
+ }
457
+
458
+ // ------------------------------------------
459
+ public get sign(): string {
460
+ return this.#sign
461
+ }
462
+
463
+ public set sign(value: string) {
464
+ // Set the sign value as formatted.
465
+ this.#sign = this.#formatSign(value)
466
+ }
467
+
468
+ public get signAsTex(): string {
469
+ if (this.#sign === '>=') {
470
+ return '\\geq'
471
+ }
472
+
473
+ if (this.#sign === '<=') {
474
+ return '\\leq'
475
+ }
476
+
477
+ return this.#sign
478
+ }
479
+
480
+ public get tex(): string {
481
+ return `${this.#left.tex}${this.signAsTex}${this.#right.tex}`
482
+ }
483
+
484
+ public get variables(): string[] {
485
+ return [...new Set(this.#right.variables.concat(this.#left.variables))]
486
+ }
487
+
488
+ #findSign = (equationString: string): string | false => {
489
+ if (equationString.includes('geq')) {
490
+ return (equationString.includes('\\geq')) ? '\\geq' : 'geq'
491
+ } else if (equationString.includes('leq')) {
492
+ return (equationString.includes('\\leq')) ? '\\leq' : 'leq'
493
+ } else if (equationString.includes('>=')) {
494
+ return '>='
495
+ } else if (equationString.includes('=>')) {
496
+ return '=>'
497
+ } else if (equationString.includes('>')) {
498
+ return '>'
499
+ } else if (equationString.includes('<=')) {
500
+ return '<='
501
+ } else if (equationString.includes('=<')) {
502
+ return '=<'
503
+ } else if (equationString.includes('<')) {
504
+ return '<'
505
+ } else if (equationString.includes('=')) {
506
+ return '='
507
+ }
508
+
509
+ throw new Error('The equation is not valid (no sign found)')
510
+ }
511
+
512
+ // -----------------------------------------------
513
+ // Equations solving algorithms
514
+ #formatSign = (signStr?: string): EQUATION_SIGN => {
515
+ if (signStr === undefined) {
516
+ return '='
517
+ }
518
+
519
+ if (signStr.includes('geq')) {
520
+ return '>='
521
+ } else if (signStr.includes('>=')) {
522
+ return '>='
523
+ } else if (signStr.includes('=>')) {
524
+ return '>='
525
+ } else if (signStr.includes('>')) {
526
+ return '>'
527
+ } else if (signStr.includes('leq')) {
528
+ return '<='
529
+ } else if (signStr.includes('<=')) {
530
+ return '<='
531
+ } else if (signStr.includes('=<')) {
532
+ return '<='
533
+ } else if (signStr.includes('<')) {
534
+ return '<'
535
+ } else {
536
+ return '='
537
+ }
538
+ }
539
+
540
+ #reverseSign = (): this => {
541
+ if (this.#sign === '=') {
542
+ return this
543
+ }
544
+
545
+ if (this.#sign.includes('<')) {
546
+ this.#sign.replace('<', '>')
547
+ return this
548
+ }
549
+ if (this.#sign.includes('>')) {
550
+ this.#sign.replace('>', '<')
551
+ return this
552
+ }
553
+
554
+ return this
555
+ }
556
+ }