mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 00:26:38 +00:00
Cleanup and revert/incorporate changes -- merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
36102a65ea
11 changed files with 545 additions and 553 deletions
|
@ -315,6 +315,7 @@ endif()
|
|||
################################################################################
|
||||
# Threading support
|
||||
################################################################################
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads)
|
||||
list(APPEND Z3_DEPENDENT_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ extern "C" {
|
|||
res = false;
|
||||
}
|
||||
else {
|
||||
*g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n";
|
||||
*g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << "\"\n";
|
||||
g_z3_log->flush();
|
||||
g_z3_log_enabled = true;
|
||||
}
|
||||
|
|
|
@ -416,6 +416,9 @@ br_status seq_rewriter::mk_bool_app(func_decl* f, unsigned n, expr* const* args,
|
|||
return mk_bool_app_helper(true, n, args, result);
|
||||
case OP_OR:
|
||||
return mk_bool_app_helper(false, n, args, result);
|
||||
case OP_EQ:
|
||||
SASSERT(n == 2);
|
||||
// return mk_eq_helper(args[0], args[1], result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -492,7 +495,27 @@ br_status seq_rewriter::mk_bool_app_helper(bool is_and, unsigned n, expr* const*
|
|||
}
|
||||
}
|
||||
|
||||
result = is_and ? m().mk_and(new_args.size(), new_args.c_ptr()) : m().mk_or(new_args.size(), new_args.c_ptr());
|
||||
result = is_and ? m().mk_and(new_args) : m().mk_or(new_args);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_eq_helper(expr* a, expr* b, expr_ref& result) {
|
||||
expr* sa = nullptr, *ra = nullptr, *sb = nullptr, *rb = nullptr;
|
||||
if (str().is_in_re(b))
|
||||
std::swap(a, b);
|
||||
if (!str().is_in_re(a, sa, ra))
|
||||
return BR_FAILED;
|
||||
bool is_not = m().is_not(b, b);
|
||||
if (!str().is_in_re(b, sb, rb))
|
||||
return BR_FAILED;
|
||||
if (sa != sb)
|
||||
return BR_FAILED;
|
||||
// sa in ra = sb in rb;
|
||||
// sa in (ra n rb) u (C(ra) n C(rb))
|
||||
if (is_not)
|
||||
rb = re().mk_complement(rb);
|
||||
expr* r = re().mk_union(re().mk_inter(ra, rb), re().mk_inter(re().mk_complement(ra), re().mk_complement(rb)));
|
||||
result = re().mk_in_re(sa, r);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
|
@ -703,9 +726,9 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
case _OP_STRING_STRIDOF:
|
||||
UNREACHABLE();
|
||||
}
|
||||
// if (st == BR_FAILED) {
|
||||
// st = lift_ites_throttled(f, num_args, args, result);
|
||||
// }
|
||||
if (st == BR_FAILED) {
|
||||
st = lift_ites_throttled(f, num_args, args, result);
|
||||
}
|
||||
CTRACE("seq_verbose", st != BR_FAILED, tout << expr_ref(m().mk_app(f, num_args, args), m()) << " -> " << result << "\n";);
|
||||
SASSERT(st == BR_FAILED || m().get_sort(result) == f->get_range());
|
||||
return st;
|
||||
|
@ -2137,7 +2160,7 @@ expr_ref seq_rewriter::is_nullable_rec(expr* r) {
|
|||
if (!result) {
|
||||
std::cout << "(m) ";
|
||||
result = is_nullable(r);
|
||||
m_op_cache.insert(_OP_RE_IS_NULLABLE, r, nullptr, nullptr, result);
|
||||
m_op_cache.insert(_OP_RE_IS_NULLABLE, r, nullptr, nullptr, result);
|
||||
} else {
|
||||
std::cout << "(h) ";
|
||||
}
|
||||
|
@ -2288,119 +2311,226 @@ br_status seq_rewriter::mk_re_reverse(expr* r, expr_ref& result) {
|
|||
Symbolic derivative: seq -> regex -> regex
|
||||
seq should be single char
|
||||
*/
|
||||
|
||||
br_status seq_rewriter::mk_re_derivative(expr* ele, expr* r, expr_ref& result) {
|
||||
sort *seq_sort = nullptr, *ele_sort = nullptr;
|
||||
result = mk_derivative(ele, r);
|
||||
// TBD: we may even declare BR_DONE here and potentially miss some simplifications
|
||||
return re().is_derivative(result) ? BR_DONE : BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Recursive implementation of the symbolic derivative such that
|
||||
the result is in an optimized BDD form.
|
||||
|
||||
Definition of BDD form:
|
||||
if-then-elses are pushed outwards
|
||||
and sorted by condition ID (cond->get_id()), from largest on
|
||||
the outside to smallest on the inside.
|
||||
Duplicate nested conditions are eliminated.
|
||||
|
||||
*/
|
||||
expr_ref seq_rewriter::mk_derivative(expr* ele, expr* r) {
|
||||
expr_ref result(m_op_cache.find(OP_RE_DERIVATIVE, ele, r, nullptr), m());
|
||||
if (!result) {
|
||||
result = mk_derivative_rec(ele, r);
|
||||
m_op_cache.insert(OP_RE_DERIVATIVE, ele, r, nullptr, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_union(expr* r1, expr* r2) {
|
||||
return mk_der_op(OP_RE_UNION, r1, r2);
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_inter(expr* r1, expr* r2) {
|
||||
return mk_der_op(OP_RE_INTERSECT, r1, r2);
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_concat(expr* r1, expr* r2) {
|
||||
return mk_der_op(OP_RE_CONCAT, r1, r2);
|
||||
}
|
||||
|
||||
/*
|
||||
Form a derivative by combining two if-then-else expressions in BDD form.
|
||||
|
||||
Preconditions:
|
||||
- k is a binary op code on REs (re.union, re.inter, etc.)
|
||||
- a and b are in BDD form
|
||||
|
||||
Postcondition:
|
||||
- result is in BDD form
|
||||
*/
|
||||
expr_ref seq_rewriter::mk_der_op_rec(decl_kind k, expr* a, expr* b) {
|
||||
expr* ca = nullptr, *a1 = nullptr, *a2 = nullptr;
|
||||
expr* cb = nullptr, *b1 = nullptr, *b2 = nullptr;
|
||||
expr_ref result(m());
|
||||
auto mk_ite = [&](expr* c, expr* a, expr* b) {
|
||||
return (a == b) ? a : m().mk_ite(c, a, b);
|
||||
};
|
||||
if (m().is_ite(a, ca, a1, a2)) {
|
||||
if (m().is_ite(b, cb, b1, b2)) {
|
||||
if (ca == cb) {
|
||||
expr_ref r1 = mk_der_op(k, a1, b1);
|
||||
expr_ref r2 = mk_der_op(k, a2, b2);
|
||||
result = mk_ite(ca, r1, r2);
|
||||
return result;
|
||||
}
|
||||
else if (ca->get_id() < cb->get_id()) {
|
||||
expr_ref r1 = mk_der_op(k, a, b1);
|
||||
expr_ref r2 = mk_der_op(k, a, b2);
|
||||
result = mk_ite(cb, r1, r2);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
expr_ref r1 = mk_der_op(k, a1, b);
|
||||
expr_ref r2 = mk_der_op(k, a2, b);
|
||||
result = mk_ite(ca, r1, r2);
|
||||
return result;
|
||||
}
|
||||
if (m().is_ite(b, cb, b1, b2)) {
|
||||
expr_ref r1 = mk_der_op(k, a, b1);
|
||||
expr_ref r2 = mk_der_op(k, a, b2);
|
||||
result = mk_ite(cb, r1, r2);
|
||||
return result;
|
||||
}
|
||||
switch (k) {
|
||||
case OP_RE_INTERSECT:
|
||||
if (BR_FAILED == mk_re_inter(a, b, result))
|
||||
result = re().mk_inter(a, b);
|
||||
break;
|
||||
case OP_RE_UNION:
|
||||
if (BR_FAILED == mk_re_union(a, b, result))
|
||||
result = re().mk_union(a, b);
|
||||
break;
|
||||
case OP_RE_CONCAT:
|
||||
if (BR_FAILED == mk_re_concat(a, b, result))
|
||||
result = re().mk_concat(a, b);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_op(decl_kind k, expr* a, expr* b) {
|
||||
expr_ref _a(a, m()), _b(b, m());
|
||||
expr_ref result(m_op_cache.find(k, a, b, nullptr), m());
|
||||
if (!result) {
|
||||
result = mk_der_op_rec(k, a, b);
|
||||
m_op_cache.insert(k, a, b, nullptr, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_compl(expr* r) {
|
||||
expr_ref result(m_op_cache.find(OP_RE_COMPLEMENT, r, nullptr, nullptr), m());
|
||||
if (!result) {
|
||||
expr* c = nullptr, * r1 = nullptr, * r2 = nullptr;
|
||||
if (m().is_ite(r, c, r1, r2)) {
|
||||
result = m().mk_ite(c, mk_der_compl(r1), mk_der_compl(r2));
|
||||
}
|
||||
else if (BR_FAILED == mk_re_complement(r, result))
|
||||
result = re().mk_complement(r);
|
||||
}
|
||||
m_op_cache.insert(OP_RE_COMPLEMENT, r, nullptr, nullptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
|
||||
expr_ref result(m());
|
||||
sort* seq_sort = nullptr, *ele_sort = nullptr;
|
||||
VERIFY(m_util.is_re(r, seq_sort));
|
||||
VERIFY(m_util.is_seq(seq_sort, ele_sort));
|
||||
SASSERT(ele_sort == m().get_sort(ele));
|
||||
expr *r1 = nullptr, *r2 = nullptr, *p = nullptr;
|
||||
expr* r1 = nullptr, *r2 = nullptr, *p = nullptr;
|
||||
auto mk_empty = [&]() { return expr_ref(re().mk_empty(m().get_sort(r)), m()); };
|
||||
unsigned lo = 0, hi = 0;
|
||||
if (re().is_concat(r, r1, r2)) {
|
||||
expr_ref is_n = is_nullable(r1);
|
||||
expr_ref dr1(re().mk_derivative(ele, r1), m());
|
||||
expr_ref dr2(re().mk_derivative(ele, r2), m());
|
||||
result = re().mk_concat(dr1, r2);
|
||||
expr_ref dr1 = mk_derivative(ele, r1);
|
||||
result = mk_der_concat(dr1, r2);
|
||||
if (m().is_false(is_n)) {
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
else if (m().is_true(is_n)) {
|
||||
result = re().mk_union(result, dr2);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
else {
|
||||
result = m().mk_ite(is_n, re().mk_union(result, dr2), result);
|
||||
return BR_REWRITE3;
|
||||
return result;
|
||||
}
|
||||
expr_ref dr2 = mk_derivative(ele, r2);
|
||||
is_n = re_predicate(is_n, seq_sort);
|
||||
return mk_der_union(result, mk_der_concat(is_n, dr2));
|
||||
}
|
||||
else if (re().is_star(r, r1)) {
|
||||
result = re().mk_concat(re().mk_derivative(ele, r1), r);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_concat(mk_derivative(ele, r1), r);
|
||||
}
|
||||
else if (re().is_plus(r, r1)) {
|
||||
result = re().mk_derivative(ele, re().mk_star(r1));
|
||||
return BR_REWRITE1;
|
||||
expr_ref star(re().mk_star(r1), m());
|
||||
return mk_derivative(ele, star);
|
||||
}
|
||||
else if (re().is_union(r, r1, r2)) {
|
||||
result = re().mk_union(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_union(mk_derivative(ele, r1), mk_derivative(ele, r2));
|
||||
}
|
||||
else if (re().is_intersection(r, r1, r2)) {
|
||||
result = re().mk_inter(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_inter(mk_derivative(ele, r1), mk_derivative(ele, r2));
|
||||
}
|
||||
else if (re().is_diff(r, r1, r2)) {
|
||||
result = re().mk_diff(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_inter(mk_derivative(ele, r1), mk_der_compl(mk_derivative(ele, r2)));
|
||||
}
|
||||
else if (m().is_ite(r, p, r1, r2)) {
|
||||
result = m().mk_ite(
|
||||
p,
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
// there is no BDD normalization here
|
||||
result = m().mk_ite(p, mk_derivative(ele, r1), mk_derivative(ele, r2));
|
||||
return result;
|
||||
}
|
||||
else if (re().is_opt(r, r1)) {
|
||||
result = re().mk_derivative(ele, r1);
|
||||
return BR_REWRITE1;
|
||||
return mk_derivative(ele, r1);
|
||||
}
|
||||
else if (re().is_complement(r, r1)) {
|
||||
result = re().mk_complement(re().mk_derivative(ele, r1));
|
||||
return BR_REWRITE2;
|
||||
return mk_der_compl(mk_derivative(ele, r1));
|
||||
}
|
||||
else if (re().is_loop(r, r1, lo)) {
|
||||
if (lo > 0) {
|
||||
lo--;
|
||||
}
|
||||
result = re().mk_concat(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_loop(r1, lo)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_concat(mk_derivative(ele, r1), re().mk_loop(r1, lo));
|
||||
}
|
||||
else if (re().is_loop(r, r1, lo, hi)) {
|
||||
if (hi == 0) {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return mk_empty();
|
||||
}
|
||||
hi--;
|
||||
if (lo > 0) {
|
||||
lo--;
|
||||
}
|
||||
result = re().mk_concat(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_loop(r1, lo, hi)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_concat(mk_derivative(ele, r1), re().mk_loop(r1, lo, hi));
|
||||
}
|
||||
else if (re().is_full_seq(r) ||
|
||||
re().is_empty(r)) {
|
||||
result = r;
|
||||
return BR_DONE;
|
||||
return expr_ref(r, m());
|
||||
}
|
||||
else if (re().is_to_re(r, r1)) {
|
||||
// r1 is a string here (not a regexp)
|
||||
expr_ref hd(m()), tl(m());
|
||||
if (get_head_tail(r1, hd, tl)) {
|
||||
// head must be equal; if so, derivative is tail
|
||||
result = re_and(m().mk_eq(ele, hd),re().mk_to_re(tl));
|
||||
return BR_REWRITE2;
|
||||
return re_and(m().mk_eq(ele, hd), re().mk_to_re(tl));
|
||||
}
|
||||
else if (str().is_empty(r1)) {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return mk_empty();
|
||||
}
|
||||
else {
|
||||
return BR_FAILED;
|
||||
return expr_ref(re().mk_derivative(ele, r), m());
|
||||
}
|
||||
}
|
||||
else if (re().is_reverse(r, r1) && re().is_to_re(r1, r2)) {
|
||||
// Reverses are rewritten so that the only derivative case is
|
||||
// derivative of a reverse of a string. (All other cases stuck)
|
||||
// This is analagous to the previous is_to_re case.
|
||||
expr_ref hd(m()), tl(m());
|
||||
if (get_head_tail_reversed(r2, hd, tl)) {
|
||||
return re_and(m().mk_eq(ele, tl), re().mk_reverse(re().mk_to_re(hd)));
|
||||
}
|
||||
else if (str().is_empty(r2)) {
|
||||
return mk_empty();
|
||||
}
|
||||
else {
|
||||
return expr_ref(re().mk_derivative(ele, r), m());
|
||||
}
|
||||
}
|
||||
else if (re().is_range(r, r1, r2)) {
|
||||
|
@ -2410,220 +2540,39 @@ br_status seq_rewriter::mk_re_derivative(expr* ele, expr* r, expr_ref& result) {
|
|||
if (s1.length() == 1 && s2.length() == 1) {
|
||||
r1 = m_util.mk_char(s1[0]);
|
||||
r2 = m_util.mk_char(s2[0]);
|
||||
result = m().mk_and(m_util.mk_le(r1, ele), m_util.mk_le(ele, r2));
|
||||
result = re_predicate(result, seq_sort);
|
||||
return BR_REWRITE3;
|
||||
return mk_der_inter(re_predicate(m_util.mk_le(r1, ele), seq_sort),
|
||||
re_predicate(m_util.mk_le(ele, r2), seq_sort));
|
||||
}
|
||||
else {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return mk_empty();
|
||||
}
|
||||
}
|
||||
expr* e1 = nullptr, *e2 = nullptr;
|
||||
if (str().is_unit(r1, e1) && str().is_unit(r2, e2)) {
|
||||
result = m().mk_and(m_util.mk_le(e1, ele), m_util.mk_le(ele, e2));
|
||||
result = re_predicate(result, seq_sort);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_inter(re_predicate(m_util.mk_le(e1, ele), seq_sort),
|
||||
re_predicate(m_util.mk_le(ele, e2), seq_sort));
|
||||
}
|
||||
}
|
||||
else if (re().is_full_char(r)) {
|
||||
result = re().mk_to_re(str().mk_empty(seq_sort));
|
||||
return BR_DONE;
|
||||
return expr_ref(re().mk_to_re(str().mk_empty(seq_sort)), m());
|
||||
}
|
||||
else if (re().is_of_pred(r, p)) {
|
||||
array_util array(m());
|
||||
expr* args[2] = { p, ele };
|
||||
result = array.mk_select(2, args);
|
||||
result = re_predicate(result, seq_sort);
|
||||
return BR_REWRITE2;
|
||||
return re_predicate(result, seq_sort);
|
||||
}
|
||||
// stuck cases: re().is_derivative, variable, ...
|
||||
// and re().is_reverse
|
||||
return BR_FAILED;
|
||||
// and re().is_reverse if the reverse is not applied to a string
|
||||
return expr_ref(re().mk_derivative(ele, r), m());
|
||||
}
|
||||
|
||||
/*
|
||||
Combine two if-then-else expressions in BDD form.
|
||||
Lift all ite expressions to the top level, safely
|
||||
throttled to not blowup the size of the expression.
|
||||
|
||||
Definition of BDD form:
|
||||
if-then-elses are pushed outwards
|
||||
and sorted by condition ID (cond->get_id()), from largest on
|
||||
the outside to smallest on the inside.
|
||||
Duplicate nested conditions are eliminated.
|
||||
|
||||
Preconditions:
|
||||
- EITHER k is a binary op code on REs (re.union, re.inter, etc.)
|
||||
and cond is nullptr,
|
||||
OR k is if-then-else (OP.ITE) and cond is the condition.
|
||||
- a and b are in BDD form.
|
||||
|
||||
Postcondition: result is in BDD form.
|
||||
if-then-elses are pushed outwards
|
||||
and sorted by condition ID (cond->get_id()), from largest on
|
||||
the outside to smallest on the inside.
|
||||
|
||||
Uses op cache (memoization) to avoid duplicating work for the same
|
||||
pair of pointers.
|
||||
*/
|
||||
expr_ref seq_rewriter::combine_ites(decl_kind k, expr* a, expr* b, expr* cond) {
|
||||
std::cout << "c";
|
||||
expr_ref result(m_op_cache.find(k, a, b, cond), m());
|
||||
if (result) {
|
||||
std::cout << "(h) ";
|
||||
return result;
|
||||
}
|
||||
std::cout << "(m) ";
|
||||
std::cout << std::endl << "combine_ites: "
|
||||
<< k << ", "
|
||||
<< expr_ref(a, m()) << ", "
|
||||
<< expr_ref(b, m()) << ", "
|
||||
<< expr_ref(cond, m()) << std::endl;
|
||||
SASSERT((k == OP_ITE) == (cond != nullptr));
|
||||
expr *acond = nullptr, *a1 = nullptr, *a2 = nullptr,
|
||||
*bcond = nullptr, *b1 = nullptr, *b2 = nullptr;
|
||||
expr_ref result1(m()), result2(m());
|
||||
if (k == OP_ITE) {
|
||||
if (m().is_ite(a, acond, a1, a2) &&
|
||||
cond->get_id() < acond->get_id()) {
|
||||
std::cout << " case 1a" << std::endl;
|
||||
// Push ITE inwards on first arg
|
||||
result1 = combine_ites(k, a1, b, cond);
|
||||
result2 = combine_ites(k, a2, b, cond);
|
||||
result = combine_ites(k, result1, result2, acond);
|
||||
}
|
||||
else if (m().is_ite(a, acond, a1, a2) &&
|
||||
cond == acond) {
|
||||
std::cout << " case 1b" << std::endl;
|
||||
// Collapse ITE on first arg
|
||||
result = combine_ites(k, a1, b, cond);
|
||||
}
|
||||
else if (m().is_ite(b, bcond, b1, b2) &&
|
||||
cond->get_id() < bcond->get_id()) {
|
||||
// Push ITE inwards on second arg
|
||||
std::cout << " case 1c" << std::endl;
|
||||
result1 = combine_ites(k, a, b1, cond);
|
||||
result2 = combine_ites(k, a, b2, cond);
|
||||
result = combine_ites(k, result1, result2, bcond);
|
||||
}
|
||||
else if (m().is_ite(b, bcond, b1, b2) &&
|
||||
cond == bcond) {
|
||||
std::cout << " case 1d" << std::endl;
|
||||
// Collapse ITE on second arg
|
||||
result = combine_ites(k, a, b2, cond);
|
||||
}
|
||||
else {
|
||||
// Apply ITE -- no simplification required
|
||||
std::cout << " case 1e" << std::endl;
|
||||
result = m().mk_ite(cond, a, b);
|
||||
}
|
||||
}
|
||||
else if (m().is_ite(a, acond, a1, a2)) {
|
||||
std::cout << " case 2" << std::endl;
|
||||
// Push binary op inwards on first arg
|
||||
result1 = combine_ites(k, a1, b, nullptr);
|
||||
result2 = combine_ites(k, a2, b, nullptr);
|
||||
result = combine_ites(OP_ITE, result1, result2, acond);
|
||||
}
|
||||
else if (m().is_ite(b, bcond, b1, b2)) {
|
||||
std::cout << " case 3" << std::endl;
|
||||
// Push binary op inwards on second arg
|
||||
result1 = combine_ites(k, a, b1, nullptr);
|
||||
result2 = combine_ites(k, a, b2, nullptr);
|
||||
result = combine_ites(OP_ITE, result1, result2, bcond);
|
||||
}
|
||||
else {
|
||||
std::cout << " case 4" << std::endl;
|
||||
// Apply binary op (a and b are free of ITE)
|
||||
result = m().mk_app(get_fid(), k, a, b);
|
||||
}
|
||||
// Save result before returning
|
||||
m_op_cache.insert(k, a, b, cond, result);
|
||||
std::cout << "combine result: " << result << std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Lift if-then-else expressions to the top level, enforcing a BDD form.
|
||||
|
||||
Postcondition: result is in BDD form.
|
||||
- Alternatively, if lift_over_union and/or lift_over_inter is false,
|
||||
then result is a disjunction and/or conjunciton of expressions in
|
||||
BDD form. (Even in this case, ITE is still lifted at lower levels,
|
||||
just not at the top level.)
|
||||
- Note that the result may not be fully simplified (particularly the
|
||||
nested expressions inside if-then-else). Simplification should be
|
||||
called afterwards.
|
||||
|
||||
Cost: Causes potential blowup in the size of an expression (when
|
||||
expanded out), but keeps the representation compact (subexpressions
|
||||
are shared).
|
||||
|
||||
Used by: the regex solver in seq_regex.cpp when dealing with
|
||||
derivatives of a regex by a symbolic character. Enables efficient
|
||||
representation in unfolding string in regex constraints.
|
||||
*/
|
||||
expr_ref seq_rewriter::lift_ites(expr* r, bool lift_over_union, bool lift_over_inter) {
|
||||
std::cout << "l ";
|
||||
decl_kind k = to_app(r)->get_decl_kind();
|
||||
family_id fid = get_fid();
|
||||
expr *r1 = nullptr, *r2 = nullptr, *cond = nullptr, *ele = nullptr;
|
||||
unsigned lo = 0, hi = 0;
|
||||
expr_ref result(m()), result1(m()), result2(m());
|
||||
if ((re().is_union(r, r1, r2) && !lift_over_union) ||
|
||||
(re().is_intersection(r, r1, r2) && !lift_over_inter)) {
|
||||
// Preserve unions and/or intersections
|
||||
result1 = lift_ites(r1, lift_over_union, lift_over_inter);
|
||||
result2 = lift_ites(r2, lift_over_union, lift_over_inter);
|
||||
result = m().mk_app(fid, k, r1, r2);
|
||||
}
|
||||
else if (m().is_ite(r, cond, r1, r2) ||
|
||||
re().is_concat(r, r1, r2) ||
|
||||
re().is_union(r, r1, r2) ||
|
||||
re().is_intersection(r, r1, r2) ||
|
||||
re().is_diff(r, r1, r2)) {
|
||||
// Use combine_ites on the subresults
|
||||
// Stop preserving unions and intersections
|
||||
result1 = lift_ites(r1, true, true);
|
||||
result2 = lift_ites(r2, true, true);
|
||||
result = combine_ites(k, r1, r2, cond);
|
||||
}
|
||||
else if (re().is_star(r, r1) ||
|
||||
re().is_plus(r, r1) ||
|
||||
re().is_opt(r, r1) ||
|
||||
re().is_complement(r, r1) ||
|
||||
re().is_reverse(r, r1)) {
|
||||
// Stop preserving unions and intersections
|
||||
result1 = lift_ites(r1, true, true);
|
||||
result = m().mk_app(fid, k, r1);
|
||||
}
|
||||
else if (re().is_derivative(r, ele, r1)) {
|
||||
result1 = lift_ites(r1, true, true);
|
||||
result = m().mk_app(fid, k, ele, r1);
|
||||
}
|
||||
else if (re().is_loop(r, r1, lo)) {
|
||||
result1 = lift_ites(r1, true, true);
|
||||
result = re().mk_loop(result1, lo);
|
||||
}
|
||||
else if (re().is_loop(r, r1, lo, hi)) {
|
||||
result1 = lift_ites(r1, true, true);
|
||||
result = re().mk_loop(result1, lo, hi);
|
||||
}
|
||||
else {
|
||||
// is_full_seq, is_empty, is_to_re, is_range, is_full_char, is_of_pred
|
||||
result = r;
|
||||
}
|
||||
std::cout << std::endl << "lift of: " << expr_ref(r, m()) << std::endl;
|
||||
std::cout << " = " << result << std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Lift all ite expressions to the top level, but
|
||||
a different "safe" version which is throttled to not
|
||||
blowup the size of the expression.
|
||||
|
||||
Note: this function does not ensure the same BDD form that lift_ites
|
||||
ensures.
|
||||
Note: this function does not ensure the same BDD form that is
|
||||
used in the normal form for derivatives in mk_re_derivative.
|
||||
*/
|
||||
br_status seq_rewriter::lift_ites_throttled(func_decl* f, unsigned n, expr* const* args, expr_ref& result) {
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
|
@ -2644,51 +2593,6 @@ br_status seq_rewriter::lift_ites_throttled(func_decl* f, unsigned n, expr* cons
|
|||
return BR_FAILED;
|
||||
}
|
||||
|
||||
// /*
|
||||
// Rewrite rules for ITEs of regexes.
|
||||
// ite(not c, r1, r2) -> ite(c, r2, r1)
|
||||
// ite(c, ite(c, r1, r2), r3)) -> ite(c, r1, r3)
|
||||
// ite(c, r1, ite(c, r2, r3)) -> ite(c, r1, r3)
|
||||
// ite(c1, ite(c2, r1, r2), r3) where id of c1 < id of c2 ->
|
||||
// ite(c2, ite(c1, r1, r3), ite(c1, r2, r3))
|
||||
// ite(c1, r1, ite(c2, r2, r3)) where id of c1 < id of c2 ->
|
||||
// ite(c2, ite(c1, r1, r2), ite(c1, r1, r3))
|
||||
// */
|
||||
// br_status seq_rewriter::rewrite_re_ite(expr* cond, expr* r1, expr* r2, expr_ref& result) {
|
||||
// VERIFY(m_util.is_re(r1));
|
||||
// VERIFY(m_util.is_re(r2));
|
||||
// expr *c = nullptr, *ra = nullptr, *rb = nullptr;
|
||||
// if (m().is_not(cond, c)) {
|
||||
// result = m().mk_ite(c, r2, r1);
|
||||
// return BR_REWRITE1;
|
||||
// }
|
||||
// if (m().is_ite(r1, c, ra, rb)) {
|
||||
// if (m().are_equal(c, cond)) {
|
||||
// result = m().mk_ite(cond, ra, r2);
|
||||
// return BR_REWRITE1;
|
||||
// }
|
||||
// if (cond->get_id() < c->get_id()) {
|
||||
// expr *result1 = m().mk_ite(cond, ra, r2);
|
||||
// expr *result2 = m().mk_ite(cond, rb, r2);
|
||||
// result = m().mk_ite(c, result1, result2);
|
||||
// return BR_REWRITE2;
|
||||
// }
|
||||
// }
|
||||
// if (m().is_ite(r2, c, ra, rb)) {
|
||||
// if (m().are_equal(c, cond)) {
|
||||
// result = m().mk_ite(cond, r1, rb);
|
||||
// return BR_REWRITE1;
|
||||
// }
|
||||
// if (cond->get_id() < c->get_id()) {
|
||||
// expr *result1 = m().mk_ite(cond, r1, ra);
|
||||
// expr* result2 = m().mk_ite(cond, r1, rb);
|
||||
// result = m().mk_ite(c, result1, result2);
|
||||
// return BR_REWRITE2;
|
||||
// }
|
||||
// }
|
||||
// return BR_DONE;
|
||||
// }
|
||||
|
||||
/*
|
||||
* pattern match against all ++ "abc" ++ all ++ "def" ++ all regexes.
|
||||
*/
|
||||
|
@ -2885,7 +2789,6 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (get_re_head_tail(b, hd, tl)) {
|
||||
SASSERT(re().min_length(hd) == re().max_length(hd));
|
||||
expr_ref len_hd(m_autil.mk_int(re().min_length(hd)), m());
|
||||
|
@ -2906,7 +2809,6 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
re().mk_in_re(str().mk_substr(a, len_hd, len_tl), tl));
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
#endif
|
||||
if (false && rewrite_contains_pattern(a, b, result))
|
||||
return BR_REWRITE_FULL;
|
||||
|
||||
|
@ -2998,6 +2900,50 @@ br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
bool seq_rewriter::are_complements(expr* r1, expr* r2) const {
|
||||
expr* r = nullptr;
|
||||
if (re().is_complement(r1, r) && r == r2)
|
||||
return true;
|
||||
if (re().is_complement(r2, r) && r == r1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* basic subset checker.
|
||||
*/
|
||||
bool seq_rewriter::is_subset(expr* r1, expr* r2) const {
|
||||
// return false;
|
||||
expr* ra1 = nullptr, *ra2 = nullptr, *ra3 = nullptr;
|
||||
expr* rb1 = nullptr, *rb2 = nullptr, *rb3 = nullptr;
|
||||
if (re().is_complement(r1, ra1) &&
|
||||
re().is_complement(r2, rb1)) {
|
||||
return is_subset(rb1, ra1);
|
||||
}
|
||||
auto is_concat = [&](expr* r, expr*& a, expr*& b, expr*& c) {
|
||||
return re().is_concat(r, a, b) && re().is_concat(b, b, c);
|
||||
};
|
||||
while (true) {
|
||||
if (r1 == r2)
|
||||
return true;
|
||||
if (re().is_full_seq(r2))
|
||||
return true;
|
||||
if (is_concat(r1, ra1, ra2, ra3) &&
|
||||
is_concat(r2, rb1, rb2, rb3) && ra1 == rb1 && ra2 == rb2) {
|
||||
r1 = ra3;
|
||||
r2 = rb3;
|
||||
continue;
|
||||
}
|
||||
if (re().is_concat(r1, ra1, ra2) &&
|
||||
re().is_concat(r2, rb1, rb2) && re().is_full_seq(rb1)) {
|
||||
r1 = ra2;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
(a + a) = a
|
||||
(a + eps) = a
|
||||
|
@ -3032,18 +2978,66 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
|
|||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
auto mk_full = [&]() { return re().mk_full_seq(m().get_sort(a)); };
|
||||
if (are_complements(a, b)) {
|
||||
result = mk_full();
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
expr* a1 = nullptr, *a2 = nullptr;
|
||||
expr* b1 = nullptr, *b2 = nullptr;
|
||||
// ensure union is right-associative
|
||||
// and swap-sort entries
|
||||
if (re().is_union(a, a1, a2)) {
|
||||
result = re().mk_union(a1, re().mk_union(a2, b));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
auto get_id = [&](expr* e) { re().is_complement(e, e); return e->get_id(); };
|
||||
if (re().is_union(b, b1, b2)) {
|
||||
if (is_subset(a, b1)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_subset(b1, a)) {
|
||||
result = re().mk_union(a, b2);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (are_complements(a, b1)) {
|
||||
result = mk_full();
|
||||
return BR_DONE;
|
||||
}
|
||||
if (get_id(a) > get_id(b1)) {
|
||||
result = re().mk_union(b1, re().mk_union(a, b2));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (get_id(a) > get_id(b)) {
|
||||
result = re().mk_union(b, a);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_subset(a, b)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_subset(b, a)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
comp(intersect e1 e2) -> union comp(e1) comp(e2)
|
||||
comp(union e1 e2) -> intersect comp(e1) comp(e2)
|
||||
comp(none) = all
|
||||
comp(all) = none
|
||||
comp(none) -> all
|
||||
comp(all) -> none
|
||||
comp(comp(e1)) -> e1
|
||||
comp(ite p e1 e2) -> ite p comp(e1) comp(e2)
|
||||
*/
|
||||
br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) {
|
||||
expr* e1, *e2;
|
||||
expr *cond = nullptr, *e1 = nullptr, *e2 = nullptr;
|
||||
if (re().is_intersection(a, e1, e2)) {
|
||||
result = re().mk_union(re().mk_complement(e1), re().mk_complement(e2));
|
||||
return BR_REWRITE2;
|
||||
|
@ -3060,10 +3054,13 @@ br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) {
|
|||
result = re().mk_empty(m().get_sort(a));
|
||||
return BR_DONE;
|
||||
}
|
||||
expr *a1 = nullptr, *a2 = nullptr, *cond = nullptr;
|
||||
if (m().is_ite(a, cond, a1, a2)) {
|
||||
result = m().mk_ite(cond, re().mk_complement(a1),
|
||||
re().mk_complement(a2));
|
||||
if (re().is_complement(a, e1)) {
|
||||
result = e1;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m().is_ite(a, cond, e1, e2)) {
|
||||
result = m().mk_ite(cond, re().mk_complement(e1),
|
||||
re().mk_complement(e2));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
return BR_FAILED;
|
||||
|
@ -3101,12 +3098,53 @@ br_status seq_rewriter::mk_re_inter(expr* a, expr* b, expr_ref& result) {
|
|||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
expr* ac = nullptr, *bc = nullptr;
|
||||
if ((re().is_complement(a, ac) && ac == b) ||
|
||||
(re().is_complement(b, bc) && bc == a)) {
|
||||
result = re().mk_empty(m().get_sort(a));
|
||||
auto mk_empty = [&]() { return re().mk_empty(m().get_sort(a)); };
|
||||
if (are_complements(a, b)) {
|
||||
result = mk_empty();
|
||||
return BR_DONE;
|
||||
}
|
||||
expr* a1 = nullptr, *a2 = nullptr;
|
||||
expr* b1 = nullptr, *b2 = nullptr;
|
||||
|
||||
// ensure intersection is right-associative
|
||||
// and swap-sort entries
|
||||
if (re().is_intersection(a, a1, a2)) {
|
||||
result = re().mk_inter(a1, re().mk_inter(a2, b));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
auto get_id = [&](expr* e) { re().is_complement(e, e); return e->get_id(); };
|
||||
if (re().is_intersection(b, b1, b2)) {
|
||||
if (is_subset(b1, a)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_subset(a, b1)) {
|
||||
result = re().mk_inter(a, b2);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (are_complements(a, b1)) {
|
||||
result = mk_empty();
|
||||
return BR_DONE;
|
||||
}
|
||||
if (get_id(a) > get_id(b1)) {
|
||||
result = re().mk_inter(b1, re().mk_inter(a, b2));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (get_id(a) > get_id(b)) {
|
||||
result = re().mk_inter(b, a);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_subset(a, b)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_subset(b, a)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
if (re().is_to_re(b))
|
||||
std::swap(a, b);
|
||||
expr* s = nullptr;
|
||||
|
@ -3388,7 +3426,6 @@ void seq_rewriter::elim_condition(expr* elem, expr_ref& cond) {
|
|||
else
|
||||
intersect(0, ch-1, ranges);
|
||||
}
|
||||
// TBD: case for negation of range (not (and (<= lo e) (<= e hi)))
|
||||
else {
|
||||
all_ranges = false;
|
||||
break;
|
||||
|
@ -3429,124 +3466,6 @@ void seq_rewriter::elim_condition(expr* elem, expr_ref& cond) {
|
|||
}
|
||||
}
|
||||
|
||||
void seq_rewriter::get_cofactors(expr* r, expr_ref_vector& conds, expr_ref_pair_vector& result) {
|
||||
expr_ref cond(m()), th(m()), el(m());
|
||||
if (has_cofactor(r, cond, th, el)) {
|
||||
conds.push_back(cond);
|
||||
get_cofactors(th, conds, result);
|
||||
conds.pop_back();
|
||||
conds.push_back(mk_not(m(), cond));
|
||||
get_cofactors(el, conds, result);
|
||||
conds.pop_back();
|
||||
}
|
||||
else {
|
||||
cond = mk_and(conds);
|
||||
result.push_back(cond, r);
|
||||
}
|
||||
}
|
||||
|
||||
bool seq_rewriter::has_cofactor(expr* r, expr_ref& cond, expr_ref& th, expr_ref& el) {
|
||||
if (m().is_ite(r)) {
|
||||
cond = to_app(r)->get_arg(0);
|
||||
th = to_app(r)->get_arg(1);
|
||||
el = to_app(r)->get_arg(2);
|
||||
return true;
|
||||
}
|
||||
expr_ref_vector trail(m()), args_th(m()), args_el(m());
|
||||
expr* c = nullptr, *tt = nullptr, *ee = nullptr;
|
||||
cond = nullptr;
|
||||
obj_map<expr,expr*> cache_th, cache_el;
|
||||
expr_mark no_cofactor, visited;
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(r);
|
||||
while (!todo.empty()) {
|
||||
expr* e = todo.back();
|
||||
if (visited.is_marked(e) || !is_app(e)) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
app* a = to_app(e);
|
||||
if (m().is_ite(e, c, tt, ee)) {
|
||||
if (!cond) {
|
||||
cond = c;
|
||||
cache_th.insert(a, tt);
|
||||
cache_el.insert(a, ee);
|
||||
}
|
||||
else if (cond == c) {
|
||||
cache_th.insert(a, tt);
|
||||
cache_el.insert(a, ee);
|
||||
}
|
||||
else {
|
||||
no_cofactor.mark(a);
|
||||
}
|
||||
visited.mark(e, true);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a->get_family_id() != u().get_family_id()) {
|
||||
visited.mark(e, true);
|
||||
no_cofactor.mark(e, true);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
switch (a->get_decl_kind()) {
|
||||
case OP_RE_CONCAT:
|
||||
case OP_RE_UNION:
|
||||
case OP_RE_INTERSECT:
|
||||
case OP_RE_COMPLEMENT:
|
||||
break;
|
||||
case OP_RE_STAR:
|
||||
case OP_RE_LOOP:
|
||||
default:
|
||||
visited.mark(e, true);
|
||||
no_cofactor.mark(e, true);
|
||||
continue;
|
||||
}
|
||||
args_th.reset();
|
||||
args_el.reset();
|
||||
bool has_cof = false;
|
||||
for (expr* arg : *a) {
|
||||
if (no_cofactor.is_marked(arg)) {
|
||||
args_th.push_back(arg);
|
||||
args_el.push_back(arg);
|
||||
}
|
||||
else if (cache_th.contains(arg)) {
|
||||
args_th.push_back(cache_th[arg]);
|
||||
args_el.push_back(cache_el[arg]);
|
||||
has_cof = true;
|
||||
}
|
||||
else {
|
||||
todo.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (args_th.size() == a->get_num_args()) {
|
||||
if (has_cof) {
|
||||
th = mk_app(a->get_decl(), args_th);
|
||||
el = mk_app(a->get_decl(), args_el);
|
||||
trail.push_back(th);
|
||||
trail.push_back(el);
|
||||
cache_th.insert(a, th);
|
||||
cache_el.insert(a, el);
|
||||
}
|
||||
else {
|
||||
no_cofactor.mark(a, true);
|
||||
}
|
||||
visited.mark(e, true);
|
||||
todo.pop_back();
|
||||
}
|
||||
}
|
||||
SASSERT(cond == !no_cofactor.is_marked(r));
|
||||
if (cond) {
|
||||
th = cache_th[r];
|
||||
el = cache_el[r];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
br_status seq_rewriter::reduce_re_is_empty(expr* r, expr_ref& result) {
|
||||
expr* r1, *r2, *r3, *r4;
|
||||
zstring s1, s2;
|
||||
|
|
|
@ -182,6 +182,18 @@ class seq_rewriter {
|
|||
|
||||
expr_ref mk_seq_concat(expr* a, expr* b);
|
||||
|
||||
expr_ref mk_der_op(decl_kind k, expr* a, expr* b);
|
||||
expr_ref mk_der_op_rec(decl_kind k, expr* a, expr* b);
|
||||
expr_ref mk_der_concat(expr* a, expr* b);
|
||||
expr_ref mk_der_union(expr* a, expr* b);
|
||||
expr_ref mk_der_inter(expr* a, expr* b);
|
||||
expr_ref mk_der_compl(expr* a);
|
||||
expr_ref mk_derivative(expr* ele, expr* r);
|
||||
expr_ref mk_derivative_rec(expr* ele, expr* r);
|
||||
|
||||
bool are_complements(expr* r1, expr* r2) const;
|
||||
bool is_subset(expr* r1, expr* r2) const;
|
||||
|
||||
br_status mk_seq_unit(expr* e, expr_ref& result);
|
||||
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_length(expr* a, expr_ref& result);
|
||||
|
@ -230,6 +242,7 @@ class seq_rewriter {
|
|||
bool rewrite_contains_pattern(expr* a, expr* b, expr_ref& result);
|
||||
|
||||
br_status mk_bool_app_helper(bool is_and, unsigned n, expr* const* args, expr_ref& result);
|
||||
br_status mk_eq_helper(expr* a, expr* b, expr_ref& result);
|
||||
|
||||
bool cannot_contain_prefix(expr* a, expr* b);
|
||||
bool cannot_contain_suffix(expr* a, expr* b);
|
||||
|
@ -265,15 +278,15 @@ class seq_rewriter {
|
|||
class seq_util::str& str() { return u().str; }
|
||||
class seq_util::str const& str() const { return u().str; }
|
||||
|
||||
void get_cofactors(expr* r, expr_ref_vector& conds, expr_ref_pair_vector& result);
|
||||
expr_ref is_nullable_rec(expr* r);
|
||||
void intersect(unsigned lo, unsigned hi, svector<std::pair<unsigned, unsigned>>& ranges);
|
||||
|
||||
expr_ref combine_ites(decl_kind k, expr* a, expr* b, expr* cond);
|
||||
br_status lift_ites_throttled(func_decl* f, unsigned n, expr* const* args, expr_ref& result);
|
||||
|
||||
public:
|
||||
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
m_util(m), m_autil(m), m_re2aut(m), m_op_cache(m), m_es(m), m_lhs(m), m_rhs(m), m_coalesce_chars(true) {
|
||||
m_util(m), m_autil(m), m_re2aut(m), m_op_cache(m), m_es(m),
|
||||
m_lhs(m), m_rhs(m), m_coalesce_chars(true) {
|
||||
}
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
family_id get_fid() const { return m_util.get_family_id(); }
|
||||
|
@ -314,23 +327,12 @@ public:
|
|||
|
||||
void add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_pair_vector& new_eqs);
|
||||
|
||||
// Memoized checking for acceptance of the empty string
|
||||
// Check for acceptance of the empty string
|
||||
expr_ref is_nullable(expr* r);
|
||||
expr_ref is_nullable_rec(expr* r);
|
||||
|
||||
// utilities for cofactors of if-then-else expressions
|
||||
bool has_cofactor(expr* r, expr_ref& cond, expr_ref& th, expr_ref& el);
|
||||
void get_cofactors(expr* r, expr_ref_pair_vector& result) {
|
||||
expr_ref_vector conds(m());
|
||||
get_cofactors(r, conds, result);
|
||||
}
|
||||
|
||||
// heuristic elimination of element from condition that comes form a derivative.
|
||||
// special case optimization for conjunctions of equalities, disequalities and ranges.
|
||||
void elim_condition(expr* elem, expr_ref& cond);
|
||||
|
||||
// if-then-else rewriting support (for REs)
|
||||
expr_ref lift_ites(expr* r, bool lift_over_union = true, bool lift_over_inter = true);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -203,7 +203,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
if (st != BR_FAILED)
|
||||
return st;
|
||||
}
|
||||
if ((k == OP_AND || k == OP_OR) && m_seq_rw.u().has_re()) {
|
||||
if ((k == OP_AND || k == OP_OR /*|| k == OP_EQ*/) && m_seq_rw.u().has_re()) {
|
||||
st = m_seq_rw.mk_bool_app(f, num, args, result);
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
|
|
|
@ -367,6 +367,7 @@ namespace opt {
|
|||
void context::fix_model(model_ref& mdl) {
|
||||
if (mdl && !m_model_fixed.contains(mdl.get())) {
|
||||
TRACE("opt", m_fm->display(tout << "fix-model\n");
|
||||
tout << *mdl << "\n";
|
||||
if (m_model_converter) m_model_converter->display(tout););
|
||||
(*m_fm)(mdl);
|
||||
apply(m_model_converter, mdl);
|
||||
|
@ -482,6 +483,7 @@ namespace opt {
|
|||
lbool context::execute_box() {
|
||||
if (m_box_index < m_box_models.size()) {
|
||||
m_model = m_box_models[m_box_index];
|
||||
CTRACE("opt", m_model, tout << *m_model << "\n";);
|
||||
++m_box_index;
|
||||
return l_true;
|
||||
}
|
||||
|
@ -505,12 +507,15 @@ namespace opt {
|
|||
m_box_models.push_back(m_model.get());
|
||||
}
|
||||
else {
|
||||
m_box_models.push_back(m_optsmt.get_model(j));
|
||||
model* mdl = m_optsmt.get_model(j);
|
||||
if (!mdl) mdl = m_model.get();
|
||||
m_box_models.push_back(mdl);
|
||||
++j;
|
||||
}
|
||||
}
|
||||
if (r == l_true && !m_box_models.empty()) {
|
||||
m_model = m_box_models[0];
|
||||
CTRACE("opt", m_model, tout << *m_model << "\n";);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -787,6 +792,7 @@ namespace opt {
|
|||
|
||||
void context::normalize(expr_ref_vector const& asms) {
|
||||
expr_ref_vector fmls(m);
|
||||
m_model_converter = nullptr;
|
||||
to_fmls(fmls);
|
||||
simplify_fmls(fmls, asms);
|
||||
from_fmls(fmls);
|
||||
|
@ -1248,7 +1254,7 @@ namespace opt {
|
|||
case O_MAXSMT: {
|
||||
maxsmt& ms = *m_maxsmts.find(obj.m_id);
|
||||
for (unsigned j = 0; j < obj.m_terms.size(); ++j) {
|
||||
ms.add(obj.m_terms[j].get(), obj.m_weights[j]);
|
||||
ms.add(obj.m_terms.get(j), obj.m_weights[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1468,6 +1474,7 @@ namespace opt {
|
|||
void context::clear_state() {
|
||||
m_pareto = nullptr;
|
||||
m_box_index = UINT_MAX;
|
||||
m_box_models.reset();
|
||||
m_model.reset();
|
||||
m_model_fixed.reset();
|
||||
m_core.reset();
|
||||
|
|
|
@ -469,6 +469,7 @@ namespace opt {
|
|||
return l_true;
|
||||
}
|
||||
|
||||
|
||||
void optsmt::setup(opt_solver& solver) {
|
||||
m_s = &solver;
|
||||
solver.reset_objectives();
|
||||
|
@ -577,7 +578,9 @@ namespace opt {
|
|||
m_upper.reset();
|
||||
m_objs.reset();
|
||||
m_vars.reset();
|
||||
m_model.reset();
|
||||
m_model.reset();
|
||||
m_best_model = nullptr;
|
||||
m_models.reset();
|
||||
m_lower_fmls.reset();
|
||||
m_s = nullptr;
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ namespace sat {
|
|||
m_stats.m_num_conflicts++;
|
||||
TRACE("ba", display(tout, c, true); );
|
||||
if (!validate_conflict(c)) {
|
||||
display(std::cout, c, true);
|
||||
IF_VERBOSE(0, display(verbose_stream(), c, true));
|
||||
UNREACHABLE();
|
||||
}
|
||||
SASSERT(validate_conflict(c));
|
||||
|
@ -2941,6 +2941,8 @@ namespace sat {
|
|||
|
||||
void ba_solver::pre_simplify() {
|
||||
VERIFY(s().at_base_lvl());
|
||||
if (s().inconsistent())
|
||||
return;
|
||||
m_constraint_removed = false;
|
||||
xor_finder xf(s());
|
||||
for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) pre_simplify(xf, *m_constraints[i]);
|
||||
|
@ -2983,6 +2985,8 @@ namespace sat {
|
|||
|
||||
void ba_solver::simplify() {
|
||||
if (!s().at_base_lvl()) s().pop_to_base_level();
|
||||
if (s().inconsistent())
|
||||
return;
|
||||
unsigned trail_sz, count = 0;
|
||||
do {
|
||||
trail_sz = s().init_trail_size();
|
||||
|
|
|
@ -118,11 +118,9 @@ namespace smt {
|
|||
if (coallesce_in_re(lit))
|
||||
return;
|
||||
|
||||
#if 1
|
||||
// Enable/disable to test effect
|
||||
if (is_string_equality(lit))
|
||||
return;
|
||||
#endif
|
||||
|
||||
//
|
||||
// TBD s in R => R != {}
|
||||
// non-emptiness enforcement could instead of here,
|
||||
|
@ -151,32 +149,6 @@ namespace smt {
|
|||
m_to_propagate.push_back(lit);
|
||||
}
|
||||
|
||||
// s in R[if(p,R1,R2)] & p => s in R[R1]
|
||||
// s in R[if(p,R1,R2)] & ~p => s in R[R2]
|
||||
|
||||
bool seq_regex::unfold_cofactors(expr_ref& r, literal_vector& conds) {
|
||||
expr_ref cond(m), tt(m), el(m);
|
||||
while (seq_rw().has_cofactor(r, cond, tt, el)) {
|
||||
rewrite(cond);
|
||||
literal lcond = th.mk_literal(cond);
|
||||
switch (ctx.get_assignment(lcond)) {
|
||||
case l_true:
|
||||
conds.push_back(~lcond);
|
||||
r = tt;
|
||||
break;
|
||||
case l_false:
|
||||
conds.push_back(lcond);
|
||||
r = el;
|
||||
break;
|
||||
case l_undef:
|
||||
ctx.mark_as_relevant(lcond);
|
||||
return false;
|
||||
}
|
||||
rewrite(r);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate the atom (accept s i r)
|
||||
*
|
||||
|
@ -184,6 +156,8 @@ namespace smt {
|
|||
*
|
||||
* (accept s i r[if(c,r1,r2)]) & c => (accept s i r[r1])
|
||||
* (accept s i r[if(c,r1,r2)]) & ~c => (accept s i r[r2])
|
||||
* (accept s i r) & nullable(r) => len(s) >= i
|
||||
* (accept s i r) & ~nullable(r) => len(s) >= i + 1
|
||||
* (accept s i r) & len(s) <= i => nullable(r)
|
||||
* (accept s i r) & len(s) > i => (accept s (+ i 1) D(nth(s,i), r))
|
||||
*/
|
||||
|
@ -195,53 +169,121 @@ namespace smt {
|
|||
expr* e = ctx.bool_var2expr(lit.var());
|
||||
unsigned idx = 0;
|
||||
VERIFY(sk().is_accept(e, s, i, idx, r));
|
||||
expr_ref is_nullable(m), d(r, m);
|
||||
|
||||
|
||||
TRACE("seq", tout << "propagate " << mk_pp(e, m) << "\n";);
|
||||
|
||||
std::cout << "P ";
|
||||
// << mk_pp(e, m) << std::endl;
|
||||
|
||||
if (re().is_empty(r)) {
|
||||
th.add_axiom(~lit);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (block_unfolding(lit, idx))
|
||||
return true;
|
||||
|
||||
propagate_nullable(lit, e, s, idx, r);
|
||||
|
||||
return propagate_derivative(lit, e, s, i, idx, r);
|
||||
}
|
||||
|
||||
/**
|
||||
Implement the two axioms as propagations:
|
||||
|
||||
(accept s i r) => len(s) >= i
|
||||
(accept s i r) & ~nullable(r) => len(s) >= i + 1
|
||||
*/
|
||||
|
||||
void seq_regex::propagate_nullable(literal lit, expr* e, expr* s, unsigned idx, expr* r) {
|
||||
expr_ref is_nullable = seq_rw().is_nullable(r);
|
||||
rewrite(is_nullable);
|
||||
literal len_s_ge_i = th.m_ax.mk_ge(th.mk_len(s), idx);
|
||||
if (m.is_true(is_nullable)) {
|
||||
th.propagate_lit(nullptr, 1,&lit, len_s_ge_i);
|
||||
}
|
||||
else if (m.is_false(is_nullable)) {
|
||||
th.propagate_lit(nullptr, 1, &lit, th.m_ax.mk_ge(th.mk_len(s), idx + 1));
|
||||
}
|
||||
else {
|
||||
literal len_s_le_i = th.m_ax.mk_le(th.mk_len(s), idx);
|
||||
switch (ctx.get_assignment(len_s_le_i)) {
|
||||
case l_undef:
|
||||
th.add_axiom(~lit, ~len_s_le_i, th.mk_literal(is_nullable));
|
||||
break;
|
||||
case l_true: {
|
||||
literal lits[2] = { lit, len_s_le_i };
|
||||
th.propagate_lit(nullptr, 2, lits, th.mk_literal(is_nullable));
|
||||
break;
|
||||
}
|
||||
case l_false:
|
||||
break;
|
||||
}
|
||||
th.propagate_lit(nullptr, 1, &lit, len_s_ge_i);
|
||||
}
|
||||
}
|
||||
|
||||
bool seq_regex::propagate_derivative(literal lit, expr* e, expr* s, expr* i, unsigned idx, expr* r) {
|
||||
// (accept s i R) & len(s) > i => (accept s (+ i 1) D(nth(s, i), R)) or conds
|
||||
expr_ref d(m);
|
||||
expr_ref head = th.mk_nth(s, i);
|
||||
|
||||
d = derivative_wrapper(m.mk_var(0, m.get_sort(head)), r);
|
||||
// timer tm;
|
||||
// std::cout << d->get_id() << " " << tm.get_seconds() << "\n";
|
||||
// if (tm.get_seconds() > 1)
|
||||
// std::cout << d << "\n";
|
||||
// std::cout.flush();
|
||||
literal_vector conds;
|
||||
conds.push_back(~lit);
|
||||
if (!unfold_cofactors(d, conds))
|
||||
return false;
|
||||
|
||||
if (re().is_empty(d)) {
|
||||
th.add_axiom(conds);
|
||||
return true;
|
||||
conds.push_back(th.m_ax.mk_le(th.mk_len(s), idx));
|
||||
expr* cond = nullptr, *tt = nullptr, *el = nullptr;
|
||||
var_subst subst(m);
|
||||
expr_ref_vector sub(m);
|
||||
sub.push_back(head);
|
||||
// s in R[if(p,R1,R2)] & p => s in R[R1]
|
||||
// s in R[if(p,R1,R2)] & ~p => s in R[R2]
|
||||
while (m.is_ite(d, cond, tt, el)) {
|
||||
literal lcond = th.mk_literal(subst(cond, sub));
|
||||
switch (ctx.get_assignment(lcond)) {
|
||||
case l_true:
|
||||
conds.push_back(~lcond);
|
||||
d = tt;
|
||||
break;
|
||||
case l_false:
|
||||
conds.push_back(lcond);
|
||||
d = el;
|
||||
break;
|
||||
case l_undef:
|
||||
#if 1
|
||||
ctx.mark_as_relevant(lcond);
|
||||
return false;
|
||||
#else
|
||||
if (re().is_empty(tt)) {
|
||||
literal_vector ensure_false(conds);
|
||||
ensure_false.push_back(~lcond);
|
||||
th.add_axiom(ensure_false);
|
||||
conds.push_back(lcond);
|
||||
d = el;
|
||||
}
|
||||
else if (re().is_empty(el)) {
|
||||
literal_vector ensure_true(conds);
|
||||
ensure_true.push_back(lcond);
|
||||
th.add_axiom(ensure_true);
|
||||
conds.push_back(~lcond);
|
||||
d = tt;
|
||||
}
|
||||
else {
|
||||
ctx.mark_as_relevant(lcond);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// s in R & len(s) <= i => nullable(R)
|
||||
literal len_s_le_i = th.m_ax.mk_le(th.mk_len(s), idx);
|
||||
switch (ctx.get_assignment(len_s_le_i)) {
|
||||
case l_undef:
|
||||
ctx.mark_as_relevant(len_s_le_i);
|
||||
return false;
|
||||
case l_true:
|
||||
is_nullable = seq_rw().is_nullable(d);
|
||||
rewrite(is_nullable);
|
||||
conds.push_back(~len_s_le_i);
|
||||
conds.push_back(th.mk_literal(is_nullable));
|
||||
th.add_axiom(conds);
|
||||
return true;
|
||||
case l_false:
|
||||
break;
|
||||
}
|
||||
|
||||
// (accept s i R) & len(s) > i => (accept s (+ i 1) D(nth(s, i), R)) or conds
|
||||
expr_ref head = th.mk_nth(s, i);
|
||||
d = derivative_wrapper(head, r);
|
||||
|
||||
literal acc_next = th.mk_literal(sk().mk_accept(s, a().mk_int(idx + 1), d));
|
||||
conds.push_back(len_s_le_i);
|
||||
conds.push_back(acc_next);
|
||||
th.add_axiom(conds);
|
||||
|
||||
// at this point there should be no free variables as the ites are at top-level.
|
||||
if (!re().is_empty(d))
|
||||
conds.push_back(th.mk_literal(sk().mk_accept(s, a().mk_int(idx + 1), d)));
|
||||
th.add_axiom(conds);
|
||||
TRACE("seq", tout << "unfold " << head << "\n" << mk_pp(r, m) << "\n";);
|
||||
return true;
|
||||
}
|
||||
|
@ -264,7 +306,6 @@ namespace smt {
|
|||
* within the same Regex.
|
||||
*/
|
||||
bool seq_regex::coallesce_in_re(literal lit) {
|
||||
// initially disable this
|
||||
return false;
|
||||
expr* s = nullptr, *r = nullptr;
|
||||
expr* e = ctx.bool_var2expr(lit.var());
|
||||
|
@ -273,10 +314,10 @@ namespace smt {
|
|||
literal_vector lits;
|
||||
for (unsigned i = 0; i < m_s_in_re.size(); ++i) {
|
||||
auto const& entry = m_s_in_re[i];
|
||||
enode* n1 = th.ensure_enode(entry.m_s);
|
||||
enode* n2 = th.ensure_enode(s);
|
||||
if (!entry.m_active)
|
||||
continue;
|
||||
enode* n1 = th.ensure_enode(entry.m_s);
|
||||
enode* n2 = th.ensure_enode(s);
|
||||
if (n1->get_root() != n2->get_root())
|
||||
continue;
|
||||
if (entry.m_re == regex)
|
||||
|
@ -284,7 +325,7 @@ namespace smt {
|
|||
|
||||
th.m_trail_stack.push(vector_value_trail<theory_seq, s_in_re, true>(m_s_in_re, i));
|
||||
m_s_in_re[i].m_active = false;
|
||||
IF_VERBOSE(11, verbose_stream() << "intersect " << regex << " " <<
|
||||
IF_VERBOSE(11, verbose_stream() << "Intersect " << regex << " " <<
|
||||
mk_pp(entry.m_re, m) << " " << mk_pp(s, m) << " " << mk_pp(entry.m_s, m) << "\n";);
|
||||
regex = re().mk_inter(entry.m_re, regex);
|
||||
rewrite(regex);
|
||||
|
@ -315,17 +356,14 @@ namespace smt {
|
|||
}
|
||||
|
||||
/*
|
||||
Memoized(TODO) wrapper around the regex symbolic derivative.
|
||||
Also ensures that the derivative is written in a normalized form
|
||||
Wrapper around the regex symbolic derivative from the rewriter.
|
||||
Ensures that the derivative is written in a normalized BDD form
|
||||
with optimizations for if-then-else expressions involving the head.
|
||||
*/
|
||||
expr_ref seq_regex::derivative_wrapper(expr* hd, expr* r) {
|
||||
std::cout << "D ";
|
||||
expr_ref result = expr_ref(re().mk_derivative(hd, r), m);
|
||||
rewrite(result);
|
||||
// don't lift over unions
|
||||
result = seq_rw().lift_ites(result); // false, true);
|
||||
rewrite(result);
|
||||
std::cout << std::endl << "Derivative result: " << result << std::endl;
|
||||
return result;
|
||||
}
|
||||
|
@ -378,7 +416,7 @@ namespace smt {
|
|||
if (null_lit != false_literal)
|
||||
lits.push_back(null_lit);
|
||||
expr_ref_pair_vector cofactors(m);
|
||||
seq_rw().get_cofactors(d, cofactors);
|
||||
get_cofactors(d, cofactors);
|
||||
for (auto const& p : cofactors) {
|
||||
if (is_member(p.second, u))
|
||||
continue;
|
||||
|
@ -395,6 +433,21 @@ namespace smt {
|
|||
th.add_axiom(lits);
|
||||
}
|
||||
|
||||
void seq_regex::get_cofactors(expr* r, expr_ref_vector& conds, expr_ref_pair_vector& result) {
|
||||
expr* cond = nullptr, *th = nullptr, *el = nullptr;
|
||||
if (m.is_ite(r, cond, th, el)) {
|
||||
conds.push_back(cond);
|
||||
get_cofactors(th, conds, result);
|
||||
conds.pop_back();
|
||||
conds.push_back(mk_not(m, cond));
|
||||
get_cofactors(el, conds, result);
|
||||
conds.pop_back();
|
||||
}
|
||||
else {
|
||||
cond = mk_and(conds);
|
||||
result.push_back(cond, r);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
is_empty(r, u) => ~is_nullable(r)
|
||||
|
@ -418,10 +471,7 @@ namespace smt {
|
|||
d = derivative_wrapper(hd, r);
|
||||
literal_vector lits;
|
||||
expr_ref_pair_vector cofactors(m);
|
||||
seq_rw().get_cofactors(d, cofactors);
|
||||
|
||||
// is_empty(r, u) => forall hd . cond => is_empty(r1, u union r)
|
||||
|
||||
get_cofactors(d, cofactors);
|
||||
for (auto const& p : cofactors) {
|
||||
if (is_member(p.second, u))
|
||||
continue;
|
||||
|
|
|
@ -59,18 +59,27 @@ namespace smt {
|
|||
|
||||
bool block_unfolding(literal lit, unsigned i);
|
||||
|
||||
void propagate_nullable(literal lit, expr* e, expr* s, unsigned idx, expr* r);
|
||||
|
||||
bool propagate_derivative(literal lit, expr* e, expr* s, expr* i, unsigned idx, expr* r);
|
||||
|
||||
expr_ref mk_first(expr* r);
|
||||
|
||||
expr_ref unroll_non_empty(expr* r, expr_mark& seen, unsigned depth);
|
||||
|
||||
bool unfold_cofactors(expr_ref& r, literal_vector& conds);
|
||||
|
||||
bool is_member(expr* r, expr* u);
|
||||
|
||||
expr_ref symmetric_diff(expr* r1, expr* r2);
|
||||
|
||||
expr_ref derivative_wrapper(expr* hd, expr* r);
|
||||
|
||||
void get_cofactors(expr* r, expr_ref_vector& conds, expr_ref_pair_vector& result);
|
||||
|
||||
void get_cofactors(expr* r, expr_ref_pair_vector& result) {
|
||||
expr_ref_vector conds(m);
|
||||
get_cofactors(r, conds, result);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
seq_regex(theory_seq& th);
|
||||
|
|
|
@ -436,7 +436,8 @@ namespace smt {
|
|||
|
||||
ctx.internalize(term->get_args(), term->get_num_args(), false);
|
||||
|
||||
enode * e = ctx.mk_enode(term, false, false, true);
|
||||
enode * e = (ctx.e_internalized(term)) ? ctx.get_enode(term) :
|
||||
ctx.mk_enode(term, false, false, true);
|
||||
|
||||
if (!is_attached_to_var(e)) {
|
||||
attach_new_th_var(e);
|
||||
|
@ -503,16 +504,14 @@ namespace smt {
|
|||
|
||||
fpa_util & fu = m_fpa_util;
|
||||
|
||||
expr_ref xe(m), ye(m);
|
||||
xe = e_x->get_owner();
|
||||
ye = e_y->get_owner();
|
||||
expr * xe = e_x->get_owner();
|
||||
expr * ye = e_y->get_owner();
|
||||
|
||||
if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye))
|
||||
return;
|
||||
|
||||
expr_ref xc(m), yc(m);
|
||||
xc = convert(xe);
|
||||
yc = convert(ye);
|
||||
expr_ref xc = convert(xe);
|
||||
expr_ref yc = convert(ye);
|
||||
|
||||
TRACE("t_fpa_detail", tout << "xc = " << mk_ismt2_pp(xc, m) << std::endl <<
|
||||
"yc = " << mk_ismt2_pp(yc, m) << std::endl;);
|
||||
|
@ -546,16 +545,14 @@ namespace smt {
|
|||
|
||||
fpa_util & fu = m_fpa_util;
|
||||
|
||||
expr_ref xe(m), ye(m);
|
||||
xe = e_x->get_owner();
|
||||
ye = e_y->get_owner();
|
||||
expr * xe = e_x->get_owner();
|
||||
expr * ye = e_y->get_owner();
|
||||
|
||||
if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye))
|
||||
return;
|
||||
|
||||
expr_ref xc(m), yc(m);
|
||||
xc = convert(xe);
|
||||
yc = convert(ye);
|
||||
expr_ref xc = convert(xe);
|
||||
expr_ref yc = convert(ye);
|
||||
|
||||
expr_ref c(m);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue