mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	debug cheap_eqs
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
		
							parent
							
								
									7a2aa28644
								
							
						
					
					
						commit
						ffaa7d0b27
					
				
					 3 changed files with 105 additions and 60 deletions
				
			
		|  | @ -30,30 +30,41 @@ class lp_bound_propagator { | |||
|         vertex*            m_parent; | ||||
|         unsigned           m_level; // the distance in hops to the root;
 | ||||
|                                     // it is handy to find the common ancestor
 | ||||
|         bool               m_neg;  // if false then the offset means the distance from the root to column value
 | ||||
|                                    // if true, then  - to minus column value
 | ||||
|     public: | ||||
|         vertex() {} | ||||
|         vertex(unsigned row, | ||||
|                unsigned column, | ||||
|                const mpq & offset) : | ||||
|                const mpq & offset, | ||||
|                bool neg) : | ||||
|             m_row(row), | ||||
|             m_column(column), | ||||
|             m_offset(offset), | ||||
|             m_parent(nullptr), | ||||
|             m_level(0) {} | ||||
|             m_level(0), | ||||
|             m_neg(neg) | ||||
|         {} | ||||
|         unsigned column() const { return m_column; } | ||||
|         unsigned row() const { return m_row; } | ||||
|         vertex* parent() const { return m_parent; } | ||||
|         unsigned level() const { return m_level; } | ||||
|         const mpq& offset() const { return m_offset; } | ||||
|         mpq& offset() { return m_offset; } | ||||
|         bool neg() const { return m_neg; } | ||||
|         bool& neg() { return m_neg; } | ||||
|         void add_child(vertex* child) { | ||||
|             SASSERT(!(*this == *child)); | ||||
|             child->m_parent = this; | ||||
|             m_children.push_back(child); | ||||
|             child->m_level = m_level + 1; | ||||
|         } | ||||
|         const ptr_vector<vertex> & children() const { return m_children; } | ||||
|         std::ostream& print(std::ostream & out) const { | ||||
|             out << "row = " << m_row << ", column = " << m_column << ", parent = " << m_parent << " , offset = " << m_offset << ", level = " << m_level << "\n";; | ||||
|             out << "row = " << m_row << ", column = " << m_column << ", parent = {"; | ||||
|             if (m_parent) { tout << "(" << m_parent->row() << ", " << m_parent->column() << ")";} | ||||
|             else { tout << "null"; } | ||||
|             tout <<  "} , offfset = " << m_offset  << ", level = " << m_level; | ||||
|             return out; | ||||
|         } | ||||
|         bool operator==(const vertex& o) const { | ||||
|  | @ -69,7 +80,10 @@ class lp_bound_propagator { | |||
|     // If the tree is fixed then in addition to checking with the m_offset_to_verts
 | ||||
|     // we are going to check with the m_fixed_var_tables.
 | ||||
|     vertex*                                   m_fixed_vertex; | ||||
|     // a pair (o, j) belongs to m_offset_to_verts iff x[j] = x[m_root->column()] + o
 | ||||
|     map<mpq, vertex*, obj_hash<mpq>, mpq_eq>  m_offset_to_verts; | ||||
|     // a pair (o, j) belongs to m_offset_to_verts_neg iff -x[j] = x[m_root->column()] + o
 | ||||
|     map<mpq, vertex*, obj_hash<mpq>, mpq_eq>  m_offset_to_verts_neg; | ||||
|     // these maps map a column index to the corresponding index in ibounds
 | ||||
|     std::unordered_map<unsigned, unsigned>    m_improved_lower_bounds; | ||||
|     std::unordered_map<unsigned, unsigned>    m_improved_upper_bounds; | ||||
|  | @ -100,6 +114,7 @@ public: | |||
|                                  m_imp(imp) {} | ||||
|      | ||||
|     const lar_solver& lp() const { return m_imp.lp(); } | ||||
|     lar_solver& lp() { return m_imp.lp(); } | ||||
|     column_type get_column_type(unsigned j) const { | ||||
|         return m_imp.lp().get_column_type(j); | ||||
|     } | ||||
|  | @ -247,31 +262,50 @@ public: | |||
|         add_eq_on_columns(ex, j, v->column()); | ||||
|     } | ||||
| 
 | ||||
|     bool tree_contains_r(vertex* root, vertex *v) const { | ||||
|         if (*root == *v) | ||||
|             return true; | ||||
|         for (vertex *c : root->children()) { | ||||
|             if (tree_contains_r(c, v)) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     bool tree_contains(vertex *v) const { | ||||
|         if (!m_root) | ||||
|             return false; | ||||
|         return tree_contains_r(m_root, v); | ||||
|     } | ||||
|      | ||||
|     vertex * alloc_v(unsigned row_index, unsigned column, const mpq& offset, bool neg) { | ||||
|         vertex * v = alloc(vertex, row_index, column, offset, neg); | ||||
|         SASSERT(!tree_contains(v)); | ||||
|         SASSERT(!m_fixed_vertex || !neg); | ||||
|         return v; | ||||
|     } | ||||
|      | ||||
|     void create_root(unsigned row_index) { | ||||
|         SASSERT(!m_root && !m_fixed_vertex); | ||||
|         signed_column x, y; | ||||
|         mpq offset; | ||||
|         TRACE("cheap_eq", display_row_info(row_index, tout);); | ||||
|         if (!is_tree_offset_row(row_index, x, y, offset)) | ||||
|             return; | ||||
|         TRACE("cheap_eq", display_row_info(row_index, tout);); | ||||
|         if (y.not_set()) { | ||||
|             m_root = alloc(vertex, row_index, x.column(), offset); | ||||
|             m_root = alloc_v(row_index, x.column(), offset, false); | ||||
|             m_fixed_vertex = m_root; | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         // create root with the offset zero
 | ||||
|         m_root = alloc(vertex, row_index, x.column(), mpq(0)); | ||||
|         // we have x + sign_y * y + offset = 0
 | ||||
|         m_root = alloc_v( row_index, x.column(), mpq(0), false); | ||||
|         // we have x + y.sign() * y + offset = 0
 | ||||
|         // x.offset is set to zero as x plays the role of m_root
 | ||||
|         // if sign_y = true then y.offset() = offset + x.offset()
 | ||||
|         // else y.offset() = - offset - x.offset()
 | ||||
|         if (!y.sign()) | ||||
|             offset.neg(); | ||||
|         | ||||
|         vertex *v = alloc(vertex, row_index, y.column(), offset); | ||||
|         // else (!y.sign())*y =  x + offset
 | ||||
| 
 | ||||
|         vertex *v = alloc_v( row_index, y.column(), offset, !y.sign()); | ||||
|         m_root->add_child(v);             | ||||
|     } | ||||
| 
 | ||||
|  | @ -280,48 +314,53 @@ public: | |||
|     } | ||||
|      | ||||
|     // returns the vertex to start exploration from, or nullptr
 | ||||
|     // parent->column() is present in the row
 | ||||
|     vertex* add_child_from_row(unsigned row_index, vertex* parent) { | ||||
|         signed_column x, y; | ||||
|         mpq offset; | ||||
|         if (!is_tree_offset_row(row_index, x, y, offset)) | ||||
|             return nullptr; | ||||
|         if (y.not_set()) { | ||||
|             // x.sign() * x + offset = 0 
 | ||||
|             SASSERT(parent->column() == x.column()); | ||||
|             if (m_fixed_vertex) { | ||||
|                 vertex* v =  alloc(vertex, row_index, x.column(), - offset); | ||||
|             mpq offs = x.sign()? offset: -offset; | ||||
|             if (m_fixed_vertex) {                 | ||||
|                 // now the neg, the last argument, is false since all offsets are
 | ||||
|                 // absolute
 | ||||
|                 vertex* v =  alloc_v( row_index, x.column(), offs , false); | ||||
|                 parent->add_child(v); | ||||
|                 return v; | ||||
|             } | ||||
|             vertex *v = alloc(vertex, row_index, x.column(), parent->offset()); | ||||
|             vertex *v = alloc_v( row_index, x.column(), parent->offset(), false); | ||||
|             m_fixed_vertex = v; | ||||
|             parent->add_child(v); | ||||
|             // need to shift the tree so  v.offset() becomes equal to - offset
 | ||||
|             shift_offsets_by_delta(m_root, - offset - parent->offset()); | ||||
|             switch_to_fixed_mode_in_tree(m_root, offs - parent->offset()); | ||||
|             return v; | ||||
|         } | ||||
|         SASSERT(x.is_set() && y.is_set()); | ||||
|         if (parent->column() == x.column()) { | ||||
|             vertex *vx = alloc(vertex, row_index, x.column(), parent->offset()); | ||||
|             vertex *vx = alloc_v( row_index, x.column(), parent->offset(), parent->neg()); | ||||
|             // mpq x_c = rat_sign(x.sign());
 | ||||
|             // mpq y_c = rat_sign(y.sign());
 | ||||
|             // we have x_c*x + y_c*y + offset = 0
 | ||||
|             // y = - offset/y_c - ( x_c/y_c )vx.offset;
 | ||||
|             bool x_c_y_c = x.sign() ^ y.sign(); | ||||
|             mpq y_offs = (y.sign()? offset: - offset) - (x_c_y_c? - vx->offset() : vx->offset()); | ||||
|             vertex *vy = alloc(vertex, row_index, y.column(), y_offs); | ||||
|             vertex *vy = alloc_v( row_index, y.column(), y_offs, x.sign() != y.sign()? parent->neg(): !parent->neg()); | ||||
|             parent->add_child(vx); | ||||
|             vx->add_child(vy); | ||||
|             return vy; // start exploring from vy
 | ||||
|         } else { | ||||
|             SASSERT(parent->column() == y.column()); | ||||
|             vertex *vy = alloc(vertex, row_index, y.column(), parent->offset()); | ||||
|             vertex *vy = alloc_v( row_index, y.column(), parent->offset(), parent->neg()); | ||||
|             // mpq x_c = rat_sign(x.sign());
 | ||||
|             // mpq y_c = rat_sign(y.sign());
 | ||||
|             // we have x_c*x + y_c*y + offset = 0
 | ||||
|             // x = - offset/x_c - ( y_c/x_c )vy.offset;
 | ||||
|             //TODO - m_fixed_vertex
 | ||||
|             bool y_c_x_c = x.sign() ^ y.sign(); | ||||
|             mpq x_offs = (x.sign()? offset: -offset) - (y_c_x_c? - vy->offset():  vy->offset()); | ||||
|             vertex *vx = alloc(vertex, row_index, y.column(), x_offs); | ||||
|             vertex *vx = alloc_v(row_index, x.column(), x_offs, x.sign() != y.sign()? parent->neg(): !parent->neg()); | ||||
|             parent->add_child(vy); | ||||
|             vy->add_child(vx); | ||||
|             return vx; | ||||
|  | @ -331,20 +370,30 @@ public: | |||
|     bool is_equal(lpvar j, lpvar k) const {         | ||||
|         return m_imp.is_equal(col_to_imp(j), col_to_imp(k)); | ||||
|     } | ||||
|      | ||||
|     void check_for_eq_and_add_to_offset_table(vertex* v) { | ||||
|         vertex *k; // the other vertex 
 | ||||
|          | ||||
|         if (m_offset_to_verts.find(v->offset(), k)) { | ||||
| 
 | ||||
|     void check_for_eq_and_add_to_offset_table(vertex* v,  map<mpq, vertex*, obj_hash<mpq>, mpq_eq>& table) { | ||||
|         vertex *k; // the other vertex
 | ||||
|         if (table.find(v->offset(), k)) { | ||||
|             if (k->column() != v->column() && | ||||
|                 !is_equal(k->column(), v->column())) | ||||
|                 report_eq(k, v); | ||||
|         } else { | ||||
|             TRACE("cheap_eq", tout << "registered offset " << v->offset() << " to " << v << "\n";); | ||||
|             m_offset_to_verts.insert(v->offset(), v); | ||||
|             TRACE("cheap_eq", tout << "registered offset " << v->offset() << " to { "; v->print(tout) << "} \n";); | ||||
|             table.insert(v->offset(), v); | ||||
|         } | ||||
| 
 | ||||
|         if (m_fixed_vertex) { | ||||
|     } | ||||
|      | ||||
|     void check_for_eq_and_add_to_offsets(vertex* v) { | ||||
|         TRACE("cheap_eq_det", v->print(tout) << "\n";); | ||||
|         if (!m_fixed_vertex) { | ||||
|             if (v->neg()) | ||||
|                 check_for_eq_and_add_to_offset_table(v, m_offset_to_verts_neg); | ||||
|             else  | ||||
|                 check_for_eq_and_add_to_offset_table(v, m_offset_to_verts);                 | ||||
|         } | ||||
|         else { // m_fixed_vertex is not nullptr - all offsets are absolute
 | ||||
|              | ||||
|             SASSERT(v->neg() == false); | ||||
|             unsigned j; | ||||
|             unsigned v_col = v->column(); | ||||
|             if (lp().find_in_fixed_tables(v->offset(), is_int(v_col), j)) { | ||||
|  | @ -359,6 +408,7 @@ public: | |||
|                     add_eq_on_columns(ex, v_col, j); | ||||
|                 }                     | ||||
|             } | ||||
|             check_for_eq_and_add_to_offset_table(v, m_offset_to_verts); | ||||
|         } | ||||
|          | ||||
|     } | ||||
|  | @ -392,12 +442,13 @@ public: | |||
|         SASSERT(j != k); | ||||
|         unsigned je = lp().column_to_reported_index(j); | ||||
|         unsigned ke = lp().column_to_reported_index(k); | ||||
|         TRACE("cheap_eq", tout << "reporting eq " << je << ", " << ke << "\n"; | ||||
|         TRACE("cheap_eq", tout << "reporting eq " << j << ", " << k << "\n"; | ||||
|               for (auto p : exp) { | ||||
|                   lp().constraints().display(tout, [this](lpvar j) { return lp().get_variable_name(j);}, p.ci()); | ||||
|               }); | ||||
|          | ||||
|         m_imp.add_eq(je, ke, exp);         | ||||
|         m_imp.add_eq(je, ke, exp); | ||||
|         lp().settings().stats().m_cheap_eqs++; | ||||
|     } | ||||
| 
 | ||||
|    /**
 | ||||
|  | @ -584,8 +635,10 @@ public: | |||
|         return false; | ||||
|     } | ||||
|     bool tree_is_correct(vertex* v, ptr_vector<vertex>& vs) const { | ||||
|         if (m_fixed_vertex && v->neg()) | ||||
|             return false; | ||||
|         for (vertex * u : v->children()) { | ||||
|             if (contains_vertex(u, vs)) | ||||
|             if (contains_vertex(u, vs))  | ||||
|                 return false; | ||||
|         } | ||||
|         for (vertex * u : v->children()) { | ||||
|  | @ -601,7 +654,7 @@ public: | |||
|     } | ||||
|     std::ostream& print_tree(std::ostream & out, vertex* v) const { | ||||
|         v->print(out); | ||||
|         out << "children :\n"; | ||||
|         out << "\nchildren :\n"; | ||||
|         for (auto * c : v->children()) { | ||||
|             print_tree(out, c); | ||||
|         } | ||||
|  | @ -616,6 +669,7 @@ public: | |||
|         if (m_root == nullptr) { | ||||
|             return; | ||||
|         } | ||||
|         TRACE("cheap_eq", tout << "tree = "; print_tree(tout, m_root) << "\n";); | ||||
|         SASSERT(tree_is_correct()); | ||||
|         explore_under(m_root); | ||||
|         TRACE("cheap_eq", tout << "done for row_index " << row_index << "\n";); | ||||
|  | @ -623,6 +677,7 @@ public: | |||
|         delete_tree(m_root); | ||||
|         m_root =  m_fixed_vertex = nullptr; | ||||
|         m_offset_to_verts.reset(); | ||||
|         m_offset_to_verts_neg.reset(); | ||||
|     } | ||||
| 
 | ||||
|     unsigned verts_size() const { | ||||
|  | @ -669,7 +724,7 @@ public: | |||
|     void explore_under(vertex * v) { | ||||
|         if (m_fixed_vertex) | ||||
|             try_add_equation_with_fixed_tables(v); | ||||
|         check_for_eq_and_add_to_offset_table(v); | ||||
|         check_for_eq_and_add_to_offsets(v); | ||||
|         go_over_vertex_column(v); | ||||
|         // v might change in m_vertices expansion
 | ||||
|         for (vertex* c : v->children()) { | ||||
|  | @ -681,20 +736,25 @@ public: | |||
|         SASSERT(v); | ||||
|         m_fixed_vertex = v; | ||||
|         mpq delta = new_v_offset - v->offset(); | ||||
|         shift_offsets_by_delta(m_root, delta); | ||||
|         switch_to_fixed_mode(m_root, delta); | ||||
|         SASSERT(v->offset() == new_v_offset); | ||||
|         m_offset_to_verts_neg.reset(); | ||||
|         m_offset_to_verts.reset(); | ||||
|     } | ||||
| 
 | ||||
|     void shift_offsets_by_delta(vertex *v, const mpq& d) { | ||||
|     void switch_to_fixed_mode(vertex *v, const mpq& d) { | ||||
|         v->offset() += d; | ||||
|         if (v->neg()) { | ||||
|             v->offset() = - v->offset(); | ||||
|             v->neg() = false; | ||||
|         } | ||||
|         for (vertex * c : v->children()) { | ||||
|             shift_offsets_by_delta(c, d); | ||||
|             switch_to_fixed_mode(c, d); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Will return x such that x.m_sign = false.
 | ||||
|     // In case of only one non fixed column, and the function returns true,
 | ||||
|     // this column would be represened by x
 | ||||
|     // this column would be represened by x.
 | ||||
|     bool is_tree_offset_row( | ||||
|         unsigned row_index, | ||||
|         signed_column & x, | ||||
|  | @ -720,26 +780,9 @@ public: | |||
|          | ||||
|         offset = mpq(0); | ||||
|         for (const auto& c : row) { | ||||
|             if (!column_is_fixed(c.var())) | ||||
|                 continue; | ||||
|             offset += c.coeff() * get_lower_bound_rational(c.var()); | ||||
|             if (column_is_fixed(c.var())) | ||||
|                 offset += c.coeff() * get_lower_bound_rational(c.var()); | ||||
|         } | ||||
|         if (offset.is_zero() && | ||||
|             x.is_set() && y.is_set() && (x.sign() != y.sign()) && | ||||
|             !is_equal(x.column(), y.column())) { | ||||
|             lp::explanation ex; | ||||
|             explain_fixed_in_row(row_index, ex); | ||||
|             add_eq_on_columns(ex, x.column(), y.column()); | ||||
|         } | ||||
|          | ||||
|         if (x.sign()) { | ||||
|             // flip the signs
 | ||||
|             x.sign() = false; | ||||
|             if (y.is_set()) { | ||||
|                 y.sign() = !y.sign(); | ||||
|             } | ||||
|             offset.neg(); | ||||
|         }         | ||||
|         return true; | ||||
|     }     | ||||
| }; | ||||
|  |  | |||
|  | @ -113,6 +113,7 @@ struct statistics { | |||
|     unsigned m_cross_nested_forms; | ||||
|     unsigned m_grobner_calls; | ||||
|     unsigned m_grobner_conflicts; | ||||
|     unsigned m_cheap_eqs; | ||||
|     statistics() { reset(); } | ||||
|     void reset() { memset(this, 0, sizeof(*this)); } | ||||
| }; | ||||
|  | @ -138,7 +139,7 @@ private: | |||
|     // used for messages, for example, the computation progress messages
 | ||||
|     std::ostream*             m_message_out; | ||||
| 
 | ||||
|     statistics                     m_stats; | ||||
|     statistics                m_stats; | ||||
|     random_gen                m_rand; | ||||
| 
 | ||||
| public: | ||||
|  |  | |||
|  | @ -3886,6 +3886,7 @@ public: | |||
|         st.update("arith-gomory-cuts", m_stats.m_gomory_cuts); | ||||
|         st.update("arith-assume-eqs", m_stats.m_assume_eqs); | ||||
|         st.update("arith-branch", m_stats.m_branch); | ||||
|         st.update("arith-cheap-eqs", lp().settings().stats().m_cheap_eqs); | ||||
|     }         | ||||
| 
 | ||||
|     /*
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue