14 return !properties.get_signs(symbol).empty() ||
22 const std::vector<std::array<std::size_t, 2>>& alternatives,
24 for (
const auto& premises : alternatives) {
26 if (!step)
throw step.
error();
27 if (visible[premises[0]] && visible[premises[1]])
return true;
35AssumptionContext::AssumptionContext() {
36 scope_stack_.emplace_back();
39AssumptionContext::AssumptionContext(AssumptionContext&& other)
40 : AssumptionContext() {
41 scope_stack_.swap(other.scope_stack_);
42 max_query_depth_ = other.max_query_depth_;
43 ++other.cache_generation_;
46AssumptionContext& AssumptionContext::operator=(
const AssumptionContext& other) {
48 auto candidate = other.scope_stack_;
49 scope_stack_.swap(candidate);
50 max_query_depth_ = other.max_query_depth_;
56AssumptionContext& AssumptionContext::operator=(AssumptionContext&& other)
noexcept {
58 scope_stack_.swap(other.scope_stack_);
59 std::swap(max_query_depth_, other.max_query_depth_);
61 ++other.cache_generation_;
66uint64_t AssumptionContext::cache_generation()
const {
68 for (
const auto& scope : scope_stack_) {
69 const auto properties = scope.properties.revision();
70 const auto relations = scope.relations.revision();
71 if (scope.observed_property_revision != properties ||
72 scope.observed_relation_revision != relations) {
73 scope.observed_property_revision = properties;
74 scope.observed_relation_revision = relations;
78 if (changed) ++cache_generation_;
79 return cache_generation_;
84void AssumptionContext::push() {
85 scope_stack_.emplace_back();
90 if (scope_stack_.size() <= 1) {
94 scope_stack_.pop_back();
99int AssumptionContext::depth()
const {
100 return static_cast<int>(scope_stack_.size());
105PropertyStore& AssumptionContext::current_properties() {
106 return scope_stack_.back().properties;
109const PropertyStore& AssumptionContext::current_properties()
const {
110 return scope_stack_.back().properties;
113RelationStore& AssumptionContext::current_relations() {
114 return scope_stack_.back().relations;
117const RelationStore& AssumptionContext::current_relations()
const {
118 return scope_stack_.back().relations;
123bool AssumptionContext::has_sign(
const std::string& symbol,
Sign sign)
const {
124 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
125 auto signs = it->properties.get_signs(symbol);
126 if (!signs.empty())
return signs.count(sign) > 0;
131bool AssumptionContext::has_domain(
const std::string& symbol,
Domain domain)
const {
132 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
133 const auto declared_domain = it->properties.get_domain(symbol);
135 return it->properties.has_domain(symbol,
domain);
141Domain AssumptionContext::get_domain(
const std::string& symbol)
const {
142 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
143 const auto domain = it->properties.get_domain(symbol);
149std::unordered_set<Sign, SignHash> AssumptionContext::get_signs(
150 const std::string& symbol)
const {
151 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
152 auto signs = it->properties.get_signs(symbol);
153 if (!signs.empty())
return signs;
158Parity AssumptionContext::get_parity(
const std::string& symbol)
const {
159 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
160 const auto parity = it->properties.get_parity(symbol);
166Boundedness AssumptionContext::get_boundedness(
const std::string& symbol)
const {
167 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
168 const auto boundedness = it->properties.get_boundedness(symbol);
174std::optional<Interval> AssumptionContext::get_bounds(
const std::string& symbol)
const {
175 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
176 auto bounds = it->properties.get_bounds(symbol);
177 if (bounds)
return bounds;
182bool AssumptionContext::is_transcendental(
const std::string& symbol)
const {
183 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
184 if (it->properties.is_transcendental(symbol))
return true;
190Finiteness AssumptionContext::get_finiteness(
const std::string& symbol)
const {
191 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
192 auto value = it->properties.get_finiteness(symbol);
198Definiteness AssumptionContext::get_definiteness(
const std::string& symbol)
const {
199 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
200 auto value = it->properties.get_definiteness(symbol);
206std::optional<SymbolicExpr> AssumptionContext::get_period(
207 const std::string& symbol,
const std::string&
variable)
const {
208 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
215bool AssumptionContext::is_periodic(
const std::string& symbol,
const std::string&
variable)
const {
216 return get_period(symbol,
variable).has_value();
219bool AssumptionContext::has_period_declarations(
const std::string& symbol)
const {
220 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
221 if (!it->properties.get_period_decls(symbol).empty())
return true;
227 const std::string& symbol,
const std::string&
variable,
230 for (
auto it = scope_stack_.rbegin(); it != scope_stack_.rend(); ++it) {
231 auto value = it->properties.get_monotonicity_checked(
246 for (std::size_t i = scope + 1; i < scope_stack_.size(); ++i) {
248 if (!step)
throw step.
error();
249 const auto& nearer = scope_stack_[i];
250 const auto& store = nearer.relations;
251 for (std::size_t j = 0; j < store.relations_.size(); ++j) {
253 if (!step)
throw step.
error();
254 if (!store.proofs_[j].declared)
continue;
255 const auto& declared = store.relations_[j];
256 const SymbolicExpr* subject =
nullptr;
258 subject = &declared.lhs;
260 subject = &declared.rhs;
262 if (!subject)
continue;
270 for (
const auto& symbol : nearer.properties.get_all_symbols()) {
272 if (!step)
throw step.
error();
273 if (has_value_declaration(nearer.properties, symbol)) {
274 shadowing.
symbols.insert(symbol);
281bool AssumptionContext::relation_shadowed(
282 const Relation&
relation,
const RelationShadowing& shadowing,
283 detail::RewriteBudget& budget) {
286 for (
const auto& symbol : shadowing.symbols) {
288 if (!step) {
throw step.error(); }
292 if (shadowing.expressions.empty()) {
return false; }
295 for (
const auto& expression : shadowing.expressions) {
297 if (!step) {
throw step.error(); }
300 if ((lhs && lhs->equals(*subject)) || (
rhs &&
rhs->equals(*subject))) {
307std::vector<bool> AssumptionContext::relation_visibility(
310 if (scope + 1 == scope_stack_.size())
return {};
311 const auto& store = scope_stack_[scope].relations;
312 const auto shadowing = collect_relation_shadowing(scope, budget);
313 std::vector<bool> unshadowed(store.relations_.size(),
false);
314 std::vector<bool> visible(store.relations_.size(),
false);
315 for (std::size_t i = 0; i < store.relations_.size(); ++i) {
317 if (!step)
throw step.
error();
318 unshadowed[i] = !relation_shadowed(store.relations_[i], shadowing, budget);
319 visible[i] = unshadowed[i] && store.proofs_[i].declared;
324 if (!step)
throw step.
error();
326 for (std::size_t i = 0; i < store.relations_.size(); ++i) {
328 if (!step)
throw step.
error();
329 if (!unshadowed[i] || visible[i])
continue;
330 if (!
has_visible_proof(store.proofs_[i].alternatives, visible, budget))
continue;
339 std::size_t scope,
const SymbolicExpr& lhs,
const SymbolicExpr&
rhs,
341 const auto& relations = scope_stack_[scope].relations.get_relations();
342 const auto visible = relation_visibility(scope, budget);
345 for (std::size_t j = 0; j < relations.size(); ++j) {
348 const auto&
relation = relations[j];
349 if (
relation.op !=
op || (!visible.empty() && !visible[j])) {
continue; }
352 if (!relation_lhs || !relation_rhs) {
continue; }
355 if (left->equals(*relation_lhs) &&
right->equals(*relation_rhs)) {
return true; }
360bool AssumptionContext::has_relation(
361 const SymbolicExpr& lhs,
const SymbolicExpr&
rhs,
RelationOp op)
const {
363 auto result = has_relation_checked(lhs,
rhs,
op,
context);
364 if (!result)
throw result.error();
365 return result.value();
373 std::numeric_limits<std::size_t>::max(),
"assumption.has_relation");
374 auto step =
context.consume_steps(1,
"assumption.has_relation");
378 if (!left || !
right) {
return false; }
381 for (std::size_t i = scope_stack_.size(); i-- > 0;) {
382 step =
context.consume_steps(1,
"assumption.has_relation");
384 auto match = has_relation_in_scope(i, lhs,
rhs,
op, budget);
385 if (!match || match.value()) {
return match; }
390 }
catch (
const std::bad_alloc&) {
392 "relation query allocation failed",
"assumption.has_relation");
396std::vector<Relation> AssumptionContext::get_visible_relations()
const {
398 auto result = get_visible_relations_checked(
context);
399 if (!result)
throw result.error();
400 return std::move(result.value());
407 std::numeric_limits<std::size_t>::max(),
"assumption.visible_relations");
408 std::vector<Relation> visible;
409 for (std::size_t i = scope_stack_.size(); i-- > 0;) {
410 auto step =
context.consume_steps(1,
"assumption.visible_relations");
412 const auto& relations = scope_stack_[i].relations.get_relations();
413 const auto visibility = relation_visibility(i, budget);
414 for (std::size_t j = 0; j < relations.size(); ++j) {
415 step =
context.consume_steps(1,
"assumption.visible_relations");
417 if (visibility.empty() || visibility[j]) visible.push_back(relations[j]);
423 }
catch (
const std::bad_alloc&) {
425 "relation query allocation failed",
"assumption.visible_relations");
438 constexpr const char*
operation =
"assume_domain";
443 auto result = scope_stack_.back().properties.declare_domain_checked(
variable,
domain);
446 result.error().code, result.error().message, operation);
454 return assume_sign_checked(
variable, sign);
460 constexpr const char*
operation =
"assume_sign";
465 auto result = scope_stack_.back().properties.declare_sign_checked(
variable, sign);
468 result.error().code, result.error().message, operation);
478 constexpr const char*
operation =
"assume";
491 auto result = scope_stack_.back().relations.add_relation_checked(
492 lhs,
rhs, rel_node->op(), scope_stack_.back().properties);
493 if (!result.has_value()) {
496 }
catch (
const std::bad_alloc&) {
499 }
catch (
const std::invalid_argument& ex) {
501 }
catch (
const std::exception& ex) {
508void AssumptionContext::set_max_query_depth(
int depth) {
509 if (
depth <= 0 ||
depth == max_query_depth_)
return;
510 max_query_depth_ =
depth;
514int AssumptionContext::get_max_query_depth()
const {
515 return max_query_depth_;
AssumptionContext class with scoped push/pop management.
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
const CasError & error() const
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
ComputationContext & context() const noexcept
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
bool has_visible_proof(const std::vector< std::array< std::size_t, 2 > > &alternatives, const std::vector< bool > &visible, detail::RewriteBudget &budget)
bool has_value_declaration(const PropertyStore &properties, const std::string &symbol)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
ComputationContext const std::string & operation
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)
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
@ Complex
Complex numbers (default, least specific)
@ Algebraic
Algebraic numbers (roots of polynomials with rational coefficients)
Boundedness
Boundedness classification for symbols.
@ Unknown
Boundedness not determined
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
@ Unknown
Monotonicity not determined
Definiteness
Matrix definiteness classification.
@ Unknown
Definiteness not determined
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
std::size_t std::size_t depth
const NumberDomainSet & domain
std::set< std::string > free_variables(const detail::SymbolicNodePtr &expression, detail::RewriteBudget *budget)
Finiteness
Finiteness classification for limits and sequences.
@ Unknown
Finiteness not determined
Result< void > AssumptionVoidResult
ExprResult relation(const ExprPtr &lhs, const ExprPtr &rhs, RelationOp op)
const std::string const ExprPtr & value
Parity
Integer parity classification.
@ Unknown
Parity not determined
Sign
Sign classification for symbols and expressions.
std::vector< SymbolicExpr > expressions
std::set< std::string > symbols