Skip to content

Commit 81189d6

Browse files
authored
Added bit2bool to the API (#5992)
* Fixed registering expressions in push/pop * Reused existing function * Reverted reusing can_propagate * Added decide-callback to user-propagator * Refactoring * Fixed index * Added bit2bool to the API Fixed bug in user-propagator's decide callback * Fixed typo
1 parent 0dd0fd2 commit 81189d6

5 files changed

Lines changed: 57 additions & 30 deletions

File tree

src/api/api_bv.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
102102
MK_BV_PUNARY(Z3_mk_sign_ext, OP_SIGN_EXT);
103103
MK_BV_PUNARY(Z3_mk_zero_ext, OP_ZERO_EXT);
104104
MK_BV_PUNARY(Z3_mk_repeat, OP_REPEAT);
105+
MK_BV_PUNARY(Z3_mk_bit2bool, OP_BIT2BOOL);
105106
MK_BV_PUNARY(Z3_mk_rotate_left, OP_ROTATE_LEFT);
106107
MK_BV_PUNARY(Z3_mk_rotate_right, OP_ROTATE_RIGHT);
107108
MK_BV_PUNARY(Z3_mk_int2bv, OP_INT2BV);

src/api/c++/z3++.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ namespace z3 {
13591359

13601360
friend expr operator~(expr const & a);
13611361
expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); ctx().check_error(); return expr(ctx(), r); }
1362+
expr bit2bool(unsigned i) const { Z3_ast r = Z3_mk_bit2bool(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); }
13621363
unsigned lo() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast<unsigned>(Z3_get_decl_int_parameter(ctx(), decl(), 1)); }
13631364
unsigned hi() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast<unsigned>(Z3_get_decl_int_parameter(ctx(), decl(), 0)); }
13641365

src/api/z3_api.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2914,6 +2914,16 @@ extern "C" {
29142914
def_API('Z3_mk_repeat', AST, (_in(CONTEXT), _in(UINT), _in(AST)))
29152915
*/
29162916
Z3_ast Z3_API Z3_mk_repeat(Z3_context c, unsigned i, Z3_ast t1);
2917+
2918+
/**
2919+
\brief Extracts the bit at position \ccode{i} of a bit-vector and
2920+
yields a boolean.
2921+
2922+
The node \c t1 must have a bit-vector sort.
2923+
2924+
def_API('Z3_mk_bit2bool', AST, (_in(CONTEXT), _in(UINT), _in(AST)))
2925+
*/
2926+
Z3_ast Z3_API Z3_mk_bit2bool(Z3_context c, unsigned i, Z3_ast t1);
29172927

29182928
/**
29192929
\brief Shift left.
@@ -6755,16 +6765,16 @@ extern "C" {
67556765
void Z3_API Z3_solver_propagate_diseq(Z3_context c, Z3_solver s, Z3_eq_eh eq_eh);
67566766

67576767
/**
6758-
* \brief register a callback when a new expression with a registered function is used by the solver
6759-
* The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare.
6768+
\brief register a callback when a new expression with a registered function is used by the solver
6769+
The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare.
67606770
*/
67616771
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh);
67626772

67636773
/**
6764-
* \brief register a callback when a the solver decides to split on a registered expression
6765-
* The callback may set passed expression to another registered expression which will be selected instead.
6766-
* In case the expression is a bitvector the bit to split on is determined by the bit argument and the
6767-
* truth-value to try first is given by is_pos
6774+
\brief register a callback when the solver decides to split on a registered expression.
6775+
The callback may set the passed expression to another registered expression which will be selected instead.
6776+
In case the expression is a bitvector the bit to split on is determined by the bit argument and the
6777+
truth-value to try first is given by is_pos. In case the truth value is undefined the solver will decide.
67686778
*/
67696779
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh);
67706780

src/smt/theory_bv.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,11 +1842,11 @@ namespace smt {
18421842
unsigned sz = bits.size();
18431843

18441844
for (unsigned i = start_bit; i < sz; ++i) {
1845-
if (ctx.get_assignment(bits[i].var()) != l_undef)
1845+
if (ctx.get_assignment(bits[i].var()) == l_undef)
18461846
return bits[i].var();
18471847
}
18481848
for (unsigned i = 0; i < start_bit; ++i) {
1849-
if (ctx.get_assignment(bits[i].var()) != l_undef)
1849+
if (ctx.get_assignment(bits[i].var()) == l_undef)
18501850
return bits[i].var();
18511851
}
18521852

src/smt/theory_user_propagator.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -159,37 +159,53 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu
159159
void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
160160

161161
const bool_var_data& d = ctx.get_bdata(var);
162-
163-
if (!d.is_theory_atom())
162+
163+
if (!d.is_enode() && !d.is_theory_atom())
164164
return;
165-
166-
theory* th = ctx.get_theory(d.get_theory());
167-
168-
bv_util bv(m);
169-
enode* original_enode = nullptr;
165+
166+
enode* original_enode = nullptr;
170167
unsigned original_bit = 0;
171-
172-
if (d.is_enode() && th->get_family_id() == get_family_id()) {
173-
// variable is just a registered expression
168+
bv_util bv(m);
169+
theory* th = nullptr;
170+
theory_var v = null_theory_var;
171+
172+
// get the associated theory
173+
if (!d.is_enode()) {
174+
// it might be a value that does not have an enode
175+
th = ctx.get_theory(d.get_theory());
176+
}
177+
else {
174178
original_enode = ctx.bool_var2enode(var);
179+
v = original_enode->get_th_var(get_family_id());
180+
if (v == null_theory_var) {
181+
// it is not a registered boolean expression
182+
th = ctx.get_theory(d.get_theory());
183+
}
175184
}
176-
else if (th->get_family_id() == bv.get_fid()) {
177-
// it might be a registered bit-vector
178-
auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id());
179-
if (!registered_bv.first)
180-
// there is no registered bv associated with the bit
185+
186+
if (!th && v == null_theory_var)
187+
return;
188+
189+
if (v == null_theory_var) {
190+
if (th->get_family_id() == bv.get_fid()) {
191+
// it is not a registered boolean value but it is a bitvector
192+
auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id());
193+
if (!registered_bv.first)
194+
// there is no registered bv associated with the bit
195+
return;
196+
original_enode = registered_bv.first;
197+
original_bit = registered_bv.second;
198+
v = original_enode->get_th_var(get_family_id());
199+
}
200+
else
181201
return;
182-
original_enode = registered_bv.first;
183-
original_bit = registered_bv.second;
184202
}
185-
else
186-
return;
187203

188204
// call the registered callback
189205
unsigned new_bit = original_bit;
190206
lbool phase = is_pos ? l_true : l_false;
191-
192-
expr* e = var2expr(original_enode->get_th_var(get_family_id()));
207+
208+
expr* e = var2expr(v);
193209
m_decide_eh(m_user_context, this, &e, &new_bit, &phase);
194210
enode* new_enode = ctx.get_enode(e);
195211

@@ -201,7 +217,6 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
201217
return;
202218
}
203219

204-
bool_var old_var = var;
205220
if (new_enode->is_bool()) {
206221
// expression was set to a boolean
207222
bool_var new_var = ctx.enode2bool_var(new_enode);

0 commit comments

Comments
 (0)