mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Add lemma: y = x[h:l] & y != 0 ==> x >= 2^l
This commit is contained in:
		
							parent
							
								
									afc292e5db
								
							
						
					
					
						commit
						bc6f0729a0
					
				
					 4 changed files with 57 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -47,6 +47,7 @@ namespace polysat {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void saturation::perform(pvar v, conflict& core) {
 | 
			
		||||
        LOG_H1("Saturation for v" << v << ", core: " << core);
 | 
			
		||||
        IF_VERBOSE(2, verbose_stream() << "v" << v << " " << core << "\n");
 | 
			
		||||
        for (signed_constraint c : core)
 | 
			
		||||
            perform(v, c, core);
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +74,8 @@ namespace polysat {
 | 
			
		|||
        bool prop = false;
 | 
			
		||||
        if (s.size(v) != i.lhs().power_of_2())
 | 
			
		||||
            return false;
 | 
			
		||||
        if (try_nonzero_upper_extract(v, core, i))
 | 
			
		||||
            prop = true;
 | 
			
		||||
        if (try_mul_bounds(v, core, i))
 | 
			
		||||
            prop = true;
 | 
			
		||||
        if (try_parity(v, core, i))
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +109,44 @@ namespace polysat {
 | 
			
		|||
        return prop;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool saturation::try_nonzero_upper_extract(pvar y, conflict& core, inequality const& i) {
 | 
			
		||||
        set_rule("y = x[h:l] & y != 0 ==> x >= 2^l");
 | 
			
		||||
        if (!s.m_justification[y].is_propagation_by_slicing())
 | 
			
		||||
            return false;
 | 
			
		||||
        if (!s.get_value(y).is_zero())
 | 
			
		||||
            return false;
 | 
			
		||||
        if (!is_nonzero_by(y, i))
 | 
			
		||||
            return false;
 | 
			
		||||
        for (pvar x : core.vars()) {
 | 
			
		||||
            if (!s.get_value(x).is_zero())
 | 
			
		||||
                continue;
 | 
			
		||||
            unsigned hi, lo;
 | 
			
		||||
            if (!s.m_slicing.is_extract(y, x, hi, lo))  // TODO: generalize; use is_equal to check this and if yes, extract the explanation. otherwise it will only work in very limited cases.
 | 
			
		||||
                continue;
 | 
			
		||||
            if (propagate(y, core, i, s.ule(rational::power_of_two(lo), s.var(x))))
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: can be generalized
 | 
			
		||||
    bool saturation::is_nonzero_by(pvar x, inequality const& i) {
 | 
			
		||||
        if (i.is_strict() && i.lhs().is_zero()) {
 | 
			
		||||
            // 0 < p
 | 
			
		||||
            pdd const& p = i.rhs();
 | 
			
		||||
            if (p.is_val())
 | 
			
		||||
                return false;
 | 
			
		||||
            if (!p.lo().is_zero())
 | 
			
		||||
                return false;
 | 
			
		||||
            if (!p.hi().is_val())
 | 
			
		||||
                return false;
 | 
			
		||||
            SASSERT(!p.hi().is_zero());
 | 
			
		||||
            // 0 < a*x for a != 0
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool saturation::try_umul_ovfl(pvar v, signed_constraint c, conflict& core) {
 | 
			
		||||
        SASSERT(c->is_umul_ovfl());
 | 
			
		||||
        bool prop = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -526,8 +567,8 @@ namespace polysat {
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool saturation::is_forced_diseq(pdd const& p, int i, signed_constraint& c) {
 | 
			
		||||
        c = s.eq(p, i);
 | 
			
		||||
    bool saturation::is_forced_diseq(pdd const& p, rational const& val, signed_constraint& c) {
 | 
			
		||||
        c = s.eq(p, val);
 | 
			
		||||
        return is_forced_false(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,6 +121,8 @@ namespace polysat {
 | 
			
		|||
        bool try_infer_parity_equality(pvar x, conflict& core, inequality const& a_l_b);
 | 
			
		||||
        bool try_div_monotonicity(conflict& core);
 | 
			
		||||
 | 
			
		||||
        bool try_nonzero_upper_extract(pvar v, conflict& core, inequality const& i);
 | 
			
		||||
 | 
			
		||||
        rational round(rational const& M, rational const& x);
 | 
			
		||||
        bool eval_round(rational const& M, pdd const& p, rational& r);
 | 
			
		||||
        bool extract_linear_form(pdd const& q, pvar& y, rational& a, rational& b);
 | 
			
		||||
| 
						 | 
				
			
			@ -199,6 +201,9 @@ namespace polysat {
 | 
			
		|||
 | 
			
		||||
        bool has_lower_bound(pvar x, conflict& core, rational& bound, vector<signed_constraint>& x_le_bound);
 | 
			
		||||
 | 
			
		||||
        // inequality i implies x != 0
 | 
			
		||||
        bool is_nonzero_by(pvar x, inequality const& i);
 | 
			
		||||
 | 
			
		||||
        // determine min/max parity of polynomial
 | 
			
		||||
        unsigned min_parity(pdd const& p, vector<signed_constraint>& explain);
 | 
			
		||||
        unsigned max_parity(pdd const& p, vector<signed_constraint>& explain);
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +215,8 @@ namespace polysat {
 | 
			
		|||
        bool is_forced_eq(pdd const& p, rational const& val);
 | 
			
		||||
        bool is_forced_eq(pdd const& p, int i) { return is_forced_eq(p, rational(i)); }
 | 
			
		||||
        
 | 
			
		||||
        bool is_forced_diseq(pdd const& p, int i, signed_constraint& c);
 | 
			
		||||
        bool is_forced_diseq(pdd const& p, rational const& val, signed_constraint& c);
 | 
			
		||||
        bool is_forced_diseq(pdd const& p, int i, signed_constraint& c) { return is_forced_diseq(p, rational(i), c); }
 | 
			
		||||
 | 
			
		||||
        bool is_forced_odd(pdd const& p, signed_constraint& c);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -834,6 +834,10 @@ namespace polysat {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool slicing::is_extract(pvar x, pvar src, unsigned& out_hi, unsigned& out_lo) {
 | 
			
		||||
        return find_range_in_ancestor(var2slice(x), var2slice(src), out_hi, out_lo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void slicing::egraph_on_merge(enode* root, enode* other) {
 | 
			
		||||
        SASSERT(!is_value(other));  // by convention, interpreted nodes are always chosen as root
 | 
			
		||||
        if (is_value(root)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -320,6 +320,9 @@ namespace polysat {
 | 
			
		|||
        pvar mk_concat(unsigned num_args, pvar const* args) { return mk_concat(num_args, args, null_var); }
 | 
			
		||||
        pvar mk_concat(std::initializer_list<pvar> args);
 | 
			
		||||
 | 
			
		||||
        // Find hi, lo such that x = src[hi:lo].
 | 
			
		||||
        bool is_extract(pvar x, pvar src, unsigned& out_hi, unsigned& out_lo);
 | 
			
		||||
 | 
			
		||||
        // Track value assignments to variables (and propagate to subslices)
 | 
			
		||||
        // (could generalize to fixed bits, then we need a way to merge interpreted enodes)
 | 
			
		||||
        void add_value(pvar v, rational const& value);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue