nerdamer 1.1.13 → 2.0.0-rc.2
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/BREAKING_CHANGES.md +244 -5
- package/LICENSE.md +184 -0
- package/README.md +232 -318
- 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 +2248 -0
- package/index.d.ts +10 -426
- package/output/algebra/adapters.d.ts +3 -0
- package/output/algebra/adapters.js +11 -0
- package/output/algebra/algorithms/arith.d.ts +84 -0
- package/output/algebra/algorithms/arith.js +324 -0
- package/output/algebra/algorithms/groebnerBase.d.ts +161 -0
- package/output/algebra/algorithms/groebnerBase.js +929 -0
- package/output/algebra/dispatch.d.ts +1 -0
- package/output/algebra/dispatch.js +25 -0
- package/output/algebra/factor/factor.d.ts +77 -0
- package/output/algebra/factor/factor.js +245 -0
- package/output/algebra/gcd/gcd.d.ts +30 -0
- package/output/algebra/gcd/gcd.js +95 -0
- package/output/algebra/groebner.d.ts +21 -0
- package/output/algebra/groebner.js +36 -0
- package/output/algebra/partfrac.d.ts +19 -0
- package/output/algebra/partfrac.js +365 -0
- package/output/algebra/polynomial/ModularSparsePolynomial.d.ts +131 -0
- package/output/algebra/polynomial/ModularSparsePolynomial.js +378 -0
- package/output/algebra/polynomial/ModularSparsePolynomialFactor.d.ts +40 -0
- package/output/algebra/polynomial/ModularSparsePolynomialFactor.js +661 -0
- package/output/algebra/polynomial/SparsePolynomialFactor.d.ts +64 -0
- package/output/algebra/polynomial/SparsePolynomialFactor.js +492 -0
- package/output/algebra/polynomial/SparsePolynomialGcd.d.ts +29 -0
- package/output/algebra/polynomial/SparsePolynomialGcd.js +259 -0
- package/output/algebra/polynomial/SparsePolynomialMultivariateFactor.d.ts +82 -0
- package/output/algebra/polynomial/SparsePolynomialMultivariateFactor.js +604 -0
- package/output/algebra/polynomial/modularGcd.d.ts +40 -0
- package/output/algebra/polynomial/modularGcd.js +365 -0
- package/output/algebra/polynomialize.d.ts +20 -0
- package/output/algebra/polynomialize.js +26 -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 +237 -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 +8 -0
- package/output/api/advanced.js +18 -0
- package/output/api/algebra.d.ts +17 -0
- package/output/api/algebra.js +35 -0
- package/output/api/assumptions.d.ts +4 -0
- package/output/api/assumptions.js +11 -0
- package/output/api/calculus.d.ts +10 -0
- package/output/api/calculus.js +22 -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/languages/deu.d.ts +3 -0
- package/output/api/languages/deu.js +266 -0
- package/output/api/languages/fra.d.ts +3 -0
- package/output/api/languages/fra.js +266 -0
- package/output/api/languages/ita.d.ts +3 -0
- package/output/api/languages/ita.js +266 -0
- package/output/api/languages/nld.d.ts +3 -0
- package/output/api/languages/nld.js +266 -0
- package/output/api/languages/por.d.ts +3 -0
- package/output/api/languages/por.js +266 -0
- package/output/api/languages/spa.d.ts +3 -0
- package/output/api/languages/spa.js +266 -0
- package/output/api/parser.d.ts +93 -0
- package/output/api/parser.js +18 -0
- package/output/api/solve.d.ts +10 -0
- package/output/api/solve.js +17 -0
- package/output/api/structures.d.ts +10 -0
- package/output/api/structures.js +23 -0
- package/output/calculus/adapters.d.ts +8 -0
- package/output/calculus/adapters.js +41 -0
- package/output/calculus/derivative/diff.d.ts +30 -0
- package/output/calculus/derivative/diff.js +241 -0
- package/output/calculus/dispatch.d.ts +1 -0
- package/output/calculus/dispatch.js +25 -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/classes/assumption/Assumption.d.ts +218 -0
- package/output/core/classes/assumption/Assumption.js +609 -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/assumption/dispatch.d.ts +1 -0
- package/output/core/classes/assumption/dispatch.js +11 -0
- package/output/core/classes/collection/Collection.d.ts +107 -0
- package/output/core/classes/collection/Collection.js +240 -0
- package/output/core/classes/complex/Complex.d.ts +109 -0
- package/output/core/classes/complex/Complex.js +153 -0
- package/output/core/classes/decimalSet/DecimalSet.d.ts +226 -0
- package/output/core/classes/decimalSet/DecimalSet.js +454 -0
- package/output/core/classes/dictionary/Dictionary.d.ts +102 -0
- package/output/core/classes/dictionary/Dictionary.js +216 -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 +197 -0
- package/output/core/classes/expression/Expression.d.ts +1691 -0
- package/output/core/classes/expression/Expression.js +2381 -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 +54 -0
- package/output/core/classes/expression/format.js +340 -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 +61 -0
- package/output/core/classes/expression/utils.js +235 -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 +901 -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/dispatch.d.ts +1 -0
- package/output/core/classes/matrix/dispatch.js +19 -0
- package/output/core/classes/matrix/functions.d.ts +28 -0
- package/output/core/classes/matrix/functions.js +57 -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 +493 -0
- package/output/core/classes/parser/Parser.js +1863 -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 +162 -0
- package/output/core/classes/parser/constants.js +229 -0
- package/output/core/classes/parser/controlFlowSignals.d.ts +38 -0
- package/output/core/classes/parser/controlFlowSignals.js +60 -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 +236 -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 +474 -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 +438 -0
- package/output/core/classes/parser/operations/multiply.d.ts +11 -0
- package/output/core/classes/parser/operations/multiply.js +328 -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 +36 -0
- package/output/core/classes/parser/preprocess.d.ts +7 -0
- package/output/core/classes/parser/preprocess.js +246 -0
- package/output/core/classes/parser/scripting/controlFlow.d.ts +23 -0
- package/output/core/classes/parser/scripting/controlFlow.js +279 -0
- package/output/core/classes/parser/scripting/deferred.d.ts +4 -0
- package/output/core/classes/parser/scripting/deferred.js +65 -0
- package/output/core/classes/parser/scripting/dispatch.d.ts +1 -0
- package/output/core/classes/parser/scripting/dispatch.js +62 -0
- package/output/core/classes/parser/scripting/evaluate.d.ts +23 -0
- package/output/core/classes/parser/scripting/evaluate.js +128 -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 +8 -0
- package/output/core/classes/parser/scripting/scope.js +132 -0
- package/output/core/classes/parser/types.d.ts +130 -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 +504 -0
- package/output/core/classes/polynomial/Polynomial.js +1195 -0
- package/output/core/classes/polynomial/SparsePolynomial.d.ts +221 -0
- package/output/core/classes/polynomial/SparsePolynomial.js +824 -0
- package/output/core/classes/polynomial/SparsePolynomialAdapter.d.ts +56 -0
- package/output/core/classes/polynomial/SparsePolynomialAdapter.js +241 -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/adapters.d.ts +18 -0
- package/output/core/classes/polynomial/adapters.js +33 -0
- package/output/core/classes/polynomial/dispatch.d.ts +1 -0
- package/output/core/classes/polynomial/dispatch.js +14 -0
- package/output/core/classes/polynomial/functions.d.ts +77 -0
- package/output/core/classes/polynomial/functions.js +189 -0
- package/output/core/classes/polynomial/utils.d.ts +62 -0
- package/output/core/classes/polynomial/utils.js +207 -0
- package/output/core/classes/rational/Rational.d.ts +501 -0
- package/output/core/classes/rational/Rational.js +829 -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 +187 -0
- package/output/core/classes/valuesSet/ValuesSet.js +399 -0
- package/output/core/classes/vector/Vector.d.ts +222 -0
- package/output/core/classes/vector/Vector.js +501 -0
- package/output/core/classes/vector/dispatch.d.ts +1 -0
- package/output/core/classes/vector/dispatch.js +11 -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 +149 -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 +62 -0
- package/output/core/common/common.js +74 -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 +806 -0
- package/output/core/converters/Pattern.d.ts +71 -0
- package/output/core/converters/Pattern.js +302 -0
- package/output/core/dispatch.d.ts +52 -0
- package/output/core/dispatch.js +26 -0
- package/output/core/errors.d.ts +316 -0
- package/output/core/errors.js +349 -0
- package/output/core/fullFunctions.d.ts +7 -0
- package/output/core/fullFunctions.js +31 -0
- package/output/core/functions/bigint/bigint.d.ts +133 -0
- package/output/core/functions/bigint/bigint.js +444 -0
- package/output/core/functions/bigint/primeFactor.d.ts +51 -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 +139 -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.dispatch.d.ts +1 -0
- package/output/core/functions/complex.dispatch.js +16 -0
- package/output/core/functions/complex.js +482 -0
- package/output/core/functions/decimal.d.ts +24 -0
- package/output/core/functions/decimal.js +665 -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 +102 -0
- package/output/core/functions/subst.d.ts +90 -0
- package/output/core/functions/subst.js +506 -0
- package/output/core/functions/utils.d.ts +24 -0
- package/output/core/functions/utils.js +51 -0
- package/output/core/parserFunctions.d.ts +7 -0
- package/output/core/parserFunctions.js +25 -0
- package/output/core/types.d.ts +48 -0
- package/output/core/types.js +2 -0
- package/output/index.d.ts +359 -0
- package/output/index.js +739 -0
- package/output/math/defint/defint.d.ts +18 -0
- package/output/math/defint/defint.js +60 -0
- package/output/math/defint/defintDecimal.d.ts +37 -0
- package/output/math/defint/defintDecimal.js +321 -0
- package/output/math/defint/defintNative.d.ts +57 -0
- package/output/math/defint/defintNative.js +281 -0
- package/output/math/dispatch.d.ts +1 -0
- package/output/math/dispatch.js +101 -0
- package/output/math/geometry.d.ts +12 -0
- package/output/math/geometry.js +55 -0
- package/output/math/math.d.ts +695 -0
- package/output/math/math.js +1955 -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 +66 -0
- package/output/math/utils.js +219 -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 +104 -0
- package/output/solve/classes/PolynomialSolver.js +492 -0
- package/output/solve/classes/SolutionSet.d.ts +172 -0
- package/output/solve/classes/SolutionSet.js +434 -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/dispatch.d.ts +1 -0
- package/output/solve/dispatch.js +13 -0
- package/output/solve/linsolve.d.ts +53 -0
- package/output/solve/linsolve.js +233 -0
- package/output/solve/solve.d.ts +44 -0
- package/output/solve/solve.js +368 -0
- package/output/solve/solveSystem.d.ts +31 -0
- package/output/solve/solveSystem.js +266 -0
- package/output/solve/utils.d.ts +10 -0
- package/output/solve/utils.js +58 -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 +296 -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 +178 -57
- package/.travis.yml +0 -3
- package/Algebra.js +0 -4568
- 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,492 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PolynomialSolver = void 0;
|
|
7
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
8
|
+
const Complex_1 = require("../../core/classes/complex/Complex");
|
|
9
|
+
const Expression_1 = require("../../core/classes/expression/Expression");
|
|
10
|
+
const Polynomial_1 = require("../../core/classes/polynomial/Polynomial");
|
|
11
|
+
const errors_1 = require("../../core/errors");
|
|
12
|
+
const bigint_1 = require("../../core/functions/bigint/bigint");
|
|
13
|
+
const DEFAULT_PRECISION = 50;
|
|
14
|
+
const DEFAULT_EPSILON = 1e-14;
|
|
15
|
+
const ABERTH_MAX_ITERATIONS = 100;
|
|
16
|
+
const ABERTH_INITIAL_ANGLE_OFFSET = 0.4;
|
|
17
|
+
const ABERTH_RADIUS_SCALE = 0.9;
|
|
18
|
+
const ABERTH_ROOT_SPACING_SCALE = 0.01;
|
|
19
|
+
const ABERTH_CONVERGENCE_SCALE = 1e-2;
|
|
20
|
+
const NEWTON_MAX_ITERATIONS = 20;
|
|
21
|
+
const NEWTON_CONVERGENCE_SCALE = 1e-6;
|
|
22
|
+
const NATIVE_EPSILON_SCALE = 16;
|
|
23
|
+
/**
|
|
24
|
+
* Finds all complex roots of a univariate polynomial numerically.
|
|
25
|
+
*
|
|
26
|
+
* Coefficient arrays use ascending powers: the element at index `k` is the
|
|
27
|
+
* coefficient of `x^k`. Expression, Polynomial, and string inputs are converted directly
|
|
28
|
+
* to numerical complex coefficients before solving. Linear and quadratic inputs are handled
|
|
29
|
+
* directly; higher degrees use simultaneous Aberth iteration followed by
|
|
30
|
+
* Newton refinement.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* The solver temporarily changes the global `decimal.js` precision while
|
|
34
|
+
* {@link roots} runs and restores the previous precision before returning.
|
|
35
|
+
* The requested precision controls the numerical work, while `epsilon`
|
|
36
|
+
* controls convergence and cleanup of numerical noise. Roots are returned
|
|
37
|
+
* once per polynomial degree, so repeated roots can appear as repeated nearby
|
|
38
|
+
* approximations.
|
|
39
|
+
*
|
|
40
|
+
* This class finds numerical roots; it does not certify completeness or exact
|
|
41
|
+
* multiplicities for ill-conditioned polynomials.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const solver = new PolynomialSolver('x^2+1', 'x');
|
|
46
|
+
* const roots = solver.roots();
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
class PolynomialSolver {
|
|
50
|
+
degree;
|
|
51
|
+
eps;
|
|
52
|
+
p;
|
|
53
|
+
precision;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a polynomial root solver.
|
|
56
|
+
*
|
|
57
|
+
* @param input - A polynomial expression, Polynomial, polynomial string, or ascending-power
|
|
58
|
+
* Decimal coefficients.
|
|
59
|
+
* @param variable - Variable expected in polynomial or string input. It is used to reject
|
|
60
|
+
* a conflicting variable or multivariate polynomial.
|
|
61
|
+
* @param precision - Working `decimal.js` precision used while finding roots.
|
|
62
|
+
* @param epsilon - Numerical convergence tolerance. Defaults to `1e-14`.
|
|
63
|
+
* @throws {@link core!UnexpectedInputError} If symbolic input is multivariate, uses a
|
|
64
|
+
* variable different from `variable`, or has nonnumeric coefficients.
|
|
65
|
+
*/
|
|
66
|
+
constructor(input, variable, precision = DEFAULT_PRECISION, epsilon) {
|
|
67
|
+
let coefficients;
|
|
68
|
+
if (Array.isArray(input)) {
|
|
69
|
+
coefficients = input.map(coefficient => new Complex_1.Complex(coefficient, 0));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const polynomialInput = Polynomial_1.Polynomial.isPolynomial(input);
|
|
73
|
+
const expression = polynomialInput
|
|
74
|
+
? input.getExpression()
|
|
75
|
+
: typeof input === 'string'
|
|
76
|
+
? Expression_1.Expression.create(input)
|
|
77
|
+
: input;
|
|
78
|
+
const variables = polynomialInput ? input.variables : expression.variables();
|
|
79
|
+
if (!expression.isPolynomialLike()) {
|
|
80
|
+
throw new errors_1.PolynomialError((0, errors_1.message)('notAPolynomial'));
|
|
81
|
+
}
|
|
82
|
+
if (variables.length > 1 ||
|
|
83
|
+
(variables.length === 1 && variable && variables[0] !== variable)) {
|
|
84
|
+
throw new errors_1.UnexpectedInputError((0, errors_1.message)('tooManyUnknowns'));
|
|
85
|
+
}
|
|
86
|
+
const coefficientVariable = variable ?? variables[0];
|
|
87
|
+
const coefficientExpressions = coefficientVariable === undefined
|
|
88
|
+
? [expression]
|
|
89
|
+
: expression.coeffs(coefficientVariable).toArray();
|
|
90
|
+
const numericComponents = coefficientExpressions.map(coefficient => {
|
|
91
|
+
const real = coefficient.realPart();
|
|
92
|
+
const imaginary = coefficient.imagPart();
|
|
93
|
+
if (!real.isNUM() || !imaginary.isNUM()) {
|
|
94
|
+
throw new errors_1.UnexpectedInputError((0, errors_1.message)('wrongInput', {
|
|
95
|
+
expected: 'numeric polynomial coefficients',
|
|
96
|
+
received: coefficient.text(),
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
real: real.getMultiplier(),
|
|
101
|
+
imaginary: imaginary.getMultiplier(),
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
const exactRationals = numericComponents.every(component => !component.real.asDecimal && !component.imaginary.asDecimal);
|
|
105
|
+
if (exactRationals) {
|
|
106
|
+
const commonDenominator = (0, bigint_1.LCM)(...numericComponents.flatMap(component => [
|
|
107
|
+
component.real.denominator,
|
|
108
|
+
component.imaginary.denominator,
|
|
109
|
+
]));
|
|
110
|
+
coefficients = numericComponents.map(component => {
|
|
111
|
+
const real = component.real.numerator *
|
|
112
|
+
(commonDenominator / component.real.denominator);
|
|
113
|
+
const imaginary = component.imaginary.numerator *
|
|
114
|
+
(commonDenominator / component.imaginary.denominator);
|
|
115
|
+
return new Complex_1.Complex(new decimal_js_1.default(String(real)), new decimal_js_1.default(String(imaginary)));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
coefficients = numericComponents.map(component => new Complex_1.Complex(component.real.toDecimal(), component.imaginary.toDecimal()));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Reverse the coefficients so p[0] is the leading coefficient
|
|
123
|
+
this.p = coefficients.slice().reverse();
|
|
124
|
+
this.degree = this.p.length - 1;
|
|
125
|
+
this.eps = epsilon || new decimal_js_1.default(DEFAULT_EPSILON);
|
|
126
|
+
this.precision = precision;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Aberth method: simultaneous approximation of all roots
|
|
130
|
+
* More stable than deflation for high-degree polynomials
|
|
131
|
+
*/
|
|
132
|
+
aberthMethod(P) {
|
|
133
|
+
const n = P.length - 1;
|
|
134
|
+
// Initialize roots on a circle
|
|
135
|
+
const roots = [];
|
|
136
|
+
const radius = this.rootMagnitudeBound(P);
|
|
137
|
+
for (let k = 0; k < n; k++) {
|
|
138
|
+
const angle = new decimal_js_1.default(2).mul(Math.PI).mul(k).div(n).plus(ABERTH_INITIAL_ANGLE_OFFSET);
|
|
139
|
+
const r = radius
|
|
140
|
+
.mul(ABERTH_RADIUS_SCALE)
|
|
141
|
+
.mul(new decimal_js_1.default(1).plus(new decimal_js_1.default(k).mul(ABERTH_ROOT_SPACING_SCALE).div(n)));
|
|
142
|
+
roots.push(new Complex_1.Complex(r.mul(decimal_js_1.default.cos(angle)), r.mul(decimal_js_1.default.sin(angle))));
|
|
143
|
+
}
|
|
144
|
+
const epsSquared = this.eps.mul(this.eps);
|
|
145
|
+
const convergenceTolerance = this.eps.mul(ABERTH_CONVERGENCE_SCALE);
|
|
146
|
+
const convergenceToleranceSquared = convergenceTolerance.mul(convergenceTolerance);
|
|
147
|
+
// Aberth iterations
|
|
148
|
+
for (let iter = 0; iter < ABERTH_MAX_ITERATIONS; iter++) {
|
|
149
|
+
let maxChangeSquared = new decimal_js_1.default(0);
|
|
150
|
+
const newRoots = [];
|
|
151
|
+
for (let i = 0; i < n; i++) {
|
|
152
|
+
const z = roots[i];
|
|
153
|
+
// Compute P(z) and P'(z) together.
|
|
154
|
+
const [pz, dpz] = this.evaluateWithDerivative(P, z);
|
|
155
|
+
if (dpz.absSquared().lessThan(epsSquared)) {
|
|
156
|
+
newRoots.push(z);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
// Compute Aberth correction
|
|
160
|
+
const newton = pz.div(dpz);
|
|
161
|
+
// Sum of 1/(z_i - z_j) for j != i
|
|
162
|
+
let sum = new Complex_1.Complex(0, 0);
|
|
163
|
+
for (let j = 0; j < n; j++) {
|
|
164
|
+
if (i !== j) {
|
|
165
|
+
const diff = z.sub(roots[j]);
|
|
166
|
+
if (diff.absSquared().greaterThan(epsSquared)) {
|
|
167
|
+
sum = sum.add(diff.reciprocal());
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Aberth correction: w = N(z) / (1 - N(z) * sum)
|
|
172
|
+
const denom = new Complex_1.Complex(1, 0).sub(newton.mul(sum));
|
|
173
|
+
const correction = denom.absSquared().lessThan(epsSquared)
|
|
174
|
+
? newton
|
|
175
|
+
: newton.div(denom);
|
|
176
|
+
const newZ = z.sub(correction);
|
|
177
|
+
newRoots.push(newZ);
|
|
178
|
+
const changeSquared = correction.absSquared();
|
|
179
|
+
if (changeSquared.greaterThan(maxChangeSquared)) {
|
|
180
|
+
maxChangeSquared = changeSquared;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
for (let i = 0; i < n; i++) {
|
|
184
|
+
roots[i] = newRoots[i];
|
|
185
|
+
}
|
|
186
|
+
// Check convergence
|
|
187
|
+
if (maxChangeSquared.lessThan(convergenceToleranceSquared)) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Final refinement with Newton's method
|
|
192
|
+
for (let i = 0; i < n; i++) {
|
|
193
|
+
roots[i] = this.newtonRefine(P, roots[i]);
|
|
194
|
+
}
|
|
195
|
+
return roots;
|
|
196
|
+
}
|
|
197
|
+
complexSqrt(z) {
|
|
198
|
+
const mag = z.abs();
|
|
199
|
+
if (mag.isZero()) {
|
|
200
|
+
return new Complex_1.Complex(0, 0);
|
|
201
|
+
}
|
|
202
|
+
const x = z.re;
|
|
203
|
+
const y = z.im;
|
|
204
|
+
if (y.abs().lessThan(this.eps)) {
|
|
205
|
+
if (x.greaterThanOrEqualTo(0)) {
|
|
206
|
+
return new Complex_1.Complex(x.sqrt(), 0);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
return new Complex_1.Complex(0, x.neg().sqrt());
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const w = mag.plus(x.abs()).div(2).sqrt();
|
|
213
|
+
if (x.greaterThanOrEqualTo(0)) {
|
|
214
|
+
return new Complex_1.Complex(w, y.div(w.mul(2)));
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
const absY = y.abs();
|
|
218
|
+
const imPart = y.greaterThanOrEqualTo(0) ? w : w.neg();
|
|
219
|
+
return new Complex_1.Complex(absY.div(w.mul(2)), imPart);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Evaluates a polynomial and its derivative together using Horner's method.
|
|
224
|
+
*/
|
|
225
|
+
evaluateWithDerivative(P, z) {
|
|
226
|
+
const n = P.length - 1;
|
|
227
|
+
let value = P[0];
|
|
228
|
+
let derivative = P[0];
|
|
229
|
+
for (let i = 1; i < n; i++) {
|
|
230
|
+
value = value.mul(z).add(P[i]);
|
|
231
|
+
derivative = derivative.mul(z).add(value);
|
|
232
|
+
}
|
|
233
|
+
value = value.mul(z).add(P[n]);
|
|
234
|
+
return [value, derivative];
|
|
235
|
+
}
|
|
236
|
+
finalize(roots, asExpressions, precision, cleanupComponents = true) {
|
|
237
|
+
// Restore the precision
|
|
238
|
+
decimal_js_1.default.set({ precision: precision });
|
|
239
|
+
if (asExpressions) {
|
|
240
|
+
return roots.map(root => {
|
|
241
|
+
let re = root.re;
|
|
242
|
+
let im = root.im;
|
|
243
|
+
if (cleanupComponents) {
|
|
244
|
+
const magnitude = root.abs();
|
|
245
|
+
const componentTolerance = magnitude.mul(this.eps);
|
|
246
|
+
re = root.re.abs().lt(componentTolerance) ? new decimal_js_1.default(0) : root.re;
|
|
247
|
+
im = root.im.abs().lt(componentTolerance) ? new decimal_js_1.default(0) : root.im;
|
|
248
|
+
}
|
|
249
|
+
const retval = Expression_1.Expression.create(re).plus(Expression_1.Expression.Img().times(im));
|
|
250
|
+
return retval;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
return roots;
|
|
254
|
+
}
|
|
255
|
+
isNumericalRoot(root) {
|
|
256
|
+
let residual = this.p[0];
|
|
257
|
+
let scale = this.p[0].abs();
|
|
258
|
+
const magnitude = root.abs();
|
|
259
|
+
for (let i = 1; i < this.p.length; i++) {
|
|
260
|
+
residual = residual.mul(root).add(this.p[i]);
|
|
261
|
+
scale = scale.mul(magnitude).plus(this.p[i].abs());
|
|
262
|
+
}
|
|
263
|
+
const tolerance = this.eps.mul(scale.plus(1));
|
|
264
|
+
return residual.absSquared().lte(tolerance.mul(tolerance));
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Uses native double-precision arithmetic to locate starting points for Decimal refinement.
|
|
268
|
+
*
|
|
269
|
+
* Returning `null` leaves the existing Decimal Aberth implementation responsible for the
|
|
270
|
+
* complete solve.
|
|
271
|
+
*/
|
|
272
|
+
nativeAberthSeeds(P) {
|
|
273
|
+
const n = P.length - 1;
|
|
274
|
+
const nativeP = [];
|
|
275
|
+
for (const coefficient of P) {
|
|
276
|
+
const re = coefficient.re.toNumber();
|
|
277
|
+
const im = coefficient.im.toNumber();
|
|
278
|
+
if (!Number.isFinite(re) || !Number.isFinite(im)) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
nativeP.push({ re, im });
|
|
282
|
+
}
|
|
283
|
+
const leadMagnitude = Math.hypot(nativeP[0].re, nativeP[0].im);
|
|
284
|
+
if (!Number.isFinite(leadMagnitude) || leadMagnitude === 0) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
const radius = this.rootMagnitudeBound(P).toNumber();
|
|
288
|
+
if (!Number.isFinite(radius)) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const roots = [];
|
|
292
|
+
for (let k = 0; k < n; k++) {
|
|
293
|
+
const angle = (2 * Math.PI * k) / n + ABERTH_INITIAL_ANGLE_OFFSET;
|
|
294
|
+
const r = radius *
|
|
295
|
+
ABERTH_RADIUS_SCALE *
|
|
296
|
+
(1 + (k * ABERTH_ROOT_SPACING_SCALE) / n);
|
|
297
|
+
roots.push({ re: r * Math.cos(angle), im: r * Math.sin(angle) });
|
|
298
|
+
}
|
|
299
|
+
const nativeTolerance = Math.max(this.eps.toNumber(), Number.EPSILON * NATIVE_EPSILON_SCALE);
|
|
300
|
+
const epsSquared = nativeTolerance * nativeTolerance;
|
|
301
|
+
for (let iter = 0; iter < ABERTH_MAX_ITERATIONS; iter++) {
|
|
302
|
+
let maxChangeSquared = 0;
|
|
303
|
+
const newRoots = [];
|
|
304
|
+
for (let i = 0; i < n; i++) {
|
|
305
|
+
const z = roots[i];
|
|
306
|
+
let valueRe = nativeP[0].re;
|
|
307
|
+
let valueIm = nativeP[0].im;
|
|
308
|
+
let derivativeRe = nativeP[0].re;
|
|
309
|
+
let derivativeIm = nativeP[0].im;
|
|
310
|
+
for (let k = 1; k < n; k++) {
|
|
311
|
+
const nextValueRe = valueRe * z.re - valueIm * z.im + nativeP[k].re;
|
|
312
|
+
const nextValueIm = valueRe * z.im + valueIm * z.re + nativeP[k].im;
|
|
313
|
+
const nextDerivativeRe = derivativeRe * z.re - derivativeIm * z.im + nextValueRe;
|
|
314
|
+
const nextDerivativeIm = derivativeRe * z.im + derivativeIm * z.re + nextValueIm;
|
|
315
|
+
valueRe = nextValueRe;
|
|
316
|
+
valueIm = nextValueIm;
|
|
317
|
+
derivativeRe = nextDerivativeRe;
|
|
318
|
+
derivativeIm = nextDerivativeIm;
|
|
319
|
+
}
|
|
320
|
+
const finalValueRe = valueRe * z.re - valueIm * z.im + nativeP[n].re;
|
|
321
|
+
const finalValueIm = valueRe * z.im + valueIm * z.re + nativeP[n].im;
|
|
322
|
+
const derivativeMagnitudeSquared = derivativeRe * derivativeRe + derivativeIm * derivativeIm;
|
|
323
|
+
if (!Number.isFinite(finalValueRe) ||
|
|
324
|
+
!Number.isFinite(finalValueIm) ||
|
|
325
|
+
!Number.isFinite(derivativeMagnitudeSquared)) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
if (derivativeMagnitudeSquared < epsSquared) {
|
|
329
|
+
newRoots.push(z);
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const newtonRe = (finalValueRe * derivativeRe + finalValueIm * derivativeIm) /
|
|
333
|
+
derivativeMagnitudeSquared;
|
|
334
|
+
const newtonIm = (finalValueIm * derivativeRe - finalValueRe * derivativeIm) /
|
|
335
|
+
derivativeMagnitudeSquared;
|
|
336
|
+
let sumRe = 0;
|
|
337
|
+
let sumIm = 0;
|
|
338
|
+
for (let j = 0; j < n; j++) {
|
|
339
|
+
if (i === j) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const diffRe = z.re - roots[j].re;
|
|
343
|
+
const diffIm = z.im - roots[j].im;
|
|
344
|
+
const diffMagnitudeSquared = diffRe * diffRe + diffIm * diffIm;
|
|
345
|
+
if (diffMagnitudeSquared > epsSquared) {
|
|
346
|
+
sumRe += diffRe / diffMagnitudeSquared;
|
|
347
|
+
sumIm -= diffIm / diffMagnitudeSquared;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const productRe = newtonRe * sumRe - newtonIm * sumIm;
|
|
351
|
+
const productIm = newtonRe * sumIm + newtonIm * sumRe;
|
|
352
|
+
const denomRe = 1 - productRe;
|
|
353
|
+
const denomIm = -productIm;
|
|
354
|
+
const denomMagnitudeSquared = denomRe * denomRe + denomIm * denomIm;
|
|
355
|
+
let correctionRe = newtonRe;
|
|
356
|
+
let correctionIm = newtonIm;
|
|
357
|
+
if (denomMagnitudeSquared >= epsSquared) {
|
|
358
|
+
correctionRe =
|
|
359
|
+
(newtonRe * denomRe + newtonIm * denomIm) / denomMagnitudeSquared;
|
|
360
|
+
correctionIm =
|
|
361
|
+
(newtonIm * denomRe - newtonRe * denomIm) / denomMagnitudeSquared;
|
|
362
|
+
}
|
|
363
|
+
const newRoot = {
|
|
364
|
+
re: z.re - correctionRe,
|
|
365
|
+
im: z.im - correctionIm,
|
|
366
|
+
};
|
|
367
|
+
const changeSquared = correctionRe * correctionRe + correctionIm * correctionIm;
|
|
368
|
+
if (!Number.isFinite(newRoot.re) ||
|
|
369
|
+
!Number.isFinite(newRoot.im) ||
|
|
370
|
+
!Number.isFinite(changeSquared)) {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
newRoots.push(newRoot);
|
|
374
|
+
maxChangeSquared = Math.max(maxChangeSquared, changeSquared);
|
|
375
|
+
}
|
|
376
|
+
for (let i = 0; i < n; i++) {
|
|
377
|
+
roots[i] = newRoots[i];
|
|
378
|
+
}
|
|
379
|
+
if (maxChangeSquared < epsSquared) {
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return roots.map(root => new Complex_1.Complex(new decimal_js_1.default(root.re), new decimal_js_1.default(root.im)));
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Refine a single root using Newton's method
|
|
387
|
+
*/
|
|
388
|
+
newtonRefine(P, z) {
|
|
389
|
+
const epsSquared = this.eps.mul(this.eps);
|
|
390
|
+
const convergenceTolerance = this.eps.mul(NEWTON_CONVERGENCE_SCALE);
|
|
391
|
+
const convergenceToleranceSquared = convergenceTolerance.mul(convergenceTolerance);
|
|
392
|
+
for (let iter = 0; iter < NEWTON_MAX_ITERATIONS; iter++) {
|
|
393
|
+
const [pz, dpz] = this.evaluateWithDerivative(P, z);
|
|
394
|
+
if (pz.absSquared().lessThan(convergenceToleranceSquared)) {
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
if (dpz.absSquared().lessThan(epsSquared)) {
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
const correction = pz.div(dpz);
|
|
401
|
+
const newZ = z.sub(correction);
|
|
402
|
+
if (correction.abs().lessThan(convergenceTolerance.mul(newZ.abs().plus(1)))) {
|
|
403
|
+
z = newZ;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
z = newZ;
|
|
407
|
+
}
|
|
408
|
+
return z;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Computes a Lagrange-Fujiwara upper bound for root magnitudes.
|
|
412
|
+
*
|
|
413
|
+
* For a polynomial with leading coefficient a_n, every root lies within
|
|
414
|
+
* 2 * max(|a_(n-i) / a_n|^(1/i)). This is substantially tighter than the
|
|
415
|
+
* simple Cauchy bound for polynomials with large middle coefficients.
|
|
416
|
+
*
|
|
417
|
+
* @see https://doi.org/10.1016/S0377-0427(03)00381-9
|
|
418
|
+
*/
|
|
419
|
+
rootMagnitudeBound(P) {
|
|
420
|
+
let maxCandidate = new decimal_js_1.default(0);
|
|
421
|
+
const leadingMagnitude = P[0].abs();
|
|
422
|
+
for (let i = 1; i < P.length; i++) {
|
|
423
|
+
const ratio = P[i].abs().div(leadingMagnitude);
|
|
424
|
+
if (!ratio.isZero()) {
|
|
425
|
+
const candidate = ratio.pow(new decimal_js_1.default(1).div(i));
|
|
426
|
+
if (candidate.greaterThan(maxCandidate)) {
|
|
427
|
+
maxCandidate = candidate;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return maxCandidate.mul(2);
|
|
432
|
+
}
|
|
433
|
+
solveQuadratic(p) {
|
|
434
|
+
const a = p[0];
|
|
435
|
+
const b = p[1];
|
|
436
|
+
const c = p[2];
|
|
437
|
+
const b2 = b.mul(b);
|
|
438
|
+
const ac4 = a.mul(c).scale(4);
|
|
439
|
+
const disc = b2.sub(ac4);
|
|
440
|
+
const sqrtDisc = this.complexSqrt(disc);
|
|
441
|
+
const twoA = a.scale(2);
|
|
442
|
+
const negB = b.neg();
|
|
443
|
+
return [negB.add(sqrtDisc).div(twoA), negB.sub(sqrtDisc).div(twoA)];
|
|
444
|
+
}
|
|
445
|
+
roots(asExpressions = true) {
|
|
446
|
+
// Store the currently used precision
|
|
447
|
+
const precision = decimal_js_1.default.precision;
|
|
448
|
+
// Set the precision to a high number. Default = 50
|
|
449
|
+
decimal_js_1.default.set({ precision: this.precision });
|
|
450
|
+
// Remove leading zeros and normalize
|
|
451
|
+
let poly = [...this.p];
|
|
452
|
+
let deg = this.degree;
|
|
453
|
+
while (deg > 0 && poly[0].re.isZero() && poly[0].im.isZero()) {
|
|
454
|
+
poly.shift();
|
|
455
|
+
deg--;
|
|
456
|
+
}
|
|
457
|
+
if (deg === 0) {
|
|
458
|
+
return this.finalize([], asExpressions, precision);
|
|
459
|
+
}
|
|
460
|
+
const lead = poly[0];
|
|
461
|
+
poly = poly.map(c => c.div(lead));
|
|
462
|
+
if (deg === 1) {
|
|
463
|
+
return this.finalize([poly[1].neg()], asExpressions, precision);
|
|
464
|
+
}
|
|
465
|
+
if (deg === 2) {
|
|
466
|
+
// Quadratic roots are computed analytically, so preserve small components instead of
|
|
467
|
+
// treating them as iterative noise.
|
|
468
|
+
return this.finalize(this.solveQuadratic(poly), asExpressions, precision, false);
|
|
469
|
+
}
|
|
470
|
+
// Native doubles are sufficient to locate ordinary roots. Refine those seeds with
|
|
471
|
+
// Decimal arithmetic and accept them only when every root passes the existing residual check.
|
|
472
|
+
const nativeSeeds = this.nativeAberthSeeds(poly);
|
|
473
|
+
if (nativeSeeds) {
|
|
474
|
+
const nativeRoots = nativeSeeds.map(root => this.newtonRefine(poly, root));
|
|
475
|
+
if (nativeRoots.length === deg &&
|
|
476
|
+
nativeRoots.every(root => this.isNumericalRoot(root))) {
|
|
477
|
+
return this.finalize(nativeRoots, asExpressions, precision);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// Fall back to the Decimal Aberth implementation when native seeding is unavailable
|
|
481
|
+
// or does not survive Decimal refinement and validation.
|
|
482
|
+
const roots = this.aberthMethod(poly);
|
|
483
|
+
return this.finalize(roots, asExpressions, precision);
|
|
484
|
+
}
|
|
485
|
+
validatedRoots(asExpressions = true) {
|
|
486
|
+
const precision = decimal_js_1.default.precision;
|
|
487
|
+
decimal_js_1.default.set({ precision: this.precision });
|
|
488
|
+
const roots = this.roots(false).filter(root => this.isNumericalRoot(root));
|
|
489
|
+
return this.finalize(roots, asExpressions, precision);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
exports.PolynomialSolver = PolynomialSolver;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Expression } from '../../core/classes/expression/Expression';
|
|
2
|
+
import { SOLUTIONS_SET } from '../../core/classes/parser/constants';
|
|
3
|
+
import { ValuesSet } from '../../core/classes/valuesSet/ValuesSet';
|
|
4
|
+
import type { ParserValuesObject } from '../../core/classes/parser/types';
|
|
5
|
+
import type { ParserEntity } from '../../core/types';
|
|
6
|
+
import type { Root } from './FunctionSolver';
|
|
7
|
+
/** Describes whether accepted solutions were produced by numerical strategies, symbolic strategies, or both. */
|
|
8
|
+
export type SolutionsType = 'numeric' | 'symbolic' | 'mixed' | undefined;
|
|
9
|
+
/** Describes whether the stored descriptors represent finite solutions, indexed families, or all values. */
|
|
10
|
+
export type SolutionForm = 'finite' | 'parametric' | 'all';
|
|
11
|
+
/**
|
|
12
|
+
* A finite set of solution descriptors with solver-specific metadata.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* `SolutionSet` inherits the finite-set storage semantics of {@link ValuesSet}: accepted
|
|
16
|
+
* descriptors are unique by symbolic equality, insertion order has no mathematical meaning,
|
|
17
|
+
* and values exposed through {@link elements} are copies rather than mutable references into
|
|
18
|
+
* the set. A descriptor normally represents one solution, but a descriptor containing the
|
|
19
|
+
* reserved `_n` index represents a parameterized family where `_n` ranges over the integers.
|
|
20
|
+
* The special `all` descriptor represents every value of the solved variable. Consequently,
|
|
21
|
+
* {@link count} reports the number of stored descriptors, not the cardinality of the
|
|
22
|
+
* mathematical solution set.
|
|
23
|
+
*
|
|
24
|
+
* {@link solutionsType} records solver provenance: whether accepted descriptors came from
|
|
25
|
+
* numerical strategies, symbolic/exact strategies, or both. It is not inferred from the
|
|
26
|
+
* printed shape of a descriptor, so a symbolic strategy may produce a value such as `1`.
|
|
27
|
+
* The orthogonal {@link solutionForm} property is derived from representation and distinguishes
|
|
28
|
+
* finite results, `_n`-indexed parametric families, and the `all` result.
|
|
29
|
+
*
|
|
30
|
+
* The class narrows membership to {@link Expression} values and keeps rejected singular
|
|
31
|
+
* candidates and numerical root metadata alongside the accepted solutions.
|
|
32
|
+
*
|
|
33
|
+
* Excluded values are enforced solver state, not merely advisory metadata. Once a value is excluded,
|
|
34
|
+
* adding the same value does not reintroduce it; excluding an already accepted value removes
|
|
35
|
+
* it from the solution set. {@link copy} preserves accepted values, exclusions, raw roots,
|
|
36
|
+
* partial-result state, solution type, and the unresolved expression when one is present.
|
|
37
|
+
*/
|
|
38
|
+
export declare class SolutionSet extends ValuesSet {
|
|
39
|
+
private excluded;
|
|
40
|
+
private roots;
|
|
41
|
+
dataType: typeof SOLUTIONS_SET;
|
|
42
|
+
partial: boolean;
|
|
43
|
+
/** Solver provenance for the currently accepted descriptors. */
|
|
44
|
+
solutionsType: SolutionsType;
|
|
45
|
+
unsolved?: Expression;
|
|
46
|
+
constructor(values?: Iterable<Expression>);
|
|
47
|
+
/** Tests whether a value is specifically a solver `SolutionSet`. */
|
|
48
|
+
static isSolutionSet(obj: unknown): obj is SolutionSet;
|
|
49
|
+
/**
|
|
50
|
+
* Combines numerical/symbolic provenance without changing any other solver state.
|
|
51
|
+
*/
|
|
52
|
+
private mergeSolutionsType;
|
|
53
|
+
/**
|
|
54
|
+
* Verifies and admits one candidate, reporting whether it belongs to this result after
|
|
55
|
+
* verification. Keeping this decision inside the same path used by {@link addSolution}
|
|
56
|
+
* avoids mistaking a pre-existing equal descriptor for a newly verified source candidate.
|
|
57
|
+
*/
|
|
58
|
+
private verifyAndAddSolution;
|
|
59
|
+
/**
|
|
60
|
+
* Replaces a parser-indexed solution while preserving Expression-only membership and
|
|
61
|
+
* uniqueness.
|
|
62
|
+
*/
|
|
63
|
+
__set__(indices: number[], value: ParserEntity): void;
|
|
64
|
+
/**
|
|
65
|
+
* Adds an accepted solution unless it is already present or explicitly excluded.
|
|
66
|
+
*/
|
|
67
|
+
add(x: Expression): SolutionSet;
|
|
68
|
+
/**
|
|
69
|
+
* Adds accepted solutions while preserving uniqueness and exclusions.
|
|
70
|
+
* The iterable is validated before the set is changed, so invalid input cannot leave a
|
|
71
|
+
* partially updated result.
|
|
72
|
+
*/
|
|
73
|
+
addMany(x: Iterable<Expression>): SolutionSet;
|
|
74
|
+
/**
|
|
75
|
+
* Stores numerical root-refinement metadata independently of the caller's object.
|
|
76
|
+
*/
|
|
77
|
+
addRawRoot(root: Root): SolutionSet;
|
|
78
|
+
/**
|
|
79
|
+
* Verifies a candidate against the source expression before admitting it to the set.
|
|
80
|
+
*
|
|
81
|
+
* Parameterized candidates that cannot yet be closed numerically are preserved. Closed
|
|
82
|
+
* residuals must evaluate nearly to zero. Candidates that encounter exact division by
|
|
83
|
+
* zero are recorded as exclusions instead.
|
|
84
|
+
*/
|
|
85
|
+
addSolution(solution: Expression, forFunction: Expression, variable: string): this;
|
|
86
|
+
/**
|
|
87
|
+
* Verifies and adds every candidate in an array or another `SolutionSet`.
|
|
88
|
+
*
|
|
89
|
+
* When the source is a `SolutionSet`, its numerical/symbolic provenance is retained if
|
|
90
|
+
* at least one source descriptor survives verification. Context-specific metadata such as
|
|
91
|
+
* exclusions, raw roots, partial state, and unresolved expressions is not transferred;
|
|
92
|
+
* use {@link append} when the complete solver result should be merged without revalidation.
|
|
93
|
+
*/
|
|
94
|
+
addSolutions(arr: Expression[] | SolutionSet, forFunction: Expression, variable: string): this;
|
|
95
|
+
/**
|
|
96
|
+
* Adds a batch of numerical solutions that has already been validated against its source
|
|
97
|
+
* polynomial. Incoming values are deduplicated by their exact numeric components before
|
|
98
|
+
* storage so a numerical root batch does not require pairwise symbolic equality checks.
|
|
99
|
+
*
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
addValidatedNumericalSolutions(values: Iterable<Expression>): SolutionSet;
|
|
103
|
+
/**
|
|
104
|
+
* Appends another solution result while preserving set and solver metadata.
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* Exclusions are merged before accepted values so an excluded candidate cannot be
|
|
108
|
+
* reintroduced. Raw numerical-root records are copied. `partial` is combined with logical
|
|
109
|
+
* OR and differing defined solution types become `mixed`. If this set has no `unsolved`
|
|
110
|
+
* expression, the appended set's unresolved expression is copied; when both sets already
|
|
111
|
+
* carry different unresolved expressions, the receiver's value is retained because the
|
|
112
|
+
* current data model can represent only one such expression.
|
|
113
|
+
*/
|
|
114
|
+
append(s: SolutionSet): SolutionSet;
|
|
115
|
+
/**
|
|
116
|
+
* Appends numerical solutions that were already validated by a numerical solver.
|
|
117
|
+
*
|
|
118
|
+
* This follows the same metadata and exclusion handling as {@link append}, but avoids
|
|
119
|
+
* repeating symbolic membership checks for a batch that has already been numerically
|
|
120
|
+
* validated and deduplicated.
|
|
121
|
+
*
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
appendValidatedNumerical(s: SolutionSet): SolutionSet;
|
|
125
|
+
/** Returns an independent Expression copy at the requested insertion-order index. */
|
|
126
|
+
at(i: number): Expression | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Removes accepted solutions and all solver state so the instance can be reused.
|
|
129
|
+
*/
|
|
130
|
+
clear(): this;
|
|
131
|
+
/** Returns an independent copy including exclusions and raw-root metadata. */
|
|
132
|
+
copy(): SolutionSet;
|
|
133
|
+
/**
|
|
134
|
+
* Visits or maps accepted solutions in insertion order.
|
|
135
|
+
*
|
|
136
|
+
* Returning an Expression replaces the current solution while preserving uniqueness and
|
|
137
|
+
* exclusions. Returning `void` leaves the current solution unchanged, which allows the
|
|
138
|
+
* same method to be used for straightforward inspection without a dummy `return e`.
|
|
139
|
+
*/
|
|
140
|
+
each(callback: (e: Expression, i?: string | number, j?: string | number) => Expression | void): this;
|
|
141
|
+
each(callback: (e: ParserEntity, i?: string | number, j?: string | number) => ParserEntity | void): this;
|
|
142
|
+
/** Returns deep-copied accepted solution descriptors in deterministic insertion order. */
|
|
143
|
+
get elements(): Expression[];
|
|
144
|
+
evaluate(values?: ParserValuesObject): SolutionSet;
|
|
145
|
+
/**
|
|
146
|
+
* Adds exclusions and removes any matching values that were already accepted.
|
|
147
|
+
*/
|
|
148
|
+
exclude(set: SolutionSet | ValuesSet): SolutionSet;
|
|
149
|
+
expand(): SolutionSet;
|
|
150
|
+
/** Visits independent Expression copies without changing this solution set. */
|
|
151
|
+
forEach(callback: (e: Expression, index: number) => void): void;
|
|
152
|
+
/** Returns an independent copy of the currently excluded values. */
|
|
153
|
+
getExcluded(): ValuesSet;
|
|
154
|
+
/**
|
|
155
|
+
* Returns independent copies of the stored numerical root-refinement records.
|
|
156
|
+
*/
|
|
157
|
+
getRawRoots(): Root[];
|
|
158
|
+
/**
|
|
159
|
+
* Classifies the mathematical result represented by the stored descriptors.
|
|
160
|
+
*
|
|
161
|
+
* Arbitrary symbolic parameters do not make a result parametric in this sense. The
|
|
162
|
+
* `parametric` form is reserved for solver-generated families that contain `_n`, where
|
|
163
|
+
* `_n` represents an integer index. The special `all` descriptor takes precedence if
|
|
164
|
+
* present.
|
|
165
|
+
*/
|
|
166
|
+
get solutionForm(): SolutionForm;
|
|
167
|
+
/** Iterates over independent Expression copies of the accepted solutions. */
|
|
168
|
+
[Symbol.iterator](): Iterator<Expression>;
|
|
169
|
+
text(): string;
|
|
170
|
+
/** Returns deep-copied accepted solutions as a plain array. */
|
|
171
|
+
toArray(): Expression[];
|
|
172
|
+
}
|