mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	Instead of asserting theory axioms lazily we create them on the fly and allow propagation eagerly. The approach uses a waterfall model as follows: - terms are created: they are inserted into an index for (set.in x S) axiom creation. - two terms are merged by an equality. Loop over all new opportunities for axiom instantiation New axioms are added to a queue of recently created axioms. - an atomic formula was asserted by the SAT solver. Update the watch list to find new propagations. During propagation recently created axioms are either inserted into a propagation queue, or inserted into a watch list. They are inserted into a propagation queue all or all but one literal is assigned to false. They are inserted into a watch list if at least two literals are unassigned They are dropped if the axiom contains a literal that is assigned to true The propagation queue is processed by by asserting the theory axiom to the core. Also add some elementary statistics. A breaking change is to change the datatype for undo-trail in smt_context to not use a custom data-structure. This can likely cause regressions. For example, the region allocator now comes from the stack_trail instead of being owned within smt_context with a different declaration order. smt_context could crash during destruction or maybe even pop. We take the risk as the change is overdue. Add swap method to ref_vector.
		
			
				
	
	
		
			435 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			435 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
| Copyright (c) 2006 Microsoft Corporation
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|     trail.h
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|     <abstract>
 | |
| 
 | |
| Author:
 | |
| 
 | |
|     Leonardo de Moura (leonardo) 2008-06-02.
 | |
| 
 | |
| Revision History:
 | |
| 
 | |
| --*/
 | |
| #pragma once
 | |
| 
 | |
| #include "util/obj_hashtable.h"
 | |
| #include "util/region.h"
 | |
| #include "util/obj_ref.h"
 | |
| #include "util/vector.h"
 | |
| 
 | |
| 
 | |
