LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
complex_root_isolation.cpp
浏览该文件的文档.
3
4#include <exception>
5#include <iterator>
6#include <optional>
7#include <utility>
8
9namespace LMCAS::detail {
10namespace {
11
13
14std::optional<Rational> exact_rational_square_root(
15 const Rational& value) {
16 if (value < Rational(0)) return std::nullopt;
17 const BigInt numerator = value.get_numerator();
18 const BigInt denominator = value.get_denominator();
19 const BigInt numerator_root = numerator.sqrt();
20 const BigInt denominator_root = denominator.sqrt();
21 if (numerator_root * numerator_root != numerator ||
22 denominator_root * denominator_root != denominator) {
23 return std::nullopt;
24 }
25 return Rational(numerator_root, denominator_root);
26}
27
28std::vector<Poly> factor_biquadratic(const Poly& polynomial) {
29 if (polynomial.degree() != 4 ||
30 polynomial.coeffs[1] != Rational(0) ||
31 polynomial.coeffs[3] != Rational(0)) {
32 return {};
33 }
34 const Rational& c = polynomial.coeffs[0];
35 const Rational& b = polynomial.coeffs[2];
36 const Rational& a = polynomial.coeffs[4];
37 const Rational discriminant = b * b - Rational(4) * a * c;
38 auto square_root = exact_rational_square_root(discriminant);
39 if (!square_root) return {};
40 const Rational first =
41 (-b - *square_root) / (Rational(2) * a);
42 const Rational second =
43 (-b + *square_root) / (Rational(2) * a);
44 if (first == second) return {};
45 return {
46 Poly({-first, Rational(0), Rational(1)}, polynomial.variable_name),
47 Poly({-second, Rational(0), Rational(1)}, polynomial.variable_name)};
48}
49
51 const RootIsolation& left,
52 const RootIsolation& right,
54 const auto* left_real = std::get_if<RealIsolation>(&left);
55 const auto* right_real = std::get_if<RealIsolation>(&right);
56 if (left_real && !right_real) {
57 return Result<int>::success(-1);
58 }
59 if (!left_real && right_real) {
60 return Result<int>::success(1);
61 }
62 if (left_real && right_real) {
64 left_real->value, right_real->value, context);
65 }
66 const auto& left_complex = std::get<ComplexIsolation>(left);
67 const auto& right_complex = std::get<ComplexIsolation>(right);
68 auto real_comparison = compare_exact_real_algebraic(
69 left_complex.real_projection,
70 right_complex.real_projection,
71 context);
72 if (!real_comparison || real_comparison.value() != 0) {
73 return real_comparison;
74 }
76 left_complex.imaginary_projection,
77 right_complex.imaginary_projection,
78 context);
79}
80
83 std::vector<RootIsolation> roots;
84 std::size_t step_cost = 1;
85};
86
87thread_local std::vector<RootIsolationCacheEntry> root_isolation_cache;
88
89bool same_polynomial(const Poly& left, const Poly& right) {
90 return left.coeffs == right.coeffs;
91}
92
94 std::vector<RootIsolation>& roots, ComputationContext& context) {
95 for (std::size_t index = 1; index < roots.size(); ++index) {
96 RootIsolation current = std::move(roots[index]);
97 std::size_t position = index;
98 while (position > 0) {
99 auto comparison = compare_isolations(roots[position - 1], current, context);
100 if (!comparison) return Result<void>::failure(comparison.error());
101 if (comparison.value() <= 0) break;
102 roots[position] = std::move(roots[position - 1]);
103 --position;
104 }
105 roots[position] = std::move(current);
106 }
107 return Result<void>::success();
108}
109
111 const Poly& polynomial, ComputationContext& context) {
112 auto factors = factor_biquadratic(polynomial);
113 if (factors.empty() && polynomial.degree() >= 6) {
114 auto factor_result = LMCAS::factor_univariate_bridge_checked(polynomial, context);
115 if (!factor_result) return Result<std::vector<Poly>>::failure(factor_result.error());
116 factors = std::move(factor_result.value().value);
117 }
118 if (factors.empty()) factors = {polynomial};
119 std::size_t factored_degree = 0;
120 bool strict_factorization = factors.size() > 1;
121 for (auto& factor : factors) {
122 factor = factor.square_free_part().make_monic();
123 factor.variable_name = "_root";
124 if (factor.degree() <= 0 || factor.degree() >= polynomial.degree()) {
125 strict_factorization = false;
126 break;
127 }
128 factored_degree += static_cast<std::size_t>(factor.degree());
129 }
130 if (!strict_factorization ||
131 factored_degree != static_cast<std::size_t>(polynomial.degree())) factors.clear();
132 return Result<std::vector<Poly>>::success(std::move(factors));
133}
134
136 const std::vector<Poly>& factors, std::size_t degree,
137 ComputationContext& context, const std::string& operation) {
138 std::vector<RootIsolation> combined;
139 combined.reserve(degree);
140 for (const auto& factor : factors) {
141 auto factor_roots = isolate_exact_roots(factor, context, operation + ".factor");
142 if (!factor_roots) return Result<std::vector<RootIsolation>>::failure(factor_roots.error());
143 combined.insert(combined.end(),
144 std::make_move_iterator(factor_roots.value().begin()),
145 std::make_move_iterator(factor_roots.value().end()));
146 }
147 auto ordered = order_isolations(combined, context);
148 if (!ordered) return Result<std::vector<RootIsolation>>::failure(ordered.error());
149 return Result<std::vector<RootIsolation>>::success(std::move(combined));
150}
151
153 const Poly& polynomial, ComputationContext& context,
154 const std::string& operation) {
155 auto real_roots = isolate_real_roots_exact(polynomial, context, operation + ".real");
156 if (!real_roots) return Result<std::vector<RootIsolation>>::failure(real_roots.error());
157 const std::size_t real_count = real_roots.value().size();
158 const std::size_t degree = static_cast<std::size_t>(polynomial.degree());
159 if (real_count > degree) {
160 return Result<std::vector<RootIsolation>>::failure(
161 CasErrc::InternalInvariant, "real-root count exceeded polynomial degree", operation);
162 }
163 std::vector<RootIsolation> result;
164 result.reserve(degree);
165 for (std::size_t index = 0; index < real_count; ++index) {
166 result.push_back(RealIsolation{ExactRealAlgebraic{
167 polynomial, real_roots.value()[index].first,
168 real_roots.value()[index].second, index, 1}});
169 }
170 if (real_count == degree) {
171 return Result<std::vector<RootIsolation>>::success(std::move(result));
172 }
173 const Poly certificate_polynomial = complex_root::clear_denominators(polynomial);
174 auto complex_roots = complex_root::isolate_nonreal_roots(
175 certificate_polynomial, degree - real_count, context, operation);
176 if (!complex_roots) return Result<std::vector<RootIsolation>>::failure(complex_roots.error());
177 for (auto& isolation : complex_roots.value()) result.push_back(std::move(isolation));
178 if (result.size() != degree) {
179 return Result<std::vector<RootIsolation>>::failure(
181 "certified root isolation did not cover the polynomial degree", operation);
182 }
183 return Result<std::vector<RootIsolation>>::success(std::move(result));
184}
185
187 const Poly& polynomial, std::vector<RootIsolation> roots, std::size_t step_cost) {
188 if (root_isolation_cache.size() >= 16) {
190 }
191 root_isolation_cache.push_back(RootIsolationCacheEntry{polynomial, roots, step_cost});
192 return Result<std::vector<RootIsolation>>::success(std::move(roots));
193}
194
195} // namespace
196
199 const std::string& operation) {
200 const std::size_t starting_steps = context.steps_used();
201 try {
202 auto step = context.consume_steps(1, operation);
203 if (!step) return Result<std::vector<RootIsolation>>::failure(step.error());
204 if (input.degree() <= 0) {
205 return Result<std::vector<RootIsolation>>::failure(
207 "exact root isolation requires a nonconstant polynomial", operation);
208 }
209 Poly polynomial = input.square_free_part().make_monic();
210 polynomial.variable_name = "_root";
211 for (const auto& entry : root_isolation_cache) {
212 if (!same_polynomial(entry.polynomial, polynomial)) continue;
213 const std::size_t remaining_cost = entry.step_cost > 0 ? entry.step_cost - 1 : 0;
214 auto cached_step = context.consume_steps(remaining_cost, operation + ".cache");
215 if (!cached_step) return Result<std::vector<RootIsolation>>::failure(cached_step.error());
216 return Result<std::vector<RootIsolation>>::success(entry.roots);
217 }
218 auto factors = strict_factors(polynomial, context);
219 if (!factors) return Result<std::vector<RootIsolation>>::failure(factors.error());
220 auto roots = factors.value().empty()
221 ? isolate_unfactored(polynomial, context, operation)
222 : isolate_factors(factors.value(), static_cast<std::size_t>(polynomial.degree()),
224 if (!roots) return roots;
225 return remember_isolations(polynomial, std::move(roots.value()),
226 context.steps_used() - starting_steps);
227 } catch (const std::bad_alloc&) {
228 return Result<std::vector<RootIsolation>>::failure(
229 CasErrc::ResourceLimit, "complex root isolation allocation failed", operation);
230 } catch (const std::exception& error) {
231 return Result<std::vector<RootIsolation>>::failure(
233 }
234}
235
237 const ExactRootId& root,
239 const std::string& operation) {
242 if (root.index >= roots.value().size()) {
245 "RootOf index exceeds the number of distinct roots",
246 operation);
247 }
249 std::move(roots.value()[root.index]));
250}
251
252} // namespace LMCAS::detail
一元多项式模板类
std::string variable_name
变量名
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
Polynomial square_free_part() const
计算无平方因子部分
int degree() const
获取多项式的次数
Polynomial make_monic() const
首一化(使首项系数为 1)
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< std::vector< Poly > > strict_factors(const Poly &polynomial, ComputationContext &context)
Result< std::vector< RootIsolation > > isolate_unfactored(const Poly &polynomial, ComputationContext &context, const std::string &operation)
Result< std::vector< RootIsolation > > isolate_factors(const std::vector< Poly > &factors, std::size_t degree, ComputationContext &context, const std::string &operation)
std::optional< Rational > exact_rational_square_root(const Rational &value)
Result< int > compare_isolations(const RootIsolation &left, const RootIsolation &right, ComputationContext &context)
Result< std::vector< RootIsolation > > remember_isolations(const Poly &polynomial, std::vector< RootIsolation > roots, std::size_t step_cost)
Result< void > order_isolations(std::vector< RootIsolation > &roots, ComputationContext &context)
Result< std::vector< ComplexIsolation > > isolate_nonreal_roots(const Poly &polynomial, std::size_t complex_count, ComputationContext &context, const std::string &operation)
多元 Hensel 提升(单变量步)
std::variant< RealIsolation, ComplexIsolation > RootIsolation
Result< std::vector< RationalInterval > > isolate_real_roots_exact(const Polynomial< Rational > &polynomial, ComputationContext &context, const std::string &operation)
Result< RootIsolation > isolate_exact_root(const ExactRootId &root, ComputationContext &context, const std::string &operation)
Result< int > compare_exact_real_algebraic(ExactRealAlgebraic lhs, ExactRealAlgebraic rhs, ComputationContext &context)
Result< std::vector< RootIsolation > > isolate_exact_roots(const Polynomial< Rational > &input, ComputationContext &context, const std::string &operation)
ComputationContext const std::string & operation
std::size_t std::size_t ComputationContext & context
const VectorField const VectorField & c
const MultiPoly & b
UnivariateFactorResult factor_univariate_bridge_checked(const Polynomial< Rational > &polynomial, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
const ExprPtr & right
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
const ExprPtr & denominator
Polynomial< Rational > polynomial