mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 04:03:39 +00:00
fix co-factoring
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
f40becf099
commit
5348af3c4c
|
@ -19,6 +19,9 @@ Author:
|
||||||
#include "smt/seq_regex.h"
|
#include "smt/seq_regex.h"
|
||||||
#include "smt/theory_seq.h"
|
#include "smt/theory_seq.h"
|
||||||
#include "ast/expr_abstract.h"
|
#include "ast/expr_abstract.h"
|
||||||
|
#include "ast/ast_util.h"
|
||||||
|
#include "ast/for_each_expr.h"
|
||||||
|
#include <ast/rewriter/expr_safe_replace.h>
|
||||||
|
|
||||||
namespace smt {
|
namespace smt {
|
||||||
|
|
||||||
|
@ -533,7 +536,62 @@ namespace smt {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return r == u;
|
return r == u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is_non_empty(r, u) => nullable or \/_i (c_i and is_non_empty(r_i, u union r))
|
||||||
|
*
|
||||||
|
* for each (c_i, r_i) in cofactors (min-terms)
|
||||||
|
*
|
||||||
|
* is_non_empty(r_i, u union r) := false if r_i in u
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void seq_regex::propagate_is_non_empty(literal lit) {
|
||||||
|
expr* e = ctx.bool_var2expr(lit.var()), *r = nullptr, *u = nullptr, *n = nullptr;
|
||||||
|
VERIFY(sk().is_is_non_empty(e, r, u, n));
|
||||||
|
|
||||||
|
if (block_if_empty(r, lit))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
TRACE("seq_regex", tout << "propagate nonempty: " << mk_pp(e, m) << std::endl;);
|
||||||
|
STRACE("seq_regex_brief", tout
|
||||||
|
<< std::endl << "PNE(" << expr_id_str(e) << "," << state_str(r)
|
||||||
|
<< "," << expr_id_str(u) << "," << expr_id_str(n) << ") ";);
|
||||||
|
|
||||||
|
expr_ref is_nullable = is_nullable_wrapper(r);
|
||||||
|
if (m.is_true(is_nullable))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
literal null_lit = th.mk_literal(is_nullable);
|
||||||
|
expr_ref hd = mk_first(r, n);
|
||||||
|
expr_ref d(m);
|
||||||
|
d = mk_derivative_wrapper(hd, r);
|
||||||
|
|
||||||
|
literal_vector lits;
|
||||||
|
lits.push_back(~lit);
|
||||||
|
if (null_lit != false_literal)
|
||||||
|
lits.push_back(null_lit);
|
||||||
|
|
||||||
|
expr_ref_pair_vector cofactors(m);
|
||||||
|
get_cofactors(d, cofactors);
|
||||||
|
for (auto const& p : cofactors) {
|
||||||
|
if (is_member(p.second, u))
|
||||||
|
continue;
|
||||||
|
expr_ref cond(p.first, m);
|
||||||
|
seq_rw().elim_condition(hd, cond);
|
||||||
|
rewrite(cond);
|
||||||
|
if (m.is_false(cond))
|
||||||
|
continue;
|
||||||
|
expr_ref next_non_empty = sk().mk_is_non_empty(p.second, re().mk_union(u, p.second), n);
|
||||||
|
if (!m.is_true(cond))
|
||||||
|
next_non_empty = m.mk_and(cond, next_non_empty);
|
||||||
|
lits.push_back(th.mk_literal(next_non_empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
th.add_axiom(lits);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a string s, index i, and a derivative r, return an
|
Given a string s, index i, and a derivative r, return an
|
||||||
|
@ -681,39 +739,47 @@ namespace smt {
|
||||||
Return a list of all (cond, leaf) pairs in a given derivative
|
Return a list of all (cond, leaf) pairs in a given derivative
|
||||||
expression r.
|
expression r.
|
||||||
|
|
||||||
Note: this recursive implementation is inefficient, since if nodes
|
Note: this implementation is inefficient: it simply collects all expressions under an if and
|
||||||
are repeated often in the expression DAG, they may be visited
|
iterates over all combinations.
|
||||||
many times. For this reason, prefer mk_deriv_accept and
|
|
||||||
get_all_derivatives when possible.
|
|
||||||
|
|
||||||
This method is still used by:
|
This method is still used by:
|
||||||
propagate_is_empty
|
propagate_is_empty
|
||||||
propagate_is_non_empty
|
propagate_is_non_empty
|
||||||
*/
|
*/
|
||||||
void seq_regex::get_cofactors(expr* r, expr_ref_pair_vector& result) {
|
void seq_regex::get_cofactors(expr* r, expr_ref_pair_vector& result) {
|
||||||
expr_ref_vector conds(m);
|
obj_hashtable<expr> ifs;
|
||||||
get_cofactors_rec(r, conds, result);
|
expr* cond = nullptr, * r1 = nullptr, * r2 = nullptr;
|
||||||
STRACE("seq_regex", tout << "Number of derivatives: "
|
for (expr* e : subterms::ground(expr_ref(r, m)))
|
||||||
<< result.size() << std::endl;);
|
if (m.is_ite(e, cond, r1, r2))
|
||||||
STRACE("seq_regex_brief", tout << "#derivs=" << result.size() << " ";);
|
ifs.insert(cond);
|
||||||
}
|
|
||||||
void seq_regex::get_cofactors_rec(expr* r, expr_ref_vector& conds,
|
expr_ref_vector rs(m);
|
||||||
expr_ref_pair_vector& result) {
|
vector<expr_ref_vector> conds;
|
||||||
expr* cond = nullptr, *r1 = nullptr, *r2 = nullptr;
|
conds.push_back(expr_ref_vector(m));
|
||||||
if (m.is_ite(r, cond, r1, r2)) {
|
rs.push_back(r);
|
||||||
conds.push_back(cond);
|
for (expr* c : ifs) {
|
||||||
get_cofactors_rec(r1, conds, result);
|
unsigned sz = conds.size();
|
||||||
conds.pop_back();
|
expr_safe_replace rep1(m);
|
||||||
conds.push_back(mk_not(m, cond));
|
expr_safe_replace rep2(m);
|
||||||
get_cofactors_rec(r2, conds, result);
|
rep1.insert(c, m.mk_true());
|
||||||
conds.pop_back();
|
rep2.insert(c, m.mk_false());
|
||||||
|
expr_ref r2(m);
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
expr_ref_vector cs = conds[i];
|
||||||
|
cs.push_back(mk_not(m, c));
|
||||||
|
conds.push_back(cs);
|
||||||
|
conds[i].push_back(c);
|
||||||
|
expr_ref r1(rs.get(i), m);
|
||||||
|
rep1(r1, r2);
|
||||||
|
rs[i] = r2;
|
||||||
|
rep2(r1, r2);
|
||||||
|
rs.push_back(r2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (re().is_union(r, r1, r2)) {
|
for (unsigned i = 0; i < conds.size(); ++i) {
|
||||||
get_cofactors_rec(r1, conds, result);
|
expr_ref conj = mk_and(conds[i]);
|
||||||
get_cofactors_rec(r2, conds, result);
|
expr_ref r(rs.get(i), m);
|
||||||
}
|
ctx.get_rewriter()(r);
|
||||||
else {
|
|
||||||
expr_ref conj = mk_and(conds);
|
|
||||||
if (!m.is_false(conj) && !re().is_empty(r))
|
if (!m.is_false(conj) && !re().is_empty(r))
|
||||||
result.push_back(conj, r);
|
result.push_back(conj, r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,8 +165,6 @@ namespace smt {
|
||||||
expr_ref mk_deriv_accept(expr* s, unsigned i, expr* r);
|
expr_ref mk_deriv_accept(expr* s, unsigned i, expr* r);
|
||||||
void get_derivative_targets(expr* r, expr_ref_vector& targets);
|
void get_derivative_targets(expr* r, expr_ref_vector& targets);
|
||||||
void get_cofactors(expr* r, expr_ref_pair_vector& result);
|
void get_cofactors(expr* r, expr_ref_pair_vector& result);
|
||||||
void get_cofactors_rec(expr* r, expr_ref_vector& conds,
|
|
||||||
expr_ref_pair_vector& result);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pretty print the regex of the state id to the out stream,
|
Pretty print the regex of the state id to the out stream,
|
||||||
|
@ -186,6 +184,8 @@ namespace smt {
|
||||||
|
|
||||||
bool block_if_empty(expr* r, literal lit);
|
bool block_if_empty(expr* r, literal lit);
|
||||||
|
|
||||||
|
void propagate_is_non_empty(literal lit);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
seq_regex(theory_seq& th);
|
seq_regex(theory_seq& th);
|
||||||
|
|
Loading…
Reference in a new issue