LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
mixed_transcendental_isolation.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace LMCAS::detail {
7namespace {
8
9constexpr lmmc_real_t minimum_width = 1e-6;
10constexpr int initial_divisions = 64;
11
13 lmmc_real_t lo;
14 lmmc_real_t hi;
15 lmmc_real_t f_lo;
16 lmmc_real_t f_hi;
17};
18
20public:
21 RootIsolation(const std::shared_ptr<SymbolicExpr>& expr,
22 const std::shared_ptr<SymbolicExpr>& derivative,
23 const std::string& var, RewriteBudget& budget)
24 : expr_(expr), derivative_(derivative), var_(var), budget_(budget) {}
25
27 std::optional<CasError>* failure, bool* complete) {
28 const auto step = (interval.hi - interval.lo) / initial_divisions;
29 std::vector<lmmc_real_t> samples(initial_divisions + 1);
30 for (int i = 0; i <= initial_divisions; ++i) {
31 if (!consume_mixed_step(budget_.context(), failure, complete)) {
32 return false;
33 }
34 samples[i] = sample(interval.lo + i * step, step * 0.5);
35 if (samples[i] == 0.0) {
36 const auto x = interval.lo + i * step;
37 if (mixed_evaluate_at(expr_, var_, x, budget_) == 0.0)
38 result_.push_back({x, x, true});
39 }
40 }
41 for (int i = 0; i < initial_divisions; ++i) {
42 const auto fa = samples[i];
43 const auto fb = samples[i + 1];
44 if (std::isnan(fa) && std::isnan(fb)) {
45 continue;
46 }
47 if (std::isnan(fa) || std::isnan(fb) || fa * fb < 0.0) {
48 work_.push_back({interval.lo + i * step,
49 interval.lo + (i + 1) * step, fa, fb});
50 }
51 }
52 return true;
53 }
54
55 void run(const SolveOptions& opts,
56 std::optional<CasError>* failure, bool* complete) {
57 while (!work_.empty()) {
58 if (!consume_mixed_step(budget_.context(), failure, complete)) {
59 break;
60 }
61 if (opts.max_roots > 0 &&
62 result_.size() >= static_cast<std::size_t>(opts.max_roots)) {
63 if (complete) {
64 *complete = false;
65 }
66 break;
67 }
68 auto current = work_.back();
69 work_.pop_back();
70 process(current);
71 }
72 }
73
74 std::vector<IsolatedInterval> finish(int max_roots, bool* complete) {
75 std::sort(result_.begin(), result_.end(),
76 [](const IsolatedInterval& a, const IsolatedInterval& b) {
77 return a.lo < b.lo;
78 });
79 if (max_roots > 0 && result_.size() > static_cast<std::size_t>(max_roots)) {
80 if (complete) {
81 *complete = false;
82 }
83 result_.resize(static_cast<std::size_t>(max_roots));
84 }
85 return std::move(result_);
86 }
87
88private:
89 lmmc_real_t sample(lmmc_real_t x, lmmc_real_t offset) const {
90 return mixed_evaluate_with_retry(expr_, var_, x, offset, budget_);
91 }
92
93 void accept(const SampledInterval& interval, bool confirmed) {
94 result_.push_back({interval.lo, interval.hi, confirmed});
95 }
96
98 const auto width = interval.hi - interval.lo;
99 if (std::isnan(interval.f_lo)) {
100 interval.f_lo = sample(interval.lo, width * 0.25);
101 if (std::isnan(interval.f_lo)) {
102 if (width > minimum_width * 2.0) {
103 const auto mid = (interval.lo + interval.hi) * 0.5;
104 const auto fm = sample(mid, width * 0.125);
105 work_.push_back({mid, interval.hi, fm, interval.f_hi});
106 }
107 return false;
108 }
109 }
110 if (std::isnan(interval.f_hi)) {
111 interval.f_hi = sample(interval.hi, width * 0.25);
112 if (std::isnan(interval.f_hi)) {
113 if (width > minimum_width * 2.0) {
114 const auto mid = (interval.lo + interval.hi) * 0.5;
115 const auto fm = sample(mid, width * 0.125);
116 work_.push_back({interval.lo, mid, interval.f_lo, fm});
117 }
118 return false;
119 }
120 }
121 return true;
122 }
123
125 const auto mid = (interval.lo + interval.hi) * 0.5;
126 const auto fm = sample(mid, (interval.hi - interval.lo) * 0.125);
127 if (std::isnan(fm)) {
128 accept(interval, false);
129 return;
130 }
131 if (fm == 0.0 && mixed_evaluate_at(expr_, var_, mid, budget_) == 0.0) {
132 result_.push_back({mid, mid, true});
133 }
134 if (interval.f_lo * fm < 0.0) {
135 work_.push_back({interval.lo, mid, interval.f_lo, fm});
136 }
137 if (fm * interval.f_hi < 0.0) {
138 work_.push_back({mid, interval.hi, fm, interval.f_hi});
139 }
140 if (interval.f_lo * fm >= 0.0 && fm * interval.f_hi >= 0.0) {
141 accept(interval, false);
142 }
143 }
144
145 void process(const SampledInterval& current) {
146 auto interval = current;
147 if (!resample_endpoints(interval) || interval.f_lo * interval.f_hi >= 0.0) {
148 return;
149 }
150 const auto width = interval.hi - interval.lo;
151 if (!derivative_) {
152 if (width > minimum_width * 4.0) {
154 } else {
155 accept(interval, false);
156 }
157 return;
158 }
159 const auto da = mixed_evaluate_at(derivative_, var_, interval.lo, budget_);
160 const auto db = mixed_evaluate_at(derivative_, var_, interval.hi, budget_);
161 const bool finite = !std::isnan(da) && !std::isnan(db);
162 const bool monotone = finite && da * db > 0.0;
163 if (width <= minimum_width || monotone) {
164 accept(interval, monotone);
165 return;
166 }
167 if (finite && da * db < 0.0 && width > minimum_width * 2.0) {
169 } else {
170 accept(interval, false);
171 }
172 }
173
174 const std::shared_ptr<SymbolicExpr>& expr_;
175 const std::shared_ptr<SymbolicExpr>& derivative_;
176 const std::string& var_;
178 std::vector<SampledInterval> work_;
179 std::vector<IsolatedInterval> result_;
180};
181
182}
183
184std::vector<IsolatedInterval> isolate_roots_with_context(
185 const std::shared_ptr<SymbolicExpr>& expr,
186 const std::shared_ptr<SymbolicExpr>& derivative,
187 const std::string& var, const SearchInterval& interval,
188 const SolveOptions& opts, RewriteBudget& budget,
189 std::optional<CasError>* failure, bool* complete) {
190 if (interval.lo >= interval.hi) {
191 return {};
192 }
193 RootIsolation isolation(expr, derivative, var, budget);
194 if (!isolation.initialize(interval, failure, complete)) {
195 return {};
196 }
197 isolation.run(opts, failure, complete);
198 return isolation.finish(opts.max_roots, complete);
199}
200
201}
202
203namespace LMCAS {
204
205std::vector<IsolatedInterval> isolate_roots(
206 const std::shared_ptr<SymbolicExpr>& expr,
207 const std::shared_ptr<SymbolicExpr>& derivative,
208 const std::string& var, const SearchInterval& interval,
209 const SolveOptions& opts) {
211 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
212 context.limits().max_ast_nodes, "isolate_roots");
213 std::optional<CasError> failure;
215 expr, derivative, var, interval, opts, budget, &failure, nullptr);
216 if (failure) throw *failure;
217 return result;
218}
219
220}
void run(const SolveOptions &opts, std::optional< CasError > *failure, bool *complete)
RootIsolation(const std::shared_ptr< SymbolicExpr > &expr, const std::shared_ptr< SymbolicExpr > &derivative, const std::string &var, RewriteBudget &budget)
bool initialize(const SearchInterval &interval, std::optional< CasError > *failure, bool *complete)
多元 Hensel 提升(单变量步)
std::variant< RealIsolation, ComplexIsolation > RootIsolation
bool consume_mixed_step(ComputationContext &context, std::optional< CasError > *failure, bool *complete)
lmmc_real_t mixed_evaluate_with_retry(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, lmmc_real_t x, lmmc_real_t half_width, RewriteBudget &budget, int max_retries=3)
lmmc_real_t mixed_evaluate_at(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, lmmc_real_t x, RewriteBudget &budget)
std::vector< IsolatedInterval > isolate_roots_with_context(const std::shared_ptr< SymbolicExpr > &expr, const std::shared_ptr< SymbolicExpr > &derivative, const std::string &var, const SearchInterval &interval, const SolveOptions &opts, RewriteBudget &budget, std::optional< CasError > *failure, bool *complete)
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
const MultiPoly & b
std::vector< IsolatedInterval > isolate_roots(const std::shared_ptr< SymbolicExpr > &expr, const std::shared_ptr< SymbolicExpr > &derivative, const std::string &var, const SearchInterval &interval, const SolveOptions &opts)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
int max_roots
数值候选数量预算;精确解集和整数解族保持完整。
隔离子区间,包含至多一个根
方程求解选项,控制数值求解行为和结果形式.