LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
exact_algebraic.cpp
浏览该文件的文档.
2
5
6#include <algorithm>
7#include <cmath>
8#include <exception>
9#include <utility>
10#include <vector>
11
12namespace LMCAS::detail {
13namespace {
14
15constexpr const char* kOperation = "exact_algebraic";
16
18 polynomial.trim();
19 if (polynomial.is_zero()) return polynomial;
20 const Rational leading = polynomial.lead_coeff();
21 for (auto& coefficient : polynomial.coeffs) coefficient = coefficient / leading;
22 polynomial.trim();
23 return polynomial;
24}
25
28 return lhs.variable_name == rhs.variable_name && lhs.coeffs == rhs.coeffs;
29}
30
31bool overlaps(const Rational& lhs_lower, const Rational& lhs_upper,
32 const Rational& rhs_lower, const Rational& rhs_upper) {
33 return !(lhs_upper < rhs_lower) && !(rhs_upper < lhs_lower);
34}
35
36int sign(const Rational& value) {
37 if (value < Rational(0)) return -1;
38 if (value > Rational(0)) return 1;
39 return 0;
40}
41
43 const ExactRealAlgebraic& lhs, const ExactRealAlgebraic& rhs,
45 auto common = monic(Polynomial<Rational>::gcd(lhs.polynomial, rhs.polynomial));
46 if (common.degree() < 1) {
47 return Result<bool>::success(false);
48 }
49 auto isolated = isolate_real_roots_exact(
50 common, context, "exact_algebraic.equal");
51 if (!isolated) {
52 return Result<bool>::failure(isolated.error());
53 }
54 for (const auto& interval : isolated.value()) {
55 if (overlaps(lhs.lower, lhs.upper, interval.first, interval.second) &&
56 overlaps(rhs.lower, rhs.upper, interval.first, interval.second)) {
57 return Result<bool>::success(true);
58 }
59 }
60 return Result<bool>::success(false);
61}
62
63} // namespace
64
66 Polynomial<Rational> polynomial,
67 std::size_t root_index,
68 std::size_t multiplicity,
70 if (polynomial.degree() < 1) {
73 "an algebraic value requires a non-constant polynomial",
74 kOperation);
75 }
76 if (multiplicity == 0) {
79 "algebraic root multiplicity must be positive",
80 kOperation);
81 }
82 auto step = context.consume_steps(1, kOperation);
83 if (!step) return ExactRealAlgebraicResult::failure(step.error());
84
85 try {
86 polynomial = monic(std::move(polynomial));
87 auto rational_roots = find_rational_roots(polynomial);
88 std::sort(rational_roots.begin(), rational_roots.end());
89 rational_roots.erase(
90 std::unique(rational_roots.begin(), rational_roots.end()),
91 rational_roots.end());
92 if (rational_roots.size() ==
93 static_cast<std::size_t>(polynomial.degree())) {
94 if (root_index >= rational_roots.size()) {
97 "real algebraic root index is out of range",
98 kOperation);
99 }
101 std::move(polynomial), rational_roots[root_index],
102 rational_roots[root_index], root_index, multiplicity});
103 }
104 auto isolated = isolate_real_roots_exact(
105 polynomial, context, kOperation);
106 if (!isolated) {
107 return ExactRealAlgebraicResult::failure(isolated.error());
108 }
109 const auto& intervals = isolated.value();
110 if (root_index >= intervals.size()) {
113 "real algebraic root index is out of range",
114 kOperation);
115 }
117 std::move(polynomial), intervals[root_index].first,
118 intervals[root_index].second, root_index, multiplicity});
119 } catch (const std::bad_alloc&) {
122 "algebraic root isolation allocation failed",
123 kOperation);
124 } catch (const std::exception& error) {
126 CasErrc::InternalInvariant, error.what(), kOperation);
127 }
128}
129
133 const std::string& operation) {
134 auto step = context.consume_steps(1, operation);
135 if (!step) return step;
136 if (value.lower == value.upper) return Result<void>::success();
137
138 const Rational lower_value = value.polynomial.eval(value.lower);
139 if (lower_value == Rational(0)) {
140 value.upper = value.lower;
141 return Result<void>::success();
142 }
143 const Rational upper_value = value.polynomial.eval(value.upper);
144 if (upper_value == Rational(0)) {
145 value.lower = value.upper;
146 return Result<void>::success();
147 }
148
149 const Rational midpoint = (value.lower + value.upper) / Rational(2);
150 const Rational midpoint_value = value.polynomial.eval(midpoint);
151 if (midpoint_value == Rational(0)) {
152 value.lower = midpoint;
153 value.upper = midpoint;
154 return Result<void>::success();
155 }
156
157 if (sign(lower_value) != sign(midpoint_value)) {
158 value.upper = midpoint;
159 } else {
160 value.lower = midpoint;
161 }
162 return Result<void>::success();
163}
164
165
170 auto step = context.consume_steps(1, "exact_algebraic.equal");
171 if (!step) {
172 return Result<bool>::failure(step.error());
173 }
174 if (!overlaps(lhs.lower, lhs.upper, rhs.lower, rhs.upper)) {
175 return Result<bool>::success(false);
176 }
177 if (same_polynomial(lhs.polynomial, rhs.polynomial)) {
178 return Result<bool>::success(lhs.root_index == rhs.root_index);
179 }
180
181 const Rational overlap_lower =
182 lhs.lower < rhs.lower ? rhs.lower : lhs.lower;
183 const Rational overlap_upper =
184 lhs.upper < rhs.upper ? lhs.upper : rhs.upper;
185 if (overlap_lower == overlap_upper &&
186 (lhs.polynomial.eval(overlap_lower) != Rational(0) ||
187 rhs.polynomial.eval(overlap_lower) != Rational(0))) {
188 return Result<bool>::success(false);
189 }
190
191 try {
192 return common_root_in_enclosures(lhs, rhs, context);
193 } catch (const std::bad_alloc&) {
196 "algebraic equality allocation failed",
197 "exact_algebraic.equal");
198 } catch (const std::exception& error) {
201 error.what(),
202 "exact_algebraic.equal");
203 }
204}
205
210 auto equal = equal_exact_real_algebraic(lhs, rhs, context);
211 if (!equal) {
212 return Result<int>::failure(equal.error());
213 }
214 if (equal.value()) {
215 return Result<int>::success(0);
216 }
217
218 while (true) {
219 if (lhs.upper < rhs.lower) {
220 return Result<int>::success(-1);
221 }
222 if (rhs.upper < lhs.lower) {
223 return Result<int>::success(1);
224 }
225 const double lhs_width = (lhs.upper - lhs.lower).to_double();
226 const double rhs_width = (rhs.upper - rhs.lower).to_double();
227 const double width = std::max(lhs_width, rhs_width);
228 if (!(width > 0.0) || !std::isfinite(width)) {
231 "distinct algebraic values retained an inseparable enclosure",
232 "exact_algebraic.compare");
233 }
234 if (lhs_width > 0.0) {
236 lhs, width / 16.0, 1e-15, context,
237 "exact_algebraic.compare");
238 if (!refined) {
239 return Result<int>::failure(refined.error());
240 }
241 }
242 if (rhs_width > 0.0) {
244 rhs, width / 16.0, 1e-15, context,
245 "exact_algebraic.compare");
246 if (!refined) {
247 return Result<int>::failure(refined.error());
248 }
249 }
250 }
251}
252
253} // namespace LMCAS::detail
一元多项式模板类
static Polynomial gcd(Polynomial a, Polynomial b)
计算两个多项式的最大公因式
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
void trim()
去除高次零系数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
bool overlaps(const Rational &lhs_lower, const Rational &lhs_upper, const Rational &rhs_lower, const Rational &rhs_upper)
Polynomial< Rational > monic(Polynomial< Rational > polynomial)
bool same_polynomial(const Polynomial< Rational > &lhs, const Polynomial< Rational > &rhs)
Result< bool > common_root_in_enclosures(const ExactRealAlgebraic &lhs, const ExactRealAlgebraic &rhs, ComputationContext &context)
多元 Hensel 提升(单变量步)
Result< std::vector< RationalInterval > > isolate_real_roots_exact(const Polynomial< Rational > &polynomial, ComputationContext &context, const std::string &operation)
Result< void > refine_exact_real_algebraic_to_tolerance(ExactRealAlgebraic &value, double absolute_tolerance, double relative_tolerance, ComputationContext &context, const std::string &operation)
ExactRealAlgebraic rhs
Result< int > compare_exact_real_algebraic(ExactRealAlgebraic lhs, ExactRealAlgebraic rhs, ComputationContext &context)
std::size_t std::size_t multiplicity
Result< void > refine_exact_real_algebraic(ExactRealAlgebraic &value, ComputationContext &context, const std::string &operation)
ComputationContext const std::string & operation
Result< ExactRealAlgebraic > ExactRealAlgebraicResult
ExactRealAlgebraicResult make_exact_real_algebraic(Polynomial< Rational > polynomial, std::size_t root_index, std::size_t multiplicity, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
Result< bool > equal_exact_real_algebraic(ExactRealAlgebraic lhs, ExactRealAlgebraic rhs, ComputationContext &context)
ExprResult e()
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
std::vector< Rational > find_rational_roots(const Polynomial< Rational > &poly)
const std::string const ExprPtr & value