LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inequality_solver_chart.cpp
浏览该文件的文档.
4#include <algorithm>
5
6namespace LMCAS {
7using namespace detail::inequality_support;
8
10
11void include_numeric_root(std::vector<Interval>& intervals,
12 const std::shared_ptr<SymbolicExpr>& root,
14 bool merged = false;
15 for (auto& interval : intervals) {
16 if (!interval.upper.is_pos_infinity && interval.upper.value &&
17 roots_equal(interval.upper.value, root, context)) {
18 interval.upper.is_open = false;
19 merged = true;
20 }
21 if (!interval.lower.is_neg_infinity && interval.lower.value &&
22 roots_equal(interval.lower.value, root, context)) {
23 interval.lower.is_open = false;
24 merged = true;
25 }
26 }
27 if (!merged) {
28 intervals.push_back(Interval::point(root));
29 }
30}
31
32static bool close_symbolic_endpoint(Endpoint& endpoint,
33 const std::shared_ptr<SymbolicExpr>& root, ComputationContext& context) {
34
35 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
36 (context).limits().max_ast_nodes, "transform");
37 if (detail::node(endpoint.value)->equals(*detail::node(root))) {
38 endpoint.is_open = false;
39 return true;
40 }
41 auto diff = SymbolicExpr::add(endpoint.value,
42 SymbolicExpr::multiply(root, SymbolicExpr::number(-1)));
43 if (!detail::make_expression_ptr(detail::normalize_node(detail::node(diff), transform_budget))->is_zero()) {
44 return false;
45 }
46 endpoint.is_open = false;
47 return true;
48}
49
50static void include_symbolic_root(std::vector<Interval>& intervals,
51 const std::shared_ptr<SymbolicExpr>& root, ComputationContext& context) {
52 bool merged = false;
53 for (auto& interval : intervals) {
54 if (!interval.upper.is_pos_infinity && interval.upper.value) {
55 if (close_symbolic_endpoint(interval.upper, root, context)) {
56 merged = true;
57 }
58 }
59 if (!interval.lower.is_neg_infinity && interval.lower.value) {
60 if (close_symbolic_endpoint(interval.lower, root, context)) {
61 merged = true;
62 }
63 }
64 }
65 if (!merged) {
66 intervals.push_back(Interval::point(root));
67 }
68}
69
70static std::vector<Interval> select_open_intervals(
71 const std::vector<std::shared_ptr<SymbolicExpr>>& roots,
72 const std::vector<int>& signs, int target_sign) {
73 std::vector<Interval> intervals;
74 for (size_t index = 0; index < signs.size(); ++index) {
75 if (signs[index] != target_sign) {
76 continue;
77 }
78 Interval interval;
79 interval.lower = index == 0 ? Endpoint::neg_inf() : Endpoint::open(roots[index - 1]);
80 interval.upper = index == roots.size() ? Endpoint::pos_inf() : Endpoint::open(roots[index]);
81 intervals.push_back(interval);
82 }
83 return intervals;
84}
85
87 const std::vector<std::shared_ptr<SymbolicExpr>>& symbolic_roots,
88 const std::vector<int>& multiplicities,
89 int leading_sign,
91
92 if (symbolic_roots.empty()) {
93
94 bool want_positive = (type == InequalityType::GreaterThan || type == InequalityType::GreaterEqual);
95 int target_sign = want_positive ? 1 : -1;
96 if (leading_sign == target_sign) {
97 return IntervalUnion::entire_line();
98 }
99 return IntervalUnion::empty();
100 }
101
102 size_t n = symbolic_roots.size();
103 std::vector<int> interval_signs(n + 1);
104
105 interval_signs[n] = leading_sign;
106
107 for (int i = (int)n - 1; i >= 0; --i) {
108 interval_signs[i] = interval_signs[i + 1];
109 if (multiplicities[i] % 2 != 0) {
110 interval_signs[i] = -interval_signs[i];
111 }
112 }
113
114 bool want_positive = (type == InequalityType::GreaterThan || type == InequalityType::GreaterEqual);
115 bool is_strict = (type == InequalityType::GreaterThan || type == InequalityType::LessThan);
116 int target_sign = want_positive ? 1 : -1;
117
118 auto result_intervals = select_open_intervals(symbolic_roots, interval_signs, target_sign);
119
120 if (!is_strict) {
121 for (const auto& root : symbolic_roots) include_symbolic_root(result_intervals, root, context);
122 }
123 return IntervalUnion(result_intervals);
124}
125
126}
127
128std::vector<SignChartEntry> InequalitySolver::build_sign_chart(
129 const std::shared_ptr<SymbolicExpr>& poly,
130 const std::string& variable,
131 const std::vector<std::shared_ptr<SymbolicExpr>>& roots,
132 const std::vector<int>& multiplicities, ComputationContext& context) {
133
134 std::vector<SignChartEntry> chart;
135 auto converted = symbolic_to_poly<SymbolicPolyCoeff>(poly, variable);
136 if (!converted) throw std::invalid_argument(converted.error().message);
137 const auto& p = converted.value();
138
139 if (roots.empty()) {
140
141 int sign = determine_leading_sign(p, context);
142 chart.push_back({Interval::entire_line(), sign});
143 return chart;
144 }
145
146 int leading_sign = determine_leading_sign(p, context);
147
148 size_t n = roots.size();
149 std::vector<int> interval_signs(n + 1);
150
151 interval_signs[n] = leading_sign;
152
153 for (int i = (int)n - 1; i >= 0; --i) {
154 interval_signs[i] = interval_signs[i + 1];
155 if (multiplicities[i] % 2 != 0) {
156 interval_signs[i] = -interval_signs[i];
157 }
158 }
159
160 {
161 Interval iv;
162 iv.lower = Endpoint::neg_inf();
163 iv.upper = Endpoint::open(roots[0]);
164 chart.push_back({iv, interval_signs[0]});
165 }
166
167 for (size_t i = 0; i + 1 < n; ++i) {
168 Interval iv;
169 iv.lower = Endpoint::open(roots[i]);
170 iv.upper = Endpoint::open(roots[i + 1]);
171 chart.push_back({iv, interval_signs[i + 1]});
172 }
173
174 {
175 Interval iv;
176 iv.lower = Endpoint::open(roots[n - 1]);
177 iv.upper = Endpoint::pos_inf();
178 chart.push_back({iv, interval_signs[n]});
179 }
180
181 return chart;
182}
183
184IntervalUnion InequalitySolver::select_intervals(
185 const std::vector<SignChartEntry>& chart,
186 InequalityType type,
187 const std::vector<std::shared_ptr<SymbolicExpr>>& roots,
188 const std::vector<int>&, ComputationContext& context) {
189
190 std::vector<Interval> result_intervals;
191
192 bool want_positive = (type == InequalityType::GreaterThan || type == InequalityType::GreaterEqual);
193 bool is_strict = (type == InequalityType::GreaterThan || type == InequalityType::LessThan);
194 int target_sign = want_positive ? 1 : -1;
195
196 for (const auto& entry : chart) {
197 if (entry.sign == target_sign) {
198 result_intervals.push_back(entry.interval);
199 }
200 }
201
202 if (!is_strict) {
203 for (const auto& root : roots) include_numeric_root(result_intervals, root, context);
204 }
205 return IntervalUnion(result_intervals);
206}
207
208IntervalUnion InequalitySolver::build_parametric_solution(
209 const std::vector<std::shared_ptr<SymbolicExpr>>& symbolic_roots,
210 const std::vector<int>& multiplicities,
211 int leading_sign,
212 InequalityType type) {
214 return build_parametric_intervals(symbolic_roots, multiplicities, leading_sign, type, context);
215}
216
217}
bool roots_equal(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, ComputationContext &context)
static std::vector< Interval > select_open_intervals(const std::vector< std::shared_ptr< SymbolicExpr > > &roots, const std::vector< int > &signs, int target_sign)
static bool close_symbolic_endpoint(Endpoint &endpoint, const std::shared_ptr< SymbolicExpr > &root, ComputationContext &context)
static void include_symbolic_root(std::vector< Interval > &intervals, const std::shared_ptr< SymbolicExpr > &root, ComputationContext &context)
void include_numeric_root(std::vector< Interval > &intervals, const std::shared_ptr< SymbolicExpr > &root, ComputationContext &context)
int determine_leading_sign(const Polynomial< SymbolicPolyCoeff > &poly, ComputationContext &context)
IntervalUnion build_parametric_intervals(const std::vector< std::shared_ptr< SymbolicExpr > > &symbolic_roots, const std::vector< int > &multiplicities, int leading_sign, 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)
std::size_t std::size_t ComputationContext & context
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
InequalityType
不等式类型
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
内部 AST 定义。