/*++ Copyright (c) 2006 Microsoft Corporation Module Name: smt_clause.h Abstract: Author: Leonardo de Moura (leonardo) 2008-02-18. Revision History: --*/ #pragma once #include "ast/ast.h" #include "smt/smt_literal.h" #include "util/tptr.h" #include "util/obj_hashtable.h" #include "smt/smt_justification.h" namespace smt { class clause; /** \brief Abstract functor: clause deletion event handler. */ class clause_del_eh { public: virtual ~clause_del_eh() = default; virtual void operator()(ast_manager & m, clause * cls) = 0; }; enum clause_kind { CLS_AUX, // an input assumption CLS_TH_AXIOM, // a theory axiom CLS_LEARNED, // learned through conflict resolution CLS_TH_LEMMA // a theory lemma }; inline bool is_axiom(clause_kind k) { return k == CLS_AUX || k == CLS_TH_AXIOM; } inline bool is_lemma(clause_kind k) { return k == CLS_LEARNED || k == CLS_TH_LEMMA; } /** \brief A SMT clause. A clause has several optional fields, I store space for them only if they are actually used. */ class clause { unsigned m_num_literals; unsigned m_capacity:24; //!< some of the clause literals can be simplified and removed, this field contains the original number of literals (used for GC). unsigned m_kind:2; //!< kind unsigned m_reinit:1; //!< true if the clause is in the reinit stack (only for learned clauses and aux_lemmas) unsigned m_reinternalize_atoms:1; //!< true if atoms must be reinitialized during reinitialization unsigned m_has_atoms:1; //!< true if the clause has memory space for storing atoms. unsigned m_has_del_eh:1; //!< true if must notify event handler when deleted. unsigned m_has_justification:1; //!< true if the clause has a justification attached to it. unsigned m_deleted:1; //!< true if the clause is marked for deletion by was not deleted yet because it is referenced by some data-structure (e.g., m_lemmas) literal m_lits[0]; static unsigned get_obj_size(unsigned num_lits, clause_kind k, bool has_atoms, bool has_del_eh, bool has_justification) { unsigned r = sizeof(clause) + sizeof(literal) * num_lits; if (smt::is_lemma(k)) r += sizeof(unsigned); /* dvitek: Fix alignment issues on 64-bit platforms. The * 'if' statement below probably isn't worthwhile since * I'm guessing the allocator is probably going to round * up internally anyway. */ //if (has_atoms || has_del_eh || has_justification) r = (r + (sizeof(void*)-1)) & ~(sizeof(void*)-1); if (has_atoms) r += sizeof(expr*) * num_lits; if (has_del_eh) r += sizeof(clause_del_eh *); if (has_justification) r += sizeof(justification *); return r; } unsigned const * get_activity_addr() const { return reinterpret_cast(m_lits + m_capacity); } unsigned * get_activity_addr() { return reinterpret_cast(m_lits + m_capacity); } clause_del_eh * const * get_del_eh_addr() const { unsigned const * addr = get_activity_addr(); if (is_lemma()) addr ++; /* dvitek: It would be better to use uintptr_t than * size_t, but we need to wait until c++11 support is * really available. */ size_t as_int = reinterpret_cast(addr); as_int = (as_int + sizeof(void*)-1) & ~static_cast(sizeof(void*)-1); return reinterpret_cast(as_int); } justification * const * get_justification_addr() const { clause_del_eh * const * addr = get_del_eh_addr(); if (m_has_del_eh) addr ++; return reinterpret_cast(addr); } expr * const * get_atoms_addr() const { justification * const * addr = get_justification_addr(); if (m_has_justification) addr ++; return reinterpret_cast(addr); } friend class context; void swap_lits(unsigned idx1, unsigned idx2) { SASSERT(idx1 < m_num_literals); SASSERT(idx2 < m_num_literals); std::swap(m_lits[idx1], m_lits[idx2]); } bool is_watch(literal l) const { return m_lits[0] == l || m_lits[1] == l; } void set_literal(unsigned idx, literal l) { m_lits[idx] = l; } void set_num_literals(unsigned n) { SASSERT(!m_reinit); m_num_literals = n; } void set_justification(justification * new_js) { SASSERT(m_has_justification); SASSERT(!m_reinit); SASSERT(!is_lemma() || new_js == 0 || !new_js->in_region()); justification ** js_addr = const_cast(get_justification_addr()); *js_addr = new_js; } void release_atoms(ast_manager & m); public: static clause * mk(ast_manager & m, unsigned num_lits, literal * lits, clause_kind k, justification * js = nullptr, clause_del_eh * del_eh = nullptr, bool save_atoms = false, expr * const * bool_var2expr_map = nullptr); void deallocate(ast_manager & m); clause_kind get_kind() const { return static_cast(m_kind); } bool is_lemma() const { return smt::is_lemma(get_kind()); } bool is_learned() const { return get_kind() == CLS_LEARNED; } bool is_th_lemma() const { return get_kind() == CLS_TH_LEMMA; } bool in_reinit_stack() const { return m_reinit; } bool reinternalize_atoms() const { return m_reinternalize_atoms; } unsigned get_num_literals() const { return m_num_literals; } literal & operator[](unsigned idx) { SASSERT(idx < m_num_literals); return m_lits[idx]; } literal operator[](unsigned idx) const { SASSERT(idx < m_num_literals); return m_lits[idx]; } literal get_literal(unsigned idx) const { return (*this)[idx]; } literal & get_literal(unsigned idx) { return (*this)[idx]; } literal * begin() { return m_lits; } literal * end() { return m_lits + m_num_literals; } literal const * begin() const { return m_lits; } literal const * end() const { return m_lits + m_num_literals; } unsigned get_activity() const { SASSERT(is_lemma()); return *(get_activity_addr()); } void set_activity(unsigned act) { SASSERT(is_lemma()); *(get_activity_addr()) = act; } clause_del_eh * get_del_eh() const { return m_has_del_eh ? *(get_del_eh_addr()) : nullptr; } justification * get_justification() const { return m_has_justification ? *(get_justification_addr()) : nullptr; } unsigned get_num_atoms() const { return m_reinternalize_atoms ? m_num_literals : 0; } expr * get_atom(unsigned idx) const { SASSERT(idx < get_num_atoms()); return UNTAG(expr*, get_atoms_addr()[idx]); } bool get_atom_sign(unsigned idx) const { SASSERT(idx < get_num_atoms()); return GET_TAG(get_atoms_addr()[idx]) == 1; } bool erase_atom(unsigned idx); void inc_clause_activity() { SASSERT(is_lemma()); set_activity(get_activity() + 1); } std::ostream& display(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; std::ostream& display_smt2(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; std::ostream& display_compact(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; unsigned hash() const { return get_ptr_hash(this); } void mark_as_deleted(ast_manager & m) { SASSERT(!m_deleted); m_deleted = true; clause_del_eh * del_eh = get_del_eh(); if (del_eh) { (*del_eh)(m, this); *(const_cast(get_del_eh_addr())) = nullptr; } } bool deleted() const { return m_deleted; } }; typedef ptr_vector clause_vector; typedef obj_hashtable clause_set; };