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.
Files changed (341) hide show
  1. package/LICENSE.md +184 -0
  2. package/README.md +293 -312
  3. package/dist/bundle.js +2 -0
  4. package/dist/bundle.js.LICENSE.txt +7 -0
  5. package/dist/parser.js +2 -0
  6. package/dist/parser.js.LICENSE.txt +7 -0
  7. package/docs-data/parser-functions.json +1960 -0
  8. package/index.d.ts +10 -426
  9. package/output/algebra/adapters.d.ts +33 -0
  10. package/output/algebra/adapters.js +109 -0
  11. package/output/algebra/algorithms/arith.d.ts +84 -0
  12. package/output/algebra/algorithms/arith.js +323 -0
  13. package/output/algebra/algorithms/factor.d.ts +3 -0
  14. package/output/algebra/algorithms/factor.js +5 -0
  15. package/output/algebra/algorithms/factorMultivariate.d.ts +23 -0
  16. package/output/algebra/algorithms/factorMultivariate.js +2393 -0
  17. package/output/algebra/algorithms/factorUnivariate.d.ts +72 -0
  18. package/output/algebra/algorithms/factorUnivariate.js +1072 -0
  19. package/output/algebra/algorithms/gcd.d.ts +22 -0
  20. package/output/algebra/algorithms/gcd.js +690 -0
  21. package/output/algebra/algorithms/groebnerBase.d.ts +157 -0
  22. package/output/algebra/algorithms/groebnerBase.js +1166 -0
  23. package/output/algebra/algorithms/multiPoly/MultiPoly.d.ts +137 -0
  24. package/output/algebra/algorithms/multiPoly/MultiPoly.js +346 -0
  25. package/output/algebra/algorithms/poly.d.ts +228 -0
  26. package/output/algebra/algorithms/poly.js +1299 -0
  27. package/output/algebra/algorithms/rational.d.ts +17 -0
  28. package/output/algebra/algorithms/rational.js +115 -0
  29. package/output/algebra/factor/factor.d.ts +62 -0
  30. package/output/algebra/factor/factor.js +158 -0
  31. package/output/algebra/gcd/gcd.d.ts +29 -0
  32. package/output/algebra/gcd/gcd.js +141 -0
  33. package/output/algebra/groebner.d.ts +21 -0
  34. package/output/algebra/groebner.js +42 -0
  35. package/output/algebra/partfrac.d.ts +19 -0
  36. package/output/algebra/partfrac.js +398 -0
  37. package/output/algebra/polynomialize.d.ts +20 -0
  38. package/output/algebra/polynomialize.js +24 -0
  39. package/output/algebra/simplify/complexsimp.d.ts +7 -0
  40. package/output/algebra/simplify/complexsimp.js +24 -0
  41. package/output/algebra/simplify/factorCommon.d.ts +13 -0
  42. package/output/algebra/simplify/factorCommon.js +136 -0
  43. package/output/algebra/simplify/funcsimp.d.ts +26 -0
  44. package/output/algebra/simplify/funcsimp.js +633 -0
  45. package/output/algebra/simplify/invtrigrewrite.d.ts +10 -0
  46. package/output/algebra/simplify/invtrigrewrite.js +96 -0
  47. package/output/algebra/simplify/ratsimp.d.ts +21 -0
  48. package/output/algebra/simplify/ratsimp.js +140 -0
  49. package/output/algebra/simplify/simplify.d.ts +25 -0
  50. package/output/algebra/simplify/simplify.js +228 -0
  51. package/output/algebra/simplify/trigreduce.d.ts +38 -0
  52. package/output/algebra/simplify/trigreduce.js +424 -0
  53. package/output/algebra/simplify/trigrewrite.d.ts +17 -0
  54. package/output/algebra/simplify/trigrewrite.js +156 -0
  55. package/output/algebra/simplify/trigsimp.d.ts +11 -0
  56. package/output/algebra/simplify/trigsimp.js +369 -0
  57. package/output/algebra/simplify/utils.d.ts +32 -0
  58. package/output/algebra/simplify/utils.js +56 -0
  59. package/output/algebra/utils.d.ts +32 -0
  60. package/output/algebra/utils.js +48 -0
  61. package/output/api/advanced.d.ts +7 -0
  62. package/output/api/advanced.js +18 -0
  63. package/output/api/algebra.d.ts +17 -0
  64. package/output/api/algebra.js +32 -0
  65. package/output/api/assumptions.d.ts +4 -0
  66. package/output/api/assumptions.js +11 -0
  67. package/output/api/calculus.d.ts +9 -0
  68. package/output/api/calculus.js +21 -0
  69. package/output/api/core.d.ts +17 -0
  70. package/output/api/core.js +41 -0
  71. package/output/api/debug.d.ts +16 -0
  72. package/output/api/debug.js +23 -0
  73. package/output/api/parser.d.ts +85 -0
  74. package/output/api/parser.js +16 -0
  75. package/output/api/solve.d.ts +10 -0
  76. package/output/api/solve.js +16 -0
  77. package/output/api/structures.d.ts +10 -0
  78. package/output/api/structures.js +22 -0
  79. package/output/calculus/derivative/diff.d.ts +30 -0
  80. package/output/calculus/derivative/diff.js +238 -0
  81. package/output/calculus/fresnel.d.ts +16 -0
  82. package/output/calculus/fresnel.js +39 -0
  83. package/output/calculus/integrate/byParts.d.ts +18 -0
  84. package/output/calculus/integrate/byParts.js +339 -0
  85. package/output/calculus/integrate/bySubstitution.d.ts +135 -0
  86. package/output/calculus/integrate/bySubstitution.js +411 -0
  87. package/output/calculus/integrate/integrate.d.ts +38 -0
  88. package/output/calculus/integrate/integrate.js +652 -0
  89. package/output/calculus/integrate/integrationTable.d.ts +2 -0
  90. package/output/calculus/integrate/integrationTable.js +914 -0
  91. package/output/calculus/integrate/utils.d.ts +28 -0
  92. package/output/calculus/integrate/utils.js +96 -0
  93. package/output/calculus/laplace/ilaplace.d.ts +31 -0
  94. package/output/calculus/laplace/ilaplace.js +192 -0
  95. package/output/calculus/laplace/ilaplaceTable.d.ts +2 -0
  96. package/output/calculus/laplace/ilaplaceTable.js +200 -0
  97. package/output/calculus/laplace/laplace.d.ts +22 -0
  98. package/output/calculus/laplace/laplace.js +109 -0
  99. package/output/calculus/laplace/laplaceTable.d.ts +2 -0
  100. package/output/calculus/laplace/laplaceTable.js +187 -0
  101. package/output/calculus/limit/limit.d.ts +35 -0
  102. package/output/calculus/limit/limit.js +1183 -0
  103. package/output/calculus/limit/limitsTable.d.ts +2 -0
  104. package/output/calculus/limit/limitsTable.js +7 -0
  105. package/output/core/Settings.d.ts +32 -0
  106. package/output/core/Settings.js +68 -0
  107. package/output/core/adapters.d.ts +18 -0
  108. package/output/core/adapters.js +40 -0
  109. package/output/core/classes/assumption/Assumption.d.ts +218 -0
  110. package/output/core/classes/assumption/Assumption.js +605 -0
  111. package/output/core/classes/assumption/assertiveFunctions.d.ts +6 -0
  112. package/output/core/classes/assumption/assertiveFunctions.js +64 -0
  113. package/output/core/classes/assumption/assume.d.ts +90 -0
  114. package/output/core/classes/assumption/assume.js +145 -0
  115. package/output/core/classes/collection/Collection.d.ts +107 -0
  116. package/output/core/classes/collection/Collection.js +231 -0
  117. package/output/core/classes/complex/Complex.d.ts +99 -0
  118. package/output/core/classes/complex/Complex.js +135 -0
  119. package/output/core/classes/decimalSet/DecimalSet.d.ts +226 -0
  120. package/output/core/classes/decimalSet/DecimalSet.js +453 -0
  121. package/output/core/classes/dictionary/Dictionary.d.ts +102 -0
  122. package/output/core/classes/dictionary/Dictionary.js +213 -0
  123. package/output/core/classes/equation/Equation.d.ts +256 -0
  124. package/output/core/classes/equation/Equation.js +350 -0
  125. package/output/core/classes/expression/CoeffObject.d.ts +100 -0
  126. package/output/core/classes/expression/CoeffObject.js +198 -0
  127. package/output/core/classes/expression/Expression.d.ts +1674 -0
  128. package/output/core/classes/expression/Expression.js +2332 -0
  129. package/output/core/classes/expression/analysis.d.ts +25 -0
  130. package/output/core/classes/expression/analysis.js +218 -0
  131. package/output/core/classes/expression/collect.d.ts +9 -0
  132. package/output/core/classes/expression/collect.js +49 -0
  133. package/output/core/classes/expression/format.d.ts +45 -0
  134. package/output/core/classes/expression/format.js +217 -0
  135. package/output/core/classes/expression/products.d.ts +23 -0
  136. package/output/core/classes/expression/products.js +115 -0
  137. package/output/core/classes/expression/shortcuts.d.ts +35 -0
  138. package/output/core/classes/expression/shortcuts.js +129 -0
  139. package/output/core/classes/expression/traversal.d.ts +31 -0
  140. package/output/core/classes/expression/traversal.js +216 -0
  141. package/output/core/classes/expression/trig.d.ts +25 -0
  142. package/output/core/classes/expression/trig.js +40 -0
  143. package/output/core/classes/expression/utils.d.ts +52 -0
  144. package/output/core/classes/expression/utils.js +189 -0
  145. package/output/core/classes/lookupTable/LookupTable.d.ts +12 -0
  146. package/output/core/classes/lookupTable/LookupTable.js +55 -0
  147. package/output/core/classes/matrix/Matrix.d.ts +227 -0
  148. package/output/core/classes/matrix/Matrix.js +889 -0
  149. package/output/core/classes/matrix/Sylvester.d.ts +11 -0
  150. package/output/core/classes/matrix/Sylvester.js +54 -0
  151. package/output/core/classes/matrix/functions.d.ts +26 -0
  152. package/output/core/classes/matrix/functions.js +52 -0
  153. package/output/core/classes/matrix/utils.d.ts +9 -0
  154. package/output/core/classes/matrix/utils.js +22 -0
  155. package/output/core/classes/parser/Parser.d.ts +480 -0
  156. package/output/core/classes/parser/Parser.js +1812 -0
  157. package/output/core/classes/parser/Token.d.ts +58 -0
  158. package/output/core/classes/parser/Token.js +137 -0
  159. package/output/core/classes/parser/constants.d.ts +160 -0
  160. package/output/core/classes/parser/constants.js +227 -0
  161. package/output/core/classes/parser/helpers.d.ts +21 -0
  162. package/output/core/classes/parser/helpers.js +42 -0
  163. package/output/core/classes/parser/operations/add.d.ts +15 -0
  164. package/output/core/classes/parser/operations/add.js +238 -0
  165. package/output/core/classes/parser/operations/comma.d.ts +7 -0
  166. package/output/core/classes/parser/operations/comma.js +11 -0
  167. package/output/core/classes/parser/operations/compare.d.ts +21 -0
  168. package/output/core/classes/parser/operations/compare.js +461 -0
  169. package/output/core/classes/parser/operations/divide.d.ts +2 -0
  170. package/output/core/classes/parser/operations/divide.js +72 -0
  171. package/output/core/classes/parser/operations/functions.d.ts +46 -0
  172. package/output/core/classes/parser/operations/functions.js +430 -0
  173. package/output/core/classes/parser/operations/multiply.d.ts +11 -0
  174. package/output/core/classes/parser/operations/multiply.js +321 -0
  175. package/output/core/classes/parser/operations/power.d.ts +48 -0
  176. package/output/core/classes/parser/operations/power.js +673 -0
  177. package/output/core/classes/parser/operations/subtract.d.ts +3 -0
  178. package/output/core/classes/parser/operations/subtract.js +35 -0
  179. package/output/core/classes/parser/preprocess.d.ts +14 -0
  180. package/output/core/classes/parser/preprocess.js +259 -0
  181. package/output/core/classes/parser/scripting/controlFlow.d.ts +121 -0
  182. package/output/core/classes/parser/scripting/controlFlow.js +355 -0
  183. package/output/core/classes/parser/scripting/evaluate.d.ts +10 -0
  184. package/output/core/classes/parser/scripting/evaluate.js +112 -0
  185. package/output/core/classes/parser/scripting/functions.d.ts +14 -0
  186. package/output/core/classes/parser/scripting/functions.js +59 -0
  187. package/output/core/classes/parser/scripting/scope.d.ts +35 -0
  188. package/output/core/classes/parser/scripting/scope.js +155 -0
  189. package/output/core/classes/parser/types.d.ts +125 -0
  190. package/output/core/classes/parser/types.js +2 -0
  191. package/output/core/classes/parser/wrappers/IndexedReference.d.ts +31 -0
  192. package/output/core/classes/parser/wrappers/IndexedReference.js +68 -0
  193. package/output/core/classes/parser/wrappers/KeyValuePair.d.ts +24 -0
  194. package/output/core/classes/parser/wrappers/KeyValuePair.js +51 -0
  195. package/output/core/classes/polynomial/Polynomial.d.ts +500 -0
  196. package/output/core/classes/polynomial/Polynomial.js +1149 -0
  197. package/output/core/classes/polynomial/Term.d.ts +222 -0
  198. package/output/core/classes/polynomial/Term.js +430 -0
  199. package/output/core/classes/polynomial/functions.d.ts +69 -0
  200. package/output/core/classes/polynomial/functions.js +126 -0
  201. package/output/core/classes/polynomial/utils.d.ts +62 -0
  202. package/output/core/classes/polynomial/utils.js +206 -0
  203. package/output/core/classes/rational/Rational.d.ts +504 -0
  204. package/output/core/classes/rational/Rational.js +779 -0
  205. package/output/core/classes/seq/SEQ.d.ts +13 -0
  206. package/output/core/classes/seq/SEQ.js +137 -0
  207. package/output/core/classes/valuesSet/ValuesSet.d.ts +179 -0
  208. package/output/core/classes/valuesSet/ValuesSet.js +381 -0
  209. package/output/core/classes/vector/Vector.d.ts +222 -0
  210. package/output/core/classes/vector/Vector.js +497 -0
  211. package/output/core/classes/vector/functions.d.ts +28 -0
  212. package/output/core/classes/vector/functions.js +47 -0
  213. package/output/core/common/classes/MathematicalAggregate.d.ts +53 -0
  214. package/output/core/common/classes/MathematicalAggregate.js +140 -0
  215. package/output/core/common/classes/Scope.d.ts +62 -0
  216. package/output/core/common/classes/Scope.js +122 -0
  217. package/output/core/common/classes/StructuredEntity.d.ts +55 -0
  218. package/output/core/common/classes/StructuredEntity.js +151 -0
  219. package/output/core/common/common.d.ts +63 -0
  220. package/output/core/common/common.js +279 -0
  221. package/output/core/common/functions/functions.d.ts +14 -0
  222. package/output/core/common/functions/functions.js +33 -0
  223. package/output/core/common/functions/structuredEntityUtils.d.ts +27 -0
  224. package/output/core/common/functions/structuredEntityUtils.js +40 -0
  225. package/output/core/converters/BaseConverter.d.ts +97 -0
  226. package/output/core/converters/BaseConverter.js +405 -0
  227. package/output/core/converters/Converter.d.ts +111 -0
  228. package/output/core/converters/Converter.js +802 -0
  229. package/output/core/converters/Pattern.d.ts +71 -0
  230. package/output/core/converters/Pattern.js +302 -0
  231. package/output/core/dispatch.d.ts +34 -0
  232. package/output/core/dispatch.js +304 -0
  233. package/output/core/errors.d.ts +531 -0
  234. package/output/core/errors.js +621 -0
  235. package/output/core/functions/bigint/bigint.d.ts +121 -0
  236. package/output/core/functions/bigint/bigint.js +392 -0
  237. package/output/core/functions/bigint/primeFactor.d.ts +49 -0
  238. package/output/core/functions/bigint/primeFactor.js +267 -0
  239. package/output/core/functions/bigint/primes.d.ts +1 -0
  240. package/output/core/functions/bigint/primes.js +11 -0
  241. package/output/core/functions/build/definitions.d.ts +12 -0
  242. package/output/core/functions/build/definitions.js +133 -0
  243. package/output/core/functions/build/index.d.ts +32 -0
  244. package/output/core/functions/build/index.js +136 -0
  245. package/output/core/functions/complex.d.ts +90 -0
  246. package/output/core/functions/complex.js +482 -0
  247. package/output/core/functions/decimal.d.ts +24 -0
  248. package/output/core/functions/decimal.js +664 -0
  249. package/output/core/functions/expand/expand.d.ts +42 -0
  250. package/output/core/functions/expand/expand.js +376 -0
  251. package/output/core/functions/fresnelNumeric.d.ts +12 -0
  252. package/output/core/functions/fresnelNumeric.js +123 -0
  253. package/output/core/functions/numeric.d.ts +140 -0
  254. package/output/core/functions/numeric.js +790 -0
  255. package/output/core/functions/rationalNormalization.d.ts +11 -0
  256. package/output/core/functions/rationalNormalization.js +117 -0
  257. package/output/core/functions/setFunction.d.ts +19 -0
  258. package/output/core/functions/setFunction.js +75 -0
  259. package/output/core/functions/string.d.ts +26 -0
  260. package/output/core/functions/string.js +101 -0
  261. package/output/core/functions/subst.d.ts +90 -0
  262. package/output/core/functions/subst.js +498 -0
  263. package/output/core/functions/utils.d.ts +24 -0
  264. package/output/core/functions/utils.js +51 -0
  265. package/output/core/types.d.ts +48 -0
  266. package/output/core/types.js +2 -0
  267. package/output/index.d.ts +339 -0
  268. package/output/index.js +715 -0
  269. package/output/math/defint/defintDecimal.d.ts +37 -0
  270. package/output/math/defint/defintDecimal.js +320 -0
  271. package/output/math/defint/defintNative.d.ts +57 -0
  272. package/output/math/defint/defintNative.js +292 -0
  273. package/output/math/geometry.d.ts +8 -0
  274. package/output/math/geometry.js +32 -0
  275. package/output/math/math.d.ts +655 -0
  276. package/output/math/math.js +1811 -0
  277. package/output/math/trig.d.ts +518 -0
  278. package/output/math/trig.js +1444 -0
  279. package/output/math/trunc.d.ts +19 -0
  280. package/output/math/trunc.js +36 -0
  281. package/output/math/utils.d.ts +60 -0
  282. package/output/math/utils.js +180 -0
  283. package/output/solve/classes/DecimalMatrix.d.ts +17 -0
  284. package/output/solve/classes/DecimalMatrix.js +86 -0
  285. package/output/solve/classes/FunctionSolver.d.ts +135 -0
  286. package/output/solve/classes/FunctionSolver.js +433 -0
  287. package/output/solve/classes/MultivariateSolver.d.ts +84 -0
  288. package/output/solve/classes/MultivariateSolver.js +240 -0
  289. package/output/solve/classes/PolynomialSolver.d.ts +85 -0
  290. package/output/solve/classes/PolynomialSolver.js +292 -0
  291. package/output/solve/classes/SolutionSet.d.ts +153 -0
  292. package/output/solve/classes/SolutionSet.js +357 -0
  293. package/output/solve/classes/Solver.d.ts +17 -0
  294. package/output/solve/classes/Solver.js +132 -0
  295. package/output/solve/classes/SymbolicSolver.d.ts +74 -0
  296. package/output/solve/classes/SymbolicSolver.js +601 -0
  297. package/output/solve/linsolve.d.ts +51 -0
  298. package/output/solve/linsolve.js +225 -0
  299. package/output/solve/solve.d.ts +34 -0
  300. package/output/solve/solve.js +260 -0
  301. package/output/solve/solveSystem.d.ts +31 -0
  302. package/output/solve/solveSystem.js +290 -0
  303. package/output/solve/utils.d.ts +9 -0
  304. package/output/solve/utils.js +62 -0
  305. package/output/utils/array.d.ts +42 -0
  306. package/output/utils/array.js +98 -0
  307. package/output/utils/debug.d.ts +131 -0
  308. package/output/utils/debug.js +295 -0
  309. package/output/utils/decimal.d.ts +3 -0
  310. package/output/utils/decimal.js +16 -0
  311. package/output/utils/numeric.d.ts +14 -0
  312. package/output/utils/numeric.js +51 -0
  313. package/output/utils/object.d.ts +26 -0
  314. package/output/utils/object.js +56 -0
  315. package/package.json +213 -57
  316. package/.travis.yml +0 -3
  317. package/Algebra.js +0 -4568
  318. package/BREAKING_CHANGES.md +0 -5
  319. package/CODE_OF_CONDUCT.md +0 -46
  320. package/CONTRIBUTING.md +0 -14
  321. package/Calculus.js +0 -2675
  322. package/Extra.js +0 -622
  323. package/Solve.js +0 -1783
  324. package/all.js +0 -16
  325. package/all.min.js +0 -1
  326. package/gulpfile.js +0 -16
  327. package/index.html +0 -158
  328. package/license.txt +0 -19
  329. package/nerdamer.core.js +0 -12510
  330. package/spec/LaTeX.spec.js +0 -302
  331. package/spec/TeXConvert.spec.js +0 -8
  332. package/spec/algebra.spec.js +0 -287
  333. package/spec/basic_parser.spec.js +0 -134
  334. package/spec/build.spec.js +0 -131
  335. package/spec/calculus.spec.js +0 -183
  336. package/spec/core.spec.js +0 -2970
  337. package/spec/extra.spec.js +0 -54
  338. package/spec/solve.spec.js +0 -126
  339. package/spec/support/jasmine.json +0 -11
  340. package/spec/support/utils.js +0 -42
  341. package/spec/text.spec.js +0 -132
