LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
exact_root.cpp
浏览该文件的文档.
3
4
5#include <cmath>
6#include <algorithm>
7#include <limits>
8
9namespace LMCAS::detail {
10namespace {
11
13 return options.absolute_tolerance > 0.0 &&
14 options.relative_tolerance > 0.0 &&
15 std::isfinite(options.absolute_tolerance) &&
16 std::isfinite(options.relative_tolerance);
17}
18
19double conversion_ulp(double value) {
20 if (!std::isfinite(value)) {
21 return std::numeric_limits<double>::infinity();
22 }
23 const double upward = std::nextafter(
24 value, std::numeric_limits<double>::infinity());
25 const double downward = std::nextafter(
26 value, -std::numeric_limits<double>::infinity());
27 double spacing = 0.0;
28 if (std::isfinite(upward)) {
29 spacing = std::max(spacing, std::abs(upward - value));
30 }
31 if (std::isfinite(downward)) {
32 spacing = std::max(spacing, std::abs(value - downward));
33 }
34 return spacing;
35}
36
38 ExactRealAlgebraic isolation,
41 const std::string& operation) {
42 while (isolation.lower != isolation.upper) {
43 const bool positive = isolation.lower > Rational(0) &&
44 isolation.upper <= Rational(2) * isolation.lower;
45 const bool negative = isolation.upper < Rational(0) &&
46 isolation.lower >= Rational(2) * isolation.upper;
47 if (positive || negative) break;
48 auto narrowed = refine_exact_real_algebraic(isolation, context, operation);
49 if (!narrowed) return Result<ApproxReal>::failure(narrowed.error());
50 }
51 const double scale = std::min(
52 std::abs(isolation.lower.to_double()), std::abs(isolation.upper.to_double()));
53 const double absolute_tolerance = std::min(
54 options.absolute_tolerance,
55 std::max(std::numeric_limits<double>::denorm_min(),
56 options.relative_tolerance * scale));
58 isolation, absolute_tolerance, options.relative_tolerance,
60 if (!refined) return Result<ApproxReal>::failure(refined.error());
61 const double lower = isolation.lower.to_double();
62 const double upper = isolation.upper.to_double();
63 const double value = lower + (upper - lower) * 0.5;
64 const double error = std::abs(upper - lower) * 0.5 +
67 if (!std::isfinite(value) || !std::isfinite(error) ||
68 (value == 0.0 &&
69 (isolation.lower > Rational(0) || isolation.upper < Rational(0)))) {
72 "certified root enclosure could not be represented as finite double",
73 operation);
74 }
77}
78
80 const Rational& lower,
81 const Rational& upper) {
82 const double lower_value = lower.to_double();
83 const double upper_value = upper.to_double();
84 const double value =
85 lower_value + (upper_value - lower_value) * 0.5;
86 const double error = std::abs(upper_value - lower_value) * 0.5 +
87 conversion_ulp(lower_value) + conversion_ulp(upper_value) +
90}
91
92} // namespace
93
94
96 Polynomial<Rational> polynomial,
97 std::size_t index,
99 const std::string& operation) {
100 auto access = context.consume_steps(1, operation);
101 if (!access) return Result<ExactRootId>::failure(access.error());
102 try {
103 polynomial.trim();
104 if (polynomial.degree() <= 0) {
107 "RootOf requires a nonconstant exact rational polynomial",
108 operation);
109 }
110 polynomial = polynomial.square_free_part().make_monic();
111 polynomial.variable_name = "_root";
112 if (polynomial.degree() <= 0 ||
113 index >= static_cast<std::size_t>(polynomial.degree())) {
116 "RootOf index exceeds the number of distinct roots",
117 operation);
118 }
120 ExactRootId{std::move(polynomial), index});
121 } catch (const std::bad_alloc&) {
124 "RootOf canonicalization allocation failed", operation);
125 } catch (const std::exception& error) {
128 }
129}
130
132 const ExactRootId& root,
135 constexpr const char* operation = "rootof.evaluate_real";
136 if (!valid_options(options)) {
139 "root evaluation tolerances must be finite and positive",
140 operation);
141 }
142 if (root.index >= static_cast<std::size_t>(root.polynomial.degree())) {
145 "RootOf index exceeds the number of distinct roots",
146 operation);
147 }
148 auto real_roots = isolate_real_roots_exact(root.polynomial, context, operation);
149 if (!real_roots) return Result<ApproxReal>::failure(real_roots.error());
150 if (root.index >= real_roots.value().size()) {
153 "selected RootOf is not real",
154 operation);
155 }
156 const auto& interval = real_roots.value()[root.index];
157 return approximate_real_isolation(
158 ExactRealAlgebraic{root.polynomial, interval.first, interval.second, root.index, 1},
160}
161
163 const ExactRootId& root,
166 constexpr const char* operation = "rootof.evaluate_complex";
167 if (!valid_options(options)) {
170 "root evaluation tolerances must be finite and positive",
171 operation);
172 }
173 auto isolated = isolate_exact_root(root, context, operation);
174 if (!isolated) return Result<ApproxComplex>::failure(isolated.error());
175 if (auto* real = std::get_if<RealIsolation>(&isolated.value())) {
176 auto approximation = approximate_real_isolation(
177 std::move(real->value), options, context, operation);
178 if (!approximation) {
179 return Result<ApproxComplex>::failure(approximation.error());
180 }
182 approximation.value(),
184 }
185 auto complex = std::get<ComplexIsolation>(std::move(isolated.value()));
186 auto refined = refine_complex_isolation(
188 if (!refined) return Result<ApproxComplex>::failure(refined.error());
189 auto real_part = approximate_component(
190 complex.real_lower, complex.real_upper);
191 auto imaginary_part = approximate_component(
192 complex.imaginary_lower, complex.imaginary_upper);
193 if (!std::isfinite(real_part.value) ||
194 !std::isfinite(real_part.absolute_error) ||
195 !std::isfinite(imaginary_part.value) ||
196 !std::isfinite(imaginary_part.absolute_error)) {
199 "certified complex root enclosure could not be represented as finite double",
200 operation);
201 }
203 ApproxComplex{real_part, imaginary_part});
204}
205
206} // namespace LMCAS::detail
一元多项式模板类
std::string variable_name
变量名
Polynomial square_free_part() const
计算无平方因子部分
int degree() const
获取多项式的次数
Polynomial make_monic() const
首一化(使首项系数为 1)
void trim()
去除高次零系数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
ApproxReal approximate_component(const Rational &lower, const Rational &upper)
bool valid_options(const NumericEvaluationOptions &options)
Result< ApproxReal > approximate_real_isolation(ExactRealAlgebraic isolation, const NumericEvaluationOptions &options, ComputationContext &context, const std::string &operation)
多元 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)
Result< RootIsolation > isolate_exact_root(const ExactRootId &root, ComputationContext &context, const std::string &operation)
Result< ExactRootId > make_exact_root_id(Polynomial< Rational > polynomial, std::size_t index, ComputationContext &context, const std::string &operation)
Result< void > refine_exact_real_algebraic(ExactRealAlgebraic &value, ComputationContext &context, const std::string &operation)
ComputationContext const std::string & operation
Result< ApproxComplex > evaluate_root_complex(const ExactRootId &root, const NumericEvaluationOptions &options, ComputationContext &context)
Result< ApproxReal > evaluate_root_real(const ExactRootId &root, const NumericEvaluationOptions &options, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
Result< void > refine_complex_isolation(const Polynomial< Rational > &, ComplexIsolation &isolation, const NumericEvaluationOptions &options, ComputationContext &context, const std::string &operation)
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
const ExprPtr & lower
const std::string ComputationContext const SolveOptions & options
ExprResult complex(ExprPtr real, ExprPtr imag)
const std::string const ExprPtr & value
Polynomial< Rational > polynomial