3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 18:31:49 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2015-12-09 00:38:03 -08:00
parent 94bd2fdbe4
commit b9302e6caf
5 changed files with 142 additions and 100 deletions

View file

@ -21,6 +21,7 @@ Notes:
#include"arith_decl_plugin.h"
#include"ast_pp.h"
#include"ast_util.h"
#include"uint_set.h"
br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
@ -42,9 +43,14 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case OP_RE_EMPTY_SET:
case OP_RE_FULL_SET:
case OP_RE_OF_PRED:
case _OP_SEQ_SKOLEM:
return BR_FAILED;
case OP_SEQ_CONCAT:
if (num_args == 1) {
result = args[0];
return BR_DONE;
}
SASSERT(num_args == 2);
return mk_seq_concat(args[0], args[1], result);
case OP_SEQ_LENGTH:
@ -588,10 +594,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
}
// reduce strings
std::string s1, s2;
if (head1 < m_lhs.size() &&
head2 < m_rhs.size() &&
m_util.str.is_string(m_lhs[head1], s1) &&
m_util.str.is_string(m_rhs[head2], s2)) {
while (head1 < m_lhs.size() &&
head2 < m_rhs.size() &&
m_util.str.is_string(m_lhs[head1], s1) &&
m_util.str.is_string(m_rhs[head2], s2)) {
size_t l = std::min(s1.length(), s2.length());
for (size_t i = 0; i < l; ++i) {
if (s1[i] != s2[i]) {
@ -614,10 +620,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
}
change = true;
}
if (head1 < m_lhs.size() &&
head2 < m_rhs.size() &&
m_util.str.is_string(m_lhs.back(), s1) &&
m_util.str.is_string(m_rhs.back(), s2)) {
while (head1 < m_lhs.size() &&
head2 < m_rhs.size() &&
m_util.str.is_string(m_lhs.back(), s1) &&
m_util.str.is_string(m_rhs.back(), s2)) {
size_t l = std::min(s1.length(), s2.length());
for (size_t i = 0; i < l; ++i) {
if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
@ -695,29 +701,32 @@ bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, ex
std::swap(l, r);
}
for (unsigned i = 1; i + szl <= szr; ++i) {
bool eq = true;
for (unsigned j = 0; eq && j < szl; ++j) {
eq = l[j] == r[i+j];
uint_set rpos;
for (unsigned i = 0; i < szl; ++i) {
bool found = false;
unsigned j = 0;
for (; !found && j < szr; ++j) {
found = !rpos.contains(j) && l[i] == r[j];
}
if (eq) {
SASSERT(szr >= i + szl);
is_sat = set_empty(i, r, lhs, rhs);
is_sat &= set_empty(szr - (i + szl), r + i + szl, lhs, rhs);
TRACE("seq",
for (unsigned k = 0; k < szl; ++k) {
tout << mk_pp(l[k], m()) << " ";
}
tout << "\n";
for (unsigned k = 0; k < szr; ++k) {
tout << mk_pp(r[k], m()) << " ";
}
tout << "\n";
tout << lhs << "; " << rhs << "\n";);
if (!found) {
return false;
}
SASSERT(0 < j && j <= szr);
rpos.insert(j-1);
}
// if we reach here, then every element of l is contained in r in some position.
ptr_vector<expr> rs;
for (unsigned j = 0; j < szr; ++j) {
if (rpos.contains(j)) {
rs.push_back(r[j]);
}
else if (!set_empty(1, r + j, lhs, rhs)) {
is_sat = false;
return true;
}
}
return false;
SASSERT(szl == rs.size());
lhs.push_back(m_util.str.mk_concat(szl, l));
rhs.push_back(m_util.str.mk_concat(szl, rs.c_ptr()));
return true;
}

View file

@ -321,8 +321,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
func_decl_info(m_family_id, OP_STRING_CONST, num_parameters, parameters));
case OP_SEQ_CONCAT: {
if (arity < 2) {
m.raise_exception("invalid concatenation. At least two arguments expected");
if (arity == 0) {
m.raise_exception("invalid concatenation. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k);
@ -330,8 +330,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return m.mk_func_decl(m_sigs[(rng == m_string)?_OP_STRING_CONCAT:k]->m_name, rng, rng, rng, info);
}
case OP_RE_CONCAT: {
if (arity < 2) {
m.raise_exception("invalid concatenation. At least two arguments expected");
if (arity == 0) {
m.raise_exception("invalid concatenation. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k);
@ -339,8 +339,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return m.mk_func_decl(m_sigs[k]->m_name, rng, rng, rng, info);
}
case _OP_STRING_CONCAT: {
if (arity < 2) {
m.raise_exception("invalid string concatenation. At least two arguments expected");
if (arity == 0) {
m.raise_exception("invalid concatenation. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, OP_SEQ_CONCAT);

View file

@ -30,6 +30,7 @@ Revision History:
#include"theory_dummy.h"
#include"theory_dl.h"
#include"theory_seq_empty.h"
#include"theory_seq.h"
#include"theory_pb.h"
#include"theory_fpa.h"
@ -200,7 +201,7 @@ namespace smt {
void setup::setup_QF_BVRE() {
setup_QF_BV();
setup_QF_LIA();
m_context.register_plugin(alloc(smt::theory_seq_empty, m_manager));
setup_seq();
}
void setup::setup_QF_UF(static_features const & st) {
@ -814,7 +815,7 @@ namespace smt {
}
void setup::setup_seq() {
m_context.register_plugin(alloc(theory_seq_empty, m_manager));
m_context.register_plugin(alloc(theory_seq, m_manager));
}
void setup::setup_card() {

View file

@ -45,12 +45,17 @@ void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d
expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) {
std::pair<expr*, enode_pair_dependency*> value;
d = 0;
// TBD add path compression?
while (m_map.find(e, value)) {
d = d ? m_dm.mk_join(d, value.second) : value.second;;
e = value.first;
unsigned num_finds = 0;
expr* result = e;
while (m_map.find(result, value)) {
d = m_dm.mk_join(d, value.second);
result = value.first;
++num_finds;
}
return e;
if (num_finds > 1) { // path compression for original key only.
update(e, result, d);
}
return result;
}
void theory_seq::solution_map::pop_scope(unsigned num_scopes) {
@ -104,6 +109,15 @@ theory_seq::theory_seq(ast_manager& m):
m_contains_right_sym = "contains_right";
}
theory_seq::~theory_seq() {
unsigned num_scopes = m_lhs.size()-1;
if (num_scopes > 0) pop_scope_eh(num_scopes);
m.del(m_lhs.back());
m.del(m_rhs.back());
m_dam.del(m_deps.back());
}
final_check_status theory_seq::final_check_eh() {
context & ctx = get_context();
TRACE("seq", display(tout););
@ -113,30 +127,32 @@ final_check_status theory_seq::final_check_eh() {
if (simplify_and_solve_eqs()) {
return FC_CONTINUE;
}
if (m.size(m_lhs.back()) > 0) {
if (ctx.inconsistent()) {
return FC_CONTINUE;
}
if (m.size(m_lhs.back()) > 0 || m_incomplete) {
return FC_GIVEUP;
}
return m_incomplete?FC_GIVEUP:FC_DONE;
return FC_DONE;
}
bool theory_seq::check_ineqs() {
context & ctx = get_context();
for (unsigned i = 0; i < m_ineqs.size(); ++i) {
expr_ref a(m_ineqs[i].get(), m);
expr* a = m_ineqs[i].get();
enode_pair_dependency* eqs = 0;
expr_ref b = canonize(a, eqs);
if (m.is_true(b)) {
TRACE("seq", tout << "Evaluates to false: " << a << "\n";);
TRACE("seq", tout << "Evaluates to false: " << mk_pp(a,m) << "\n";);
ctx.internalize(a, false);
literal lit(ctx.get_literal(a));
propagate(lit, eqs);
propagate_lit(eqs, ctx.get_literal(a));
return false;
}
}
return true;
}
void theory_seq::propagate(literal lit, enode_pair_dependency* dep) {
void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) {
context& ctx = get_context();
ctx.mark_as_relevant(lit);
vector<enode_pair, false> _eqs;
@ -149,12 +165,46 @@ void theory_seq::propagate(literal lit, enode_pair_dependency* dep) {
<< mk_pp(_eqs[i].second->get_owner(), m) << "\n";
}
);
ctx.assign(
lit,
justification* js =
ctx.mk_justification(
ext_theory_propagation_justification(
get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), lit)));
get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), lit));
ctx.assign(lit, js);
}
void theory_seq::set_conflict(enode_pair_dependency* dep) {
context& ctx = get_context();
vector<enode_pair, false> _eqs;
m_dm.linearize(dep, _eqs);
TRACE("seq",
for (unsigned i = 0; i < _eqs.size(); ++i) {
tout << mk_pp(_eqs[i].first->get_owner(), m) << " = "
<< mk_pp(_eqs[i].second->get_owner(), m) << "\n";
}
);
ctx.set_conflict(
ctx.mk_justification(
ext_theory_conflict_justification(
get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), 0, 0)));
}
void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2) {
context& ctx = get_context();
vector<enode_pair, false> _eqs;
m_dm.linearize(dep, _eqs);
TRACE("seq",
tout << mk_pp(n1->get_owner(), m) << " " << mk_pp(n2->get_owner(), m) << " <- ";
for (unsigned i = 0; i < _eqs.size(); ++i) {
tout << mk_pp(_eqs[i].first->get_owner(), m) << " = "
<< mk_pp(_eqs[i].second->get_owner(), m) << "\n";
}
);
justification* js = ctx.mk_justification(
ext_theory_eq_propagation_justification(
get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), n1, n2));
ctx.assign_eq(n1, n2, eq_justification(js));
}
@ -165,11 +215,10 @@ bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps) {
expr_ref_vector lhs(m), rhs(m);
expr_ref lh = canonize(l, deps);
expr_ref rh = canonize(r, deps);
if (!rw.reduce_eq(l, r, lhs, rhs)) {
if (!rw.reduce_eq(lh, rh, lhs, rhs)) {
// equality is inconsistent.
// create conflict assignment.
literal lit(mk_eq(l, r, false));
propagate(~lit, deps);
TRACE("seq", tout << lh << " != " << rh << "\n";);
set_conflict(deps);
return true;
}
if (lhs.size() == 1 && l == lhs[0].get() &&
@ -255,20 +304,7 @@ void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) {
if (ctx.e_internalized(l) && ctx.e_internalized(r)) {
enode* n1 = ctx.get_enode(l);
enode* n2 = ctx.get_enode(r);
vector<enode_pair, false> _eqs;
m_dm.linearize(deps, _eqs);
TRACE("seq",
tout << mk_pp(n1->get_owner(), m) << " " << mk_pp(n2->get_owner(), m) << " <- ";
for (unsigned i = 0; i < _eqs.size(); ++i) {
tout << mk_pp(_eqs[i].first->get_owner(), m) << " = "
<< mk_pp(_eqs[i].second->get_owner(), m) << "\n";
}
);
justification* js = ctx.mk_justification(
ext_theory_eq_propagation_justification(
get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), n1, n2));
ctx.assign_eq(n1, n2, eq_justification(js));
propagate_eq(deps, n1, n2);
}
}
@ -296,11 +332,11 @@ bool theory_seq::pre_process_eqs(bool simplify_or_solve) {
m_dam.set(deps, i, m_dam.get(deps, m_dam.size(deps)-1));
--i;
++m_stats.m_num_reductions;
change = true;
}
m.pop_back(lhs);
m.pop_back(rhs);
m_dam.pop_back(deps);
change = true;
}
}
return change;
@ -338,13 +374,13 @@ bool theory_seq::internalize_term(app* term) {
if (ctx.e_internalized(term)) {
return true;
}
enode * e = ctx.mk_enode(term, false, m.is_bool(term), true);
if (m.is_bool(term)) {
bool_var bv = ctx.mk_bool_var(term);
ctx.set_var_theory(bv, get_id());
ctx.set_enode_flag(bv, true);
}
else {
enode * e = ctx.mk_enode(term, false, m.is_bool(term), true);
theory_var v = mk_var(e);
ctx.attach_th_var(e, this, v);
}
@ -425,7 +461,7 @@ void theory_seq::init_model(model_generator & mg) {
model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
enode_pair_dependency* deps = 0;
expr_ref e(m);
expr_ref e(n->get_owner(), m);
canonize(e, deps);
SASSERT(is_app(e));
m_factory->add_trail(e);
@ -443,8 +479,7 @@ void theory_seq::set_incomplete(app* term) {
}
theory_var theory_seq::mk_var(enode* n) {
theory_var r = theory::mk_var(n);
return r;
return theory::mk_var(n);
}
bool theory_seq::can_propagate() {
@ -461,7 +496,7 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
enode_pair_dependency* deps = 0;
e = m_rep.find(e, deps);
expr* e1, *e2;
eqs = join(eqs, deps);
eqs = m_dm.mk_join(eqs, deps);
if (m_util.str.is_concat(e, e1, e2)) {
return expr_ref(m_util.str.mk_concat(expand(e1, eqs), expand(e2, eqs)), m);
}
@ -484,18 +519,11 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
}
void theory_seq::add_dependency(enode_pair_dependency*& dep, enode* a, enode* b) {
dep = join(dep, leaf(a, b));
if (a != b) {
dep = m_dm.mk_join(dep, m_dm.mk_leaf(std::make_pair(a, b)));
}
}
theory_seq::enode_pair_dependency* theory_seq::join(enode_pair_dependency* a, enode_pair_dependency* b) {
if (!a) return b;
if (!b) return a;
return m_dm.mk_join(a, b);
}
theory_seq::enode_pair_dependency* theory_seq::leaf(enode* a, enode* b) {
return (a == b)?0:m_dm.mk_leaf(std::make_pair(a, b));
}
void theory_seq::propagate() {
context & ctx = get_context();
@ -523,10 +551,8 @@ void theory_seq::assert_axiom(expr_ref& e) {
}
expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1, expr* e2) {
expr_ref result(m);
expr* es[2] = { e1, e2 };
result = m_util.mk_skolem(name, 2, es, m.get_sort(e1));
return result;
return expr_ref(m_util.mk_skolem(name, 2, es, m.get_sort(e1)), m);
}
void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) {
@ -536,18 +562,20 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) {
<< mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";);
ctx.internalize(e1, false);
SASSERT(ctx.e_internalized(e2));
enode* n1 = ctx.get_enode(e1);
enode* n2 = ctx.get_enode(e2);
literal lit(v);
justification* js = ctx.mk_justification(ext_theory_eq_propagation_justification(
get_id(), ctx.get_region(), 1, &lit, 0, 0, n1, n2));
justification* js =
ctx.mk_justification(
ext_theory_eq_propagation_justification(
get_id(), ctx.get_region(), 1, &lit, 0, 0, n1, n2));
ctx.assign_eq(n1, n2, eq_justification(js));
}
void theory_seq::assign_eq(bool_var v, bool is_true) {
context & ctx = get_context();
enode* n = ctx.bool_var2enode(v);
app* e = n->get_owner();
if (is_true) {
@ -585,9 +613,11 @@ void theory_seq::assign_eq(bool_var v, bool is_true) {
void theory_seq::new_eq_eh(theory_var v1, theory_var v2) {
enode* n1 = get_enode(v1);
enode* n2 = get_enode(v2);
m.push_back(m_lhs.back(), n1->get_owner());
m.push_back(m_rhs.back(), n2->get_owner());
m_dam.push_back(m_deps.back(), leaf(n1, n2));
if (n1 != n2) {
m.push_back(m_lhs.back(), n1->get_owner());
m.push_back(m_rhs.back(), n2->get_owner());
m_dam.push_back(m_deps.back(), m_dm.mk_leaf(enode_pair(n1, n2)));
}
}
void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {

View file

@ -126,7 +126,11 @@ namespace smt {
bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep);
bool solve_basic_eqs();
bool simplify_and_solve_eqs();
void propagate(literal lit, enode_pair_dependency* dep);
void propagate_lit(enode_pair_dependency* dep, literal lit);
void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2);
void propagate_eq(bool_var v, expr* e1, expr* e2);
void set_conflict(enode_pair_dependency* dep);
bool occurs(expr* a, expr* b);
bool is_var(expr* b);
void add_solution(expr* l, expr* r, enode_pair_dependency* dep);
@ -140,15 +144,13 @@ namespace smt {
expr_ref canonize(expr* e, enode_pair_dependency*& eqs);
expr_ref expand(expr* e, enode_pair_dependency*& eqs);
void add_dependency(enode_pair_dependency*& dep, enode* a, enode* b);
enode_pair_dependency* leaf(enode* a, enode* b);
enode_pair_dependency* join(enode_pair_dependency* a, enode_pair_dependency* b);
void propagate_eq(bool_var v, expr* e1, expr* e2);
expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2);
void set_incomplete(app* term);
public:
theory_seq(ast_manager& m);
virtual ~theory_seq();
};
};