nerdamer 2.0.0-rc.1 → 2.0.0

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 (236) hide show
  1. package/BREAKING_CHANGES.md +244 -0
  2. package/README.md +168 -229
  3. package/dist/bundle.js +1 -1
  4. package/dist/bundle.js.LICENSE.txt +6 -6
  5. package/output/algebra/adapters.d.ts +3 -33
  6. package/output/algebra/adapters.js +7 -105
  7. package/output/algebra/algorithms/arith.js +10 -9
  8. package/output/algebra/algorithms/groebnerBase.d.ts +24 -20
  9. package/output/algebra/algorithms/groebnerBase.js +486 -723
  10. package/output/algebra/dispatch.d.ts +1 -0
  11. package/output/algebra/dispatch.js +25 -0
  12. package/output/algebra/factor/factor.d.ts +15 -0
  13. package/output/algebra/factor/factor.js +99 -12
  14. package/output/algebra/gcd/gcd.d.ts +8 -7
  15. package/output/algebra/gcd/gcd.js +32 -78
  16. package/output/algebra/groebner.d.ts +2 -2
  17. package/output/algebra/groebner.js +6 -12
  18. package/output/algebra/partfrac.d.ts +3 -3
  19. package/output/algebra/partfrac.js +28 -61
  20. package/output/algebra/polynomial/ModularSparsePolynomial.d.ts +131 -0
  21. package/output/algebra/polynomial/ModularSparsePolynomial.js +378 -0
  22. package/output/algebra/polynomial/ModularSparsePolynomialFactor.d.ts +40 -0
  23. package/output/algebra/polynomial/ModularSparsePolynomialFactor.js +661 -0
  24. package/output/algebra/polynomial/SparsePolynomialFactor.d.ts +64 -0
  25. package/output/algebra/polynomial/SparsePolynomialFactor.js +492 -0
  26. package/output/algebra/polynomial/SparsePolynomialGcd.d.ts +29 -0
  27. package/output/algebra/polynomial/SparsePolynomialGcd.js +259 -0
  28. package/output/algebra/polynomial/SparsePolynomialMultivariateFactor.d.ts +82 -0
  29. package/output/algebra/polynomial/SparsePolynomialMultivariateFactor.js +604 -0
  30. package/output/algebra/polynomial/modularGcd.d.ts +40 -0
  31. package/output/algebra/polynomial/modularGcd.js +365 -0
  32. package/output/algebra/polynomialize.js +4 -2
  33. package/output/algebra/simplify/funcsimp.js +1 -1
  34. package/output/algebra/simplify/ratsimp.js +1 -1
  35. package/output/algebra/simplify/simplify.js +11 -2
  36. package/output/algebra/utils.d.ts +1 -1
  37. package/output/algebra/utils.js +3 -3
  38. package/output/api/advanced.d.ts +2 -1
  39. package/output/api/advanced.js +3 -3
  40. package/output/api/algebra.d.ts +21 -4
  41. package/output/api/algebra.js +22 -3
  42. package/output/api/assumptions.d.ts +1 -1
  43. package/output/api/assumptions.js +2 -1
  44. package/output/api/calculus.d.ts +2 -1
  45. package/output/api/calculus.js +2 -1
  46. package/output/api/core.d.ts +28 -7
  47. package/output/api/core.js +28 -2
  48. package/output/api/languages/deu.d.ts +3 -0
  49. package/output/api/languages/deu.js +266 -0
  50. package/output/api/languages/fra.d.ts +3 -0
  51. package/output/api/languages/fra.js +266 -0
  52. package/output/api/languages/ita.d.ts +3 -0
  53. package/output/api/languages/ita.js +266 -0
  54. package/output/api/languages/nld.d.ts +3 -0
  55. package/output/api/languages/nld.js +266 -0
  56. package/output/api/languages/por.d.ts +3 -0
  57. package/output/api/languages/por.js +266 -0
  58. package/output/api/languages/spa.d.ts +3 -0
  59. package/output/api/languages/spa.js +266 -0
  60. package/output/api/parser.d.ts +10 -2
  61. package/output/api/parser.js +2 -0
  62. package/output/api/solve.d.ts +1 -1
  63. package/output/api/solve.js +2 -1
  64. package/output/api/structures.d.ts +1 -1
  65. package/output/api/structures.js +2 -1
  66. package/output/calculus/adapters.d.ts +8 -0
  67. package/output/calculus/adapters.js +41 -0
  68. package/output/calculus/derivative/diff.js +6 -3
  69. package/output/calculus/dispatch.d.ts +1 -0
  70. package/output/calculus/dispatch.js +25 -0
  71. package/output/calculus/integrate/integrate.js +4 -4
  72. package/output/calculus/integrate/integrationTable.js +16 -16
  73. package/output/calculus/laplace/ilaplace.js +1 -1
  74. package/output/calculus/laplace/ilaplaceTable.js +18 -17
  75. package/output/calculus/laplace/laplaceTable.js +3 -2
  76. package/output/calculus/limit/limit.js +1 -1
  77. package/output/core/classes/assumption/Assumption.js +14 -10
  78. package/output/core/classes/assumption/assume.d.ts +6 -0
  79. package/output/core/classes/assumption/assume.js +9 -0
  80. package/output/core/classes/assumption/dispatch.d.ts +1 -0
  81. package/output/core/classes/assumption/dispatch.js +11 -0
  82. package/output/core/classes/collection/Collection.js +11 -2
  83. package/output/core/classes/complex/Complex.d.ts +10 -0
  84. package/output/core/classes/complex/Complex.js +19 -1
  85. package/output/core/classes/decimalSet/DecimalSet.js +5 -4
  86. package/output/core/classes/dictionary/Dictionary.js +4 -1
  87. package/output/core/classes/expression/CoeffObject.d.ts +1 -1
  88. package/output/core/classes/expression/CoeffObject.js +1 -2
  89. package/output/core/classes/expression/Expression.d.ts +35 -26
  90. package/output/core/classes/expression/Expression.js +77 -50
  91. package/output/core/classes/expression/analysis.d.ts +1 -1
  92. package/output/core/classes/expression/analysis.js +7 -7
  93. package/output/core/classes/expression/format.d.ts +9 -0
  94. package/output/core/classes/expression/format.js +130 -7
  95. package/output/core/classes/expression/utils.d.ts +9 -0
  96. package/output/core/classes/expression/utils.js +52 -6
  97. package/output/core/classes/matrix/Matrix.d.ts +2 -3
  98. package/output/core/classes/matrix/Matrix.js +26 -23
  99. package/output/core/classes/matrix/dispatch.d.ts +1 -0
  100. package/output/core/classes/matrix/dispatch.js +19 -0
  101. package/output/core/classes/matrix/functions.d.ts +2 -0
  102. package/output/core/classes/matrix/functions.js +5 -0
  103. package/output/core/classes/parser/Parser.d.ts +31 -5
  104. package/output/core/classes/parser/Parser.js +357 -444
  105. package/output/core/classes/parser/constants.d.ts +2 -0
  106. package/output/core/classes/parser/constants.js +4 -2
  107. package/output/core/classes/parser/controlFlowSignals.d.ts +38 -0
  108. package/output/core/classes/parser/controlFlowSignals.js +60 -0
  109. package/output/core/classes/parser/operations/add.js +14 -16
  110. package/output/core/classes/parser/operations/compare.js +13 -0
  111. package/output/core/classes/parser/operations/functions.d.ts +3 -4
  112. package/output/core/classes/parser/operations/functions.js +48 -102
  113. package/output/core/classes/parser/operations/multiply.js +22 -15
  114. package/output/core/classes/parser/operations/power.js +11 -11
  115. package/output/core/classes/parser/operations/subtract.js +2 -1
  116. package/output/core/classes/parser/preprocess.d.ts +0 -7
  117. package/output/core/classes/parser/preprocess.js +33 -39
  118. package/output/core/classes/parser/scripting/controlFlow.d.ts +4 -102
  119. package/output/core/classes/parser/scripting/controlFlow.js +134 -186
  120. package/output/core/classes/parser/scripting/deferred.d.ts +4 -0
  121. package/output/core/classes/parser/scripting/deferred.js +65 -0
  122. package/output/core/classes/parser/scripting/dispatch.d.ts +1 -0
  123. package/output/core/classes/parser/scripting/dispatch.js +62 -0
  124. package/output/core/classes/parser/scripting/evaluate.d.ts +13 -0
  125. package/output/core/classes/parser/scripting/evaluate.js +17 -1
  126. package/output/core/classes/parser/scripting/scope.d.ts +1 -28
  127. package/output/core/classes/parser/scripting/scope.js +36 -40
  128. package/output/core/classes/parser/types.d.ts +5 -5
  129. package/output/core/classes/parser/wrappers/IndexedReference.d.ts +4 -3
  130. package/output/core/classes/parser/wrappers/IndexedReference.js +8 -0
  131. package/output/core/classes/parser/wrappers/KeyValuePair.d.ts +2 -2
  132. package/output/core/classes/polynomial/Polynomial.d.ts +5 -1
  133. package/output/core/classes/polynomial/Polynomial.js +53 -7
  134. package/output/core/classes/polynomial/SparsePolynomial.d.ts +221 -0
  135. package/output/core/classes/polynomial/SparsePolynomial.js +824 -0
  136. package/output/core/classes/polynomial/SparsePolynomialAdapter.d.ts +56 -0
  137. package/output/core/classes/polynomial/SparsePolynomialAdapter.js +241 -0
  138. package/output/core/classes/polynomial/Term.js +2 -2
  139. package/output/core/{adapters.d.ts → classes/polynomial/adapters.d.ts} +2 -2
  140. package/output/core/classes/polynomial/adapters.js +33 -0
  141. package/output/core/classes/polynomial/dispatch.d.ts +1 -0
  142. package/output/core/classes/polynomial/dispatch.js +14 -0
  143. package/output/core/classes/polynomial/functions.d.ts +8 -0
  144. package/output/core/classes/polynomial/functions.js +71 -8
  145. package/output/core/classes/polynomial/utils.js +2 -1
  146. package/output/core/classes/rational/Rational.d.ts +8 -11
  147. package/output/core/classes/rational/Rational.js +70 -20
  148. package/output/core/classes/seq/SEQ.js +4 -4
  149. package/output/core/classes/valuesSet/ValuesSet.d.ts +9 -1
  150. package/output/core/classes/valuesSet/ValuesSet.js +22 -4
  151. package/output/core/classes/vector/Vector.d.ts +2 -3
  152. package/output/core/classes/vector/Vector.js +11 -15
  153. package/output/core/classes/vector/dispatch.d.ts +1 -0
  154. package/output/core/classes/vector/dispatch.js +11 -0
  155. package/output/core/common/classes/MathematicalAggregate.js +11 -2
  156. package/output/core/common/classes/StructuredEntity.d.ts +0 -17
  157. package/output/core/common/classes/StructuredEntity.js +3 -64
  158. package/output/core/common/common.d.ts +0 -1
  159. package/output/core/common/common.js +29 -234
  160. package/output/core/converters/BaseConverter.js +3 -2
  161. package/output/core/converters/Converter.js +9 -5
  162. package/output/core/converters/Pattern.js +1 -1
  163. package/output/core/dispatch.d.ts +18 -0
  164. package/output/core/dispatch.js +3 -281
  165. package/output/core/errors.d.ts +259 -474
  166. package/output/core/errors.js +270 -542
  167. package/output/core/fullFunctions.d.ts +7 -0
  168. package/output/core/fullFunctions.js +31 -0
  169. package/output/core/functions/bigint/bigint.d.ts +13 -1
  170. package/output/core/functions/bigint/bigint.js +56 -4
  171. package/output/core/functions/bigint/primeFactor.d.ts +2 -0
  172. package/output/core/functions/bigint/primeFactor.js +13 -13
  173. package/output/core/functions/build/definitions.js +6 -0
  174. package/output/core/functions/complex.d.ts +2 -2
  175. package/output/core/functions/complex.dispatch.d.ts +1 -0
  176. package/output/core/functions/complex.dispatch.js +16 -0
  177. package/output/core/functions/complex.js +7 -7
  178. package/output/core/functions/decimal.js +2 -1
  179. package/output/core/functions/expand/expand.js +2 -2
  180. package/output/core/functions/numeric.d.ts +1 -1
  181. package/output/core/functions/string.js +2 -1
  182. package/output/core/functions/subst.js +21 -13
  183. package/output/core/parserFunctions.d.ts +7 -0
  184. package/output/core/parserFunctions.js +25 -0
  185. package/output/index.d.ts +50 -30
  186. package/output/index.js +147 -19
  187. package/output/math/defint/defint.d.ts +18 -0
  188. package/output/math/defint/defint.js +60 -0
  189. package/output/math/defint/defintDecimal.js +6 -5
  190. package/output/math/defint/defintNative.js +7 -18
  191. package/output/math/dispatch.d.ts +1 -0
  192. package/output/math/dispatch.js +101 -0
  193. package/output/math/geometry.d.ts +4 -0
  194. package/output/math/geometry.js +23 -0
  195. package/output/math/math.d.ts +59 -19
  196. package/output/math/math.js +244 -100
  197. package/output/math/trig.js +4 -4
  198. package/output/math/utils.d.ts +6 -0
  199. package/output/math/utils.js +39 -0
  200. package/output/solve/classes/PolynomialSolver.d.ts +33 -14
  201. package/output/solve/classes/PolynomialSolver.js +267 -67
  202. package/output/solve/classes/SolutionSet.d.ts +20 -1
  203. package/output/solve/classes/SolutionSet.js +82 -5
  204. package/output/solve/dispatch.d.ts +1 -0
  205. package/output/solve/dispatch.js +13 -0
  206. package/output/solve/linsolve.d.ts +2 -0
  207. package/output/solve/linsolve.js +13 -5
  208. package/output/solve/solve.d.ts +10 -0
  209. package/output/solve/solve.js +128 -20
  210. package/output/solve/solveSystem.d.ts +1 -1
  211. package/output/solve/solveSystem.js +8 -32
  212. package/output/solve/utils.d.ts +2 -1
  213. package/output/solve/utils.js +18 -22
  214. package/output/utils/array.d.ts +1 -1
  215. package/output/utils/debug.js +2 -1
  216. package/package.json +22 -38
  217. package/dist/parser.js +0 -2
  218. package/dist/parser.js.LICENSE.txt +0 -7
  219. package/docs-data/parser-functions.json +0 -1960
  220. package/output/algebra/algorithms/factor.d.ts +0 -3
  221. package/output/algebra/algorithms/factor.js +0 -5
  222. package/output/algebra/algorithms/factorMultivariate.d.ts +0 -23
  223. package/output/algebra/algorithms/factorMultivariate.js +0 -2393
  224. package/output/algebra/algorithms/factorUnivariate.d.ts +0 -72
  225. package/output/algebra/algorithms/factorUnivariate.js +0 -1072
  226. package/output/algebra/algorithms/gcd.d.ts +0 -22
  227. package/output/algebra/algorithms/gcd.js +0 -690
  228. package/output/algebra/algorithms/multiPoly/MultiPoly.d.ts +0 -137
  229. package/output/algebra/algorithms/multiPoly/MultiPoly.js +0 -346
  230. package/output/algebra/algorithms/poly.d.ts +0 -228
  231. package/output/algebra/algorithms/poly.js +0 -1299
  232. package/output/algebra/algorithms/rational.d.ts +0 -17
  233. package/output/algebra/algorithms/rational.js +0 -115
  234. package/output/core/adapters.js +0 -40
  235. package/output/core/classes/parser/operations/comma.d.ts +0 -7
  236. package/output/core/classes/parser/operations/comma.js +0 -11
