/*++ Copyright (c) 2020 Microsoft Corporation Module Name: q_clause.h Abstract: Literals, clauses, justifications for quantifier instantiation Author: Nikolaj Bjorner (nbjorner) 2021-01-24 --*/ #pragma once #include "util/dlist.h" #include "ast/ast.h" #include "ast/quantifier_stat.h" #include "ast/euf/euf_enode.h" #include "sat/smt/euf_solver.h" namespace q { struct lit { expr_ref lhs; expr_ref rhs; bool sign; lit(expr_ref const& lhs, expr_ref const& rhs, bool sign): lhs(lhs), rhs(rhs), sign(sign) { SASSERT(!rhs.m().is_false(rhs) || !sign); } std::ostream& display(std::ostream& out) const; }; struct binding; struct clause { unsigned m_index; vector m_lits; quantifier_ref m_q; unsigned m_watch = 0; sat::literal m_literal = sat::null_literal; q::quantifier_stat* m_stat = nullptr; binding* m_bindings = nullptr; clause(ast_manager& m, unsigned idx) : m_index(idx), m_q(m) {} std::ostream& display(euf::solver& ctx, std::ostream& out) const; lit const& operator[](unsigned i) const { return m_lits[i]; } lit& operator[](unsigned i) { return m_lits[i]; } unsigned size() const { return m_lits.size(); } unsigned num_decls() const { return m_q->get_num_decls(); } unsigned index() const { return m_index; } quantifier* q() const { return m_q; } }; struct binding : public dll_base { clause* c; app* m_pattern; unsigned m_max_generation; unsigned m_min_top_generation; unsigned m_max_top_generation; euf::enode* m_nodes[0]; binding(clause& c, app* pat, unsigned max_generation, unsigned min_top, unsigned max_top): c(&c), m_pattern(pat), m_max_generation(max_generation), m_min_top_generation(min_top), m_max_top_generation(max_top) {} euf::enode* const* nodes() { return m_nodes; } euf::enode* operator[](unsigned i) const { return m_nodes[i]; } std::ostream& display(euf::solver& ctx, std::ostream& out) const; unsigned size() const { return c->num_decls(); } quantifier* q() const { return c->m_q; } bool eq(binding const& other) const { if (q() != other.q()) return false; for (unsigned i = size(); i-- > 0; ) if ((*this)[i] != other[i]) return false; return true; } }; struct binding_khasher { unsigned operator()(binding const* f) const { return f->q()->get_id(); } }; struct binding_chasher { unsigned operator()(binding const* f, unsigned idx) const { return f->m_nodes[idx]->hash(); } }; struct binding_hash_proc { unsigned operator()(binding const* f) const { return get_composite_hash(const_cast(f), f->size()); } }; struct binding_eq_proc { bool operator()(binding const* a, binding const* b) const { return a->eq(*b); } }; typedef ptr_hashtable bindings; inline std::ostream& operator<<(std::ostream& out, binding const& f) { out << "[fp " << f.q()->get_id() << ":"; for (unsigned i = 0; i < f.size(); ++i) out << " " << f[i]->get_expr_id(); return out << "]"; } struct justification { expr* m_lhs, * m_rhs; bool m_sign; unsigned m_generation; unsigned m_num_ex; size_t** m_explain; clause& m_clause; euf::enode* const* m_binding; justification(lit const& l, clause& c, euf::enode* const* b, unsigned generation, unsigned n, size_t** ev) : m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_generation(generation), m_num_ex(n), m_explain(ev), m_clause(c), m_binding(b) {} sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); } static justification& from_index(size_t idx) { return *reinterpret_cast(sat::constraint_base::from_index(idx)->mem()); } static size_t get_obj_size() { return sat::constraint_base::obj_size(sizeof(justification)); } }; }