nerdamer 1.1.13 → 2.0.0-rc.1
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/LICENSE.md +184 -0
- package/README.md +293 -312
- package/dist/bundle.js +2 -0
- package/dist/bundle.js.LICENSE.txt +7 -0
- package/dist/parser.js +2 -0
- package/dist/parser.js.LICENSE.txt +7 -0
- package/docs-data/parser-functions.json +1960 -0
- package/index.d.ts +10 -426
- package/output/algebra/adapters.d.ts +33 -0
- package/output/algebra/adapters.js +109 -0
- package/output/algebra/algorithms/arith.d.ts +84 -0
- package/output/algebra/algorithms/arith.js +323 -0
- package/output/algebra/algorithms/factor.d.ts +3 -0
- package/output/algebra/algorithms/factor.js +5 -0
- package/output/algebra/algorithms/factorMultivariate.d.ts +23 -0
- package/output/algebra/algorithms/factorMultivariate.js +2393 -0
- package/output/algebra/algorithms/factorUnivariate.d.ts +72 -0
- package/output/algebra/algorithms/factorUnivariate.js +1072 -0
- package/output/algebra/algorithms/gcd.d.ts +22 -0
- package/output/algebra/algorithms/gcd.js +690 -0
- package/output/algebra/algorithms/groebnerBase.d.ts +157 -0
- package/output/algebra/algorithms/groebnerBase.js +1166 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.d.ts +137 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.js +346 -0
- package/output/algebra/algorithms/poly.d.ts +228 -0
- package/output/algebra/algorithms/poly.js +1299 -0
- package/output/algebra/algorithms/rational.d.ts +17 -0
- package/output/algebra/algorithms/rational.js +115 -0
- package/output/algebra/factor/factor.d.ts +62 -0
- package/output/algebra/factor/factor.js +158 -0
- package/output/algebra/gcd/gcd.d.ts +29 -0
- package/output/algebra/gcd/gcd.js +141 -0
- package/output/algebra/groebner.d.ts +21 -0
- package/output/algebra/groebner.js +42 -0
- package/output/algebra/partfrac.d.ts +19 -0
- package/output/algebra/partfrac.js +398 -0
- package/output/algebra/polynomialize.d.ts +20 -0
- package/output/algebra/polynomialize.js +24 -0
- package/output/algebra/simplify/complexsimp.d.ts +7 -0
- package/output/algebra/simplify/complexsimp.js +24 -0
- package/output/algebra/simplify/factorCommon.d.ts +13 -0
- package/output/algebra/simplify/factorCommon.js +136 -0
- package/output/algebra/simplify/funcsimp.d.ts +26 -0
- package/output/algebra/simplify/funcsimp.js +633 -0
- package/output/algebra/simplify/invtrigrewrite.d.ts +10 -0
- package/output/algebra/simplify/invtrigrewrite.js +96 -0
- package/output/algebra/simplify/ratsimp.d.ts +21 -0
- package/output/algebra/simplify/ratsimp.js +140 -0
- package/output/algebra/simplify/simplify.d.ts +25 -0
- package/output/algebra/simplify/simplify.js +228 -0
- package/output/algebra/simplify/trigreduce.d.ts +38 -0
- package/output/algebra/simplify/trigreduce.js +424 -0
- package/output/algebra/simplify/trigrewrite.d.ts +17 -0
- package/output/algebra/simplify/trigrewrite.js +156 -0
- package/output/algebra/simplify/trigsimp.d.ts +11 -0
- package/output/algebra/simplify/trigsimp.js +369 -0
- package/output/algebra/simplify/utils.d.ts +32 -0
- package/output/algebra/simplify/utils.js +56 -0
- package/output/algebra/utils.d.ts +32 -0
- package/output/algebra/utils.js +48 -0
- package/output/api/advanced.d.ts +7 -0
- package/output/api/advanced.js +18 -0
- package/output/api/algebra.d.ts +17 -0
- package/output/api/algebra.js +32 -0
- package/output/api/assumptions.d.ts +4 -0
- package/output/api/assumptions.js +11 -0
- package/output/api/calculus.d.ts +9 -0
- package/output/api/calculus.js +21 -0
- package/output/api/core.d.ts +17 -0
- package/output/api/core.js +41 -0
- package/output/api/debug.d.ts +16 -0
- package/output/api/debug.js +23 -0
- package/output/api/parser.d.ts +85 -0
- package/output/api/parser.js +16 -0
- package/output/api/solve.d.ts +10 -0
- package/output/api/solve.js +16 -0
- package/output/api/structures.d.ts +10 -0
- package/output/api/structures.js +22 -0
- package/output/calculus/derivative/diff.d.ts +30 -0
- package/output/calculus/derivative/diff.js +238 -0
- package/output/calculus/fresnel.d.ts +16 -0
- package/output/calculus/fresnel.js +39 -0
- package/output/calculus/integrate/byParts.d.ts +18 -0
- package/output/calculus/integrate/byParts.js +339 -0
- package/output/calculus/integrate/bySubstitution.d.ts +135 -0
- package/output/calculus/integrate/bySubstitution.js +411 -0
- package/output/calculus/integrate/integrate.d.ts +38 -0
- package/output/calculus/integrate/integrate.js +652 -0
- package/output/calculus/integrate/integrationTable.d.ts +2 -0
- package/output/calculus/integrate/integrationTable.js +914 -0
- package/output/calculus/integrate/utils.d.ts +28 -0
- package/output/calculus/integrate/utils.js +96 -0
- package/output/calculus/laplace/ilaplace.d.ts +31 -0
- package/output/calculus/laplace/ilaplace.js +192 -0
- package/output/calculus/laplace/ilaplaceTable.d.ts +2 -0
- package/output/calculus/laplace/ilaplaceTable.js +200 -0
- package/output/calculus/laplace/laplace.d.ts +22 -0
- package/output/calculus/laplace/laplace.js +109 -0
- package/output/calculus/laplace/laplaceTable.d.ts +2 -0
- package/output/calculus/laplace/laplaceTable.js +187 -0
- package/output/calculus/limit/limit.d.ts +35 -0
- package/output/calculus/limit/limit.js +1183 -0
- package/output/calculus/limit/limitsTable.d.ts +2 -0
- package/output/calculus/limit/limitsTable.js +7 -0
- package/output/core/Settings.d.ts +32 -0
- package/output/core/Settings.js +68 -0
- package/output/core/adapters.d.ts +18 -0
- package/output/core/adapters.js +40 -0
- package/output/core/classes/assumption/Assumption.d.ts +218 -0
- package/output/core/classes/assumption/Assumption.js +605 -0
- package/output/core/classes/assumption/assertiveFunctions.d.ts +6 -0
- package/output/core/classes/assumption/assertiveFunctions.js +64 -0
- package/output/core/classes/assumption/assume.d.ts +90 -0
- package/output/core/classes/assumption/assume.js +145 -0
- package/output/core/classes/collection/Collection.d.ts +107 -0
- package/output/core/classes/collection/Collection.js +231 -0
- package/output/core/classes/complex/Complex.d.ts +99 -0
- package/output/core/classes/complex/Complex.js +135 -0
- package/output/core/classes/decimalSet/DecimalSet.d.ts +226 -0
- package/output/core/classes/decimalSet/DecimalSet.js +453 -0
- package/output/core/classes/dictionary/Dictionary.d.ts +102 -0
- package/output/core/classes/dictionary/Dictionary.js +213 -0
- package/output/core/classes/equation/Equation.d.ts +256 -0
- package/output/core/classes/equation/Equation.js +350 -0
- package/output/core/classes/expression/CoeffObject.d.ts +100 -0
- package/output/core/classes/expression/CoeffObject.js +198 -0
- package/output/core/classes/expression/Expression.d.ts +1674 -0
- package/output/core/classes/expression/Expression.js +2332 -0
- package/output/core/classes/expression/analysis.d.ts +25 -0
- package/output/core/classes/expression/analysis.js +218 -0
- package/output/core/classes/expression/collect.d.ts +9 -0
- package/output/core/classes/expression/collect.js +49 -0
- package/output/core/classes/expression/format.d.ts +45 -0
- package/output/core/classes/expression/format.js +217 -0
- package/output/core/classes/expression/products.d.ts +23 -0
- package/output/core/classes/expression/products.js +115 -0
- package/output/core/classes/expression/shortcuts.d.ts +35 -0
- package/output/core/classes/expression/shortcuts.js +129 -0
- package/output/core/classes/expression/traversal.d.ts +31 -0
- package/output/core/classes/expression/traversal.js +216 -0
- package/output/core/classes/expression/trig.d.ts +25 -0
- package/output/core/classes/expression/trig.js +40 -0
- package/output/core/classes/expression/utils.d.ts +52 -0
- package/output/core/classes/expression/utils.js +189 -0
- package/output/core/classes/lookupTable/LookupTable.d.ts +12 -0
- package/output/core/classes/lookupTable/LookupTable.js +55 -0
- package/output/core/classes/matrix/Matrix.d.ts +227 -0
- package/output/core/classes/matrix/Matrix.js +889 -0
- package/output/core/classes/matrix/Sylvester.d.ts +11 -0
- package/output/core/classes/matrix/Sylvester.js +54 -0
- package/output/core/classes/matrix/functions.d.ts +26 -0
- package/output/core/classes/matrix/functions.js +52 -0
- package/output/core/classes/matrix/utils.d.ts +9 -0
- package/output/core/classes/matrix/utils.js +22 -0
- package/output/core/classes/parser/Parser.d.ts +480 -0
- package/output/core/classes/parser/Parser.js +1812 -0
- package/output/core/classes/parser/Token.d.ts +58 -0
- package/output/core/classes/parser/Token.js +137 -0
- package/output/core/classes/parser/constants.d.ts +160 -0
- package/output/core/classes/parser/constants.js +227 -0
- package/output/core/classes/parser/helpers.d.ts +21 -0
- package/output/core/classes/parser/helpers.js +42 -0
- package/output/core/classes/parser/operations/add.d.ts +15 -0
- package/output/core/classes/parser/operations/add.js +238 -0
- package/output/core/classes/parser/operations/comma.d.ts +7 -0
- package/output/core/classes/parser/operations/comma.js +11 -0
- package/output/core/classes/parser/operations/compare.d.ts +21 -0
- package/output/core/classes/parser/operations/compare.js +461 -0
- package/output/core/classes/parser/operations/divide.d.ts +2 -0
- package/output/core/classes/parser/operations/divide.js +72 -0
- package/output/core/classes/parser/operations/functions.d.ts +46 -0
- package/output/core/classes/parser/operations/functions.js +430 -0
- package/output/core/classes/parser/operations/multiply.d.ts +11 -0
- package/output/core/classes/parser/operations/multiply.js +321 -0
- package/output/core/classes/parser/operations/power.d.ts +48 -0
- package/output/core/classes/parser/operations/power.js +673 -0
- package/output/core/classes/parser/operations/subtract.d.ts +3 -0
- package/output/core/classes/parser/operations/subtract.js +35 -0
- package/output/core/classes/parser/preprocess.d.ts +14 -0
- package/output/core/classes/parser/preprocess.js +259 -0
- package/output/core/classes/parser/scripting/controlFlow.d.ts +121 -0
- package/output/core/classes/parser/scripting/controlFlow.js +355 -0
- package/output/core/classes/parser/scripting/evaluate.d.ts +10 -0
- package/output/core/classes/parser/scripting/evaluate.js +112 -0
- package/output/core/classes/parser/scripting/functions.d.ts +14 -0
- package/output/core/classes/parser/scripting/functions.js +59 -0
- package/output/core/classes/parser/scripting/scope.d.ts +35 -0
- package/output/core/classes/parser/scripting/scope.js +155 -0
- package/output/core/classes/parser/types.d.ts +125 -0
- package/output/core/classes/parser/types.js +2 -0
- package/output/core/classes/parser/wrappers/IndexedReference.d.ts +31 -0
- package/output/core/classes/parser/wrappers/IndexedReference.js +68 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.d.ts +24 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.js +51 -0
- package/output/core/classes/polynomial/Polynomial.d.ts +500 -0
- package/output/core/classes/polynomial/Polynomial.js +1149 -0
- package/output/core/classes/polynomial/Term.d.ts +222 -0
- package/output/core/classes/polynomial/Term.js +430 -0
- package/output/core/classes/polynomial/functions.d.ts +69 -0
- package/output/core/classes/polynomial/functions.js +126 -0
- package/output/core/classes/polynomial/utils.d.ts +62 -0
- package/output/core/classes/polynomial/utils.js +206 -0
- package/output/core/classes/rational/Rational.d.ts +504 -0
- package/output/core/classes/rational/Rational.js +779 -0
- package/output/core/classes/seq/SEQ.d.ts +13 -0
- package/output/core/classes/seq/SEQ.js +137 -0
- package/output/core/classes/valuesSet/ValuesSet.d.ts +179 -0
- package/output/core/classes/valuesSet/ValuesSet.js +381 -0
- package/output/core/classes/vector/Vector.d.ts +222 -0
- package/output/core/classes/vector/Vector.js +497 -0
- package/output/core/classes/vector/functions.d.ts +28 -0
- package/output/core/classes/vector/functions.js +47 -0
- package/output/core/common/classes/MathematicalAggregate.d.ts +53 -0
- package/output/core/common/classes/MathematicalAggregate.js +140 -0
- package/output/core/common/classes/Scope.d.ts +62 -0
- package/output/core/common/classes/Scope.js +122 -0
- package/output/core/common/classes/StructuredEntity.d.ts +55 -0
- package/output/core/common/classes/StructuredEntity.js +151 -0
- package/output/core/common/common.d.ts +63 -0
- package/output/core/common/common.js +279 -0
- package/output/core/common/functions/functions.d.ts +14 -0
- package/output/core/common/functions/functions.js +33 -0
- package/output/core/common/functions/structuredEntityUtils.d.ts +27 -0
- package/output/core/common/functions/structuredEntityUtils.js +40 -0
- package/output/core/converters/BaseConverter.d.ts +97 -0
- package/output/core/converters/BaseConverter.js +405 -0
- package/output/core/converters/Converter.d.ts +111 -0
- package/output/core/converters/Converter.js +802 -0
- package/output/core/converters/Pattern.d.ts +71 -0
- package/output/core/converters/Pattern.js +302 -0
- package/output/core/dispatch.d.ts +34 -0
- package/output/core/dispatch.js +304 -0
- package/output/core/errors.d.ts +531 -0
- package/output/core/errors.js +621 -0
- package/output/core/functions/bigint/bigint.d.ts +121 -0
- package/output/core/functions/bigint/bigint.js +392 -0
- package/output/core/functions/bigint/primeFactor.d.ts +49 -0
- package/output/core/functions/bigint/primeFactor.js +267 -0
- package/output/core/functions/bigint/primes.d.ts +1 -0
- package/output/core/functions/bigint/primes.js +11 -0
- package/output/core/functions/build/definitions.d.ts +12 -0
- package/output/core/functions/build/definitions.js +133 -0
- package/output/core/functions/build/index.d.ts +32 -0
- package/output/core/functions/build/index.js +136 -0
- package/output/core/functions/complex.d.ts +90 -0
- package/output/core/functions/complex.js +482 -0
- package/output/core/functions/decimal.d.ts +24 -0
- package/output/core/functions/decimal.js +664 -0
- package/output/core/functions/expand/expand.d.ts +42 -0
- package/output/core/functions/expand/expand.js +376 -0
- package/output/core/functions/fresnelNumeric.d.ts +12 -0
- package/output/core/functions/fresnelNumeric.js +123 -0
- package/output/core/functions/numeric.d.ts +140 -0
- package/output/core/functions/numeric.js +790 -0
- package/output/core/functions/rationalNormalization.d.ts +11 -0
- package/output/core/functions/rationalNormalization.js +117 -0
- package/output/core/functions/setFunction.d.ts +19 -0
- package/output/core/functions/setFunction.js +75 -0
- package/output/core/functions/string.d.ts +26 -0
- package/output/core/functions/string.js +101 -0
- package/output/core/functions/subst.d.ts +90 -0
- package/output/core/functions/subst.js +498 -0
- package/output/core/functions/utils.d.ts +24 -0
- package/output/core/functions/utils.js +51 -0
- package/output/core/types.d.ts +48 -0
- package/output/core/types.js +2 -0
- package/output/index.d.ts +339 -0
- package/output/index.js +715 -0
- package/output/math/defint/defintDecimal.d.ts +37 -0
- package/output/math/defint/defintDecimal.js +320 -0
- package/output/math/defint/defintNative.d.ts +57 -0
- package/output/math/defint/defintNative.js +292 -0
- package/output/math/geometry.d.ts +8 -0
- package/output/math/geometry.js +32 -0
- package/output/math/math.d.ts +655 -0
- package/output/math/math.js +1811 -0
- package/output/math/trig.d.ts +518 -0
- package/output/math/trig.js +1444 -0
- package/output/math/trunc.d.ts +19 -0
- package/output/math/trunc.js +36 -0
- package/output/math/utils.d.ts +60 -0
- package/output/math/utils.js +180 -0
- package/output/solve/classes/DecimalMatrix.d.ts +17 -0
- package/output/solve/classes/DecimalMatrix.js +86 -0
- package/output/solve/classes/FunctionSolver.d.ts +135 -0
- package/output/solve/classes/FunctionSolver.js +433 -0
- package/output/solve/classes/MultivariateSolver.d.ts +84 -0
- package/output/solve/classes/MultivariateSolver.js +240 -0
- package/output/solve/classes/PolynomialSolver.d.ts +85 -0
- package/output/solve/classes/PolynomialSolver.js +292 -0
- package/output/solve/classes/SolutionSet.d.ts +153 -0
- package/output/solve/classes/SolutionSet.js +357 -0
- package/output/solve/classes/Solver.d.ts +17 -0
- package/output/solve/classes/Solver.js +132 -0
- package/output/solve/classes/SymbolicSolver.d.ts +74 -0
- package/output/solve/classes/SymbolicSolver.js +601 -0
- package/output/solve/linsolve.d.ts +51 -0
- package/output/solve/linsolve.js +225 -0
- package/output/solve/solve.d.ts +34 -0
- package/output/solve/solve.js +260 -0
- package/output/solve/solveSystem.d.ts +31 -0
- package/output/solve/solveSystem.js +290 -0
- package/output/solve/utils.d.ts +9 -0
- package/output/solve/utils.js +62 -0
- package/output/utils/array.d.ts +42 -0
- package/output/utils/array.js +98 -0
- package/output/utils/debug.d.ts +131 -0
- package/output/utils/debug.js +295 -0
- package/output/utils/decimal.d.ts +3 -0
- package/output/utils/decimal.js +16 -0
- package/output/utils/numeric.d.ts +14 -0
- package/output/utils/numeric.js +51 -0
- package/output/utils/object.d.ts +26 -0
- package/output/utils/object.js +56 -0
- package/package.json +213 -57
- package/.travis.yml +0 -3
- package/Algebra.js +0 -4568
- package/BREAKING_CHANGES.md +0 -5
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -14
- package/Calculus.js +0 -2675
- package/Extra.js +0 -622
- package/Solve.js +0 -1783
- package/all.js +0 -16
- package/all.min.js +0 -1
- package/gulpfile.js +0 -16
- package/index.html +0 -158
- package/license.txt +0 -19
- package/nerdamer.core.js +0 -12510
- package/spec/LaTeX.spec.js +0 -302
- package/spec/TeXConvert.spec.js +0 -8
- package/spec/algebra.spec.js +0 -287
- package/spec/basic_parser.spec.js +0 -134
- package/spec/build.spec.js +0 -131
- package/spec/calculus.spec.js +0 -183
- package/spec/core.spec.js +0 -2970
- package/spec/extra.spec.js +0 -54
- package/spec/solve.spec.js +0 -126
- package/spec/support/jasmine.json +0 -11
- package/spec/support/utils.js +0 -42
- package/spec/text.spec.js +0 -132
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.partfrac = partfrac;
|
|
4
|
+
const Expression_1 = require("../core/classes/expression/Expression");
|
|
5
|
+
const shortcuts_1 = require("../core/classes/expression/shortcuts");
|
|
6
|
+
const Matrix_1 = require("../core/classes/matrix/Matrix");
|
|
7
|
+
const Polynomial_1 = require("../core/classes/polynomial/Polynomial");
|
|
8
|
+
const utils_1 = require("../core/classes/polynomial/utils");
|
|
9
|
+
const factor_1 = require("./factor/factor");
|
|
10
|
+
/**
|
|
11
|
+
* Decomposes a rational expression P(x)/Q(x) into partial fractions.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* The routine extracts `P(x)/Q(x)`, performs polynomial long division for an improper
|
|
15
|
+
* fraction, factors `Q` over the supported exact polynomial domain, and solves the
|
|
16
|
+
* undetermined coefficients by exact evaluation and row reduction. Repeated linear
|
|
17
|
+
* factors and irreducible quadratic factors are supported. An irreducible factor of
|
|
18
|
+
* higher degree, a singular coefficient system, a denominator independent of the
|
|
19
|
+
* selected variable, or a factorization that does not expose a useful decomposition
|
|
20
|
+
* leaves the original expression unchanged.
|
|
21
|
+
*
|
|
22
|
+
* @param x - Rational expression to decompose.
|
|
23
|
+
* @param variable - Main variable; defaults to the first variable reported by the expression.
|
|
24
|
+
* @returns A new decomposition when one is found, otherwise the original parsed expression.
|
|
25
|
+
*/
|
|
26
|
+
function partfrac(x, variable) {
|
|
27
|
+
const expr = Expression_1.Expression.create(x);
|
|
28
|
+
let result = expr;
|
|
29
|
+
// Determine the variable
|
|
30
|
+
const vars = expr.variables();
|
|
31
|
+
const v = variable ? String(variable) : vars[0];
|
|
32
|
+
if (v && vars.length > 0) {
|
|
33
|
+
// Extract numerator and denominator.
|
|
34
|
+
const { num, den } = extractNumDen(expr, v);
|
|
35
|
+
// Proceed only if the denominator depends on the variable
|
|
36
|
+
if (den.hasVariable(v)) {
|
|
37
|
+
const pNum = new Polynomial_1.Polynomial(num, [v]);
|
|
38
|
+
const pDen = new Polynomial_1.Polynomial(den, [v]);
|
|
39
|
+
const degNum = pNum.deg();
|
|
40
|
+
const degDen = pDen.deg();
|
|
41
|
+
// Step 1: If improper fraction, do polynomial long division
|
|
42
|
+
let polyPart = (0, shortcuts_1.zero)();
|
|
43
|
+
let remainder = num;
|
|
44
|
+
if (degNum >= degDen) {
|
|
45
|
+
const [quotient, rem] = (0, utils_1.divide)(num, den);
|
|
46
|
+
polyPart = quotient;
|
|
47
|
+
remainder = rem;
|
|
48
|
+
}
|
|
49
|
+
if (Expression_1.Expression.create(remainder).isZero()) {
|
|
50
|
+
// Remainder is zero — the expression is a polynomial
|
|
51
|
+
result = polyPart;
|
|
52
|
+
}
|
|
53
|
+
else if (degDen <= 1) {
|
|
54
|
+
// Denominator is linear or constant — no further decomposition possible.
|
|
55
|
+
// If we performed long division, return polyPart + remainder/den.
|
|
56
|
+
if (!polyPart.isZero()) {
|
|
57
|
+
result = polyPart.plus(remainder.div(den));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Step 2: Factor the denominator
|
|
62
|
+
const factors = (0, factor_1.polyFactorExpressions)(den);
|
|
63
|
+
const factorList = collectFactors(factors, v);
|
|
64
|
+
// Only decompose if factoring produced multiple factors or a repeated factor
|
|
65
|
+
const canDecompose = factorList.length > 1 || (factorList.length === 1 && factorList[0].power > 1);
|
|
66
|
+
if (canDecompose) {
|
|
67
|
+
// Step 3: Set up and solve partial fractions for remainder/den
|
|
68
|
+
const decomposition = decompose(remainder, den, factorList, v);
|
|
69
|
+
if (decomposition !== undefined) {
|
|
70
|
+
result = polyPart.isZero() ? decomposition : polyPart.plus(decomposition);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// A successful decomposition is mathematically equal to its input by definition.
|
|
77
|
+
// Use canonical text here to detect an unchanged shape rather than semantic equality.
|
|
78
|
+
return result.text() === expr.text() ? expr : result;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Extracts the numerator and denominator from an expression.
|
|
82
|
+
* For P/Q, returns { num: P, den: Q }.
|
|
83
|
+
*
|
|
84
|
+
* Rational expressions are typically stored as products where denominator
|
|
85
|
+
* factors have negative powers: P * Q^(-1).
|
|
86
|
+
*/
|
|
87
|
+
function extractNumDen(expr, _v) {
|
|
88
|
+
// Use getNumerator/getDenominator if available
|
|
89
|
+
try {
|
|
90
|
+
const num = expr.getNumerator();
|
|
91
|
+
const den = expr.getDenominator();
|
|
92
|
+
if (den && !den.isOne()) {
|
|
93
|
+
return { num, den };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Fall through to manual extraction
|
|
98
|
+
}
|
|
99
|
+
// Manual extraction: examine the product structure
|
|
100
|
+
// If the expression is a product, separate positive-power and negative-power factors
|
|
101
|
+
if (expr.isProduct()) {
|
|
102
|
+
let num = (0, shortcuts_1.one)();
|
|
103
|
+
let den = (0, shortcuts_1.one)();
|
|
104
|
+
for (const element of expr.elementsArray()) {
|
|
105
|
+
if (element.getPower().isNegative()) {
|
|
106
|
+
// Negative power → denominator factor
|
|
107
|
+
den = den.times(element.invert());
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
num = num.times(element);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Apply the overall multiplier
|
|
114
|
+
num = num.times(Expression_1.Expression.fromRational(expr.getMultiplier()));
|
|
115
|
+
return { num, den };
|
|
116
|
+
}
|
|
117
|
+
// Not a product — check if it has a negative power overall
|
|
118
|
+
if (expr.getPower().sign() === -1) {
|
|
119
|
+
return { num: Expression_1.Expression.fromRational(expr.getMultiplier()), den: expr.invert() };
|
|
120
|
+
}
|
|
121
|
+
// No denominator
|
|
122
|
+
return { num: expr, den: (0, shortcuts_1.one)() };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Collects factors from the factor() result, grouping repeated factors.
|
|
126
|
+
* Extracts embedded powers from expressions like (x-1)^3 so that the
|
|
127
|
+
* base (x-1) is stored with degree 1 and power 3.
|
|
128
|
+
*/
|
|
129
|
+
function collectFactors(factors, v) {
|
|
130
|
+
const result = [];
|
|
131
|
+
const seen = new Map(); // text → index in result
|
|
132
|
+
for (const factor of factors) {
|
|
133
|
+
let f = factor;
|
|
134
|
+
// Skip constant factors (no variable)
|
|
135
|
+
if (!f.hasVariable(v)) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Extract embedded power from the expression (e.g., (x-1)^3 → base=(x-1), power=3)
|
|
139
|
+
let expPower = 1;
|
|
140
|
+
const p = f.getPower();
|
|
141
|
+
if (p.isInteger()) {
|
|
142
|
+
const n = Number(p.getNumerator());
|
|
143
|
+
if (n > 1) {
|
|
144
|
+
expPower = n;
|
|
145
|
+
f = f.getBase();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const key = f.text();
|
|
149
|
+
const deg = new Polynomial_1.Polynomial(f, [v]).deg();
|
|
150
|
+
if (seen.has(key)) {
|
|
151
|
+
// Repeated factor — accumulate power
|
|
152
|
+
result[seen.get(key)].power += expPower;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
seen.set(key, result.length);
|
|
156
|
+
result.push({ expr: f, power: expPower, degree: deg });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Decomposes remainder/den into partial fractions given the factored denominator.
|
|
163
|
+
*
|
|
164
|
+
* For each linear factor (ax+b)^k:
|
|
165
|
+
* A₁/(ax+b) + A₂/(ax+b)² + ... + Aₖ/(ax+b)^k
|
|
166
|
+
*
|
|
167
|
+
* For each irreducible quadratic factor (ax²+bx+c)^k:
|
|
168
|
+
* (B₁x+C₁)/(ax²+bx+c) + ... + (Bₖx+Cₖ)/(ax²+bx+c)^k
|
|
169
|
+
*
|
|
170
|
+
* Uses evaluation at strategic points to solve for coefficients.
|
|
171
|
+
*/
|
|
172
|
+
function decompose(numerator, denominator, factors, v) {
|
|
173
|
+
// Build the list of partial fraction terms and count unknowns.
|
|
174
|
+
// Each term is: coefficient(s) / factor^power
|
|
175
|
+
// For linear: 1 unknown per power level
|
|
176
|
+
// For quadratic: 2 unknowns per power level (Bx + C)
|
|
177
|
+
const terms = [];
|
|
178
|
+
let totalUnknowns = 0;
|
|
179
|
+
let supported = true;
|
|
180
|
+
for (const f of factors) {
|
|
181
|
+
for (let k = 1; k <= f.power; k++) {
|
|
182
|
+
if (f.degree === 1) {
|
|
183
|
+
terms.push({
|
|
184
|
+
factor: f.expr,
|
|
185
|
+
power: k,
|
|
186
|
+
degree: f.degree,
|
|
187
|
+
unknownIndex: totalUnknowns,
|
|
188
|
+
numUnknowns: 1,
|
|
189
|
+
});
|
|
190
|
+
totalUnknowns += 1;
|
|
191
|
+
}
|
|
192
|
+
else if (f.degree === 2) {
|
|
193
|
+
terms.push({
|
|
194
|
+
factor: f.expr,
|
|
195
|
+
power: k,
|
|
196
|
+
degree: f.degree,
|
|
197
|
+
unknownIndex: totalUnknowns,
|
|
198
|
+
numUnknowns: 2,
|
|
199
|
+
});
|
|
200
|
+
totalUnknowns += 2;
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// Higher-degree irreducible factors — not supported yet
|
|
204
|
+
supported = false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (!supported) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
// We need to solve: P(x)/Q(x) = Σ terms
|
|
212
|
+
// Multiply both sides by Q(x):
|
|
213
|
+
// P(x) = Σ (coefficients_i × Q(x) / factor_i^power_i)
|
|
214
|
+
//
|
|
215
|
+
// Strategy: evaluate at `totalUnknowns` distinct values of x to get a linear system,
|
|
216
|
+
// then solve it.
|
|
217
|
+
// Collect evaluation points: roots of linear factors + additional integer points
|
|
218
|
+
const evalPoints = [];
|
|
219
|
+
for (const f of factors) {
|
|
220
|
+
if (f.degree === 1) {
|
|
221
|
+
// Linear factor ax + b: root is x = -b/a
|
|
222
|
+
const root = findLinearRoot(f.expr, v);
|
|
223
|
+
if (root !== undefined) {
|
|
224
|
+
evalPoints.push(root);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Add additional integer points to get enough equations
|
|
229
|
+
let pointVal = 0;
|
|
230
|
+
while (evalPoints.length < totalUnknowns) {
|
|
231
|
+
const candidate = Expression_1.Expression.Number(pointVal);
|
|
232
|
+
// Make sure this isn't a root of the denominator (would give division by zero)
|
|
233
|
+
const denAtPoint = evaluateAt(denominator, v, candidate);
|
|
234
|
+
if (!denAtPoint.isZero()) {
|
|
235
|
+
// Also make sure it's not already in our list
|
|
236
|
+
const isDuplicate = evalPoints.some(p => p.eq(candidate));
|
|
237
|
+
if (!isDuplicate) {
|
|
238
|
+
evalPoints.push(candidate);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
pointVal = pointVal <= 0 ? -pointVal + 1 : -pointVal;
|
|
242
|
+
}
|
|
243
|
+
// Build and solve the linear system by evaluation.
|
|
244
|
+
// For each eval point xᵢ:
|
|
245
|
+
// P(xᵢ) = Σⱼ unknowns_j × basisⱼ(xᵢ)
|
|
246
|
+
// where basisⱼ(x) is what multiplies the j-th unknown after clearing denominators.
|
|
247
|
+
const rows = [];
|
|
248
|
+
const rhs = [];
|
|
249
|
+
const cofactors = terms.map(term => computeCofactor(denominator, term.factor, term.power));
|
|
250
|
+
for (let i = 0; i < totalUnknowns; i++) {
|
|
251
|
+
const x = evalPoints[i];
|
|
252
|
+
const numVal = evaluateAt(numerator, v, x);
|
|
253
|
+
rhs.push(numVal);
|
|
254
|
+
const row = [];
|
|
255
|
+
for (let j = 0; j < terms.length; j++) {
|
|
256
|
+
const term = terms[j];
|
|
257
|
+
// The basis for this term: Q(x) / factor^power, evaluated at x
|
|
258
|
+
const cofactor = evaluateAt(cofactors[j], v, x);
|
|
259
|
+
if (term.numUnknowns === 1) {
|
|
260
|
+
row.push(cofactor);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// Quadratic: (Bx + C) contributes B*x*cofactor + C*cofactor
|
|
264
|
+
row.push(x.times(cofactor)); // coefficient of B
|
|
265
|
+
row.push(cofactor); // coefficient of C
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
rows.push(row);
|
|
269
|
+
}
|
|
270
|
+
// Solve the system
|
|
271
|
+
const solution = solveLinearSystem(rows, rhs);
|
|
272
|
+
if (solution === undefined) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
// Build the result expression from the solved coefficients
|
|
276
|
+
let result = (0, shortcuts_1.zero)();
|
|
277
|
+
for (const term of terms) {
|
|
278
|
+
const denomPart = term.power === 1 ? term.factor : term.factor.pow(Expression_1.Expression.Number(term.power));
|
|
279
|
+
if (term.numUnknowns === 1) {
|
|
280
|
+
const A = solution[term.unknownIndex];
|
|
281
|
+
if (!A.isZero()) {
|
|
282
|
+
result = result.plus(A.div(denomPart));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const B = solution[term.unknownIndex];
|
|
287
|
+
const C = solution[term.unknownIndex + 1];
|
|
288
|
+
// (Bx + C) / factor^power
|
|
289
|
+
const numPart = B.times(Expression_1.Expression.create(v)).plus(C);
|
|
290
|
+
if (!numPart.isZero()) {
|
|
291
|
+
result = result.plus(numPart.div(denomPart));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Finds the root of a linear expression ax + b, returning -b/a.
|
|
299
|
+
*/
|
|
300
|
+
function findLinearRoot(expr, v) {
|
|
301
|
+
// A linear expression ax + b: evaluate at x=0 to get b, at x=1 to get a+b
|
|
302
|
+
const atZero = evaluateAt(expr, v, (0, shortcuts_1.zero)());
|
|
303
|
+
const atOne = evaluateAt(expr, v, (0, shortcuts_1.one)());
|
|
304
|
+
const a = atOne.plus(atZero.times((0, shortcuts_1.minusOne)())); // a = f(1) - f(0)
|
|
305
|
+
if (a.isZero()) {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
// root = -b/a = -f(0)/a
|
|
309
|
+
return atZero.times((0, shortcuts_1.minusOne)()).div(a);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Evaluates a polynomial expression at a specific rational value of the variable.
|
|
313
|
+
* Returns the result as an Expression.
|
|
314
|
+
*/
|
|
315
|
+
function evaluateAt(expr, v, value) {
|
|
316
|
+
return expr.subst(v, value);
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Computes Q(x) / factor(x)^power.
|
|
320
|
+
* This is the "cofactor" — the part of the denominator that remains after removing this term's factor.
|
|
321
|
+
*/
|
|
322
|
+
function computeCofactor(denominator, fac, power) {
|
|
323
|
+
// Q / factor^power
|
|
324
|
+
const facPow = power === 1 ? fac : fac.pow(Expression_1.Expression.Number(power));
|
|
325
|
+
const [quotient] = (0, utils_1.divide)(denominator, facPow);
|
|
326
|
+
return quotient;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Solves a linear system Ax = b using Gaussian elimination with partial pivoting.
|
|
330
|
+
* Works with Expression arithmetic (exact rational arithmetic).
|
|
331
|
+
*
|
|
332
|
+
* @param A The coefficient matrix (array of rows)
|
|
333
|
+
* @param b The right-hand side vector
|
|
334
|
+
* @returns The solution vector, or undefined if the system is singular
|
|
335
|
+
*/
|
|
336
|
+
function solveLinearSystem(A, b) {
|
|
337
|
+
const n = b.length;
|
|
338
|
+
if (n === 0) {
|
|
339
|
+
return [];
|
|
340
|
+
}
|
|
341
|
+
// This solver is used to recover exact coefficients for partial fractions.
|
|
342
|
+
// Use Matrix.rref() so we don't duplicate row-reduction logic.
|
|
343
|
+
// Require a unique solution (square, full-rank). Otherwise return undefined.
|
|
344
|
+
const A_mat = new Matrix_1.Matrix(...A);
|
|
345
|
+
const b_col = new Matrix_1.Matrix(...b.map(v => [v]));
|
|
346
|
+
const aug = A_mat.augment(b_col).rref();
|
|
347
|
+
const rows = aug.rows();
|
|
348
|
+
const cols = aug.cols();
|
|
349
|
+
const unknowns = cols - 1;
|
|
350
|
+
if (rows !== n || unknowns !== n) {
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
// Inconsistency: [0 ... 0 | nonzero]
|
|
354
|
+
for (let i = 0; i < rows; i++) {
|
|
355
|
+
let allZero = true;
|
|
356
|
+
for (let j = 0; j < unknowns; j++) {
|
|
357
|
+
if (!aug.elements[i][j].isZero()) {
|
|
358
|
+
allZero = false;
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (allZero && !aug.elements[i][unknowns].isZero()) {
|
|
363
|
+
return undefined;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Extract solution from pivots. Expect [I | x] up to row ordering.
|
|
367
|
+
const solution = new Array(n);
|
|
368
|
+
const pivotCols = new Set();
|
|
369
|
+
for (let i = 0; i < rows; i++) {
|
|
370
|
+
let pivot = -1;
|
|
371
|
+
for (let j = 0; j < unknowns; j++) {
|
|
372
|
+
if (!aug.elements[i][j].isZero()) {
|
|
373
|
+
pivot = j;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (pivot === -1) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
if (!aug.elements[i][pivot].eq('1')) {
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
if (pivotCols.has(pivot)) {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
pivotCols.add(pivot);
|
|
387
|
+
solution[pivot] = aug.elements[i][unknowns];
|
|
388
|
+
}
|
|
389
|
+
if (pivotCols.size !== n) {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
for (let i = 0; i < n; i++) {
|
|
393
|
+
if (!solution[i]) {
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return solution;
|
|
398
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Expression } from '../core/classes/expression/Expression';
|
|
2
|
+
import type { Vector } from '../core/classes/vector/Vector';
|
|
3
|
+
import type { MapObjectType } from '../core/functions/subst';
|
|
4
|
+
/**
|
|
5
|
+
* Attempts to put the expression in polynomial form.
|
|
6
|
+
*
|
|
7
|
+
* @param expression The expression to normalize and polynomialize.
|
|
8
|
+
* @param map Existing u-substitutions to preserve across related expressions.
|
|
9
|
+
* @returns Polynomial numerator and denominator plus the substitution map.
|
|
10
|
+
*/
|
|
11
|
+
export declare function polynomialize(expression: Expression, map?: MapObjectType): {
|
|
12
|
+
numerator: Expression;
|
|
13
|
+
denominator: Expression;
|
|
14
|
+
map: MapObjectType;
|
|
15
|
+
};
|
|
16
|
+
export declare function polynomialize<T extends Expression | Vector>(expression: Expression, map: MapObjectType | undefined, callback: (e: Expression, map: MapObjectType) => T): {
|
|
17
|
+
numerator: T;
|
|
18
|
+
denominator: T;
|
|
19
|
+
map: MapObjectType;
|
|
20
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.polynomialize = polynomialize;
|
|
4
|
+
const subst_1 = require("../core/functions/subst");
|
|
5
|
+
const simplify_1 = require("./simplify/simplify");
|
|
6
|
+
function polynomialize(expression, map, callback) {
|
|
7
|
+
map ??= {};
|
|
8
|
+
// First simplify the expression
|
|
9
|
+
let x = (0, simplify_1.simplify)(expression);
|
|
10
|
+
// Substitute out all functions
|
|
11
|
+
[x, map] = (0, subst_1.uSubFN)(x, map);
|
|
12
|
+
// Substitute out all exponential functions
|
|
13
|
+
[x, map] = (0, subst_1.uSubEXP)(x, map);
|
|
14
|
+
// Constants although numeric are irrationals and need to be removed.
|
|
15
|
+
[x, map] = (0, subst_1.uSubConstants)(x, map);
|
|
16
|
+
// Extract the numerator and denominator
|
|
17
|
+
const num = x.getNumerator();
|
|
18
|
+
const den = x.getDenominator();
|
|
19
|
+
return {
|
|
20
|
+
numerator: callback ? callback(num, map) : num,
|
|
21
|
+
denominator: callback ? callback(den, map) : den,
|
|
22
|
+
map,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.complexSimplify = complexSimplify;
|
|
4
|
+
const Expression_1 = require("../../core/classes/expression/Expression");
|
|
5
|
+
const shortcuts_1 = require("../../core/classes/expression/shortcuts");
|
|
6
|
+
const expand_1 = require("../../core/functions/expand/expand");
|
|
7
|
+
/**
|
|
8
|
+
* Simplifies a complex number. Assumes expression is in the form a*i+b
|
|
9
|
+
*
|
|
10
|
+
* @param x
|
|
11
|
+
*/
|
|
12
|
+
function complexSimplify(x) {
|
|
13
|
+
const p = x.getPower();
|
|
14
|
+
// Only handle (a*i+b)^(-1) -> a/(a^2+b^2) - b/(a^2+b^2)*i
|
|
15
|
+
if (!p.isInteger() || !p.isMinusOne() /* or p.text() !== '-1' */) {
|
|
16
|
+
return x;
|
|
17
|
+
}
|
|
18
|
+
// base = (a*i+b)
|
|
19
|
+
const base = (0, expand_1.expand)(x.invert());
|
|
20
|
+
const re = base.realPart();
|
|
21
|
+
const im = base.imagPart();
|
|
22
|
+
const d = re.pow((0, shortcuts_1.two)()).plus(im.pow((0, shortcuts_1.two)()));
|
|
23
|
+
return re.div(d).minus(im.div(d).times(Expression_1.Expression.Img()));
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Expression } from '../../core/classes/expression/Expression';
|
|
2
|
+
/**
|
|
3
|
+
* Factors out the greatest common power from each base in a sum expression.
|
|
4
|
+
*
|
|
5
|
+
* For example:
|
|
6
|
+
* x^(3/2) + x^(1/2) → x^(1/2) * (x + 1)
|
|
7
|
+
* x^3 + x^2 → x^2 * (x + 1)
|
|
8
|
+
* 2*x^(5/2) + 3*x^(3/2) → x^(3/2) * (2*x + 3)
|
|
9
|
+
* x^2*y + x*y^2 → x*y * (x + y)
|
|
10
|
+
*
|
|
11
|
+
* Only applies to sums. Non-sum expressions are returned unchanged.
|
|
12
|
+
*/
|
|
13
|
+
export declare function factorCommonPower(x: Expression): Expression;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.factorCommonPower = factorCommonPower;
|
|
4
|
+
const Expression_1 = require("../../core/classes/expression/Expression");
|
|
5
|
+
const shortcuts_1 = require("../../core/classes/expression/shortcuts");
|
|
6
|
+
/**
|
|
7
|
+
* Extracts a map of {base_value → power} from a single term of a sum.
|
|
8
|
+
*
|
|
9
|
+
* For a simple variable like x^(3/2), returns { 'x': 3/2 as Expression }
|
|
10
|
+
* For a product like 2*x^(3/2)*y^2, returns { 'x': 3/2, 'y': 2 }
|
|
11
|
+
* For a constant like 5, returns {}
|
|
12
|
+
*
|
|
13
|
+
* The coefficient (numeric multiplier) is not included in the map.
|
|
14
|
+
*/
|
|
15
|
+
function extractBasePowers(term) {
|
|
16
|
+
const map = new Map();
|
|
17
|
+
if (term.isNUM()) {
|
|
18
|
+
// Pure number — no bases to extract
|
|
19
|
+
return map;
|
|
20
|
+
}
|
|
21
|
+
if (term.isProduct()) {
|
|
22
|
+
for (const element of term.elementsArray()) {
|
|
23
|
+
if (!element.isNUM()) {
|
|
24
|
+
const base = element.getBase();
|
|
25
|
+
const key = base.text();
|
|
26
|
+
const power = element.getPower();
|
|
27
|
+
// Accumulate: a product might have the same base appear once,
|
|
28
|
+
// but just in case, add powers
|
|
29
|
+
const existing = map.get(key);
|
|
30
|
+
map.set(key, existing !== undefined ? existing.plus(power) : power);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const base = term.getBase();
|
|
36
|
+
const key = base.text();
|
|
37
|
+
map.set(key, term.getPower());
|
|
38
|
+
}
|
|
39
|
+
return map;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Factors out the greatest common power from each base in a sum expression.
|
|
43
|
+
*
|
|
44
|
+
* For example:
|
|
45
|
+
* x^(3/2) + x^(1/2) → x^(1/2) * (x + 1)
|
|
46
|
+
* x^3 + x^2 → x^2 * (x + 1)
|
|
47
|
+
* 2*x^(5/2) + 3*x^(3/2) → x^(3/2) * (2*x + 3)
|
|
48
|
+
* x^2*y + x*y^2 → x*y * (x + y)
|
|
49
|
+
*
|
|
50
|
+
* Only applies to sums. Non-sum expressions are returned unchanged.
|
|
51
|
+
*/
|
|
52
|
+
function factorCommonPower(x) {
|
|
53
|
+
if (!x.isSum()) {
|
|
54
|
+
return x;
|
|
55
|
+
}
|
|
56
|
+
const m = x.getMultiplier();
|
|
57
|
+
const p = x.getPower();
|
|
58
|
+
const terms = x.elementsArray();
|
|
59
|
+
// Edge case: single term or empty
|
|
60
|
+
if (terms.length < 2) {
|
|
61
|
+
return x;
|
|
62
|
+
}
|
|
63
|
+
// Step 1: Extract base → power maps for each term
|
|
64
|
+
const termMaps = [];
|
|
65
|
+
let hasConstantTerm = false;
|
|
66
|
+
for (const term of terms) {
|
|
67
|
+
const map = extractBasePowers(term);
|
|
68
|
+
termMaps.push(map);
|
|
69
|
+
if (map.size === 0) {
|
|
70
|
+
hasConstantTerm = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// If there's a constant term (no bases), no common base can be factored
|
|
74
|
+
if (hasConstantTerm) {
|
|
75
|
+
return x;
|
|
76
|
+
}
|
|
77
|
+
// Step 2: Find bases common to ALL terms
|
|
78
|
+
const commonBases = new Set(termMaps[0].keys());
|
|
79
|
+
for (let i = 1; i < termMaps.length; i++) {
|
|
80
|
+
for (const key of commonBases) {
|
|
81
|
+
if (!termMaps[i].has(key)) {
|
|
82
|
+
commonBases.delete(key);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Nothing common to factor out
|
|
87
|
+
if (commonBases.size === 0) {
|
|
88
|
+
return x;
|
|
89
|
+
}
|
|
90
|
+
// Step 3: For each common base, find the minimum power across all terms
|
|
91
|
+
const minPowers = new Map();
|
|
92
|
+
for (const base of commonBases) {
|
|
93
|
+
let minPow = termMaps[0].get(base);
|
|
94
|
+
if (minPow === undefined) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
for (let i = 1; i < termMaps.length; i++) {
|
|
98
|
+
const pow = termMaps[i].get(base);
|
|
99
|
+
if (pow === undefined) {
|
|
100
|
+
minPow = undefined;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
// Use lt to compare — take the smaller power
|
|
104
|
+
if (pow.lt(minPow)) {
|
|
105
|
+
minPow = pow;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Only factor out positive powers
|
|
109
|
+
if (minPow !== undefined && minPow.sign() === 1) {
|
|
110
|
+
minPowers.set(base, minPow);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Nothing positive to factor out
|
|
114
|
+
if (minPowers.size === 0) {
|
|
115
|
+
return x;
|
|
116
|
+
}
|
|
117
|
+
// Step 4: Build the common factor and the reduced sum
|
|
118
|
+
let commonFactor = (0, shortcuts_1.one)();
|
|
119
|
+
for (const [base, power] of minPowers) {
|
|
120
|
+
commonFactor = commonFactor.times(Expression_1.Expression.create(base).pow(power));
|
|
121
|
+
}
|
|
122
|
+
// Step 5: Divide each term by the common factor to get the inner sum
|
|
123
|
+
let innerSum = (0, shortcuts_1.zero)();
|
|
124
|
+
for (const term of terms) {
|
|
125
|
+
innerSum = innerSum.plus(term.div(commonFactor));
|
|
126
|
+
}
|
|
127
|
+
// Step 6: Reconstruct with outer multiplier and power
|
|
128
|
+
let result = commonFactor.times(innerSum);
|
|
129
|
+
if (!p.isOne()) {
|
|
130
|
+
result = result.pow(p);
|
|
131
|
+
}
|
|
132
|
+
if (!m.isOne()) {
|
|
133
|
+
result = result.times(m);
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Expression } from '../../core/classes/expression/Expression';
|
|
2
|
+
/**
|
|
3
|
+
* Simplifies factorial ratios in a product expression.
|
|
4
|
+
*
|
|
5
|
+
* n! · (n+k)!^(-1) → 1 / ((n+1)(n+2)...(n+k)) when k > 0
|
|
6
|
+
* (n+k)! · n!^(-1) → (n+1)(n+2)...(n+k) when k > 0
|
|
7
|
+
*
|
|
8
|
+
* Works by finding pairs of factorials where one has power 1 and the other
|
|
9
|
+
* has power -1, computing their argument difference, and replacing with
|
|
10
|
+
* the product of consecutive integers.
|
|
11
|
+
*/
|
|
12
|
+
export declare function simplifyFactorials(x: Expression): Expression;
|
|
13
|
+
/**
|
|
14
|
+
* Combines logarithmic terms in a sum expression when their arguments are
|
|
15
|
+
* provably positive real values. Unknown-sign logarithms are left unchanged
|
|
16
|
+
* so these real-domain identities do not cross principal complex branches.
|
|
17
|
+
*
|
|
18
|
+
* Power lifting + combination:
|
|
19
|
+
* log(x) + log(y) → log(x·y) [combine, coeff=1]
|
|
20
|
+
* 2·log(x) + 3·log(y) → log(x²·y³) [lift then combine]
|
|
21
|
+
* (1/2)·log(x) → (1/2)·log(x) [rational, standalone: keep]
|
|
22
|
+
* (1/2)·log(x) + (1/3)·log(y) → log(x^(1/2)·y^(1/3)) [rational, combining: lift]
|
|
23
|
+
* a·log(u) + a·log(v) → a·log(u·v) [symbolic, group by coeff]
|
|
24
|
+
* log(a) - log(b) → log(a/b) [sign handling]
|
|
25
|
+
*/
|
|
26
|
+
export declare function simplifyLogs(x: Expression): Expression;
|