LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
query_interface.cpp
浏览该文件的文档.
1#include "query_interface.hpp"
6
7namespace LMCAS {
8
9// Construction
10
11QueryInterface::QueryInterface(const AssumptionContext& ctx)
12 : ctx_(ctx), observed_generation_(ctx.cache_generation()) {}
13
14// Cache management
15
16void QueryInterface::invalidate_cache() const {
17 cache_.clear();
18 observed_generation_ = ctx_.cache_generation();
19}
20
21
22QueryTriboolResult QueryInterface::cached_query_checked(
23 const SymbolicExpr& expr,
24 PropType prop,
25 const std::string& operation,
26 const std::function<QueryTriboolResult()>& compute,
27 const std::string& variable) const {
28 if (!LMCAS::detail::node(expr)) {
29 return QueryTriboolResult::failure(
30 CasErrc::InvalidArgument, "query expression must not be null", operation);
31 }
32
33 // Check if the context has been mutated since we last validated the cache.
34 // If so, invalidate and update our observed generation.
35 uint64_t current_gen = ctx_.cache_generation();
36 if (current_gen != observed_generation_) {
37 cache_.clear();
38 observed_generation_ = current_gen;
39 }
40
41 CacheKey key{LMCAS::detail::node(expr)->hash(), prop, variable};
42 auto it = cache_.find(key);
43 if (it != cache_.end()) {
44 for (const auto& entry : it->second) {
45 if (LMCAS::detail::node(entry.expression)->equals(*LMCAS::detail::node(expr))) {
46 return QueryTriboolResult::success(entry.result);
47 }
48 }
49 }
50
51 auto result = compute();
52 if (!result) return result;
53 cache_[key].push_back(CacheEntry{expr, result.value()});
54 return result;
55}
56// Public query methods
57
58QueryTriboolResult QueryInterface::query_positive(const SymbolicExpr& expr) const {
59 return query_positive_checked(expr);
60}
61
62QueryTriboolResult QueryInterface::query_positive_checked(const SymbolicExpr& expr) const {
63 return query_detail::checked_expression_result(expr, "query_positive_checked",
64 [&]() {
65 auto result = cached_query_checked(
66 expr, PropType::Positive, "query_positive_checked", [&]() -> QueryTriboolResult {
67 if (is_unhandled_type(expr)) {
68 return Tribool::Unknown;
69 }
70 if (is_infinity_node(expr)) {
71 int sign = get_infinity_sign(expr);
72 if (sign > 0) return Tribool::True;
73 if (sign < 0) return Tribool::False;
74 return Tribool::Unknown;
75 }
76 InferenceEngine engine(ctx_);
77 return engine.query_positive_checked(expr);
78 });
79 return result;
80 });
81}
82
83QueryTriboolResult QueryInterface::query_negative(const SymbolicExpr& expr) const {
84 return query_negative_checked(expr);
85}
86
87QueryTriboolResult QueryInterface::query_negative_checked(const SymbolicExpr& expr) const {
88 return query_detail::checked_expression_result(expr, "query_negative_checked",
89 [&]() {
90 auto result = cached_query_checked(
91 expr, PropType::Negative, "query_negative_checked", [&]() -> QueryTriboolResult {
92 if (is_unhandled_type(expr)) {
93 return Tribool::Unknown;
94 }
95 if (is_infinity_node(expr)) {
96 int sign = get_infinity_sign(expr);
97 if (sign < 0) return Tribool::True;
98 if (sign > 0) return Tribool::False;
99 return Tribool::Unknown;
100 }
101 InferenceEngine engine(ctx_);
102 return engine.query_negative_checked(expr);
103 });
104 return result;
105 });
106}
107
108QueryTriboolResult QueryInterface::query_nonnegative(const SymbolicExpr& expr) const {
109 return query_nonnegative_checked(expr);
110}
111
112QueryTriboolResult QueryInterface::query_nonnegative_checked(const SymbolicExpr& expr) const {
113 return query_detail::checked_expression_result(expr, "query_nonnegative_checked",
114 [&]() {
115 auto result = cached_query_checked(
116 expr, PropType::NonNegative, "query_nonnegative_checked", [&]() -> QueryTriboolResult {
117 if (is_unhandled_type(expr)) {
118 return Tribool::Unknown;
119 }
120 if (is_infinity_node(expr)) {
121 int sign = get_infinity_sign(expr);
122 if (sign > 0) return Tribool::True;
123 if (sign < 0) return Tribool::False;
124 return Tribool::Unknown;
125 }
126 InferenceEngine engine(ctx_);
127 return engine.query_nonnegative_checked(expr);
128 });
129 return result;
130 });
131}
132
133QueryTriboolResult QueryInterface::query_real(const SymbolicExpr& expr) const {
134 return query_real_checked(expr);
135}
136
137QueryTriboolResult QueryInterface::query_real_checked(const SymbolicExpr& expr) const {
138 return query_detail::checked_expression_result(expr, "query_real_checked",
139 [&]() {
140 auto result = cached_query_checked(
141 expr, PropType::Real, "query_real_checked", [&]() -> QueryTriboolResult {
142 if (is_unhandled_type(expr)) {
143 return Tribool::Unknown;
144 }
145 if (is_infinity_node(expr)) {
146 return Tribool::Unknown;
147 }
148 InferenceEngine engine(ctx_);
149 return engine.query_real_checked(expr);
150 });
151 return result;
152 });
153}
154
155QueryTriboolResult QueryInterface::query_integer(const SymbolicExpr& expr) const {
156 return query_integer_checked(expr);
157}
158
159QueryTriboolResult QueryInterface::query_integer_checked(const SymbolicExpr& expr) const {
160 return query_detail::checked_expression_result(expr, "query_integer_checked",
161 [&]() {
162 auto result = cached_query_checked(
163 expr, PropType::Integer, "query_integer_checked", [&]() -> QueryTriboolResult {
164 if (is_unhandled_type(expr)) {
165 return Tribool::Unknown;
166 }
167 if (is_infinity_node(expr)) {
168 return Tribool::False;
169 }
170 InferenceEngine engine(ctx_);
171 return engine.query_integer_checked(expr);
172 });
173 return result;
174 });
175}
176
177QueryTriboolResult QueryInterface::query_nonzero(const SymbolicExpr& expr) const {
178 return query_nonzero_checked(expr);
179}
180
181QueryTriboolResult QueryInterface::query_nonzero_checked(const SymbolicExpr& expr) const {
182 return query_detail::checked_expression_result(expr, "query_nonzero_checked",
183 [&]() {
184 auto result = cached_query_checked(
185 expr, PropType::NonZero, "query_nonzero_checked", [&]() -> QueryTriboolResult {
186 if (is_unhandled_type(expr)) {
187 return Tribool::Unknown;
188 }
189 if (is_infinity_node(expr)) {
190 return Tribool::True;
191 }
192 InferenceEngine engine(ctx_);
193 return engine.query_nonzero_checked(expr);
194 });
195 return result;
196 });
197}
198
199// Extended property queries
200
201QueryTriboolResult QueryInterface::query_algebraic(const SymbolicExpr& expr) const {
202 return query_algebraic_checked(expr);
203}
204
205QueryTriboolResult QueryInterface::query_algebraic_checked(const SymbolicExpr& expr) const {
206 return query_detail::checked_expression_result(expr, "query_algebraic_checked",
207 [&]() {
208 auto result = cached_query_checked(
209 expr, PropType::Algebraic, "query_algebraic_checked", [&]() -> QueryTriboolResult {
210 if (is_unhandled_type(expr)) {
211 return Tribool::Unknown;
212 }
213 if (is_infinity_node(expr)) {
214 return Tribool::False;
215 }
216 InferenceEngine engine(ctx_);
217 return engine.query_algebraic_checked(expr);
218 });
219 return result;
220 });
221}
222
223QueryTriboolResult QueryInterface::query_transcendental(const SymbolicExpr& expr) const {
224 return query_transcendental_checked(expr);
225}
226
227QueryTriboolResult QueryInterface::query_transcendental_checked(const SymbolicExpr& expr) const {
228 return query_detail::checked_expression_result(expr, "query_transcendental_checked",
229 [&]() {
230 auto result = cached_query_checked(
231 expr, PropType::Transcendental, "query_transcendental_checked", [&]() -> QueryTriboolResult {
232 if (is_unhandled_type(expr)) {
233 return Tribool::Unknown;
234 }
235 if (is_infinity_node(expr)) {
236 return Tribool::False;
237 }
238 InferenceEngine engine(ctx_);
239 return engine.query_transcendental_checked(expr);
240 });
241 return result;
242 });
243}
244
245QueryTriboolResult QueryInterface::query_finite(const SymbolicExpr& expr) const {
246 return query_finite_checked(expr);
247}
248
249QueryTriboolResult QueryInterface::query_finite_checked(const SymbolicExpr& expr) const {
250 return query_detail::checked_expression_result(expr, "query_finite_checked",
251 [&]() {
252 auto result = cached_query_checked(
253 expr, PropType::Finite, "query_finite_checked", [&]() -> QueryTriboolResult {
254 if (is_unhandled_type(expr)) {
255 return Tribool::Unknown;
256 }
257 if (is_infinity_node(expr)) {
258 return Tribool::False;
259 }
260 InferenceEngine engine(ctx_);
261 return engine.query_finite_checked(expr);
262 });
263 return result;
264 });
265}
266
267QueryTriboolResult QueryInterface::query_divergent(const SymbolicExpr& expr) const {
268 return query_divergent_checked(expr);
269}
270
271QueryTriboolResult QueryInterface::query_divergent_checked(const SymbolicExpr& expr) const {
272 return query_detail::checked_expression_result(expr, "query_divergent_checked",
273 [&]() {
274 auto result = cached_query_checked(
275 expr, PropType::Divergent, "query_divergent_checked", [&]() -> QueryTriboolResult {
276 if (is_unhandled_type(expr)) {
277 return Tribool::Unknown;
278 }
279 if (is_infinity_node(expr)) {
280 return Tribool::True;
281 }
282 InferenceEngine engine(ctx_);
283 return engine.query_divergent_checked(expr);
284 });
285 return result;
286 });
287}
288
289QueryTriboolResult QueryInterface::query_periodic(
290 const SymbolicExpr& expr, const std::string& variable) const {
291 return query_periodic_checked(expr, variable);
292}
293
294QueryTriboolResult QueryInterface::query_periodic_checked(
295 const SymbolicExpr& expr, const std::string& variable) const {
296 if (variable.empty()) {
297 return QueryTriboolResult::failure(CasErrc::InvalidArgument,
298 "independent variable must not be empty", "query_periodic_checked");
299 }
300 return query_detail::checked_expression_result(expr, "query_periodic_checked", [&]() {
301 return cached_query_checked(expr, PropType::Periodic, "query_periodic_checked",
302 [&]() -> QueryTriboolResult {
303 InferenceEngine engine(ctx_);
304 return engine.query_periodic_checked(expr, variable);
305 }, variable);
306 });
307}
308
309QueryPeriodResult QueryInterface::get_period(
310 const SymbolicExpr& expr, const std::string& variable) const {
311 return get_period_checked(expr, variable);
312}
313
314QueryPeriodResult QueryInterface::get_period_checked(
315 const SymbolicExpr& expr, const std::string& variable) const {
316 InferenceEngine engine(ctx_);
317 return engine.infer_period_checked(expr, variable);
318}
319
320QueryTriboolResult QueryInterface::query_positive_definite(
321 const SymbolicExpr& expr) const {
322 return query_positive_definite_checked(expr);
323}
324
325QueryTriboolResult QueryInterface::query_positive_definite_checked(const SymbolicExpr& expr) const {
326 return query_detail::checked_expression_result(expr, "query_positive_definite_checked",
327 [&]() {
328 auto result = cached_query_checked(
329 expr,
330 PropType::PositiveDefinite,
331 "query_positive_definite_checked",
332 [&]() -> QueryTriboolResult {
333 if (auto var = std::dynamic_pointer_cast<const VariableNode>(
334 LMCAS::detail::node(expr))) {
335 if (var->is_constant()) return Tribool::Unknown;
336 const auto& props = ctx_;
337 Definiteness d = props.get_definiteness(var->name());
338 if (d == Definiteness::PositiveDefinite) return Tribool::True;
339 if (d == Definiteness::NegativeDefinite ||
340 d == Definiteness::NegativeSemiDefinite ||
341 d == Definiteness::Indefinite) return Tribool::False;
342 return Tribool::Unknown;
343 }
344 return Tribool::Unknown;
345 });
346 return result;
347 });
348}
349
350QueryTriboolResult QueryInterface::query_positive_semidefinite(
351 const SymbolicExpr& expr) const {
352 return query_positive_semidefinite_checked(expr);
353}
354
355QueryTriboolResult QueryInterface::query_positive_semidefinite_checked(const SymbolicExpr& expr) const {
356 return query_detail::checked_expression_result(expr, "query_positive_semidefinite_checked",
357 [&]() {
358 auto result = cached_query_checked(
359 expr,
360 PropType::PositiveSemiDefinite,
361 "query_positive_semidefinite_checked",
362 [&]() -> QueryTriboolResult {
363 if (auto var = std::dynamic_pointer_cast<const VariableNode>(
364 LMCAS::detail::node(expr))) {
365 if (var->is_constant()) return Tribool::Unknown;
366 const auto& props = ctx_;
367 Definiteness d = props.get_definiteness(var->name());
368 if (d == Definiteness::PositiveDefinite ||
369 d == Definiteness::PositiveSemiDefinite) return Tribool::True;
370 if (d == Definiteness::NegativeDefinite ||
371 d == Definiteness::NegativeSemiDefinite ||
372 d == Definiteness::Indefinite) return Tribool::False;
373 return Tribool::Unknown;
374 }
375 return Tribool::Unknown;
376 });
377 return result;
378 });
379}
380
381}
AssumptionContext class with scoped push/pop management.
InferenceEngine class for deriving properties of composite expressions.
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
const std::string & variable
Result< Tribool > QueryTriboolResult
Definiteness
Matrix definiteness classification.
Result< std::optional< SymbolicExpr > > QueryPeriodResult
QueryInterface class - unified tri-state query API for property questions on arbitrary expressions.
内部 AST 定义。