LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inequality_solver.cpp
浏览该文件的文档.
5#include "poly_utils.hpp"
9#include "newton_raphson.hpp"
10#include "root_of_utils.hpp"
13#include <algorithm>
14#include <cmath>
15#include <set>
16#include <limits>
17#include <functional>
18#include <optional>
19
20namespace LMCAS {
27
28
29namespace {
30
31constexpr const char* kCheckedInequalityOperation = "solve_inequality_checked";
32
33
34}
35
36
37
38Result<IntervalUnion> InequalitySolver::solve_inequality_checked(
39 const std::shared_ptr<SymbolicExpr>& expr,
40 InequalityType type,
41 const std::string& variable,
43 if (!expr || !LMCAS::detail::node(expr)) {
45 CasErrc::InvalidArgument, "inequality expression cannot be null",
46 kCheckedInequalityOperation);
47 }
48 if (variable.empty()) {
50 CasErrc::InvalidArgument, "inequality variable cannot be empty",
51 kCheckedInequalityOperation);
52 }
53
54 try {
55 auto recognized = recognize_rational_polynomial(*expr, variable, context);
56 if (!recognized) {
57 return Result<IntervalUnion>::failure(recognized.error());
58 }
59 if (!recognized.value()) {
62 "expression is not an exact rational polynomial in the requested variable",
63 kCheckedInequalityOperation);
64 }
65 if (recognized.value()->degree() == 2 &&
66 recognized.value()->coeffs.size() >= 3) {
67 return solve_exact_quadratic_inequality(
68 *recognized.value(), type, context);
69 }
70 if (recognized.value()->degree() <= 1) {
72 *recognized.value(), type, context);
73 }
75 *recognized.value(), type, context);
76 } catch (const CasError& error) {
78 } catch (const std::bad_alloc&) {
80 CasErrc::ResourceLimit, "inequality allocation failed",
81 kCheckedInequalityOperation);
82 } catch (const std::length_error& error) {
84 CasErrc::ResourceLimit, error.what(), kCheckedInequalityOperation);
85 } catch (const std::exception& error) {
87 CasErrc::InternalInvariant, error.what(), kCheckedInequalityOperation);
88 }
89}
90
91Result<IntervalUnion> InequalitySolver::solve_inequality_checked(
92 const std::shared_ptr<SymbolicExpr>& expr,
93 InequalityType type,
94 const std::string& variable) {
96 return solve_inequality_checked(expr, type, variable, context);
97}
98
99Result<IntervalUnion> InequalitySolver::solve_inequalities_checked(
100 const std::vector<std::pair<std::shared_ptr<SymbolicExpr>,
101 InequalityType>>& inequalities,
102 const std::string& variable,
104 if (variable.empty()) {
106 CasErrc::InvalidArgument, "inequality variable cannot be empty",
107 "solve_inequalities_checked");
108 }
109
110 auto initial_step = context.consume_steps(1, "solve_inequalities_checked");
111 if (!initial_step) {
112 return Result<IntervalUnion>::failure(initial_step.error());
113 }
114 if (inequalities.empty()) {
115 return Result<IntervalUnion>::success(IntervalUnion::entire_line());
116 }
117
118 std::optional<IntervalUnion> aggregate;
119 for (const auto& inequality : inequalities) {
120 auto solved = solve_inequality_checked(
121 inequality.first, inequality.second, variable, context);
122 if (!solved) {
123 return Result<IntervalUnion>::failure(solved.error());
124 }
125 if (!aggregate) {
126 aggregate = std::move(solved.value());
127 continue;
128 }
129 auto intersection = aggregate->intersect_checked(solved.value(), context);
130 if (!intersection) {
131 return Result<IntervalUnion>::failure(intersection.error());
132 }
133 aggregate = std::move(intersection.value());
134 if (aggregate->is_empty()) {
135 break;
136 }
137 }
138 return Result<IntervalUnion>::success(std::move(*aggregate));
139}
140catch (const CasError& error) {
141 return Result<IntervalUnion>::failure(error);
142} catch (const std::bad_alloc&) {
144 "inequality intersection allocation failed", "solve_inequalities_checked");
145} catch (const std::length_error& error) {
147 CasErrc::ResourceLimit, error.what(), "solve_inequalities_checked");
148} catch (const std::exception& error) {
150 CasErrc::InternalInvariant, error.what(), "solve_inequalities_checked");
151}
152
153Result<IntervalUnion> InequalitySolver::solve_inequalities_checked(
154 const std::vector<std::pair<std::shared_ptr<SymbolicExpr>,
155 InequalityType>>& inequalities,
156 const std::string& variable) {
158 return solve_inequalities_checked(inequalities, variable, context);
159}
160
161
162
163static IntervalUnion solve_constant_inequality(
166 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
167 (context).limits().max_ast_nodes, "transform");
168 auto lc = poly.lead_coeff().val;
169 if (!lc) {
170 return IntervalUnion::empty();
171 }
172 int sign = exact_numeric_sign(lc, context);
173 if (sign == 0 && !lc->is_zero()) {
174 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(lc), transform_budget));
175 if (!simplified || !simplified->is_zero()) {
176 return IntervalUnion::empty();
177 }
178 }
179
180 bool satisfies = false;
181 switch (type) {
182 case InequalityType::GreaterThan: satisfies = (sign > 0); break;
183 case InequalityType::GreaterEqual: satisfies = (sign >= 0); break;
184 case InequalityType::LessThan: satisfies = (sign < 0); break;
185 case InequalityType::LessEqual: satisfies = (sign <= 0); break;
186 default:
187 return IntervalUnion::empty();
188 }
189 return satisfies ? IntervalUnion::entire_line() : IntervalUnion::empty();
190}
191
192IntervalUnion InequalitySolver::solve_inequality_impl(
193 const std::shared_ptr<SymbolicExpr>& expr,
194 InequalityType type,
195 const std::string& variable, ComputationContext& context) {
196
197 if (!expr) {
198 return IntervalUnion::empty();
199 }
200
201 auto converted = symbolic_to_poly<SymbolicPolyCoeff>(expr, variable);
202 if (!converted) throw std::invalid_argument(converted.error().message);
203 const auto& poly = converted.value();
204 if (poly.is_zero()) {
206 return IntervalUnion::entire_line();
207 }
208 return IntervalUnion::empty();
209 }
210
211 if (poly.degree() <= 0) {
212 return solve_constant_inequality(poly, type, context);
213 }
214
215 {
216 auto poly_rat = symbolic_to_poly<Rational>(expr, variable);
217 if (!poly_rat) throw std::invalid_argument(poly_rat.error().message);
218
219 }
220
221 auto roots_with_mult = find_roots_with_multiplicity(expr, variable, context);
222
223 std::sort(roots_with_mult.begin(), roots_with_mult.end(),
224 [&context](const auto& a, const auto& b) {
225 return root_less_than(a.first, b.first, context);
226 });
227
228 std::vector<std::pair<std::shared_ptr<SymbolicExpr>, int>> unique_roots;
229 for (const auto& [root, mult] : roots_with_mult) {
230 if (!unique_roots.empty() && roots_equal(unique_roots.back().first, root, context)) {
231
232 unique_roots.back().second = std::max(unique_roots.back().second, mult);
233 } else {
234 unique_roots.push_back({root, mult});
235 }
236 }
237
238 std::vector<std::shared_ptr<SymbolicExpr>> roots;
239 std::vector<int> multiplicities;
240 for (const auto& [root, mult] : unique_roots) {
241 roots.push_back(root);
242 multiplicities.push_back(mult);
243 }
244
245 auto chart = build_sign_chart(expr, variable, roots, multiplicities, context);
246
247 return select_intervals(chart, type, roots, multiplicities, context);
248}
249
250
251IntervalUnion InequalitySolver::solve_inequality(
252 const std::shared_ptr<SymbolicExpr>& expr, InequalityType type,
253 const std::string& variable) {
255 return solve_inequality_impl(expr, type, variable, context);
256}
257
258IntervalUnion InequalitySolver::solve_inequalities(
259 const std::vector<std::pair<std::shared_ptr<SymbolicExpr>,
260 InequalityType>>& inequalities,
261 const std::string& variable) {
263
264 if (inequalities.empty()) {
265 return IntervalUnion::entire_line();
266 }
267
268 IntervalUnion result = solve_inequality_impl(
269 inequalities[0].first, inequalities[0].second, variable, context);
270
271 for (size_t i = 1; i < inequalities.size(); ++i) {
272 auto solution = solve_inequality_impl(
273 inequalities[i].first, inequalities[i].second, variable, context);
274 result = result.intersect(solution);
275 if (result.is_empty()) {
276 break;
277 }
278 }
279
280 return result;
281}
282
283
284
285
286}
一元多项式模板类
CoeffType lead_coeff() const
获取首项系数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
不等式求解器 InequalitySolver,支持多项式,有理式,参数化不等式.
Result< IntervalUnion > solve_exact_polynomial_inequality(const Polynomial< Rational > &polynomial, InequalityType type, ComputationContext &context)
std::vector< std::pair< std::shared_ptr< SymbolicExpr >, int > > find_roots_with_multiplicity(const std::shared_ptr< SymbolicExpr > &expr, const std::string &variable, ComputationContext &context)
bool root_less_than(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, ComputationContext &context)
bool roots_equal(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, ComputationContext &context)
int exact_numeric_sign(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context)
Result< IntervalUnion > solve_exact_affine_inequality(const Polynomial< Rational > &polynomial, InequalityType type, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const MultiPoly & b
__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
InequalityType
不等式类型
Result< OptionalRationalPolynomial > recognize_rational_polynomial(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
static IntervalUnion solve_constant_inequality(const Polynomial< SymbolicPolyCoeff > &poly, InequalityType type, ComputationContext &context)
数值求根:Newton-Raphson 迭代,二分法,Sturm 实根隔离.
多项式转换与精确符号多项式代数。
RootOf 恒等关系、求值及代数闭式化简。
方程求解策略调度器 solve_dispatch 及相关选项结构体.
内部 AST 定义。