/*++ Copyright (c) 2006 Microsoft Corporation Module Name: theory_array_base.h Abstract: Author: Leonardo de Moura (leonardo) 2008-06-02. Revision History: --*/ #pragma once #include "smt/smt_theory.h" #include "smt/theory_array_bapa.h" #include "ast/array_decl_plugin.h" #include "model/array_factory.h" namespace smt { class theory_array_base : public theory { friend class theory_array_bapa; protected: bool m_found_unsupported_op; unsigned m_array_weak_head; svector m_array_weak_trail; bool has_propagate_up_trail() const { return m_array_weak_head < m_array_weak_trail.size(); } void add_weak_var(theory_var v); virtual void set_prop_upward(theory_var v) {} void found_unsupported_op(expr * n); void found_unsupported_op(enode* n) { found_unsupported_op(n->get_expr()); } void found_unsupported_op(theory_var v) { found_unsupported_op(get_enode(v)->get_expr()); } bool is_store(app const* n) const { return n->is_app_of(get_id(), OP_STORE); } bool is_map(app const* n) const { return n->is_app_of(get_id(), OP_ARRAY_MAP); } bool is_select(app const* n) const { return n->is_app_of(get_id(), OP_SELECT); } bool is_default(app const* n) const { return n->is_app_of(get_id(), OP_ARRAY_DEFAULT); } bool is_const(app const* n) const { return n->is_app_of(get_id(), OP_CONST_ARRAY); } bool is_array_ext(app const * n) const { return n->is_app_of(get_id(), OP_ARRAY_EXT); } bool is_as_array(app const * n) const { return n->is_app_of(get_id(), OP_AS_ARRAY); } bool is_array_sort(sort const* s) const { return s->is_sort_of(get_id(), ARRAY_SORT); } bool is_array_sort(app const* n) const { return is_array_sort(n->get_sort()); } bool is_set_has_size(app const* n) const { return n->is_app_of(get_id(), OP_SET_HAS_SIZE); } bool is_set_card(app const* n) const { return n->is_app_of(get_id(), OP_SET_CARD); } bool is_store(enode const * n) const { return is_store(n->get_expr()); } bool is_map(enode const* n) const { return is_map(n->get_expr()); } bool is_select(enode const* n) const { return is_select(n->get_expr()); } bool is_const(enode const* n) const { return is_const(n->get_expr()); } bool is_as_array(enode const * n) const { return is_as_array(n->get_expr()); } bool is_default(enode const* n) const { return is_default(n->get_expr()); } bool is_array_sort(enode const* n) const { return is_array_sort(n->get_expr()); } bool is_set_has_size(enode const* n) const { return is_set_has_size(n->get_expr()); } bool is_set_carde(enode const* n) const { return is_set_card(n->get_expr()); } bool is_select_arg(enode* r); app * mk_select(unsigned num_args, expr * const * args); app * mk_select_reduce(unsigned num_args, expr * * args); app * mk_select(expr_ref_vector const& args) { return mk_select(args.size(), args.data()); } app * mk_store(unsigned num_args, expr * const * args); app * mk_default(expr* a); unsigned get_dimension(sort* s) const; ptr_vector m_axiom1_todo; enode_pair_vector m_axiom2_todo; enode_pair_vector m_extensionality_todo; enode_pair_vector m_congruent_todo; scoped_ptr m_bapa; void assert_axiom(unsigned num_lits, literal * lits); void assert_axiom(literal l1, literal l2); void assert_axiom(literal l); void assert_store_axiom1_core(enode * n); void assert_store_axiom2_core(enode * store, enode * select); void assert_store_axiom1(enode * n) { m_axiom1_todo.push_back(n); } bool assert_store_axiom2(enode * store, enode * select); void assert_extensionality_core(enode * a1, enode * a2); bool assert_extensionality(enode * a1, enode * a2); expr_ref instantiate_lambda(app* e); void assert_congruent_core(enode * a1, enode * a2); void assert_congruent(enode * a1, enode * a2); // -------------------------------------------------- // Array sort -> extensionality skolems // // -------------------------------------------------- ptr_vector m_sorts_trail; obj_map m_sort2skolem; func_decl_ref_vector * register_sort(sort * s_array); // -------------------------------------------------- // array_value table // // Use select(A, i) nodes to represent an assignment for A. // This structure is used to minimize the number of times the // extensionality axiom is applied. // // -------------------------------------------------- struct value_chasher { unsigned operator()(enode const * n, unsigned idx) const { return n->get_arg(idx+1)->get_root()->hash(); } }; struct value_khasher { unsigned operator()(enode * n) const { return 17; } }; struct value_hash_proc { unsigned operator()(enode * n) const { return get_composite_hash(n, n->get_num_args() - 1); } }; struct value_eq_proc { bool operator()(enode * n1, enode * n2) const; }; typedef ptr_hashtable array_value; array_value m_array_value; bool already_diseq(enode * v1, enode * v2); // -------------------------------------------------- // Backtracking // // // -------------------------------------------------- struct scope { unsigned m_sorts_trail_lim; scope(unsigned l):m_sorts_trail_lim(l) {} }; svector m_scopes; void restore_sorts(unsigned old_size); // -------------------------------------------------- // Interface // // // -------------------------------------------------- bool is_shared(theory_var v) const override; bool is_beta_redex(enode* p, enode* n) const override; void collect_shared_vars(sbuffer & result); unsigned mk_interface_eqs(); bool can_propagate() override; void propagate() override; void push_scope_eh() override; void pop_scope_eh(unsigned num_scopes) override; void reset_eh() override; void reset_queues(); // ----------------------------------- // // Model generation // // ----------------------------------- // I need a set of select enodes where select(A,i) = select(B,j) if i->get_root() == j->get_root() struct sel_khasher { unsigned operator()(enode const * n) const { return 0; } }; struct sel_chasher { unsigned operator()(enode const * n, unsigned idx) const { return n->get_arg(idx+1)->get_root()->hash(); } }; struct sel_hash { unsigned operator()(enode * n) const; }; struct sel_eq { bool operator()(enode * n1, enode * n2) const; }; typedef ptr_hashtable select_set; array_factory * m_factory; ptr_vector m_defaults; // temporary field for model construction ptr_vector m_else_values; // tagged pointer: expr or extra_fresh_value svector m_parents; // temporary field for model construction obj_map m_selects; // mapping from array -> relevant selects ptr_vector m_selects_domain; ptr_vector m_selects_range; bool m_use_unspecified_default; // temporary field for model construction theory_var mg_find(theory_var v); void mg_merge(theory_var n, theory_var m); void set_default(theory_var v, enode* n); enode* get_default(theory_var v); void init_model(model_generator & m) override; bool is_unspecified_default_ok() const; void collect_defaults(); void collect_selects(); void propagate_select_to_store_parents(enode * r, enode * sel, enode_pair_vector & todo); void propagate_selects_to_store_parents(enode * r, enode_pair_vector & todo); void propagate_selects(); select_set * get_select_set(enode * n); void finalize_model(model_generator & m) override; model_value_proc * mk_value(enode * n, model_generator & m) override; bool include_func_interp(func_decl* f) override; public: theory_array_base(context& ctx); ~theory_array_base() override { restore_sorts(0); } }; };