3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-03-21 20:18:50 +00:00

First step towards explaining single bits

This commit is contained in:
Clemens Eisenhofer 2022-12-19 12:27:37 +01:00
parent d5bc4b84a7
commit ec06027515
8 changed files with 418 additions and 6 deletions

View file

@ -113,6 +113,9 @@ namespace polysat {
if (first)
activate(s);
if (!propagate_bits(s, is_positive))
return; // conflict
if (clause_ref lemma = produce_lemma(s, s.assignment()))
s.add_clause(*lemma);
@ -120,6 +123,20 @@ namespace polysat {
s.set_conflict(signed_constraint(this, is_positive));
}
bool op_constraint::propagate_bits(solver& s, bool is_positive) {
switch (m_op) {
case code::lshr_op:
return propagate_bits_lshr(s, is_positive);
case code::shl_op:
return propagate_bits_shl(s, is_positive);
case code::and_op:
return propagate_bits_and(s, is_positive);
default:
NOT_IMPLEMENTED_YET();
return false;
}
}
/**
* Produce lemmas that contradict the given assignment.
*
@ -335,6 +352,39 @@ namespace polysat {
return l_undef;
}
bool op_constraint::propagate_bits_shl(solver& s, bool is_positive) {
tbv_ref p_val = s.m_fixed_bits.eval(m_p);
tbv_ref q_val = s.m_fixed_bits.eval(m_q);
tbv_ref r_val = s.m_fixed_bits.eval(m_r);
unsigned sz = m_p.power_of_2();
auto [shift_min, shift_max] = s.m_fixed_bits.min_max(q_val);
unsigned shift_min_u, shift_max_u;
if (!shift_min.is_unsigned() || shift_min.get_unsigned() > sz)
shift_min_u = sz;
else
shift_min_u = shift_min.get_unsigned();
if (!shift_max.is_unsigned() || shift_max.get_unsigned() > sz)
shift_max_u = sz;
else
shift_max_u = shift_max.get_unsigned();
SASSERT(shift_max_u <= sz);
SASSERT(shift_min_u <= shift_max_u);
for (unsigned i = 0; i < shift_min_u; i++) {
if (!s.m_fixed_bits.fix_value(s, m_r, i, BIT_0, this, s.))
return false;
}
for (unsigned i = shift_min_u; i < sz; i++) {
propagate_bit(s, m_r.var(), i, p_val[i - shift_min_u]);
}
}
void op_constraint::activate_and(solver& s) {
auto x = p(), y = q();
if (x.is_val())
@ -448,6 +498,31 @@ namespace polysat {
return l_undef;
}
bool op_constraint::propagate_bits_and(solver& s, bool is_positive){
tbv_ref p_val = s.m_fixed_bits.eval(m_p);
tbv_ref q_val = s.m_fixed_bits.eval(m_q);
tbv_ref r_val = s.m_fixed_bits.eval(m_r);
unsigned sz = m_p.power_of_2();
for (int i = 0; i < sz; i++) {
tbit bp = p_val[i];
tbit bq = q_val[i];
tbit br = r_val[i];
// TODO: Propagate from the result to the operands. e.g., 110... = xx1... & yyy...
// TODO: ==> x = 111..., y = 110...
if (bp == BIT_0 || bq == BIT_0) {
if (!s.m_fixed_bits.fix_value(s, m_r, i, BIT_0, this, std::pair(m_p, i), std::pair(m_q, i)))
return false;
}
else if (bp == BIT_1 && bq == BIT_1) {
if (!s.m_fixed_bits.fix_value(s, m_r, i, BIT_1, this, std::pair(m_p, i), std::pair(m_q, i)))
return false;
}
}
return true;
}
void op_constraint::add_to_univariate_solver(solver& s, univariate_solver& us, unsigned dep, bool is_positive) const {
auto p_coeff = s.subst(p()).get_univariate_coefficients();
auto q_coeff = s.subst(q()).get_univariate_coefficients();