| class trail {
 | |
| public:
 | |
|     virtual ~trail() = default;
 | |
|     virtual void undo() = 0;
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| class value_trail : public trail {
 | |
|     T & m_value;
 | |
|     T   m_old_value;
 | |
| 
 | |
| public:
 | |
|     value_trail(T & value):
 | |
|         m_value(value),
 | |
|         m_old_value(value) {
 | |
|     }
 | |
| 
 | |
|     value_trail(T & value, T const& new_value):
 | |
|         m_value(value),
 | |
|         m_old_value(value) {
 | |
|         m_value = new_value;
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_value = m_old_value;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
|     
 | |
| template<typename T, typename Ts>
 | |
| class scoped_value_trail : public trail {
 | |
|     T & m_value;
 | |
|     Ts & m_values;
 | |
|     
 | |
| public:
 | |
|     scoped_value_trail(T & value, Ts& values):
 | |
|         m_value(value),
 | |
|         m_values(values) {
 | |
|     }
 | |
|     
 | |
|     void undo() override {
 | |
|         m_value = m_values.back();
 | |
|         m_values.pop_back();
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| class reset_flag_trail : public trail {
 | |
|     bool & m_value;
 | |
| public:
 | |
|     reset_flag_trail(bool & value):
 | |
|         m_value(value) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_value = false;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| class set_ptr_trail : public trail {
 | |
|     T * & m_ptr;
 | |
| public:
 | |
|     set_ptr_trail(T * & ptr):
 | |
|         m_ptr(ptr) {
 | |
|         SASSERT(m_ptr == 0);
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_ptr = nullptr;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename V>
 | |
| class restore_vector : public trail {
 | |
|     V& m_vector;
 | |
|     unsigned m_old_size;
 | |
| public:
 | |
|     restore_vector(V& v):
 | |
|         m_vector(v),
 | |
|         m_old_size(v.size())
 | |
|     {}
 | |
|     
 | |
|     restore_vector(V& v, unsigned sz):
 | |
|         m_vector(v),
 | |
|         m_old_size(sz)
 | |
|     {}
 | |
|     
 | |
|     void undo() override {
 | |
|         m_vector.shrink(m_old_size);
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename T, bool CallDestructors=true>
 | |
| class vector_value_trail : public trail {
 | |
|     vector<T, CallDestructors> & m_vector;
 | |
|     unsigned                     m_idx;
 | |
|     T                            m_old_value;
 | |
| public:
 | |
|     vector_value_trail(vector<T, CallDestructors> & v, unsigned idx):
 | |
|         m_vector(v),
 | |
|         m_idx(idx),
 | |
|         m_old_value(v[idx]) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector[m_idx] = m_old_value;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename V, typename T>
 | |
| class vector2_value_trail : public trail {
 | |
|     V             & m_vector;
 | |
|     unsigned        m_i;
 | |
|     unsigned        m_j;
 | |
|     T               m_old_value;
 | |
| public:
 | |
|     vector2_value_trail(V& v, unsigned i, unsigned j):
 | |
|         m_vector(v),
 | |
|         m_i(i),
 | |
|         m_j(j),
 | |
|         m_old_value(v[i][j]) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector[m_i][m_j] = m_old_value;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename D, typename R>
 | |
| class insert_obj_map : public trail {
 | |
|     obj_map<D,R>&     m_map;
 | |
|     D*                m_obj;
 | |
| public:
 | |
|     insert_obj_map(obj_map<D,R>& t, D* o) : m_map(t), m_obj(o) {}
 | |
|     void undo() override { m_map.remove(m_obj); }
 | |
| };
 | |
| 
 | |
| template<typename D, typename R>
 | |
| class remove_obj_map : public trail {
 | |
|     obj_map<D,R>&     m_map;
 | |
|     D*                m_obj;
 | |
|     R                 m_value;
 | |
| public:
 | |
|     remove_obj_map(obj_map<D,R>& t, D* o, R v) : m_map(t), m_obj(o), m_value(v) {}
 | |
|     void undo() override { m_map.insert(m_obj, m_value); }
 | |
| };
 | |
| 
 | |
| template<typename M, typename D>
 | |
| class insert_map : public trail {
 | |
|     M&            m_map;
 | |
|     D             m_obj;
 | |
| public:
 | |
|     insert_map(M& t, D o) : m_map(t), m_obj(o) {}
 | |
|     void undo() override { m_map.remove(m_obj); }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename M, typename Mgr, typename D>
 | |
| class insert_ref_map : public trail {
 | |
|     Mgr&          m;
 | |
|     M&            m_map;
 | |
|     D             m_obj;
 | |
| public:
 | |
|     insert_ref_map(Mgr& m, M& t, D o) : m(m), m_map(t), m_obj(o) {}
 | |
|     void undo() override { m_map.remove(m_obj); m.dec_ref(m_obj); }
 | |
| };
 | |
| 
 | |
| template<typename Mgr, typename D, typename R>
 | |
| class insert_ref2_map : public trail {
 | |
|     Mgr&           m;
 | |
|     obj_map<D,R*>&  m_map;
 | |
|     D*             m_obj;
 | |
|     R*             m_val;
 | |
| public:
 | |
|     insert_ref2_map(Mgr& m, obj_map<D,R*>& t, D*o, R*r) : m(m), m_map(t), m_obj(o), m_val(r) {}
 | |
|     void undo() override { m_map.remove(m_obj); m.dec_ref(m_obj); m.dec_ref(m_val); }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename V>
 | |
| class push_back_vector : public trail {
 | |
|     V & m_vector;
 | |
| public:
 | |
|     push_back_vector(V & v):
 | |
|         m_vector(v) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector.pop_back();
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename V>
 | |
| class set_vector_idx_trail : public trail {
 | |
|     V & m_vector;
 | |
|     unsigned                         m_idx;
 | |
| public:
 | |
|     set_vector_idx_trail(V & v, unsigned idx):
 | |
|         m_vector(v),
 | |
|         m_idx(idx) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector[m_idx] = nullptr;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename T, bool CallDestructors=true>
 | |
| class pop_back_trail : public trail {
 | |
|     vector<T, CallDestructors> & m_vector;
 | |
|     T m_value;
 | |
| public:
 | |
|     pop_back_trail(vector<T, CallDestructors> & v):
 | |
|     m_vector(v),
 | |
|     m_value(m_vector.back()) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector.push_back(m_value);
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename T, bool CallDestructors=true>
 | |
| class pop_back2_trail : public trail {
 | |
|     vector<T, CallDestructors> & m_vector;
 | |
|     typedef vector<vector<T, CallDestructors>, true> vector_t;
 | |
|     unsigned m_index;
 | |
|     T m_value;
 | |
| public:
 | |
|     pop_back2_trail(vector<T, CallDestructors> & v, unsigned index):
 | |
|     m_vector(v),
 | |
|     m_index(index),
 | |
|     m_value(m_vector[index].back()) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector[m_index].push_back(m_value);
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| template<typename T, bool CallDestructors=true>
 | |
| class push_back_trail : public trail {
 | |
|     vector<T, CallDestructors> & m_vector;
 | |
| public:
 | |
|     push_back_trail(vector<T, CallDestructors> & v):
 | |
|         m_vector(v) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector.pop_back();
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename T, bool CallDestructors=true>
 | |
| class push_back2_trail : public trail {
 | |
|     typedef vector<vector<T, CallDestructors>, true> vector_t;
 | |
|     vector_t & m_vector;
 | |
|     unsigned   m_index;
 | |
| public:
 | |
|     push_back2_trail(vector_t & v, unsigned index) :
 | |
|     m_vector(v),
 | |
|     m_index(index) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector[m_index].pop_back();
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| class set_bitvector_trail : public trail {
 | |
|     bool_vector & m_vector;
 | |
|     unsigned        m_idx;
 | |
| public:
 | |
|     set_bitvector_trail(bool_vector & v, unsigned idx):
 | |
|         m_vector(v),
 | |
|         m_idx(idx) {
 | |
|         SASSERT(m_vector[m_idx] == false);
 | |
|         m_vector[m_idx] = true;
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_vector[m_idx] = false;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename T, bool CallDestructors = true>
 | |
| class history_trail : public trail {
 | |
|     vector<T, CallDestructors>& m_dst;
 | |
|     unsigned                     m_idx;
 | |
|     vector<T, CallDestructors>& m_hist;
 | |
| public:
 | |
|     history_trail(vector<T, CallDestructors>& v, unsigned idx, vector<T, CallDestructors>& hist) :
 | |
|         m_dst(v),
 | |
|         m_idx(idx),
 | |
|         m_hist(hist) {}
 | |
|     
 | |
|     void undo() override {
 | |
|         m_dst[m_idx] = m_hist.back();
 | |
|         m_hist.pop_back();
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename T>
 | |
| class new_obj_trail : public trail {
 | |
|     T * m_obj;
 | |
| public:
 | |
|     new_obj_trail(T * obj):
 | |
|         m_obj(obj) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         dealloc(m_obj);
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename M, typename T>
 | |
| class obj_ref_trail : public trail {
 | |
|     obj_ref<T,M> m_obj;
 | |
| public:
 | |
|     obj_ref_trail(obj_ref<T,M>& obj):
 | |
|         m_obj(obj) {
 | |
|     }
 | |
| 
 | |
|     void undo() override {
 | |
|         m_obj.reset();
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| class insert_obj_trail : public trail {
 | |
|     obj_hashtable<T>& m_table;
 | |
|     T*                m_obj;
 | |
| public:
 | |
|     insert_obj_trail(obj_hashtable<T>& t, T* o) : m_table(t), m_obj(o) {}
 | |
|     void undo() override { m_table.remove(m_obj); }
 | |
| };
 | |
| 
 | |
| 
 | |
| template<typename T>
 | |
| class remove_obj_trail : public trail {
 | |
|     obj_hashtable<T>& m_table;
 | |
|     T*                m_obj;
 | |
| public:
 | |
|     remove_obj_trail(obj_hashtable<T>& t, T* o) : m_table(t), m_obj(o) {}
 | |
|     void undo() override { m_table.insert(m_obj); }
 | |
| };
 | |
| 
 | |
| 
 | |
| inline void undo_trail_stack(ptr_vector<trail> & s, unsigned old_size) {
 | |
|     SASSERT(old_size <= s.size());
 | |
|     typename ptr_vector<trail >::iterator begin = s.begin() + old_size;
 | |
|     typename ptr_vector<trail >::iterator it    = s.end();
 | |
|     while (it != begin) {
 | |
|         --it;
 | |
|         (*it)->undo();
 | |
|     }
 | |
|     s.shrink(old_size);
 | |
| }
 | |
| 
 | |
| class trail_stack {
 | |
|     ptr_vector<trail>       m_trail_stack;
 | |
|     unsigned_vector         m_scopes;
 | |
|     region                  m_region;
 | |
| public:
 | |
|     region & get_region() { return m_region; }
 | |
| 
 | |
|     void reset() {
 | |
|         pop_scope(m_scopes.size());
 | |
|         // Undo trail objects stored at lvl 0 (avoid memory leaks if lvl 0 contains new_obj_trail objects).
 | |
|         undo_trail_stack(m_trail_stack, 0);
 | |
|     }
 | |
| 
 | |
|     void push_ptr(trail * t) { m_trail_stack.push_back(t); }
 | |
| 
 | |
|     template<typename TrailObject>
 | |
|     void push(TrailObject const & obj) { m_trail_stack.push_back(new (m_region) TrailObject(obj)); }
 | |
| 
 | |
|     unsigned get_num_scopes() const { return m_scopes.size(); }
 | |
| 
 | |
|     void push_scope() { m_region.push_scope(); m_scopes.push_back(m_trail_stack.size()); }
 | |
| 
 | |
|     void pop_scope(unsigned num_scopes) {
 | |
|         if (num_scopes == 0) return;
 | |
|         unsigned lvl      = m_scopes.size();
 | |
|         SASSERT(num_scopes <= lvl);
 | |
|         unsigned new_lvl  = lvl - num_scopes;
 | |
|         unsigned old_size = m_scopes[new_lvl];
 | |
|         undo_trail_stack(m_trail_stack, old_size);
 | |
|         m_scopes.shrink(new_lvl);
 | |
|         m_region.pop_scope(num_scopes);
 | |
|     }
 | |
| 
 | |
|     unsigned size() const {
 | |
|         return m_trail_stack.size();
 | |
|     }
 | |
| 
 | |
|     void shrink(unsigned new_size) {
 | |
|         SASSERT(new_size <= m_trail_stack.size());
 | |
|         m_trail_stack.shrink(new_size);
 | |
|     }
 | |
| };
 |