LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
ode_polynomial_utils.hpp
浏览该文件的文档.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <utility>
6#include <vector>
7
9
10using RealPolynomial = std::vector<double>;
11
12struct CharRoot {
13 double real_part;
14 double imag_part;
17};
18
19struct Complex {
20 double re;
21 double im;
22
23 Complex(double real = 0.0, double imaginary = 0.0)
24 : re(real), im(imaginary) {}
25 Complex operator*(const Complex& other) const {
26 return {re * other.re - im * other.im,
27 re * other.im + im * other.re};
28 }
29 Complex operator+(const Complex& other) const {
30 return {re + other.re, im + other.im};
31 }
32 Complex operator-(const Complex& other) const {
33 return {re - other.re, im - other.im};
34 }
35 Complex operator/(const Complex& other) const {
36 const double denominator =
37 other.re * other.re + other.im * other.im;
38 if (denominator < 1e-300) {
39 return {INFINITY, INFINITY};
40 }
41 return {(re * other.re + im * other.im) / denominator,
42 (im * other.re - re * other.im) / denominator};
43 }
44 double magnitude() const {
45 return std::hypot(re, im);
46 }
47};
48
50 const RealPolynomial& coefficients, const Complex& root) {
51 return root.re == 0.0 && root.im == 0.0 && coefficients.back() == 0.0;
52}
53
55 const RealPolynomial& coefficients, const Complex& root) {
56 Complex value{coefficients.front(), 0.0};
57 double scale = std::abs(coefficients.front());
58 const double root_magnitude = root.magnitude();
59 for (size_t i = 1; i < coefficients.size(); ++i) {
60 value = value * root + Complex{coefficients[i], 0.0};
61 scale = scale * root_magnitude + std::abs(coefficients[i]);
62 }
63 if (!std::isfinite(value.re) || !std::isfinite(value.im) ||
64 !std::isfinite(scale)) {
65 return INFINITY;
66 }
67 if (scale == 0.0) {
68 // At an exact zero root with zero constant term, both the residual
69 // and its coefficientwise bound vanish: no perturbation is needed.
70 // A nonzero root can instead underflow the bound, which is not proof.
71 return is_exact_zero_polynomial_root(coefficients, root)
72 ? 0.0 : INFINITY;
73 }
74 return value.magnitude() / scale;
75}
76
77inline double polynomial_scale(const RealPolynomial& polynomial) {
78 double scale = 0.0;
79 for (double coefficient : polynomial) {
80 scale = std::max(scale, std::abs(coefficient));
81 }
82 return scale;
83}
84
85inline void trim_polynomial(RealPolynomial& polynomial) {
86 const double scale = polynomial_scale(polynomial);
87 const double tolerance = std::max(1.0, scale) * 1e-10;
88 auto first = polynomial.begin();
89 while (first + 1 != polynomial.end() && std::abs(*first) <= tolerance) {
90 ++first;
91 }
92 polynomial.erase(polynomial.begin(), first);
93 if (polynomial.empty()) {
94 polynomial.push_back(0.0);
95 }
96}
97
98inline std::pair<RealPolynomial, RealPolynomial> divide_polynomials(
99 const RealPolynomial& dividend, const RealPolynomial& divisor) {
100 if (divisor.empty() || divisor.front() == 0.0 ||
101 dividend.size() < divisor.size()) {
102 return {{0.0}, dividend};
103 }
104
105 RealPolynomial remainder = dividend;
106 RealPolynomial quotient(
107 dividend.size() - divisor.size() + 1, 0.0);
108 for (size_t i = 0; i < quotient.size(); ++i) {
109 const double factor = remainder[i] / divisor.front();
110 quotient[i] = factor;
111 for (size_t j = 0; j < divisor.size(); ++j) {
112 remainder[i + j] -= factor * divisor[j];
113 }
114 }
115 remainder.erase(
116 remainder.begin(), remainder.begin() + quotient.size());
117 if (remainder.empty()) {
118 remainder.push_back(0.0);
119 }
120 trim_polynomial(quotient);
121 trim_polynomial(remainder);
122 return {std::move(quotient), std::move(remainder)};
123}
124
126 trim_polynomial(polynomial);
127 if (polynomial.empty() || polynomial.front() == 0.0) {
128 return {0.0};
129 }
130 const double leading = polynomial.front();
131 for (double& coefficient : polynomial) coefficient /= leading;
132 return polynomial;
133}
134
136 const RealPolynomial& polynomial) {
137 if (polynomial.size() <= 1) {
138 return {0.0};
139 }
140 RealPolynomial derivative;
141 derivative.reserve(polynomial.size() - 1);
142 const size_t degree = polynomial.size() - 1;
143 for (size_t i = 0; i < degree; ++i) {
144 derivative.push_back(
145 polynomial[i] * static_cast<double>(degree - i));
146 }
147 return derivative;
148}
149
152 lhs = monic_polynomial(std::move(lhs));
153 rhs = monic_polynomial(std::move(rhs));
154 for (int iteration = 0; iteration < 8 && rhs.size() > 1; ++iteration) {
155 auto division = divide_polynomials(lhs, rhs);
156 RealPolynomial remainder = std::move(division.second);
157 if (remainder.size() == 1 && remainder.front() == 0.0) {
158 return rhs;
159 }
160 lhs = std::move(rhs);
161 rhs = monic_polynomial(std::move(remainder));
162 }
163 return {1.0};
164}
165
167 const RealPolynomial& remainder, const RealPolynomial& dividend) {
168 return polynomial_scale(remainder) <=
169 std::max(1.0, polynomial_scale(dividend)) * 1e-7;
170}
171
172}
std::pair< RealPolynomial, RealPolynomial > divide_polynomials(const RealPolynomial &dividend, const RealPolynomial &divisor)
RealPolynomial polynomial_derivative(const RealPolynomial &polynomial)
double polynomial_root_backward_error(const RealPolynomial &coefficients, const Complex &root)
void trim_polynomial(RealPolynomial &polynomial)
RealPolynomial monic_polynomial(RealPolynomial polynomial)
bool is_exact_zero_polynomial_root(const RealPolynomial &coefficients, const Complex &root)
RealPolynomial approximate_polynomial_gcd(RealPolynomial lhs, RealPolynomial rhs)
double polynomial_scale(const RealPolynomial &polynomial)
bool polynomial_remainder_is_small(const RealPolynomial &remainder, const RealPolynomial &dividend)
ExprResult e()
ExprResult real(const ExprPtr &expression, ComputationContext &context)
const std::string const ExprPtr & value
const ExprPtr & rhs
const ExprPtr & denominator
Complex operator-(const Complex &other) const
Complex operator*(const Complex &other) const
Complex operator/(const Complex &other) const
Complex(double real=0.0, double imaginary=0.0)
Complex operator+(const Complex &other) const