LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
complex_root_rectangles.cpp
浏览该文件的文档.
3
4#include <algorithm>
5#include <utility>
6
8int rational_sign(const Rational& value) {
9 if (value < Rational(0)) return -1;
10 if (value > Rational(0)) return 1;
11 return 0;
12}
13
15 const Poly& polynomial,
18 const std::string& operation) {
19 auto step = context.consume_steps(1, operation);
20 if (!step) return step;
21 if (interval.first == interval.second) return Result<void>::success();
22 const Rational midpoint =
23 (interval.first + interval.second) / Rational(2);
24 const Rational middle_value = polynomial.eval(midpoint);
25 if (middle_value == Rational(0)) {
26 interval = {midpoint, midpoint};
27 return Result<void>::success();
28 }
29 const int lower_sign = rational_sign(polynomial.eval(interval.first));
30 if (lower_sign == 0) {
31 interval.second = interval.first;
32 } else if (lower_sign != rational_sign(middle_value)) {
33 interval.second = midpoint;
34 } else {
35 interval.first = midpoint;
36 }
37 return Result<void>::success();
38}
39
40namespace {
41
44 std::vector<RationalInterval> real_roots;
45 std::vector<RationalInterval> imaginary_roots;
46 std::vector<RationalInterval> real_bands;
47 std::vector<RationalInterval> imaginary_bands;
48};
49
51 const Poly& projection, RationalInterval& interval,
52 std::size_t index, std::size_t round,
53 ComputationContext& context, const std::string& operation) {
54 if (interval.first == interval.second) return Result<void>::success();
55 if (round < 8) return refine_interval(projection, interval, context, operation);
56 const double width = (interval.second - interval.first).to_double();
57 ExactRealAlgebraic value{projection, interval.first, interval.second, index, 1};
59 value, width / 16.0, 1e-15, context, operation);
60 if (!refined) return refined;
61 interval = {value.lower, value.upper};
62 return Result<void>::success();
63}
64
66 const Poly& projection, std::vector<RationalInterval>& intervals,
67 ComputationContext& context, const std::string& operation) {
68 if (intervals.size() < 2) return Result<void>::success();
69 bool separated = false;
70 std::size_t round = 0;
71 while (!separated) {
72 separated = true;
73 for (std::size_t index = 1; index < intervals.size(); ++index) {
74 if (intervals[index - 1].second < intervals[index].first) continue;
75 separated = false;
77 projection, intervals[index - 1], index - 1, round, context, operation);
78 if (!left) return left;
80 projection, intervals[index], index, round, context, operation);
81 if (!right) return right;
82 }
83 ++round;
84 }
85 return Result<void>::success();
86}
87
88std::vector<RationalInterval> projection_bands(
89 const std::vector<RationalInterval>& intervals,
90 const Rational& bound) {
91 std::vector<RationalInterval> bands;
92 bands.reserve(intervals.size());
93 for (std::size_t index = 0; index < intervals.size(); ++index) {
94 const Rational lower = index == 0
95 ? -bound
96 : (intervals[index - 1].second + intervals[index].first) /
97 Rational(2);
98 const Rational upper = index + 1 == intervals.size()
99 ? bound
100 : (intervals[index].second + intervals[index + 1].first) /
101 Rational(2);
102 bands.emplace_back(lower, upper);
103 }
104 return bands;
105}
106
107
109 const Poly& polynomial, ComputationContext& context,
110 const std::string& operation) {
111 auto projections = coordinate_projections(polynomial, context, operation);
112 if (!projections) return Result<ProjectionGrid>::failure(projections.error());
114 projections.value().real, context, operation + ".projection.real");
116 auto imaginary = isolate_real_roots_exact(
117 projections.value().imaginary, context, operation + ".projection.imaginary");
118 if (!imaginary) return Result<ProjectionGrid>::failure(imaginary.error());
119 auto real_separated = separate_projection_intervals(
120 projections.value().real, real.value(), context, operation + ".projection.real");
121 if (!real_separated) return Result<ProjectionGrid>::failure(real_separated.error());
122 auto imaginary_separated = separate_projection_intervals(
123 projections.value().imaginary, imaginary.value(), context,
124 operation + ".projection.imaginary");
125 if (!imaginary_separated) {
126 return Result<ProjectionGrid>::failure(imaginary_separated.error());
127 }
129 std::move(projections.value()), std::move(real.value()),
130 std::move(imaginary.value()), {}, {}});
131}
132
134 const Poly& projection, RationalInterval& interval,
135 ComputationContext& context, const std::string& operation) {
136 while (interval.first <= Rational(0) && interval.second >= Rational(0) &&
137 !(interval.first == Rational(0) && interval.second == Rational(0))) {
138 if (projection.eval(Rational(0)) == Rational(0)) {
139 interval = {Rational(0), Rational(0)};
140 break;
141 }
142 auto refined = refine_interval(projection, interval, context, operation);
143 if (!refined) return refined;
144 }
145 return Result<void>::success();
146}
147
149 ProjectionGrid& grid, std::size_t complex_count,
150 ComputationContext& context, const std::string& operation) {
151 bool have_positive = false;
152 bool have_negative = false;
153 for (auto& interval : grid.imaginary_roots) {
154 auto separated = separate_imaginary_axis(
156 if (!separated) return separated;
157 if (interval.first > Rational(0)) have_positive = true;
158 if (interval.second < Rational(0)) have_negative = true;
159 }
160 if (!have_positive || !have_negative || (complex_count & 1U) != 0) {
163 "non-real roots lacked conjugate imaginary projections", operation);
164 }
165 return Result<void>::success();
166}
167
169 const ProjectionGrid& grid, const RationalRectangle& rectangle,
170 std::size_t real_index, std::size_t imaginary_index) {
171 const auto& real_interval = grid.real_roots[real_index];
172 const auto& imaginary_interval = grid.imaginary_roots[imaginary_index];
173 return ComplexIsolation{
174 rectangle.real_lower, rectangle.real_upper,
175 rectangle.imaginary_lower, rectangle.imaginary_upper,
177 real_interval.first, real_interval.second, real_index, 1},
179 imaginary_interval.first, imaginary_interval.second, imaginary_index, 1}};
180}
181
183 const Poly& polynomial, const ProjectionGrid& grid, std::size_t real_index,
184 std::vector<ComplexIsolation>& roots, ComputationContext& context,
185 const std::string& operation) {
186 for (std::size_t imaginary_index = 0;
187 imaginary_index < grid.imaginary_bands.size(); ++imaginary_index) {
188 const auto& interval = grid.imaginary_roots[imaginary_index];
189 if (grid.projections.imaginary.eval(Rational(0)) == Rational(0) &&
190 interval.first <= Rational(0) && interval.second >= Rational(0)) continue;
191 const RationalRectangle rectangle{
192 grid.real_bands[real_index].first, grid.real_bands[real_index].second,
193 grid.imaginary_bands[imaginary_index].first,
194 grid.imaginary_bands[imaginary_index].second};
195 auto count = count_rectangle_roots(
196 polynomial, rectangle, context, operation + ".rectangles.projection_grid");
197 if (!count) return Result<void>::failure(count.error());
198 if (!count.value().boundary_clear || count.value().count > 1) {
201 "projection-band rectangle was not a clear one-root cell", operation);
202 }
203 if (count.value().count == 0) continue;
204 roots.push_back(make_cell_isolation(grid, rectangle, real_index, imaginary_index));
205 }
206 return Result<void>::success();
207}
208
209}
210
212 const Poly& polynomial, std::size_t complex_count,
213 ComputationContext& context, const std::string& operation) {
214 auto prepared = prepare_projection_grid(polynomial, context, operation);
215 if (!prepared) return Result<std::vector<ComplexIsolation>>::failure(prepared.error());
216 auto& grid = prepared.value();
217 auto conjugate = certify_conjugate_projections(grid, complex_count, context, operation);
218 if (!conjugate) return Result<std::vector<ComplexIsolation>>::failure(conjugate.error());
219 const Rational bound = strict_cauchy_root_bound(polynomial);
220 grid.real_bands = projection_bands(grid.real_roots, bound);
221 grid.imaginary_bands = projection_bands(grid.imaginary_roots, bound);
222 std::vector<ComplexIsolation> roots;
223 roots.reserve(complex_count);
224 for (std::size_t real_index = 0; real_index < grid.real_bands.size(); ++real_index) {
225 auto isolated = isolate_grid_row(polynomial, grid, real_index, roots, context, operation);
226 if (!isolated) return Result<std::vector<ComplexIsolation>>::failure(isolated.error());
227 }
228 if (roots.size() != complex_count) {
231 "projection-band rectangles did not cover every non-real root", operation);
232 }
233 std::sort(roots.begin(), roots.end(),
234 [](const ComplexIsolation& left, const ComplexIsolation& right) {
235 if (left.real_projection.root_index != right.real_projection.root_index) {
236 return left.real_projection.root_index < right.real_projection.root_index;
237 }
238 return left.imaginary_projection.root_index < right.imaginary_projection.root_index;
239 });
240 return Result<std::vector<ComplexIsolation>>::success(std::move(roots));
241}
242
243}
244
245namespace LMCAS::detail {
246
249 ComplexIsolation& isolation,
252 const std::string& operation) {
254 isolation.real_projection,
255 options.absolute_tolerance,
256 options.relative_tolerance,
257 context,
258 operation);
259 if (!real) return real;
261 isolation.imaginary_projection,
262 options.absolute_tolerance,
263 options.relative_tolerance,
264 context,
265 operation);
266 if (!imaginary) return imaginary;
267 isolation.real_lower = isolation.real_projection.lower;
268 isolation.real_upper = isolation.real_projection.upper;
269 isolation.imaginary_lower = isolation.imaginary_projection.lower;
270 isolation.imaginary_upper = isolation.imaginary_projection.upper;
271 return Result<void>::success();
272}
273
274}
一元多项式模板类
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< void > refine_projection_interval(const Poly &projection, RationalInterval &interval, std::size_t index, std::size_t round, ComputationContext &context, const std::string &operation)
Result< void > isolate_grid_row(const Poly &polynomial, const ProjectionGrid &grid, std::size_t real_index, std::vector< ComplexIsolation > &roots, ComputationContext &context, const std::string &operation)
Result< void > separate_projection_intervals(const Poly &projection, std::vector< RationalInterval > &intervals, ComputationContext &context, const std::string &operation)
Result< void > certify_conjugate_projections(ProjectionGrid &grid, std::size_t complex_count, ComputationContext &context, const std::string &operation)
std::vector< RationalInterval > projection_bands(const std::vector< RationalInterval > &intervals, const Rational &bound)
ComplexIsolation make_cell_isolation(const ProjectionGrid &grid, const RationalRectangle &rectangle, std::size_t real_index, std::size_t imaginary_index)
Result< ProjectionGrid > prepare_projection_grid(const Poly &polynomial, ComputationContext &context, const std::string &operation)
Result< void > separate_imaginary_axis(const Poly &projection, RationalInterval &interval, ComputationContext &context, const std::string &operation)
Result< CoordinateProjections > coordinate_projections(const Poly &polynomial, ComputationContext &context, const std::string &operation)
Result< std::vector< ComplexIsolation > > isolate_nonreal_roots(const Poly &polynomial, std::size_t complex_count, ComputationContext &context, const std::string &operation)
Result< RectangleCount > count_rectangle_roots(const Poly &polynomial, const RationalRectangle &rectangle, ComputationContext &context, const std::string &operation)
Result< void > refine_interval(const Poly &polynomial, RationalInterval &interval, 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)
ComputationContext const std::string & operation
std::pair< Rational, Rational > RationalInterval
std::size_t std::size_t ComputationContext & context
Rational strict_cauchy_root_bound(const Polynomial< Rational > &polynomial)
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 e()
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
const ExprPtr & right
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
ExprResult round(const ExprPtr &expression, ComputationContext &context)