nerdamer 1.1.13 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +184 -0
- package/README.md +293 -312
- package/dist/bundle.js +2 -0
- package/dist/bundle.js.LICENSE.txt +7 -0
- package/dist/parser.js +2 -0
- package/dist/parser.js.LICENSE.txt +7 -0
- package/docs-data/parser-functions.json +1960 -0
- package/index.d.ts +10 -426
- package/output/algebra/adapters.d.ts +33 -0
- package/output/algebra/adapters.js +109 -0
- package/output/algebra/algorithms/arith.d.ts +84 -0
- package/output/algebra/algorithms/arith.js +323 -0
- package/output/algebra/algorithms/factor.d.ts +3 -0
- package/output/algebra/algorithms/factor.js +5 -0
- package/output/algebra/algorithms/factorMultivariate.d.ts +23 -0
- package/output/algebra/algorithms/factorMultivariate.js +2393 -0
- package/output/algebra/algorithms/factorUnivariate.d.ts +72 -0
- package/output/algebra/algorithms/factorUnivariate.js +1072 -0
- package/output/algebra/algorithms/gcd.d.ts +22 -0
- package/output/algebra/algorithms/gcd.js +690 -0
- package/output/algebra/algorithms/groebnerBase.d.ts +157 -0
- package/output/algebra/algorithms/groebnerBase.js +1166 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.d.ts +137 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.js +346 -0
- package/output/algebra/algorithms/poly.d.ts +228 -0
- package/output/algebra/algorithms/poly.js +1299 -0
- package/output/algebra/algorithms/rational.d.ts +17 -0
- package/output/algebra/algorithms/rational.js +115 -0
- package/output/algebra/factor/factor.d.ts +62 -0
- package/output/algebra/factor/factor.js +158 -0
- package/output/algebra/gcd/gcd.d.ts +29 -0
- package/output/algebra/gcd/gcd.js +141 -0
- package/output/algebra/groebner.d.ts +21 -0
- package/output/algebra/groebner.js +42 -0
- package/output/algebra/partfrac.d.ts +19 -0
- package/output/algebra/partfrac.js +398 -0
- package/output/algebra/polynomialize.d.ts +20 -0
- package/output/algebra/polynomialize.js +24 -0
- package/output/algebra/simplify/complexsimp.d.ts +7 -0
- package/output/algebra/simplify/complexsimp.js +24 -0
- package/output/algebra/simplify/factorCommon.d.ts +13 -0
- package/output/algebra/simplify/factorCommon.js +136 -0
- package/output/algebra/simplify/funcsimp.d.ts +26 -0
- package/output/algebra/simplify/funcsimp.js +633 -0
- package/output/algebra/simplify/invtrigrewrite.d.ts +10 -0
- package/output/algebra/simplify/invtrigrewrite.js +96 -0
- package/output/algebra/simplify/ratsimp.d.ts +21 -0
- package/output/algebra/simplify/ratsimp.js +140 -0
- package/output/algebra/simplify/simplify.d.ts +25 -0
- package/output/algebra/simplify/simplify.js +228 -0
- package/output/algebra/simplify/trigreduce.d.ts +38 -0
- package/output/algebra/simplify/trigreduce.js +424 -0
- package/output/algebra/simplify/trigrewrite.d.ts +17 -0
- package/output/algebra/simplify/trigrewrite.js +156 -0
- package/output/algebra/simplify/trigsimp.d.ts +11 -0
- package/output/algebra/simplify/trigsimp.js +369 -0
- package/output/algebra/simplify/utils.d.ts +32 -0
- package/output/algebra/simplify/utils.js +56 -0
- package/output/algebra/utils.d.ts +32 -0
- package/output/algebra/utils.js +48 -0
- package/output/api/advanced.d.ts +7 -0
- package/output/api/advanced.js +18 -0
- package/output/api/algebra.d.ts +17 -0
- package/output/api/algebra.js +32 -0
- package/output/api/assumptions.d.ts +4 -0
- package/output/api/assumptions.js +11 -0
- package/output/api/calculus.d.ts +9 -0
- package/output/api/calculus.js +21 -0
- package/output/api/core.d.ts +17 -0
- package/output/api/core.js +41 -0
- package/output/api/debug.d.ts +16 -0
- package/output/api/debug.js +23 -0
- package/output/api/parser.d.ts +85 -0
- package/output/api/parser.js +16 -0
- package/output/api/solve.d.ts +10 -0
- package/output/api/solve.js +16 -0
- package/output/api/structures.d.ts +10 -0
- package/output/api/structures.js +22 -0
- package/output/calculus/derivative/diff.d.ts +30 -0
- package/output/calculus/derivative/diff.js +238 -0
- package/output/calculus/fresnel.d.ts +16 -0
- package/output/calculus/fresnel.js +39 -0
- package/output/calculus/integrate/byParts.d.ts +18 -0
- package/output/calculus/integrate/byParts.js +339 -0
- package/output/calculus/integrate/bySubstitution.d.ts +135 -0
- package/output/calculus/integrate/bySubstitution.js +411 -0
- package/output/calculus/integrate/integrate.d.ts +38 -0
- package/output/calculus/integrate/integrate.js +652 -0
- package/output/calculus/integrate/integrationTable.d.ts +2 -0
- package/output/calculus/integrate/integrationTable.js +914 -0
- package/output/calculus/integrate/utils.d.ts +28 -0
- package/output/calculus/integrate/utils.js +96 -0
- package/output/calculus/laplace/ilaplace.d.ts +31 -0
- package/output/calculus/laplace/ilaplace.js +192 -0
- package/output/calculus/laplace/ilaplaceTable.d.ts +2 -0
- package/output/calculus/laplace/ilaplaceTable.js +200 -0
- package/output/calculus/laplace/laplace.d.ts +22 -0
- package/output/calculus/laplace/laplace.js +109 -0
- package/output/calculus/laplace/laplaceTable.d.ts +2 -0
- package/output/calculus/laplace/laplaceTable.js +187 -0
- package/output/calculus/limit/limit.d.ts +35 -0
- package/output/calculus/limit/limit.js +1183 -0
- package/output/calculus/limit/limitsTable.d.ts +2 -0
- package/output/calculus/limit/limitsTable.js +7 -0
- package/output/core/Settings.d.ts +32 -0
- package/output/core/Settings.js +68 -0
- package/output/core/adapters.d.ts +18 -0
- package/output/core/adapters.js +40 -0
- package/output/core/classes/assumption/Assumption.d.ts +218 -0
- package/output/core/classes/assumption/Assumption.js +605 -0
- package/output/core/classes/assumption/assertiveFunctions.d.ts +6 -0
- package/output/core/classes/assumption/assertiveFunctions.js +64 -0
- package/output/core/classes/assumption/assume.d.ts +90 -0
- package/output/core/classes/assumption/assume.js +145 -0
- package/output/core/classes/collection/Collection.d.ts +107 -0
- package/output/core/classes/collection/Collection.js +231 -0
- package/output/core/classes/complex/Complex.d.ts +99 -0
- package/output/core/classes/complex/Complex.js +135 -0
- package/output/core/classes/decimalSet/DecimalSet.d.ts +226 -0
- package/output/core/classes/decimalSet/DecimalSet.js +453 -0
- package/output/core/classes/dictionary/Dictionary.d.ts +102 -0
- package/output/core/classes/dictionary/Dictionary.js +213 -0
- package/output/core/classes/equation/Equation.d.ts +256 -0
- package/output/core/classes/equation/Equation.js +350 -0
- package/output/core/classes/expression/CoeffObject.d.ts +100 -0
- package/output/core/classes/expression/CoeffObject.js +198 -0
- package/output/core/classes/expression/Expression.d.ts +1674 -0
- package/output/core/classes/expression/Expression.js +2332 -0
- package/output/core/classes/expression/analysis.d.ts +25 -0
- package/output/core/classes/expression/analysis.js +218 -0
- package/output/core/classes/expression/collect.d.ts +9 -0
- package/output/core/classes/expression/collect.js +49 -0
- package/output/core/classes/expression/format.d.ts +45 -0
- package/output/core/classes/expression/format.js +217 -0
- package/output/core/classes/expression/products.d.ts +23 -0
- package/output/core/classes/expression/products.js +115 -0
- package/output/core/classes/expression/shortcuts.d.ts +35 -0
- package/output/core/classes/expression/shortcuts.js +129 -0
- package/output/core/classes/expression/traversal.d.ts +31 -0
- package/output/core/classes/expression/traversal.js +216 -0
- package/output/core/classes/expression/trig.d.ts +25 -0
- package/output/core/classes/expression/trig.js +40 -0
- package/output/core/classes/expression/utils.d.ts +52 -0
- package/output/core/classes/expression/utils.js +189 -0
- package/output/core/classes/lookupTable/LookupTable.d.ts +12 -0
- package/output/core/classes/lookupTable/LookupTable.js +55 -0
- package/output/core/classes/matrix/Matrix.d.ts +227 -0
- package/output/core/classes/matrix/Matrix.js +889 -0
- package/output/core/classes/matrix/Sylvester.d.ts +11 -0
- package/output/core/classes/matrix/Sylvester.js +54 -0
- package/output/core/classes/matrix/functions.d.ts +26 -0
- package/output/core/classes/matrix/functions.js +52 -0
- package/output/core/classes/matrix/utils.d.ts +9 -0
- package/output/core/classes/matrix/utils.js +22 -0
- package/output/core/classes/parser/Parser.d.ts +480 -0
- package/output/core/classes/parser/Parser.js +1812 -0
- package/output/core/classes/parser/Token.d.ts +58 -0
- package/output/core/classes/parser/Token.js +137 -0
- package/output/core/classes/parser/constants.d.ts +160 -0
- package/output/core/classes/parser/constants.js +227 -0
- package/output/core/classes/parser/helpers.d.ts +21 -0
- package/output/core/classes/parser/helpers.js +42 -0
- package/output/core/classes/parser/operations/add.d.ts +15 -0
- package/output/core/classes/parser/operations/add.js +238 -0
- package/output/core/classes/parser/operations/comma.d.ts +7 -0
- package/output/core/classes/parser/operations/comma.js +11 -0
- package/output/core/classes/parser/operations/compare.d.ts +21 -0
- package/output/core/classes/parser/operations/compare.js +461 -0
- package/output/core/classes/parser/operations/divide.d.ts +2 -0
- package/output/core/classes/parser/operations/divide.js +72 -0
- package/output/core/classes/parser/operations/functions.d.ts +46 -0
- package/output/core/classes/parser/operations/functions.js +430 -0
- package/output/core/classes/parser/operations/multiply.d.ts +11 -0
- package/output/core/classes/parser/operations/multiply.js +321 -0
- package/output/core/classes/parser/operations/power.d.ts +48 -0
- package/output/core/classes/parser/operations/power.js +673 -0
- package/output/core/classes/parser/operations/subtract.d.ts +3 -0
- package/output/core/classes/parser/operations/subtract.js +35 -0
- package/output/core/classes/parser/preprocess.d.ts +14 -0
- package/output/core/classes/parser/preprocess.js +259 -0
- package/output/core/classes/parser/scripting/controlFlow.d.ts +121 -0
- package/output/core/classes/parser/scripting/controlFlow.js +355 -0
- package/output/core/classes/parser/scripting/evaluate.d.ts +10 -0
- package/output/core/classes/parser/scripting/evaluate.js +112 -0
- package/output/core/classes/parser/scripting/functions.d.ts +14 -0
- package/output/core/classes/parser/scripting/functions.js +59 -0
- package/output/core/classes/parser/scripting/scope.d.ts +35 -0
- package/output/core/classes/parser/scripting/scope.js +155 -0
- package/output/core/classes/parser/types.d.ts +125 -0
- package/output/core/classes/parser/types.js +2 -0
- package/output/core/classes/parser/wrappers/IndexedReference.d.ts +31 -0
- package/output/core/classes/parser/wrappers/IndexedReference.js +68 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.d.ts +24 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.js +51 -0
- package/output/core/classes/polynomial/Polynomial.d.ts +500 -0
- package/output/core/classes/polynomial/Polynomial.js +1149 -0
- package/output/core/classes/polynomial/Term.d.ts +222 -0
- package/output/core/classes/polynomial/Term.js +430 -0
- package/output/core/classes/polynomial/functions.d.ts +69 -0
- package/output/core/classes/polynomial/functions.js +126 -0
- package/output/core/classes/polynomial/utils.d.ts +62 -0
- package/output/core/classes/polynomial/utils.js +206 -0
- package/output/core/classes/rational/Rational.d.ts +504 -0
- package/output/core/classes/rational/Rational.js +779 -0
- package/output/core/classes/seq/SEQ.d.ts +13 -0
- package/output/core/classes/seq/SEQ.js +137 -0
- package/output/core/classes/valuesSet/ValuesSet.d.ts +179 -0
- package/output/core/classes/valuesSet/ValuesSet.js +381 -0
- package/output/core/classes/vector/Vector.d.ts +222 -0
- package/output/core/classes/vector/Vector.js +497 -0
- package/output/core/classes/vector/functions.d.ts +28 -0
- package/output/core/classes/vector/functions.js +47 -0
- package/output/core/common/classes/MathematicalAggregate.d.ts +53 -0
- package/output/core/common/classes/MathematicalAggregate.js +140 -0
- package/output/core/common/classes/Scope.d.ts +62 -0
- package/output/core/common/classes/Scope.js +122 -0
- package/output/core/common/classes/StructuredEntity.d.ts +55 -0
- package/output/core/common/classes/StructuredEntity.js +151 -0
- package/output/core/common/common.d.ts +63 -0
- package/output/core/common/common.js +279 -0
- package/output/core/common/functions/functions.d.ts +14 -0
- package/output/core/common/functions/functions.js +33 -0
- package/output/core/common/functions/structuredEntityUtils.d.ts +27 -0
- package/output/core/common/functions/structuredEntityUtils.js +40 -0
- package/output/core/converters/BaseConverter.d.ts +97 -0
- package/output/core/converters/BaseConverter.js +405 -0
- package/output/core/converters/Converter.d.ts +111 -0
- package/output/core/converters/Converter.js +802 -0
- package/output/core/converters/Pattern.d.ts +71 -0
- package/output/core/converters/Pattern.js +302 -0
- package/output/core/dispatch.d.ts +34 -0
- package/output/core/dispatch.js +304 -0
- package/output/core/errors.d.ts +531 -0
- package/output/core/errors.js +621 -0
- package/output/core/functions/bigint/bigint.d.ts +121 -0
- package/output/core/functions/bigint/bigint.js +392 -0
- package/output/core/functions/bigint/primeFactor.d.ts +49 -0
- package/output/core/functions/bigint/primeFactor.js +267 -0
- package/output/core/functions/bigint/primes.d.ts +1 -0
- package/output/core/functions/bigint/primes.js +11 -0
- package/output/core/functions/build/definitions.d.ts +12 -0
- package/output/core/functions/build/definitions.js +133 -0
- package/output/core/functions/build/index.d.ts +32 -0
- package/output/core/functions/build/index.js +136 -0
- package/output/core/functions/complex.d.ts +90 -0
- package/output/core/functions/complex.js +482 -0
- package/output/core/functions/decimal.d.ts +24 -0
- package/output/core/functions/decimal.js +664 -0
- package/output/core/functions/expand/expand.d.ts +42 -0
- package/output/core/functions/expand/expand.js +376 -0
- package/output/core/functions/fresnelNumeric.d.ts +12 -0
- package/output/core/functions/fresnelNumeric.js +123 -0
- package/output/core/functions/numeric.d.ts +140 -0
- package/output/core/functions/numeric.js +790 -0
- package/output/core/functions/rationalNormalization.d.ts +11 -0
- package/output/core/functions/rationalNormalization.js +117 -0
- package/output/core/functions/setFunction.d.ts +19 -0
- package/output/core/functions/setFunction.js +75 -0
- package/output/core/functions/string.d.ts +26 -0
- package/output/core/functions/string.js +101 -0
- package/output/core/functions/subst.d.ts +90 -0
- package/output/core/functions/subst.js +498 -0
- package/output/core/functions/utils.d.ts +24 -0
- package/output/core/functions/utils.js +51 -0
- package/output/core/types.d.ts +48 -0
- package/output/core/types.js +2 -0
- package/output/index.d.ts +339 -0
- package/output/index.js +715 -0
- package/output/math/defint/defintDecimal.d.ts +37 -0
- package/output/math/defint/defintDecimal.js +320 -0
- package/output/math/defint/defintNative.d.ts +57 -0
- package/output/math/defint/defintNative.js +292 -0
- package/output/math/geometry.d.ts +8 -0
- package/output/math/geometry.js +32 -0
- package/output/math/math.d.ts +655 -0
- package/output/math/math.js +1811 -0
- package/output/math/trig.d.ts +518 -0
- package/output/math/trig.js +1444 -0
- package/output/math/trunc.d.ts +19 -0
- package/output/math/trunc.js +36 -0
- package/output/math/utils.d.ts +60 -0
- package/output/math/utils.js +180 -0
- package/output/solve/classes/DecimalMatrix.d.ts +17 -0
- package/output/solve/classes/DecimalMatrix.js +86 -0
- package/output/solve/classes/FunctionSolver.d.ts +135 -0
- package/output/solve/classes/FunctionSolver.js +433 -0
- package/output/solve/classes/MultivariateSolver.d.ts +84 -0
- package/output/solve/classes/MultivariateSolver.js +240 -0
- package/output/solve/classes/PolynomialSolver.d.ts +85 -0
- package/output/solve/classes/PolynomialSolver.js +292 -0
- package/output/solve/classes/SolutionSet.d.ts +153 -0
- package/output/solve/classes/SolutionSet.js +357 -0
- package/output/solve/classes/Solver.d.ts +17 -0
- package/output/solve/classes/Solver.js +132 -0
- package/output/solve/classes/SymbolicSolver.d.ts +74 -0
- package/output/solve/classes/SymbolicSolver.js +601 -0
- package/output/solve/linsolve.d.ts +51 -0
- package/output/solve/linsolve.js +225 -0
- package/output/solve/solve.d.ts +34 -0
- package/output/solve/solve.js +260 -0
- package/output/solve/solveSystem.d.ts +31 -0
- package/output/solve/solveSystem.js +290 -0
- package/output/solve/utils.d.ts +9 -0
- package/output/solve/utils.js +62 -0
- package/output/utils/array.d.ts +42 -0
- package/output/utils/array.js +98 -0
- package/output/utils/debug.d.ts +131 -0
- package/output/utils/debug.js +295 -0
- package/output/utils/decimal.d.ts +3 -0
- package/output/utils/decimal.js +16 -0
- package/output/utils/numeric.d.ts +14 -0
- package/output/utils/numeric.js +51 -0
- package/output/utils/object.d.ts +26 -0
- package/output/utils/object.js +56 -0
- package/package.json +213 -57
- package/.travis.yml +0 -3
- package/Algebra.js +0 -4568
- package/BREAKING_CHANGES.md +0 -5
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -14
- package/Calculus.js +0 -2675
- package/Extra.js +0 -622
- package/Solve.js +0 -1783
- package/all.js +0 -16
- package/all.min.js +0 -1
- package/gulpfile.js +0 -16
- package/index.html +0 -158
- package/license.txt +0 -19
- package/nerdamer.core.js +0 -12510
- package/spec/LaTeX.spec.js +0 -302
- package/spec/TeXConvert.spec.js +0 -8
- package/spec/algebra.spec.js +0 -287
- package/spec/basic_parser.spec.js +0 -134
- package/spec/build.spec.js +0 -131
- package/spec/calculus.spec.js +0 -183
- package/spec/core.spec.js +0 -2970
- package/spec/extra.spec.js +0 -54
- package/spec/solve.spec.js +0 -126
- package/spec/support/jasmine.json +0 -11
- package/spec/support/utils.js +0 -42
- package/spec/text.spec.js +0 -132
|
@@ -0,0 +1,1299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module poly
|
|
4
|
+
*
|
|
5
|
+
* Core polynomial representation and operations.
|
|
6
|
+
*
|
|
7
|
+
* This file contains both univariate and multivariate utilities used by:
|
|
8
|
+
* - multivariate GCD (Zippel-style)
|
|
9
|
+
* - multivariate factorization (evaluation + Hensel lifting)
|
|
10
|
+
* - Gröbner basis computations
|
|
11
|
+
*
|
|
12
|
+
* Notes:
|
|
13
|
+
* - Univariate polynomials over Z are represented as coefficient arrays `ZPoly`.
|
|
14
|
+
* - Multivariate polynomials are represented by `MultiPoly` (see near bottom of file).
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.zTrim = zTrim;
|
|
18
|
+
exports.zIsZero = zIsZero;
|
|
19
|
+
exports.zLC = zLC;
|
|
20
|
+
exports.zSub = zSub;
|
|
21
|
+
exports.zTryDivExact = zTryDivExact;
|
|
22
|
+
exports.zDivExact = zDivExact;
|
|
23
|
+
exports.zScale = zScale;
|
|
24
|
+
exports.zNormalizePrimitiveSign = zNormalizePrimitiveSign;
|
|
25
|
+
exports.zNormalizeSign = zNormalizeSign;
|
|
26
|
+
exports.zPrimitivePart = zPrimitivePart;
|
|
27
|
+
exports.zPseudoRemainder = zPseudoRemainder;
|
|
28
|
+
exports.zGcdPrimitivePRS = zGcdPrimitivePRS;
|
|
29
|
+
exports.zGcdFull = zGcdFull;
|
|
30
|
+
exports.zDerivative = zDerivative;
|
|
31
|
+
exports.zShift = zShift;
|
|
32
|
+
exports.fpAdd = fpAdd;
|
|
33
|
+
exports.fpSub = fpSub;
|
|
34
|
+
exports.fpScale = fpScale;
|
|
35
|
+
exports.fpMul = fpMul;
|
|
36
|
+
exports.fpDivRem = fpDivRem;
|
|
37
|
+
exports.fpGCD = fpGCD;
|
|
38
|
+
exports.zTrimMod = zTrimMod;
|
|
39
|
+
exports.zToSymmetricMod = zToSymmetricMod;
|
|
40
|
+
exports.zAddMod = zAddMod;
|
|
41
|
+
exports.zSubMod = zSubMod;
|
|
42
|
+
exports.zScaleMod = zScaleMod;
|
|
43
|
+
exports.zMulMod = zMulMod;
|
|
44
|
+
exports.zDivRemMod = zDivRemMod;
|
|
45
|
+
exports.isOnePoly = isOnePoly;
|
|
46
|
+
exports.mvNormalize = mvNormalize;
|
|
47
|
+
exports.mvDivideByCoeffContent = mvDivideByCoeffContent;
|
|
48
|
+
exports.mvNormalizePrimitiveSignLex = mvNormalizePrimitiveSignLex;
|
|
49
|
+
exports.mvNormalizeSignUnivariateInVar = mvNormalizeSignUnivariateInVar;
|
|
50
|
+
exports.denseToKey = denseToKey;
|
|
51
|
+
exports.mvVariablesSorted = mvVariablesSorted;
|
|
52
|
+
exports.mapCombineInPlace = mapCombineInPlace;
|
|
53
|
+
exports.addPoly = addPoly;
|
|
54
|
+
exports.subPoly = subPoly;
|
|
55
|
+
exports.negPoly = negPoly;
|
|
56
|
+
exports.scalePoly = scalePoly;
|
|
57
|
+
exports.mulPoly = mulPoly;
|
|
58
|
+
exports.equalPoly = equalPoly;
|
|
59
|
+
exports.leadTermLex = leadTermLex;
|
|
60
|
+
exports.mvNumVars = mvNumVars;
|
|
61
|
+
exports.mvExactDiv = mvExactDiv;
|
|
62
|
+
exports.mvExactDivByMonomial = mvExactDivByMonomial;
|
|
63
|
+
exports.monoDividesDense = monoDividesDense;
|
|
64
|
+
exports.monoSubDense = monoSubDense;
|
|
65
|
+
exports.substituteVarIndex = substituteVarIndex;
|
|
66
|
+
exports.removeVarIndex = removeVarIndex;
|
|
67
|
+
exports.addVarIndex = addVarIndex;
|
|
68
|
+
exports.fromUnivariate = fromUnivariate;
|
|
69
|
+
exports.toUnivariate = toUnivariate;
|
|
70
|
+
exports.viewAsUnivariate = viewAsUnivariate;
|
|
71
|
+
exports.fromUnivariateView = fromUnivariateView;
|
|
72
|
+
exports.pseudoDivide = pseudoDivide;
|
|
73
|
+
exports.multiPolyGCD = multiPolyGCD;
|
|
74
|
+
exports.mvContentInVar = mvContentInVar;
|
|
75
|
+
exports.primitivePart = primitivePart;
|
|
76
|
+
exports.quadraticCoeffsInVar = quadraticCoeffsInVar;
|
|
77
|
+
const arith_1 = require("./arith");
|
|
78
|
+
const MultiPoly_1 = require("./multiPoly/MultiPoly");
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Z[x] helpers
|
|
81
|
+
// ============================================================================
|
|
82
|
+
/** Returns a trimmed copy (does not mutate input). */
|
|
83
|
+
function zTrim(a) {
|
|
84
|
+
let n = a.length;
|
|
85
|
+
while (n > 1 && a[n - 1] === 0n) {
|
|
86
|
+
n--;
|
|
87
|
+
}
|
|
88
|
+
return n === a.length ? a : a.slice(0, n);
|
|
89
|
+
}
|
|
90
|
+
/** In-place trim (mutates) and returns the same array. */
|
|
91
|
+
function zTrimInPlace(a) {
|
|
92
|
+
while (a.length > 1 && a[a.length - 1] === 0n) {
|
|
93
|
+
a.pop();
|
|
94
|
+
}
|
|
95
|
+
return a;
|
|
96
|
+
}
|
|
97
|
+
/** True iff polynomial is identically 0. */
|
|
98
|
+
function zIsZero(a) {
|
|
99
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
100
|
+
if ((a[i] ?? 0n) !== 0n) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
function zDeg(a) {
|
|
107
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
108
|
+
if ((a[i] ?? 0n) !== 0n) {
|
|
109
|
+
return i;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
function zLC(a) {
|
|
115
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
116
|
+
const c = a[i] ?? 0n;
|
|
117
|
+
if (c !== 0n) {
|
|
118
|
+
return c;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return 0n;
|
|
122
|
+
}
|
|
123
|
+
function zSub(a, b) {
|
|
124
|
+
const n = Math.max(a.length, b.length);
|
|
125
|
+
const out = new Array(n).fill(0n);
|
|
126
|
+
for (let i = 0; i < n; i++) {
|
|
127
|
+
out[i] = (a[i] ?? 0n) - (b[i] ?? 0n);
|
|
128
|
+
}
|
|
129
|
+
return zTrimInPlace(out);
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Exact division in Z[x]
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
/** Polynomial long division in Z[x]. Returns quotient and remainder. */
|
|
135
|
+
function zDivRem(a, b) {
|
|
136
|
+
a = zTrim(a.slice());
|
|
137
|
+
b = zTrim(b.slice());
|
|
138
|
+
if (zIsZero(b)) {
|
|
139
|
+
throw new Error('zDivRem: division by zero polynomial');
|
|
140
|
+
}
|
|
141
|
+
const da = zDeg(a);
|
|
142
|
+
const db = zDeg(b);
|
|
143
|
+
if (da < db) {
|
|
144
|
+
return { q: [0n], r: a };
|
|
145
|
+
}
|
|
146
|
+
const lcb = zLC(b);
|
|
147
|
+
const q = new Array(da - db + 1).fill(0n);
|
|
148
|
+
const r = a.slice();
|
|
149
|
+
for (let k = da; k >= db; k--) {
|
|
150
|
+
const idx = k - db;
|
|
151
|
+
const cr = r[k] ?? 0n;
|
|
152
|
+
if (cr === 0n) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// exact coefficient division is required for an exact division result.
|
|
156
|
+
if (cr % lcb !== 0n) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const coeff = cr / lcb;
|
|
160
|
+
q[idx] += coeff;
|
|
161
|
+
for (let j = 0; j <= db; j++) {
|
|
162
|
+
r[idx + j] = (r[idx + j] ?? 0n) - coeff * (b[j] ?? 0n);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { q: zTrimInPlace(q), r: zTrimInPlace(r) };
|
|
166
|
+
}
|
|
167
|
+
/** Returns q iff a = b*q exactly; otherwise null. */
|
|
168
|
+
function zTryDivExact(a, b) {
|
|
169
|
+
const { q, r } = zDivRem(a, b);
|
|
170
|
+
return zIsZero(r) ? q : null;
|
|
171
|
+
}
|
|
172
|
+
/** Returns q such that a = b*q. Throws if division is not exact. */
|
|
173
|
+
function zDivExact(a, b) {
|
|
174
|
+
const q = zTryDivExact(a, b);
|
|
175
|
+
if (q === null) {
|
|
176
|
+
throw new Error('zDivExact: non-exact division');
|
|
177
|
+
}
|
|
178
|
+
return q;
|
|
179
|
+
}
|
|
180
|
+
function zScale(a, k) {
|
|
181
|
+
if (k === 0n) {
|
|
182
|
+
return [0n];
|
|
183
|
+
}
|
|
184
|
+
if (k === 1n) {
|
|
185
|
+
return zTrim(a);
|
|
186
|
+
}
|
|
187
|
+
const out = a.map(c => (c ?? 0n) * k);
|
|
188
|
+
return zTrimInPlace(out);
|
|
189
|
+
}
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// Canonical normalization layer (public)
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
/**
|
|
194
|
+
* Normalize polynomial by extracting nonnegative content and fixing the sign
|
|
195
|
+
* so the leading coefficient is positive.
|
|
196
|
+
*
|
|
197
|
+
* - For 0 returns { content: 0, primitive: 0 }
|
|
198
|
+
* - For nonzero returns { content: c, primitive: p } where:
|
|
199
|
+
* - c = gcd(|coeffs|) >= 1
|
|
200
|
+
* - p has gcd(|coeffs|)=1
|
|
201
|
+
* - LC(p) > 0
|
|
202
|
+
*/
|
|
203
|
+
function zNormalizePrimitiveSign(a) {
|
|
204
|
+
const t = zTrimInPlace(a.slice());
|
|
205
|
+
if (t.length === 1 && t[0] === 0n) {
|
|
206
|
+
return { content: 0n, primitive: [0n] };
|
|
207
|
+
}
|
|
208
|
+
let c = (0, arith_1.contentBigint)(t);
|
|
209
|
+
if (c === 0n) {
|
|
210
|
+
c = 1n;
|
|
211
|
+
}
|
|
212
|
+
const prim = t.map(x => (x ?? 0n) / c);
|
|
213
|
+
// Normalize sign: positive leading coefficient
|
|
214
|
+
const lc = prim[prim.length - 1] ?? 0n;
|
|
215
|
+
if (lc < 0n) {
|
|
216
|
+
for (let i = 0; i < prim.length; i++) {
|
|
217
|
+
prim[i] = -prim[i];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return { content: c, primitive: zTrimInPlace(prim) };
|
|
221
|
+
}
|
|
222
|
+
/** Normalize only by sign (units in Z are ±1). Does not strip content. */
|
|
223
|
+
function zNormalizeSign(aIn) {
|
|
224
|
+
let a = zTrim(aIn.slice());
|
|
225
|
+
if (a.length === 0) {
|
|
226
|
+
return [0n];
|
|
227
|
+
}
|
|
228
|
+
if (a.length === 1) {
|
|
229
|
+
return a[0] === 0n ? [0n] : [a[0] < 0n ? -a[0] : a[0]];
|
|
230
|
+
}
|
|
231
|
+
if ((a[a.length - 1] ?? 0n) < 0n) {
|
|
232
|
+
a = a.map(c => -c);
|
|
233
|
+
}
|
|
234
|
+
return a;
|
|
235
|
+
}
|
|
236
|
+
/** Primitive part with positive leading coefficient. */
|
|
237
|
+
function zPrimitivePart(a) {
|
|
238
|
+
return zNormalizePrimitiveSign(a).primitive;
|
|
239
|
+
}
|
|
240
|
+
/** Pseudo-remainder of `a` by `b` over Z[x]. */
|
|
241
|
+
function zPseudoRemainder(aIn, bIn) {
|
|
242
|
+
const a = zTrim(aIn.slice());
|
|
243
|
+
const b = zTrim(bIn.slice());
|
|
244
|
+
if (zIsZero(b)) {
|
|
245
|
+
throw new Error('zPseudoRemainder: divide by zero');
|
|
246
|
+
}
|
|
247
|
+
const db = b.length - 1;
|
|
248
|
+
const lcB = b[db];
|
|
249
|
+
let r = a;
|
|
250
|
+
while (!zIsZero(r) && r.length - 1 >= db) {
|
|
251
|
+
const dr = r.length - 1;
|
|
252
|
+
const k = dr - db;
|
|
253
|
+
const lcR = r[dr];
|
|
254
|
+
const scaled = r.map(c => c * lcB);
|
|
255
|
+
for (let i = 0; i <= db; i++) {
|
|
256
|
+
scaled[i + k] -= lcR * (b[i] ?? 0n);
|
|
257
|
+
}
|
|
258
|
+
r = zTrimInPlace(scaled);
|
|
259
|
+
const cont = (0, arith_1.contentBigint)(r);
|
|
260
|
+
if (cont > 1n) {
|
|
261
|
+
for (let i = 0; i < r.length; i++) {
|
|
262
|
+
r[i] /= cont;
|
|
263
|
+
}
|
|
264
|
+
zTrimInPlace(r);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return r;
|
|
268
|
+
}
|
|
269
|
+
/** Primitive PRS GCD over Z[x] with positive leading coefficient. */
|
|
270
|
+
function zGcdPrimitivePRS(fIn, gIn) {
|
|
271
|
+
let a = zPrimitivePart(fIn);
|
|
272
|
+
let b = zPrimitivePart(gIn);
|
|
273
|
+
if (zIsZero(a) && zIsZero(b)) {
|
|
274
|
+
return [0n];
|
|
275
|
+
}
|
|
276
|
+
if (zIsZero(a)) {
|
|
277
|
+
return zPrimitivePart(b);
|
|
278
|
+
}
|
|
279
|
+
if (zIsZero(b)) {
|
|
280
|
+
return zPrimitivePart(a);
|
|
281
|
+
}
|
|
282
|
+
while (!zIsZero(b)) {
|
|
283
|
+
const r = zPseudoRemainder(a, b);
|
|
284
|
+
a = b;
|
|
285
|
+
b = zPrimitivePart(r);
|
|
286
|
+
}
|
|
287
|
+
return zPrimitivePart(a);
|
|
288
|
+
}
|
|
289
|
+
/** Full GCD over Z[x], including gcd(content(f), content(g)). */
|
|
290
|
+
function zGcdFull(fIn, gIn) {
|
|
291
|
+
if (zIsZero(fIn)) {
|
|
292
|
+
return zNormalizeSign(gIn);
|
|
293
|
+
}
|
|
294
|
+
if (zIsZero(gIn)) {
|
|
295
|
+
return zNormalizeSign(fIn);
|
|
296
|
+
}
|
|
297
|
+
const cf = zNormalizePrimitiveSign(fIn).content;
|
|
298
|
+
const cg = zNormalizePrimitiveSign(gIn).content;
|
|
299
|
+
const c = (0, arith_1.gcd)(cf, cg);
|
|
300
|
+
const f = cf === 0n || cf === 1n ? zTrim(fIn.slice()) : zDivExact(fIn, [cf]);
|
|
301
|
+
const g = cg === 0n || cg === 1n ? zTrim(gIn.slice()) : zDivExact(gIn, [cg]);
|
|
302
|
+
const dpp = zGcdPrimitivePRS(f, g);
|
|
303
|
+
if (c === 0n || c === 1n) {
|
|
304
|
+
return zNormalizeSign(dpp);
|
|
305
|
+
}
|
|
306
|
+
return zNormalizeSign(dpp.map(a => a * c));
|
|
307
|
+
}
|
|
308
|
+
function zDerivative(a) {
|
|
309
|
+
const t = zTrimInPlace(a.slice());
|
|
310
|
+
if (t.length <= 1) {
|
|
311
|
+
return [0n];
|
|
312
|
+
}
|
|
313
|
+
const out = new Array(t.length - 1).fill(0n);
|
|
314
|
+
for (let i = 1; i < t.length; i++) {
|
|
315
|
+
out[i - 1] = (t[i] ?? 0n) * BigInt(i);
|
|
316
|
+
}
|
|
317
|
+
return zTrimInPlace(out);
|
|
318
|
+
}
|
|
319
|
+
/** Multiply by x^k. */
|
|
320
|
+
function zShift(a, k) {
|
|
321
|
+
if (k <= 0) {
|
|
322
|
+
return zTrim(a);
|
|
323
|
+
}
|
|
324
|
+
const t = zTrimInPlace(a.slice());
|
|
325
|
+
if (t.length === 1 && t[0] === 0n) {
|
|
326
|
+
return [0n];
|
|
327
|
+
}
|
|
328
|
+
const out = new Array(t.length + k).fill(0n);
|
|
329
|
+
for (let i = 0; i < t.length; i++) {
|
|
330
|
+
out[i + k] = t[i] ?? 0n;
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
function fpTrim(f) {
|
|
335
|
+
const a = f.coeffs.slice();
|
|
336
|
+
const p = f.p;
|
|
337
|
+
for (let i = 0; i < a.length; i++) {
|
|
338
|
+
a[i] = (0, arith_1.modNorm)(a[i] ?? 0n, p);
|
|
339
|
+
}
|
|
340
|
+
zTrimInPlace(a);
|
|
341
|
+
return { p, coeffs: a };
|
|
342
|
+
}
|
|
343
|
+
function fpIsZero(f) {
|
|
344
|
+
const t = fpTrim(f);
|
|
345
|
+
return t.coeffs.length === 1 && t.coeffs[0] === 0n;
|
|
346
|
+
}
|
|
347
|
+
function fpLC(f) {
|
|
348
|
+
const t = fpTrim(f).coeffs;
|
|
349
|
+
return t[t.length - 1] ?? 0n;
|
|
350
|
+
}
|
|
351
|
+
function fpAdd(a, b) {
|
|
352
|
+
if (a.p !== b.p) {
|
|
353
|
+
throw new Error('fpAdd: modulus mismatch');
|
|
354
|
+
}
|
|
355
|
+
const p = a.p;
|
|
356
|
+
const n = Math.max(a.coeffs.length, b.coeffs.length);
|
|
357
|
+
const out = new Array(n).fill(0n);
|
|
358
|
+
for (let i = 0; i < n; i++) {
|
|
359
|
+
out[i] = (0, arith_1.modNorm)((a.coeffs[i] ?? 0n) + (b.coeffs[i] ?? 0n), p);
|
|
360
|
+
}
|
|
361
|
+
return { p, coeffs: zTrimInPlace(out) };
|
|
362
|
+
}
|
|
363
|
+
function fpSub(a, b) {
|
|
364
|
+
if (a.p !== b.p) {
|
|
365
|
+
throw new Error('fpSub: modulus mismatch');
|
|
366
|
+
}
|
|
367
|
+
const p = a.p;
|
|
368
|
+
const n = Math.max(a.coeffs.length, b.coeffs.length);
|
|
369
|
+
const out = new Array(n).fill(0n);
|
|
370
|
+
for (let i = 0; i < n; i++) {
|
|
371
|
+
out[i] = (0, arith_1.modNorm)((a.coeffs[i] ?? 0n) - (b.coeffs[i] ?? 0n), p);
|
|
372
|
+
}
|
|
373
|
+
return { p, coeffs: zTrimInPlace(out) };
|
|
374
|
+
}
|
|
375
|
+
function fpScale(a, k) {
|
|
376
|
+
const p = a.p;
|
|
377
|
+
const kk = (0, arith_1.modNorm)(k, p);
|
|
378
|
+
if (kk === 0n) {
|
|
379
|
+
return { p, coeffs: [0n] };
|
|
380
|
+
}
|
|
381
|
+
if (kk === 1n) {
|
|
382
|
+
return fpTrim(a);
|
|
383
|
+
}
|
|
384
|
+
const out = a.coeffs.map(c => (0, arith_1.modNorm)((c ?? 0n) * kk, p));
|
|
385
|
+
return { p, coeffs: zTrimInPlace(out) };
|
|
386
|
+
}
|
|
387
|
+
function fpMul(a, b) {
|
|
388
|
+
if (a.p !== b.p) {
|
|
389
|
+
throw new Error('fpMul: modulus mismatch');
|
|
390
|
+
}
|
|
391
|
+
const p = a.p;
|
|
392
|
+
const aa = fpTrim(a).coeffs;
|
|
393
|
+
const bb = fpTrim(b).coeffs;
|
|
394
|
+
if (aa.length === 1 && aa[0] === 0n) {
|
|
395
|
+
return { p, coeffs: [0n] };
|
|
396
|
+
}
|
|
397
|
+
if (bb.length === 1 && bb[0] === 0n) {
|
|
398
|
+
return { p, coeffs: [0n] };
|
|
399
|
+
}
|
|
400
|
+
const out = new Array(aa.length + bb.length - 1).fill(0n);
|
|
401
|
+
for (let i = 0; i < aa.length; i++) {
|
|
402
|
+
const ai = aa[i] ?? 0n;
|
|
403
|
+
if (ai === 0n) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
for (let j = 0; j < bb.length; j++) {
|
|
407
|
+
const bj = bb[j] ?? 0n;
|
|
408
|
+
if (bj === 0n) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
out[i + j] = (0, arith_1.modNorm)((out[i + j] ?? 0n) + ai * bj, p);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return { p, coeffs: zTrimInPlace(out) };
|
|
415
|
+
}
|
|
416
|
+
function fpMonic(f) {
|
|
417
|
+
const t = fpTrim(f);
|
|
418
|
+
if (fpIsZero(t)) {
|
|
419
|
+
return t;
|
|
420
|
+
}
|
|
421
|
+
const lc = fpLC(t);
|
|
422
|
+
const inv = (0, arith_1.modInv)(lc, t.p);
|
|
423
|
+
return fpScale(t, inv);
|
|
424
|
+
}
|
|
425
|
+
function fpDivRem(a, b) {
|
|
426
|
+
if (a.p !== b.p) {
|
|
427
|
+
throw new Error('fpDivRem: modulus mismatch');
|
|
428
|
+
}
|
|
429
|
+
const p = a.p;
|
|
430
|
+
const A = fpTrim(a).coeffs.slice();
|
|
431
|
+
const B = fpTrim(b).coeffs.slice();
|
|
432
|
+
zTrimInPlace(A);
|
|
433
|
+
zTrimInPlace(B);
|
|
434
|
+
if (B.length === 1 && B[0] === 0n) {
|
|
435
|
+
throw new Error('fpDivRem: division by zero polynomial');
|
|
436
|
+
}
|
|
437
|
+
if (A.length === 1 && A[0] === 0n) {
|
|
438
|
+
return { q: { p, coeffs: [0n] }, r: { p, coeffs: [0n] } };
|
|
439
|
+
}
|
|
440
|
+
const da = A.length - 1;
|
|
441
|
+
const db = B.length - 1;
|
|
442
|
+
if (da < db) {
|
|
443
|
+
return { q: { p, coeffs: [0n] }, r: { p, coeffs: A } };
|
|
444
|
+
}
|
|
445
|
+
const q = new Array(da - db + 1).fill(0n);
|
|
446
|
+
const invLc = (0, arith_1.modInv)(B[db] ?? 0n, p);
|
|
447
|
+
for (let k = da - db; k >= 0; k--) {
|
|
448
|
+
const coeff = (0, arith_1.modNorm)((A[db + k] ?? 0n) * invLc, p);
|
|
449
|
+
q[k] = coeff;
|
|
450
|
+
if (coeff !== 0n) {
|
|
451
|
+
for (let j = 0; j <= db; j++) {
|
|
452
|
+
A[j + k] = (0, arith_1.modNorm)((A[j + k] ?? 0n) - coeff * (B[j] ?? 0n), p);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const r = A.slice(0, db);
|
|
457
|
+
zTrimInPlace(q);
|
|
458
|
+
zTrimInPlace(r);
|
|
459
|
+
return { q: { p, coeffs: q }, r: { p, coeffs: r.length ? r : [0n] } };
|
|
460
|
+
}
|
|
461
|
+
function fpGCD(a, b) {
|
|
462
|
+
if (a.p !== b.p) {
|
|
463
|
+
throw new Error('fpGCD: modulus mismatch');
|
|
464
|
+
}
|
|
465
|
+
let A = fpTrim(a);
|
|
466
|
+
let B = fpTrim(b);
|
|
467
|
+
while (!fpIsZero(B)) {
|
|
468
|
+
const { r } = fpDivRem(A, B);
|
|
469
|
+
A = B;
|
|
470
|
+
B = fpTrim(r);
|
|
471
|
+
}
|
|
472
|
+
return fpMonic(A);
|
|
473
|
+
}
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// Z/mZ[x] helpers (generic modulus, coefficient arrays low->high)
|
|
476
|
+
// ============================================================================
|
|
477
|
+
/** Trim and reduce coefficients modulo m (does not mutate input). */
|
|
478
|
+
function zTrimMod(a, m) {
|
|
479
|
+
const out = a.map(c => (0, arith_1.modNorm)(c ?? 0n, m));
|
|
480
|
+
return zTrimInPlace(out);
|
|
481
|
+
}
|
|
482
|
+
/** Map coefficients to symmetric representatives modulo m (each in (-m/2, m/2]). */
|
|
483
|
+
function zToSymmetricMod(poly, m) {
|
|
484
|
+
return poly.map(c => (0, arith_1.modSymmetric)(c, m));
|
|
485
|
+
}
|
|
486
|
+
function zAddMod(a, b, m) {
|
|
487
|
+
const n = Math.max(a.length, b.length);
|
|
488
|
+
const out = new Array(n).fill(0n);
|
|
489
|
+
for (let i = 0; i < n; i++) {
|
|
490
|
+
out[i] = (0, arith_1.modNorm)((a[i] ?? 0n) + (b[i] ?? 0n), m);
|
|
491
|
+
}
|
|
492
|
+
return zTrimInPlace(out);
|
|
493
|
+
}
|
|
494
|
+
function zSubMod(a, b, m) {
|
|
495
|
+
const n = Math.max(a.length, b.length);
|
|
496
|
+
const out = new Array(n).fill(0n);
|
|
497
|
+
for (let i = 0; i < n; i++) {
|
|
498
|
+
out[i] = (0, arith_1.modNorm)((a[i] ?? 0n) - (b[i] ?? 0n), m);
|
|
499
|
+
}
|
|
500
|
+
return zTrimInPlace(out);
|
|
501
|
+
}
|
|
502
|
+
function zScaleMod(a, k, m) {
|
|
503
|
+
const kk = (0, arith_1.modNorm)(k, m);
|
|
504
|
+
if (kk === 0n) {
|
|
505
|
+
return [0n];
|
|
506
|
+
}
|
|
507
|
+
const out = a.map(c => (0, arith_1.modNorm)((c ?? 0n) * kk, m));
|
|
508
|
+
return zTrimInPlace(out);
|
|
509
|
+
}
|
|
510
|
+
function zMulMod(a, b, m) {
|
|
511
|
+
a = zTrimMod(a, m);
|
|
512
|
+
b = zTrimMod(b, m);
|
|
513
|
+
if (zIsZero(a) || zIsZero(b)) {
|
|
514
|
+
return [0n];
|
|
515
|
+
}
|
|
516
|
+
const out = new Array(a.length + b.length - 1).fill(0n);
|
|
517
|
+
for (let i = 0; i < a.length; i++) {
|
|
518
|
+
const ai = (0, arith_1.modNorm)(a[i] ?? 0n, m);
|
|
519
|
+
if (ai === 0n) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
for (let j = 0; j < b.length; j++) {
|
|
523
|
+
const bj = (0, arith_1.modNorm)(b[j] ?? 0n, m);
|
|
524
|
+
if (bj === 0n) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
out[i + j] = (0, arith_1.modNorm)((out[i + j] ?? 0n) + ai * bj, m);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return zTrimInPlace(out);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Polynomial long division in (Z/mZ)[x] assuming the leading coefficient of b
|
|
534
|
+
* is invertible modulo m.
|
|
535
|
+
*/
|
|
536
|
+
function zDivRemMod(a, b, m) {
|
|
537
|
+
const A = zTrimMod(a, m).slice();
|
|
538
|
+
const B = zTrimMod(b, m).slice();
|
|
539
|
+
if (zIsZero(B)) {
|
|
540
|
+
throw new Error('zDivRemMod: division by zero polynomial');
|
|
541
|
+
}
|
|
542
|
+
const da = zDeg(A);
|
|
543
|
+
const db = zDeg(B);
|
|
544
|
+
if (da < db) {
|
|
545
|
+
return { q: [0n], r: A };
|
|
546
|
+
}
|
|
547
|
+
const invLc = (0, arith_1.modInv)(zLC(B), m);
|
|
548
|
+
const q = new Array(da - db + 1).fill(0n);
|
|
549
|
+
const r = A;
|
|
550
|
+
while (zDeg(r) >= db && !zIsZero(r)) {
|
|
551
|
+
const dr = zDeg(r);
|
|
552
|
+
const k = dr - db;
|
|
553
|
+
const coeff = (0, arith_1.modNorm)((r[dr] ?? 0n) * invLc, m);
|
|
554
|
+
q[k] = (0, arith_1.modNorm)((q[k] ?? 0n) + coeff, m);
|
|
555
|
+
for (let i = 0; i <= db; i++) {
|
|
556
|
+
r[i + k] = (0, arith_1.modNorm)((r[i + k] ?? 0n) - coeff * (B[i] ?? 0n), m);
|
|
557
|
+
}
|
|
558
|
+
zTrimInPlace(r);
|
|
559
|
+
}
|
|
560
|
+
return { q: zTrimInPlace(q), r: zTrimInPlace(r) };
|
|
561
|
+
}
|
|
562
|
+
/** Lex compare of dense exponent vectors. Returns 1 if a>b, -1 if a<b. */
|
|
563
|
+
function compareDenseLex(a, b) {
|
|
564
|
+
const n = Math.max(a.length, b.length);
|
|
565
|
+
for (let i = 0; i < n; i++) {
|
|
566
|
+
const ai = a[i] ?? 0;
|
|
567
|
+
const bi = b[i] ?? 0;
|
|
568
|
+
if (ai !== bi) {
|
|
569
|
+
return ai > bi ? 1 : -1;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
// Helper: detect multiplicative identity
|
|
575
|
+
function isOnePoly(p) {
|
|
576
|
+
return p.isConstant() && p.constantTerm() === 1n;
|
|
577
|
+
}
|
|
578
|
+
// ---------------------------------------------------------------------------
|
|
579
|
+
// Canonicalization / simple queries
|
|
580
|
+
// ---------------------------------------------------------------------------
|
|
581
|
+
/**
|
|
582
|
+
* Return a trimmed clone of p (removes zero coefficients).
|
|
583
|
+
* MultiPoly does not guarantee trimming after every operation; keep this
|
|
584
|
+
* as the single canonical normalization entry point for algorithms.
|
|
585
|
+
*/
|
|
586
|
+
function mvNormalize(p) {
|
|
587
|
+
const out = p.clone();
|
|
588
|
+
out.trim();
|
|
589
|
+
return out;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Divide by coefficient content, returning {content, primitive}.
|
|
593
|
+
* For the zero polynomial returns {0, 0}.
|
|
594
|
+
*/
|
|
595
|
+
function mvDivideByCoeffContent(p) {
|
|
596
|
+
const c = (0, arith_1.contentBigint)(p.terms.values());
|
|
597
|
+
if (c === 0n) {
|
|
598
|
+
return { content: 0n, primitive: MultiPoly_1.MultiPoly.zero() };
|
|
599
|
+
}
|
|
600
|
+
if (c === 1n) {
|
|
601
|
+
return { content: 1n, primitive: p.clone() };
|
|
602
|
+
}
|
|
603
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
604
|
+
for (const [k, coeff] of p.terms) {
|
|
605
|
+
if (coeff % c !== 0n) {
|
|
606
|
+
throw new Error('mvDivideByCoeffContent: non-exact division');
|
|
607
|
+
}
|
|
608
|
+
const q = coeff / c;
|
|
609
|
+
if (q !== 0n) {
|
|
610
|
+
out.terms.set(k, q);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
out.trim();
|
|
614
|
+
return { content: c, primitive: out };
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Normalize by extracting coefficient content and fixing sign so the
|
|
618
|
+
* lex-leading term coefficient is positive.
|
|
619
|
+
*
|
|
620
|
+
* - For 0 returns { content: 0, primitive: 0 }
|
|
621
|
+
* - For nonzero returns { content: c>=1, primitive } with:
|
|
622
|
+
* - coeff-content(primitive)=1
|
|
623
|
+
* - lex-leading term coefficient > 0
|
|
624
|
+
*/
|
|
625
|
+
function mvNormalizePrimitiveSignLex(p) {
|
|
626
|
+
if (p.terms.size === 0) {
|
|
627
|
+
return { content: 0n, primitive: MultiPoly_1.MultiPoly.zero() };
|
|
628
|
+
}
|
|
629
|
+
const { content, primitive } = mvDivideByCoeffContent(p);
|
|
630
|
+
if (primitive.terms.size === 0) {
|
|
631
|
+
return { content, primitive };
|
|
632
|
+
}
|
|
633
|
+
const lt = leadTermLex(primitive, mvNumVars(primitive));
|
|
634
|
+
if (lt && lt.coeff < 0n) {
|
|
635
|
+
return { content: -content, primitive: scalePoly(primitive, -1n) };
|
|
636
|
+
}
|
|
637
|
+
return { content, primitive };
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Normalize the sign of a polynomial that is univariate in `varIndex` without changing its content.
|
|
641
|
+
*
|
|
642
|
+
* IMPORTANT: This is intended for evaluation/interpolation pipelines where dividing by coefficient
|
|
643
|
+
* content would introduce a point-dependent scaling and break reconstruction.
|
|
644
|
+
*/
|
|
645
|
+
function mvNormalizeSignUnivariateInVar(p, varIndex) {
|
|
646
|
+
if (p.terms.size === 0) {
|
|
647
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
648
|
+
}
|
|
649
|
+
let q = p;
|
|
650
|
+
const deg = mvDegree(q, varIndex);
|
|
651
|
+
if (deg <= 0) {
|
|
652
|
+
return q;
|
|
653
|
+
}
|
|
654
|
+
// Find leading coefficient term for x_varIndex^deg (assuming univariate in varIndex).
|
|
655
|
+
let lc = 0n;
|
|
656
|
+
for (const [key, coeff] of q.terms) {
|
|
657
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
658
|
+
if ((exp.get(varIndex) ?? 0) !== deg) {
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
let ok = true;
|
|
662
|
+
for (const [v, e] of exp.entries()) {
|
|
663
|
+
if (v !== varIndex && e !== 0) {
|
|
664
|
+
ok = false;
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (ok) {
|
|
669
|
+
lc = coeff;
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (lc < 0n) {
|
|
674
|
+
q = scalePoly(q, -1n);
|
|
675
|
+
}
|
|
676
|
+
return q;
|
|
677
|
+
}
|
|
678
|
+
function denseToExponents(exps) {
|
|
679
|
+
const m = new Map();
|
|
680
|
+
for (let i = 0; i < exps.length; i++) {
|
|
681
|
+
const e = exps[i] ?? 0;
|
|
682
|
+
if (e !== 0) {
|
|
683
|
+
m.set(i, e);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return m;
|
|
687
|
+
}
|
|
688
|
+
function denseToKey(exps) {
|
|
689
|
+
return (0, MultiPoly_1.expToKey)(denseToExponents(exps));
|
|
690
|
+
}
|
|
691
|
+
/** Return the variable indices that occur in p, sorted ascending. */
|
|
692
|
+
function mvVariablesSorted(p) {
|
|
693
|
+
return Array.from(p.variables()).sort((a, b) => a - b);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Degree of p in variable varIndex.
|
|
697
|
+
* Convention: deg(0) = -1
|
|
698
|
+
*/
|
|
699
|
+
function mvDegree(p, varIndex) {
|
|
700
|
+
if (p.terms.size === 0) {
|
|
701
|
+
return -1;
|
|
702
|
+
}
|
|
703
|
+
let maxDeg = 0;
|
|
704
|
+
for (const key of p.terms.keys()) {
|
|
705
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
706
|
+
const d = exp.get(varIndex) ?? 0;
|
|
707
|
+
if (d > maxDeg) {
|
|
708
|
+
maxDeg = d;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return maxDeg;
|
|
712
|
+
}
|
|
713
|
+
// Generic helper to combine coefficient maps without duplicating merge logic.
|
|
714
|
+
// NOTE: Kept generic so factor.ts (Rat coefficients) can reuse it without poly.ts depending on Rat.
|
|
715
|
+
function mapCombineInPlace(dest, src, combine, isZero, zero) {
|
|
716
|
+
for (const [k, b] of src) {
|
|
717
|
+
const a = dest.get(k) ?? zero();
|
|
718
|
+
const c = combine(a, b);
|
|
719
|
+
if (isZero(c)) {
|
|
720
|
+
dest.delete(k);
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
dest.set(k, c);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
/** Add two polynomials. */
|
|
728
|
+
function addPoly(a, b) {
|
|
729
|
+
const out = new MultiPoly_1.MultiPoly(a.terms);
|
|
730
|
+
mapCombineInPlace(out.terms, b.terms, (x, y) => x + y, v => v === 0n, () => 0n);
|
|
731
|
+
out.trim();
|
|
732
|
+
return out;
|
|
733
|
+
}
|
|
734
|
+
/** Subtract b from a. */
|
|
735
|
+
function subPoly(a, b) {
|
|
736
|
+
const out = new MultiPoly_1.MultiPoly(a.terms);
|
|
737
|
+
mapCombineInPlace(out.terms, b.terms, (x, y) => x - y, v => v === 0n, () => 0n);
|
|
738
|
+
out.trim();
|
|
739
|
+
return out;
|
|
740
|
+
}
|
|
741
|
+
/** Negate polynomial. */
|
|
742
|
+
function negPoly(a) {
|
|
743
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
744
|
+
for (const [k, c] of a.terms) {
|
|
745
|
+
if (c !== 0n) {
|
|
746
|
+
out.terms.set(k, -c);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
out.trim();
|
|
750
|
+
return out;
|
|
751
|
+
}
|
|
752
|
+
/** Multiply all coefficients of a polynomial by a scalar. */
|
|
753
|
+
function scalePoly(a, k) {
|
|
754
|
+
if (k === 0n) {
|
|
755
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
756
|
+
}
|
|
757
|
+
if (k === 1n) {
|
|
758
|
+
return a.clone();
|
|
759
|
+
}
|
|
760
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
761
|
+
for (const [key, coeff] of a.terms) {
|
|
762
|
+
const v = coeff * k;
|
|
763
|
+
if (v !== 0n) {
|
|
764
|
+
out.terms.set(key, v);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
out.trim();
|
|
768
|
+
return out;
|
|
769
|
+
}
|
|
770
|
+
/** Multiply polynomials. */
|
|
771
|
+
function mulPoly(a, b) {
|
|
772
|
+
if (a.terms.size === 0 || b.terms.size === 0) {
|
|
773
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
774
|
+
}
|
|
775
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
776
|
+
for (const [ka, ca] of a.terms) {
|
|
777
|
+
const ea = (0, MultiPoly_1.keyToExp)(ka);
|
|
778
|
+
for (const [kb, cb] of b.terms) {
|
|
779
|
+
const eb = (0, MultiPoly_1.keyToExp)(kb);
|
|
780
|
+
const e = new Map(ea);
|
|
781
|
+
for (const [v, p] of eb) {
|
|
782
|
+
e.set(v, (e.get(v) ?? 0) + p);
|
|
783
|
+
}
|
|
784
|
+
const k = (0, MultiPoly_1.expToKey)(e);
|
|
785
|
+
const prev = out.terms.get(k) ?? 0n;
|
|
786
|
+
const val = prev + ca * cb;
|
|
787
|
+
if (val === 0n) {
|
|
788
|
+
out.terms.delete(k);
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
out.terms.set(k, val);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
out.trim();
|
|
796
|
+
return out;
|
|
797
|
+
}
|
|
798
|
+
/** Structural equality of two polynomials (assumes both are already trimmed/normalized). */
|
|
799
|
+
function equalPoly(a, b) {
|
|
800
|
+
if (a === b) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
803
|
+
if (a.terms.size !== b.terms.size) {
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
for (const [k, ca] of a.terms) {
|
|
807
|
+
if ((b.terms.get(k) ?? 0n) !== ca) {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
// ---------------------------------------------------------------------------
|
|
814
|
+
// Higher-level helpers used by GCD + adapters
|
|
815
|
+
// ---------------------------------------------------------------------------
|
|
816
|
+
/**
|
|
817
|
+
* Leading term in lex order (highest exponents lexicographically).
|
|
818
|
+
* Returns the dense exponent vector (length nVars) and its coefficient.
|
|
819
|
+
*/
|
|
820
|
+
function leadTermLex(p, nVars) {
|
|
821
|
+
let bestExp = null;
|
|
822
|
+
let bestCoeff = 0n;
|
|
823
|
+
for (const [key, coeff] of p.terms.entries()) {
|
|
824
|
+
if (coeff === 0n) {
|
|
825
|
+
continue;
|
|
826
|
+
}
|
|
827
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
828
|
+
const dense = new Array(nVars).fill(0);
|
|
829
|
+
for (const [i, e] of exp.entries()) {
|
|
830
|
+
if (i >= 0 && i < nVars) {
|
|
831
|
+
dense[i] = e;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (!bestExp || compareDenseLex(dense, bestExp) > 0) {
|
|
835
|
+
bestExp = dense;
|
|
836
|
+
bestCoeff = coeff;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return bestExp ? { exp: bestExp, coeff: bestCoeff } : null;
|
|
840
|
+
}
|
|
841
|
+
// ---------------------------------------------------------------------------
|
|
842
|
+
// Exact division (Z) in lex order
|
|
843
|
+
// ---------------------------------------------------------------------------
|
|
844
|
+
/**
|
|
845
|
+
* Compute a conservative number of variables from the support of one or more polynomials.
|
|
846
|
+
* Returns maxVarIndex+1 across all terms (or 0 if all are zero).
|
|
847
|
+
*/
|
|
848
|
+
function mvNumVars(...polys) {
|
|
849
|
+
let max = -1;
|
|
850
|
+
for (const p of polys) {
|
|
851
|
+
for (const key of p.terms.keys()) {
|
|
852
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
853
|
+
for (const i of exp.keys()) {
|
|
854
|
+
if (i > max) {
|
|
855
|
+
max = i;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
return max + 1;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Exact division A/B in Z[x0..] using the canonical lex-leading-term algorithm.
|
|
864
|
+
* Returns null if division is not exact.
|
|
865
|
+
*/
|
|
866
|
+
function mvExactDiv(A, B) {
|
|
867
|
+
const nVars = mvNumVars(A, B);
|
|
868
|
+
return exactDivLex(A, B, nVars);
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Exact division by a monomial (single-term polynomial).
|
|
872
|
+
* Returns null if `m` is not a monomial or division is not exact.
|
|
873
|
+
*/
|
|
874
|
+
function mvExactDivByMonomial(p, m) {
|
|
875
|
+
if (m.terms.size !== 1) {
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
return mvExactDiv(p, m);
|
|
879
|
+
}
|
|
880
|
+
function monoDividesDense(a, b) {
|
|
881
|
+
const n = Math.max(a.length, b.length);
|
|
882
|
+
for (let i = 0; i < n; i++) {
|
|
883
|
+
if ((a[i] ?? 0) > (b[i] ?? 0)) {
|
|
884
|
+
return false;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
function monoSubDense(b, a) {
|
|
890
|
+
const n = Math.max(a.length, b.length);
|
|
891
|
+
const out = new Array(n).fill(0);
|
|
892
|
+
for (let i = 0; i < n; i++) {
|
|
893
|
+
out[i] = (b[i] ?? 0) - (a[i] ?? 0);
|
|
894
|
+
}
|
|
895
|
+
return out;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Exact division A/B in Z[x0..x{nVars-1}] assuming B divides A exactly.
|
|
899
|
+
* Uses lex order for leading terms. Returns null if division fails.
|
|
900
|
+
*/
|
|
901
|
+
function exactDivLex(A, B, nVars) {
|
|
902
|
+
const ltB = leadTermLex(B, nVars);
|
|
903
|
+
if (!ltB) {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
let R = A.clone();
|
|
907
|
+
R.trim();
|
|
908
|
+
const out = MultiPoly_1.MultiPoly.zero();
|
|
909
|
+
while (!R.isZero()) {
|
|
910
|
+
const ltR = leadTermLex(R, nVars);
|
|
911
|
+
if (!ltR) {
|
|
912
|
+
break;
|
|
913
|
+
}
|
|
914
|
+
if (!monoDividesDense(ltB.exp, ltR.exp)) {
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
const qExp = monoSubDense(ltR.exp, ltB.exp);
|
|
918
|
+
if (ltB.coeff === 0n) {
|
|
919
|
+
return null;
|
|
920
|
+
}
|
|
921
|
+
if (ltR.coeff % ltB.coeff !== 0n) {
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
const qCoeff = ltR.coeff / ltB.coeff;
|
|
925
|
+
// out += qCoeff * x^qExp
|
|
926
|
+
const qMono = MultiPoly_1.MultiPoly.monomial(qCoeff, qExp);
|
|
927
|
+
const out2 = addPoly(out, qMono);
|
|
928
|
+
out.terms = out2.terms;
|
|
929
|
+
// R -= (qCoeff * x^qExp) * B
|
|
930
|
+
const prod = mulPoly(qMono, B);
|
|
931
|
+
R = subPoly(R, prod);
|
|
932
|
+
}
|
|
933
|
+
out.trim();
|
|
934
|
+
return out;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Substitute a single variable (by index) with an integer value.
|
|
938
|
+
* The chosen variable's exponent is set to 0 in every term.
|
|
939
|
+
*/
|
|
940
|
+
function substituteVarIndex(p, varIndex, value) {
|
|
941
|
+
if (p.terms.size === 0) {
|
|
942
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
943
|
+
}
|
|
944
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
945
|
+
for (const [key, coeff0] of p.terms.entries()) {
|
|
946
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
947
|
+
const e = exp.get(varIndex) ?? 0;
|
|
948
|
+
let coeff = coeff0;
|
|
949
|
+
if (e !== 0) {
|
|
950
|
+
// Fast exponentiation for integer powers.
|
|
951
|
+
let base = value;
|
|
952
|
+
let pow = 1n;
|
|
953
|
+
let k = BigInt(e);
|
|
954
|
+
while (k > 0n) {
|
|
955
|
+
if (k & 1n) {
|
|
956
|
+
pow *= base;
|
|
957
|
+
}
|
|
958
|
+
base *= base;
|
|
959
|
+
k >>= 1n;
|
|
960
|
+
}
|
|
961
|
+
coeff *= pow;
|
|
962
|
+
exp.delete(varIndex);
|
|
963
|
+
}
|
|
964
|
+
const newKey = (0, MultiPoly_1.expToKey)(exp);
|
|
965
|
+
const prev = out.terms.get(newKey) ?? 0n;
|
|
966
|
+
const sum = prev + coeff;
|
|
967
|
+
if (sum === 0n) {
|
|
968
|
+
out.terms.delete(newKey);
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
out.terms.set(newKey, sum);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
out.trim();
|
|
975
|
+
return out;
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Remove a variable index from a polynomial by shifting indices > varIndex down.
|
|
979
|
+
* (Assumes the removed variable is no longer used, but handles exponents safely.)
|
|
980
|
+
*/
|
|
981
|
+
function removeVarIndex(p, varIndex) {
|
|
982
|
+
if (p.terms.size === 0) {
|
|
983
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
984
|
+
}
|
|
985
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
986
|
+
for (const [key, coeff] of p.terms.entries()) {
|
|
987
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
988
|
+
const newExp = new Map();
|
|
989
|
+
for (const [i, e] of exp.entries()) {
|
|
990
|
+
if (i === varIndex) {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
newExp.set(i > varIndex ? i - 1 : i, e);
|
|
994
|
+
}
|
|
995
|
+
const nk = (0, MultiPoly_1.expToKey)(newExp);
|
|
996
|
+
out.terms.set(nk, (out.terms.get(nk) ?? 0n) + coeff);
|
|
997
|
+
if (out.terms.get(nk) === 0n) {
|
|
998
|
+
out.terms.delete(nk);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
out.trim();
|
|
1002
|
+
return out;
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Add a variable index to a polynomial by shifting indices >= varIndex up.
|
|
1006
|
+
*/
|
|
1007
|
+
function addVarIndex(p, varIndex) {
|
|
1008
|
+
if (p.terms.size === 0) {
|
|
1009
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
1010
|
+
}
|
|
1011
|
+
const out = new MultiPoly_1.MultiPoly();
|
|
1012
|
+
for (const [key, coeff] of p.terms.entries()) {
|
|
1013
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1014
|
+
const newExp = new Map();
|
|
1015
|
+
for (const [i, e] of exp.entries()) {
|
|
1016
|
+
newExp.set(i >= varIndex ? i + 1 : i, e);
|
|
1017
|
+
}
|
|
1018
|
+
const nk = (0, MultiPoly_1.expToKey)(newExp);
|
|
1019
|
+
out.terms.set(nk, (out.terms.get(nk) ?? 0n) + coeff);
|
|
1020
|
+
if (out.terms.get(nk) === 0n) {
|
|
1021
|
+
out.terms.delete(nk);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
out.trim();
|
|
1025
|
+
return out;
|
|
1026
|
+
}
|
|
1027
|
+
// ---------------------------------------------------------------------------
|
|
1028
|
+
// MV ↔ Univariate view utilities
|
|
1029
|
+
// ---------------------------------------------------------------------------
|
|
1030
|
+
/** Convert univariate coefficient array (number, low→high) to MultiPoly in `varIndex`. */
|
|
1031
|
+
function fromUnivariate(coeffs, varIndex = 0) {
|
|
1032
|
+
const p = new MultiPoly_1.MultiPoly();
|
|
1033
|
+
for (let i = 0; i < coeffs.length; i++) {
|
|
1034
|
+
const c = coeffs[i];
|
|
1035
|
+
if (c === 0) {
|
|
1036
|
+
continue;
|
|
1037
|
+
}
|
|
1038
|
+
const exp = new Map();
|
|
1039
|
+
if (i > 0) {
|
|
1040
|
+
exp.set(varIndex, i);
|
|
1041
|
+
}
|
|
1042
|
+
p.terms.set((0, MultiPoly_1.expToKey)(exp), BigInt(c));
|
|
1043
|
+
}
|
|
1044
|
+
return p;
|
|
1045
|
+
}
|
|
1046
|
+
const MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
1047
|
+
function bigintToSafeNumber(b, context) {
|
|
1048
|
+
if (b > MAX_SAFE_BIGINT || b < -MAX_SAFE_BIGINT) {
|
|
1049
|
+
throw new Error(`${context}: coefficient ${b.toString()} exceeds Number.MAX_SAFE_INTEGER`);
|
|
1050
|
+
}
|
|
1051
|
+
return Number(b);
|
|
1052
|
+
}
|
|
1053
|
+
function trimTrailingZeros(coeffs) {
|
|
1054
|
+
let i = coeffs.length - 1;
|
|
1055
|
+
while (i > 0 && coeffs[i] === 0) {
|
|
1056
|
+
i--;
|
|
1057
|
+
}
|
|
1058
|
+
return coeffs.slice(0, i + 1);
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Convert MultiPoly to univariate coefficient array (numbers) if it only has one variable.
|
|
1062
|
+
* Returns null if polynomial has more than one variable.
|
|
1063
|
+
*/
|
|
1064
|
+
function toUnivariate(p, varIndex = 0) {
|
|
1065
|
+
// Check that only varIndex appears
|
|
1066
|
+
for (const key of p.terms.keys()) {
|
|
1067
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1068
|
+
for (const v of exp.keys()) {
|
|
1069
|
+
if (v !== varIndex) {
|
|
1070
|
+
return null;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
const deg = p.degree(varIndex);
|
|
1075
|
+
if (deg < 0) {
|
|
1076
|
+
return [0];
|
|
1077
|
+
}
|
|
1078
|
+
const result = new Array(deg + 1).fill(0);
|
|
1079
|
+
for (const [key, coeff] of p.terms) {
|
|
1080
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1081
|
+
const d = exp.get(varIndex) ?? 0;
|
|
1082
|
+
result[d] = bigintToSafeNumber(coeff, 'toUnivariate');
|
|
1083
|
+
}
|
|
1084
|
+
return trimTrailingZeros(result);
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* View multivariate polynomial as univariate in varIndex with polynomial coefficients.
|
|
1088
|
+
* Returns array of [coefficient polynomial, degree] pairs sorted by degree.
|
|
1089
|
+
*/
|
|
1090
|
+
function viewAsUnivariate(p, varIndex) {
|
|
1091
|
+
const coeffMap = new Map();
|
|
1092
|
+
for (const [key, coeff] of p.terms) {
|
|
1093
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1094
|
+
const deg = exp.get(varIndex) ?? 0;
|
|
1095
|
+
// Build coefficient without varIndex
|
|
1096
|
+
const newExp = new Map(exp);
|
|
1097
|
+
newExp.delete(varIndex);
|
|
1098
|
+
const newKey = (0, MultiPoly_1.expToKey)(newExp);
|
|
1099
|
+
let poly = coeffMap.get(deg);
|
|
1100
|
+
if (poly === undefined) {
|
|
1101
|
+
poly = MultiPoly_1.MultiPoly.zero();
|
|
1102
|
+
coeffMap.set(deg, poly);
|
|
1103
|
+
}
|
|
1104
|
+
const existing = poly.terms.get(newKey) ?? 0n;
|
|
1105
|
+
const sum = existing + coeff;
|
|
1106
|
+
if (sum === 0n) {
|
|
1107
|
+
poly.terms.delete(newKey);
|
|
1108
|
+
}
|
|
1109
|
+
else {
|
|
1110
|
+
poly.terms.set(newKey, sum);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
const result = [];
|
|
1114
|
+
for (const [deg, poly] of coeffMap) {
|
|
1115
|
+
if (!poly.isZero()) {
|
|
1116
|
+
result.push([poly, deg]);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
result.sort((a, b) => a[1] - b[1]);
|
|
1120
|
+
return result;
|
|
1121
|
+
}
|
|
1122
|
+
/** Reconstruct polynomial from univariate view. */
|
|
1123
|
+
function fromUnivariateView(terms, varIndex) {
|
|
1124
|
+
const result = MultiPoly_1.MultiPoly.zero();
|
|
1125
|
+
for (const [coeff, deg] of terms) {
|
|
1126
|
+
for (const [key, c] of coeff.terms) {
|
|
1127
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1128
|
+
if (deg > 0) {
|
|
1129
|
+
exp.set(varIndex, (exp.get(varIndex) ?? 0) + deg);
|
|
1130
|
+
}
|
|
1131
|
+
const newKey = (0, MultiPoly_1.expToKey)(exp);
|
|
1132
|
+
const existing = result.terms.get(newKey) ?? 0n;
|
|
1133
|
+
result.terms.set(newKey, existing + c);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
result.trim();
|
|
1137
|
+
return result;
|
|
1138
|
+
}
|
|
1139
|
+
// ============================================================================
|
|
1140
|
+
// Shared multivariate division / content helpers
|
|
1141
|
+
// ============================================================================
|
|
1142
|
+
function mvPrimitiveNormalized(p) {
|
|
1143
|
+
if (p.isZero()) {
|
|
1144
|
+
return MultiPoly_1.MultiPoly.zero();
|
|
1145
|
+
}
|
|
1146
|
+
return mvNormalizePrimitiveSignLex(p).primitive;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Pseudo-division of multivariate polynomials viewed as univariate in `varIndex`.
|
|
1150
|
+
* Returns [q, r] such that lc(b)^k * a = q*b + r with deg(r) < deg(b) in `varIndex`.
|
|
1151
|
+
*/
|
|
1152
|
+
function pseudoDivide(a, b, varIndex) {
|
|
1153
|
+
if (b.isZero()) {
|
|
1154
|
+
throw new Error('Division by zero');
|
|
1155
|
+
}
|
|
1156
|
+
const degB = b.degree(varIndex);
|
|
1157
|
+
const degA = a.degree(varIndex);
|
|
1158
|
+
if (degA < degB) {
|
|
1159
|
+
return [MultiPoly_1.MultiPoly.zero(), a.clone()];
|
|
1160
|
+
}
|
|
1161
|
+
const lcB = b.leadingCoeff(varIndex);
|
|
1162
|
+
let q = MultiPoly_1.MultiPoly.zero();
|
|
1163
|
+
let r = a.clone();
|
|
1164
|
+
const delta = degA - degB + 1;
|
|
1165
|
+
let e = delta;
|
|
1166
|
+
while (!r.isZero() && r.degree(varIndex) >= degB) {
|
|
1167
|
+
const degR = r.degree(varIndex);
|
|
1168
|
+
const lcR = r.leadingCoeff(varIndex);
|
|
1169
|
+
const shift = degR - degB;
|
|
1170
|
+
const s = new MultiPoly_1.MultiPoly();
|
|
1171
|
+
for (const [key, coeff] of lcR.terms) {
|
|
1172
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1173
|
+
if (shift > 0) {
|
|
1174
|
+
exp.set(varIndex, (exp.get(varIndex) ?? 0) + shift);
|
|
1175
|
+
}
|
|
1176
|
+
s.terms.set((0, MultiPoly_1.expToKey)(exp), coeff);
|
|
1177
|
+
}
|
|
1178
|
+
q = addPoly(mulPoly(q, lcB), s);
|
|
1179
|
+
r = subPoly(mulPoly(r, lcB), mulPoly(s, b));
|
|
1180
|
+
e--;
|
|
1181
|
+
}
|
|
1182
|
+
let lcBPower = MultiPoly_1.MultiPoly.constant(1n);
|
|
1183
|
+
for (let i = 0; i < e; i++) {
|
|
1184
|
+
lcBPower = mulPoly(lcBPower, lcB);
|
|
1185
|
+
}
|
|
1186
|
+
q = mulPoly(q, lcBPower);
|
|
1187
|
+
r = mulPoly(r, lcBPower);
|
|
1188
|
+
return [q, r];
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Primitive GCD for multivariate polynomials, computed by viewing the inputs
|
|
1192
|
+
* as univariate in `varIndex` with multivariate coefficients.
|
|
1193
|
+
*/
|
|
1194
|
+
function multiPolyGCD(a, b, varIndex) {
|
|
1195
|
+
if (a.isZero()) {
|
|
1196
|
+
return b.isZero() ? MultiPoly_1.MultiPoly.constant(1n) : mvPrimitiveNormalized(b);
|
|
1197
|
+
}
|
|
1198
|
+
if (b.isZero()) {
|
|
1199
|
+
return mvPrimitiveNormalized(a);
|
|
1200
|
+
}
|
|
1201
|
+
let aPrim = mvPrimitiveNormalized(a);
|
|
1202
|
+
let bPrim = mvPrimitiveNormalized(b);
|
|
1203
|
+
if (aPrim.degree(varIndex) < bPrim.degree(varIndex)) {
|
|
1204
|
+
[aPrim, bPrim] = [bPrim, aPrim];
|
|
1205
|
+
}
|
|
1206
|
+
while (!bPrim.isZero()) {
|
|
1207
|
+
const [, r] = pseudoDivide(aPrim, bPrim, varIndex);
|
|
1208
|
+
if (r.isZero()) {
|
|
1209
|
+
break;
|
|
1210
|
+
}
|
|
1211
|
+
aPrim = bPrim;
|
|
1212
|
+
bPrim = mvPrimitiveNormalized(r);
|
|
1213
|
+
}
|
|
1214
|
+
return mvPrimitiveNormalized(bPrim);
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Content of a polynomial with respect to one variable, i.e. the gcd of the
|
|
1218
|
+
* coefficient-polynomials in the univariate view.
|
|
1219
|
+
*/
|
|
1220
|
+
function mvContentInVar(p, varIndex) {
|
|
1221
|
+
const terms = viewAsUnivariate(p, varIndex);
|
|
1222
|
+
if (terms.length === 0) {
|
|
1223
|
+
return MultiPoly_1.MultiPoly.constant(1n);
|
|
1224
|
+
}
|
|
1225
|
+
if (terms.length === 1) {
|
|
1226
|
+
return mvPrimitiveNormalized(terms[0][0]);
|
|
1227
|
+
}
|
|
1228
|
+
let g = terms[0][0];
|
|
1229
|
+
for (let i = 1; i < terms.length; i++) {
|
|
1230
|
+
const vars = new Set([...g.variables(), ...terms[i][0].variables()]);
|
|
1231
|
+
if (vars.size === 0) {
|
|
1232
|
+
g = MultiPoly_1.MultiPoly.constant((0, arith_1.gcd)(g.constantTerm(), terms[i][0].constantTerm()));
|
|
1233
|
+
}
|
|
1234
|
+
else {
|
|
1235
|
+
const gcdVar = Math.min(...vars);
|
|
1236
|
+
g = multiPolyGCD(g, terms[i][0], gcdVar);
|
|
1237
|
+
}
|
|
1238
|
+
if (g.isConstant() && g.constantTerm() === 1n) {
|
|
1239
|
+
return MultiPoly_1.MultiPoly.constant(1n);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
return mvPrimitiveNormalized(g);
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Primitive part of a polynomial relative to the univariate view in `varIndex`.
|
|
1246
|
+
*/
|
|
1247
|
+
function primitivePart(p, varIndex) {
|
|
1248
|
+
const cont = mvContentInVar(p, varIndex);
|
|
1249
|
+
if (cont.isConstant() && cont.constantTerm() === 1n) {
|
|
1250
|
+
return p;
|
|
1251
|
+
}
|
|
1252
|
+
const terms = viewAsUnivariate(p, varIndex);
|
|
1253
|
+
const newTerms = [];
|
|
1254
|
+
for (const [coeff, deg] of terms) {
|
|
1255
|
+
const vars = cont.variables();
|
|
1256
|
+
if (vars.size === 0) {
|
|
1257
|
+
const c = cont.constantTerm();
|
|
1258
|
+
const newCoeff = new MultiPoly_1.MultiPoly();
|
|
1259
|
+
for (const [key, val] of coeff.terms) {
|
|
1260
|
+
newCoeff.terms.set(key, val / c);
|
|
1261
|
+
}
|
|
1262
|
+
newTerms.push([newCoeff, deg]);
|
|
1263
|
+
}
|
|
1264
|
+
else {
|
|
1265
|
+
const divVar = Math.min(...vars);
|
|
1266
|
+
const [q] = pseudoDivide(coeff, cont, divVar);
|
|
1267
|
+
newTerms.push([mvPrimitiveNormalized(q), deg]);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return fromUnivariateView(newTerms, varIndex);
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Extract quadratic coefficients of `p` viewed as `A*v^2 + B*v + C`.
|
|
1274
|
+
* Terms with degree > 2 in `v` are silently ignored.
|
|
1275
|
+
*/
|
|
1276
|
+
function quadraticCoeffsInVar(p, v) {
|
|
1277
|
+
const A = new MultiPoly_1.MultiPoly();
|
|
1278
|
+
const B = new MultiPoly_1.MultiPoly();
|
|
1279
|
+
const C = new MultiPoly_1.MultiPoly();
|
|
1280
|
+
for (const [key, coeff] of p.terms) {
|
|
1281
|
+
const exp = (0, MultiPoly_1.keyToExp)(key);
|
|
1282
|
+
const e = exp.get(v) ?? 0;
|
|
1283
|
+
exp.delete(v);
|
|
1284
|
+
const k = (0, MultiPoly_1.expToKey)(exp);
|
|
1285
|
+
if (e === 2) {
|
|
1286
|
+
A.terms.set(k, (A.terms.get(k) ?? 0n) + coeff);
|
|
1287
|
+
}
|
|
1288
|
+
else if (e === 1) {
|
|
1289
|
+
B.terms.set(k, (B.terms.get(k) ?? 0n) + coeff);
|
|
1290
|
+
}
|
|
1291
|
+
else if (e === 0) {
|
|
1292
|
+
C.terms.set(k, (C.terms.get(k) ?? 0n) + coeff);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
A.trim();
|
|
1296
|
+
B.trim();
|
|
1297
|
+
C.trim();
|
|
1298
|
+
return { A, B, C };
|
|
1299
|
+
}
|