@@ -402,8 +402,8 @@ function tan(x) {
402
402
  retval = Expression_1.Expression.Number(x.getMultiplier().toDecimal().tan());
403
403
  }
404
404
  else if (Settings_1.Settings.EVALUATE && x.isComplex()) {
405
- const dblRe = x.realPart().times(2);
406
- const dblIm = x.imagPart().times(2);
405
+ const dblRe = x.realPart().times((0, shortcuts_1.two)());
406
+ const dblIm = x.imagPart().times((0, shortcuts_1.two)());
407
407
  const d = cos(dblRe).plus(cosh(dblIm));
408
408
  retval = sin(dblRe).div(d).plus(sinh(dblIm).div(d).i());
409
409
  }
@@ -599,7 +599,7 @@ function acos(x) {
599
599
  let retval;
600
600
  if (Settings_1.Settings.EVALUATE && x.isNUM()) {
601
601
  // Becomes complex between [-1, 1]
602
- if (x.lt(-1) || x.gt(1)) {
602
+ if (x.lt((0, shortcuts_1.minusOne)()) || x.gt((0, shortcuts_1.one)())) {
603
603
  const sgn = x.sign();
604
604
  const halfPi = Expression_1.Expression.Pi().div((0, shortcuts_1.two)());
605
605
  let asinX = asin(x.abs());
@@ -1225,7 +1225,7 @@ function acosh(x) {
1225
1225
  retval = Expression_1.Expression.Pi().div((0, shortcuts_1.two)()).times(Expression_1.Expression.Img());
1226
1226
  }
1227
1227
  else if (Settings_1.Settings.EVALUATE) {
1228
- if (x.isComplex() || x.lt('1')) {
1228
+ if (x.isComplex() || x.lt((0, shortcuts_1.one)())) {
1229
1229
  const a = (0, math_1.sqrt)(x.plus((0, shortcuts_1.one)()));
1230
1230
  const b = (0, math_1.sqrt)(x.minus((0, shortcuts_1.one)()));
1231
1231
  const c = x.plus(a.times(b));
@@ -1,6 +1,12 @@
1
+ import { Collection } from '../core/classes/collection/Collection';
1
2
  import { Expression } from '../core/classes/expression/Expression';
2
3
  export { product, stripPower, sum } from '../core/classes/expression/utils';
3
4
  import type { ExpressionInput, ParserEntity } from '../core/types';
5
+ /**
6
+ * Returns the continued-fraction decomposition as a Collection containing
7
+ * sign, whole part, and a Vector of partial quotients.
8
+ */
9
+ export declare function continuedFraction(x: ExpressionInput, depth?: ExpressionInput): Collection;
4
10
  /**
5
11
  * Contains useful functions which are not likely to be exported to the user through `build`
6
12
  */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.sum = exports.stripPower = exports.product = void 0;
4
+ exports.continuedFraction = continuedFraction;
4
5
  exports.toFactor = toFactor;
5
6
  exports.roots = roots;
6
7
  exports.getCombinations = getCombinations;
@@ -23,7 +24,45 @@ const Matrix_1 = require("../core/classes/matrix/Matrix");
23
24
  const constants_1 = require("../core/classes/parser/constants");
24
25
  const ValuesSet_1 = require("../core/classes/valuesSet/ValuesSet");
25
26
  const Vector_1 = require("../core/classes/vector/Vector");
27
+ const errors_1 = require("../core/errors");
26
28
  const primeFactor_1 = require("../core/functions/bigint/primeFactor");
29
+ /**
30
+ * Returns the continued-fraction decomposition as a Collection containing
31
+ * sign, whole part, and a Vector of partial quotients.
32
+ */
33
+ function continuedFraction(x, depth = 10) {
34
+ const input = Expression_1.Expression.create(x);
35
+ const limitExpression = Expression_1.Expression.create(depth);
36
+ if (!limitExpression.isNUM() ||
37
+ !limitExpression.isInteger() ||
38
+ limitExpression.lt((0, shortcuts_1.zero)()) ||
39
+ limitExpression.getMultiplier().numerator > BigInt(Number.MAX_SAFE_INTEGER)) {
40
+ throw new errors_1.UnexpectedInputError((0, errors_1.message)('wrongInput', {
41
+ expected: 'a non-negative integer',
42
+ received: limitExpression.text(),
43
+ }));
44
+ }
45
+ const limit = Number(limitExpression.getMultiplier().numerator);
46
+ const evaluated = input.isConstant() ? input.evaluate() : input;
47
+ if (!evaluated.isNUM()) {
48
+ return new Collection_1.Collection([(0, shortcuts_1.one)(), input, new Vector_1.Vector()]);
49
+ }
50
+ const rational = evaluated.getMultiplier();
51
+ const sign = Expression_1.Expression.Number(rational.sign());
52
+ const numerator = rational.numerator < 0n ? -rational.numerator : rational.numerator;
53
+ let denominator = rational.denominator;
54
+ const whole = numerator / denominator;
55
+ let remainder = numerator % denominator;
56
+ const fractions = [];
57
+ for (let i = 0; i < limit && remainder !== 0n; i++) {
58
+ const quotient = denominator / remainder;
59
+ fractions.push(Expression_1.Expression.Number(quotient));
60
+ const nextRemainder = denominator % remainder;
61
+ denominator = remainder;
62
+ remainder = nextRemainder;
63
+ }
64
+ return new Collection_1.Collection([sign, Expression_1.Expression.Number(whole), new Vector_1.Vector(fractions)]);
65
+ }
27
66
  /**
28
67
  * Contains useful functions which are not likely to be exported to the user through `build`
29
68
  */
@@ -6,8 +6,8 @@ import { Polynomial } from '../../core/classes/polynomial/Polynomial';
6
6
  * Finds all complex roots of a univariate polynomial numerically.
7
7
  *
8
8
  * Coefficient arrays use ascending powers: the element at index `k` is the
9
- * coefficient of `x^k`. Polynomial and string inputs are converted to that
10
- * representation before solving. Linear and quadratic inputs are handled
9
+ * coefficient of `x^k`. Expression, Polynomial, and string inputs are converted directly
10
+ * to numerical complex coefficients before solving. Linear and quadratic inputs are handled
11
11
  * directly; higher degrees use simultaneous Aberth iteration followed by
12
12
  * Newton refinement.
13
13
  *
@@ -36,37 +36,50 @@ export declare class PolynomialSolver {
36
36
  /**
37
37
  * Creates a polynomial root solver.
38
38
  *
39
- * @param input - A polynomial, a polynomial string, or ascending-power
40
- * coefficients.
39
+ * @param input - A polynomial expression, Polynomial, polynomial string, or ascending-power
40
+ * Decimal coefficients.
41
41
  * @param variable - Variable expected in polynomial or string input. It is used to reject
42
42
  * a conflicting variable or multivariate polynomial.
43
43
  * @param precision - Working `decimal.js` precision used while finding roots.
44
44
  * @param epsilon - Numerical convergence tolerance. Defaults to `1e-14`.
45
- * @throws {@link core!UnexpectedInputError} If polynomial or string input is multivariate or
46
- * uses a variable different from `variable`.
45
+ * @throws {@link core!UnexpectedInputError} If symbolic input is multivariate, uses a
46
+ * variable different from `variable`, or has nonnumeric coefficients.
47
47
  */
48
- constructor(input: Decimal[] | Polynomial | string, variable?: string, precision?: number, epsilon?: Decimal);
48
+ constructor(input: Decimal[] | Polynomial | Expression | string, variable?: string, precision?: number, epsilon?: Decimal);
49
49
  /**
50
50
  * Aberth method: simultaneous approximation of all roots
51
51
  * More stable than deflation for high-degree polynomials
52
52
  */
53
53
  private aberthMethod;
54
+ private complexSqrt;
54
55
  /**
55
- * Compute Cauchy bound for root magnitudes
56
+ * Evaluates a polynomial and its derivative together using Horner's method.
56
57
  */
57
- private cauchyBound;
58
- private complexSqrt;
58
+ private evaluateWithDerivative;
59
59
  private finalize;
60
+ private isNumericalRoot;
61
+ /**
62
+ * Uses native double-precision arithmetic to locate starting points for Decimal refinement.
63
+ *
64
+ * Returning `null` leaves the existing Decimal Aberth implementation responsible for the
65
+ * complete solve.
66
+ */
67
+ private nativeAberthSeeds;
60
68
  /**
61
69
  * Refine a single root using Newton's method
62
70
  */
63
71
  private newtonRefine;
64
- private solveQuadratic;
65
72
  /**
66
- * Synthetic division
67
- * Returns [P(s), quotient Q] where P(x) = (x-s)*Q(x) + P(s)
73
+ * Computes a Lagrange-Fujiwara upper bound for root magnitudes.
74
+ *
75
+ * For a polynomial with leading coefficient a_n, every root lies within
76
+ * 2 * max(|a_(n-i) / a_n|^(1/i)). This is substantially tighter than the
77
+ * simple Cauchy bound for polynomials with large middle coefficients.
78
+ *
79
+ * @see https://doi.org/10.1016/S0377-0427(03)00381-9
68
80
  */
69
- private syntheticDiv;
81
+ private rootMagnitudeBound;
82
+ private solveQuadratic;
70
83
  /**
71
84
  * Computes the roots of the configured polynomial.
72
85
  *
@@ -82,4 +95,10 @@ export declare class PolynomialSolver {
82
95
  */
83
96
  roots(asExpressions?: true): Expression[];
84
97
  roots(asExpressions?: false): Complex[];
98
+ /**
99
+ * Computes roots numerically, rejects candidates with an excessive polynomial residual,
100
+ * and converts accepted values only after numerical validation is complete.
101
+ */
102
+ validatedRoots(asExpressions?: true): Expression[];
103
+ validatedRoots(asExpressions?: false): Complex[];
85
104
  }
@@ -9,6 +9,7 @@ const Complex_1 = require("../../core/classes/complex/Complex");
9
9
  const Expression_1 = require("../../core/classes/expression/Expression");
10
10
  const Polynomial_1 = require("../../core/classes/polynomial/Polynomial");
11
11
  const errors_1 = require("../../core/errors");
12
+ const bigint_1 = require("../../core/functions/bigint/bigint");
12
13
  const DEFAULT_PRECISION = 50;
13
14
  const DEFAULT_EPSILON = 1e-14;
14
15
  const ABERTH_MAX_ITERATIONS = 100;
@@ -18,12 +19,13 @@ const ABERTH_ROOT_SPACING_SCALE = 0.01;
18
19
  const ABERTH_CONVERGENCE_SCALE = 1e-2;
19
20
  const NEWTON_MAX_ITERATIONS = 20;
20
21
  const NEWTON_CONVERGENCE_SCALE = 1e-6;
22
+ const NATIVE_EPSILON_SCALE = 16;
21
23
  /**
22
24
  * Finds all complex roots of a univariate polynomial numerically.
23
25
  *
24
26
  * Coefficient arrays use ascending powers: the element at index `k` is the
25
- * coefficient of `x^k`. Polynomial and string inputs are converted to that
26
- * representation before solving. Linear and quadratic inputs are handled
27
+ * coefficient of `x^k`. Expression, Polynomial, and string inputs are converted directly
28
+ * to numerical complex coefficients before solving. Linear and quadratic inputs are handled
27
29
  * directly; higher degrees use simultaneous Aberth iteration followed by
28
30
  * Newton refinement.
29
31
  *
@@ -52,33 +54,73 @@ class PolynomialSolver {
52
54
  /**
53
55
  * Creates a polynomial root solver.
54
56
  *
55
- * @param input - A polynomial, a polynomial string, or ascending-power
56
- * coefficients.
57
+ * @param input - A polynomial expression, Polynomial, polynomial string, or ascending-power
58
+ * Decimal coefficients.
57
59
  * @param variable - Variable expected in polynomial or string input. It is used to reject
58
60
  * a conflicting variable or multivariate polynomial.
59
61
  * @param precision - Working `decimal.js` precision used while finding roots.
60
62
  * @param epsilon - Numerical convergence tolerance. Defaults to `1e-14`.
61
- * @throws {@link core!UnexpectedInputError} If polynomial or string input is multivariate or
62
- * uses a variable different from `variable`.
63
+ * @throws {@link core!UnexpectedInputError} If symbolic input is multivariate, uses a
64
+ * variable different from `variable`, or has nonnumeric coefficients.
63
65
  */
64
66
  constructor(input, variable, precision = DEFAULT_PRECISION, epsilon) {
65
- // Allow for input to be a string
66
- if (typeof input === 'string') {
67
- input = new Polynomial_1.Polynomial(input);
67
+ let coefficients;
68
+ if (Array.isArray(input)) {
69
+ coefficients = input.map(coefficient => new Complex_1.Complex(coefficient, 0));
68
70
  }
69
- if (Polynomial_1.Polynomial.isPolynomial(input)) {
70
- const vars = input.variables;
71
- // Expect the input to be a univariate polynomial
72
- if (vars.length > 1 || (vars.length === 1 && variable && vars[0] !== variable)) {
71
+ else {
72
+ const polynomialInput = Polynomial_1.Polynomial.isPolynomial(input);
73
+ const expression = polynomialInput
74
+ ? input.getExpression()
75
+ : typeof input === 'string'
76
+ ? Expression_1.Expression.create(input)
77
+ : input;
78
+ const variables = polynomialInput ? input.variables : expression.variables();
79
+ if (!expression.isPolynomialLike()) {
80
+ throw new errors_1.PolynomialError((0, errors_1.message)('notAPolynomial'));
81
+ }
82
+ if (variables.length > 1 ||
83
+ (variables.length === 1 && variable && variables[0] !== variable)) {
73
84
  throw new errors_1.UnexpectedInputError((0, errors_1.message)('tooManyUnknowns'));
74
85
  }
86
+ const coefficientVariable = variable ?? variables[0];
87
+ const coefficientExpressions = coefficientVariable === undefined
88
+ ? [expression]
89
+ : expression.coeffs(coefficientVariable).toArray();
90
+ const numericComponents = coefficientExpressions.map(coefficient => {
91
+ const real = coefficient.realPart();
92
+ const imaginary = coefficient.imagPart();
93
+ if (!real.isNUM() || !imaginary.isNUM()) {
94
+ throw new errors_1.UnexpectedInputError((0, errors_1.message)('wrongInput', {
95
+ expected: 'numeric polynomial coefficients',
96
+ received: coefficient.text(),
97
+ }));
98
+ }
99
+ return {
100
+ real: real.getMultiplier(),
101
+ imaginary: imaginary.getMultiplier(),
102
+ };
103
+ });
104
+ const exactRationals = numericComponents.every(component => !component.real.asDecimal && !component.imaginary.asDecimal);
105
+ if (exactRationals) {
106
+ const commonDenominator = (0, bigint_1.LCM)(...numericComponents.flatMap(component => [
107
+ component.real.denominator,
108
+ component.imaginary.denominator,
109
+ ]));
110
+ coefficients = numericComponents.map(component => {
111
+ const real = component.real.numerator *
112
+ (commonDenominator / component.real.denominator);
113
+ const imaginary = component.imaginary.numerator *
114
+ (commonDenominator / component.imaginary.denominator);
115
+ return new Complex_1.Complex(new decimal_js_1.default(String(real)), new decimal_js_1.default(String(imaginary)));
116
+ });
117
+ }
118
+ else {
119
+ coefficients = numericComponents.map(component => new Complex_1.Complex(component.real.toDecimal(), component.imaginary.toDecimal()));
120
+ }
75
121
  }
76
- const coefficients = Polynomial_1.Polynomial.isPolynomial(input) ? input.toDecimalArray() : input;
77
122
  // Reverse the coefficients so p[0] is the leading coefficient
78
- this.p = coefficients
79
- .slice()
80
- .reverse()
81
- .map(c => new Complex_1.Complex(c, 0));
123
+ this.p = coefficients.slice().reverse();
82
124
  this.degree = this.p.length - 1;
83
125
  this.eps = epsilon || new decimal_js_1.default(DEFAULT_EPSILON);
84
126
  this.precision = precision;
@@ -91,7 +133,7 @@ class PolynomialSolver {
91
133
  const n = P.length - 1;
92
134
  // Initialize roots on a circle
93
135
  const roots = [];
94
- const radius = this.cauchyBound(P);
136
+ const radius = this.rootMagnitudeBound(P);
95
137
  for (let k = 0; k < n; k++) {
96
138
  const angle = new decimal_js_1.default(2).mul(Math.PI).mul(k).div(n).plus(ABERTH_INITIAL_ANGLE_OFFSET);
97
139
  const r = radius
@@ -99,16 +141,18 @@ class PolynomialSolver {
99
141
  .mul(new decimal_js_1.default(1).plus(new decimal_js_1.default(k).mul(ABERTH_ROOT_SPACING_SCALE).div(n)));
100
142
  roots.push(new Complex_1.Complex(r.mul(decimal_js_1.default.cos(angle)), r.mul(decimal_js_1.default.sin(angle))));
101
143
  }
144
+ const epsSquared = this.eps.mul(this.eps);
145
+ const convergenceTolerance = this.eps.mul(ABERTH_CONVERGENCE_SCALE);
146
+ const convergenceToleranceSquared = convergenceTolerance.mul(convergenceTolerance);
102
147
  // Aberth iterations
103
148
  for (let iter = 0; iter < ABERTH_MAX_ITERATIONS; iter++) {
104
- let maxChange = new decimal_js_1.default(0);
149
+ let maxChangeSquared = new decimal_js_1.default(0);
105
150
  const newRoots = [];
106
151
  for (let i = 0; i < n; i++) {
107
152
  const z = roots[i];
108
- // Compute P(z) and P'(z)
109
- const [pz, qp] = this.syntheticDiv(n, P, z);
110
- const [dpz, _] = this.syntheticDiv(n - 1, qp, z);
111
- if (dpz.abs().lessThan(this.eps)) {
153
+ // Compute P(z) and P'(z) together.
154
+ const [pz, dpz] = this.evaluateWithDerivative(P, z);
155
+ if (dpz.absSquared().lessThan(epsSquared)) {
112
156
  newRoots.push(z);
113
157
  continue;
114
158
  }
@@ -119,28 +163,28 @@ class PolynomialSolver {
119
163
  for (let j = 0; j < n; j++) {
120
164
  if (i !== j) {
121
165
  const diff = z.sub(roots[j]);
122
- if (diff.abs().greaterThan(this.eps)) {
123
- sum = sum.add(new Complex_1.Complex(1, 0).div(diff));
166
+ if (diff.absSquared().greaterThan(epsSquared)) {
167
+ sum = sum.add(diff.reciprocal());
124
168
  }
125
169
  }
126
170
  }
127
171
  // Aberth correction: w = N(z) / (1 - N(z) * sum)
128
172
  const denom = new Complex_1.Complex(1, 0).sub(newton.mul(sum));
129
- const correction = denom.abs().lessThan(this.eps)
173
+ const correction = denom.absSquared().lessThan(epsSquared)
130
174
  ? newton
131
175
  : newton.div(denom);
132
176
  const newZ = z.sub(correction);
133
177
  newRoots.push(newZ);
134
- const change = correction.abs();
135
- if (change.greaterThan(maxChange)) {
136
- maxChange = change;
178
+ const changeSquared = correction.absSquared();
179
+ if (changeSquared.greaterThan(maxChangeSquared)) {
180
+ maxChangeSquared = changeSquared;
137
181
  }
138
182
  }
139
183
  for (let i = 0; i < n; i++) {
140
184
  roots[i] = newRoots[i];
141
185
  }
142
186
  // Check convergence
143
- if (maxChange.lessThan(this.eps.mul(ABERTH_CONVERGENCE_SCALE))) {
187
+ if (maxChangeSquared.lessThan(convergenceToleranceSquared)) {
144
188
  break;
145
189
  }
146
190
  }
@@ -150,20 +194,6 @@ class PolynomialSolver {
150
194
  }
151
195
  return roots;
152
196
  }
153
- /**
154
- * Compute Cauchy bound for root magnitudes
155
- */
156
- cauchyBound(P) {
157
- const n = P.length - 1;
158
- let maxRatio = new decimal_js_1.default(0);
159
- for (let i = 1; i <= n; i++) {
160
- const ratio = P[i].abs().div(P[0].abs());
161
- if (ratio.greaterThan(maxRatio)) {
162
- maxRatio = ratio;
163
- }
164
- }
165
- return maxRatio.plus(1);
166
- }
167
197
  complexSqrt(z) {
168
198
  const mag = z.abs();
169
199
  if (mag.isZero()) {
@@ -189,6 +219,20 @@ class PolynomialSolver {
189
219
  return new Complex_1.Complex(absY.div(w.mul(2)), imPart);
190
220
  }
191
221
  }
222
+ /**
223
+ * Evaluates a polynomial and its derivative together using Horner's method.
224
+ */
225
+ evaluateWithDerivative(P, z) {
226
+ const n = P.length - 1;
227
+ let value = P[0];
228
+ let derivative = P[0];
229
+ for (let i = 1; i < n; i++) {
230
+ value = value.mul(z).add(P[i]);
231
+ derivative = derivative.mul(z).add(value);
232
+ }
233
+ value = value.mul(z).add(P[n]);
234
+ return [value, derivative];
235
+ }
192
236
  finalize(roots, asExpressions, precision, cleanupComponents = true) {
193
237
  // Restore the precision
194
238
  decimal_js_1.default.set({ precision: precision });
@@ -208,22 +252,154 @@ class PolynomialSolver {
208
252
  }
209
253
  return roots;
210
254
  }
255
+ isNumericalRoot(root) {
256
+ let residual = this.p[0];
257
+ let scale = this.p[0].abs();
258
+ const magnitude = root.abs();
259
+ for (let i = 1; i < this.p.length; i++) {
260
+ residual = residual.mul(root).add(this.p[i]);
261
+ scale = scale.mul(magnitude).plus(this.p[i].abs());
262
+ }
263
+ const tolerance = this.eps.mul(scale.plus(1));
264
+ return residual.absSquared().lte(tolerance.mul(tolerance));
265
+ }
266
+ /**
267
+ * Uses native double-precision arithmetic to locate starting points for Decimal refinement.
268
+ *
269
+ * Returning `null` leaves the existing Decimal Aberth implementation responsible for the
270
+ * complete solve.
271
+ */
272
+ nativeAberthSeeds(P) {
273
+ const n = P.length - 1;
274
+ const nativeP = [];
275
+ for (const coefficient of P) {
276
+ const re = coefficient.re.toNumber();
277
+ const im = coefficient.im.toNumber();
278
+ if (!Number.isFinite(re) || !Number.isFinite(im)) {
279
+ return null;
280
+ }
281
+ nativeP.push({ re, im });
282
+ }
283
+ const leadMagnitude = Math.hypot(nativeP[0].re, nativeP[0].im);
284
+ if (!Number.isFinite(leadMagnitude) || leadMagnitude === 0) {
285
+ return null;
286
+ }
287
+ const radius = this.rootMagnitudeBound(P).toNumber();
288
+ if (!Number.isFinite(radius)) {
289
+ return null;
290
+ }
291
+ const roots = [];
292
+ for (let k = 0; k < n; k++) {
293
+ const angle = (2 * Math.PI * k) / n + ABERTH_INITIAL_ANGLE_OFFSET;
294
+ const r = radius *
295
+ ABERTH_RADIUS_SCALE *
296
+ (1 + (k * ABERTH_ROOT_SPACING_SCALE) / n);
297
+ roots.push({ re: r * Math.cos(angle), im: r * Math.sin(angle) });
298
+ }
299
+ const nativeTolerance = Math.max(this.eps.toNumber(), Number.EPSILON * NATIVE_EPSILON_SCALE);
300
+ const epsSquared = nativeTolerance * nativeTolerance;
301
+ for (let iter = 0; iter < ABERTH_MAX_ITERATIONS; iter++) {
302
+ let maxChangeSquared = 0;
303
+ const newRoots = [];
304
+ for (let i = 0; i < n; i++) {
305
+ const z = roots[i];
306
+ let valueRe = nativeP[0].re;
307
+ let valueIm = nativeP[0].im;
308
+ let derivativeRe = nativeP[0].re;
309
+ let derivativeIm = nativeP[0].im;
310
+ for (let k = 1; k < n; k++) {
311
+ const nextValueRe = valueRe * z.re - valueIm * z.im + nativeP[k].re;
312
+ const nextValueIm = valueRe * z.im + valueIm * z.re + nativeP[k].im;
313
+ const nextDerivativeRe = derivativeRe * z.re - derivativeIm * z.im + nextValueRe;
314
+ const nextDerivativeIm = derivativeRe * z.im + derivativeIm * z.re + nextValueIm;
315
+ valueRe = nextValueRe;
316
+ valueIm = nextValueIm;
317
+ derivativeRe = nextDerivativeRe;
318
+ derivativeIm = nextDerivativeIm;
319
+ }
320
+ const finalValueRe = valueRe * z.re - valueIm * z.im + nativeP[n].re;
321
+ const finalValueIm = valueRe * z.im + valueIm * z.re + nativeP[n].im;
322
+ const derivativeMagnitudeSquared = derivativeRe * derivativeRe + derivativeIm * derivativeIm;
323
+ if (!Number.isFinite(finalValueRe) ||
324
+ !Number.isFinite(finalValueIm) ||
325
+ !Number.isFinite(derivativeMagnitudeSquared)) {
326
+ return null;
327
+ }
328
+ if (derivativeMagnitudeSquared < epsSquared) {
329
+ newRoots.push(z);
330
+ continue;
331
+ }
332
+ const newtonRe = (finalValueRe * derivativeRe + finalValueIm * derivativeIm) /
333
+ derivativeMagnitudeSquared;
334
+ const newtonIm = (finalValueIm * derivativeRe - finalValueRe * derivativeIm) /
335
+ derivativeMagnitudeSquared;
336
+ let sumRe = 0;
337
+ let sumIm = 0;
338
+ for (let j = 0; j < n; j++) {
339
+ if (i === j) {
340
+ continue;
341
+ }
342
+ const diffRe = z.re - roots[j].re;
343
+ const diffIm = z.im - roots[j].im;
344
+ const diffMagnitudeSquared = diffRe * diffRe + diffIm * diffIm;
345
+ if (diffMagnitudeSquared > epsSquared) {
346
+ sumRe += diffRe / diffMagnitudeSquared;
347
+ sumIm -= diffIm / diffMagnitudeSquared;
348
+ }
349
+ }
350
+ const productRe = newtonRe * sumRe - newtonIm * sumIm;
351
+ const productIm = newtonRe * sumIm + newtonIm * sumRe;
352
+ const denomRe = 1 - productRe;
353
+ const denomIm = -productIm;
354
+ const denomMagnitudeSquared = denomRe * denomRe + denomIm * denomIm;
355
+ let correctionRe = newtonRe;
356
+ let correctionIm = newtonIm;
357
+ if (denomMagnitudeSquared >= epsSquared) {
358
+ correctionRe =
359
+ (newtonRe * denomRe + newtonIm * denomIm) / denomMagnitudeSquared;
360
+ correctionIm =
361
+ (newtonIm * denomRe - newtonRe * denomIm) / denomMagnitudeSquared;
362
+ }
363
+ const newRoot = {
364
+ re: z.re - correctionRe,
365
+ im: z.im - correctionIm,
366
+ };
367
+ const changeSquared = correctionRe * correctionRe + correctionIm * correctionIm;
368
+ if (!Number.isFinite(newRoot.re) ||
369
+ !Number.isFinite(newRoot.im) ||
370
+ !Number.isFinite(changeSquared)) {
371
+ return null;
372
+ }
373
+ newRoots.push(newRoot);
374
+ maxChangeSquared = Math.max(maxChangeSquared, changeSquared);
375
+ }
376
+ for (let i = 0; i < n; i++) {
377
+ roots[i] = newRoots[i];
378
+ }
379
+ if (maxChangeSquared < epsSquared) {
380
+ break;
381
+ }
382
+ }
383
+ return roots.map(root => new Complex_1.Complex(new decimal_js_1.default(root.re), new decimal_js_1.default(root.im)));
384
+ }
211
385
  /**
212
386
  * Refine a single root using Newton's method
213
387
  */
214
388
  newtonRefine(P, z) {
389
+ const epsSquared = this.eps.mul(this.eps);
390
+ const convergenceTolerance = this.eps.mul(NEWTON_CONVERGENCE_SCALE);
391
+ const convergenceToleranceSquared = convergenceTolerance.mul(convergenceTolerance);
215
392
  for (let iter = 0; iter < NEWTON_MAX_ITERATIONS; iter++) {
216
- const [pz, qp] = this.syntheticDiv(P.length - 1, P, z);
217
- if (pz.abs().lessThan(this.eps.mul(NEWTON_CONVERGENCE_SCALE))) {
393
+ const [pz, dpz] = this.evaluateWithDerivative(P, z);
394
+ if (pz.absSquared().lessThan(convergenceToleranceSquared)) {
218
395
  break;
219
396
  }
220
- const [dpz, _] = this.syntheticDiv(P.length - 2, qp, z);
221
- if (dpz.abs().lessThan(this.eps)) {
397
+ if (dpz.absSquared().lessThan(epsSquared)) {
222
398
  break;
223
399
  }
224
400
  const correction = pz.div(dpz);
225
401
  const newZ = z.sub(correction);
226
- if (correction.abs().lessThan(this.eps.mul(NEWTON_CONVERGENCE_SCALE).mul(newZ.abs().plus(1)))) {
402
+ if (correction.abs().lessThan(convergenceTolerance.mul(newZ.abs().plus(1)))) {
227
403
  z = newZ;
228
404
  break;
229
405
  }
@@ -231,6 +407,29 @@ class PolynomialSolver {
231
407
  }
232
408
  return z;
233
409
  }
410
+ /**
411
+ * Computes a Lagrange-Fujiwara upper bound for root magnitudes.
412
+ *
413
+ * For a polynomial with leading coefficient a_n, every root lies within
414
+ * 2 * max(|a_(n-i) / a_n|^(1/i)). This is substantially tighter than the
415
+ * simple Cauchy bound for polynomials with large middle coefficients.
416
+ *
417
+ * @see https://doi.org/10.1016/S0377-0427(03)00381-9
418
+ */
419
+ rootMagnitudeBound(P) {
420
+ let maxCandidate = new decimal_js_1.default(0);
421
+ const leadingMagnitude = P[0].abs();
422
+ for (let i = 1; i < P.length; i++) {
423
+ const ratio = P[i].abs().div(leadingMagnitude);
424
+ if (!ratio.isZero()) {
425
+ const candidate = ratio.pow(new decimal_js_1.default(1).div(i));
426
+ if (candidate.greaterThan(maxCandidate)) {
427
+ maxCandidate = candidate;
428
+ }
429
+ }
430
+ }
431
+ return maxCandidate.mul(2);
432
+ }
234
433
  solveQuadratic(p) {
235
434
  const a = p[0];
236
435
  const b = p[1];
@@ -243,22 +442,6 @@ class PolynomialSolver {
243
442
  const negB = b.neg();
244
443
  return [negB.add(sqrtDisc).div(twoA), negB.sub(sqrtDisc).div(twoA)];
245
444
  }
246
- /**
247
- * Synthetic division
248
- * Returns [P(s), quotient Q] where P(x) = (x-s)*Q(x) + P(s)
249
- */
250
- syntheticDiv(n, P, s) {
251
- const Q = [];
252
- let b = P[0];
253
- Q[0] = b;
254
- for (let i = 1; i <= n; i++) {
255
- b = b.mul(s).add(P[i]);
256
- if (i < n) {
257
- Q[i] = b;
258
- }
259
- }
260
- return [b, Q];
261
- }
262
445
  roots(asExpressions = true) {
263
446
  // Store the currently used precision
264
447
  const precision = decimal_js_1.default.precision;
@@ -284,9 +467,26 @@ class PolynomialSolver {
284
467
  // treating them as iterative noise.
285
468
  return this.finalize(this.solveQuadratic(poly), asExpressions, precision, false);
286
469
  }
287
- // For degree >= 3, use Aberth method for better numerical stability
470
+ // Native doubles are sufficient to locate ordinary roots. Refine those seeds with
471
+ // Decimal arithmetic and accept them only when every root passes the existing residual check.
472
+ const nativeSeeds = this.nativeAberthSeeds(poly);
473
+ if (nativeSeeds) {
474
+ const nativeRoots = nativeSeeds.map(root => this.newtonRefine(poly, root));
475
+ if (nativeRoots.length === deg &&
476
+ nativeRoots.every(root => this.isNumericalRoot(root))) {
477
+ return this.finalize(nativeRoots, asExpressions, precision);
478
+ }
479
+ }
480
+ // Fall back to the Decimal Aberth implementation when native seeding is unavailable
481
+ // or does not survive Decimal refinement and validation.
288
482
  const roots = this.aberthMethod(poly);
289
483
  return this.finalize(roots, asExpressions, precision);
290
484
  }
485
+ validatedRoots(asExpressions = true) {
486
+ const precision = decimal_js_1.default.precision;
487
+ decimal_js_1.default.set({ precision: this.precision });
488
+ const roots = this.roots(false).filter(root => this.isNumericalRoot(root));
489
+ return this.finalize(roots, asExpressions, precision);
490
+ }
291
491
  }
292
492
  exports.PolynomialSolver = PolynomialSolver;