/*++ Copyright (c) 2006 Microsoft Corporation Module Name: smt_enode.h Abstract: Author: Leonardo de Moura (leonardo) 2008-02-18. Revision History: --*/ #ifndef _SMT_ENODE_H_ #define _SMT_ENODE_H_ #include"ast.h" #include"smt_types.h" #include"smt_eq_justification.h" #include"smt_theory_var_list.h" #include"approx_set.h" namespace smt { /** \brief Justification for the transitivity rule. */ struct trans_justification { enode * m_target; eq_justification m_justification; trans_justification(): m_target(0), m_justification(null_eq_justification) { } }; class tmp_enode; /** \brief Aditional data-structure for implementing congruence closure, equality propagation, and the theory central bus of equalities. */ class enode { app * m_owner; //!< The application that 'owns' this enode. enode * m_root; //!< Representative of the equivalence class enode * m_next; //!< Next element in the equivalence class. enode * m_cg; unsigned m_class_size; //!< Size of the equivalence class if the enode is the root. unsigned m_generation; //!< Tracks how many quantifier instantiation rounds were needed to generate this enode. unsigned m_func_decl_id; //!< Id generated by the congruence table for fast indexing. unsigned m_mark:1; //!< Multi-purpose auxiliary mark. unsigned m_mark2:1; //!< Multi-purpose auxiliary mark. unsigned m_interpreted:1; //!< True if the node is an interpreted constant. unsigned m_suppress_args:1; //!< True if the arguments of m_owner should not be accessed by this enode. unsigned m_eq:1; //!< True if it is an equality unsigned m_commutative:1; //!< True if commutative app unsigned m_bool:1; //!< True if it is a boolean enode unsigned m_merge_tf:1; //!< True if the enode should be merged with true/false when the associated boolean variable is assigned. unsigned m_cgc_enabled:1; //!< True if congruence closure is enabled for this enode. unsigned m_iscope_lvl; //!< When the enode was internalized /* The following property is valid for m_parents If this = m_root, then for every term f(a) such that a->get_root() == m_root, there is a f(b) in m_parents such that b->get_root() == m_root, and f(a) and f(b) are congruent. Remark: f(a) and f(b) may have other arguments. Exception: If f(a) and f(b) are terms of the form (= a c) and (= b d), then m_parents will not contains (= b d) if b->get_root() == d->get_root(). Remark regarding relevancy propagation: relevancy is propagated to all elements of an equivalence class. So, if there is a f(a) that is relevant, then the congruent f(b) in m_parents will also be relevant. */ enode_vector m_parents; //!< Parent enodes of the equivalence class. theory_var_list m_th_var_list; //!< List of theories that 'care' about this enode. trans_justification m_trans; //!< A justification for the enode being equal to its root. char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern approx_set m_lbls; approx_set m_plbls; enode * m_args[0]; //!< Cached args friend class context; friend class euf_manager; friend class conflict_resolution; theory_var_list * get_th_var_list() { return m_th_var_list.get_th_var() == null_theory_var ? 0 : &m_th_var_list; } friend class set_merge_tf_trail; /** \brief Return true if the enode should be merged with the true (false) enodes when the associated boolean variable is assigned to true (false). */ bool merge_tf() const { return m_merge_tf; } friend class add_th_var_trail; friend class replace_th_var_trail; void add_th_var(theory_var v, theory_id id, region & r); void replace_th_var(theory_var v, theory_id id); void del_th_var(theory_id id); friend class tmp_enode; static enode * init(ast_manager & m, void * mem, ptr_vector const & app2enode, app * owner, unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl, bool cgc_enabled, bool update_children_parent); public: static unsigned get_enode_size(unsigned num_args) { return sizeof(enode) + num_args * sizeof(enode*); } static enode * mk(ast_manager & m, region & r, ptr_vector const & app2enode, app * owner, unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl, bool cgc_enabled, bool update_children_parent); static enode * mk_dummy(ast_manager & m, ptr_vector const & app2enode, app * owner); static void del_dummy(enode * n) { dealloc_svect(reinterpret_cast(n)); } unsigned get_func_decl_id() const { return m_func_decl_id; } void set_func_decl_id(unsigned id) { m_func_decl_id = id; } void mark_as_interpreted() { SASSERT(!m_interpreted); SASSERT(m_owner->get_num_args() == 0); SASSERT(m_class_size == 1); m_interpreted = true; } void del_eh(ast_manager & m, bool update_children_parent = true); app * get_owner() const { return m_owner; } unsigned get_owner_id() const { return m_owner->get_id(); } func_decl * get_decl() const { return m_owner->get_decl(); } unsigned get_decl_id() const { return m_owner->get_decl()->get_decl_id(); } unsigned hash() const { return m_owner->hash(); } enode * get_root() const { return m_root; } enode * get_next() const { return m_next; } unsigned get_num_args() const { return m_suppress_args ? 0 : m_owner->get_num_args(); } enode * get_arg(unsigned idx) const { SASSERT(idx < get_num_args()); return m_args[idx]; } enode * const * get_args() const { return m_args; } // unsigned get_id() const { // return m_id; // } unsigned get_class_size() const { return m_class_size; } bool is_bool() const { return m_bool; } bool is_eq() const { return m_eq; } bool is_true_eq() const { return m_eq && get_arg(0)->get_root() == get_arg(1)->get_root(); } bool is_marked() const { return m_mark; } void set_mark() { SASSERT(!m_mark); m_mark = true; } void unset_mark() { SASSERT(m_mark); m_mark = false; } bool is_marked2() const { return m_mark2; } void set_mark2() { SASSERT(!m_mark2); m_mark2 = true; } void unset_mark2() { SASSERT(m_mark2); m_mark2 = false; } bool is_interpreted() const { return m_interpreted; } /** \brief Return true if node is not a constant and it is the root of its congruence class. \remark if get_num_args() == 0, then is_cgr() = false. */ bool is_cgr() const { return m_cg == this; } enode * get_cg() const { return m_cg; } bool is_cgc_enabled() const { return m_cgc_enabled; } bool is_commutative() const { return m_commutative; } unsigned get_num_parents() const { return m_parents.size(); } enode_vector::iterator begin_parents() { return m_parents.begin(); } enode_vector::iterator end_parents() { return m_parents.end(); } enode_vector::const_iterator begin_parents() const { return m_parents.begin(); } enode_vector::const_iterator end_parents() const { return m_parents.end(); } theory_var_list const * get_th_var_list() const { return m_th_var_list.get_th_var() == null_theory_var ? 0 : &m_th_var_list; } bool has_th_vars() const { return m_th_var_list.get_th_var() != null_theory_var; } unsigned get_num_th_vars() const; theory_var get_th_var(theory_id th_id) const; unsigned get_generation() const { return m_generation; } void set_generation(context & ctx, unsigned generation); /** \brief Return the enode n that is in the eqc of *this, and has the minimal generation. That is, there is no other enode with smaller generation. */ enode * get_eq_enode_with_min_gen(); unsigned get_iscope_lvl() const { return m_iscope_lvl; } void set_lbl_hash(context & ctx); bool has_lbl_hash() const { return m_lbl_hash >= 0; } unsigned char get_lbl_hash() const { SASSERT(m_lbl_hash >= 0 && static_cast(m_lbl_hash) < approx_set_traits::capacity); return static_cast(m_lbl_hash); } approx_set & get_lbls() { return m_lbls; } approx_set & get_plbls() { return m_plbls; } const approx_set & get_lbls() const { return m_lbls; } const approx_set & get_plbls() const { return m_plbls; } void display_lbls(std::ostream & out) const; #ifdef Z3DEBUG bool check_invariant() const; bool trans_reaches(enode * n) const; bool check_parent_invariant() const; bool contains_parent_congruent_to(enode * p) const; #endif }; inline bool same_eqc(enode const * n1 , enode const * n2) { return n1->get_root() == n2->get_root(); } /** \brief Return true, if n1 and n2 are congruent. Set comm to true, if the nodes are congruent modulo commutativity. */ bool congruent(enode * n1, enode * n2, bool & comm); inline bool congruent(enode * n1, enode * n2) { bool aux; return congruent(n1, n2, aux); } unsigned get_max_generation(unsigned num_enodes, enode * const * enodes); void unmark_enodes(unsigned num_enodes, enode * const * enodes); void unmark_enodes2(unsigned num_enodes, enode * const * enodes); class tmp_enode { tmp_app m_app; unsigned m_capacity; char * m_enode_data; enode * get_enode() { return reinterpret_cast(m_enode_data); } void set_capacity(unsigned new_capacity); public: tmp_enode(); ~tmp_enode(); enode * set(func_decl * f, unsigned num_args, enode * const * args); void reset(); }; }; #endif /* _SMT_ENODE_H_ */