3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 00:26:38 +00:00

starting solve_concat_eq_str(); currently there is an unsoundness bug

This commit is contained in:
Murphy Berzish 2015-09-27 21:30:45 -04:00
parent 6481fe941a
commit 86e6087718
2 changed files with 212 additions and 3 deletions

View file

@ -144,6 +144,7 @@ void theory_str::propagate() {
* Instantiate an axiom of the following form:
* Length(Concat(x, y)) = Length(x) + Length(y)
*/
// TODO this isn't used yet
void theory_str::instantiate_concat_axiom(enode * cat) {
SASSERT(is_concat(cat));
app * a_cat = cat->get_owner();
@ -302,6 +303,99 @@ void theory_str::reset_eh() {
pop_scope_eh(0);
}
/*
* Check equality among equivalence class members of LHS and RHS
* to discover an incorrect LHS == RHS.
* For example, if we have y2 == "str3"
* and the equivalence classes are
* { y2, (Concat ce m2) }
* { "str3", (Concat abc x2) }
* then y2 can't be equal to "str3".
* Then add an assertion: (y2 == (Concat ce m2)) AND ("str3" == (Concat abc x2)) -> (y2 != "str3")
*/
bool theory_str::new_eq_check(expr * lhs, expr * rhs) {
// TODO this involves messing around with enodes and equivalence classes
return true;
}
void theory_str::group_terms_by_eqc(expr * n, std::set<expr*> & concats, std::set<expr*> & vars, std::set<expr*> & consts) {
ast_manager & m = get_manager();
context & ctx = get_context();
enode * nNode = ctx.get_enode(n);
enode * eqcNode = nNode;
do {
app * ast = eqcNode->get_owner();
if (is_concat(eqcNode)) {
// TODO simplify_concat
/*
Z3_ast simConcat = simplifyConcat(t, eqcNode);
if (simConcat != eqcNode) {
if (isConcatFunc(t, simConcat)) {
concats.insert(simConcat);
} else {
if (isConstStr(t, simConcat)) {
constStrs.insert(simConcat);
} else {
vars.insert(simConcat);
}
}
} else {
concats.insert(simConcat);
}
*/
concats.insert(ast);
} else if (is_string(eqcNode)) {
consts.insert(ast);
} else {
vars.insert(ast);
}
eqcNode = eqcNode->get_next();
} while (eqcNode != nNode);
}
void theory_str::simplify_concat_equality(expr * lhs, expr * rhs) {
// TODO strArgmt::simplifyConcatEq()
}
/*
* strArgmt::solve_concat_eq_str()
* Solve concatenations of the form:
* const == Concat(const, X)
* const == Concat(X, const)
*/
void theory_str::solve_concat_eq_str(expr * concat, expr * str) {
ast_manager & m = get_manager();
context & ctx = get_context();
TRACE("t_str_detail", tout << mk_ismt2_pp(concat, m) << " == " << mk_ismt2_pp(str, m) << std::endl;);
if (is_concat(to_app(concat)) && is_string(to_app(str))) {
const char * tmp = 0;
m_strutil.is_string(str, & tmp);
std::string const_str(tmp);
app * a_concat = to_app(concat);
SASSERT(a_concat->get_num_args() == 2);
expr * a1 = a_concat->get_arg(0);
expr * a2 = a_concat->get_arg(1);
if (const_str == "") {
TRACE("t_str", tout << "quick path: concat == \"\"" << std::endl;);
// assert the following axiom:
// ( (Concat a1 a2) == str ) -> ( (a1 == "") AND (a2 == "") )
expr_ref premise(ctx.mk_eq_atom(concat, str), m);
expr_ref empty_str(m_strutil.mk_string(""), m);
expr_ref c1(ctx.mk_eq_atom(a1, empty_str), m);
expr_ref c2(ctx.mk_eq_atom(a2, empty_str), m);
expr_ref conclusion(m.mk_and(c1, c2), m);
expr_ref axiom(m.mk_implies(premise, conclusion), m);
TRACE("t_str_detail", tout << "learn " << mk_ismt2_pp(axiom, m) << std::endl;);
assert_axiom(axiom);
return;
}
// TODO the rest...
}
}
void theory_str::handle_equality(expr * lhs, expr * rhs) {
ast_manager & m = get_manager();
context & ctx = get_context();
@ -319,7 +413,10 @@ void theory_str::handle_equality(expr * lhs, expr * rhs) {
// TODO simplify concat?
// TODO newEqCheck()?
// newEqCheck() -- check consistency wrt. existing equivalence classes
if (!new_eq_check(lhs, rhs)) {
return;
}
// BEGIN new_eq_handler() in strTheory
@ -332,6 +429,94 @@ void theory_str::handle_equality(expr * lhs, expr * rhs) {
enode * e_rhs = ctx.get_enode(rhs);
std::pair<enode*,enode*> eq_pair(e_lhs, e_rhs);
m_str_eq_length_axiom_todo.push_back(eq_pair);
// group terms by equivalence class (groupNodeInEqc())
std::set<expr*> eqc_lhs_concat;
std::set<expr*> eqc_lhs_var;
std::set<expr*> eqc_lhs_const;
group_terms_by_eqc(lhs, eqc_lhs_concat, eqc_lhs_var, eqc_lhs_const);
TRACE("t_str_detail",
tout << "eqc[lhs]:" << std::endl;
tout << "Concats:" << std::endl;
for (std::set<expr*>::iterator it = eqc_lhs_concat.begin(); it != eqc_lhs_concat.end(); ++it) {
expr * ex = *it;
tout << mk_ismt2_pp(ex, get_manager()) << std::endl;
}
tout << "Variables:" << std::endl;
for (std::set<expr*>::iterator it = eqc_lhs_var.begin(); it != eqc_lhs_var.end(); ++it) {
expr * ex = *it;
tout << mk_ismt2_pp(ex, get_manager()) << std::endl;
}
tout << "Constants:" << std::endl;
for (std::set<expr*>::iterator it = eqc_lhs_const.begin(); it != eqc_lhs_const.end(); ++it) {
expr * ex = *it;
tout << mk_ismt2_pp(ex, get_manager()) << std::endl;
}
);
std::set<expr*> eqc_rhs_concat;
std::set<expr*> eqc_rhs_var;
std::set<expr*> eqc_rhs_const;
group_terms_by_eqc(rhs, eqc_rhs_concat, eqc_rhs_var, eqc_rhs_const);
TRACE("t_str_detail",
tout << "eqc[rhs]:" << std::endl;
tout << "Concats:" << std::endl;
for (std::set<expr*>::iterator it = eqc_rhs_concat.begin(); it != eqc_rhs_concat.end(); ++it) {
expr * ex = *it;
tout << mk_ismt2_pp(ex, get_manager()) << std::endl;
}
tout << "Variables:" << std::endl;
for (std::set<expr*>::iterator it = eqc_rhs_var.begin(); it != eqc_rhs_var.end(); ++it) {
expr * ex = *it;
tout << mk_ismt2_pp(ex, get_manager()) << std::endl;
}
tout << "Constants:" << std::endl;
for (std::set<expr*>::iterator it = eqc_rhs_const.begin(); it != eqc_rhs_const.end(); ++it) {
expr * ex = *it;
tout << mk_ismt2_pp(ex, get_manager()) << std::endl;
}
);
// step 1: Concat == Concat
bool hasCommon = false;
if (eqc_lhs_concat.size() != 0 && eqc_rhs_concat.size() != 0) {
std::set<expr*>::iterator itor1 = eqc_lhs_concat.begin();
std::set<expr*>::iterator itor2 = eqc_rhs_concat.begin();
for (; itor1 != eqc_lhs_concat.end(); ++itor1) {
if (eqc_rhs_concat.find(*itor1) != eqc_rhs_concat.end()) {
hasCommon = true;
break;
}
}
for (; !hasCommon && itor2 != eqc_rhs_concat.end(); ++itor2) {
if (eqc_lhs_concat.find(*itor2) != eqc_lhs_concat.end()) {
hasCommon = true;
break;
}
}
if (!hasCommon) {
simplify_concat_equality(*(eqc_lhs_concat.begin()), *(eqc_rhs_concat.begin()));
}
}
// step 2: Concat == Constant
if (eqc_lhs_const.size() != 0) {
expr * conStr = *(eqc_lhs_const.begin());
std::set<expr*>::iterator itor2 = eqc_rhs_concat.begin();
for (; itor2 != eqc_rhs_concat.end(); ++itor2) {
solve_concat_eq_str(*itor2, conStr);
}
} else if (eqc_rhs_const.size() != 0) {
expr * conStr = *(eqc_rhs_const.begin());
std::set<expr*>::iterator itor1 = eqc_lhs_concat.begin();
for (; itor1 != eqc_lhs_concat.end(); ++itor1) {
solve_concat_eq_str(*itor1, conStr);
}
}
// TODO regex unroll? (much later)
}
void theory_str::set_up_axioms(expr * ex) {
@ -368,6 +553,9 @@ void theory_str::init_search_eh() {
ast_manager & m = get_manager();
context & ctx = get_context();
// TODO it would be better to refactor this function so that instead of deferring the axioms
// instead we defer the evaluation of the expression
TRACE("t_str_detail",
tout << "dumping all asserted formulas:" << std::endl;
unsigned nFormulas = ctx.get_num_asserted_formulas();
@ -410,11 +598,11 @@ void theory_str::init_search_eh() {
}
}
TRACE("t_str", tout << "search started" << std::endl;);
search_started = true;
}
void theory_str::new_eq_eh(theory_var x, theory_var y) {
// TODO
TRACE("t_str", tout << "new eq: v#" << x << " = v#" << y << std::endl;);
TRACE("t_str_detail", tout << mk_ismt2_pp(get_enode(x)->get_owner(), get_manager()) << " = " <<
mk_ismt2_pp(get_enode(y)->get_owner(), get_manager()) << std::endl;);
@ -422,7 +610,6 @@ void theory_str::new_eq_eh(theory_var x, theory_var y) {
}
void theory_str::new_diseq_eh(theory_var x, theory_var y) {
// TODO
TRACE("t_str", tout << "new diseq: v#" << x << " != v#" << y << std::endl;);
TRACE("t_str_detail", tout << mk_ismt2_pp(get_enode(x)->get_owner(), get_manager()) << " != " <<
mk_ismt2_pp(get_enode(y)->get_owner(), get_manager()) << std::endl;);
@ -442,8 +629,21 @@ void theory_str::push_scope_eh() {
}
final_check_status theory_str::final_check_eh() {
ast_manager & m = get_manager();
context & ctx = get_context();
// TODO
TRACE("t_str", tout << "final check" << std::endl;);
TRACE("t_str_detail",
tout << "dumping all assignments:" << std::endl;
expr_ref_vector assignments(m);
ctx.get_assignments(assignments);
for (expr_ref_vector::iterator i = assignments.begin(); i != assignments.end(); ++i) {
expr * ex = *i;
tout << mk_ismt2_pp(ex, m) << std::endl;
}
);
return FC_DONE;
}

View file

@ -23,6 +23,7 @@ Revision History:
#include"value_factory.h"
#include"smt_model_generator.h"
#include"arith_decl_plugin.h"
#include<set>
namespace smt {
@ -46,12 +47,20 @@ namespace smt {
bool is_concat(app const * a) const { return a->is_app_of(get_id(), OP_STRCAT); }
bool is_concat(enode const * n) const { return is_concat(n->get_owner()); }
bool is_string(app const * a) const { return a->is_app_of(get_id(), OP_STR); }
bool is_string(enode const * n) const { return is_string(n->get_owner()); }
void instantiate_concat_axiom(enode * cat);
void instantiate_basic_string_axioms(enode * str);
void instantiate_str_eq_length_axiom(enode * lhs, enode * rhs);
void set_up_axioms(expr * ex);
void handle_equality(expr * lhs, expr * rhs);
void simplify_concat_equality(expr * lhs, expr * rhs);
void solve_concat_eq_str(expr * concat, expr * str);
bool new_eq_check(expr * lhs, expr * rhs);
void group_terms_by_eqc(expr * n, std::set<expr*> & concats, std::set<expr*> & vars, std::set<expr*> & consts);
public:
theory_str(ast_manager & m);
virtual ~theory_str();