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,824 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module sparsePolynomial
|
|
4
|
+
*
|
|
5
|
+
* Sparse polynomial storage with exact bigint coefficients and exponents.
|
|
6
|
+
*
|
|
7
|
+
* External references consulted for monomial representation and ordering:
|
|
8
|
+
* - SymPy monomial operations:
|
|
9
|
+
* https://github.com/sympy/sympy/blob/120ee85f346f6292b763cc195afda4f907260d4a/sympy/polys/monomials.py
|
|
10
|
+
* - SymPy lexicographic, graded lexicographic, and graded reverse lexicographic orders:
|
|
11
|
+
* https://github.com/sympy/sympy/blob/120ee85f346f6292b763cc195afda4f907260d4a/sympy/polys/orderings.py
|
|
12
|
+
* - SymPy coefficient content and primitive-part operations:
|
|
13
|
+
* https://github.com/sympy/sympy/blob/120ee85f346f6292b763cc195afda4f907260d4a/sympy/polys/densetools.py
|
|
14
|
+
* - SymPy sparse polynomial division:
|
|
15
|
+
* https://github.com/sympy/sympy/blob/120ee85f346f6292b763cc195afda4f907260d4a/sympy/polys/sparsetools.py
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.SparsePolynomial = void 0;
|
|
19
|
+
const errors_1 = require("../../errors");
|
|
20
|
+
const bigint_1 = require("../../functions/bigint/bigint");
|
|
21
|
+
/**
|
|
22
|
+
* Sparse polynomial with bigint coefficients and bigint exponents.
|
|
23
|
+
*
|
|
24
|
+
* The variable count is part of the polynomial rather than inferred from its support.
|
|
25
|
+
* Exponent vectors therefore have one exact entry for every variable, including zero
|
|
26
|
+
* polynomials and constants. The internal map key is an encoding detail and is never
|
|
27
|
+
* exposed or parsed by polynomial algorithms.
|
|
28
|
+
*/
|
|
29
|
+
class SparsePolynomial {
|
|
30
|
+
termsByKey;
|
|
31
|
+
variableCount;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a sparse polynomial in a ring with a fixed number of variables.
|
|
34
|
+
*
|
|
35
|
+
* Duplicate monomials are combined and zero coefficients are removed.
|
|
36
|
+
*
|
|
37
|
+
* @param variableCount - Number of variables in the polynomial ring.
|
|
38
|
+
* @param terms - Terms with exponent vectors of exactly variableCount entries.
|
|
39
|
+
*/
|
|
40
|
+
constructor(variableCount, terms = []) {
|
|
41
|
+
if (!Number.isSafeInteger(variableCount) || variableCount < 0) {
|
|
42
|
+
throw new RangeError((0, errors_1.message)('sparseVariableCountInvalid'));
|
|
43
|
+
}
|
|
44
|
+
this.variableCount = variableCount;
|
|
45
|
+
this.termsByKey = new Map();
|
|
46
|
+
for (const term of terms) {
|
|
47
|
+
SparsePolynomial.assertExponents(variableCount, term.exponents);
|
|
48
|
+
const exponents = term.exponents.map(exponent => exponent);
|
|
49
|
+
const frozenExponents = Object.freeze(exponents);
|
|
50
|
+
const key = SparsePolynomial.keyOf(frozenExponents);
|
|
51
|
+
const coefficient = (this.termsByKey.get(key)?.coefficient ?? 0n) + term.coefficient;
|
|
52
|
+
if (coefficient === 0n) {
|
|
53
|
+
this.termsByKey.delete(key);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.termsByKey.set(key, Object.freeze({ coefficient, exponents: frozenExponents }));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Verifies that an exponent vector belongs to a ring and contains only
|
|
62
|
+
* non-negative exact integer exponents.
|
|
63
|
+
*/
|
|
64
|
+
static assertExponents(variableCount, exponents) {
|
|
65
|
+
if (exponents.length !== variableCount) {
|
|
66
|
+
throw new RangeError((0, errors_1.message)('sparseExponentVectorLengthMismatch'));
|
|
67
|
+
}
|
|
68
|
+
for (const exponent of exponents) {
|
|
69
|
+
if (typeof exponent !== 'bigint' || exponent < 0n) {
|
|
70
|
+
throw new RangeError((0, errors_1.message)('sparseExponentsNonNegativeBigInt'));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compares exponent vectors using the three global monomial orders required by
|
|
76
|
+
* the polynomial algorithms.
|
|
77
|
+
*/
|
|
78
|
+
static compareMonomials(a, b, order) {
|
|
79
|
+
if (order === 'lex') {
|
|
80
|
+
for (let i = 0; i < a.length; i++) {
|
|
81
|
+
if (a[i] !== b[i]) {
|
|
82
|
+
return a[i] > b[i] ? 1 : -1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
let degreeA = 0n;
|
|
88
|
+
let degreeB = 0n;
|
|
89
|
+
for (let i = 0; i < a.length; i++) {
|
|
90
|
+
degreeA += a[i];
|
|
91
|
+
degreeB += b[i];
|
|
92
|
+
}
|
|
93
|
+
if (degreeA !== degreeB) {
|
|
94
|
+
return degreeA > degreeB ? 1 : -1;
|
|
95
|
+
}
|
|
96
|
+
if (order === 'grlex') {
|
|
97
|
+
for (let i = 0; i < a.length; i++) {
|
|
98
|
+
if (a[i] !== b[i]) {
|
|
99
|
+
return a[i] > b[i] ? 1 : -1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
105
|
+
if (a[i] !== b[i]) {
|
|
106
|
+
return a[i] < b[i] ? 1 : -1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
/** Creates a constant polynomial in a ring with variableCount variables. */
|
|
112
|
+
static constant(variableCount, coefficient) {
|
|
113
|
+
return new SparsePolynomial(variableCount, [
|
|
114
|
+
{
|
|
115
|
+
coefficient,
|
|
116
|
+
exponents: new Array(variableCount).fill(0n),
|
|
117
|
+
},
|
|
118
|
+
]);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Encodes an exponent vector only for map identity.
|
|
122
|
+
*
|
|
123
|
+
* The polynomial retains the exponent vector beside the key, so no decoder exists.
|
|
124
|
+
*/
|
|
125
|
+
static keyOf(exponents) {
|
|
126
|
+
return exponents.join(',');
|
|
127
|
+
}
|
|
128
|
+
/** Creates a one-term polynomial. */
|
|
129
|
+
static monomial(variableCount, coefficient, exponents) {
|
|
130
|
+
return new SparsePolynomial(variableCount, [{ coefficient, exponents }]);
|
|
131
|
+
}
|
|
132
|
+
/** Creates the variable at variableIndex with coefficient one. */
|
|
133
|
+
static variable(variableCount, variableIndex) {
|
|
134
|
+
if (!Number.isSafeInteger(variableIndex) ||
|
|
135
|
+
variableIndex < 0 ||
|
|
136
|
+
variableIndex >= variableCount) {
|
|
137
|
+
throw new RangeError((0, errors_1.message)('sparseVariableIndexOutOfRing'));
|
|
138
|
+
}
|
|
139
|
+
const exponents = new Array(variableCount).fill(0n);
|
|
140
|
+
exponents[variableIndex] = 1n;
|
|
141
|
+
return new SparsePolynomial(variableCount, [{ coefficient: 1n, exponents }]);
|
|
142
|
+
}
|
|
143
|
+
/** Creates the zero polynomial in a ring with variableCount variables. */
|
|
144
|
+
static zero(variableCount) {
|
|
145
|
+
return new SparsePolynomial(variableCount);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Adds another polynomial in the same ring.
|
|
149
|
+
*
|
|
150
|
+
* Like monomials are combined exactly and zero coefficients are removed from
|
|
151
|
+
* the returned polynomial.
|
|
152
|
+
*/
|
|
153
|
+
add(other) {
|
|
154
|
+
if (this.variableCount !== other.variableCount) {
|
|
155
|
+
throw new RangeError((0, errors_1.message)('sparseAdditionRingMismatch'));
|
|
156
|
+
}
|
|
157
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
158
|
+
for (const [key, term] of this.termsByKey) {
|
|
159
|
+
result.termsByKey.set(key, term);
|
|
160
|
+
}
|
|
161
|
+
for (const [key, term] of other.termsByKey) {
|
|
162
|
+
const existing = result.termsByKey.get(key);
|
|
163
|
+
const coefficient = (existing?.coefficient ?? 0n) + term.coefficient;
|
|
164
|
+
if (coefficient === 0n) {
|
|
165
|
+
result.termsByKey.delete(key);
|
|
166
|
+
}
|
|
167
|
+
else if (existing === undefined || coefficient !== existing.coefficient) {
|
|
168
|
+
result.termsByKey.set(key, Object.freeze({
|
|
169
|
+
coefficient,
|
|
170
|
+
exponents: existing?.exponents ?? term.exponents,
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Returns the coefficient of one monomial.
|
|
178
|
+
*
|
|
179
|
+
* @param exponents - Exact exponent vector for the requested monomial.
|
|
180
|
+
*/
|
|
181
|
+
coefficient(exponents) {
|
|
182
|
+
SparsePolynomial.assertExponents(this.variableCount, exponents);
|
|
183
|
+
return this.termsByKey.get(SparsePolynomial.keyOf(exponents))?.coefficient ?? 0n;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns the coefficient polynomial at one exact power of a selected variable.
|
|
187
|
+
*
|
|
188
|
+
* The selected variable remains in the ring with exponent zero so recursive
|
|
189
|
+
* algorithms can preserve the original coordinate layout.
|
|
190
|
+
*/
|
|
191
|
+
coefficientIn(variableIndex, exponent) {
|
|
192
|
+
this.degree(variableIndex);
|
|
193
|
+
if (exponent < 0n) {
|
|
194
|
+
throw new RangeError((0, errors_1.message)('sparseCoefficientExponentNonNegative'));
|
|
195
|
+
}
|
|
196
|
+
const terms = [];
|
|
197
|
+
for (const term of this.termsByKey.values()) {
|
|
198
|
+
if (term.exponents[variableIndex] !== exponent) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const exponents = [...term.exponents];
|
|
202
|
+
exponents[variableIndex] = 0n;
|
|
203
|
+
terms.push({
|
|
204
|
+
coefficient: term.coefficient,
|
|
205
|
+
exponents,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return new SparsePolynomial(this.variableCount, terms);
|
|
209
|
+
}
|
|
210
|
+
/** Returns the constant coefficient, or zero when the constant monomial is absent. */
|
|
211
|
+
constantTerm() {
|
|
212
|
+
const exponents = new Array(this.variableCount).fill(0n);
|
|
213
|
+
return this.termsByKey.get(SparsePolynomial.keyOf(exponents))?.coefficient ?? 0n;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Returns the positive greatest common divisor of all coefficients.
|
|
217
|
+
*
|
|
218
|
+
* The zero polynomial has coefficient content zero.
|
|
219
|
+
*/
|
|
220
|
+
content() {
|
|
221
|
+
let content = 0n;
|
|
222
|
+
for (const term of this.termsByKey.values()) {
|
|
223
|
+
content = (0, bigint_1.GCD)(content, term.coefficient);
|
|
224
|
+
if (content === 1n) {
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return content;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Returns the degree in one variable.
|
|
232
|
+
*
|
|
233
|
+
* The zero polynomial has no degree and returns null.
|
|
234
|
+
*/
|
|
235
|
+
degree(variableIndex) {
|
|
236
|
+
if (!Number.isSafeInteger(variableIndex) ||
|
|
237
|
+
variableIndex < 0 ||
|
|
238
|
+
variableIndex >= this.variableCount) {
|
|
239
|
+
throw new RangeError((0, errors_1.message)('sparseVariableIndexOutOfRing'));
|
|
240
|
+
}
|
|
241
|
+
if (this.isZero()) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
let degree = 0n;
|
|
245
|
+
for (const term of this.termsByKey.values()) {
|
|
246
|
+
if (term.exponents[variableIndex] > degree) {
|
|
247
|
+
degree = term.exponents[variableIndex];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return degree;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Differentiates with respect to one ring variable.
|
|
254
|
+
*
|
|
255
|
+
* Coefficients and exponents stay in bigint arithmetic, including exponents
|
|
256
|
+
* above JavaScript's safe-integer range.
|
|
257
|
+
*/
|
|
258
|
+
derivative(variableIndex) {
|
|
259
|
+
this.degree(variableIndex);
|
|
260
|
+
const terms = [];
|
|
261
|
+
for (const term of this.termsByKey.values()) {
|
|
262
|
+
const exponent = term.exponents[variableIndex];
|
|
263
|
+
if (exponent === 0n) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const exponents = term.exponents.map(value => value);
|
|
267
|
+
exponents[variableIndex] = exponent - 1n;
|
|
268
|
+
terms.push({
|
|
269
|
+
coefficient: term.coefficient * exponent,
|
|
270
|
+
exponents,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return new SparsePolynomial(this.variableCount, terms);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Divides every term by one monomial when the quotient stays in the integer
|
|
277
|
+
* polynomial ring.
|
|
278
|
+
*
|
|
279
|
+
* Returns null when any coefficient or exponent is not exactly divisible.
|
|
280
|
+
*/
|
|
281
|
+
divideByMonomial(divisor) {
|
|
282
|
+
if (divisor.coefficient === 0n) {
|
|
283
|
+
throw new RangeError((0, errors_1.message)('sparseZeroMonomialDivision'));
|
|
284
|
+
}
|
|
285
|
+
SparsePolynomial.assertExponents(this.variableCount, divisor.exponents);
|
|
286
|
+
const terms = [];
|
|
287
|
+
for (const term of this.termsByKey.values()) {
|
|
288
|
+
if (term.coefficient % divisor.coefficient !== 0n) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const exponents = new Array(this.variableCount);
|
|
292
|
+
for (let variableIndex = 0; variableIndex < this.variableCount; variableIndex++) {
|
|
293
|
+
if (term.exponents[variableIndex] < divisor.exponents[variableIndex]) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
exponents[variableIndex] =
|
|
297
|
+
term.exponents[variableIndex] - divisor.exponents[variableIndex];
|
|
298
|
+
}
|
|
299
|
+
terms.push({
|
|
300
|
+
coefficient: term.coefficient / divisor.coefficient,
|
|
301
|
+
exponents,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return new SparsePolynomial(this.variableCount, terms);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Divides all coefficients by an integer scalar.
|
|
308
|
+
*
|
|
309
|
+
* @throws RangeError When the scalar is zero or does not divide every coefficient.
|
|
310
|
+
*/
|
|
311
|
+
divideByScalarExact(divisor) {
|
|
312
|
+
if (divisor === 0n) {
|
|
313
|
+
throw new RangeError((0, errors_1.message)('sparseZeroScalarDivision'));
|
|
314
|
+
}
|
|
315
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
316
|
+
for (const [key, term] of this.termsByKey) {
|
|
317
|
+
if (term.coefficient % divisor !== 0n) {
|
|
318
|
+
throw new RangeError((0, errors_1.message)('sparseScalarDivisionExact'));
|
|
319
|
+
}
|
|
320
|
+
result.termsByKey.set(key, Object.freeze({
|
|
321
|
+
coefficient: term.coefficient / divisor,
|
|
322
|
+
exponents: term.exponents,
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Divides by one polynomial using exact integer coefficient arithmetic.
|
|
329
|
+
*
|
|
330
|
+
* Returns null as soon as the current leading term is not exactly divisible
|
|
331
|
+
* by the divisor leading term. A successful result therefore has zero
|
|
332
|
+
* remainder in the selected monomial order.
|
|
333
|
+
*/
|
|
334
|
+
divideExact(divisor, order = 'lex') {
|
|
335
|
+
if (this.variableCount !== divisor.variableCount) {
|
|
336
|
+
throw new RangeError((0, errors_1.message)('sparseDivisionRingMismatch'));
|
|
337
|
+
}
|
|
338
|
+
const divisorLeading = divisor.leadingTerm(order);
|
|
339
|
+
if (divisorLeading === null) {
|
|
340
|
+
throw new RangeError((0, errors_1.message)('sparseZeroPolynomialDivision'));
|
|
341
|
+
}
|
|
342
|
+
let quotient = SparsePolynomial.zero(this.variableCount);
|
|
343
|
+
let remainder = new SparsePolynomial(this.variableCount, this.termsByKey.values());
|
|
344
|
+
while (!remainder.isZero()) {
|
|
345
|
+
const leading = remainder.leadingTerm(order);
|
|
346
|
+
if (leading === null) {
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
const leadingPolynomial = SparsePolynomial.monomial(this.variableCount, leading.coefficient, leading.exponents);
|
|
350
|
+
const quotientTerm = leadingPolynomial.divideByMonomial(divisorLeading);
|
|
351
|
+
if (quotientTerm === null) {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
quotient = quotient.add(quotientTerm);
|
|
355
|
+
remainder = remainder.subtract(divisor.multiply(quotientTerm));
|
|
356
|
+
}
|
|
357
|
+
return quotient;
|
|
358
|
+
}
|
|
359
|
+
/** Returns whether both polynomials have the same ring and exact nonzero terms. */
|
|
360
|
+
equals(other) {
|
|
361
|
+
if (this.variableCount !== other.variableCount || this.termCount !== other.termCount) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
for (const [key, term] of this.termsByKey) {
|
|
365
|
+
if (other.termsByKey.get(key)?.coefficient !== term.coefficient) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Substitutes one variable with an exact integer while retaining the same ring.
|
|
373
|
+
*
|
|
374
|
+
* Terms that become like terms after substitution are combined in the result.
|
|
375
|
+
*/
|
|
376
|
+
evaluateVariable(variableIndex, value) {
|
|
377
|
+
this.degree(variableIndex);
|
|
378
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
379
|
+
for (const [key, term] of this.termsByKey) {
|
|
380
|
+
const exponent = term.exponents[variableIndex];
|
|
381
|
+
let coordinateStart = 0;
|
|
382
|
+
for (let index = 0; index < variableIndex; index++) {
|
|
383
|
+
coordinateStart = key.indexOf(',', coordinateStart) + 1;
|
|
384
|
+
}
|
|
385
|
+
const separator = key.indexOf(',', coordinateStart);
|
|
386
|
+
const coordinateEnd = separator === -1 ? key.length : separator;
|
|
387
|
+
const evaluatedKey = key.slice(0, coordinateStart) + '0' + key.slice(coordinateEnd);
|
|
388
|
+
const existing = result.termsByKey.get(evaluatedKey);
|
|
389
|
+
const contribution = term.coefficient * value ** exponent;
|
|
390
|
+
const coefficient = (existing?.coefficient ?? 0n) + contribution;
|
|
391
|
+
if (coefficient === 0n) {
|
|
392
|
+
result.termsByKey.delete(evaluatedKey);
|
|
393
|
+
}
|
|
394
|
+
else if (existing !== undefined) {
|
|
395
|
+
if (coefficient !== existing.coefficient) {
|
|
396
|
+
result.termsByKey.set(evaluatedKey, Object.freeze({
|
|
397
|
+
coefficient,
|
|
398
|
+
exponents: existing.exponents,
|
|
399
|
+
}));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if (contribution !== 0n) {
|
|
403
|
+
if (exponent === 0n) {
|
|
404
|
+
result.termsByKey.set(evaluatedKey, term);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
const exponents = [...term.exponents];
|
|
408
|
+
exponents[variableIndex] = 0n;
|
|
409
|
+
result.termsByKey.set(evaluatedKey, Object.freeze({
|
|
410
|
+
coefficient,
|
|
411
|
+
exponents: Object.freeze(exponents),
|
|
412
|
+
}));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Substitutes several variables with exact integers in one sparse traversal.
|
|
420
|
+
*
|
|
421
|
+
* The selected coordinates remain in the polynomial ring with exponent zero.
|
|
422
|
+
*/
|
|
423
|
+
evaluateVariables(variableIndices, values) {
|
|
424
|
+
if (variableIndices.length !== values.length) {
|
|
425
|
+
throw new RangeError((0, errors_1.message)('wrongInput', {
|
|
426
|
+
expected: `${variableIndices.length} evaluation values`,
|
|
427
|
+
received: `${values.length}`,
|
|
428
|
+
}));
|
|
429
|
+
}
|
|
430
|
+
if (variableIndices.length === 0) {
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
const selected = new Set();
|
|
434
|
+
for (const variableIndex of variableIndices) {
|
|
435
|
+
this.degree(variableIndex);
|
|
436
|
+
if (selected.has(variableIndex)) {
|
|
437
|
+
throw new RangeError((0, errors_1.message)('wrongInput', {
|
|
438
|
+
expected: 'unique evaluation variables',
|
|
439
|
+
received: 'duplicate variable index',
|
|
440
|
+
}));
|
|
441
|
+
}
|
|
442
|
+
selected.add(variableIndex);
|
|
443
|
+
}
|
|
444
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
445
|
+
for (const [key, term] of this.termsByKey) {
|
|
446
|
+
let coefficient = term.coefficient;
|
|
447
|
+
let changesMonomial = false;
|
|
448
|
+
for (let index = 0; index < variableIndices.length; index++) {
|
|
449
|
+
const variableIndex = variableIndices[index];
|
|
450
|
+
const exponent = term.exponents[variableIndex];
|
|
451
|
+
if (exponent === 0n) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
changesMonomial = true;
|
|
455
|
+
const value = values[index];
|
|
456
|
+
if (value === 0n) {
|
|
457
|
+
coefficient = 0n;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
if (value === 1n) {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (value === -1n) {
|
|
464
|
+
if ((exponent & 1n) === 1n) {
|
|
465
|
+
coefficient = -coefficient;
|
|
466
|
+
}
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
coefficient *= value ** exponent;
|
|
470
|
+
}
|
|
471
|
+
if (coefficient === 0n) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
let evaluatedKey = key;
|
|
475
|
+
let exponents = term.exponents;
|
|
476
|
+
if (changesMonomial) {
|
|
477
|
+
const projected = [...term.exponents];
|
|
478
|
+
for (const variableIndex of variableIndices) {
|
|
479
|
+
projected[variableIndex] = 0n;
|
|
480
|
+
}
|
|
481
|
+
exponents = Object.freeze(projected);
|
|
482
|
+
evaluatedKey = SparsePolynomial.keyOf(exponents);
|
|
483
|
+
}
|
|
484
|
+
const existing = result.termsByKey.get(evaluatedKey);
|
|
485
|
+
const combined = (existing?.coefficient ?? 0n) + coefficient;
|
|
486
|
+
if (combined === 0n) {
|
|
487
|
+
result.termsByKey.delete(evaluatedKey);
|
|
488
|
+
}
|
|
489
|
+
else if (existing === undefined) {
|
|
490
|
+
result.termsByKey.set(evaluatedKey, changesMonomial || coefficient !== term.coefficient
|
|
491
|
+
? Object.freeze({ coefficient, exponents })
|
|
492
|
+
: term);
|
|
493
|
+
}
|
|
494
|
+
else if (combined !== existing.coefficient) {
|
|
495
|
+
result.termsByKey.set(evaluatedKey, Object.freeze({
|
|
496
|
+
coefficient: combined,
|
|
497
|
+
exponents: existing.exponents,
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return result;
|
|
502
|
+
}
|
|
503
|
+
/** Returns whether the polynomial is zero or contains only a constant term. */
|
|
504
|
+
isConstant() {
|
|
505
|
+
if (this.isZero()) {
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
if (this.termsByKey.size !== 1) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
const term = this.termsByKey.values().next().value;
|
|
512
|
+
return term !== undefined && term.exponents.every(exponent => exponent === 0n);
|
|
513
|
+
}
|
|
514
|
+
/** Returns whether the polynomial has no nonzero terms. */
|
|
515
|
+
isZero() {
|
|
516
|
+
return this.termsByKey.size === 0;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Returns the coefficient polynomial of the highest power of one variable.
|
|
520
|
+
*
|
|
521
|
+
* The selected coordinate remains present with exponent zero.
|
|
522
|
+
*/
|
|
523
|
+
leadingCoefficientIn(variableIndex) {
|
|
524
|
+
const degree = this.degree(variableIndex);
|
|
525
|
+
return degree === null ? null : this.coefficientIn(variableIndex, degree);
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Returns the leading term under the requested monomial order.
|
|
529
|
+
*
|
|
530
|
+
* Variable priority follows exponent-vector index order.
|
|
531
|
+
*/
|
|
532
|
+
leadingTerm(order = 'lex') {
|
|
533
|
+
if (order !== 'lex' && order !== 'grlex' && order !== 'grevlex') {
|
|
534
|
+
throw new RangeError((0, errors_1.message)('sparseMonomialOrderUnsupported'));
|
|
535
|
+
}
|
|
536
|
+
let leading = null;
|
|
537
|
+
for (const term of this.termsByKey.values()) {
|
|
538
|
+
if (leading === null ||
|
|
539
|
+
SparsePolynomial.compareMonomials(term.exponents, leading.exponents, order) > 0) {
|
|
540
|
+
leading = term;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return leading;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Applies an exact bigint transformation to every stored coefficient while
|
|
547
|
+
* preserving the existing monomial keys and exponent vectors.
|
|
548
|
+
*/
|
|
549
|
+
mapCoefficients(mapper) {
|
|
550
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
551
|
+
for (const [key, term] of this.termsByKey) {
|
|
552
|
+
const coefficient = mapper(term.coefficient);
|
|
553
|
+
if (coefficient === 0n) {
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
result.termsByKey.set(key, coefficient === term.coefficient
|
|
557
|
+
? term
|
|
558
|
+
: Object.freeze({
|
|
559
|
+
coefficient,
|
|
560
|
+
exponents: term.exponents,
|
|
561
|
+
}));
|
|
562
|
+
}
|
|
563
|
+
return result;
|
|
564
|
+
}
|
|
565
|
+
/** Returns the largest absolute coefficient, or zero for the zero polynomial. */
|
|
566
|
+
maxAbsoluteCoefficient() {
|
|
567
|
+
let maximum = 0n;
|
|
568
|
+
for (const term of this.termsByKey.values()) {
|
|
569
|
+
const absolute = term.coefficient < 0n ? -term.coefficient : term.coefficient;
|
|
570
|
+
if (absolute > maximum) {
|
|
571
|
+
maximum = absolute;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return maximum;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Multiplies by another polynomial in the same ring.
|
|
578
|
+
*
|
|
579
|
+
* Monomial exponents are added as bigints. The constructor combines products
|
|
580
|
+
* that land on the same monomial and removes coefficients that cancel to zero.
|
|
581
|
+
*/
|
|
582
|
+
multiply(other) {
|
|
583
|
+
if (this.variableCount !== other.variableCount) {
|
|
584
|
+
throw new RangeError((0, errors_1.message)('sparseMultiplicationRingMismatch'));
|
|
585
|
+
}
|
|
586
|
+
if (this.isZero() || other.isZero()) {
|
|
587
|
+
return SparsePolynomial.zero(this.variableCount);
|
|
588
|
+
}
|
|
589
|
+
const terms = [];
|
|
590
|
+
for (const left of this.termsByKey.values()) {
|
|
591
|
+
for (const right of other.termsByKey.values()) {
|
|
592
|
+
const exponents = new Array(this.variableCount);
|
|
593
|
+
for (let variableIndex = 0; variableIndex < this.variableCount; variableIndex++) {
|
|
594
|
+
exponents[variableIndex] =
|
|
595
|
+
left.exponents[variableIndex] + right.exponents[variableIndex];
|
|
596
|
+
}
|
|
597
|
+
terms.push({
|
|
598
|
+
coefficient: left.coefficient * right.coefficient,
|
|
599
|
+
exponents,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return new SparsePolynomial(this.variableCount, terms);
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Computes the difference of two monomial-scaled polynomials in one sparse
|
|
607
|
+
* traversal. This avoids constructing the monomial factors and multiplication
|
|
608
|
+
* results used by fraction-free S-polynomials.
|
|
609
|
+
*/
|
|
610
|
+
monomialScaleSubtract(leftScalar, leftMonomialExponents, other, rightScalar, rightMonomialExponents) {
|
|
611
|
+
if (this.variableCount !== other.variableCount) {
|
|
612
|
+
throw new RangeError((0, errors_1.message)('sparseSubtractionRingMismatch'));
|
|
613
|
+
}
|
|
614
|
+
SparsePolynomial.assertExponents(this.variableCount, leftMonomialExponents);
|
|
615
|
+
SparsePolynomial.assertExponents(this.variableCount, rightMonomialExponents);
|
|
616
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
617
|
+
const accumulate = (polynomial, scalar, monomialExponents) => {
|
|
618
|
+
if (scalar === 0n) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
for (const term of polynomial.termsByKey.values()) {
|
|
622
|
+
const exponents = new Array(this.variableCount);
|
|
623
|
+
for (let variableIndex = 0; variableIndex < this.variableCount; variableIndex++) {
|
|
624
|
+
exponents[variableIndex] =
|
|
625
|
+
term.exponents[variableIndex] + monomialExponents[variableIndex];
|
|
626
|
+
}
|
|
627
|
+
const frozenExponents = Object.freeze(exponents);
|
|
628
|
+
const key = SparsePolynomial.keyOf(frozenExponents);
|
|
629
|
+
const existing = result.termsByKey.get(key);
|
|
630
|
+
const coefficient = (existing?.coefficient ?? 0n) + term.coefficient * scalar;
|
|
631
|
+
if (coefficient === 0n) {
|
|
632
|
+
result.termsByKey.delete(key);
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
result.termsByKey.set(key, Object.freeze({ coefficient, exponents: existing?.exponents ?? frozenExponents }));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
accumulate(this, leftScalar, leftMonomialExponents);
|
|
640
|
+
accumulate(other, -rightScalar, rightMonomialExponents);
|
|
641
|
+
return result;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Computes a scaled subtraction where the right polynomial is also multiplied
|
|
645
|
+
* by one monomial. This avoids constructing the two scaled intermediate
|
|
646
|
+
* polynomials used by fraction-free reduction.
|
|
647
|
+
*/
|
|
648
|
+
scaleSubtractMonomial(leftScalar, other, rightScalar, monomialExponents) {
|
|
649
|
+
if (this.variableCount !== other.variableCount) {
|
|
650
|
+
throw new RangeError((0, errors_1.message)('sparseSubtractionRingMismatch'));
|
|
651
|
+
}
|
|
652
|
+
SparsePolynomial.assertExponents(this.variableCount, monomialExponents);
|
|
653
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
654
|
+
if (leftScalar !== 0n) {
|
|
655
|
+
for (const [key, term] of this.termsByKey) {
|
|
656
|
+
const coefficient = term.coefficient * leftScalar;
|
|
657
|
+
if (coefficient !== 0n) {
|
|
658
|
+
result.termsByKey.set(key, Object.freeze({ coefficient, exponents: term.exponents }));
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (rightScalar === 0n) {
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
665
|
+
for (const term of other.termsByKey.values()) {
|
|
666
|
+
const exponents = new Array(this.variableCount);
|
|
667
|
+
for (let variableIndex = 0; variableIndex < this.variableCount; variableIndex++) {
|
|
668
|
+
exponents[variableIndex] =
|
|
669
|
+
term.exponents[variableIndex] + monomialExponents[variableIndex];
|
|
670
|
+
}
|
|
671
|
+
const frozenExponents = Object.freeze(exponents);
|
|
672
|
+
const key = SparsePolynomial.keyOf(frozenExponents);
|
|
673
|
+
const existing = result.termsByKey.get(key);
|
|
674
|
+
const coefficient = (existing?.coefficient ?? 0n) - term.coefficient * rightScalar;
|
|
675
|
+
if (coefficient === 0n) {
|
|
676
|
+
result.termsByKey.delete(key);
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
result.termsByKey.set(key, Object.freeze({
|
|
680
|
+
coefficient,
|
|
681
|
+
exponents: existing?.exponents ?? frozenExponents,
|
|
682
|
+
}));
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return result;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Returns the additive inverse of this polynomial.
|
|
689
|
+
*/
|
|
690
|
+
negate() {
|
|
691
|
+
return this.scale(-1n);
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Makes the leading coefficient positive without changing coefficient content.
|
|
695
|
+
*/
|
|
696
|
+
normalizeLeadingSign(order = 'lex') {
|
|
697
|
+
const leading = this.leadingTerm(order);
|
|
698
|
+
return leading !== null && leading.coefficient < 0n ? this.negate() : this;
|
|
699
|
+
}
|
|
700
|
+
/** Raises the polynomial to a non-negative exact integer power. */
|
|
701
|
+
pow(exponent) {
|
|
702
|
+
if (exponent < 0n) {
|
|
703
|
+
throw new RangeError((0, errors_1.message)('sparseExponentNonNegative'));
|
|
704
|
+
}
|
|
705
|
+
let result = SparsePolynomial.constant(this.variableCount, 1n);
|
|
706
|
+
let power = exponent;
|
|
707
|
+
if (power === 0n) {
|
|
708
|
+
return result;
|
|
709
|
+
}
|
|
710
|
+
if ((power & 1n) === 1n) {
|
|
711
|
+
result = result.multiply(this);
|
|
712
|
+
}
|
|
713
|
+
power >>= 1n;
|
|
714
|
+
if (power === 0n) {
|
|
715
|
+
return result;
|
|
716
|
+
}
|
|
717
|
+
let factor = this.multiply(this);
|
|
718
|
+
while (power > 0n) {
|
|
719
|
+
if ((power & 1n) === 1n) {
|
|
720
|
+
result = result.multiply(factor);
|
|
721
|
+
}
|
|
722
|
+
power >>= 1n;
|
|
723
|
+
if (power > 0n) {
|
|
724
|
+
factor = factor.multiply(factor);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return result;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Divides by positive coefficient content while preserving the polynomial sign.
|
|
731
|
+
*/
|
|
732
|
+
primitivePart() {
|
|
733
|
+
const content = this.content();
|
|
734
|
+
return content === 0n || content === 1n ? this : this.divideByScalarExact(content);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Multiplies every coefficient by an exact integer scalar.
|
|
738
|
+
*/
|
|
739
|
+
scale(scalar) {
|
|
740
|
+
if (scalar === 0n || this.isZero()) {
|
|
741
|
+
return SparsePolynomial.zero(this.variableCount);
|
|
742
|
+
}
|
|
743
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
744
|
+
for (const [key, term] of this.termsByKey) {
|
|
745
|
+
result.termsByKey.set(key, Object.freeze({
|
|
746
|
+
coefficient: term.coefficient * scalar,
|
|
747
|
+
exponents: term.exponents,
|
|
748
|
+
}));
|
|
749
|
+
}
|
|
750
|
+
return result;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Subtracts another polynomial in the same ring.
|
|
754
|
+
*/
|
|
755
|
+
subtract(other) {
|
|
756
|
+
if (this.variableCount !== other.variableCount) {
|
|
757
|
+
throw new RangeError((0, errors_1.message)('sparseSubtractionRingMismatch'));
|
|
758
|
+
}
|
|
759
|
+
const result = SparsePolynomial.zero(this.variableCount);
|
|
760
|
+
for (const [key, term] of this.termsByKey) {
|
|
761
|
+
result.termsByKey.set(key, term);
|
|
762
|
+
}
|
|
763
|
+
for (const [key, term] of other.termsByKey) {
|
|
764
|
+
const existing = result.termsByKey.get(key);
|
|
765
|
+
const coefficient = (existing?.coefficient ?? 0n) - term.coefficient;
|
|
766
|
+
if (coefficient === 0n) {
|
|
767
|
+
result.termsByKey.delete(key);
|
|
768
|
+
}
|
|
769
|
+
else if (existing === undefined || coefficient !== existing.coefficient) {
|
|
770
|
+
result.termsByKey.set(key, Object.freeze({
|
|
771
|
+
coefficient,
|
|
772
|
+
exponents: existing?.exponents ?? term.exponents,
|
|
773
|
+
}));
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return result;
|
|
777
|
+
}
|
|
778
|
+
/** Number of stored nonzero terms. */
|
|
779
|
+
get termCount() {
|
|
780
|
+
return this.termsByKey.size;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Returns a copy of the stored terms.
|
|
784
|
+
*
|
|
785
|
+
* The exponent arrays themselves are frozen so callers cannot alter polynomial storage.
|
|
786
|
+
*/
|
|
787
|
+
terms() {
|
|
788
|
+
return Array.from(this.termsByKey.values());
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Returns the largest total degree among the stored monomials.
|
|
792
|
+
*
|
|
793
|
+
* The zero polynomial has no total degree and returns null.
|
|
794
|
+
*/
|
|
795
|
+
totalDegree() {
|
|
796
|
+
if (this.isZero()) {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
let maxDegree = 0n;
|
|
800
|
+
for (const term of this.termsByKey.values()) {
|
|
801
|
+
let degree = 0n;
|
|
802
|
+
for (const exponent of term.exponents) {
|
|
803
|
+
degree += exponent;
|
|
804
|
+
}
|
|
805
|
+
if (degree > maxDegree) {
|
|
806
|
+
maxDegree = degree;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return maxDegree;
|
|
810
|
+
}
|
|
811
|
+
/** Returns the variable indices that occur with a positive exponent. */
|
|
812
|
+
variables() {
|
|
813
|
+
const present = new Set();
|
|
814
|
+
for (const term of this.termsByKey.values()) {
|
|
815
|
+
for (let variableIndex = 0; variableIndex < this.variableCount; variableIndex++) {
|
|
816
|
+
if (term.exponents[variableIndex] !== 0n) {
|
|
817
|
+
present.add(variableIndex);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return Array.from(present).sort((a, b) => a - b);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
exports.SparsePolynomial = SparsePolynomial;
|