mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	integrate polysat into bv solver
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									3f5df04dc4
								
							
						
					
					
						commit
						ff93c03972
					
				
					 14 changed files with 459 additions and 74 deletions
				
			
		|  | @ -14,6 +14,7 @@ z3_add_component(sat_smt | |||
|     bv_delay_internalize.cpp | ||||
|     bv_internalize.cpp | ||||
|     bv_invariant.cpp | ||||
|     bv_polysat.cpp | ||||
|     bv_solver.cpp | ||||
|     dt_solver.cpp | ||||
|     euf_ackerman.cpp | ||||
|  | @ -46,5 +47,6 @@ z3_add_component(sat_smt | |||
|     euf | ||||
|     mbp | ||||
|     smt_params | ||||
|     polysat | ||||
| ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -357,28 +357,12 @@ namespace bv { | |||
|     } | ||||
| 
 | ||||
|     solver::internalize_mode solver::get_internalize_mode(expr* e) { | ||||
|         if (!bv.is_bv(e)) | ||||
|             return internalize_mode::no_delay_i; | ||||
|         if (!reflect()) | ||||
|             return internalize_mode::no_delay_i; | ||||
|         if (get_config().m_bv_polysat) { | ||||
|             switch (to_app(e)->get_decl_kind()) { | ||||
|             case OP_BMUL:  | ||||
|             case OP_BUMUL_NO_OVFL: | ||||
|             case OP_BSMOD_I: | ||||
|             case OP_BUREM_I: | ||||
|             case OP_BUDIV_I: | ||||
|             case OP_BADD: | ||||
|                 return internalize_mode::polysat_i; | ||||
|             case OP_BSMUL_NO_OVFL: | ||||
|             case OP_BSMUL_NO_UDFL: | ||||
|             case OP_BSDIV_I:  | ||||
|             case OP_BSREM_I: | ||||
|             default: | ||||
|                 return internalize_mode::no_delay_i; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (get_config().m_bv_polysat) | ||||
|             return internalize_mode::polysat_i; | ||||
|         if (!bv.is_bv(e)) | ||||
|             return internalize_mode::no_delay_i; | ||||
|         if (!get_config().m_bv_delay) | ||||
|             return internalize_mode::no_delay_i; | ||||
|         internalize_mode mode; | ||||
|  |  | |||
|  | @ -96,6 +96,8 @@ namespace bv { | |||
| 
 | ||||
|     void solver::apply_sort_cnstr(euf::enode * n, sort * s) { | ||||
|         force_push(); | ||||
|         if (polysat_sort_cnstr(n)) | ||||
|             return; | ||||
|         get_var(n); | ||||
|     } | ||||
| 
 | ||||
|  | @ -149,7 +151,7 @@ namespace bv { | |||
|             internalize_circuit(a); | ||||
|             break; | ||||
|         case internalize_mode::polysat_i: | ||||
|             NOT_IMPLEMENTED_YET(); | ||||
|             internalize_polysat(a); | ||||
|             break; | ||||
|         default: | ||||
|             mk_bits(n->get_th_var(get_id())); | ||||
|  | @ -351,8 +353,8 @@ namespace bv { | |||
|             for (expr* bit : bits) { | ||||
|                 sat::literal lit = ctx.internalize(bit, false, false, m_is_redundant); | ||||
|                 TRACE("bv", tout << "set " << m_bits[v][i] << " == " << lit << "\n";); | ||||
|                 add_clause(~lit, m_bits[v][i]); | ||||
|                 add_clause(lit, ~m_bits[v][i]); | ||||
|                 add_equiv(lit, m_bits[v][i]); | ||||
|                 ctx.add_aux_equiv(lit, m_bits[v][i]); | ||||
|                 ++i; | ||||
|             } | ||||
|             return; | ||||
|  | @ -545,8 +547,8 @@ namespace bv { | |||
| 	    unsigned sz = bv.get_bv_size(n); | ||||
| 	    expr_ref zero(bv.mk_numeral(0, sz), m); | ||||
| 	    sat::literal eqZ = eq_internalize(arg2, zero); | ||||
| 	    sat::literal eqU = mk_literal(iun(arg1)); | ||||
| 	    sat::literal eqI = mk_literal(ibin(arg1, arg2)); | ||||
| 	    sat::literal eqU = eq_internalize(n, iun(arg1)); | ||||
| 	    sat::literal eqI = eq_internalize(n, ibin(arg1, arg2)); | ||||
| 	    add_clause(~eqZ, eqU); | ||||
| 	    add_clause(eqZ, eqI); | ||||
| 	    ctx.add_aux(~eqZ, eqU); | ||||
|  | @ -676,12 +678,13 @@ namespace bv { | |||
|             TRACE("bv", tout << "add-bit: " << lit << " " << literal2expr(lit) << "\n";); | ||||
|             atom* a = new (get_region()) atom(lit.var()); | ||||
|             a->m_occs = new (get_region()) var_pos_occ(v_arg, idx); | ||||
|             polysat_bit2bool(a, arg, idx); | ||||
|             insert_bv2a(lit.var(), a); | ||||
|             ctx.push(mk_atom_trail(lit.var(), *this)); | ||||
|         } | ||||
|         else if (lit != lit0) { | ||||
|             add_clause(lit0, ~lit); | ||||
|             add_clause(~lit0, lit); | ||||
|             add_equiv(lit0, lit); | ||||
|             ctx.add_aux_equiv(lit0, lit); | ||||
|         } | ||||
| 
 | ||||
|         // validate_atoms();
 | ||||
|  |  | |||
							
								
								
									
										324
									
								
								src/sat/smt/bv_polysat.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								src/sat/smt/bv_polysat.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,324 @@ | |||
| /*++
 | ||||
| Copyright (c) 2022 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     bv_polysat.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     PolySAT interface to bit-vector | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2022-01-26 | ||||
| 
 | ||||
| Notes: | ||||
| - equality propagation from polysat? | ||||
| - reuse bit propagation from bv-solver? | ||||
| - finish other bit-vector operations | ||||
| - introduce gradual bit-blasting? | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #include "params/bv_rewriter_params.hpp" | ||||
| #include "sat/smt/bv_solver.h" | ||||
| #include "sat/smt/euf_solver.h" | ||||
| #include "math/polysat/solver.h" | ||||
| 
 | ||||
| namespace bv { | ||||
| 
 | ||||
|     typedef polysat::pdd pdd; | ||||
| 
 | ||||
|     void solver::internalize_polysat(app* a) { | ||||
| 
 | ||||
|         std::function<polysat::pdd(polysat::pdd, polysat::pdd)> bin; | ||||
| 
 | ||||
| #define mk_binary(a, fn) bin = fn; polysat_binary(a, bin); | ||||
| 
 | ||||
|         switch (to_app(a)->get_decl_kind()) { | ||||
|         case OP_BMUL:             mk_binary(a, [&](pdd const& p, pdd const& q) { return p * q; }); break; | ||||
|         case OP_BADD:             mk_binary(a, [&](pdd const& p, pdd const& q) { return p + q; }); break; | ||||
|         case OP_BSUB:             mk_binary(a, [&](pdd const& p, pdd const& q) { return p - q; }); break; | ||||
|         case OP_BLSHR:            mk_binary(a, [&](pdd const& p, pdd const& q) { return m_polysat.lshr(p, q); }); break; | ||||
|         case OP_BAND:             mk_binary(a, [&](pdd const& p, pdd const& q) { return m_polysat.band(p, q); }); break; | ||||
| 
 | ||||
|         case OP_BNEG:             polysat_neg(a); break;             | ||||
|         case OP_MKBV:             polysat_mkbv(a); break; | ||||
|         case OP_BV_NUM:           polysat_num(a); break; | ||||
|              | ||||
|         case OP_ULEQ:             polysat_le<false, false, false>(a); break; | ||||
|         case OP_SLEQ:             polysat_le<true,  false, false>(a); break; | ||||
|         case OP_UGEQ:             polysat_le<false, true,  false>(a); break; | ||||
|         case OP_SGEQ:             polysat_le<true,  true,  false>(a); break; | ||||
|         case OP_ULT:              polysat_le<false, true,  true>(a); break; | ||||
|         case OP_SLT:              polysat_le<true,  true,  true>(a); break; | ||||
|         case OP_UGT:              polysat_le<false, false, true>(a); break; | ||||
|         case OP_SGT:              polysat_le<true,  false, true>(a); break; | ||||
| 
 | ||||
|         case OP_BUMUL_NO_OVFL:    polysat_umul_noovfl(a); break; | ||||
|         case OP_BUDIV_I:          polysat_div_rem_i(a, true); break;        | ||||
|         case OP_BUREM_I:          polysat_div_rem_i(a, false); break; | ||||
| 
 | ||||
|         case OP_BUDIV:            polysat_div_rem(a, true); break;             | ||||
|         case OP_BUREM:            polysat_div_rem(a, false); break; | ||||
|         case OP_BSDIV0:           break; | ||||
|         case OP_BUDIV0:           break; | ||||
|         case OP_BSREM0:           break; | ||||
|         case OP_BUREM0:           break; | ||||
|         case OP_BSMOD0:           break; | ||||
| 
 | ||||
|             // polysat::solver should also support at least:
 | ||||
|         case OP_BREDAND: // x == 2^K - 1
 | ||||
|         case OP_BREDOR:  // x > 0
 | ||||
|         case OP_BSDIV:             | ||||
|         case OP_BSREM:             | ||||
|         case OP_BSMOD:                         | ||||
|         case OP_BSMUL_NO_OVFL:     | ||||
|         case OP_BSMUL_NO_UDFL:     | ||||
|         case OP_BSDIV_I:             | ||||
|         case OP_BSREM_I:                         | ||||
|         case OP_BSMOD_I: | ||||
|         case OP_BSHL:             | ||||
|         case OP_BASHR: | ||||
|         case OP_BOR: | ||||
|         case OP_BXOR: | ||||
|         case OP_BNAND: | ||||
|         case OP_BNOR: | ||||
|         case OP_BNOT: | ||||
|         case OP_BCOMP: | ||||
|         case OP_SIGN_EXT: | ||||
|         case OP_ZERO_EXT: | ||||
|         case OP_CONCAT: | ||||
|         case OP_EXTRACT: | ||||
|             std::cout << mk_pp(a, m) << "\n"; | ||||
|             NOT_IMPLEMENTED_YET(); | ||||
|             return; | ||||
|         default: | ||||
|             std::cout << "fall back to circuit " << mk_pp(a, m) << "\n"; | ||||
|             internalize_circuit(a); | ||||
|             break;             | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_umul_noovfl(app* e) { | ||||
|         auto p = expr2pdd(e->get_arg(0)); | ||||
|         auto q = expr2pdd(e->get_arg(1)); | ||||
|         auto sc = ~m_polysat.mul_ovfl(p, q); | ||||
|         sat::literal lit = expr2literal(e); | ||||
|         atom* a = mk_atom(lit.var()); | ||||
|         a->m_sc = sc; | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_div_rem_i(app* e, bool is_div) { | ||||
|         auto p = expr2pdd(e->get_arg(0)); | ||||
|         auto q = expr2pdd(e->get_arg(1)); | ||||
|         auto [quot, rem] = m_polysat.quot_rem(p, q); | ||||
|         polysat_set(e, is_div ? quot : rem);         | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_div_rem(app* e, bool is_div) { | ||||
|         bv_rewriter_params p(s().params()); | ||||
|         if (p.hi_div0()) { | ||||
|             polysat_div_rem_i(e, is_div); | ||||
|             return; | ||||
|         }         | ||||
|         expr* arg1 = e->get_arg(0); | ||||
|         expr* arg2 = e->get_arg(1); | ||||
|         unsigned sz = bv.get_bv_size(e); | ||||
|         expr_ref zero(bv.mk_numeral(0, sz), m); | ||||
|         sat::literal eqZ = eq_internalize(arg2, zero); | ||||
|         sat::literal eqU = eq_internalize(e, is_div ? bv.mk_bv_udiv0(arg1) : bv.mk_bv_urem0(arg1)); | ||||
|         sat::literal eqI = eq_internalize(e, is_div ? bv.mk_bv_udiv_i(arg1, arg2) : bv.mk_bv_urem_i(arg1, arg2)); | ||||
|         add_clause(~eqZ, eqU); | ||||
|         add_clause(eqZ, eqI); | ||||
|         ctx.add_aux(~eqZ, eqU); | ||||
|         ctx.add_aux(eqZ, eqI);         | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_neg(app* e) { | ||||
|         SASSERT(e->get_num_args() == 1); | ||||
|         auto p = expr2pdd(e->get_arg(0)); | ||||
|         polysat_set(e, -p); | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_num(app* a) { | ||||
|         numeral val; | ||||
|         unsigned sz = 0; | ||||
|         VERIFY(bv.is_numeral(a, val, sz)); | ||||
|         auto p = m_polysat.value(val, sz); | ||||
|         polysat_set(a, p); | ||||
|     } | ||||
| 
 | ||||
|     // TODO - test that internalize works with recursive call on bit2bool
 | ||||
|     void solver::polysat_mkbv(app* a) { | ||||
|         unsigned i = 0; | ||||
|         for (expr* arg : *a) { | ||||
|             expr_ref b2b(m); | ||||
|             b2b = bv.mk_bit2bool(a, i);             | ||||
|             sat::literal bit_i = ctx.internalize(b2b, false, false, m_is_redundant); | ||||
|             sat::literal lit = expr2literal(arg); | ||||
|             add_equiv(lit, bit_i); | ||||
|             ctx.add_aux_equiv(lit, bit_i); | ||||
|             ++i; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_binary(app* e, std::function<polysat::pdd(polysat::pdd, polysat::pdd)>& fn) { | ||||
|         SASSERT(e->get_num_args() >= 1); | ||||
|         auto p = expr2pdd(e->get_arg(0)); | ||||
|         for (unsigned i = 1; i < e->get_num_args(); ++i)  | ||||
|             p = fn(p, expr2pdd(e->get_arg(i))); | ||||
|         polysat_set(e, p); | ||||
|     } | ||||
| 
 | ||||
|     template<bool Signed, bool Rev, bool Negated> | ||||
|     void solver::polysat_le(app* e) { | ||||
|         auto p = expr2pdd(e->get_arg(0)); | ||||
|         auto q = expr2pdd(e->get_arg(1)); | ||||
|         if (Rev) | ||||
|             std::swap(p, q); | ||||
|          | ||||
|         auto sc = Signed ? m_polysat.sle(p, q) : m_polysat.ule(p, q); | ||||
|         if (Negated) | ||||
|             sc = ~sc; | ||||
|          | ||||
|         sat::literal lit = expr2literal(e); | ||||
|         atom* a = mk_atom(lit.var()); | ||||
|         a->m_sc = sc; | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_bit2bool(atom* a, expr* e, unsigned idx) { | ||||
|         if (!use_polysat()) | ||||
|             return; | ||||
|         pdd p = expr2pdd(e); | ||||
|         a->m_sc = m_polysat.bit(p, idx); | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_assign(atom* a) { | ||||
|         polysat::signed_constraint sc = a->m_sc; | ||||
|         if (!sc) | ||||
|             return; | ||||
|         SASSERT(s().value(a->m_bv) != l_undef); | ||||
|         bool sign = l_false == s().value(a->m_bv); | ||||
|         sat::literal lit(a->m_bv, sign); | ||||
|         if (sign) | ||||
|             sc = ~sc; | ||||
|         m_polysat.assign_eh(sc, 1 + 2*lit.index()); | ||||
|     } | ||||
| 
 | ||||
|     bool solver::polysat_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { | ||||
|         if (!use_polysat()) | ||||
|             return false; | ||||
|         pdd p = var2pdd(r1); | ||||
|         pdd q = var2pdd(r2); | ||||
|         auto sc = m_polysat.eq(p, q); | ||||
|         m_var_eqs.setx(m_var_eqs_head, std::make_pair(v1, v2), std::make_pair(v1, v2)); | ||||
|         ctx.push(value_trail<unsigned>(m_var_eqs_head));         | ||||
|         m_polysat.assign_eh(sc, 2 * m_var_eqs_head);  | ||||
|         m_var_eqs_head++; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool solver::polysat_diseq_eh(euf::th_eq const& ne) { | ||||
|         euf::theory_var v1 = ne.v1(), v2 = ne.v2(); | ||||
|         pdd p = var2pdd(v1); | ||||
|         pdd q = var2pdd(v2); | ||||
|         auto sc = ~m_polysat.eq(p, q); | ||||
|         sat::literal neq = ~expr2literal(ne.eq()); | ||||
|         m_polysat.assign_eh(sc, 1 + 2 * neq.index()); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_propagate() { | ||||
|         if (!use_polysat()) | ||||
|             return; | ||||
|         lbool r = m_polysat.unit_propagate(); | ||||
|         if (r == l_false) | ||||
|             polysat_core(); | ||||
|     } | ||||
| 
 | ||||
|     lbool solver::polysat_final() { | ||||
|         if (!use_polysat()) | ||||
|             return l_true; | ||||
|         lbool r = m_polysat.check_sat(); | ||||
|         if (r == l_false)  | ||||
|             polysat_core(); | ||||
|         return r; | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_core() { | ||||
|         svector<polysat::dep_t> deps; | ||||
|         sat::literal_vector core; | ||||
|         euf::enode_pair_vector eqs; | ||||
|         m_polysat.unsat_core(deps); | ||||
|         for (auto n : deps) { | ||||
|             if (0 != (n & 1)) | ||||
|                 core.push_back(sat::to_literal(n / 2)); | ||||
|             else { | ||||
|                 auto [v1, v2] = m_var_eqs[n / 2]; | ||||
|                 eqs.push_back(euf::enode_pair(var2enode(v1), var2enode(v2))); | ||||
|             } | ||||
|         } | ||||
|         auto* ex = euf::th_explain::conflict(*this, core, eqs); | ||||
|         ctx.set_conflict(ex); | ||||
|     } | ||||
| 
 | ||||
|     polysat::pdd solver::expr2pdd(expr* e) { | ||||
|         return var2pdd(get_th_var(e)); | ||||
|     } | ||||
| 
 | ||||
|     polysat::pdd solver::var2pdd(euf::theory_var v) { | ||||
|         if (!m_var2pdd_valid.get(v, false)) { | ||||
|             unsigned bv_size = get_bv_size(v); | ||||
|             polysat::pvar pv = m_polysat.add_var(bv_size); | ||||
|             m_pddvar2var.setx(pv, v, UINT_MAX); | ||||
|             pdd p = m_polysat.var(pv); | ||||
|             polysat_set(v, p); | ||||
|             return p; | ||||
|         } | ||||
|         return m_var2pdd[v]; | ||||
|     } | ||||
| 
 | ||||
|     bool solver::polysat_sort_cnstr(euf::enode* n) { | ||||
|         if (!use_polysat()) | ||||
|             return false; | ||||
|         if (!bv.is_bv(n->get_expr())) | ||||
|             return false; | ||||
|         theory_var v = n->get_th_var(get_id()); | ||||
|         if (v == euf::null_theory_var)  | ||||
|             v = mk_var(n); | ||||
|         var2pdd(v); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_set(expr* e, pdd const& p) { | ||||
|         polysat_set(get_th_var(e), p); | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_set(euf::theory_var v, pdd const& p) { | ||||
|         m_var2pdd.reserve(get_num_vars(), p); | ||||
|         m_var2pdd_valid.reserve(get_num_vars(), false); | ||||
|         ctx.push(set_bitvector_trail(m_var2pdd_valid, v)); | ||||
|         m_var2pdd[v] = p;         | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_pop(unsigned n) { | ||||
|         if (!use_polysat()) | ||||
|             return; | ||||
|         m_polysat.pop(n); | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_push() { | ||||
|         if (!use_polysat()) | ||||
|             return; | ||||
|         m_polysat.push(); | ||||
|     } | ||||
| 
 | ||||
|     void solver::polysat_add_value(euf::enode* n, model& mdl, expr_ref_vector& values) { | ||||
|         auto p = expr2pdd(n->get_expr()); | ||||
|         rational val; | ||||
|         VERIFY(m_polysat.try_eval(p, val)); | ||||
|         values[n->get_root_id()] = bv.mk_numeral(val, get_bv_size(n));         | ||||
|     }    | ||||
| } | ||||
|  | @ -52,6 +52,7 @@ namespace bv { | |||
|         euf::th_euf_solver(ctx, symbol("bv"), id), | ||||
|         bv(m), | ||||
|         m_autil(m), | ||||
|         m_polysat(m.limit()), | ||||
|         m_ackerman(*this), | ||||
|         m_bb(m, get_config()), | ||||
|         m_find(*this) { | ||||
|  | @ -217,6 +218,8 @@ namespace bv { | |||
|             return; | ||||
|         if (s().is_probing()) | ||||
|             return; | ||||
|         if (polysat_diseq_eh(ne)) | ||||
|             return; | ||||
|          | ||||
|         TRACE("bv", tout << "diff: " << v1 << " != " << v2 << " @" << s().scope_lvl() << "\n";); | ||||
|         unsigned sz = m_bits[v1].size(); | ||||
|  | @ -400,9 +403,8 @@ namespace bv { | |||
|         if (a) { | ||||
|             force_push(); | ||||
|             m_prop_queue.push_back(propagation_item(a));             | ||||
|             for (auto p : a->m_bit2occ) { | ||||
|                 del_eq_occurs(p.first, p.second); | ||||
|             } | ||||
|             for (auto p : a->m_bit2occ)  | ||||
|                 del_eq_occurs(p.first, p.second);             | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -417,11 +419,13 @@ namespace bv { | |||
|                 for (auto vp : *p.m_atom) | ||||
|                     propagate_bits(vp); | ||||
|                 for (eq_occurs const& eq : p.m_atom->eqs())  | ||||
|                     propagate_eq_occurs(eq);                 | ||||
|                     propagate_eq_occurs(eq); | ||||
|                 polysat_assign(p.m_atom); | ||||
|             } | ||||
|             else  | ||||
|                 propagate_bits(p.m_vp);             | ||||
|         } | ||||
|         polysat_propagate(); | ||||
|         // check_missing_propagation();
 | ||||
|         return true; | ||||
|     } | ||||
|  | @ -521,13 +525,19 @@ namespace bv { | |||
|          | ||||
|         if (!ok) | ||||
|             return sat::check_result::CR_CONTINUE; | ||||
|         return sat::check_result::CR_DONE; | ||||
| 
 | ||||
|         switch (polysat_final()) { | ||||
|         case l_true: return sat::check_result::CR_DONE; | ||||
|         case l_false: return sat::check_result::CR_CONTINUE; | ||||
|         default: return sat::check_result::CR_GIVEUP; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void solver::push_core() { | ||||
|         TRACE("bv", tout << "push: " << get_num_vars() << "@" << m_prop_queue_lim.size() << "\n";); | ||||
|         th_euf_solver::push_core(); | ||||
|         m_prop_queue_lim.push_back(m_prop_queue.size()); | ||||
|         polysat_push(); | ||||
|     } | ||||
| 
 | ||||
|     void solver::pop_core(unsigned n) { | ||||
|  | @ -540,6 +550,8 @@ namespace bv { | |||
|         m_bits.shrink(old_sz); | ||||
|         m_wpos.shrink(old_sz); | ||||
|         m_zero_one_bits.shrink(old_sz); | ||||
|         polysat_pop(n); | ||||
|          | ||||
|         TRACE("bv", tout << "num vars " << old_sz << "@" << m_prop_queue_lim.size() << "\n";); | ||||
|     } | ||||
| 
 | ||||
|  | @ -605,10 +617,13 @@ namespace bv { | |||
|     lbool solver::get_phase(bool_var v) { return l_undef; } | ||||
|     std::ostream& solver::display(std::ostream& out) const { | ||||
|         unsigned num_vars = get_num_vars(); | ||||
|         if (num_vars > 0) | ||||
|             out << "bv-solver:\n"; | ||||
|         if (num_vars == 0) | ||||
|             return out; | ||||
|         out << "bv-solver:\n"; | ||||
|         for (unsigned v = 0; v < num_vars; v++) | ||||
|             out << pp(v); | ||||
|         if (use_polysat()) | ||||
|             m_polysat.display(out); | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|  | @ -662,6 +677,7 @@ namespace bv { | |||
|         st.update("bv bit2eq", m_stats.m_num_bit2eq); | ||||
|         st.update("bv bit2ne", m_stats.m_num_bit2ne); | ||||
|         st.update("bv ackerman", m_stats.m_ackerman); | ||||
|         m_polysat.collect_statistics(st); | ||||
|     } | ||||
| 
 | ||||
|     sat::extension* solver::copy(sat::solver* s) { UNREACHABLE(); return nullptr; } | ||||
|  | @ -727,6 +743,10 @@ namespace bv { | |||
|             return; | ||||
|         } | ||||
|         theory_var v = n->get_th_var(get_id()); | ||||
|         if (m_bits[v].empty() && use_polysat()) { | ||||
|             polysat_add_value(n, mdl, values); | ||||
|             return; | ||||
|         } | ||||
|         rational val; | ||||
|         unsigned i = 0; | ||||
|         for (auto l : m_bits[v]) { | ||||
|  | @ -748,6 +768,9 @@ namespace bv { | |||
| 
 | ||||
|     void solver::merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { | ||||
| 
 | ||||
|         if (polysat_merge_eh(r1, r2, v1, v2)) | ||||
|             return; | ||||
| 
 | ||||
|         TRACE("bv", tout << "merging: v" << v1 << " #" << var2enode(v1)->get_expr_id() << " v" << v2 << " #" << var2enode(v2)->get_expr_id() << "\n";); | ||||
| 
 | ||||
|         if (!merge_zero_one_bits(r1, r2)) { | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ Author: | |||
| #include "sat/smt/sat_th.h" | ||||
| #include "sat/smt/bv_ackerman.h" | ||||
| #include "ast/rewriter/bit_blaster/bit_blaster.h" | ||||
| #include "math/polysat/solver.h" | ||||
| 
 | ||||
| namespace euf { | ||||
|     class solver; | ||||
|  | @ -166,6 +167,7 @@ namespace bv { | |||
|             svector<std::pair<atom*, eq_occurs*>> m_bit2occ; | ||||
|             literal    m_var = sat::null_literal; | ||||
|             literal    m_def = sat::null_literal; | ||||
|             polysat::signed_constraint m_sc; | ||||
|             atom(bool_var b) :m_bv(b), m_eqs(nullptr), m_occs(nullptr) {} | ||||
|             ~atom() { m_bit2occ.clear(); } | ||||
|             var_pos_it begin() const { return var_pos_it(m_occs); } | ||||
|  | @ -194,6 +196,7 @@ namespace bv { | |||
| 
 | ||||
|         bv_util                  bv; | ||||
|         arith_util               m_autil; | ||||
|         polysat::solver          m_polysat; | ||||
|         stats                    m_stats; | ||||
|         ackerman                 m_ackerman; | ||||
|         bit_blaster              m_bb; | ||||
|  | @ -232,7 +235,7 @@ namespace bv { | |||
|         void add_bit(theory_var v, sat::literal lit); | ||||
|         atom* mk_atom(sat::bool_var b); | ||||
|         void eq_internalized(sat::bool_var b1, sat::bool_var b2, unsigned idx, theory_var v1, theory_var v2, sat::literal eq, euf::enode* n); | ||||
|         void del_eq_occurs(atom* a, eq_occurs* occ); | ||||
|         void del_eq_occurs(atom* a, eq_occurs* occ);         | ||||
| 
 | ||||
|         void set_bit_eh(theory_var v, literal l, unsigned idx); | ||||
|         void init_bits(expr* e, expr_ref_vector const & bits); | ||||
|  | @ -263,6 +266,39 @@ namespace bv { | |||
|         void assert_ackerman(theory_var v1, theory_var v2); | ||||
|         bool reflect() const { return get_config().m_bv_reflect; } | ||||
| 
 | ||||
|         // polysat
 | ||||
|         void internalize_polysat(app* a); | ||||
|         void polysat_push(); | ||||
|         void polysat_pop(unsigned n); | ||||
|         void polysat_binary(app* e, std::function<polysat::pdd(polysat::pdd, polysat::pdd)>& fn); | ||||
|         polysat::pdd expr2pdd(expr* e); | ||||
|         void polysat_set(euf::theory_var v, polysat::pdd const& p); | ||||
|         polysat::pdd var2pdd(euf::theory_var v); | ||||
|         void polysat_set(expr* e, polysat::pdd const& p); | ||||
|         template<bool Signed, bool Reverse, bool Negated> | ||||
|         void polysat_le(app* n); | ||||
|         void polysat_neg(app* a); | ||||
|         void polysat_num(app* a); | ||||
|         void polysat_mkbv(app* a); | ||||
|         void solver::polysat_umul_noovfl(app* e); | ||||
|         void solver::polysat_div_rem_i(app* e, bool is_div); | ||||
|         void solver::polysat_div_rem(app* e, bool is_div); | ||||
|         void polysat_bit2bool(atom* a, expr* e, unsigned idx); | ||||
|         bool polysat_sort_cnstr(euf::enode* n); | ||||
|         void polysat_assign(atom* a); | ||||
|         void polysat_propagate(); | ||||
|         void polysat_core(); | ||||
|         bool polysat_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2); | ||||
|         bool polysat_diseq_eh(euf::th_eq const& ne); | ||||
|         void polysat_add_value(euf::enode* n, model& mdl, expr_ref_vector& values); | ||||
|         lbool polysat_final(); | ||||
|         bool use_polysat() const { return get_config().m_bv_polysat; } | ||||
|         vector<polysat::pdd> m_var2pdd; | ||||
|         bool_vector          m_var2pdd_valid; | ||||
|         unsigned_vector      m_pddvar2var; | ||||
|         svector<std::pair<euf::theory_var, euf::theory_var>> m_var_eqs; | ||||
|         unsigned             m_var_eqs_head = 0; | ||||
| 
 | ||||
|         // delay internalize
 | ||||
|         enum class internalize_mode { | ||||
|             delay_i, | ||||
|  |  | |||
|  | @ -384,6 +384,7 @@ namespace euf { | |||
|         void add_aux(sat::literal_vector const& lits) { add_aux(lits.size(), lits.data()); } | ||||
|         void add_aux(unsigned n, sat::literal const* lits) { m_relevancy.add_def(n, lits); } | ||||
|         void add_aux(sat::literal a) { sat::literal lits[1] = { a }; add_aux(1, lits); } | ||||
|         void add_aux_equiv(sat::literal a, sat::literal b) { add_aux(~a, b); add_aux(a, ~b); } | ||||
|         void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); }  | ||||
|         void add_aux(sat::literal a, sat::literal b, sat::literal c) { sat::literal lits[3] = { a, b, c }; add_aux(3, lits); } | ||||
|         void mark_relevant(sat::literal lit) { m_relevancy.mark_relevant(lit); } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue