LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
exact_algebraic_refinement.cpp
浏览该文件的文档.
3
4#include <algorithm>
5#include <cmath>
6#include <exception>
7
8namespace LMCAS::detail {
9namespace {
10
12 Rational base;
13 Rational span;
14 Rational fraction;
16};
17
19 double point) {
20 double result = 0.0;
21 for (std::size_t position = polynomial.coeffs.size(); position-- > 0;) {
22 result = result * point + polynomial.coeffs[position].to_double();
23 }
24 return result;
25}
26
28 double lower = value.lower.to_double();
29 double upper = value.upper.to_double();
30 double lower_value = evaluate_polynomial_double(value.polynomial, lower);
31 for (int iteration = 0; iteration < 128; ++iteration) {
32 const double midpoint = (lower + upper) * 0.5;
33 const double midpoint_value = evaluate_polynomial_double(value.polynomial, midpoint);
34 if (!std::isfinite(midpoint_value) || midpoint_value == 0.0) {
35 lower = midpoint;
36 upper = midpoint;
37 break;
38 }
39 if ((lower_value < 0.0) != (midpoint_value < 0.0)) {
40 upper = midpoint;
41 } else {
42 lower = midpoint;
43 lower_value = midpoint_value;
44 }
45 }
46 return (lower + upper) * 0.5;
47}
48
51 double relative_tolerance, const std::string& operation) {
52 const Rational base = value.lower;
53 const Rational span = value.upper - value.lower;
54 const double approximation = approximate_root(value);
55 const double target_tolerance = absolute_tolerance +
56 relative_tolerance * std::abs(approximation);
57 const double span_double = span.to_double();
58 double requested_depth = 1.0;
59 if (span_double > 2.0 * target_tolerance) {
60 requested_depth = std::ceil(std::log2(
61 span_double / (2.0 * target_tolerance))) + 2.0;
62 }
63 if (!std::isfinite(approximation) || !std::isfinite(target_tolerance) ||
64 !std::isfinite(span_double) || !std::isfinite(requested_depth) ||
65 requested_depth > 60.0) {
68 "requested algebraic tolerance is finer than the double evaluation boundary",
69 operation);
70 }
71 const int initial_depth = static_cast<int>(std::max(1.0, requested_depth));
72 const Rational fraction = std::clamp(
73 (Rational::from_double(approximation) - base) / span,
74 Rational(0), Rational(1));
76 DyadicProposal{base, span, fraction, initial_depth});
77}
78
80 ExactRealAlgebraic& value, const DyadicProposal& proposal,
81 const BigInt& candidate, const BigInt& scale,
82 ComputationContext& context, const std::string& operation) {
83 const Rational lower = proposal.base + proposal.span * Rational(candidate, scale);
84 const Rational upper = proposal.base + proposal.span * Rational(candidate + BigInt(1), scale);
85 auto count = count_real_roots_exact(value.polynomial, lower, upper, context, operation);
86 if (!count) return Result<bool>::failure(count.error());
87 if (count.value() != 1) return Result<bool>::success(false);
88 value.lower = lower;
89 value.upper = upper;
90 return Result<bool>::success(true);
91}
92
94 ExactRealAlgebraic& value, const DyadicProposal& proposal, int depth,
95 ComputationContext& context, const std::string& operation) {
96 auto step = context.consume_steps(1, operation);
97 if (!step) {
98 return Result<bool>::failure(step.error());
99 }
100 auto bits = context.require_integer_bits(static_cast<std::size_t>(depth) + 1, operation);
101 if (!bits) {
102 return Result<bool>::failure(bits.error());
103 }
104 const BigInt scale = BigInt(1) << depth;
105 BigInt center = (proposal.fraction.get_numerator() * scale) /
106 proposal.fraction.get_denominator();
107 if (center >= scale) {
108 center = scale - BigInt(1);
109 }
110 for (int radius = 0; radius <= 16; ++radius) {
111 for (int direction : {radius == 0 ? 0 : -1, radius == 0 ? 0 : 1}) {
112 const BigInt candidate = center + BigInt(direction * radius);
113 if (candidate.is_negative() || candidate >= scale) {
114 continue;
115 }
116 auto certified = certify_dyadic_candidate(
117 value, proposal, candidate, scale, context, operation);
118 if (!certified || certified.value()) {
119 return certified;
120 }
121 if (radius == 0) {
122 break;
123 }
124 }
125 }
126 return Result<bool>::success(false);
127}
128
129}
130
133 ComputationContext& context, const std::string& operation) {
134 if (!(absolute_tolerance > 0.0) || !(relative_tolerance > 0.0) ||
135 !std::isfinite(absolute_tolerance) || !std::isfinite(relative_tolerance)) {
138 "algebraic refinement tolerances must be finite and positive", operation);
139 }
140 if (value.lower == value.upper) {
141 return Result<void>::success();
142 }
143 try {
144 auto proposal = propose_dyadic_bracket(
146 if (!proposal) {
147 return Result<void>::failure(proposal.error());
148 }
149 for (int depth = std::max(1, proposal.value().initial_depth); depth <= 60; ++depth) {
150 auto certified = search_dyadic_scale(value, proposal.value(), depth, context, operation);
151 if (!certified) {
152 return Result<void>::failure(certified.error());
153 }
154 if (certified.value()) {
155 return Result<void>::success();
156 }
157 }
160 "exact projection refinement could not certify the suggested bracket", operation);
161 } catch (const std::bad_alloc&) {
163 CasErrc::ResourceLimit, "algebraic refinement allocation failed", operation);
164 } catch (const std::exception& error) {
166 }
167}
168
169}
一元多项式模板类
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< bool > search_dyadic_scale(ExactRealAlgebraic &value, const DyadicProposal &proposal, int depth, ComputationContext &context, const std::string &operation)
double evaluate_polynomial_double(const Polynomial< Rational > &polynomial, double point)
Result< DyadicProposal > propose_dyadic_bracket(const ExactRealAlgebraic &value, double absolute_tolerance, double relative_tolerance, const std::string &operation)
Result< bool > certify_dyadic_candidate(ExactRealAlgebraic &value, const DyadicProposal &proposal, const BigInt &candidate, const BigInt &scale, ComputationContext &context, const std::string &operation)
多元 Hensel 提升(单变量步)
Result< void > refine_exact_real_algebraic_to_tolerance(ExactRealAlgebraic &value, double absolute_tolerance, double relative_tolerance, ComputationContext &context, const std::string &operation)
Result< std::size_t > count_real_roots_exact(const Polynomial< Rational > &polynomial, const Rational &lower, const Rational &upper, ComputationContext &context, const std::string &operation)
ComputationContext const std::string & operation
std::size_t std::size_t ComputationContext & context
double double relative_tolerance
const std::string const LimitExprPtr & point
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
const ExprPtr & lower
const std::string const LimitExprPtr LimitDirection direction
std::size_t std::size_t depth
const std::string const ExprPtr & value