pimath 0.0.124 → 0.0.125
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/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_07_11_2023_08_30_[Default_Changelist]/shelved.patch +192 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_07_11_2023_08_30_[Default_Changelist]1/shelved.patch +0 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_07_11_2023_08_30__Default_Changelist_.xml +4 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_09_11_2023_10_43_[Default_Changelist]/shelved.patch +2404 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_09_11_2023_10_43__Default_Changelist_.xml +4 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_09_11_2023_11_01_[Default_Changelist]/shelved.patch +1362 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_09_11_2023_11_01__Default_Changelist_.xml +4 -0
- package/dist/pimath.js +27 -6
- package/dist/pimath.js.map +1 -1
- package/dist/pimath.min.js +1 -1
- package/dist/pimath.min.js.map +1 -1
- package/esm/maths/randomization/random.d.ts +1 -1
- package/esm/maths/randomization/random.js +2 -2
- package/esm/maths/randomization/random.js.map +1 -1
- package/esm/maths/randomization/rndHelpers.d.ts +1 -1
- package/esm/maths/randomization/rndHelpers.js +25 -4
- package/esm/maths/randomization/rndHelpers.js.map +1 -1
- package/package.json +1 -1
- package/src/maths/randomization/random.ts +2 -2
- package/src/maths/randomization/rndHelpers.ts +49 -18
- package/tests/geometry/circle.test.ts +125 -10
- package/tests/numexp.test.ts +10 -2
- package/dev/pimath.js +0 -7935
- package/dev/pimath.js.map +0 -1
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -78
- package/docs/assets/main.js +0 -58
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1367
- package/docs/classes/Logicalset.Logicalset.html +0 -221
- package/docs/classes/Polynom.Rational.html +0 -391
- package/docs/classes/Vector-1.Vector.html +0 -494
- package/docs/classes/Vector.Point.html +0 -341
- package/docs/classes/algebra_equation.Equation.html +0 -796
- package/docs/classes/algebra_linearSystem.LinearSystem.html +0 -408
- package/docs/classes/algebra_monom.Monom.html +0 -967
- package/docs/classes/algebra_polynom.Polynom.html +0 -1281
- package/docs/classes/coefficients_fraction.Fraction.html +0 -939
- package/docs/classes/geometry_circle.Circle.html +0 -476
- package/docs/classes/geometry_line.Line.html +0 -779
- package/docs/classes/geometry_triangle.Triangle.html +0 -429
- package/docs/classes/numeric.Numeric.html +0 -269
- package/docs/classes/shutingyard.Shutingyard.html +0 -259
- package/docs/enums/algebra_equation.PARTICULAR_SOLUTION.html +0 -89
- package/docs/enums/geometry_line.LinePropriety.html +0 -102
- package/docs/enums/shutingyard.ShutingyardMode.html +0 -106
- package/docs/enums/shutingyard.ShutingyardType.html +0 -120
- package/docs/index.html +0 -63
- package/docs/interfaces/algebra_equation.ISolution.html +0 -111
- package/docs/interfaces/algebra_polynom.IEuclidian.html +0 -93
- package/docs/interfaces/geometry_triangle.remarquableLines.html +0 -150
- package/docs/modules/Logicalset.html +0 -69
- package/docs/modules/Polynom.html +0 -69
- package/docs/modules/Vector-1.html +0 -69
- package/docs/modules/Vector.html +0 -69
- package/docs/modules/algebra_equation.html +0 -75
- package/docs/modules/algebra_linearSystem.html +0 -65
- package/docs/modules/algebra_monom.html +0 -70
- package/docs/modules/algebra_polynom.html +0 -75
- package/docs/modules/coefficients_fraction.html +0 -70
- package/docs/modules/geometry_circle.html +0 -65
- package/docs/modules/geometry_line.html +0 -70
- package/docs/modules/geometry_triangle.html +0 -70
- package/docs/modules/numeric.html +0 -65
- package/docs/modules/shutingyard.html +0 -84
- package/docs/types/algebra_monom.literalType.html +0 -66
- package/docs/types/algebra_polynom.PolynomParsingType.html +0 -62
- package/docs/types/coefficients_fraction.FractionParsingType.html +0 -61
- package/docs/types/shutingyard.Token.html +0 -72
- package/docs/types/shutingyard.tokenType.html +0 -77
- package/docs/variables/shutingyard.tokenConstant.html +0 -70
- package/esm/maths/expressions/ExpressionTree.d.ts +0 -17
- package/esm/maths/expressions/ExpressionTree.js +0 -150
- package/esm/maths/expressions/ExpressionTree.js.map +0 -1
- package/esm/maths/expressions/expression.d.ts +0 -27
- package/esm/maths/expressions/expression.js +0 -239
- package/esm/maths/expressions/expression.js.map +0 -1
- package/esm/maths/expressions/expressionFactor.d.ts +0 -36
- package/esm/maths/expressions/expressionFactor.js +0 -156
- package/esm/maths/expressions/expressionFactor.js.map +0 -1
- package/esm/maths/expressions/expressionMember.d.ts +0 -27
- package/esm/maths/expressions/expressionMember.js +0 -199
- package/esm/maths/expressions/expressionMember.js.map +0 -1
- package/esm/maths/expressions/expressionOperators.d.ts +0 -8
- package/esm/maths/expressions/expressionOperators.js +0 -42
- package/esm/maths/expressions/expressionOperators.js.map +0 -1
- package/esm/maths/expressions/expressionParser.d.ts +0 -14
- package/esm/maths/expressions/expressionParser.js +0 -259
- package/esm/maths/expressions/expressionParser.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactor.d.ts +0 -7
- package/esm/maths/expressions/factors/ExpFactor.js +0 -34
- package/esm/maths/expressions/factors/ExpFactor.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactorConstant.d.ts +0 -14
- package/esm/maths/expressions/factors/ExpFactorConstant.js +0 -52
- package/esm/maths/expressions/factors/ExpFactorConstant.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactorExponential.d.ts +0 -8
- package/esm/maths/expressions/factors/ExpFactorExponential.js +0 -22
- package/esm/maths/expressions/factors/ExpFactorExponential.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactorNumber.d.ts +0 -14
- package/esm/maths/expressions/factors/ExpFactorNumber.js +0 -59
- package/esm/maths/expressions/factors/ExpFactorNumber.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactorPower.d.ts +0 -13
- package/esm/maths/expressions/factors/ExpFactorPower.js +0 -35
- package/esm/maths/expressions/factors/ExpFactorPower.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactorTrigo.d.ts +0 -20
- package/esm/maths/expressions/factors/ExpFactorTrigo.js +0 -48
- package/esm/maths/expressions/factors/ExpFactorTrigo.js.map +0 -1
- package/esm/maths/expressions/factors/ExpFactorVariable.d.ts +0 -13
- package/esm/maths/expressions/factors/ExpFactorVariable.js +0 -36
- package/esm/maths/expressions/factors/ExpFactorVariable.js.map +0 -1
- package/esm/maths/expressions/internals.d.ts +0 -12
- package/esm/maths/expressions/internals.js +0 -29
- package/esm/maths/expressions/internals.js.map +0 -1
- package/esm/maths/expressions/numexp.d.ts +0 -19
- package/esm/maths/expressions/numexp.js +0 -186
- package/esm/maths/expressions/numexp.js.map +0 -1
- package/esm/maths/expressions/polynomexp.bkp.d.ts +0 -33
- package/esm/maths/expressions/polynomexp.bkp.js +0 -184
- package/esm/maths/expressions/polynomexp.bkp.js.map +0 -1
- package/esm/maths/expressions/polynomexp.d.ts +0 -52
- package/esm/maths/expressions/polynomexp.js +0 -246
- package/esm/maths/expressions/polynomexp.js.map +0 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Index: src/maths/algebra/polynom.ts
|
|
2
|
+
IDEA additional info:
|
|
3
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
4
|
+
<+>/**\r\n * Polynom module contains everything necessary to handle polynoms.*\r\n */\r\n\r\nimport {Monom} from './monom';\r\nimport {Shutingyard, ShutingyardType, Token} from '../shutingyard';\r\nimport {Numeric} from '../numeric';\r\nimport {Fraction} from \"../coefficients/fraction\";\r\nimport {Equation, ISolution} from \"./equation\";\r\nimport {literalType} from \"../types\";\r\nimport {RootFraction} from \"../coefficients/rootFraction\";\r\n\r\nexport type PolynomParsingType = string | Polynom | number | Fraction | RootFraction | Monom\r\n\r\nexport interface IEuclidian {\r\n quotient: Polynom,\r\n reminder: Polynom\r\n}\r\n\r\n/**\r\n * Polynom class can handle polynoms, reorder, resolve, ...\r\n * ```\r\n * let P = new Polynom('3x-4')\r\n * ```\r\n */\r\nexport class Polynom {\r\n private _rawString: string;\r\n\r\n /**\r\n *\r\n * @param {string} polynomString (optional) Default polynom to parse on class creation\r\n * @param values\r\n */\r\n constructor(polynomString?: PolynomParsingType, ...values: unknown[]) {\r\n this._monoms = [];\r\n this._factors = [];\r\n this.mark_as_dirty()\r\n\r\n if (polynomString !== undefined) {\r\n this.parse(polynomString, ...values);\r\n }\r\n return this;\r\n }\r\n\r\n private _dirty_factors: boolean\r\n\r\n // ------------------------------------------\r\n get dirty_factors(): boolean {\r\n return this._dirty_factors;\r\n }\r\n\r\n set dirty_factors(value: boolean) {\r\n this._dirty_factors = value;\r\n }\r\n\r\n private _dirty_zeroes: boolean\r\n\r\n get dirty_zeroes(): boolean {\r\n return this._dirty_zeroes;\r\n }\r\n\r\n set dirty_zeroes(value: boolean) {\r\n this._dirty_zeroes = value;\r\n }\r\n\r\n private _euclidianCache: { [Key: string]: IEuclidian }\r\n\r\n get euclidianCache(): { [p: string]: IEuclidian } {\r\n return this._euclidianCache;\r\n }\r\n\r\n set euclidianCache(value: { [p: string]: IEuclidian }) {\r\n this._euclidianCache = value;\r\n }\r\n\r\n private _factors: Polynom[];\r\n\r\n get factors(): Polynom[] {\r\n return this.factorize()\r\n }\r\n\r\n set factors(value: Polynom[]) {\r\n this.mark_as_dirty()\r\n this._factors = value;\r\n }\r\n\r\n private _monoms: Monom[];\r\n\r\n // ------------------------------------------\r\n get monoms() {\r\n return this._monoms;\r\n }\r\n\r\n set monoms(M: Monom[]) {\r\n this._monoms = M;\r\n }\r\n\r\n private _texString: string;\r\n\r\n get texString(): string {\r\n return this._texString;\r\n }\r\n\r\n private _zeroes: ISolution[]\r\n\r\n get zeroes(): ISolution[] {\r\n return this.getZeroes()\r\n }\r\n\r\n get texFactors(): string {\r\n this.factorize()\r\n\r\n if (this.factors.length <= 1) {\r\n return this.tex\r\n }\r\n\r\n // Build an array of texFactors with the number of similar items.\r\n let factorsCount: { [Key: string]: { degree: number, factor: Polynom } } = {}\r\n for (let f of this.factors) {\r\n if (factorsCount[f.tex] !== undefined) {\r\n factorsCount[f.tex].degree++\r\n } else {\r\n factorsCount[f.tex] = {\r\n degree: 1,\r\n factor: f\r\n }\r\n }\r\n }\r\n\r\n // First round to put the 'monom' first\r\n let simpleFactor = new Polynom().one()\r\n\r\n for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length === 1)) {\r\n simpleFactor.multiply(item.factor)\r\n }\r\n\r\n let tex = simpleFactor.isOne() ? '' : simpleFactor.tex\r\n\r\n // Loop through all factors that contains at least 2 monoms.\r\n for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length > 1)) {\r\n if (item.factor.length > 1) {\r\n tex += `\\\\left( ${item.factor.tex} \\\\right)${item.degree > 1 ? '^{ ' + item.degree + ' }' : ''}`\r\n }\r\n }\r\n\r\n return tex;\r\n }\r\n\r\n get displayFactors() {\r\n this.factorize()\r\n\r\n if (this.factors.length <= 1) {\r\n return this.display\r\n }\r\n\r\n // Build an array of texFactors with the number of similar items.\r\n let factorsCount: { [Key: string]: { degree: number, factor: Polynom } } = {}\r\n for (let f of this.factors) {\r\n if (factorsCount[f.display] !== undefined) {\r\n factorsCount[f.display].degree++\r\n } else {\r\n factorsCount[f.display] = {\r\n degree: 1,\r\n factor: f\r\n }\r\n }\r\n }\r\n\r\n // First round to put the 'monom' first\r\n let simpleFactor = new Polynom().one()\r\n\r\n for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length === 1)) {\r\n simpleFactor.multiply(item.factor)\r\n }\r\n\r\n let display = simpleFactor.isOne() ? '' : simpleFactor.display\r\n\r\n // Loop through all factors that contains at least 2 monoms.\r\n for (let item of Object.values(factorsCount).filter(item => item.factor.monoms.length > 1)) {\r\n if (item.factor.length > 1) {\r\n display += `(${item.factor.display})${item.degree > 1 ? '^(' + item.degree + ')' : ''}`\r\n }\r\n }\r\n\r\n return display;\r\n }\r\n\r\n get length() {\r\n // TODO: Must reduce the monoms list to remove the zero coefficient.\r\n return this._monoms.length;\r\n }\r\n\r\n get display(): string {\r\n return this.genDisplay();\r\n }\r\n\r\n get raw(): string {\r\n return this._rawString\r\n }\r\n\r\n get tex(): string {\r\n return this.genDisplay('tex');\r\n }\r\n\r\n get isMultiVariable(): boolean {\r\n const B = false;\r\n for (const m of this._monoms) {\r\n if (m.variables.length > 1) {\r\n return true;\r\n }\r\n }\r\n return B;\r\n }\r\n\r\n get variables(): string[] {\r\n let V: string[] = [];\r\n\r\n for (const m of this._monoms) {\r\n V = V.concat(m.variables);\r\n }\r\n\r\n // Remove duplicates.\r\n V = [...new Set(V)];\r\n V.sort()\r\n return V;\r\n }\r\n\r\n get numberOfVars(): number {\r\n return this.variables.length;\r\n }\r\n\r\n get plotFunction(): string {\r\n return this.genDisplay('tex', false, false, true)\r\n }\r\n\r\n get texWithSign(): string {\r\n const t = this.tex,\r\n first = t[0]\r\n\r\n if (t[0] !== '+' && t[0] !== '-') {\r\n return `+${t}`\r\n }\r\n\r\n return t\r\n };\r\n\r\n get displayWithSign(): string {\r\n const t = this.display,\r\n first = t[0]\r\n\r\n if (t[0] !== '+' && t[0] !== '-') {\r\n return `+${t}`\r\n }\r\n\r\n return t\r\n }\r\n\r\n\r\n // ------------------------------------------\r\n // Creation / parsing functions\r\n\r\n mark_as_dirty = (): void => {\r\n this.dirty_factors = true\r\n this.dirty_zeroes = true\r\n this.euclidianCache = {}\r\n }\r\n\r\n addToken = (stack: Polynom[], element: Token): void => {\r\n switch (element.tokenType) {\r\n case ShutingyardType.COEFFICIENT:\r\n stack.push(new Polynom(element.token))\r\n break\r\n\r\n case ShutingyardType.VARIABLE:\r\n stack.push(new Polynom().add(new Monom(element.token)))\r\n break\r\n\r\n case ShutingyardType.CONSTANT:\r\n // TODO: add constant support to Polynom parsing.\r\n console.log('Actually, not supported - will be added later !')\r\n break\r\n\r\n case ShutingyardType.OPERATION:\r\n if (stack.length >= 2) {\r\n const b = stack.pop(),\r\n a = stack.pop()\r\n\r\n if (element.token === '+') {\r\n stack.push(a.add(b))\r\n } else if (element.token === '-') {\r\n stack.push(a.subtract(b))\r\n } else if (element.token === '*') {\r\n stack.push(a.multiply(b))\r\n } else if (element.token === '/') {\r\n if (b.degree().isStrictlyPositive()) {\r\n console.log('divide by a polynom -> should create a rational polynom !')\r\n } else {\r\n stack.push(a.divide(b.monoms[0].coefficient))\r\n\r\n }\r\n } else if (element.token === '^') {\r\n if (b.degree().isStrictlyPositive()) {\r\n console.error('Cannot elevate a polynom with another polynom !', a.tex, b.tex)\r\n } else {\r\n if (b.monoms[0].coefficient.isRelative()) {\r\n // Integer power\r\n stack.push(a.pow(b.monoms[0].coefficient.value))\r\n } else {\r\n // Only allow power if the previous polynom is only a monom, without coefficient.\r\n if (a.monoms.length === 1 && a.monoms[0].coefficient.isOne()) {\r\n for (let letter in a.monoms[0].literal) {\r\n a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient)\r\n }\r\n stack.push(a)\r\n } else {\r\n console.error('Cannot have power with fraction')\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n if (element.token === '-') {\r\n stack.push(stack.pop().opposed())\r\n } else {\r\n throw \"Error parsing the polynom \" + this._rawString\r\n }\r\n }\r\n break\r\n\r\n case ShutingyardType.MONOM:\r\n // Should never appear.\r\n console.error('The monom token should not appear here')\r\n break;\r\n\r\n case ShutingyardType.FUNCTION:\r\n // Should never appear.\r\n console.error('The function token should not appear here - might be introduced later.')\r\n break;\r\n }\r\n }\r\n\r\n // ------------------------------------------\r\n /**\r\n * Parse a string to a polynom.\r\n * @param inputStr\r\n * @param values: as string, numbers or fractions\r\n */\r\n parse = (inputStr: PolynomParsingType, ...values: unknown[]): Polynom => {\r\n // Reset the main variables.\r\n this._monoms = []\r\n this._factors = []\r\n this.mark_as_dirty()\r\n\r\n // TODO: allow to enter a liste of Fraction (a, b, c, ...) to make a polynom ax^n + bx^(n-1) + cx^(n-2) + ...\r\n if (typeof inputStr === 'string') {\r\n return this._parseString(inputStr, ...values)\r\n } else if (\r\n (typeof inputStr === 'number' || inputStr instanceof Fraction || inputStr instanceof RootFraction || inputStr instanceof Monom)\r\n && (values === undefined || values.length === 0)\r\n ) {\r\n this._monoms.push(new Monom(inputStr))\r\n } else if (inputStr instanceof Monom && values.length > 0) {\r\n this._monoms.push(new Monom(inputStr))\r\n values.forEach(m => {\r\n this._monoms.push(new Monom(m))\r\n })\r\n } else if (inputStr instanceof Polynom) {\r\n for (const m of inputStr.monoms) {\r\n this._monoms.push(m.clone())\r\n }\r\n }\r\n\r\n return this\r\n };\r\n\r\n /**\r\n * Clone the polynom\r\n */\r\n clone = (): Polynom => {\r\n const P = new Polynom();\r\n const M: Monom[] = [];\r\n\r\n for (const m of this._monoms) {\r\n M.push(m.clone());\r\n }\r\n\r\n P.monoms = M;\r\n\r\n return P;\r\n };\r\n\r\n /**\r\n * Set the polynom to zero.\r\n * @returns {this}\r\n */\r\n zero = (): Polynom => {\r\n this._monoms = [];\r\n this._monoms.push(new Monom().zero());\r\n this._rawString = '0';\r\n this.mark_as_dirty()\r\n return this;\r\n };\r\n\r\n one = (): Polynom => {\r\n this._monoms = [];\r\n this._monoms.push(new Monom().one());\r\n this._rawString = '1';\r\n this.mark_as_dirty()\r\n return this;\r\n }\r\n\r\n\r\n // ------------------------------------------\r\n // Mathematical operations\r\n\r\n empty = (): Polynom => {\r\n this._monoms = [];\r\n this._rawString = '';\r\n this.mark_as_dirty()\r\n return this;\r\n };\r\n\r\n // ------------------------------------------\r\n opposed = (): Polynom => {\r\n this._monoms = this._monoms.map(m => m.opposed());\r\n this.mark_as_dirty()\r\n return this;\r\n };\r\n\r\n add = (...values: unknown[]): Polynom => {\r\n this.mark_as_dirty()\r\n\r\n // @ts-ignore\r\n for (let value of values) {\r\n if (value instanceof Polynom) {\r\n this._monoms = this._monoms.concat(value.monoms);\r\n } else if (value instanceof Monom) {\r\n this._monoms.push(value.clone());\r\n } else if (Number.isSafeInteger(value)) {\r\n this._monoms.push(new Monom(value.toString()));\r\n } else {\r\n this._monoms.push(new Monom(value));\r\n }\r\n }\r\n\r\n return this.reduce();\r\n };\r\n\r\n subtract = (...values: unknown[]): Polynom => {\r\n this.mark_as_dirty()\r\n\r\n for (let value of values) {\r\n if (value instanceof Polynom) {\r\n this._monoms = this._monoms.concat(value.clone().opposed().monoms);\r\n } else if (value instanceof Monom) {\r\n this._monoms.push(value.clone().opposed());\r\n } else if (Number.isSafeInteger(value)) {\r\n this._monoms.push(new Monom(value.toString()).opposed());\r\n } else {\r\n this._monoms.push(new Monom(value).opposed());\r\n }\r\n }\r\n\r\n return this.reduce();\r\n };\r\n\r\n multiply = (value: unknown): Polynom => {\r\n this.mark_as_dirty()\r\n\r\n if (value instanceof Polynom) {\r\n return this.multiplyByPolynom(value);\r\n } else if (value instanceof Fraction) {\r\n return this.multiplyByFraction(value);\r\n } else if (value instanceof Monom) {\r\n return this.multiplyByMonom(value);\r\n } else if (Number.isSafeInteger(value) && typeof value === 'number') {\r\n return this.multiplyByInteger(value);\r\n }\r\n\r\n // Something went wrong...\r\n return this;\r\n }\r\n\r\n /**\r\n * Divide the current polynom by another polynom.\r\n * @param P\r\n * returns {quotient: Polynom, reminder: Polynom}\r\n */\r\n euclidian = (P: Polynom): IEuclidian => {\r\n\r\n if (this.euclidianCache[P.tex] !== undefined) {\r\n return this.euclidianCache[P.tex]\r\n }\r\n\r\n const letter: string = P.variables[0];\r\n const quotient: Polynom = new Polynom().zero();\r\n const reminder: Polynom = this.clone().reorder(letter);\r\n\r\n // There is no variable - means it's a number\r\n if (P.variables.length === 0) {\r\n let q = this.clone().divide(P)\r\n return {\r\n quotient: this.clone().divide(P),\r\n reminder: new Polynom().zero()\r\n }\r\n }\r\n\r\n // Get at least a letter\r\n\r\n const maxMP: Monom = P.monomByDegree(undefined, letter);\r\n const degreeP: Fraction = P.degree(letter);\r\n\r\n let newM: Monom;\r\n\r\n // Make the euclidian division of the two polynoms.\r\n let MaxIteration = this.degree(letter).clone().multiply(2);\r\n while (reminder.degree(letter).isGreaterOrEqualTo(degreeP) && MaxIteration.isPositive()) {\r\n MaxIteration.subtract(1)\r\n\r\n // Get the greatest monom divided by the max monom of the divider\r\n newM = reminder.monomByDegree(undefined, letter).clone().divide(maxMP);\r\n\r\n if (newM.isZero()) {\r\n break;\r\n }\r\n\r\n // Get the new quotient and reminder.\r\n quotient.add(newM);\r\n reminder.subtract(P.clone().multiply(newM));\r\n }\r\n\r\n quotient.reduce()\r\n reminder.reduce()\r\n return {quotient, reminder};\r\n };\r\n\r\n divide = (value: unknown): Polynom => {\r\n this.mark_as_dirty()\r\n\r\n if (value instanceof Fraction) {\r\n return this.divideByFraction(value);\r\n } else if (typeof value === 'number' && Number.isSafeInteger(value)) {\r\n return this.divideByInteger(value);\r\n } else if (value instanceof Monom) {\r\n return this.divide(new Polynom(value))\r\n } else if (value instanceof Polynom) {\r\n if (value.monoms.length === 1 && value.variables.length === 0) {\r\n return this.divideByFraction(value.monoms[0].coefficient)\r\n } else {\r\n let {quotient, reminder} = this.euclidian(value)\r\n if (reminder.isZero()) {\r\n return quotient\r\n } else {\r\n console.log(`${this.tex} is not divideable by ${value.tex}`)\r\n return new Polynom().zero()\r\n }\r\n }\r\n }\r\n }\r\n\r\n pow = (nb: number): Polynom => {\r\n this.mark_as_dirty()\r\n\r\n if (!Number.isSafeInteger(nb)) {\r\n return this.zero();\r\n }\r\n if (nb < 0) {\r\n return this.zero();\r\n }\r\n if (nb === 0) {\r\n return new Polynom();\r\n }\r\n\r\n const P = this.clone();\r\n for (let i = 1; i < nb; i++) {\r\n this.multiply(P);\r\n }\r\n return this.reduce();\r\n };\r\n\r\n // ------------------------------------------\r\n /**\r\n * Compare the current coefficient with another coefficient\r\n * @param P\r\n * @param sign (string| default is =): authorized values: =, <, <=, >, >= with some variations.\r\n */\r\n compare = (P: Polynom, sign?: string): boolean => {\r\n if (sign === undefined) {\r\n sign = '='\r\n }\r\n\r\n // Create clone version to reduce them without altering the original polynoms.\r\n const cP1 = this.clone().reduce().reorder();\r\n const cP2 = P.clone().reduce().reorder();\r\n\r\n switch (sign) {\r\n case '=':\r\n // They must have the isSame length and the isSame degree\r\n if (cP1.length !== cP2.length || !cP1.degree().isEqualTo(cP2.degree())) {\r\n return false;\r\n }\r\n\r\n // Check if the coefficients are the isSame.\r\n for (const i in cP1.monoms) {\r\n if (!cP1.monoms[i].isEqual(cP2.monoms[i])) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n case 'same':\r\n // They must have the isSame length and the isSame degree\r\n if (cP1.length !== cP2.length || cP1.degree() !== cP2.degree()) {\r\n return false;\r\n }\r\n\r\n for (const i in cP1.monoms) {\r\n if (!cP1.monoms[i].isSameAs(cP2.monoms[i])) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n default:\r\n return false;\r\n }\r\n };\r\n\r\n isZero(): boolean {\r\n return (this._monoms.length === 1 && this._monoms[0].coefficient.isZero()) || this._monoms.length === 0;\r\n }\r\n\r\n isOne(): boolean {\r\n return this._monoms.length === 1 && this._monoms[0].coefficient.isOne();\r\n }\r\n\r\n isEqual = (P: Polynom): boolean => {\r\n return this.compare(P, '=');\r\n };\r\n\r\n isSameAs = (P: Polynom): boolean => {\r\n return this.compare(P, 'same');\r\n };\r\n\r\n\r\n // ------------------------------------------\r\n // Compare functions\r\n\r\n isOpposedAt = (P: Polynom): boolean => {\r\n return this.compare(P.clone().opposed(), '=');\r\n };\r\n\r\n isFactorized = (polynomString: string, soft?: boolean): boolean => {\r\n let P;\r\n\r\n // Check if polynom is complete...\r\n if (polynomString.split('(').length !== polynomString.split(')').length) {\r\n return false\r\n }\r\n\r\n // Try to build the polynom\r\n try {\r\n P = new Polynom(polynomString);\r\n } catch (e) {\r\n return false;\r\n }\r\n\r\n // Both polynom aren't the same (once developed and reduced => they cannot be equivalent)\r\n if (!this.isEqual(P)) {\r\n return false;\r\n }\r\n\r\n // Check if the provided (string) version is fully factorized.\r\n // Run a regex on the string.\r\n let polynomStringNormalized = polynomString.replaceAll('*', ''),\r\n polynomStringReduced = '' + polynomStringNormalized,\r\n factors: string[] = [];\r\n\r\n for (let x of polynomStringNormalized.matchAll(/\\(([a-z0-9+\\-]+)\\)(\\^[0-9]*)?/g)) {\r\n\r\n if (x[2] !== undefined) {\r\n // if there is an exponential value, add it multiple times\r\n for (let i = 0; i < +x[2].substring(1); i++) {\r\n factors.push(x[1])\r\n }\r\n } else {\r\n // no power - add it once.\r\n factors.push(x[1]);\r\n }\r\n\r\n // Remove the current polynom\r\n polynomStringReduced = polynomStringReduced.replaceAll(x[0], '');\r\n }\r\n if (polynomStringReduced !== '') {\r\n factors.push(polynomStringReduced);\r\n }\r\n let polyFactors = factors.map(x => new Polynom(x));\r\n\r\n // polyFactors contain all polynoms.\r\n let checkPolyFactors = polyFactors.filter(x => x.degree().isGreaterOrEqualTo(1) && !x.commonMonom().isOne())\r\n\r\n // Some polynoms are not completely factorized.\r\n if (checkPolyFactors.length > 0 && !soft) {\r\n return false\r\n }\r\n if (checkPolyFactors.length > 0 && soft) {\r\n polyFactors = polyFactors.filter(x => x.commonMonom().isOne())\r\n\r\n let FactorizedConstant = new Fraction().one()\r\n for (let p of checkPolyFactors) {\r\n let k = p.commonMonom(),\r\n pFactor = p.clone().divide(k)\r\n\r\n if (k.degree().isZero()) {\r\n FactorizedConstant.multiply(k.coefficient)\r\n polyFactors.push(pFactor.clone())\r\n }\r\n }\r\n }\r\n\r\n\r\n // Factorize the current polynom.\r\n this.factorize();\r\n\r\n // Compare the given factors with the generated factors\r\n let sign = 1,\r\n notFoundedFactors = []\r\n for (let f of this.factors) {\r\n // The factor is just a coefficient. Might be opposite\r\n if (f.degree().isZero()) {\r\n if (f.monoms[0].coefficient.isMinusOne()) {\r\n sign = -sign\r\n }\r\n }\r\n\r\n let factorFound = false\r\n for (let i = 0; i < polyFactors.length; i++) {\r\n if (f.isEqual(polyFactors[i])) {\r\n polyFactors.splice(i, 1);\r\n factorFound = true\r\n break;\r\n } else if (f.isOpposedAt(polyFactors[i])) {\r\n polyFactors.splice(i, 1);\r\n sign = -sign;\r\n factorFound = true\r\n break;\r\n }\r\n }\r\n\r\n if (!factorFound) {\r\n notFoundedFactors.push(f.clone())\r\n }\r\n }\r\n\r\n // The polyfactors must be empty and the cumulative opposite factors must be 1.\r\n return (polyFactors.length === 0 && sign === 1);\r\n }\r\n\r\n isReduced = (polynomString?: string): boolean => {\r\n // The polynom must be developed to be reduced.\r\n if (!this.isDeveloped(polynomString)) {\r\n return false\r\n }\r\n\r\n let P = new Polynom(polynomString)\r\n if (P.monoms.length > this.monoms.length) {\r\n return false\r\n }\r\n\r\n // TODO: Not ur the reduced systme checking is working properly !\r\n for (let m of P.monoms) {\r\n if (!m.coefficient.isReduced()) {\r\n return false\r\n }\r\n }\r\n\r\n return false\r\n }\r\n\r\n isDeveloped = (polynomString: string): boolean => {\r\n let P: Polynom;\r\n\r\n // Start by removing the parenthis after a \"power\"\r\n let pString = polynomString.replaceAll(/\\^\\(([-0-9/]+)\\)/g, '$1')\r\n\r\n // There is at least one parenthese - it is not developed.\r\n if (pString.includes('(') || pString.includes(')')) {\r\n return false\r\n }\r\n\r\n // Try to build the polynom\r\n try {\r\n // Build the polynom\r\n P = new Polynom(polynomString);\r\n } catch (e) {\r\n return false;\r\n }\r\n\r\n // Both polynom aren't the same (once developed and reduced => they cannot be equivalent)\r\n if (!this.isEqual(P)) {\r\n return false;\r\n }\r\n\r\n // Check that everything is completely developed. Actually, there are no parentheses... so it is fully developed\r\n return true\r\n\r\n // // maybe it wasn't reduced and not ordered...\r\n // // compare polynom string.\r\n //\r\n // // normalize the string\r\n // let polynomStringNormalized = polynomString.replaceAll('[*\\s]', '')\r\n //\r\n // // Determine if it's the exact same string.\r\n // // TODO: Maybe it's enough to just make this test !a\r\n // return polynomStringNormalized === P.reduce().reorder().display\r\n }\r\n\r\n // -------------------------------------\r\n reduce = (): Polynom => {\r\n // Reduce the polynom\r\n let values = [...this._monoms],\r\n vars = [...this.variables]\r\n\r\n this._monoms = []\r\n\r\n let coeffs = values.filter(x => x.variables.length === 0)\r\n\r\n if (coeffs.length > 0) {\r\n this._monoms.push(coeffs.reduce((a, b) => a.add(b)))\r\n }\r\n\r\n // Build the new monoms\r\n for (let letter of vars) {\r\n // Monom with same letters, but might be of different degrees\r\n let M = values.filter(x => x.hasLetter(letter))\r\n\r\n while (M.length > 0) {\r\n // Take the first element\r\n const m = M.shift(), degree = m.degree(letter)\r\n\r\n for (let a of M.filter(x => x.degree(letter).isEqualTo(degree))) {\r\n m.add(a)\r\n }\r\n\r\n this._monoms.push(m)\r\n\r\n // Make the new array.\r\n M = M.filter(x => !x.degree(letter).isEqualTo(degree))\r\n }\r\n // reduce the monom\r\n\r\n }\r\n\r\n // Remove all null monoms\r\n this._monoms = this._monoms.filter((m) => {\r\n return m.coefficient.value !== 0\r\n });\r\n\r\n // Reduce all monoms coefficient.\r\n for (const m of this._monoms) {\r\n m.coefficient.reduce();\r\n }\r\n\r\n if (this.length === 0) {\r\n return new Polynom().zero();\r\n }\r\n return this.reorder();\r\n };\r\n\r\n reorder = (letter: string = 'x', revert?: boolean): Polynom => {\r\n if (revert === undefined) {\r\n revert = false\r\n }\r\n\r\n // TODO: Must handle multiple setLetter reorder system\r\n let otherLetters = this.variables.filter(x => x !== letter)\r\n this._monoms.sort(function (a, b) {\r\n let da = a.degree(letter).value,\r\n db = b.degree(letter).value\r\n\r\n // Values are different\r\n if (da !== db) return revert ? da - db : db - da\r\n\r\n // if values are equals, check other letters - it must be revert in that case !\r\n if (otherLetters.length > 0) {\r\n for (let L of otherLetters) {\r\n let da = a.degree(L).value,\r\n db = b.degree(L).value\r\n\r\n // Values are different\r\n if (da !== db) return revert ? da - db : db - da\r\n }\r\n }\r\n\r\n return 0\r\n // return b.degree(letter).clone().subtract(a.degree(letter)).value\r\n });\r\n\r\n return this;\r\n };\r\n\r\n degree = (letter?: string): Fraction => {\r\n let d: Fraction = new Fraction().zero();\r\n for (const m of this._monoms) {\r\n // d = d.getMax(m.degree(letter).value, d);\r\n d = Fraction.max(m.degree(letter), d);\r\n }\r\n return d;\r\n };\r\n\r\n letters = (): string[] => {\r\n let L: string[] = [], S = new Set();\r\n\r\n for (let m of this._monoms) {\r\n S = new Set([...S, ...m.variables]);\r\n }\r\n\r\n // @ts-ignore\r\n return [...S];\r\n }\r\n\r\n /**\r\n * Replace a variable (letter) by a polynom.\r\n * @param letter\r\n * @param P\r\n */\r\n replaceBy = (letter: string, P: Polynom): Polynom => {\r\n this.mark_as_dirty()\r\n\r\n let pow: Fraction;\r\n const resultPolynom: Polynom = new Polynom().zero();\r\n\r\n for (const m of this.monoms) {\r\n if (m.literal[letter] === undefined || m.literal[letter].isZero()) {\r\n resultPolynom.add(m.clone());\r\n } else {\r\n // We have found a setLetter.\r\n // Get the power and reset it.\r\n pow = m.literal[letter].clone();\r\n delete m.literal[letter];\r\n\r\n // TODO: replaceBy works only with positive and natural pow\r\n resultPolynom.add(P.clone().pow(Math.abs(pow.numerator)).multiply(m));\r\n }\r\n }\r\n\r\n this._monoms = resultPolynom.reduce().reorder().monoms;\r\n return this;\r\n };\r\n\r\n // Evaluate a polynom.\r\n evaluate = (values: literalType | Fraction | number): Fraction => {\r\n const r = new Fraction().zero();\r\n\r\n this._monoms.forEach(monom => {\r\n //console.log('Evaluate polynom: ', monom.display, values, monom.evaluate(values).display);\r\n r.add(monom.evaluate(values));\r\n });\r\n\r\n return r;\r\n };\r\n // ------------------------------------------\r\n // Misc polynoms functions\r\n\r\n evaluateAsNumeric = (values: { [Key: string]: number } | number): number => {\r\n let r = 0\r\n this._monoms.forEach(monom => {\r\n r += monom.evaluateAsNumeric(values)\r\n })\r\n\r\n return r\r\n }\r\n\r\n derivative = (letter?: string): Polynom => {\r\n let dP = new Polynom();\r\n\r\n for (let m of this._monoms) {\r\n dP.add(m.derivative(letter));\r\n }\r\n return dP;\r\n }\r\n\r\n primitive = (letter?: string): Polynom => {\r\n let dP = new Polynom();\r\n\r\n for (let m of this._monoms) {\r\n dP.add(m.primitive(letter))\r\n }\r\n return dP\r\n }\r\n\r\n integrate = (a: Fraction | number, b: Fraction | number, letter?: string): Fraction => {\r\n const primitive = this.primitive(letter)\r\n\r\n if (letter === undefined) {\r\n letter = 'x'\r\n }\r\n\r\n let valuesA: literalType = {},\r\n valuesB: literalType = {}\r\n valuesA[letter] = new Fraction(a);\r\n valuesB[letter] = new Fraction(b);\r\n\r\n return primitive.evaluate(valuesB).subtract(primitive.evaluate(valuesA))\r\n }\r\n\r\n // -------------------------------------\r\n /**\r\n * Factorize a polynom and store the best results in factors.\r\n * @param maxValue Defines the greatest value to search to (default is 20).\r\n */\r\n factorize = (letter?: string): Polynom[] => {\r\n if (!this.dirty_factors) {\r\n return this._factors\r\n }\r\n\r\n let factors: Polynom[] = [];\r\n let P = this.clone().reorder()\r\n\r\n // Extract the common monom\r\n // 2x^3+6x^2 => 2x^2\r\n let M = P.commonMonom()\r\n // If the polynom starts with a negative monom, factorize it.\r\n if (P.monomByDegree().coefficient.isStrictlyNegative() && M.coefficient.isStrictlyPositive() && !M.isOne()) {\r\n M.opposed()\r\n }\r\n\r\n if (!M.isOne()) {\r\n let tempPolynom: Polynom = new Polynom(M)\r\n factors = [tempPolynom.clone()]\r\n P = P.euclidian(tempPolynom).quotient;\r\n }\r\n\r\n // Main loop\r\n let securityLoop = P.degree().clone().multiply(2).value,\r\n maxDegree = 1\r\n while (securityLoop >= 0) {\r\n securityLoop--\r\n if (P.monoms.length < 2) {\r\n // The polynom has only one monom => 7x^2\r\n // No need to continue.\r\n if (!P.isOne()) {\r\n factors.push(P.clone())\r\n P.one()\r\n }\r\n break\r\n } else if (P.degree(letter).isOne()) {\r\n // The polynom is a first degree polynom => 3x-5\r\n // No need to continue\r\n factors.push(P.clone())\r\n P.one()\r\n break\r\n } else {\r\n // Create the list of all \"potential\" polynom dividers.\r\n let allDividers: Polynom[] = this._getAllPotentialFactors(P, maxDegree, letter)\r\n maxDegree = P.degree(letter).value\r\n\r\n // Actually: 100ms\r\n while (allDividers.length > 0) {\r\n let div = allDividers[0]\r\n\r\n if (!P.isDividableBy(div)) {\r\n // Not dividable. Remove it from the list\r\n allDividers.shift()\r\n } else {\r\n // It's dividable - so make the division\r\n let result = P.euclidian(div)\r\n\r\n // Add the factor\r\n factors.push(div)\r\n\r\n // As it's dividable, get the quotient.\r\n P = result.quotient.clone()\r\n\r\n // filter all dividers that are no more suitable.\r\n allDividers = allDividers.filter(x => {\r\n let pX = P.monoms[0],\r\n pC = P.monoms[P.monoms.length - 1],\r\n dX = x.monoms[0],\r\n dC = x.monoms[x.monoms.length - 1]\r\n\r\n // Check last item (degree zero)\r\n if (!pC.isDivisible(dC)) {\r\n return false\r\n }\r\n\r\n // Check the first item (degree max)\r\n if (!pX.isDivisible(dX)) {\r\n return false\r\n }\r\n\r\n return true\r\n })\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Maybe there is still something in the Polynom (not everything was possible to factorize)\r\n if (!P.isOne()) {\r\n factors.push(P.clone())\r\n }\r\n\r\n // Save the factors\r\n this._factors = factors\r\n\r\n // The factors list is no more dirty\r\n this.dirty_factors = false\r\n\r\n return this._factors;\r\n }\r\n\r\n isDividableBy = (div: Polynom): boolean => {\r\n // Quick evaluation.\r\n if (div.degree().isOne()) {\r\n let zero = div.getZeroes()[0]\r\n\r\n if (zero.exact instanceof Fraction) {\r\n return this.evaluate(zero.exact).isZero()\r\n } else {\r\n return false\r\n }\r\n } else {\r\n this.euclidianCache[div.tex] = this.euclidian(div)\r\n return this.euclidianCache[div.tex].reminder.isZero()\r\n }\r\n }\r\n\r\n // TODO: get zeroes for more than first degree and for more than natural degrees\r\n getZeroes = (): ISolution[] => {\r\n if (this.dirty_zeroes) {\r\n let equ = new Equation(this.clone(), 0)\r\n equ.solve()\r\n this._zeroes = equ.solutions\r\n this.dirty_zeroes = false\r\n }\r\n\r\n return this._zeroes\r\n };\r\n\r\n // TODO: analyse the next functions to determine if they are useful or not...\r\n monomByDegree = (degree?: Fraction | number, letter?: string): Monom => {\r\n if (degree === undefined) {\r\n // return the highest degree monom.\r\n return this.monomByDegree(this.degree(letter), letter);\r\n }\r\n\r\n // Reduce the polynom.\r\n const M = this.clone().reduce();\r\n for (const m of M._monoms) {\r\n if (m.degree(letter).isEqualTo(degree)) {\r\n return m.clone();\r\n }\r\n }\r\n\r\n // Nothing was found - return the null monom.\r\n return new Monom().zero();\r\n };\r\n\r\n monomsByDegree = (degree?: number | Fraction, letter?: string): Monom[] => {\r\n if (degree === undefined) {\r\n // return the highest degree monom.\r\n return this.monomsByDegree(this.degree(letter));\r\n }\r\n\r\n // Reduce the polynom.\r\n let Ms: Monom[] = [];\r\n\r\n const M = this.clone().reduce();\r\n for (const m of M._monoms) {\r\n if (m.degree(letter) === degree) {\r\n Ms.push(m.clone())\r\n }\r\n }\r\n\r\n return Ms\r\n // Nothing was found - retur\r\n }\r\n\r\n // Used in LinearSystem.tex\r\n monomByLetter = (letter: string): Monom => {\r\n const M = this.clone().reduce();\r\n for (const m of M._monoms) {\r\n if (m.hasLetter(letter)) {\r\n return m.clone();\r\n }\r\n }\r\n\r\n return new Monom().zero();\r\n };\r\n\r\n // Next functions are used for for commonMonom, which is used in the factorize method.\r\n getDenominators = (): number[] => {\r\n const denominators: number[] = [];\r\n for (const m of this._monoms) {\r\n denominators.push(m.coefficient.denominator);\r\n }\r\n return denominators;\r\n };\r\n // ------------------------------------------\r\n // Polynoms factorization functions\r\n\r\n getNumerators = (): number[] => {\r\n const numerators: number[] = [];\r\n for (const m of this._monoms) {\r\n numerators.push(m.coefficient.numerator);\r\n }\r\n return numerators;\r\n };\r\n\r\n lcmDenominator = (): number => {\r\n return Numeric.lcm(...this.getDenominators());\r\n };\r\n\r\n gcdDenominator = (): number => {\r\n return Numeric.gcd(...this.getDenominators());\r\n };\r\n // ------------------------------------------\r\n // Polynoms helpers functions\r\n // -------------------------------------\r\n\r\n lcmNumerator = (): number => {\r\n return Numeric.lcm(...this.getNumerators());\r\n };\r\n\r\n gcdNumerator = (): number => {\r\n return Numeric.gcd(...this.getNumerators());\r\n };\r\n\r\n commonMonom = (): Monom => {\r\n let M = new Monom().one(), numerator: number, denominator: number, degree = this.degree();\r\n\r\n numerator = this.gcdNumerator();\r\n denominator = this.gcdDenominator();\r\n\r\n M.coefficient = new Fraction(numerator, denominator);\r\n for (let L of this.variables) {\r\n // Initialize the setLetter with the max degree\r\n M.setLetter(L, degree);\r\n for (let m of this._monoms) {\r\n M.setLetter(L, Fraction.min(m.degree(L), M.degree(L)));\r\n if (M.degree(L).isZero()) {\r\n break;\r\n }\r\n }\r\n }\r\n return M;\r\n }\r\n\r\n limitToInfinity = (letter?: string): Fraction => {\r\n const M = this.monomByDegree(undefined, letter),\r\n sign = M.coefficient.sign,\r\n degree = M.degree(letter)\r\n\r\n if (degree.isStrictlyPositive()) {\r\n return sign === 1 ? (new Fraction()).infinite() : (new Fraction()).infinite().opposite()\r\n } else if (degree.isZero()) {\r\n return M.coefficient\r\n }\r\n\r\n // Any other cases\r\n return (new Fraction()).zero()\r\n }\r\n\r\n limitToNegativeInfinity = (letter?: string): Fraction => {\r\n const M = this.monomByDegree(undefined, letter),\r\n sign = M.coefficient.sign,\r\n degree = M.degree(letter)\r\n\r\n if (degree.isStrictlyPositive()) {\r\n return sign === -1 ? (new Fraction()).infinite() : (new Fraction()).infinite().opposite()\r\n } else if (degree.isZero()) {\r\n return M.coefficient\r\n }\r\n\r\n // Any other cases\r\n return (new Fraction()).zero()\r\n }\r\n\r\n hasLetter(letter?: string | undefined): boolean {\r\n return this.monoms.some(M => M.hasLetter(letter));\r\n }\r\n\r\n isDivisible(P: Polynom): boolean {\r\n return this.euclidian(P).reminder.isZero()\r\n }\r\n\r\n isInverted(P: Polynom): boolean {\r\n return this.clone().multiply(P).isOne()\r\n }\r\n\r\n isNotEqual(P: Polynom): boolean {\r\n return !this.isEqual(P);\r\n }\r\n\r\n isNotZero(): boolean {\r\n return !this.isZero();\r\n }\r\n\r\n isOpposed(P: Polynom): boolean {\r\n return this.clone().subtract(P).isZero();\r\n }\r\n\r\n reset(): Polynom {\r\n this._monoms = [];\r\n this._factors = [];\r\n return this\r\n }\r\n\r\n root(value?: number | Fraction): unknown {\r\n return undefined;\r\n }\r\n\r\n private _getAllPotentialFactors = (P: Polynom, maxDegree: number, letter: string): Polynom[] => {\r\n let m1 = P.monoms[0].dividers,\r\n m2 = P.monoms[P.monoms.length - 1].dividers\r\n\r\n let allDividers: Polynom[] = []\r\n m1.forEach(m1d => {\r\n // Get only polynom that has a degree less than a specific value\r\n if (m1d.degree(letter).isLesserOrEqualTo(maxDegree)) {\r\n m2.forEach(m2d => {\r\n if (!m1d.degree(letter).isEqualTo(m2d.degree(letter))) {\r\n allDividers.push(new Polynom(m1d, m2d))\r\n allDividers.push(new Polynom(m1d, m2d.clone().opposed()))\r\n }\r\n })\r\n }\r\n })\r\n\r\n return allDividers\r\n\r\n }\r\n\r\n private _parseString(inputStr: string, ...values: unknown[]): Polynom {\r\n if (values === undefined || values.length === 0) {\r\n inputStr = '' + inputStr;\r\n this._rawString = inputStr.trim().replaceAll(' ', '');\r\n\r\n // Parse the polynom using the shutting yard algorithm\r\n if (inputStr !== '' && !isNaN(Number(inputStr))) {\r\n this.empty();\r\n // It's a simple number.\r\n let m = new Monom(inputStr);\r\n // m.coefficient = new Fraction(inputStr);\r\n // m.literalStr = '';\r\n this.add(m);\r\n return this;\r\n }\r\n\r\n // Parse the string.\r\n return this.shutingYardToReducedPolynom(inputStr);\r\n } else if (/^[a-z]/.test(inputStr)) {\r\n // We assume the inputStr contains only letters.\r\n this.empty();\r\n\r\n let fractions = values.map(x => new Fraction(x as string));\r\n // Multiple setLetter version\r\n if (inputStr.length > 1) {\r\n // TODO: check that the number of values given correspond to the letters (+1 eventually)\r\n let letters = inputStr.split(''),\r\n i = 0;\r\n for (let F of fractions) {\r\n let m = new Monom();\r\n m.coefficient = F.clone();\r\n m.literalStr = letters[i] || '';\r\n this.add(m);\r\n i++;\r\n }\r\n }\r\n // Single setLetter version\r\n else {\r\n let n = fractions.length - 1;\r\n for (let F of fractions) {\r\n let m = new Monom()\r\n m.coefficient = F.clone();\r\n m.literalStr = `${inputStr}^${n}`\r\n this.add(m);\r\n n--;\r\n }\r\n }\r\n return this;\r\n } else {\r\n return this.zero();\r\n }\r\n }\r\n\r\n private genDisplay = (output?: string, forceSign?: boolean, wrapParentheses?: boolean, withAllMultSign?: boolean): string => {\r\n let P: string = '';\r\n\r\n for (const k of this._monoms) {\r\n if (k.coefficient.value === 0) {\r\n continue;\r\n }\r\n\r\n // The monom to be displayed\r\n let m\r\n if (withAllMultSign) {\r\n m = k.plotFunction\r\n } else {\r\n m = (output === 'tex') ? k.tex : k.display\r\n }\r\n\r\n P += `${(k.coefficient.sign === 1 && (P !== '' || forceSign === true)) ? '+' : ''}${m}`;\r\n }\r\n\r\n if (wrapParentheses === true && this.length > 1) {\r\n if (output === 'tex') {\r\n P = `\\\\left( ${P} \\\\right)`;\r\n } else {\r\n P = `(${P})`;\r\n }\r\n }\r\n\r\n if (P === '') {\r\n P = '0';\r\n }\r\n return P;\r\n };\r\n\r\n /**\r\n * Main parse using a shutting yard class\r\n * @param inputStr\r\n */\r\n private shutingYardToReducedPolynom = (inputStr: string): Polynom => {\r\n // Get the RPN array of the current expression\r\n const SY: Shutingyard = new Shutingyard().parse(inputStr);\r\n const rpn: { token: string, tokenType: string }[] = SY.rpn;\r\n\r\n // New version for reducing shuting yard.\r\n this.zero()\r\n\r\n let stack: Polynom[] = [],\r\n monom: Monom = new Monom()\r\n\r\n // Loop through the\r\n for (const element of rpn) {\r\n this.addToken(stack, element);\r\n }\r\n\r\n if (stack.length === 1) {\r\n this.add(stack[0])\r\n }\r\n\r\n return this.reorder()\r\n }\r\n\r\n private multiplyByPolynom = (P: Polynom): Polynom => {\r\n const M: Monom[] = [];\r\n for (const m1 of this._monoms) {\r\n for (const m2 of P.monoms) {\r\n M.push(Monom.xmultiply(m1, m2));\r\n }\r\n }\r\n\r\n this._monoms = M;\r\n return this.reduce();\r\n };\r\n\r\n private multiplyByFraction = (F: Fraction): Polynom => {\r\n for (const m of this._monoms) {\r\n m.coefficient.multiply(F);\r\n }\r\n\r\n return this.reduce();\r\n };\r\n\r\n private multiplyByInteger = (nb: number): Polynom => {\r\n return this.multiplyByFraction(new Fraction(nb));\r\n };\r\n\r\n private multiplyByMonom = (M: Monom): Polynom => {\r\n for (const m of this._monoms) {\r\n m.multiply(M)\r\n }\r\n return this.reduce();\r\n };\r\n\r\n private divideByInteger = (nb: number): Polynom => {\r\n const nbF = new Fraction(nb);\r\n for (const m of this._monoms) {\r\n m.coefficient.divide(nbF);\r\n }\r\n return this;\r\n };\r\n\r\n private divideByFraction = (F: Fraction): Polynom => {\r\n for (const m of this._monoms) {\r\n m.coefficient.divide(F);\r\n }\r\n return this;\r\n };\r\n\r\n private _factorize2ndDegree = (letter: string): Polynom[] => {\r\n let P1: Polynom, P2: Polynom,\r\n a, b, c, delta, x1, x2, factor;\r\n\r\n // One variable only\r\n if (this.numberOfVars === 1) {\r\n a = this.monomByDegree(2, letter).coefficient;\r\n b = this.monomByDegree(1, letter).coefficient;\r\n c = this.monomByDegree(0, letter).coefficient;\r\n delta = b.clone().pow(2).subtract(a.clone().multiply(c).multiply(4));\r\n\r\n if (delta.isZero()) {\r\n x1 = b.clone().opposite().divide(a.clone().multiply(2))\r\n P1 = new Polynom(letter).subtract(x1.display).multiply(x1.denominator)\r\n P2 = new Polynom(letter).subtract(x1.display).multiply(x1.denominator)\r\n factor = a.divide(x1.denominator).divide(x1.denominator);\r\n\r\n if (!factor.isOne()) {\r\n // TODO: Update new Polynom to accept anything...\r\n return [new Polynom(factor.display), P1, P2]\r\n } else {\r\n return [P1, P2]\r\n }\r\n } else if (delta.isPositive() && delta.isSquare()) {\r\n x1 = b.clone().opposite()\r\n .add(delta.clone().sqrt())\r\n .divide(a.clone().multiply(2))\r\n x2 = b.clone().opposite()\r\n .subtract(delta.clone().sqrt())\r\n .divide(a.clone().multiply(2))\r\n\r\n // (2x+5)(3x-2)\r\n // 6x^2+11x-10\r\n // a = 6, b = 11, c = -10\r\n // delta = 121-4*6*(-10) = 361= 19^2\r\n // x1 = (-11 + 19) / 12 = 8/12 = 2/3\r\n // x2 = (-11 - 19) / 12 = -30/12 = -5/2\r\n factor = a.divide(x1.denominator).divide(x2.denominator);\r\n if (factor.isOne()) {\r\n return [\r\n new Polynom(letter).subtract(x1.display).multiply(x1.denominator),\r\n new Polynom(letter).subtract(x2.display).multiply(x2.denominator),\r\n ]\r\n } else {\r\n return [\r\n new Polynom(factor.display),\r\n new Polynom(letter).subtract(x1.display).multiply(x1.denominator),\r\n new Polynom(letter).subtract(x2.display).multiply(x2.denominator),\r\n ]\r\n\r\n }\r\n } else {\r\n // No solution possible - return the complete value.\r\n return [this.clone()]\r\n }\r\n } else {\r\n // If multiple variables, only handle perfect squares...\r\n a = this.monomByDegree(2, letter);\r\n b = this.monomByDegree(1, letter);\r\n c = this.monomByDegree(0, letter);\r\n\r\n\r\n if (a.isLiteralSquare() && c.isLiteralSquare()) {\r\n // Check the middle item is same as...\r\n if (b.clone().pow(2).isSameAs(a.clone().multiply(c))) {\r\n // Determine if the coefficient values matches.\r\n\r\n // Search 4 values (r, s, t, u) that matches:\r\n // (r X + s Y)(t X + u Y) = rt X^2 + (ru + st) XY + su Y^2\r\n\r\n let xPolynom = new Polynom('x', a.coefficient, b.coefficient, c.coefficient);\r\n let xFactors = xPolynom._factorize2ndDegree('x');\r\n\r\n let factors = [], xyzPolynom: Polynom;\r\n\r\n if (xFactors.length >= 2) {\r\n for (let p of xFactors) {\r\n if (p.degree().isZero()) {\r\n factors.push(p.clone())\r\n } else {\r\n xyzPolynom = p.clone();\r\n xyzPolynom.monoms[0].literal = a.literalSqrt\r\n xyzPolynom.monoms[1].literal = c.literalSqrt\r\n factors.push(xyzPolynom.clone())\r\n }\r\n }\r\n return factors\r\n }\r\n }\r\n }\r\n\r\n return [this.clone()]\r\n }\r\n }\r\n\r\n private _factorizeByGroups = (): Polynom[] => {\r\n // TODO: Factorize by groups.\r\n return [];\r\n }\r\n}\r\n
|
|
5
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
6
|
+
<+>UTF-8
|
|
7
|
+
===================================================================
|
|
8
|
+
diff --git a/src/maths/algebra/polynom.ts b/src/maths/algebra/polynom.ts
|
|
9
|
+
--- a/src/maths/algebra/polynom.ts
|
|
10
|
+
+++ b/src/maths/algebra/polynom.ts
|
|
11
|
+
@@ -309,7 +309,8 @@
|
|
12
|
+
// Only allow power if the previous polynom is only a monom, without coefficient.
|
|
13
|
+
if (a.monoms.length === 1 && a.monoms[0].coefficient.isOne()) {
|
|
14
|
+
for (let letter in a.monoms[0].literal) {
|
|
15
|
+
- a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient)
|
|
16
|
+
+ // TODO: make sure the coefficeint is a Fraction
|
|
17
|
+
+ a.monoms[0].literal[letter].multiply(b.monoms[0].coefficient as Fraction)
|
|
18
|
+
}
|
|
19
|
+
stack.push(a)
|
|
20
|
+
} else {
|
|
21
|
+
@@ -545,7 +546,8 @@
|
|
22
|
+
return this.divide(new Polynom(value))
|
|
23
|
+
} else if (value instanceof Polynom) {
|
|
24
|
+
if (value.monoms.length === 1 && value.variables.length === 0) {
|
|
25
|
+
- return this.divideByFraction(value.monoms[0].coefficient)
|
|
26
|
+
+ // TODO: Make sure the coefficient is a Fraction
|
|
27
|
+
+ return this.divideByFraction(value.monoms[0].coefficient as Fraction)
|
|
28
|
+
} else {
|
|
29
|
+
let {quotient, reminder} = this.euclidian(value)
|
|
30
|
+
if (reminder.isZero()) {
|
|
31
|
+
@@ -711,7 +713,8 @@
|
|
32
|
+
pFactor = p.clone().divide(k)
|
|
33
|
+
|
|
34
|
+
if (k.degree().isZero()) {
|
|
35
|
+
- FactorizedConstant.multiply(k.coefficient)
|
|
36
|
+
+ // TODO: Make sur the coefficient is a Fraction
|
|
37
|
+
+ FactorizedConstant.multiply(k.coefficient as Fraction)
|
|
38
|
+
polyFactors.push(pFactor.clone())
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
@@ -902,7 +905,7 @@
|
|
42
|
+
let d: Fraction = new Fraction().zero();
|
|
43
|
+
for (const m of this._monoms) {
|
|
44
|
+
// d = d.getMax(m.degree(letter).value, d);
|
|
45
|
+
- d = Fraction.max(m.degree(letter), d);
|
|
46
|
+
+ d = Fraction.max(m.degree(letter), d) as Fraction;
|
|
47
|
+
}
|
|
48
|
+
return d;
|
|
49
|
+
};
|
|
50
|
+
Index: src/maths/algebra/monom.ts
|
|
51
|
+
IDEA additional info:
|
|
52
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
53
|
+
<+>/***\r\n * Monom class\r\n * The monom class represents of monom of the form:\r\n * k * x^n * y^m * z^p\r\n * k: Coefficient\r\n * n, m, p: powers as Fraction\r\n * x, y, z: letters as string\r\n */\r\nimport {Numeric} from \"../numeric\";\r\nimport {Shutingyard, ShutingyardType, Token} from \"../shutingyard\";\r\nimport {COMPARESIGNS, literalType} from \"../types\";\r\nimport {RootFraction} from \"../coefficients/rootFraction\";\r\nimport {\r\n COEFFICIENT_MODE,\r\n CoefficientCore,\r\n CoefficientParserTypes,\r\n CoefficientTypes\r\n} from \"../coefficients/coefficientCore\";\r\nimport {Fraction} from \"../coefficients/fraction\";\r\n\r\n\r\nexport class Monom {\r\n private _coefficientMode: COEFFICIENT_MODE\r\n\r\n /**\r\n * Create a Monom\r\n * Defined as \\\\(k \\\\cdot x^{n}\\\\), where \\\\( k,n \\in \\\\mathbb{Q}\\\\).\r\n * Examples: \\\\(3x^2\\\\) or \\\\(3/5x^2\\\\)\r\n * @param value (optional) string The value that should be parse. Can be a Monom, a Fraction, a string or a number. If nothing is provided, it will return the trivial monom (0).\r\n */\r\n constructor(value?: unknown) {\r\n this.zero();\r\n\r\n if (value !== undefined) {\r\n // A string is given - try to parse the value.\r\n this.parse(value);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n // ------------------------------------------\r\n // Getter and setter\r\n\r\n private _coefficient: CoefficientCore<any>;\r\n\r\n // ------------------------------------------\r\n /**\r\n * Get the coefficient \\\\(k\\\\) of the Monom \\\\(k\\\\cdot x^{n}\\\\)\r\n * @returns {Fraction}\r\n */\r\n get coefficient(): CoefficientCore<any> {\r\n return this._coefficient;\r\n }\r\n\r\n /**\r\n * Set the coefficient \\\\(k\\\\) value of the monom\r\n * @param {Fraction | number | string} F\r\n */\r\n set coefficient(F: CoefficientParserTypes) {\r\n this._coefficient = this.makeCoefficient(F);\r\n }\r\n\r\n private _literal: literalType;\r\n\r\n /**\r\n * Get the literal part of \\\\(x^{n_1}y^{n_2}\\\\) as dictionary \\\\[\\\\begin{array}{ll}x&=n_1\\\\\\\\y&=n_2\\\\end{array}\\\\]\r\n * @returns {literalType}\r\n */\r\n get literal(): literalType {\r\n return this._literal;\r\n }\r\n\r\n /**\r\n * Set the literal part of the monom. Must be a dictionary {x: Fraction, y: Fraction, ...}\r\n * @param {literalType} L\r\n */\r\n set literal(L: literalType) {\r\n this._literal = L;\r\n }\r\n\r\n /**\r\n * Get the literal square roots of the Monom.\r\n * TODO: remove this getter ? Is it used and is it correct ?\r\n * @returns {literalType}\r\n */\r\n get literalSqrt(): literalType {\r\n if (this.isLiteralSquare()) {\r\n let L: literalType = {}\r\n for (let key in this._literal) {\r\n L[key] = this._literal[key].clone().sqrt()\r\n }\r\n return L;\r\n } else {\r\n return this._literal;\r\n }\r\n }\r\n\r\n /**\r\n * Set the literal part of the monom from a string\r\n * @param inputStr String like x^2y^3\r\n */\r\n set literalStr(inputStr: string) {\r\n // TODO : parse using shutingyard tree !\r\n\r\n // Match all x^n\r\n for (const v of [...inputStr.matchAll(/([a-z])\\^([+-]?[0-9]+)/g)]) {\r\n // Create the default letter entry if necessary.\r\n if (!(v[1] in this._literal)) {\r\n this._literal[v[1]] = this.makeCoefficient().zero();\r\n }\r\n\r\n // Add the new value.\r\n // TODO: actually, it adds only numeric value\r\n this._literal[v[1]].add(+v[2]);\r\n }\r\n\r\n // Match all x\r\n for (const v of [...inputStr.matchAll(/([a-z](?!\\^))/g)]) {\r\n // Match all single letters\r\n if (!(v[1] in this._literal)) {\r\n this._literal[v[1]] = this.makeCoefficient().zero();\r\n }\r\n\r\n // Add one to the value.\r\n this._literal[v[1]].add(1)\r\n }\r\n }\r\n\r\n // Getter helpers.\r\n /**\r\n * Get the variables letters\r\n */\r\n get variables(): string[] {\r\n let M = this.clone().clean();\r\n return Object.keys(M.literal)\r\n }\r\n\r\n // Display getter\r\n /**\r\n * This display getter is to be used in the polynom display getter\r\n */\r\n get display(): string {\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += `${letter}`;\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^(${this._literal[letter].display})`;\r\n }\r\n }\r\n }\r\n\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.display}`;\r\n } else {\r\n return '';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.display}${L}`;\r\n }\r\n }\r\n }\r\n\r\n get dividers(): Monom[] {\r\n // Decompose only if the coefficient is a natural number\r\n if (!this.coefficient.isRelative()) {\r\n return [this.clone()]\r\n }\r\n\r\n\r\n // Decompose only if the power values are natural numbers.\r\n if (this.hasFractionCoefficient()) {\r\n return [this.clone()]\r\n }\r\n\r\n // Security : do not do this if isGreaterThan than 10000\r\n if (this.coefficient.numerator > 1000000) {\r\n return [this.clone()]\r\n }\r\n\r\n const dividers = Numeric.dividers(Math.abs(this.coefficient.numerator))\r\n\r\n // Decompose the literals parts.\r\n let literals: literalType[] = [];\r\n for (let L in this.literal) {\r\n // L is the letter.\r\n literals = this._getLiteralDividers(literals, L)\r\n }\r\n\r\n const monomDividers: Monom[] = [];\r\n if (literals.length > 0 && dividers.length > 0) {\r\n for (let N of dividers) {\r\n for (let L of literals) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient(N)\r\n M.literal = L\r\n monomDividers.push(M)\r\n }\r\n }\r\n } else if (dividers.length === 0) {\r\n for (let L of literals) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient().one()\r\n M.literal = L\r\n monomDividers.push(M)\r\n }\r\n } else {\r\n for (let N of dividers) {\r\n let M = new Monom();\r\n M.coefficient = this.makeCoefficient(N)\r\n monomDividers.push(M)\r\n }\r\n }\r\n\r\n return monomDividers.length === 0 ? [new Monom().one()] : monomDividers;\r\n }\r\n\r\n /**\r\n * Display the monom, forcing the '+' sign to appear\r\n */\r\n get displayWithSign(): string {\r\n let d: String = this.display;\r\n return (d[0] !== '-' ? '+' : '') + d;\r\n }\r\n\r\n get texWithSign(): string {\r\n if (this.coefficient.isStrictlyPositive()) {\r\n return '+' + this.tex\r\n }\r\n\r\n return this.tex\r\n }\r\n\r\n get plotFunction(): string {\r\n\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += (L === '' ? \"\" : \"*\") + `${letter}`\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^(${this._literal[letter].display})`;\r\n }\r\n }\r\n }\r\n\r\n // No literal part\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.display}`;\r\n } else {\r\n return '';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.display}*${L}`;\r\n }\r\n }\r\n }\r\n\r\n // ------------------------------------------\r\n // Creation / parsing functions\r\n\r\n /**\r\n * Get the tex output of the monom\r\n */\r\n get tex(): string {\r\n // TODO: display with square root !\r\n let L: string = '',\r\n letters = Object.keys(this._literal).sort()\r\n\r\n for (let letter of letters) {\r\n if (!this._literal[letter].isZero()) {\r\n L += `${letter}`;\r\n if (!this._literal[letter].isEqualTo(1)) {\r\n L += `^{${this._literal[letter].asTopFraction().tex}}`;\r\n }\r\n }\r\n }\r\n\r\n if (L === '') {\r\n // No setLetter - means it's only a number !\r\n if (this._coefficient.value != 0) {\r\n return `${this._coefficient.tex}`;\r\n } else {\r\n return '0';\r\n }\r\n } else {\r\n if (this._coefficient.value === 1) {\r\n return L;\r\n } else if (this._coefficient.value === -1) {\r\n return `-${L}`;\r\n } else if (this._coefficient.value === 0) {\r\n return '0';\r\n } else {\r\n return `${this._coefficient.tex}${L}`;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get the least common multiple of monoms\r\n * @param monoms Array of monoms\r\n */\r\n static lcm = (...monoms: Monom[]): Monom => {\r\n // All the monoms must be with natural powers...\r\n for (let m of monoms) {\r\n if (m.hasFractionCoefficient()) {\r\n return new Monom().zero()\r\n }\r\n }\r\n\r\n\r\n let M = new Monom(),\r\n coeffN: number[] = monoms.map(value => value.coefficient.numerator),\r\n coeffD: number[] = monoms.map(value => value.coefficient.denominator),\r\n n = Numeric.gcd(...coeffN),\r\n d = Numeric.lcm(...coeffD);\r\n\r\n // Get the coefficient.\r\n M.coefficient = this.makeCoefficient(n, d).reduce();\r\n\r\n // Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.\r\n for (let m of monoms) {\r\n // Remove the inexistant letters from the resulting monom\r\n for (let letter in M.literal) {\r\n if (!(letter in m.literal)) {\r\n M.literal[letter].zero();\r\n }\r\n }\r\n for (let letter in m.literal) {\r\n if (M.literal[letter] === undefined && m.literal[letter].isStrictlyPositive()) {\r\n M.literal[letter] = m.literal[letter].clone();\r\n } else {\r\n M.literal[letter] = this.makeCoefficient(Math.min(m.literal[letter].value, M.literal[letter].value))\r\n }\r\n }\r\n }\r\n\r\n return M;\r\n };\r\n\r\n /**\r\n * Multiply two monoms and return a NEW monom.\r\n * @param monoms\r\n */\r\n static xmultiply = (...monoms: Monom[]): Monom => {\r\n let M = new Monom().one();\r\n\r\n for (let m of monoms) {\r\n M.multiply(m);\r\n }\r\n\r\n return M;\r\n };\r\n\r\n makeCoefficient = (...values: CoefficientParserTypes[]): CoefficientTypes => {\r\n if (this._coefficientMode === COEFFICIENT_MODE.FRACTION) {\r\n return new Fraction(...values as (Fraction | string | number)[])\r\n } else if (this._coefficientMode === COEFFICIENT_MODE.ROOT) {\r\n return new RootFraction(...values as (RootFraction | Fraction | string | number)[])\r\n }\r\n\r\n // TODO: add the other modes\r\n return new Fraction(...values as (Fraction | string | number)[])\r\n }\r\n\r\n// -----------------------------------------\r\n /**\r\n * Parse a string to a monom. The string may include fraction.\r\n * @param inputStr\r\n */\r\n parse = (inputStr: unknown): Monom => {\r\n\r\n if (typeof inputStr === 'string') {\r\n this._shutingYardToReducedMonom(inputStr)\r\n } else if (typeof inputStr === 'number') {\r\n this._coefficient = this.makeCoefficient(inputStr)\r\n this._literal = {}\r\n } else if (inputStr instanceof Fraction) {\r\n this._coefficient = inputStr.clone()\r\n this._literal = {}\r\n } else if (inputStr instanceof RootFraction) {\r\n this._coefficient = inputStr.clone()\r\n this._literal = {}\r\n } else if (inputStr instanceof Monom) {\r\n this._coefficient = inputStr._coefficient.clone()\r\n this._literal = this.copyLiterals(inputStr.literal)\r\n }\r\n\r\n return this;\r\n };\r\n\r\n addToken = (stack: Monom[], element: Token): void => {\r\n\r\n let q1: Monom, q2: Monom, m: Monom, letter: string, pow: CoefficientCore<any>\r\n\r\n if (element.tokenType === ShutingyardType.COEFFICIENT) {\r\n stack.push(new Monom(this.makeCoefficient(element.token)))\r\n\r\n } else if (element.tokenType === ShutingyardType.VARIABLE) {\r\n let M = new Monom().one()\r\n M.setLetter(element.token, 1)\r\n stack.push(M.clone())\r\n\r\n } else if (element.tokenType === ShutingyardType.OPERATION) {\r\n switch (element.token) {\r\n case '-':\r\n // this should only happen for negative powers or for negative coefficient.\r\n q2 = (stack.pop()) || new Monom().zero()\r\n q1 = (stack.pop()) || new Monom().zero()\r\n\r\n stack.push(q1.subtract(q2))\r\n\r\n break;\r\n case '*':\r\n // Get the last element in the stack\r\n q2 = (stack.pop()) || new Monom().one()\r\n q1 = (stack.pop()) || new Monom().one()\r\n\r\n stack.push(q1.multiply(q2))\r\n break\r\n case '/':\r\n // Get the last element in the stack\r\n q2 = (stack.pop()) || new Monom().one()\r\n q1 = (stack.pop()) || new Monom().one()\r\n\r\n stack.push(q1.divide(q2))\r\n break\r\n case '^':\r\n // get the two last elements in the stack\r\n pow = (stack.pop().coefficient) || this.makeCoefficient().one()\r\n m = (stack.pop()) || new Monom().one()\r\n\r\n letter = m.variables[0]\r\n\r\n if (letter !== undefined) {\r\n m.setLetter(letter, pow)\r\n }\r\n\r\n stack.push(m)\r\n // this.multiply(m.clone())\r\n break\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Clone the current Monom.\r\n */\r\n clone = (): Monom => {\r\n let F: Monom = new Monom();\r\n\r\n F.coefficient = this._coefficient.clone();\r\n\r\n // Copy the literal parts.\r\n for (let k in this._literal) {\r\n F.setLetter(k, this._literal[k].clone());\r\n }\r\n return F;\r\n };\r\n\r\n copyLiterals = (literal: literalType): literalType => {\r\n let L: literalType = {}\r\n\r\n for (let k in literal) {\r\n L[k] = literal[k].clone()\r\n }\r\n return L\r\n }\r\n\r\n makeSame = (M: Monom): Monom => {\r\n // Copy the literal parts.\r\n for (let k in M._literal) {\r\n this.setLetter(k, M._literal[k].clone());\r\n }\r\n return this\r\n }\r\n\r\n /**\r\n * Create a zero value monom\r\n */\r\n zero = (): Monom => {\r\n this._coefficient = this.makeCoefficient().zero();\r\n this._literal = {};\r\n return this;\r\n };\r\n\r\n /**\r\n * Create a one value monom\r\n */\r\n one = (): Monom => {\r\n this._coefficient = this.makeCoefficient().one();\r\n this._literal = {};\r\n return this;\r\n };\r\n\r\n// ------------------------------------------\r\n// Mathematical operations\r\n// ------------------------------------------\r\n\r\n /**\r\n * Clean the monom by removing each letters with a power of zero.\r\n */\r\n clean = (): Monom => {\r\n for (let letter in this._literal) {\r\n if (this._literal[letter].isZero()) {\r\n delete this._literal[letter];\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n reduce = (): Monom => {\r\n this.clean()\r\n this.coefficient.reduce()\r\n return this\r\n }\r\n\r\n /**\r\n * Get the opposite\r\n * Returns a monom.\r\n */\r\n opposed = (): Monom => {\r\n this._coefficient.opposite();\r\n return this;\r\n };\r\n\r\n /**\r\n * Add all similar monoms. If they aren't similar, they are simply skipped.\r\n * @param M (Monom[]) The monoms to add.\r\n */\r\n add = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n if (this.isSameAs(m)) {\r\n if (this.isZero()) {\r\n this.makeSame(m)\r\n }\r\n this._coefficient.add(m.coefficient);\r\n } else {\r\n console.log('Add monom: ' + this.display + ' is not similar with ', m.display);\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Subtract multiple monoms\r\n * @param M (Monom[]) The monoms to subtract\r\n */\r\n subtract = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n if (this.isSameAs(m)) {\r\n if (this.isZero()) {\r\n this.makeSame(m)\r\n }\r\n this._coefficient.add(m.clone().coefficient.opposite());\r\n } else {\r\n console.log('Subtract: Is not similar: ', m.display);\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Multiple multiple monoms to the current monom\r\n * @param M (Monom[]) The monoms to multiply to.\r\n */\r\n multiply = (...M: Monom[]): Monom => {\r\n for (let m of M) {\r\n // Multiply the coefficient.\r\n this._coefficient.multiply(m.coefficient);\r\n\r\n // Multiply the literal parts.\r\n for (let letter in m.literal) {\r\n if (this._literal[letter] === undefined) {\r\n this._literal[letter] = m.literal[letter].clone()\r\n } else {\r\n this._literal[letter].add(m.literal[letter])\r\n }\r\n\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n multiplyByNumber = (F: Fraction | number): Monom => {\r\n this._coefficient.multiply(F);\r\n return this;\r\n }\r\n\r\n /**\r\n * Divide the current monoms by multiple monoms\r\n * @param M (Monom[])\r\n */\r\n divide = (...M: Monom[]): Monom => {\r\n // Depending on the given value, choose the current item\r\n for (let v of M) {\r\n // Divide the coefficient\r\n this._coefficient.divide(v.coefficient);\r\n\r\n // Subtract the power values\r\n for (let letter in v.literal) {\r\n this._literal[letter] = (this._literal[letter] === undefined) ? v.literal[letter].clone().opposite() : this._literal[letter].subtract(v.literal[letter])\r\n\r\n // If the power of a particular setLetter is zero, delete it from the literal part..\r\n if (this._literal[letter].isZero()) {\r\n delete this._literal[letter];\r\n }\r\n }\r\n }\r\n return this;\r\n };\r\n\r\n /**\r\n * Get the pow of a monom.\r\n * @param nb (number) : Mathematical pow\r\n */\r\n pow = (nb: number | Fraction): Monom => {\r\n this._coefficient.pow(nb);\r\n for (let letter in this._literal) {\r\n this._literal[letter].multiply(nb)\r\n }\r\n return this;\r\n };\r\n\r\n// ------------------------------------------\r\n// Compare functions\r\n\r\n /**\r\n * Get the index-root of the monom\r\n * @param p\r\n */\r\n root = (p: number): Monom => {\r\n // TODO: determiner the index root of a monom\r\n return this;\r\n }\r\n\r\n /**\r\n * Return the square root of a monom\r\n */\r\n sqrt = (): Monom => {\r\n if (this.isSquare()) {\r\n this._coefficient.sqrt();\r\n for (let letter in this._literal) {\r\n this._literal[letter].clone().divide(2)\r\n }\r\n }\r\n return this.root(2);\r\n }\r\n\r\n// ------------------------------------------\r\n compare = (M: Monom, sign?: COMPARESIGNS): boolean => {\r\n // TODO: Build the compare systems.\r\n if (sign === undefined) {\r\n sign = COMPARESIGNS.EQUALS;\r\n }\r\n\r\n\r\n switch (sign) {\r\n case COMPARESIGNS.EQUALS:\r\n // To be equal, they must be the isSame\r\n if (!this.compare(M, COMPARESIGNS.SAME)) {\r\n return false;\r\n }\r\n\r\n // The literal parts are the isSame. The coefficient must be equal\r\n return this._coefficient.isEqualTo(M.coefficient);\r\n case COMPARESIGNS.SAME:\r\n // Get the list of all variables from both monoms.\r\n let M1: string[] = this.variables,\r\n M2: string[] = M.variables,\r\n K: string[] = M1.concat(M2.filter((item) => M1.indexOf(item) < 0));\r\n\r\n if (M1.length === 0 && M2.length === 0) {\r\n return true\r\n }\r\n // To compare, both must be different than zero.\r\n if (!this.isZero() && !M.isZero()) {\r\n for (let key of K) {\r\n // The setLetter is not available in one of the monom\r\n if (this._literal[key] === undefined || M.literal[key] === undefined) {\r\n return false;\r\n }\r\n // The setLetter does not have the isSame power in each monoms.\r\n if (!this._literal[key].isEqualTo(M.literal[key])) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n // All are positive check - the monoms are the sames.\r\n return true;\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Determine if the monom is null\r\n */\r\n isZero()\r\n :\r\n boolean {\r\n return this._coefficient.value === 0;\r\n }\r\n\r\n /**\r\n * Determine if the monom is one\r\n */\r\n isOne()\r\n :\r\n boolean {\r\n return this._coefficient.value === 1 && this.variables.length === 0;\r\n }\r\n\r\n /**\r\n * Determine if two monoms are equals\r\n * @param M\r\n */\r\n isEqual = (M: Monom): boolean => {\r\n return this.compare(M, COMPARESIGNS.EQUALS);\r\n };\r\n\r\n /**\r\n * Determine if two monoms are similar\r\n * @param M\r\n */\r\n isSameAs = (M: Monom): boolean => {\r\n return this.compare(M, COMPARESIGNS.SAME);\r\n };\r\n\r\n isSquare = (): boolean => {\r\n if (!this.coefficient.isSquare()) {\r\n return false;\r\n }\r\n return this.isLiteralSquare();\r\n }\r\n// ------------------------------------------\r\n// Misc monoms functions\r\n\r\n isLiteralSquare = (): boolean => {\r\n for (let letter in this.literal) {\r\n // A literal square must have a natural power\r\n if (this.literal[letter].isRational()) {\r\n return false\r\n }\r\n\r\n // The natural power must be be even\r\n if (this.literal[letter].isEven()) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n hasFractionCoefficient = (): boolean => {\r\n for (let letter in this._literal) {\r\n if (this._literal[letter].isRational()) {\r\n return true\r\n }\r\n }\r\n\r\n return false\r\n }\r\n\r\n// -------------------------------------\r\n /**\r\n * Determine if a monom contains a setLetter in it's literal part\r\n * @param letter\r\n */\r\n hasLetter = (letter?: string): boolean => {\r\n // The letter was not found\r\n if (this._literal[letter === undefined ? 'x' : letter] === undefined) {\r\n return false\r\n }\r\n\r\n // The letter is found and is not zero !\r\n return !this._literal[letter === undefined ? 'x' : letter].isZero();\r\n };\r\n\r\n /**\r\n * Set the power of a particular setLetter\r\n * @param letter (string) Letter to change\r\n * @param pow (number) Power of the setLetter (must be positive integer.\r\n */\r\n setLetter = (letter: string, pow: CoefficientCore<any> | number): void => {\r\n if (pow instanceof CoefficientCore) {\r\n // Set the power of the letter to zero => remove it\r\n if (this.hasLetter(letter) && pow.isZero()) {\r\n delete this._literal[letter]\r\n }\r\n\r\n this._literal[letter] = pow.clone()\r\n } else {\r\n this.setLetter(letter, this.makeCoefficient(pow))\r\n }\r\n };\r\n\r\n /**\r\n * Get the degree of a monom. If no setLetter is given, the result will be the global degree.\r\n * @param letter (string) Letter to get to degree (power)\r\n */\r\n degree = (letter?: string): CoefficientTypes => {\r\n if (this.variables.length === 0) {\r\n return this.makeCoefficient().zero();\r\n }\r\n if (letter === undefined) {\r\n // Not setLetter given -> we get the global monom degree (sum of all the letters).\r\n return Object.values(this._literal)\r\n .reduce(\r\n (t, n) => t.clone().add(n)\r\n );\r\n } else {\r\n // A setLetter is given -> get the corresponding power.\r\n return this._literal[letter] === undefined ? this.makeCoefficient().zero() : this._literal[letter].clone();\r\n }\r\n };\r\n\r\n /**\r\n * Evaluate a monom. Each setLetter must be assigned to a Fraction.\r\n * @param values Dictionary of <setLetter: Fraction>\r\n */\r\n evaluate = (values?: literalType | Fraction | number): CoefficientCore<any> => {\r\n let r = this.coefficient.clone();\r\n\r\n if (typeof values === 'number' || values instanceof Fraction) {\r\n let tmpValues: literalType = {}\r\n tmpValues[this.variables[0]] = this.makeCoefficient(values)\r\n return this.evaluate(tmpValues);\r\n }\r\n\r\n if (typeof values === 'object') {\r\n if (this.variables.length === 0) {\r\n return this.coefficient\r\n }\r\n for (let L in this._literal) {\r\n if (values[L] === undefined) {\r\n return this.makeCoefficient().zero();\r\n }\r\n\r\n let value = this.makeCoefficient(values[L])\r\n\r\n r.multiply(value.pow(this._literal[L]))\r\n }\r\n }\r\n\r\n return r;\r\n };\r\n\r\n evaluateAsNumeric = (values: { [Key: string]: number } | number): number => {\r\n let r = this.coefficient.value\r\n\r\n if (typeof values === 'number') {\r\n let tmpValues: { [Key: string]: number } = {}\r\n tmpValues[this.variables[0]] = values\r\n return this.evaluateAsNumeric(tmpValues);\r\n }\r\n\r\n if (typeof values === 'object') {\r\n if (this.variables.length === 0) {\r\n return this.coefficient.value\r\n }\r\n for (let L in this._literal) {\r\n if (values[L] === undefined) {\r\n return 0;\r\n }\r\n\r\n r *= values[L] ** (this._literal[L].value)\r\n }\r\n }\r\n\r\n return r\r\n }\r\n// ----------------------------------------\r\n// Static functions\r\n// ----------------------------------------\r\n\r\n /**\r\n * Derivative the monom\r\n * @param letter\r\n */\r\n derivative = (letter?: string): Monom => {\r\n // No setLetter given - assume it's the setLetter 'x'\r\n if (letter === undefined) {\r\n letter = 'x';\r\n }\r\n\r\n if (this.hasLetter(letter)) {\r\n let d = this._literal[letter].clone(),\r\n dM = this.clone();\r\n\r\n // Subtract one to the degree.\r\n dM._literal[letter].subtract(1)\r\n\r\n // Multiply the coefficient by the previous degree\r\n dM._coefficient.multiply(this.makeCoefficient(d.clone()));\r\n return dM;\r\n } else {\r\n return new Monom().zero();\r\n }\r\n };\r\n\r\n primitive = (letter?: string): Monom => {\r\n // TODO: derivative including the ln value => implies creating different monom system ?\r\n if (letter === undefined) {\r\n letter = 'x'\r\n }\r\n\r\n // Zero monom\r\n let M = this.clone(), degree\r\n\r\n if (M.hasLetter(letter)) {\r\n degree = M.degree(letter).clone().add(1)\r\n M.coefficient = M.coefficient.clone().divide(degree)\r\n M.setLetter(letter, degree)\r\n } else {\r\n // There is no letter.\r\n\r\n // The coefficient might be zero (=> x) or a number a (=> ax)\r\n if (M.coefficient.isZero()) {\r\n M.coefficient = this.makeCoefficient().one()\r\n }\r\n M.setLetter(letter, 1)\r\n }\r\n\r\n return M\r\n }\r\n\r\n// TODO: The rest of the functions are not used or unnecessary ?\r\n /**\r\n * Determine if multiple monoms are similar\r\n * @param M\r\n */\r\n areSameAs = (...M: Monom[]): boolean => {\r\n let result: boolean = true;\r\n\r\n // Check all monoms if they are the isSame as the \"this\" one.\r\n for (let i = 0; i < M.length; i++) {\r\n if (!this.isSameAs(M[i])) {\r\n return false;\r\n }\r\n }\r\n\r\n // All check passed -> all the monoms are similar.\r\n return result;\r\n };\r\n\r\n /**\r\n * Determine if multiple monoms are equals\r\n * @param M\r\n */\r\n areEquals = (...M: Monom[]): boolean => {\r\n // They are not similar.\r\n if (!this.areSameAs(...M)) {\r\n return false;\r\n }\r\n\r\n // Check all coefficient. They must be equals.\r\n for (let m of M) {\r\n if (!this._coefficient.isEqualTo(m.coefficient)) {\r\n return false;\r\n }\r\n }\r\n\r\n // All checks passed.\r\n return true;\r\n };\r\n\r\n isDivisible = (div: Monom): boolean => {\r\n // For all variables (letters), the current monom must have a degree higher than the divider\r\n if (div.degree().isStrictlyPositive()) {\r\n for (let letter of div.variables) {\r\n if (!this.degree(letter).isGreaterOrEqualTo(div.degree(letter))) {\r\n return false\r\n }\r\n }\r\n }\r\n\r\n // If the coefficient is rational, we suppose we don't need to check the division by the coefficient.\r\n if (this.coefficient.isRational() || div.coefficient.isRational()) {\r\n return true\r\n }\r\n\r\n return this.coefficient.clone().divide(div.coefficient).isRelative()\r\n }\r\n\r\n isInverted(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return this.clone().multiply(M).isOne();\r\n }\r\n\r\n isNegativeOne()\r\n :\r\n boolean {\r\n return this._coefficient.value === -1 && this.variables.length === 0;\r\n }\r\n\r\n isNotEqual(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return !this.isEqual(M);\r\n }\r\n\r\n isNotZero()\r\n :\r\n boolean {\r\n return !this.isZero();\r\n }\r\n\r\n isOpposed(M\r\n :\r\n Monom\r\n ):\r\n boolean {\r\n return this.clone().subtract(M).isZero();\r\n }\r\n\r\n isReduced()\r\n :\r\n boolean {\r\n // By construction, it is already reduced (litterals\r\n return this.coefficient.isReduced();\r\n }\r\n\r\n reset()\r\n :\r\n any {\r\n this._coefficient = this.makeCoefficient()\r\n this._literal = {}\r\n }\r\n\r\n _getLiteralDividers(arr: literalType[], letter: string):\r\n literalType[] {\r\n let tmpList: { [key: string]: CoefficientTypes }[] = [];\r\n\r\n // Be default, this.literal[letter] should be a rational number.\r\n for (let d = 0; d <= this.literal[letter].value; d++) {\r\n if (arr.length === 0) {\r\n let litt: literalType = {}\r\n litt[letter] = this.makeCoefficient(d)\r\n tmpList.push(litt)\r\n } else {\r\n for (let item of arr) {\r\n let litt: literalType = {}\r\n for (let currentLetter in item) {\r\n litt[currentLetter] = item[currentLetter]\r\n }\r\n litt[letter] = this.makeCoefficient(d)\r\n tmpList.push(litt)\r\n }\r\n }\r\n }\r\n return tmpList;\r\n }\r\n\r\n _shutingYardToReducedMonom = (inputStr: string): Monom => {\r\n // Get the RPN array of the current expression\r\n const SY: Shutingyard = new Shutingyard().parse(inputStr);\r\n const rpn: { token: string, tokenType: string }[] = SY.rpn;\r\n\r\n let stack: Monom[] = []\r\n\r\n if (rpn.length === 0) {\r\n this.zero()\r\n return this\r\n } else if (rpn.length === 1) {\r\n const element = rpn[0]\r\n\r\n this.one()\r\n if (element.tokenType === 'coefficient') {\r\n this.coefficient = this.makeCoefficient(element.token)\r\n } else if (element.tokenType === 'variable') {\r\n this.setLetter(element.token, 1)\r\n }\r\n return this\r\n } else {\r\n // Reset the monom\r\n for (const element of rpn) {\r\n this.addToken(stack, element)\r\n }\r\n }\r\n\r\n this.one()\r\n this.multiply(stack[0])\r\n return this\r\n }\r\n}\r\n
|
|
54
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
55
|
+
<+>UTF-8
|
|
56
|
+
===================================================================
|
|
57
|
+
diff --git a/src/maths/algebra/monom.ts b/src/maths/algebra/monom.ts
|
|
58
|
+
--- a/src/maths/algebra/monom.ts
|
|
59
|
+
+++ b/src/maths/algebra/monom.ts
|
|
60
|
+
@@ -107,7 +107,7 @@
|
|
61
|
+
for (const v of [...inputStr.matchAll(/([a-z])\^([+-]?[0-9]+)/g)]) {
|
|
62
|
+
// Create the default letter entry if necessary.
|
|
63
|
+
if (!(v[1] in this._literal)) {
|
|
64
|
+
- this._literal[v[1]] = this.makeCoefficient().zero();
|
|
65
|
+
+ this._literal[v[1]] = new Fraction().zero();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Add the new value.
|
|
69
|
+
@@ -119,7 +119,7 @@
|
|
70
|
+
for (const v of [...inputStr.matchAll(/([a-z](?!\^))/g)]) {
|
|
71
|
+
// Match all single letters
|
|
72
|
+
if (!(v[1] in this._literal)) {
|
|
73
|
+
- this._literal[v[1]] = this.makeCoefficient().zero();
|
|
74
|
+
+ this._literal[v[1]] = new Fraction().zero();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Add one to the value.
|
|
78
|
+
@@ -322,6 +322,7 @@
|
|
79
|
+
* @param monoms Array of monoms
|
|
80
|
+
*/
|
|
81
|
+
static lcm = (...monoms: Monom[]): Monom => {
|
|
82
|
+
+ // TODO: Make it work for any coefficient !
|
|
83
|
+
// All the monoms must be with natural powers...
|
|
84
|
+
for (let m of monoms) {
|
|
85
|
+
if (m.hasFractionCoefficient()) {
|
|
86
|
+
@@ -337,7 +338,7 @@
|
|
87
|
+
d = Numeric.lcm(...coeffD);
|
|
88
|
+
|
|
89
|
+
// Get the coefficient.
|
|
90
|
+
- M.coefficient = this.makeCoefficient(n, d).reduce();
|
|
91
|
+
+ M.coefficient = new Fraction(n, d).reduce();
|
|
92
|
+
|
|
93
|
+
// Set the literal parts - go through each monoms literal parts and get only the lowest degree of each letters.
|
|
94
|
+
for (let m of monoms) {
|
|
95
|
+
@@ -351,7 +352,7 @@
|
|
96
|
+
if (M.literal[letter] === undefined && m.literal[letter].isStrictlyPositive()) {
|
|
97
|
+
M.literal[letter] = m.literal[letter].clone();
|
|
98
|
+
} else {
|
|
99
|
+
- M.literal[letter] = this.makeCoefficient(Math.min(m.literal[letter].value, M.literal[letter].value))
|
|
100
|
+
+ M.literal[letter] = new Fraction(Math.min(m.literal[letter].value, M.literal[letter].value))
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
@@ -841,12 +842,12 @@
|
|
105
|
+
* Evaluate a monom. Each setLetter must be assigned to a Fraction.
|
|
106
|
+
* @param values Dictionary of <setLetter: Fraction>
|
|
107
|
+
*/
|
|
108
|
+
- evaluate = (values?: literalType | Fraction | number): CoefficientCore<any> => {
|
|
109
|
+
+ evaluate = (values?: literalType | CoefficientTypes | number): CoefficientCore<any> => {
|
|
110
|
+
let r = this.coefficient.clone();
|
|
111
|
+
|
|
112
|
+
if (typeof values === 'number' || values instanceof Fraction) {
|
|
113
|
+
let tmpValues: literalType = {}
|
|
114
|
+
- tmpValues[this.variables[0]] = this.makeCoefficient(values)
|
|
115
|
+
+ tmpValues[this.variables[0]] = new Fraction(values)
|
|
116
|
+
return this.evaluate(tmpValues);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@@ -1057,13 +1058,13 @@
|
|
120
|
+
|
|
121
|
+
_getLiteralDividers(arr: literalType[], letter: string):
|
|
122
|
+
literalType[] {
|
|
123
|
+
- let tmpList: { [key: string]: CoefficientTypes }[] = [];
|
|
124
|
+
+ let tmpList: { [key: string]: Fraction }[] = [];
|
|
125
|
+
|
|
126
|
+
// Be default, this.literal[letter] should be a rational number.
|
|
127
|
+
for (let d = 0; d <= this.literal[letter].value; d++) {
|
|
128
|
+
if (arr.length === 0) {
|
|
129
|
+
let litt: literalType = {}
|
|
130
|
+
- litt[letter] = this.makeCoefficient(d)
|
|
131
|
+
+ litt[letter] = new Fraction(d)
|
|
132
|
+
tmpList.push(litt)
|
|
133
|
+
} else {
|
|
134
|
+
for (let item of arr) {
|
|
135
|
+
@@ -1071,7 +1072,7 @@
|
|
136
|
+
for (let currentLetter in item) {
|
|
137
|
+
litt[currentLetter] = item[currentLetter]
|
|
138
|
+
}
|
|
139
|
+
- litt[letter] = this.makeCoefficient(d)
|
|
140
|
+
+ litt[letter] = new Fraction(d)
|
|
141
|
+
tmpList.push(litt)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
Index: src/maths/coefficients/coefficientCore.ts
|
|
145
|
+
IDEA additional info:
|
|
146
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
147
|
+
<+>import {Fraction} from \"./fraction\";\r\nimport {RootFraction} from \"./rootFraction\";\r\nimport {Numeric} from \"../numeric\";\r\n\r\n\r\nexport type CoefficientTypes = Fraction | RootFraction\r\nexport type CoefficientParserTypes = CoefficientTypes | number | string\r\n\r\nexport enum COEFFICIENT_MODE {\r\n \"FRACTION\",\r\n \"ROOT\",\r\n \"RADIAN\",\r\n \"COMPLEX\"\r\n}\r\n\r\nexport enum FRACTION_FRAC {\r\n \"frac\",\r\n \"dfrac\",\r\n \"tfrac\",\r\n}\r\n\r\nexport abstract class CoefficientCore<T extends CoefficientTypes> {\r\n private _fracType: FRACTION_FRAC\r\n\r\n get fracType(): FRACTION_FRAC {\r\n return this._fracType;\r\n }\r\n\r\n set fracType(value: FRACTION_FRAC) {\r\n this._fracType = value;\r\n }\r\n\r\n private _numerator: number\r\n\r\n get numerator(): number {\r\n return this._numerator;\r\n }\r\n\r\n set numerator(value: number) {\r\n this._numerator = value;\r\n }\r\n\r\n private _denominator: number\r\n\r\n get denominator(): number {\r\n return this._denominator;\r\n }\r\n\r\n set denominator(value: number) {\r\n this._denominator = value;\r\n }\r\n\r\n get value(): number {\r\n return this._numerator / this._denominator\r\n }\r\n\r\n get sign(): number {\r\n return (this.numerator * this.denominator >= 0) ? 1 : -1;\r\n };\r\n\r\n get signTeX(): string {\r\n return this.sign === 1 ? '+' : '-'\r\n }\r\n\r\n get fracTeX(): string {\r\n return this._fracType === FRACTION_FRAC.frac ? '\\\\frac' : this._fracType === FRACTION_FRAC.dfrac ? '\\\\dfrac' : '\\\\tfrac'\r\n }\r\n\r\n abstract get tex(): string\r\n\r\n abstract get display(): string\r\n\r\n static max = <T extends CoefficientTypes>(...values: T[]): T => {\r\n const [first, ...rest] = values\r\n return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? acc : cur, first)\r\n }\r\n\r\n static min = <T extends CoefficientTypes>(...values: T[]): T => {\r\n const [first, ...rest] = values\r\n return rest.reduce((acc, cur) => acc.isGreaterThan(cur) ? cur : acc, first)\r\n }\r\n\r\n static unique = <T extends CoefficientTypes>(values: T[], sort?: boolean): T[] => {\r\n let uniqueObjects: T[] = [],\r\n uniqueValues: number[] = []\r\n\r\n values.forEach((value, index) => {\r\n if (!uniqueValues.includes(value.value)) {\r\n uniqueValues.push(value.value)\r\n uniqueObjects.push(value)\r\n }\r\n })\r\n\r\n if (sort) return CoefficientCore.sort(uniqueObjects)\r\n\r\n return uniqueObjects\r\n }\r\n\r\n static sort = <T extends CoefficientTypes>(values: T[], reverse?: boolean): T[] => {\r\n let sorted = values.sort((a, b) => a.value - b.value)\r\n\r\n if (reverse) sorted = sorted.reverse()\r\n\r\n return sorted\r\n }\r\n\r\n abstract createInstance(value?: number | string | T): T\r\n\r\n abstract clone(): T\r\n\r\n abstract reduce(): T\r\n\r\n getReducedCoefficient = (): { N: number, D: number } => {\r\n if (this.numerator === 1 || this.denominator === 1) return {N: this.numerator, D: this.denominator}\r\n\r\n let g = Numeric.gcd(this.numerator, this.denominator);\r\n let [N, D] = [this.numerator, this.denominator]\r\n\r\n N = N / g;\r\n D = D / g;\r\n\r\n if (D < 0) {\r\n D = -D;\r\n N = -N;\r\n }\r\n\r\n return {N, D}\r\n };\r\n\r\n zero = (): T => {\r\n this.numerator = 0;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n one = (): T => {\r\n this.numerator = 1;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n infinite = (): T => {\r\n this.numerator = Infinity;\r\n this.denominator = 1;\r\n return this as unknown as T;\r\n };\r\n\r\n invalid = (): T => {\r\n this.numerator = NaN;\r\n this.denominator = 1;\r\n return this as unknown as T\r\n };\r\n\r\n abstract add(...coefficients: (T | number | string)[]): T\r\n\r\n opposite = (): T => {\r\n this.numerator = -this.numerator;\r\n return this as unknown as T;\r\n }\r\n\r\n subtract = (...coefficients: (T | number | string)[]): T => this.add(...coefficients.map(c => this.createInstance(c).opposite() as T))\r\n\r\n abstract multiply(...coefficients: (T | number | string)[]): T\r\n\r\n abstract invert(): T\r\n\r\n divide = (F: T | number): T => this.multiply(this.createInstance(F).invert() as T);\r\n\r\n abs = (): T => {\r\n this.numerator = Math.abs(this.numerator);\r\n return this as unknown as T;\r\n }\r\n\r\n pow = (value: number | CoefficientTypes): T => {\r\n if (Number.isSafeInteger(value)) {\r\n const factor = this.clone(),\r\n abs = Math.abs(value as number)\r\n for (let i = abs; i <= abs; i++) {\r\n this.multiply(factor)\r\n }\r\n\r\n if ((value as number) < 0) this.invert()\r\n } else {\r\n throw new Error('Cannot raise a coefficient to a non-integer power')\r\n }\r\n return this as unknown as T\r\n }\r\n\r\n abstract root(value: number | CoefficientTypes): T\r\n\r\n sqrt = (): T => this.root(2)\r\n\r\n asTopFraction = (): T => {\r\n this.fracType = FRACTION_FRAC.tfrac\r\n return this as unknown as T\r\n }\r\n\r\n asDisplayFraction = (): T => {\r\n this.fracType = FRACTION_FRAC.dfrac\r\n return this as unknown as T\r\n }\r\n\r\n\r\n /**\r\n * All the is* methods without argument\r\n */\r\n\r\n isReduced = (): boolean => Math.abs(Numeric.gcd(this._numerator, this._denominator)) === 1\r\n\r\n isOne = (): boolean => this._numerator === 1 && this._denominator === 1\r\n\r\n isMinusOne = (): boolean => this._numerator === -1 && this._denominator === 1\r\n\r\n isUnit = (): boolean => this.isOne() || this.isMinusOne()\r\n\r\n isZero = (): boolean => this._numerator === 0\r\n\r\n isFinite = (): boolean => !this.isInfinity() && !this.isNaN()\r\n\r\n isSquare = (): boolean => Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0\r\n\r\n isNaN = (): boolean => isNaN(this.value)\r\n\r\n isPositive = (): boolean => this.sign === 1\r\n\r\n isNegative = (): boolean => this.sign === -1\r\n\r\n isStrictlyNegative = (): boolean => this.value < 0\r\n\r\n isStrictlyPositive = (): boolean => this.value > 0\r\n\r\n isNatural = (): boolean => this.isRelative() && this.isPositive()\r\n\r\n isRelative = (): boolean => {\r\n const {N, D} = this.getReducedCoefficient()\r\n return D === 1\r\n }\r\n\r\n isRational = (): boolean => !this.isRelative()\r\n\r\n isReal = (): boolean => true\r\n\r\n isComplex = (): boolean => false\r\n\r\n isInfinity = (): boolean => Math.abs(this.value) === Infinity\r\n\r\n isEven = (): boolean => this.isRelative() && this.value % 2 === 0\r\n\r\n isOdd = (): boolean => this.isRelative() && this.value % 2 === 1\r\n\r\n isApproximative = (): boolean => this._numerator.toString().length >= 15 && this._denominator.toString().length >= 15\r\n\r\n isExact = (): boolean => !this.isApproximative()\r\n\r\n isGreaterThan = (than: CoefficientCore<any> | number | string): boolean => this.value > this.createInstance(than as T).value;\r\n\r\n isSimilarTo = (to: CoefficientCore<any> | number | string): boolean => true;\r\n\r\n isGreaterOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value >= this.createInstance(than as T).value;\r\n\r\n isLesserOrEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value <= this.createInstance(than as T).value;\r\n\r\n isLesserThan = (than: CoefficientCore<any> | number | string): boolean => this.value < this.createInstance(than as T).value;\r\n\r\n isEqualTo = (than: CoefficientCore<any> | number | string): boolean => this.value === this.createInstance(than as T).value\r\n\r\n isOpposedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).opposite())\r\n\r\n isInvertedTo = (to: CoefficientCore<any> | number | string): boolean => this.isEqualTo(this.createInstance(to as T).invert())\r\n\r\n}\r\n
|
|
148
|
+
===================================================================
|
|
149
|
+
diff --git a/src/maths/coefficients/coefficientCore.ts b/src/maths/coefficients/coefficientCore.ts
|
|
150
|
+
--- a/src/maths/coefficients/coefficientCore.ts
|
|
151
|
+
+++ b/src/maths/coefficients/coefficientCore.ts
|
|
152
|
+
@@ -1,10 +1,12 @@
|
|
153
|
+
import {Fraction} from "./fraction";
|
|
154
|
+
-import {RootFraction} from "./rootFraction";
|
|
155
|
+
import {Numeric} from "../numeric";
|
|
156
|
+
|
|
157
|
+
+// Give the ability to add multiply Coefficient type, for extending.
|
|
158
|
+
+export type CoefficientTypes = Fraction
|
|
159
|
+
|
|
160
|
+
-export type CoefficientTypes = Fraction | RootFraction
|
|
161
|
+
-export type CoefficientParserTypes = CoefficientTypes | number | string
|
|
162
|
+
+export interface ICoefficient {
|
|
163
|
+
+
|
|
164
|
+
+}
|
|
165
|
+
|
|
166
|
+
export enum COEFFICIENT_MODE {
|
|
167
|
+
"FRACTION",
|
|
168
|
+
Index: src/maths/types.ts
|
|
169
|
+
IDEA additional info:
|
|
170
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
171
|
+
<+>import {Monom} from \"./algebra/monom\";\r\nimport {Polynom} from \"./algebra/polynom\";\r\nimport {Rational} from \"./algebra/rational\";\r\nimport {CoefficientTypes} from \"./coefficients/coefficientCore\";\r\n\r\ninterface coreInterface {\r\n parse: (...values: unknown[]) => ThisType<this>,\r\n clone: () => ThisType<this>,\r\n\r\n readonly tex: string,\r\n readonly display: string\r\n}\r\n\r\ninterface operationInterface {\r\n add: (...values: unknown[]) => ThisType<this>,\r\n subtract: (...values: unknown[]) => ThisType<this>,\r\n multiply: (...values: unknown[]) => ThisType<this>,\r\n divide: (value: unknown) => ThisType<this>,\r\n opposite: () => ThisType<this>,\r\n invert: () => ThisType<this>,\r\n pow: (value: unknown) => ThisType<this>,\r\n root: (value: unknown) => ThisType<this>,\r\n reduce: () => ThisType<this>,\r\n}\r\n\r\ninterface compareInterface {\r\n compare: (value: unknown, sign: COMPARESIGNS) => boolean,\r\n isEqualTo: (value: unknown) => boolean,\r\n isReduced: () => boolean,\r\n isOne: () => boolean,\r\n isMinusOne: () => boolean,\r\n isUnit: () => boolean,\r\n isZero: () => boolean,\r\n}\r\n\r\nexport interface coefficientInterface extends coreInterface, operationInterface, compareInterface {\r\n isGreaterOrEqualTo: (value: unknown) => boolean,\r\n isGreaterThan: (value: unknown) => boolean,\r\n isLesserOrEqualTo: (value: unknown) => boolean,\r\n isLesserThan: (value: unknown) => boolean,\r\n isNaN: () => boolean,\r\n isPositive: () => boolean,\r\n isNegative: () => boolean,\r\n isStrictlyNegative: () => boolean,\r\n isStrictlyPositive: () => boolean,\r\n isOpposedTo: (value: unknown) => boolean,\r\n isInvertedTo: (value: unknown) => boolean,\r\n isNatural: () => boolean,\r\n isRelative: () => boolean,\r\n isRational: () => boolean,\r\n isReal: () => boolean,\r\n isComplex: () => boolean,\r\n isInfinity: () => boolean,\r\n isEven: () => boolean,\r\n isOdd: () => boolean,\r\n readonly value: number,\r\n}\r\n\r\nexport interface coefficientStaticTypes {\r\n average: (...values: unknown[]) => coefficientInterface,\r\n max: (...values: unknown[]) => coefficientInterface,\r\n min: (...values: unknown[]) => coefficientInterface,\r\n sort: (...values: unknown[]) => coefficientInterface[],\r\n unique: (...values: unknown[]) => coefficientInterface[],\r\n}\r\n\r\nexport interface expressionInterface extends coreInterface, operationInterface, compareInterface {\r\n // variables getter\r\n readonly variables: string[],\r\n hasLetter: (letter?: string) => boolean\r\n\r\n // Evaluate\r\n evaluate: (value?: evaluateType) => numericType,\r\n\r\n // Helpers\r\n isDivisible?: (value: unknown) => boolean,\r\n}\r\n\r\n\r\nexport type literalType = { [Key: string]: CoefficientTypes }\r\nexport type numericType = number | string | CoefficientTypes\r\nexport type expressionType = Monom | Polynom | Rational\r\nexport type evaluateType = numericType | { [key: string]: numericType }\r\n\r\nexport enum COMPARESIGNS {\r\n \"EQUALS\" = \"=\",\r\n \"SAME\" = \"same\",\r\n \"GREATER\" = \">\",\r\n \"GEQ\" = \">=\",\r\n \"LESSER\" = \"<\",\r\n \"LEQ\" = \"<=\",\r\n \"DIFFERENT\" = \"<>\"\r\n}
|
|
172
|
+
===================================================================
|
|
173
|
+
diff --git a/src/maths/types.ts b/src/maths/types.ts
|
|
174
|
+
--- a/src/maths/types.ts
|
|
175
|
+
+++ b/src/maths/types.ts
|
|
176
|
+
@@ -2,6 +2,7 @@
|
|
177
|
+
import {Polynom} from "./algebra/polynom";
|
|
178
|
+
import {Rational} from "./algebra/rational";
|
|
179
|
+
import {CoefficientTypes} from "./coefficients/coefficientCore";
|
|
180
|
+
+import {Fraction} from "./coefficients/fraction";
|
|
181
|
+
|
|
182
|
+
interface coreInterface {
|
|
183
|
+
parse: (...values: unknown[]) => ThisType<this>,
|
|
184
|
+
@@ -77,7 +78,7 @@
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
-export type literalType = { [Key: string]: CoefficientTypes }
|
|
189
|
+
+export type literalType = { [Key: string]: Fraction }
|
|
190
|
+
export type numericType = number | string | CoefficientTypes
|
|
191
|
+
export type expressionType = Monom | Polynom | Rational
|
|
192
|
+
export type evaluateType = numericType | { [key: string]: numericType }
|
|
File without changes
|
package/.idea/shelf/Uncommitted_changes_before_Checkout_at_07_11_2023_08_30__Default_Changelist_.xml
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<changelist name="Uncommitted_changes_before_Checkout_at_07_11_2023_08_30_[Default_Changelist]" date="1699342221748" recycled="false" toDelete="true">
|
|
2
|
+
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_Checkout_at_07_11_2023_08_30_[Default_Changelist]/shelved.patch" />
|
|
3
|
+
<option name="DESCRIPTION" value="Uncommitted changes before Checkout at 07.11.2023 08:30 [Default Changelist]" />
|
|
4
|
+
</changelist>
|