LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
assumption_context.hpp
浏览该文件的文档.
1/**
2 * @file assumption_context.hpp
3 * @brief AssumptionContext class with scoped push/pop management.
4 *
5 * Provides a scope stack where each scope has its own PropertyStore and
6 * RelationStore. Queries read through from the top scope down to the root,
7 * with child scope declarations shadowing parent declarations.
8 */
9#pragma once
10
11#include "assumption.hpp"
12#include "property_store.hpp"
13#include "relation_store.hpp"
14#include "result.hpp"
15#include <vector>
16#include <string>
17#include <stdexcept>
18#include <unordered_set>
19#include <optional>
20#include <sstream>
21#include <type_traits>
22#include <initializer_list>
23#include <variant>
24
25namespace LMCAS {
26
27// Forward declarations
28class InferenceEngine;
30struct Interval;
31namespace detail { class RewriteBudget; class AssumptionFacts; }
32
35
36/**
37 * @brief Scoped assumption context with push/pop management.
38 *
39 * Maintains a stack of scopes, each containing a PropertyStore and RelationStore.
40 * Queries use read-through semantics: searching from the top scope down to root,
41 * 查询按子作用域到父作用域的顺序定位首个符号声明.
42 * 子作用域声明覆盖查询结果,同时保留父作用域状态;弹出作用域后恢复先前结果.
43 */
44class LMCAS_API AssumptionContext {
45public:
46 AssumptionContext();
47 AssumptionContext(const AssumptionContext&) = default;
48 AssumptionContext(AssumptionContext&& other);
49 AssumptionContext& operator=(const AssumptionContext& other);
50 AssumptionContext& operator=(AssumptionContext&& other) noexcept;
51
52
53 // --- Scope management ---
54
55 /// Push a new scope onto the stack.
56 void push();
57
58 /// Pop the current scope.
60
61 /// Return the current nesting depth (number of scopes on the stack).
62 int depth() const;
63
64 // --- Direct access to current (top) scope stores ---
65
66 /**
67 * @brief 访问当前作用域可修改的 PropertyStore,用于声明。
68 * push 可能使引用失效,pop 销毁弹出的存储;仍有效的引用可观察后续提交。
69 */
70 PropertyStore& current_properties();
71
72 /// Access the current scope's PropertyStore (const).
73 const PropertyStore& current_properties() const;
74
75 /// Access the current scope's RelationStore (mutable).
76 RelationStore& current_relations();
77
78 /// Access the current scope's RelationStore (const).
79 const RelationStore& current_relations() const;
80
81 // --- Read-through query methods ---
82 // These search from the top scope down to root, returning the first
83 // scope's value that has a declaration for the symbol. This provides
84 // shadowing semantics: child declarations override parent declarations.
85
86 /// Check if a symbol has a specific sign (read-through all scopes).
87 bool has_sign(const std::string& symbol, Sign sign) const;
88
89 /// Check if a symbol has at least the given domain specificity (read-through).
90 bool has_domain(const std::string& symbol, Domain domain) const;
91
92 /// Get the most specific domain for a symbol (read-through).
93 Domain get_domain(const std::string& symbol) const;
94
95 /// Get all signs for a symbol (read-through).
96 std::unordered_set<Sign, SignHash> get_signs(const std::string& symbol) const;
97
98 /// Get parity for a symbol (read-through).
99 Parity get_parity(const std::string& symbol) const;
100
101 /// Get boundedness for a symbol (read-through).
102 Boundedness get_boundedness(const std::string& symbol) const;
103
104 /// Get interval bounds for a symbol (read-through).
105 std::optional<Interval> get_bounds(const std::string& symbol) const;
106
107 bool is_transcendental(const std::string& symbol) const;
108 Finiteness get_finiteness(const std::string& symbol) const;
109 Definiteness get_definiteness(const std::string& symbol) const;
110 std::optional<SymbolicExpr> get_period(
111 const std::string& symbol, const std::string& variable) const;
112 bool is_periodic(const std::string& symbol, const std::string& variable) const;
113 /** @brief 仅查询周期声明元数据;不透明周期符号仍按非常量处理。 */
114 bool has_period_declarations(const std::string& symbol) const;
115 Result<Monotonicity> get_monotonicity_checked(
116 const std::string& symbol, const std::string& variable,
117 const Interval& interval) const;
118
119 /** @brief 继承父作用域关系时排除被较近声明遮蔽的关系;仅使用已有关系,不构造跨作用域传递闭包。 */
120 bool has_relation(const SymbolicExpr& lhs, const SymbolicExpr& rhs, RelationOp op) const;
121 std::vector<Relation> get_visible_relations() const;
122 Result<bool> has_relation_checked(
123 const SymbolicExpr& lhs, const SymbolicExpr& rhs, RelationOp op,
125 Result<std::vector<Relation>> get_visible_relations_checked(
127
128 /// Declare domain for a variable in the current scope.
129 /// Returns an explicit error if the variable name is empty or contradictory.
130 AssumptionVoidResult assume_domain(const std::string& variable, Domain domain);
131
132 /** @brief Declares a domain and reports invalid or contradictory input. */
133 AssumptionVoidResult assume_domain_checked(const std::string& variable, Domain domain);
134
135 /// Declare sign for a variable in the current scope.
136 /// Returns an explicit error if the variable name is empty or contradictory.
137 AssumptionVoidResult assume_sign(const std::string& variable, Sign sign);
138
139 /** @brief Declares a sign and reports invalid or contradictory input. */
140 AssumptionVoidResult assume_sign_checked(const std::string& variable, Sign sign);
141
142 /// Store a relational constraint. The expression's root must be a RelationalNode.
143 /// Invalid or contradictory relations are returned as an explicit error.
144 AssumptionVoidResult assume(const SymbolicExpr& relation);
145
146 /** @brief Stores a relation and reports invalid or contradictory input. */
147 AssumptionVoidResult assume_checked(const SymbolicExpr& relation);
148
149 /**
150 * @brief Store a conditional assumption: if condition holds, conclude conclusion.
151 *
152 * The conditional is stored in the current scope and discarded on scope pop.
153 * When a query depends on the conclusion, the system checks if the condition
154 * is satisfied by the current assumption state. If satisfied, the conclusion
155 * is used; if not verifiable, the conditional is inactive.
156 *
157 * @param condition A relational expression (e.g., x > 1) serving as the guard
158 * @param conclusion A relational expression (e.g., ln(x) > 0) to use when condition holds
159 * Invalid or contradictory relations are returned as an explicit error.
160 */
161 AssumptionVoidResult assume_conditional(const SymbolicExpr& condition, const SymbolicExpr& conclusion);
162
163 /** @brief Stores a guarded conclusion and reports invalid input. */
164 AssumptionVoidResult assume_conditional_checked(
165 const SymbolicExpr& condition,
166 const SymbolicExpr& conclusion);
167
168 /**
169 * @brief A conditional assumption: "if condition then conclusion".
170 */
171 struct ConditionalAssumption {
172 SymbolicExpr condition;
173 SymbolicExpr conclusion;
174 };
175
176 /**
177 * @brief Retrieve all active conditional assumptions across all scopes (top to bottom).
178 *
179 * Used by the QueryInterface/InferenceEngine to check if any conditional
180 * conclusions are applicable given the current assumption state.
181 *
182 * @return Vector of all conditional assumptions from all scopes (most recent first)
183 */
184 std::vector<ConditionalAssumption> get_active_conditionals() const;
185
186 /**
187 * @brief Evaluate whether a condition expression is satisfied by the current state.
188 *
189 * Checks if the condition (a RelationalNode) can be verified against the
190 * current RelationStore and PropertyStore. Returns True if the condition
191 * is provably satisfied, False if provably unsatisfied, Unknown otherwise.
192 *
193 * @param condition The condition expression to evaluate
194 * @return Tribool indicating whether the condition is satisfied
195 */
196 Tribool evaluate_condition(const SymbolicExpr& condition) const;
197
198 // --- Expression property queries ---
199
200 /// Query whether the expression is positive (> 0).
201 AssumptionTriboolResult is_positive(const SymbolicExpr& expr) const;
202
203 /** @brief Queries positivity and propagates computation failures. */
204 AssumptionTriboolResult is_positive_checked(const SymbolicExpr& expr) const;
205 AssumptionTriboolResult is_positive_checked(
206 const SymbolicExpr& expr, ComputationContext& context) const;
207
208 /// Query whether the expression is negative (< 0).
209 AssumptionTriboolResult is_negative(const SymbolicExpr& expr) const;
210
211 /** @brief Queries negativity and propagates computation failures. */
212 AssumptionTriboolResult is_negative_checked(const SymbolicExpr& expr) const;
213 AssumptionTriboolResult is_negative_checked(
214 const SymbolicExpr& expr, ComputationContext& context) const;
215
216 /// Query whether the expression is non-negative (>= 0).
217 AssumptionTriboolResult is_nonnegative(const SymbolicExpr& expr) const;
218
219 /** @brief Queries non-negativity and propagates computation failures. */
220 AssumptionTriboolResult is_nonnegative_checked(const SymbolicExpr& expr) const;
221 AssumptionTriboolResult is_nonnegative_checked(
222 const SymbolicExpr& expr, ComputationContext& context) const;
223
224 /// Query whether the expression is real.
225 AssumptionTriboolResult is_real(const SymbolicExpr& expr) const;
226
227 /** @brief Queries real-domain membership and propagates computation failures. */
228 AssumptionTriboolResult is_real_checked(const SymbolicExpr& expr) const;
229 AssumptionTriboolResult is_real_checked(
230 const SymbolicExpr& expr, ComputationContext& context) const;
231
232 /// Query whether the expression is an integer.
233 AssumptionTriboolResult is_integer(const SymbolicExpr& expr) const;
234
235 /** @brief Queries integer-domain membership and propagates computation failures. */
236 AssumptionTriboolResult is_integer_checked(const SymbolicExpr& expr) const;
237 AssumptionTriboolResult is_integer_checked(
238 const SymbolicExpr& expr, ComputationContext& context) const;
239
240 /// Query whether the expression is non-zero (!= 0).
241 AssumptionTriboolResult is_nonzero(const SymbolicExpr& expr) const;
242
243 /** @brief Queries nonzero status and propagates computation failures. */
244 AssumptionTriboolResult is_nonzero_checked(const SymbolicExpr& expr) const;
245 AssumptionTriboolResult is_nonzero_checked(
246 const SymbolicExpr& expr, ComputationContext& context) const;
247
248 /**
249 * @brief Serialize the entire AssumptionContext to a human-readable string.
250 *
251 * Format is line-oriented with SCOPE delimiters. Each scope's properties,
252 * relations, and conditionals are serialized one per line. The output ends
253 * with "END".
254 *
255 * @return Serialized string representation of all scopes.
256 */
257 std::string serialize() const;
258
259 /**
260 * @brief Deserialize a string into a fully reconstructed AssumptionContext.
261 *
262 * Parses the line-oriented format produced by serialize().
263 *
264 * @param data Serialized string (as produced by serialize()).
265 * @return Reconstructed context or a parse/contradiction error.
266 */
267 static Result<AssumptionContext> deserialize(const std::string& data);
268
269 /// 面向不可信输入的受检反序列化接口,通过 CasError 传递格式与约束诊断.
270 static Result<AssumptionContext> deserialize_checked(const std::string& data);
271 /// Checked deserialization using the caller's resource and cancellation policy.
272 static Result<AssumptionContext> deserialize_checked(
273 const std::string& data, ComputationContext& context);
274
275 /**
276 * @brief Query whether a symbol is continuous on a given interval (read-through all scopes).
277 * @param symbol Symbol name to query.
278 * @param interval Interval on which to check continuity.
279 * @return True if continuous, False if not, Unknown if undetermined.
280 */
281 AssumptionTriboolResult is_continuous(const std::string& symbol, const Interval& interval) const;
282
283 /** @brief Queries interval continuity and propagates computation failures. */
284 AssumptionTriboolResult is_continuous_checked(
285 const std::string& symbol,
286 const Interval& interval) const;
287
288 /**
289 * @brief Query whether a symbol is differentiable on a given interval (read-through all scopes).
290 * @param symbol Symbol name to query.
291 * @param interval Interval on which to check differentiability.
292 * @return True if differentiable, False if not, Unknown if undetermined.
293 */
294 AssumptionTriboolResult is_differentiable(const std::string& symbol, const Interval& interval) const;
295
296 /** @brief Queries interval differentiability and propagates computation failures. */
297 AssumptionTriboolResult is_differentiable_checked(
298 const std::string& symbol,
299 const Interval& interval) const;
300
301 /**
302 * @brief Query whether a symbol (matrix) is positive definite (read-through all scopes).
303 * @param symbol Symbol name to query.
304 * @return True if positive definite, False if known not, Unknown if undetermined.
305 */
306 AssumptionTriboolResult is_positive_definite(const std::string& symbol) const;
307
308 /** @brief Queries positive definiteness and propagates computation failures. */
309 AssumptionTriboolResult is_positive_definite_checked(const std::string& symbol) const;
310
311 /**
312 * @brief Query whether a symbol (matrix) is positive semidefinite (read-through all scopes).
313 * @param symbol Symbol name to query.
314 * @return True if positive semidefinite, False if known not, Unknown if undetermined.
315 */
316 AssumptionTriboolResult is_positive_semidefinite(const std::string& symbol) const;
317
318 /** @brief Queries positive semidefiniteness and propagates computation failures. */
319 AssumptionTriboolResult is_positive_semidefinite_checked(const std::string& symbol) const;
320
321 /**
322 * @brief Set the maximum recursion depth for inference queries.
323 *
324 * This depth limit is wired to the InferenceEngine used by QueryInterface.
325 * @param depth Maximum depth (must be > 0). Default is 32.
326 */
327 void set_max_query_depth(int depth);
328
329 /**
330 * @brief Get the current maximum recursion depth for inference queries.
331 * @return The configured maximum depth.
332 */
333 int get_max_query_depth() const;
334
335private:
336 friend class detail::AssumptionFacts;
337
338 static AssumptionContext deserialize_impl(
339 const std::string& data, ComputationContext& context);
340
341 struct Scope {
342 PropertyStore properties;
343 RelationStore relations;
344 std::vector<ConditionalAssumption> conditionals;
345 mutable std::uint64_t observed_property_revision = 0;
346 mutable std::uint64_t observed_relation_revision = 0;
347 };
348
349 std::vector<Scope> scope_stack_;
350 struct RelationShadowing;
351 RelationShadowing collect_relation_shadowing(
352 std::size_t scope, detail::RewriteBudget& budget) const;
353 static bool relation_shadowed(
354 const Relation& relation, const RelationShadowing& shadowing,
355 detail::RewriteBudget& budget);
356 std::vector<bool> relation_visibility(
357 std::size_t scope, detail::RewriteBudget& budget) const;
358 Result<bool> has_relation_in_scope(
359 std::size_t scope, const SymbolicExpr& lhs, const SymbolicExpr& rhs,
360 RelationOp op, detail::RewriteBudget& budget) const;
361
362 /// Maximum recursion depth for inference queries (default 32).
363 int max_query_depth_ = 32;
364
365 /** @brief QueryInterface 观察到的缓存代数;存储提交采用惰性检测。 */
366 mutable uint64_t cache_generation_ = 0;
367
368public:
369 /** @brief 观察事务修订并返回当前缓存代数。 */
370 uint64_t cache_generation() const;
371};
372
373/**
374 * @brief Declaration of an assumption to apply within a with_assumptions block.
375 *
376 * Represents a single domain, sign, or relational assumption that can be
377 * applied to an AssumptionContext scope.
378 */
380public:
381 /// The type of assumption being declared.
382 enum class Type { Domain, Sign, Relation };
383
384 /// Construct a domain assumption declaration.
385 static AssumptionDecl make_domain(const std::string& sym, Domain d) {
387 }
388
389 /// Construct a sign assumption declaration.
390 static AssumptionDecl make_sign(const std::string& sym, Sign s) {
392 }
393
394 /// Construct a relational assumption declaration.
395 static AssumptionDecl make_relation(const SymbolicExpr& rel) {
396 return AssumptionDecl(rel);
397 }
398
399 Type type() const noexcept {
400 if (std::holds_alternative<DomainDeclaration>(payload_)) return Type::Domain;
401 if (std::holds_alternative<SignDeclaration>(payload_)) return Type::Sign;
402 return Type::Relation;
403 }
404
405 const std::string& symbol() const {
406 if (const auto* domain = std::get_if<DomainDeclaration>(&payload_)) {
407 return domain->symbol;
408 }
409 if (const auto* sign = std::get_if<SignDeclaration>(&payload_)) {
410 return sign->symbol;
411 }
412 throw std::logic_error("relational assumption has no symbol field");
413 }
414
415 Domain domain() const {
416 return std::get<DomainDeclaration>(payload_).domain;
417 }
418
419 Sign sign() const {
420 return std::get<SignDeclaration>(payload_).sign;
421 }
422
423 const SymbolicExpr& relation() const {
424 return std::get<SymbolicExpr>(payload_);
425 }
426
427private:
429 std::string symbol;
431 };
432
434 std::string symbol;
436 };
437
438 using Payload = std::variant<DomainDeclaration, SignDeclaration, SymbolicExpr>;
439
440 explicit AssumptionDecl(DomainDeclaration declaration)
441 : payload_(std::move(declaration)) {}
442 explicit AssumptionDecl(SignDeclaration declaration)
443 : payload_(std::move(declaration)) {}
444 explicit AssumptionDecl(SymbolicExpr relation)
445 : payload_(std::move(relation)) {}
446
448};
449
451 AssumptionContext& ctx,
452 const AssumptionDecl& decl) {
453 switch (decl.type()) {
455 return ctx.assume_domain_checked(decl.symbol(), decl.domain());
457 return ctx.assume_sign_checked(decl.symbol(), decl.sign());
459 return ctx.assume_checked(decl.relation());
460 }
462 CasErrc::InternalInvariant, "unknown assumption declaration type", "with_assumptions");
463}
464
465/**
466 * @brief Execute a callable within a temporary assumption scope.
467 *
468 * Declaration and callable failures are returned as `CasError`. The temporary
469 * scope is removed before every return.
470 */
471template<typename F>
472auto with_assumptions(AssumptionContext& ctx,
473 const std::vector<AssumptionDecl>& decls,
474 F&& callable)
475 -> std::enable_if_t<!std::is_void_v<decltype(callable())>, Result<decltype(callable())>>
476{
477 using ReturnT = decltype(callable());
478 ctx.push();
479 try {
480 for (const auto& decl : decls) {
481 auto applied = apply_assumption_decl_checked(ctx, decl);
482 if (!applied) {
483 auto popped = ctx.pop();
484 if (!popped) return Result<ReturnT>::failure(popped.error());
485 return Result<ReturnT>::failure(applied.error());
486 }
487 }
488 auto result = callable();
489 auto popped = ctx.pop();
490 if (!popped) return Result<ReturnT>::failure(popped.error());
491 return Result<ReturnT>::success(std::move(result));
492 } catch (const CasError& error) {
493 auto popped = ctx.pop();
494 if (!popped) return Result<ReturnT>::failure(popped.error());
495 return Result<ReturnT>::failure(error);
496 } catch (const std::bad_alloc&) {
497 auto popped = ctx.pop();
498 if (!popped) return Result<ReturnT>::failure(popped.error());
500 CasErrc::ResourceLimit, "with_assumptions allocation failed", "with_assumptions");
501 } catch (const std::exception& ex) {
502 auto popped = ctx.pop();
503 if (!popped) return Result<ReturnT>::failure(popped.error());
505 CasErrc::InternalInvariant, ex.what(), "with_assumptions");
506 } catch (...) {
507 auto popped = ctx.pop();
508 if (!popped) return Result<ReturnT>::failure(popped.error());
509 throw;
510 }
511}
512
513template<typename F>
514auto with_assumptions(AssumptionContext& ctx,
515 const std::vector<AssumptionDecl>& decls,
516 F&& callable)
517 -> std::enable_if_t<std::is_void_v<decltype(callable())>, AssumptionVoidResult>
518{
519 ctx.push();
520 try {
521 for (const auto& decl : decls) {
522 auto applied = apply_assumption_decl_checked(ctx, decl);
523 if (!applied) {
524 auto popped = ctx.pop();
525 if (!popped) return AssumptionVoidResult::failure(popped.error());
526 return AssumptionVoidResult::failure(applied.error());
527 }
528 }
529 callable();
530 auto popped = ctx.pop();
531 if (!popped) return AssumptionVoidResult::failure(popped.error());
533 } catch (const CasError& error) {
534 auto popped = ctx.pop();
535 if (!popped) return AssumptionVoidResult::failure(popped.error());
536 return AssumptionVoidResult::failure(error);
537 } catch (const std::bad_alloc&) {
538 auto popped = ctx.pop();
539 if (!popped) return AssumptionVoidResult::failure(popped.error());
541 CasErrc::ResourceLimit, "with_assumptions allocation failed", "with_assumptions");
542 } catch (const std::exception& ex) {
543 auto popped = ctx.pop();
544 if (!popped) return AssumptionVoidResult::failure(popped.error());
546 CasErrc::InternalInvariant, ex.what(), "with_assumptions");
547 } catch (...) {
548 auto popped = ctx.pop();
549 if (!popped) return AssumptionVoidResult::failure(popped.error());
550 throw;
551 }
552}
553
554template<typename F>
555auto with_assumptions(AssumptionContext& ctx,
556 std::initializer_list<AssumptionDecl> decls,
557 F&& callable)
558 -> decltype(with_assumptions(
559 ctx, std::vector<AssumptionDecl>(decls), std::forward<F>(callable)))
560{
561 return with_assumptions(
562 ctx, std::vector<AssumptionDecl>(decls), std::forward<F>(callable));
563}
564
565} // namespace LMCAS
Core enumerations and forward declarations for the Assumption System.
Declaration of an assumption to apply within a with_assumptions block.
static AssumptionDecl make_relation(const SymbolicExpr &rel)
Construct a relational assumption declaration.
const SymbolicExpr & relation() const
Type
The type of assumption being declared.
AssumptionDecl(SignDeclaration declaration)
AssumptionDecl(DomainDeclaration declaration)
const std::string & symbol() const
std::variant< DomainDeclaration, SignDeclaration, SymbolicExpr > Payload
AssumptionDecl(SymbolicExpr relation)
static AssumptionDecl make_sign(const std::string &sym, Sign s)
Construct a sign assumption declaration.
static AssumptionDecl make_domain(const std::string &sym, Domain d)
Construct a domain assumption declaration.
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
#define LMCAS_API
多元 Hensel 提升(单变量步)
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)
AssumptionVoidResult apply_assumption_decl_checked(AssumptionContext &ctx, const AssumptionDecl &decl)
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
Boundedness
Boundedness classification for symbols.
Tribool
Tri-state logic value for property queries.
Result< Tribool > AssumptionTriboolResult
Definiteness
Matrix definiteness classification.
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
std::size_t std::size_t depth
const NumberDomainSet & domain
auto with_assumptions(AssumptionContext &ctx, const std::vector< AssumptionDecl > &decls, F &&callable) -> std::enable_if_t<!std::is_void_v< decltype(callable())>, Result< decltype(callable())> >
Execute a callable within a temporary assumption scope.
ExprResult sym(const std::string &name)
Finiteness
Finiteness classification for limits and sequences.
Result< void > AssumptionVoidResult
ExprResult relation(const ExprPtr &lhs, const ExprPtr &rhs, RelationOp op)
const ExprPtr & rhs
Parity
Integer parity classification.
Sign
Sign classification for symbols and expressions.
A stored relational constraint between two symbolic expressions.
PropertyStore class for mapping symbol names to declared properties.
RelationStore class for storing relational constraints between symbolic expressions.