LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
mixed_transcendental_refinement.cpp
浏览该文件的文档.
3
4#include <cmath>
5#include <limits>
6
7namespace LMCAS::detail {
8namespace {
9
11public:
12 RootRefinement(const std::shared_ptr<SymbolicExpr>& expr,
13 const std::shared_ptr<SymbolicExpr>& derivative,
14 const std::string& var, const IsolatedInterval& interval,
15 const SolveOptions& opts, RewriteBudget& budget)
16 : expr_(expr), derivative_(derivative), var_(var), opts_(opts), budget_(budget),
17 lo_(interval.lo), hi_(interval.hi), x_(midpoint()),
19 best_{x_, std::numeric_limits<lmmc_real_t>::max(), 0} {}
20
21 std::optional<NumericRoot> endpoint_root() const {
22 auto lower = root_at(lo_, f_lo_, 0);
23 if (lower) {
24 return lower;
25 }
26 return root_at(hi_, f_hi_, 0);
27 }
28
29 std::optional<NumericRoot> bisect(
30 std::optional<CasError>* failure,
31 bool* complete) {
32 if (std::isnan(f_lo_) || std::isnan(f_hi_) || f_lo_ * f_hi_ > 0.0) {
33 return root_at(x_, evaluate(x_), 1);
34 }
35 for (int i = 1; i <= opts_.max_newton_iterations; ++i) {
36 if (!consume_mixed_step(budget_.context(), failure, complete)) {
37 return std::nullopt;
38 }
39 const auto mid = midpoint();
40 const auto f_mid = evaluate(mid);
41 if (std::isnan(f_mid)) {
42 hi_ = mid;
43 continue;
44 }
45 remember(mid, f_mid, i);
46 auto root = root_at(mid, f_mid, i);
47 if (root) {
48 return root;
49 }
50 if (f_lo_ * f_mid < 0.0) {
51 hi_ = mid;
52 } else {
53 lo_ = mid;
54 f_lo_ = f_mid;
55 }
56 if (hi_ - lo_ < opts_.tolerance) {
57 const auto final_x = midpoint();
58 remember(final_x, evaluate(final_x), i);
59 break;
60 }
61 }
62 return best_root();
63 }
64
65 std::optional<NumericRoot> newton(
66 std::optional<CasError>* failure,
67 bool* complete) {
68 if (!resample_endpoints()) {
69 return std::nullopt;
70 }
71 for (int i = 1; i <= opts_.max_newton_iterations; ++i) {
72 if (!consume_mixed_step(budget_.context(), failure, complete)) {
73 return std::nullopt;
74 }
75 const auto fx = evaluate(x_);
76 if (std::isnan(fx)) {
77 x_ = midpoint();
78 continue;
79 }
80 remember(x_, fx, i);
81 auto root = root_at(x_, fx, i);
82 if (root) {
83 return root;
84 }
85 const auto dfx = mixed_evaluate_at(derivative_, var_, x_, budget_);
86 if (std::isnan(dfx) || std::fabs(dfx) < 1e-15) {
88 continue;
89 }
90 if (accept_newton_step(fx, dfx)) {
91 continue;
92 }
94 if (hi_ - lo_ < opts_.tolerance) {
95 const auto final_x = midpoint();
96 root = root_at(final_x, evaluate(final_x), i);
97 if (root) {
98 return root;
99 }
100 break;
101 }
102 }
103 return best_root();
104 }
105
106private:
107 lmmc_real_t midpoint() const {
109 }
110
111 lmmc_real_t evaluate(lmmc_real_t x) const {
112 return mixed_evaluate_at(expr_, var_, x, budget_);
113 }
114
115 std::optional<NumericRoot> root_at(
116 lmmc_real_t x, lmmc_real_t fx, int iterations) const {
117 if (!std::isnan(fx) && std::fabs(fx) < opts_.tolerance) {
118 return NumericRoot{x, std::fabs(fx), iterations};
119 }
120 return std::nullopt;
121 }
122
123 void remember(lmmc_real_t x, lmmc_real_t fx, int iterations) {
124 const auto residual = std::fabs(fx);
125 if (!std::isnan(residual) && residual < best_.residual) {
126 best_ = {x, residual, iterations};
127 }
128 }
129
130 std::optional<NumericRoot> best_root() const {
131 if (best_.residual < opts_.tolerance) {
132 return best_;
133 }
134 return std::nullopt;
135 }
136
138 if (std::isnan(f_lo_)) {
139 f_lo_ = evaluate(lo_ + (hi_ - lo_) * 0.01);
140 lo_ = lo_ + (hi_ - lo_) * 0.01;
141 }
142 if (std::isnan(f_hi_)) {
143 f_hi_ = evaluate(hi_ - (hi_ - lo_) * 0.01);
144 hi_ = hi_ - (hi_ - lo_) * 0.01;
145 }
146 return !std::isnan(f_lo_) && !std::isnan(f_hi_);
147 }
148
150 const auto mid = midpoint();
151 const auto f_mid = evaluate(mid);
152 if (!std::isnan(f_mid)) {
153 if (!std::isnan(f_lo_) && f_lo_ * f_mid < 0.0) {
154 hi_ = mid;
155 f_hi_ = f_mid;
156 } else {
157 lo_ = mid;
158 f_lo_ = f_mid;
159 }
160 }
161 x_ = midpoint();
162 }
163
164 bool accept_newton_step(lmmc_real_t fx, lmmc_real_t dfx) {
165 const auto next = x_ - fx / dfx;
166 if (next < lo_ || next > hi_) {
167 return false;
168 }
169 const auto f_next = evaluate(next);
170 if (std::isnan(f_next) || std::fabs(f_next) > std::fabs(fx)) {
171 return false;
172 }
173 if (!std::isnan(f_lo_) && fx * f_lo_ < 0.0) {
174 hi_ = x_;
175 f_hi_ = fx;
176 } else if (!std::isnan(f_hi_) && fx * f_hi_ < 0.0) {
177 lo_ = x_;
178 f_lo_ = fx;
179 }
180 x_ = next;
181 return true;
182 }
183
184 const std::shared_ptr<SymbolicExpr>& expr_;
185 const std::shared_ptr<SymbolicExpr>& derivative_;
186 const std::string& var_;
189 lmmc_real_t lo_;
190 lmmc_real_t hi_;
191 lmmc_real_t x_;
192 lmmc_real_t f_lo_;
193 lmmc_real_t f_hi_;
195};
196
197}
198
199std::optional<NumericRoot> refine_root_with_context(
200 const std::shared_ptr<SymbolicExpr>& expr,
201 const std::shared_ptr<SymbolicExpr>& derivative,
202 const std::string& var, const IsolatedInterval& interval,
203 const SolveOptions& opts, RewriteBudget& budget,
204 std::optional<CasError>* failure, bool* complete) {
205 RootRefinement refinement(expr, derivative, var, interval, opts, budget);
206 auto endpoint = refinement.endpoint_root();
207 if (endpoint) {
208 return endpoint;
209 }
210 if (!derivative) {
211 return refinement.bisect(failure, complete);
212 }
213 return refinement.newton(failure, complete);
214}
215
216}
217
218namespace LMCAS {
219
220std::optional<NumericRoot> refine_root(
221 const std::shared_ptr<SymbolicExpr>& expr,
222 const std::shared_ptr<SymbolicExpr>& derivative,
223 const std::string& var, const IsolatedInterval& interval,
224 const SolveOptions& opts) {
226 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
227 context.limits().max_ast_nodes, "refine_root");
228 std::optional<CasError> failure;
230 expr, derivative, var, interval, opts, budget, &failure, nullptr);
231 if (failure) throw *failure;
232 return result;
233}
234
235}
std::optional< NumericRoot > root_at(lmmc_real_t x, lmmc_real_t fx, int iterations) const
std::optional< NumericRoot > bisect(std::optional< CasError > *failure, bool *complete)
RootRefinement(const std::shared_ptr< SymbolicExpr > &expr, const std::shared_ptr< SymbolicExpr > &derivative, const std::string &var, const IsolatedInterval &interval, const SolveOptions &opts, RewriteBudget &budget)
std::optional< NumericRoot > newton(std::optional< CasError > *failure, bool *complete)
多元 Hensel 提升(单变量步)
bool consume_mixed_step(ComputationContext &context, std::optional< CasError > *failure, bool *complete)
std::optional< NumericRoot > refine_root_with_context(const std::shared_ptr< SymbolicExpr > &expr, const std::shared_ptr< SymbolicExpr > &derivative, const std::string &var, const IsolatedInterval &interval, const SolveOptions &opts, RewriteBudget &budget, std::optional< CasError > *failure, bool *complete)
lmmc_real_t mixed_evaluate_at(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, lmmc_real_t x, RewriteBudget &budget)
lmmc_real_t finite_midpoint(lmmc_real_t lower, lmmc_real_t upper)
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
const ExprPtr & lower
std::optional< NumericRoot > refine_root(const std::shared_ptr< SymbolicExpr > &expr, const std::shared_ptr< SymbolicExpr > &derivative, const std::string &var, const IsolatedInterval &interval, const SolveOptions &opts)
隔离子区间,包含至多一个根
方程求解选项,控制数值求解行为和结果形式.
数值根结果,包含根值,残差和迭代次数.