@@ -0,0 +1,1072 @@
1
+ "use strict";
2
+ /**
3
+ * @module factor_univariate
4
+ *
5
+ * Exact univariate polynomial factorization over Z[x].
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.factorPolynomialBig = factorPolynomialBig;
9
+ exports.factorPolynomial = factorPolynomial;
10
+ const arith_1 = require("./arith");
11
+ const poly_1 = require("./poly");
12
+ const MAX_DISTINCT_DEGREE_ITERATIONS = 64n;
13
+ const BASE_PRIME_BUDGET = 32;
14
+ const PRIME_BUDGET_DEGREE_DIVISOR = 4;
15
+ const PRIME_BUDGET_BIT_DIVISOR = 64;
16
+ const MAX_PRIME_BUDGET = 256;
17
+ const DEFAULT_MIN_FACTOR_PRIME = 3;
18
+ function sqrtExactBigint(n) {
19
+ if (n < 0n) {
20
+ return null;
21
+ }
22
+ const r = (0, arith_1.bigIntSqrt)(n);
23
+ return r * r === n ? r : null;
24
+ }
25
+ function degZPoly(f) {
26
+ const t = (0, poly_1.zTrim)(f);
27
+ if (t.length === 1 && t[0] === 0n) {
28
+ return -1;
29
+ }
30
+ return t.length - 1;
31
+ }
32
+ // ============================================================================
33
+ // MOD p ARITHMETIC (BigInt GF(p))
34
+ // ============================================================================
35
+ // We represent F_p[x] polynomials with the same coefficient array type as ZPoly.
36
+ // The only difference is that coefficients are interpreted modulo p.
37
+ const modP = (a, p) => (0, arith_1.modNorm)(a, p);
38
+ const invP = (a, p) => (0, arith_1.modInv)(a, p);
39
+ const asFp = (coeffs, p) => ({ p, coeffs });
40
+ const addFp = (a, b, p) => (0, poly_1.fpAdd)(asFp(a, p), asFp(b, p)).coeffs;
41
+ const subFp = (a, b, p) => (0, poly_1.fpSub)(asFp(a, p), asFp(b, p)).coeffs;
42
+ const mulFp = (a, b, p) => (0, poly_1.fpMul)(asFp(a, p), asFp(b, p)).coeffs;
43
+ const scalarMulFp = (a, c, p) => (0, poly_1.fpScale)(asFp(a, p), c).coeffs;
44
+ const divFp = (f, g, p) => {
45
+ const { q, r } = (0, poly_1.fpDivRem)(asFp(f, p), asFp(g, p));
46
+ return [q.coeffs, r.coeffs];
47
+ };
48
+ const gcdFp = (f, g, p) => (0, poly_1.fpGCD)(asFp(f, p), asFp(g, p)).coeffs;
49
+ // x^e mod f over Fp
50
+ function powXModFp(e, f, p) {
51
+ if (e === 0n) {
52
+ return [1n];
53
+ }
54
+ let result = [1n];
55
+ let base = [0n, 1n]; // x
56
+ // reduce base mod f
57
+ base = divFp(base, f, p)[1];
58
+ let k = e;
59
+ while (k > 0n) {
60
+ if (k & 1n) {
61
+ result = divFp(mulFp(result, base, p), f, p)[1];
62
+ }
63
+ base = divFp(mulFp(base, base, p), f, p)[1];
64
+ k >>= 1n;
65
+ }
66
+ return (0, poly_1.zTrim)(result);
67
+ }
68
+ // pow(h, e) mod f over Fp
69
+ function powPolyModFp(h, e, f, p) {
70
+ if (e === 0n) {
71
+ return [1n];
72
+ }
73
+ let result = [1n];
74
+ let base = divFp(h, f, p)[1];
75
+ let k = e;
76
+ while (k > 0n) {
77
+ if (k & 1n) {
78
+ result = divFp(mulFp(result, base, p), f, p)[1];
79
+ }
80
+ base = divFp(mulFp(base, base, p), f, p)[1];
81
+ k >>= 1n;
82
+ }
83
+ return (0, poly_1.zTrim)(result);
84
+ }
85
+ // ============================================================================
86
+ // BERLEKAMP (correct Frobenius powers)
87
+ // ============================================================================
88
+ function berlekampMatrixFp(f, p) {
89
+ const n = degZPoly(f);
90
+ if (n <= 0) {
91
+ return [];
92
+ }
93
+ const QminusI = [];
94
+ for (let i = 0; i < n; i++) {
95
+ // FIX: x^(p^i) mod f (NOT x^(i*p))
96
+ const exp = (0, arith_1.pow)(p, BigInt(i));
97
+ const xpi = powXModFp(exp, f, p);
98
+ const row = new Array(n).fill(0n);
99
+ for (let j = 0; j < n; j++) {
100
+ row[j] = modP(xpi[j] ?? 0n, p);
101
+ }
102
+ row[i] = modP(row[i] - 1n, p); // subtract I
103
+ QminusI.push(row);
104
+ }
105
+ return QminusI;
106
+ }
107
+ function nullSpaceFp(A, p) {
108
+ const m = A.length;
109
+ if (m === 0) {
110
+ return [];
111
+ }
112
+ const n = A[0].length;
113
+ // row-reduced echelon form
114
+ const M = A.map(r => r.map(x => modP(x, p)));
115
+ const pivotCols = [];
116
+ let pivotRow = 0;
117
+ for (let col = 0; col < n && pivotRow < m; col++) {
118
+ let sel = -1;
119
+ for (let r = pivotRow; r < m; r++) {
120
+ if (M[r][col] !== 0n) {
121
+ sel = r;
122
+ break;
123
+ }
124
+ }
125
+ if (sel === -1) {
126
+ continue;
127
+ }
128
+ [M[pivotRow], M[sel]] = [M[sel], M[pivotRow]];
129
+ const inv = invP(M[pivotRow][col], p);
130
+ for (let j = col; j < n; j++) {
131
+ M[pivotRow][j] = modP(M[pivotRow][j] * inv, p);
132
+ }
133
+ for (let r = 0; r < m; r++) {
134
+ if (r === pivotRow) {
135
+ continue;
136
+ }
137
+ const factor = M[r][col];
138
+ if (factor === 0n) {
139
+ continue;
140
+ }
141
+ for (let j = col; j < n; j++) {
142
+ M[r][j] = modP(M[r][j] - factor * M[pivotRow][j], p);
143
+ }
144
+ }
145
+ pivotCols.push(col);
146
+ pivotRow++;
147
+ }
148
+ const isPivot = new Array(n).fill(false);
149
+ for (const c of pivotCols) {
150
+ isPivot[c] = true;
151
+ }
152
+ const freeCols = [];
153
+ for (let c = 0; c < n; c++) {
154
+ if (!isPivot[c]) {
155
+ freeCols.push(c);
156
+ }
157
+ }
158
+ // If no free cols, nullspace is {0}. But Berlekamp always has at least constant 1 in kernel of Q-I,
159
+ // so with our construction we should have at least 1 free column in typical cases.
160
+ const basis = [];
161
+ for (const free of freeCols) {
162
+ const v = new Array(n).fill(0n);
163
+ v[free] = 1n;
164
+ for (let i = pivotCols.length - 1; i >= 0; i--) {
165
+ const pc = pivotCols[i];
166
+ let sum = 0n;
167
+ for (let j = pc + 1; j < n; j++) {
168
+ sum = modP(sum + M[i][j] * v[j], p);
169
+ }
170
+ v[pc] = modP(-sum, p);
171
+ }
172
+ basis.push(v);
173
+ }
174
+ // Ensure we always include the constant vector (1,0,0,...)
175
+ // In some edge cases, elimination choices might miss it; add if absent.
176
+ const hasConst = basis.some(v => v[0] === 1n && v.slice(1).every(x => x === 0n));
177
+ if (!hasConst) {
178
+ const v = new Array(n).fill(0n);
179
+ v[0] = 1n;
180
+ basis.unshift(v);
181
+ }
182
+ return basis;
183
+ }
184
+ function vecToPoly(v, p) {
185
+ return (0, poly_1.zTrim)(v.map(x => modP(x, p)));
186
+ }
187
+ /**
188
+ * Deterministic Berlekamp splitting (good for small/moderate p), with CZ fallback for stubborn cases.
189
+ */
190
+ function berlekampFactorFp(fIn, p) {
191
+ let f = (0, poly_1.zTrim)(fIn.slice());
192
+ const n = degZPoly(f);
193
+ if (n <= 0) {
194
+ return [f];
195
+ }
196
+ if (n === 1) {
197
+ return [f];
198
+ }
199
+ // Make monic
200
+ const inv = invP((0, poly_1.zLC)(f), p);
201
+ f = scalarMulFp(f, inv, p);
202
+ const QmI = berlekampMatrixFp(f, p);
203
+ const ns = nullSpaceFp(QmI, p);
204
+ // If kernel dimension is 1 -> irreducible
205
+ if (ns.length <= 1) {
206
+ return [f];
207
+ }
208
+ const basisPolys = ns.map(v => vecToPoly(v, p));
209
+ let factors = [f];
210
+ // Try each basis polynomial (skip the constant one)
211
+ for (let bIdx = 0; bIdx < basisPolys.length; bIdx++) {
212
+ const b = basisPolys[bIdx];
213
+ if (degZPoly(b) <= 0) {
214
+ continue;
215
+ }
216
+ const newFactors = [];
217
+ let changed = false;
218
+ for (const fac of factors) {
219
+ if (degZPoly(fac) <= 1) {
220
+ newFactors.push(fac);
221
+ continue;
222
+ }
223
+ let splitDone = false;
224
+ for (let a = 0n; a < p; a++) {
225
+ const bMinusA = b.slice();
226
+ bMinusA[0] = modP((bMinusA[0] ?? 0n) - a, p);
227
+ const g = gcdFp(fac, (0, poly_1.zTrim)(bMinusA), p);
228
+ if (degZPoly(g) > 0 && degZPoly(g) < degZPoly(fac)) {
229
+ const [q] = divFp(fac, g, p);
230
+ newFactors.push(g, q);
231
+ changed = true;
232
+ splitDone = true;
233
+ break;
234
+ }
235
+ }
236
+ if (!splitDone) {
237
+ newFactors.push(fac);
238
+ }
239
+ }
240
+ factors = newFactors;
241
+ if (!changed) {
242
+ continue;
243
+ }
244
+ }
245
+ // CZ fallback (probabilistic) if still composite factors remain
246
+ // Uses: gcd(f, h^((p^d - 1)/2) +/- 1) for target d
247
+ const trySplitCZ = (fac, seed) => {
248
+ const d = degZPoly(fac);
249
+ if (d <= 1) {
250
+ return null;
251
+ }
252
+ // cheap deterministic "random" poly from seed
253
+ const h = new Array(d)
254
+ .fill(0n)
255
+ .map((_, i) => modP(seed * 17n + BigInt(i) * 31n + seed * BigInt(i), p));
256
+ for (let targetDeg = 1; targetDeg < d; targetDeg++) {
257
+ const exp = ((0, arith_1.pow)(p, BigInt(targetDeg)) - 1n) / 2n;
258
+ const hPow = powPolyModFp(h, exp, fac, p);
259
+ const g1 = gcdFp(fac, subFp(hPow, [1n], p), p);
260
+ if (degZPoly(g1) > 0 && degZPoly(g1) < d) {
261
+ const [q] = divFp(fac, g1, p);
262
+ return [g1, q];
263
+ }
264
+ const g2 = gcdFp(fac, addFp(hPow, [1n], p), p);
265
+ if (degZPoly(g2) > 0 && degZPoly(g2) < d) {
266
+ const [q] = divFp(fac, g2, p);
267
+ return [g2, q];
268
+ }
269
+ }
270
+ return null;
271
+ };
272
+ for (let iter = 1n; iter <= MAX_DISTINCT_DEGREE_ITERATIONS; iter++) {
273
+ let changed = false;
274
+ const newFactors = [];
275
+ for (const fac of factors) {
276
+ if (degZPoly(fac) <= 1) {
277
+ newFactors.push(fac);
278
+ continue;
279
+ }
280
+ const split = trySplitCZ(fac, iter);
281
+ if (split) {
282
+ newFactors.push(split[0], split[1]);
283
+ changed = true;
284
+ }
285
+ else {
286
+ newFactors.push(fac);
287
+ }
288
+ }
289
+ factors = newFactors;
290
+ if (!changed) {
291
+ break;
292
+ }
293
+ }
294
+ return factors;
295
+ }
296
+ // ============================================================================
297
+ // HENSEL LIFTING (BigInt, two-factor step + multi-factor tree)
298
+ // ============================================================================
299
+ // NOTE: All generic univariate (Z/mZ)[x] operations are centralized in poly.ts
300
+ // (zTrimMod/zAddMod/zSubMod/zMulMod/zScaleMod/zDivRemMod).
301
+ function extendedGcdMod(a, b, m) {
302
+ let old_r = (0, poly_1.zTrimMod)(a, m);
303
+ let r = (0, poly_1.zTrimMod)(b, m);
304
+ let old_s = [1n];
305
+ let s = [0n];
306
+ let old_t = [0n];
307
+ let t = [1n];
308
+ while (!(0, poly_1.zIsZero)(r)) {
309
+ const { q, r: rem } = (0, poly_1.zDivRemMod)(old_r, r, m);
310
+ old_r = r;
311
+ r = rem;
312
+ old_s = (0, poly_1.zSubMod)(old_s, (0, poly_1.zMulMod)(q, s, m), m);
313
+ old_t = (0, poly_1.zSubMod)(old_t, (0, poly_1.zMulMod)(q, t, m), m);
314
+ // shift
315
+ [old_s, s] = [s, old_s];
316
+ [old_t, t] = [t, old_t];
317
+ }
318
+ // make gcd monic
319
+ if (!(0, poly_1.zIsZero)(old_r)) {
320
+ const inv = invP((0, poly_1.zLC)(old_r), m);
321
+ old_r = (0, poly_1.zScaleMod)(old_r, inv, m);
322
+ old_s = (0, poly_1.zScaleMod)(old_s, inv, m);
323
+ old_t = (0, poly_1.zScaleMod)(old_t, inv, m);
324
+ }
325
+ return [old_r, old_s, old_t];
326
+ }
327
+ /**
328
+ * Two-factor Hensel lift step:
329
+ * given f ≡ g*h (mod pk), and s*g + t*h ≡ 1 (mod pk),
330
+ * lift to modulus pkNext = pk*p.
331
+ */
332
+ function henselStep(f, g, h, s, t, p, pk) {
333
+ const pkNext = pk * p;
334
+ // e = f - g*h mod pkNext
335
+ const gh = (0, poly_1.zMulMod)(g, h, pkNext);
336
+ const e = (0, poly_1.zSubMod)((0, poly_1.zTrimMod)(f, pkNext), gh, pkNext);
337
+ // Compute correction:
338
+ // q,r = (s*e) / h (mod pkNext) so that deg(r) < deg(h)
339
+ const se = (0, poly_1.zMulMod)(s, e, pkNext);
340
+ const { q, r } = (0, poly_1.zDivRemMod)(se, h, pkNext);
341
+ // g' = g + t*e + q*g (mod pkNext)
342
+ let gNew = (0, poly_1.zAddMod)(g, (0, poly_1.zMulMod)(t, e, pkNext), pkNext);
343
+ gNew = (0, poly_1.zAddMod)(gNew, (0, poly_1.zMulMod)(q, g, pkNext), pkNext);
344
+ // h' = h + r (mod pkNext)
345
+ const hNew = (0, poly_1.zAddMod)(h, r, pkNext);
346
+ // Update Bezout:
347
+ // b = s*g' + t*h' (mod pkNext)
348
+ const b = (0, poly_1.zAddMod)((0, poly_1.zMulMod)(s, gNew, pkNext), (0, poly_1.zMulMod)(t, hNew, pkNext), pkNext);
349
+ // c = b - 1
350
+ const c = (0, poly_1.zSubMod)(b, [1n], pkNext);
351
+ // q2,r2 = (s*c)/h' (mod pkNext)
352
+ const sc = (0, poly_1.zMulMod)(s, c, pkNext);
353
+ const { q: q2, r: r2 } = (0, poly_1.zDivRemMod)(sc, hNew, pkNext);
354
+ const sNew = (0, poly_1.zSubMod)(s, r2, pkNext);
355
+ let tNew = (0, poly_1.zSubMod)(t, (0, poly_1.zMulMod)(t, c, pkNext), pkNext);
356
+ tNew = (0, poly_1.zSubMod)(tNew, (0, poly_1.zMulMod)(q2, gNew, pkNext), pkNext);
357
+ return {
358
+ g: (0, poly_1.zTrimMod)(gNew, pkNext),
359
+ h: (0, poly_1.zTrimMod)(hNew, pkNext),
360
+ s: (0, poly_1.zTrimMod)(sNew, pkNext),
361
+ t: (0, poly_1.zTrimMod)(tNew, pkNext),
362
+ };
363
+ }
364
+ function henselLiftMulti(f, factorsModP, pNum, power) {
365
+ if (factorsModP.length === 0) {
366
+ return [];
367
+ }
368
+ if (factorsModP.length === 1) {
369
+ return [(0, poly_1.zPrimitivePart)(f)];
370
+ }
371
+ const p = BigInt(pNum);
372
+ function toZPolyFromFp(fp) {
373
+ // coefficients already in [0,p-1], embed into bigint
374
+ return (0, poly_1.zTrim)(fp.map(c => BigInt(c)));
375
+ }
376
+ function buildTree(polys, mod) {
377
+ if (polys.length === 1) {
378
+ return { poly: (0, poly_1.zTrimMod)(polys[0], mod) };
379
+ }
380
+ const mid = Math.floor(polys.length / 2);
381
+ const left = buildTree(polys.slice(0, mid), mod);
382
+ const right = buildTree(polys.slice(mid), mod);
383
+ const poly = (0, poly_1.zMulMod)(left.poly, right.poly, mod);
384
+ const [, s, t] = extendedGcdMod(left.poly, right.poly, mod);
385
+ return { poly, s, t, left, right };
386
+ }
387
+ function liftTree(node, target, pk) {
388
+ if (!node.left || !node.right) {
389
+ return;
390
+ }
391
+ const lifted = henselStep(target, node.left.poly, node.right.poly, node.s, node.t, p, pk);
392
+ node.left.poly = lifted.g;
393
+ node.right.poly = lifted.h;
394
+ node.s = lifted.s;
395
+ node.t = lifted.t;
396
+ liftTree(node.left, lifted.g, pk);
397
+ liftTree(node.right, lifted.h, pk);
398
+ }
399
+ function collectLeaves(node) {
400
+ if (!node.left && !node.right) {
401
+ return [node.poly];
402
+ }
403
+ return [
404
+ ...(node.left ? collectLeaves(node.left) : []),
405
+ ...(node.right ? collectLeaves(node.right) : []),
406
+ ];
407
+ }
408
+ // Start modulus pk = p (k=1)
409
+ let pk = p;
410
+ const factorsZ = factorsModP.map(toZPolyFromFp);
411
+ const tree = buildTree(factorsZ, pk);
412
+ // Lift k=1..power-1 to pk = p^power
413
+ for (let k = 1; k < power; k++) {
414
+ const pkNext = pk * p;
415
+ const target = (0, poly_1.zTrimMod)(f, pkNext);
416
+ // One global step to pkNext is achieved by calling henselStep with pk (current modulus)
417
+ liftTree(tree, target, pk);
418
+ pk = pkNext;
419
+ }
420
+ return collectLeaves(tree).map(poly => (0, poly_1.zTrimMod)(poly, pk));
421
+ }
422
+ // ============================================================================
423
+ // RECOMBINATION (BigInt exact division) — FIXED seed (start at 1)
424
+ // ============================================================================
425
+ function combinations(n, k) {
426
+ const res = [];
427
+ const combo = [];
428
+ function rec(start) {
429
+ if (combo.length === k) {
430
+ res.push(combo.slice());
431
+ return;
432
+ }
433
+ for (let i = start; i < n; i++) {
434
+ combo.push(i);
435
+ rec(i + 1);
436
+ combo.pop();
437
+ }
438
+ }
439
+ rec(0);
440
+ return res;
441
+ }
442
+ function recombineFactorsBig(f, lifted, modulus) {
443
+ const result = [];
444
+ let remaining = (0, poly_1.zTrim)(f.slice());
445
+ const n = lifted.length;
446
+ const used = new Set();
447
+ // Try increasing subset sizes
448
+ for (let size = 1; size < n; size++) {
449
+ const combos = combinations(n, size);
450
+ for (const combo of combos) {
451
+ if (combo.some(i => used.has(i))) {
452
+ continue;
453
+ }
454
+ // FIX: start at 1n, not lc
455
+ let prod = [1n];
456
+ for (const idx of combo) {
457
+ prod = (0, poly_1.zMulMod)(prod, lifted[idx], modulus);
458
+ }
459
+ const candidateSym = (0, poly_1.zToSymmetricMod)(prod, modulus);
460
+ const { primitive: cand } = (0, poly_1.zNormalizePrimitiveSign)(candidateSym);
461
+ if (degZPoly(cand) <= 0) {
462
+ continue;
463
+ }
464
+ const q = (0, poly_1.zTryDivExact)(remaining, cand);
465
+ if (q) {
466
+ result.push(cand);
467
+ remaining = q;
468
+ for (const idx of combo) {
469
+ used.add(idx);
470
+ }
471
+ if (degZPoly(remaining) <= 0) {
472
+ // consumed everything
473
+ return result;
474
+ }
475
+ }
476
+ }
477
+ }
478
+ if (degZPoly(remaining) > 0) {
479
+ result.push((0, poly_1.zPrimitivePart)(remaining));
480
+ }
481
+ return result;
482
+ }
483
+ // ============================================================================
484
+ // PRIME SELECTION + BOUNDS (BigInt exact)
485
+ // ============================================================================
486
+ function toFpPolyFromZ(f, p) {
487
+ return (0, poly_1.zTrim)(f.map(c => modP(c, p)));
488
+ }
489
+ function countFactorsModP_Berlekamp(f, pNum) {
490
+ const p = BigInt(pNum);
491
+ const fMod = toFpPolyFromZ(f, p);
492
+ const lc = (0, poly_1.zLC)(fMod);
493
+ const fMonic = lc === 1n ? fMod : scalarMulFp(fMod, invP(lc, p), p);
494
+ const QmI = berlekampMatrixFp(fMonic, p);
495
+ const ns = nullSpaceFp(QmI, p);
496
+ return ns.length; // kernel dimension
497
+ }
498
+ function coefficientBoundMignotte(f) {
499
+ // bound = 2^n * ||f||_2, where ||f||_2 = sqrt(sum c^2)
500
+ const n = degZPoly(f);
501
+ let sum = 0n;
502
+ for (const c of f) {
503
+ sum += c * c;
504
+ }
505
+ const norm = (0, arith_1.bigIntSqrt)(sum) + ((0, arith_1.bigIntSqrt)(sum) * (0, arith_1.bigIntSqrt)(sum) === sum ? 0n : 1n); // ceil sqrt
506
+ const twoPow = 1n << BigInt(Math.max(0, n));
507
+ return twoPow * norm;
508
+ }
509
+ function primeBudgetForUniZ(f) {
510
+ // Adaptive budget: grows (slowly) with degree and coefficient bit-size.
511
+ // Goal: terminate deterministically, but avoid giving up too early on hard inputs.
512
+ const n = Math.max(0, degZPoly(f));
513
+ let maxAbs = 0n;
514
+ for (const c of f) {
515
+ const a = c < 0n ? -c : c;
516
+ if (a > maxAbs) {
517
+ maxAbs = a;
518
+ }
519
+ }
520
+ const bits = (0, arith_1.bigintBitLength)(maxAbs);
521
+ // Scale the baseline prime budget with polynomial degree and coefficient size.
522
+ let budget = BASE_PRIME_BUDGET +
523
+ Math.ceil(n / PRIME_BUDGET_DEGREE_DIVISOR) +
524
+ Math.ceil(bits / PRIME_BUDGET_BIT_DIVISOR);
525
+ // Clamp to a reasonable range.
526
+ if (budget < BASE_PRIME_BUDGET) {
527
+ budget = BASE_PRIME_BUDGET;
528
+ }
529
+ if (budget > MAX_PRIME_BUDGET) {
530
+ budget = MAX_PRIME_BUDGET;
531
+ }
532
+ return budget;
533
+ }
534
+ function findGoodPrimeBig(f, minPrime = DEFAULT_MIN_FACTOR_PRIME, maxPrimes = undefined) {
535
+ const lc = (0, arith_1.abs)((0, poly_1.zLC)(f));
536
+ const df = (0, poly_1.zDerivative)(f);
537
+ const budget = (maxPrimes ?? primeBudgetForUniZ(f)) | 0;
538
+ if (!Number.isFinite(budget) || budget <= 0) {
539
+ throw new arith_1.PrimeSelectionError('findGoodPrimeBig: invalid maxPrimes', { budget });
540
+ }
541
+ let bestP = 0;
542
+ let bestCount = Number.POSITIVE_INFINITY;
543
+ let tried = 0;
544
+ let pNum = (0, arith_1.nextPrime32)(Math.max(2, minPrime));
545
+ while (tried < budget) {
546
+ tried++;
547
+ const pBig = BigInt(pNum);
548
+ // Reject primes dividing the leading coefficient (degree drop)
549
+ if (lc % pBig === 0n) {
550
+ pNum = (0, arith_1.nextPrime32)(pNum + 1);
551
+ continue;
552
+ }
553
+ // square-free test: gcd(f mod p, f' mod p) == 1
554
+ const p = pBig;
555
+ const fMod = toFpPolyFromZ(f, p);
556
+ const dfMod = toFpPolyFromZ(df, p);
557
+ const g = gcdFp(fMod, dfMod, p);
558
+ if (degZPoly(g) !== 0) {
559
+ pNum = (0, arith_1.nextPrime32)(pNum + 1);
560
+ continue;
561
+ }
562
+ const cnt = countFactorsModP_Berlekamp(f, pNum);
563
+ if (cnt < bestCount) {
564
+ bestCount = cnt;
565
+ bestP = pNum;
566
+ if (cnt <= 2) {
567
+ break;
568
+ }
569
+ }
570
+ pNum = (0, arith_1.nextPrime32)(pNum + 1);
571
+ }
572
+ if (bestP === 0) {
573
+ throw new arith_1.PrimeSelectionError(`Could not find suitable prime after trying ${tried} primes (budget=${budget})`, {
574
+ tried,
575
+ budget,
576
+ minPrime,
577
+ });
578
+ }
579
+ return { p: bestP, numFactors: bestCount };
580
+ }
581
+ // ============================================================================
582
+ // SQUARE-FREE FACTORIZATION (BigInt)
583
+ // ============================================================================
584
+ /**
585
+ * Square-free factorization over **ℤ** (BigInt).
586
+ *
587
+ * Returns a list of pairs `[g_i, m_i]` such that:
588
+ * f = ∏ g_i^{m_i}
589
+ * and each g_i is square-free and pairwise coprime.
590
+ *
591
+ * Implementation follows the standard gcd-with-derivative approach:
592
+ * - Let d = f' and g = gcd(f, d)
593
+ * - Repeatedly split out square-free parts by dividing by g and updating g with gcd steps.
594
+ *
595
+ * @param f Primitive, trimmed polynomial.
596
+ * @returns Array of `[factor, multiplicity]` pairs.
597
+ */
598
+ function squareFreeFactorizationBig(f) {
599
+ f = (0, poly_1.zTrim)(f);
600
+ if (degZPoly(f) <= 0) {
601
+ return [];
602
+ }
603
+ // make primitive
604
+ f = (0, poly_1.zPrimitivePart)(f);
605
+ const df = (0, poly_1.zDerivative)(f);
606
+ if ((0, poly_1.zIsZero)(df)) {
607
+ return [[f, 1]];
608
+ }
609
+ let g = (0, poly_1.zGcdPrimitivePRS)(f, df);
610
+ if (degZPoly(g) === 0) {
611
+ return [[f, 1]];
612
+ }
613
+ const sq = (0, poly_1.zTryDivExact)(f, g);
614
+ if (!sq) {
615
+ return [[f, 1]];
616
+ }
617
+ let w = sq;
618
+ let i = 1;
619
+ const out = [];
620
+ while (degZPoly(w) > 0) {
621
+ const nextG = (0, poly_1.zGcdPrimitivePRS)(g, w);
622
+ const factor = (0, poly_1.zTryDivExact)(w, nextG);
623
+ if (factor && degZPoly(factor) > 0) {
624
+ out.push([(0, poly_1.zPrimitivePart)(factor), i]);
625
+ }
626
+ w = nextG;
627
+ const gDiv = (0, poly_1.zTryDivExact)(g, nextG);
628
+ if (!gDiv) {
629
+ break;
630
+ }
631
+ g = gDiv;
632
+ i++;
633
+ }
634
+ return out;
635
+ }
636
+ // ============================================================================
637
+ // MAIN SQUARE-FREE FACTORING OVER bigint (Zassenhaus outline)
638
+ // ============================================================================
639
+ function tryFactorQuarticEvenZ(f) {
640
+ f = (0, poly_1.zTrim)(f);
641
+ if (degZPoly(f) !== 4) {
642
+ return null;
643
+ }
644
+ const a0 = f[0] ?? 0n;
645
+ const a1 = f[1] ?? 0n;
646
+ const a2 = f[2] ?? 0n;
647
+ const a3 = f[3] ?? 0n;
648
+ const a4 = f[4] ?? 0n;
649
+ if (a4 === 0n) {
650
+ return null;
651
+ }
652
+ // Only handle monic quartics for now (covers current failures).
653
+ if (a4 !== 1n) {
654
+ return null;
655
+ }
656
+ // If odd terms present, not an even quartic.
657
+ if (a1 !== 0n || a3 !== 0n) {
658
+ return null;
659
+ }
660
+ // 1) Even-quartic split: x^4 + a2*x^2 + a0 = (x^2 + u*x + v)(x^2 - u*x + v)
661
+ // Requires v^2 = a0 and u^2 = 2*v - a2.
662
+ const v = sqrtExactBigint(a0);
663
+ if (v !== null) {
664
+ const u2 = 2n * v - a2;
665
+ const u = sqrtExactBigint(u2);
666
+ if (u !== null) {
667
+ const f1 = [v, u, 1n]; // x^2 + u*x + v
668
+ const f2 = [v, -u, 1n]; // x^2 - u*x + v
669
+ return [(0, poly_1.zPrimitivePart)(f1), (0, poly_1.zPrimitivePart)(f2)];
670
+ }
671
+ }
672
+ // 2) Biquadratic: treat as quadratic in t=x^2: t^2 + a2*t + a0.
673
+ // Roots are r1,r2 = (-a2 ± sqrt(a2^2 - 4*a0)) / 2; need integer roots.
674
+ const disc = a2 * a2 - 4n * a0;
675
+ const s = sqrtExactBigint(disc);
676
+ if (s !== null) {
677
+ const n1 = -a2 + s;
678
+ const n2 = -a2 - s;
679
+ if (n1 % 2n === 0n && n2 % 2n === 0n) {
680
+ const r1 = n1 / 2n;
681
+ const r2 = n2 / 2n;
682
+ // t^2 + a2*t + a0 = (t - r1)(t - r2) => (x^2 - r1)(x^2 - r2)
683
+ const g1 = [-r1, 0n, 1n];
684
+ const g2 = [-r2, 0n, 1n];
685
+ return [(0, poly_1.zPrimitivePart)(g1), (0, poly_1.zPrimitivePart)(g2)];
686
+ }
687
+ }
688
+ return null;
689
+ }
690
+ /**
691
+ * Stride substitution: if all nonzero exponents in f share a common divisor s >= 2,
692
+ * write f(x) = g(x^s) where g has degree n/s. Factor g over Z, then for each factor
693
+ * h(t) of g, expand h(x^s) and recursively factor it (it may split further).
694
+ *
695
+ * Examples:
696
+ * x^6+4x^4+16x^2+64, s=2 → g(t)=t^3+4t^2+16t+64=(t+4)(t^2+16) → (x^2+4)(x^4+16)
697
+ * x^8+x^4+1, s=4 → g(t)=t^2+t+1 (irreducible) → returns null, but then
698
+ * tryFactorQuarticEvenZ or Berlekamp handles x^8+x^4+1 directly.
699
+ */
700
+ function tryFactorStrideSubstitutionZ(f) {
701
+ f = (0, poly_1.zTrim)(f);
702
+ const n = degZPoly(f);
703
+ if (n < 4) {
704
+ return null;
705
+ }
706
+ // Find stride = gcd of all nonzero exponent indices
707
+ let stride = 0;
708
+ for (let i = 1; i < f.length; i++) {
709
+ if ((f[i] ?? 0n) !== 0n) {
710
+ stride = stride === 0 ? i : Number((0, arith_1.gcd)(BigInt(stride), BigInt(i)));
711
+ }
712
+ }
713
+ if (stride < 2) {
714
+ return null;
715
+ }
716
+ // Build g(t) where f(x) = g(x^stride)
717
+ const gLen = Math.floor(n / stride) + 1;
718
+ const g = new Array(gLen).fill(0n);
719
+ for (let i = 0; i < f.length; i++) {
720
+ const c = f[i] ?? 0n;
721
+ if (c !== 0n) {
722
+ if (i % stride !== 0) {
723
+ return null; // Safety check
724
+ }
725
+ g[i / stride] = c;
726
+ }
727
+ }
728
+ // Factor g(t). Try factorPolynomialBig first; if it fails to split,
729
+ // fall back to rational root search (catches cases where Hensel lifting
730
+ // fails due to bad prime/factor grouping on small polynomials).
731
+ let gResult = factorPolynomialBig((0, poly_1.zTrim)(g));
732
+ if (!gResult.factors || gResult.factors.length <= 1) {
733
+ // Rational root fallback: try divisors of the constant term / leading coeff
734
+ const gTrimmed = (0, poly_1.zTrim)(g);
735
+ const gDeg = degZPoly(gTrimmed);
736
+ if (gDeg >= 2 && gDeg <= 6) {
737
+ const constTerm = gTrimmed[0] ?? 0n;
738
+ const leadCoeff = gTrimmed[gDeg] ?? 1n;
739
+ if (constTerm !== 0n) {
740
+ const constDivs = (0, arith_1.getDivisors)(constTerm < 0n ? -constTerm : constTerm);
741
+ const leadDivs = (0, arith_1.getDivisors)(leadCoeff < 0n ? -leadCoeff : leadCoeff);
742
+ for (const p_val of constDivs) {
743
+ for (const q_val of leadDivs) {
744
+ for (const sign of [1n, -1n]) {
745
+ const numer = sign * p_val;
746
+ // Evaluate q^deg * g(numer/q) to avoid fractions
747
+ let evalResult = 0n;
748
+ for (let i = 0; i <= gDeg; i++) {
749
+ const coeff = gTrimmed[i] ?? 0n;
750
+ let numerPow = 1n;
751
+ for (let j = 0; j < i; j++) {
752
+ numerPow *= numer;
753
+ }
754
+ let qPow = 1n;
755
+ for (let j = 0; j < gDeg - i; j++) {
756
+ qPow *= q_val;
757
+ }
758
+ evalResult += coeff * numerPow * qPow;
759
+ }
760
+ if (evalResult === 0n) {
761
+ // Found root numer/q_val. Factor is (q_val*t - numer).
762
+ const linFactor = [-numer, q_val];
763
+ const quotient = (0, poly_1.zTryDivExact)(gTrimmed, linFactor);
764
+ if (quotient) {
765
+ // Rebuild factorization result
766
+ const quotResult = factorPolynomialBig(quotient);
767
+ const newFactors = [
768
+ { coefficients: (0, poly_1.zTrim)(linFactor), multiplicity: 1 },
769
+ ];
770
+ for (const f of quotResult.factors) {
771
+ newFactors.push(f);
772
+ }
773
+ gResult = {
774
+ content: quotResult.content,
775
+ factors: newFactors,
776
+ };
777
+ break;
778
+ }
779
+ }
780
+ }
781
+ if (gResult.factors.length > 1) {
782
+ break;
783
+ }
784
+ }
785
+ if (gResult.factors.length > 1) {
786
+ break;
787
+ }
788
+ }
789
+ }
790
+ }
791
+ }
792
+ if (!gResult.factors || gResult.factors.length <= 1) {
793
+ return null; // g is irreducible, substitution didn't help
794
+ }
795
+ // Expand each factor h(t) → h(x^stride) and recursively factor
796
+ const out = [];
797
+ for (const factor of gResult.factors) {
798
+ const hCoeffs = factor.coefficients;
799
+ const mult = factor.multiplicity ?? 1;
800
+ // Build h(x^stride)
801
+ const expanded = new Array((hCoeffs.length - 1) * stride + 1).fill(0n);
802
+ for (let i = 0; i < hCoeffs.length; i++) {
803
+ expanded[i * stride] = hCoeffs[i];
804
+ }
805
+ // Recursively factor (h(x^stride) may split further, e.g. x^4+16 might factor)
806
+ const subFactors = factorSquareFreeBig((0, poly_1.zTrim)(expanded));
807
+ for (let k = 0; k < mult; k++) {
808
+ out.push(...subFactors);
809
+ }
810
+ }
811
+ // Handle content
812
+ if (gResult.content !== 1n && gResult.content !== -1n) {
813
+ out.unshift([gResult.content]);
814
+ }
815
+ else if (gResult.content === -1n && out.length > 0) {
816
+ out[0] = out[0].map(c => -c);
817
+ }
818
+ return out.length > 1 ? out : null;
819
+ }
820
+ function factorSquareFreeBig(f) {
821
+ f = (0, poly_1.zTrim)(f);
822
+ if (degZPoly(f) <= 1) {
823
+ return [(0, poly_1.zPrimitivePart)(f)];
824
+ }
825
+ // Cheap special cases that Berlekamp/Hensel sometimes misses due to recombination heuristics.
826
+ const quartic = tryFactorQuarticEvenZ(f);
827
+ if (quartic) {
828
+ return quartic;
829
+ }
830
+ // Stride substitution: if all nonzero terms have exponents divisible by some
831
+ // stride s >= 2 (e.g. only even-degree terms when s=2), substitute t = x^s,
832
+ // factor the lower-degree polynomial g(t), then expand each factor h(t) back
833
+ // to h(x^s) and recursively factor (since h(x^s) may split further over Z[x]).
834
+ // Example: x^6+4x^4+16x^2+64 with s=2 gives t^3+4t^2+16t+64 = (t+4)(t^2+16),
835
+ // yielding (x^2+4)(x^4+16).
836
+ const strideSub = tryFactorStrideSubstitutionZ(f);
837
+ if (strideSub) {
838
+ return strideSub;
839
+ }
840
+ // bound (BigInt exact)
841
+ const bound = coefficientBoundMignotte(f);
842
+ const lcAbs = (0, arith_1.abs)((0, poly_1.zLC)(f));
843
+ // pick prime: do NOT conclude irreducible from a single prime.
844
+ // A reducible polynomial over ℤ can be irreducible modulo some primes, so
845
+ // keep trying until Berlekamp actually splits (within a deterministic budget).
846
+ let pNum;
847
+ let p;
848
+ const df = (0, poly_1.zDerivative)(f);
849
+ const budget = primeBudgetForUniZ(f);
850
+ // Start from a "good" prime if possible, but keep searching until we get a split.
851
+ let startPrime = 3;
852
+ try {
853
+ startPrime = findGoodPrimeBig(f).p;
854
+ }
855
+ catch {
856
+ startPrime = 3;
857
+ }
858
+ let tried = 0;
859
+ let cand = (0, arith_1.nextPrime32)(Math.max(2, startPrime));
860
+ let factorsModP_monic;
861
+ while (tried < budget) {
862
+ tried++;
863
+ const pBig = BigInt(cand);
864
+ // Reject primes dividing the leading coefficient (degree drop)
865
+ if (modP((0, poly_1.zLC)(f), pBig) === 0n) {
866
+ cand = (0, arith_1.nextPrime32)(cand + 1);
867
+ continue;
868
+ }
869
+ // square-free test: gcd(f mod p, f' mod p) == 1
870
+ const fModTry = toFpPolyFromZ(f, pBig);
871
+ const dfModTry = toFpPolyFromZ(df, pBig);
872
+ const g = gcdFp(fModTry, dfModTry, pBig);
873
+ if (degZPoly(g) !== 0) {
874
+ cand = (0, arith_1.nextPrime32)(cand + 1);
875
+ continue;
876
+ }
877
+ // Factor mod p (Berlekamp)
878
+ const facs = berlekampFactorFp(fModTry, pBig);
879
+ if (facs.length > 1) {
880
+ pNum = cand;
881
+ p = pBig;
882
+ factorsModP_monic = facs;
883
+ break;
884
+ }
885
+ cand = (0, arith_1.nextPrime32)(cand + 1);
886
+ }
887
+ if (!pNum || !p || !factorsModP_monic) {
888
+ return [(0, poly_1.zPrimitivePart)(f)];
889
+ }
890
+ // lifting height: find k with p^k > 2*lc*bound
891
+ const target = 2n * lcAbs * bound;
892
+ let k = 1;
893
+ let modulus = p;
894
+ while (modulus <= target) {
895
+ modulus *= p;
896
+ k++;
897
+ }
898
+ // Berlekamp factors a monic polynomial; we need product == f (mod p).
899
+ // Restore leading coefficient by scaling one factor by lc(f) mod p.
900
+ const lcModP = modP((0, poly_1.zLC)(f), p);
901
+ const factorsModP = factorsModP_monic.map(g => g.slice());
902
+ if (lcModP !== 1n) {
903
+ factorsModP[0] = scalarMulFp(factorsModP[0], lcModP, p);
904
+ }
905
+ // Hensel lift to p^k
906
+ const lifted = henselLiftMulti((0, poly_1.zTrim)(f), factorsModP, pNum, k);
907
+ // Recombine (BigInt exact)
908
+ const recombined = recombineFactorsBig(f, lifted, modulus);
909
+ // If recombination returns same polynomial, treat as irreducible
910
+ if (recombined.length === 1) {
911
+ const a = (0, poly_1.zPrimitivePart)(f);
912
+ const b = (0, poly_1.zPrimitivePart)(recombined[0]);
913
+ if (polyEqualsZ(a, b)) {
914
+ return [a];
915
+ }
916
+ }
917
+ // Recursively factor any composite returned factors
918
+ const out = [];
919
+ for (const cand of recombined) {
920
+ if (degZPoly(cand) <= 1) {
921
+ out.push((0, poly_1.zPrimitivePart)(cand));
922
+ }
923
+ else {
924
+ const candNorm = (0, poly_1.zPrimitivePart)(cand);
925
+ if (polyEqualsZ(candNorm, (0, poly_1.zPrimitivePart)(f))) {
926
+ out.push(candNorm);
927
+ }
928
+ else {
929
+ out.push(...factorSquareFreeBig(candNorm));
930
+ }
931
+ }
932
+ }
933
+ return out;
934
+ }
935
+ function polyEqualsZ(a, b) {
936
+ a = (0, poly_1.zTrim)(a);
937
+ b = (0, poly_1.zTrim)(b);
938
+ if (a.length !== b.length) {
939
+ return false;
940
+ }
941
+ for (let i = 0; i < a.length; i++) {
942
+ if (a[i] !== b[i]) {
943
+ return false;
944
+ }
945
+ }
946
+ return true;
947
+ }
948
+ // ============================================================================
949
+ // PUBLIC API (BigInt)
950
+ // ============================================================================
951
+ /**
952
+ * Factor a univariate integer polynomial over Z.
953
+ *
954
+ * @param input Polynomial given as either:
955
+ * - a string (parsed using the library parser), or
956
+ * - a coefficient array `ZPoly` (lowest degree first).
957
+ * @param variable Variable name to treat as the univariate indeterminate.
958
+ *
959
+ * @returns A normalized factorization:
960
+ * - `content`: the integer content extracted from the polynomial
961
+ * - `factors`: primitive, normalized factors with multiplicities
962
+ *
963
+ * @remarks
964
+ * This is the preferred API if you need exact arithmetic (no `number` rounding).
965
+ */
966
+ /**
967
+ * Factor a univariate polynomial over **ℤ** using exact BigInt arithmetic.
968
+ *
969
+ * Pipeline (high level):
970
+ * 1) Parse + trim
971
+ * 2) Split into `content` and `primitive` part
972
+ * 3) Square-free factorization
973
+ * 4) Factor each square-free component (modular splitting + lifting)
974
+ * 5) Recombine multiplicities and return a normalized factor list
975
+ *
976
+ * Notes:
977
+ * - Factors are returned **primitive** and **normalized** (unit/sign absorbed into `content`).
978
+ * - For multivariate inputs, use the multivariate entry points in this module.
979
+ *
980
+ * @param input Polynomial string (parser format) or coefficient array.
981
+ * @param variable The variable name to use when parsing from string.
982
+ * @returns `{ content, factors }` where `content` is the integer unit/content and `factors` are primitive factors.
983
+ *
984
+ * @throws {Error} If parsing fails or the polynomial is malformed.
985
+ */
986
+ function factorPolynomialBig(input) {
987
+ let f = (0, poly_1.zTrim)(input);
988
+ if ((0, poly_1.zIsZero)(f)) {
989
+ return { content: 0n, factors: [] };
990
+ }
991
+ if (degZPoly(f) === 0) {
992
+ return { content: f[0] ?? 0n, factors: [] };
993
+ }
994
+ const { content, primitive } = (0, poly_1.zNormalizePrimitiveSign)(f);
995
+ f = primitive;
996
+ const sqf = squareFreeFactorizationBig(f);
997
+ const sqfParts = sqf.length === 0 ? [[f, 1]] : sqf;
998
+ const result = { content, factors: [] };
999
+ for (const [part, mult] of sqfParts) {
1000
+ const irr = factorSquareFreeBig(part);
1001
+ for (const fac of irr) {
1002
+ result.factors.push({
1003
+ coefficients: (0, poly_1.zPrimitivePart)(fac),
1004
+ multiplicity: mult,
1005
+ });
1006
+ }
1007
+ }
1008
+ return result;
1009
+ }
1010
+ // ============================================================================
1011
+ // COMPATIBILITY WRAPPERS (number[] / number output)
1012
+ // ============================================================================
1013
+ function assertSafeIntArray(arr, who) {
1014
+ if (arr.length === 0) {
1015
+ throw new Error(`${who}: empty coefficient array`);
1016
+ }
1017
+ for (let i = 0; i < arr.length; i++) {
1018
+ const c = arr[i];
1019
+ if (!Number.isFinite(c) || !Number.isInteger(c) || !Number.isSafeInteger(c)) {
1020
+ throw new Error(`${who}: coefficient at index ${i} is not a safe integer: ${c}`);
1021
+ }
1022
+ }
1023
+ }
1024
+ function toBigFromNumberPoly(f) {
1025
+ return (0, poly_1.zTrim)(f.map(x => BigInt(x)));
1026
+ }
1027
+ function toNumberFromBigPoly(f) {
1028
+ // only safe if all coefficients fit safe integer
1029
+ const out = [];
1030
+ for (const c of f) {
1031
+ if (c > BigInt(Number.MAX_SAFE_INTEGER) || c < BigInt(Number.MIN_SAFE_INTEGER)) {
1032
+ throw new Error(`toNumberFromBigPoly: coefficient out of safe range: ${c.toString()}`);
1033
+ }
1034
+ out.push(Number(c));
1035
+ }
1036
+ // trim zeros
1037
+ while (out.length > 1 && out[out.length - 1] === 0) {
1038
+ out.pop();
1039
+ }
1040
+ return out;
1041
+ }
1042
+ /**
1043
+ * Factor a univariate integer polynomial over Z with safe JS-number coefficients.
1044
+ *
1045
+ * @param input Polynomial given as either:
1046
+ * - a string, or
1047
+ * - a `number[]` coefficient array (lowest degree first).
1048
+ * @param variable Variable name to treat as the univariate indeterminate.
1049
+ *
1050
+ * @returns A normalized factorization (same shape as `factorPolynomialBig`, but using `number[]` input).
1051
+ *
1052
+ * @throws If coefficients are not safe integers.
1053
+ */
1054
+ function factorPolynomial(input) {
1055
+ if (Array.isArray(input)) {
1056
+ assertSafeIntArray(input, 'factorPolynomial');
1057
+ }
1058
+ const big = toBigFromNumberPoly(input);
1059
+ const r = factorPolynomialBig(big);
1060
+ const content = (() => {
1061
+ if (r.content > BigInt(Number.MAX_SAFE_INTEGER) ||
1062
+ r.content < BigInt(Number.MIN_SAFE_INTEGER)) {
1063
+ throw new Error(`factorPolynomial: content out of safe range: ${r.content.toString()}`);
1064
+ }
1065
+ return Number(r.content);
1066
+ })();
1067
+ const factors = r.factors.map(f => ({
1068
+ coefficients: toNumberFromBigPoly(f.coefficients),
1069
+ multiplicity: f.multiplicity,
1070
+ }));
1071
+ return { content, factors };
1072
+ }