LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
complex_root_winding.cpp
浏览该文件的文档.
3
4#include <utility>
5
7namespace {
8
9std::pair<Poly, Poly> edge_image(
10 const Poly& polynomial,
11 const Rational& real_start,
12 const Rational& imaginary_start,
13 const Rational& real_delta,
14 const Rational& imaginary_delta) {
15 const Poly real_line(
16 std::vector<Rational>{real_start, real_delta}, "t");
17 const Poly imaginary_line(
18 std::vector<Rational>{imaginary_start, imaginary_delta}, "t");
19 Poly real("t");
20 Poly imaginary("t");
21 for (std::size_t position = polynomial.coeffs.size(); position-- > 0;) {
22 Poly next_real = real * real_line - imaginary * imaginary_line;
23 Poly next_imaginary = real * imaginary_line + imaginary * real_line;
24 if (next_real.coeffs.empty()) next_real.coeffs.resize(1, Rational(0));
25 next_real.coeffs[0] = next_real.coeffs[0] + polynomial.coeffs[position];
26 next_real.trim();
27 real = std::move(next_real);
28 imaginary = std::move(next_imaginary);
29 }
30 return {std::move(real), std::move(imaginary)};
31}
32
33std::vector<std::pair<Poly, Poly>> rectangle_edges(
34 const Poly& polynomial,
35 const RationalRectangle& rectangle) {
36 const Rational width = rectangle.real_upper - rectangle.real_lower;
37 const Rational height =
38 rectangle.imaginary_upper - rectangle.imaginary_lower;
39 std::vector<std::pair<Poly, Poly>> edges;
40 edges.reserve(4);
41 edges.push_back(edge_image(
42 polynomial, rectangle.real_lower, rectangle.imaginary_lower,
43 width, Rational(0)));
44 edges.push_back(edge_image(
45 polynomial, rectangle.real_upper, rectangle.imaginary_lower,
46 Rational(0), height));
47 edges.push_back(edge_image(
48 polynomial, rectangle.real_upper, rectangle.imaginary_upper,
49 -width, Rational(0)));
50 edges.push_back(edge_image(
51 polynomial, rectangle.real_lower, rectangle.imaginary_upper,
52 Rational(0), -height));
53 return edges;
54}
55
57 const Poly& real,
58 const Poly& imaginary,
60 const std::string& operation) {
61 if (real.eval(Rational(0)) == Rational(0) &&
62 imaginary.eval(Rational(0)) == Rational(0)) {
63 return Result<bool>::success(false);
64 }
65 if (real.eval(Rational(1)) == Rational(0) &&
66 imaginary.eval(Rational(1)) == Rational(0)) {
67 return Result<bool>::success(false);
68 }
69 Poly common = Poly::gcd(real, imaginary);
70 if (common.degree() <= 0) return Result<bool>::success(true);
72 common, Rational(0), Rational(1), context, operation);
73 if (!roots) return Result<bool>::failure(roots.error());
74 return Result<bool>::success(roots.value() == 0);
75}
76
78 const Poly& denominator, const Poly& numerator,
80 const std::string& operation) {
81 auto denominator_roots = count_real_roots_exact(
83 if (!denominator_roots) return Result<bool>::failure(denominator_roots.error());
84 auto numerator_roots = count_real_roots_exact(
85 numerator, interval.first, interval.second, context, operation);
86 if (!numerator_roots) return Result<bool>::failure(numerator_roots.error());
87 return Result<bool>::success(denominator_roots.value() == 1 &&
88 numerator_roots.value() == 0 &&
89 denominator.eval(interval.first) != Rational(0));
90}
91
93 const Poly& factor, const Poly& denominator, const Poly& numerator,
95 const std::string& operation) {
96 while (true) {
97 auto step = context.consume_steps(1, operation);
98 if (!step) {
99 return step;
100 }
101 if (interval.first == interval.second) {
102 break;
103 }
104 if (interval.second <= Rational(0) || interval.first >= Rational(1)) {
105 break;
106 }
107 if (interval.first > Rational(0) && interval.second < Rational(1)) {
108 auto clear = pole_interval_is_clear(
109 denominator, numerator, interval, context, operation);
110 if (!clear) {
111 return Result<void>::failure(clear.error());
112 }
113 if (clear.value()) {
114 break;
115 }
116 }
117 auto refined = refine_interval(factor, interval, context, operation);
118 if (!refined) {
119 return refined;
120 }
121 }
122 return Result<void>::success();
123}
124
126 const Poly& denominator, const Rational& root,
127 ComputationContext& context, const std::string& operation) {
128 Rational left_sample = root / Rational(2);
129 while (true) {
130 auto step = context.consume_steps(1, operation);
131 if (!step) return Result<Rational>::failure(step.error());
132 auto count = count_real_roots_exact(
133 denominator, left_sample, root, context, operation);
134 if (!count) return Result<Rational>::failure(count.error());
135 if (count.value() == 1 && denominator.eval(left_sample) != Rational(0)) break;
136 left_sample = (left_sample + root) / Rational(2);
137 }
138 return Result<Rational>::success(std::move(left_sample));
139}
140
142 const Poly& denominator, const Poly& numerator,
144 const std::string& operation) {
145 if (interval.second <= Rational(0) || interval.first >= Rational(1)) {
146 return Result<int>::success(0);
147 }
148 Rational numerator_sample;
149 Rational left_sample;
150 if (interval.first == interval.second) {
151 const Rational root = interval.first;
152 if (!(root > Rational(0) && root < Rational(1))) return Result<int>::success(0);
153 numerator_sample = root;
154 auto sample = left_pole_sample(denominator, root, context, operation);
155 if (!sample) return Result<int>::failure(sample.error());
156 left_sample = std::move(sample.value());
157 } else {
158 numerator_sample = (interval.first + interval.second) / Rational(2);
159 left_sample = interval.first;
160 }
161 const int denominator_left_sign = rational_sign(denominator.eval(left_sample));
162 const int numerator_sign = rational_sign(numerator.eval(numerator_sample));
163 if (denominator_left_sign == 0 || numerator_sign == 0) {
166 "Cauchy-index pole sign could not be certified", operation);
167 }
168 return Result<int>::success(denominator_left_sign * numerator_sign);
169}
170
172 const Poly& denominator, const Poly& numerator,
173 ComputationContext& context, const std::string& operation) {
174 int index = 0;
175 const auto factors = square_free_factorization(denominator);
176 for (const auto& [factor, multiplicity] : factors) {
177 if ((multiplicity & 1) == 0) continue;
179 if (!roots) return Result<int>::failure(roots.error());
180 for (auto interval : roots.value()) {
181 auto refined = refine_pole_interval(
182 factor, denominator, numerator, interval, context, operation);
183 if (!refined) return Result<int>::failure(refined.error());
184 auto contribution = pole_index(
185 denominator, numerator, interval, context, operation);
186 if (!contribution) return contribution;
187 index += contribution.value();
188 }
189 }
190 return Result<int>::success(index);
191}
192
193bool shear_is_valid(const std::vector<std::pair<Poly, Poly>>& edges,
194 const Rational& shear) {
195 for (const auto& [real, imaginary] : edges) {
196 const Poly denominator = real + scale_poly(imaginary, shear);
197 if (denominator.is_zero() ||
198 denominator.eval(Rational(0)) == Rational(0) ||
199 denominator.eval(Rational(1)) == Rational(0)) return false;
200 }
201 return true;
202}
203
205 const std::vector<std::pair<Poly, Poly>>& edges, const Rational& shear,
206 int degree, ComputationContext& context, const std::string& operation) {
207 int total_index = 0;
208 for (const auto& [real, imaginary] : edges) {
209 const Poly denominator = real + scale_poly(imaginary, shear);
210 auto edge_index = cauchy_index_on_edge(
211 denominator, imaginary, context, operation);
212 if (!edge_index) return Result<RectangleCount>::failure(edge_index.error());
213 total_index += edge_index.value();
214 }
215 if ((total_index & 1) != 0) {
218 "argument-principle Cauchy index was odd", operation);
219 }
220 const int count = total_index / 2;
221 if (count < 0 || count > degree) {
224 "argument-principle root count was outside polynomial degree", operation);
225 }
227 RectangleCount{true, static_cast<std::size_t>(count)});
228}
229
230}
231
233 const Poly& polynomial, const RationalRectangle& rectangle,
234 ComputationContext& context, const std::string& operation) {
235 auto step = context.consume_steps(1, operation);
236 if (!step) return Result<RectangleCount>::failure(step.error());
237 const auto edges = rectangle_edges(polynomial, rectangle);
238 for (const auto& [real, imaginary] : edges) {
239 auto clear = edge_is_clear(real, imaginary, context, operation);
240 if (!clear) return Result<RectangleCount>::failure(clear.error());
241 if (!clear.value()) {
243 }
244 }
245 BigInt shear_magnitude(0);
246 int shear_direction = 1;
247 while (true) {
248 step = context.consume_steps(1, operation);
249 if (!step) return Result<RectangleCount>::failure(step.error());
250 auto bits = context.require_integer_bits(shear_magnitude.bit_length(), operation);
251 if (!bits) return Result<RectangleCount>::failure(bits.error());
252 const Rational shear(shear_direction > 0 ? shear_magnitude : -shear_magnitude);
253 if (shear_is_valid(edges, shear)) {
254 return count_sheared_edges(edges, shear, polynomial.degree(), context, operation);
255 }
256 if (shear_direction > 0) {
257 shear_direction = -1;
258 if (shear_magnitude.is_zero()) shear_magnitude = BigInt(1);
259 } else {
260 shear_direction = 1;
261 shear_magnitude += BigInt(1);
262 }
263 }
264}
265
266}
static Polynomial gcd(Polynomial a, Polynomial b)
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
int degree() const
获取多项式的次数
void trim()
去除高次零系数
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< bool > pole_interval_is_clear(const Poly &denominator, const Poly &numerator, const RationalInterval &interval, ComputationContext &context, const std::string &operation)
Result< int > cauchy_index_on_edge(const Poly &denominator, const Poly &numerator, ComputationContext &context, const std::string &operation)
std::vector< std::pair< Poly, Poly > > rectangle_edges(const Poly &polynomial, const RationalRectangle &rectangle)
std::pair< Poly, Poly > edge_image(const Poly &polynomial, const Rational &real_start, const Rational &imaginary_start, const Rational &real_delta, const Rational &imaginary_delta)
Result< RectangleCount > count_sheared_edges(const std::vector< std::pair< Poly, Poly > > &edges, const Rational &shear, int degree, ComputationContext &context, const std::string &operation)
Result< bool > edge_is_clear(const Poly &real, const Poly &imaginary, ComputationContext &context, const std::string &operation)
Result< int > pole_index(const Poly &denominator, const Poly &numerator, const RationalInterval &interval, ComputationContext &context, const std::string &operation)
Result< Rational > left_pole_sample(const Poly &denominator, const Rational &root, ComputationContext &context, const std::string &operation)
Result< void > refine_pole_interval(const Poly &factor, const Poly &denominator, const Poly &numerator, RationalInterval &interval, ComputationContext &context, const std::string &operation)
bool shear_is_valid(const std::vector< std::pair< Poly, Poly > > &edges, const Rational &shear)
Result< RectangleCount > count_rectangle_roots(const Poly &polynomial, const RationalRectangle &rectangle, ComputationContext &context, const std::string &operation)
Poly scale_poly(Poly polynomial, const Rational &scalar)
Result< void > refine_interval(const Poly &polynomial, RationalInterval &interval, ComputationContext &context, const std::string &operation)
Result< std::vector< RationalInterval > > isolate_real_roots_exact(const Polynomial< Rational > &polynomial, 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)
std::size_t std::size_t multiplicity
ComputationContext const std::string & operation
std::pair< Rational, Rational > RationalInterval
std::size_t std::size_t ComputationContext & context
std::vector< std::pair< Polynomial< Rational >, int > > square_free_factorization(const Polynomial< Rational > &poly)
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const ExprPtr & denominator