3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-27 19:08:49 +00:00

Better tracking for debugging

This commit is contained in:
CEisenhofer 2026-06-01 19:50:34 +02:00
parent 2da7c7b3db
commit 5b41c6eb9f
5 changed files with 153 additions and 116 deletions

View file

@ -220,8 +220,8 @@ namespace seq {
// nielsen_edge
// -----------------------------------------------
nielsen_edge::nielsen_edge(nielsen_node* src, nielsen_node* tgt, const bool is_progress):
m_src(src), m_tgt(tgt),
nielsen_edge::nielsen_edge(nielsen_node* src, nielsen_node* tgt, const char* rule, const bool is_progress):
m_src(src), m_tgt(tgt), m_rule_name(rule),
m_is_progress(is_progress) { }
void nielsen_edge::add_subst(nielsen_subst const& s) {
@ -514,10 +514,11 @@ namespace seq {
return child;
}
nielsen_edge* nielsen_graph::mk_edge(nielsen_node* src, nielsen_node* tgt, const bool is_progress) {
nielsen_edge* nielsen_graph::mk_edge(nielsen_node *src, nielsen_node *tgt, const char *rule,
const bool is_progress) {
SASSERT(src != nullptr);
SASSERT(tgt != nullptr);
nielsen_edge* e = alloc(nielsen_edge, src, tgt, is_progress);
nielsen_edge* e = alloc(nielsen_edge, src, tgt, rule, is_progress);
m_edges.push_back(e);
src->add_outgoing(e);
return e;
@ -1707,6 +1708,29 @@ namespace seq {
}
}
// Empty-language check for *primitive* memberships whose regex contains a
// projection operator. The regex widening pass below skips primitives,
// and is_contradiction only fires once the string side is empty. But a
// cycle decomposition constrains the remainder x'' by ~((π(r)∩~ε)·Σ*),
// and deriving this through the cycle can collapse it to the empty
// language: e.g. ~(π(r)·Σ*) ≡ ∅ because π(r) is nullable (r ∈ F), so
// π(r)·Σ* ≡ Σ*. Such a constraint is unsatisfiable, but without this
// eager check the variable would be unwound depth-deep before the
// conflict surfaces — the source of the multi-cycle-SCC blow-up. The
// check is cheap: is_empty_bfs on these projection regexes settles in a
// couple of states (a nullable projection short-circuits to non-empty).
SASSERT(m_graph.m_seq_regex);
for (str_mem const& mem : m_str_mem) {
if (!mem.is_primitive() || !mem.m_regex->has_projection())
continue;
if (m_graph.m_seq_regex->is_empty_bfs(mem.m_regex) == l_true) {
TRACE(seq, tout << "empty primitive projection regex " << mem_pp(mem, m) << "\n");
set_general_conflict();
set_conflict(backtrack_reason::regex, mem.m_dep);
return simplify_result::conflict;
}
}
// remove trivial membership constraints once again
unsigned wj = 0;
for (unsigned j = 0; j < m_str_mem.size(); ++j) {
@ -1904,7 +1928,7 @@ namespace seq {
return search_result::unknown;
#ifdef Z3DEBUG
if (m_stats.m_num_dfs_nodes % 200 == 0) {
if (m_stats.m_num_dfs_nodes % 50 == 0) {
std::string dot = to_dot();
std::cout << "";
}
@ -2097,7 +2121,7 @@ namespace seq {
if (l->is_empty() || r->is_empty()) {
euf::snode* non_empty_side = l->is_empty() ? r : l;
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "det", true);
euf::snode_vector tokens;
non_empty_side->collect_tokens(tokens);
@ -2107,7 +2131,7 @@ namespace seq {
for (euf::snode* t : tokens) {
if (t->is_var()) {
nielsen_subst s(t, m_sg.mk_empty_seq(t->get_sort()), nullptr, eq.m_dep);
nielsen_subst s(t, m_sg.mk_empty_seq(t->get_sort()), eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
} else if (t->is_power()) {
@ -2115,7 +2139,7 @@ namespace seq {
expr* pow_base = nullptr, *pow_exp = nullptr;
if (seq().str.is_power(expr_node, pow_base, pow_exp) && pow_exp)
e->add_side_constraint(mk_constraint(a.mk_eq(pow_exp, a.mk_int(0)), eq.m_dep));
nielsen_subst s(t, m_sg.mk_empty_seq(t->get_sort()), nullptr, eq.m_dep);
nielsen_subst s(t, m_sg.mk_empty_seq(t->get_sort()), eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
@ -2140,7 +2164,7 @@ namespace seq {
break;
else if (lt->is_char_or_unit() && rt->is_char_or_unit()) {
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "det", true);
if (lt->is_char()) {
std::swap(lt, rt);
@ -2157,7 +2181,7 @@ namespace seq {
if (lt->is_char())
std::swap(lt, rt);
nielsen_subst subst(lt, rt, m_sg.mk(a.mk_int(1)), eq.m_dep);
nielsen_subst subst(lt, rt, eq.m_dep);
e->add_subst(subst);
child->apply_subst(m_sg, subst);
@ -2181,7 +2205,7 @@ namespace seq {
break;
else if (lt->is_char_or_unit() && rt->is_char_or_unit()) {
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "det", true);
euf::snode* lhs_rest = m_sg.drop_right(l, suffix + 1);
euf::snode* rhs_rest = m_sg.drop_right(r, suffix + 1);
@ -2192,7 +2216,7 @@ namespace seq {
if (lt->is_char())
std::swap(lt, rt);
nielsen_subst subst(lt, rt, nullptr, eq.m_dep);
nielsen_subst subst(lt, rt, eq.m_dep);
e->add_subst(subst);
child->apply_subst(m_sg, subst);
@ -2222,8 +2246,8 @@ namespace seq {
if (m.are_equal(base_head->get_expr(), other_head->get_expr())) continue;
// Directional base/head mismatch -> force exponent 0 and power -> ε.
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_subst s(pow_head, m_sg.mk_empty_seq(pow_head->get_sort()), nullptr, eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "det", true);
nielsen_subst s(pow_head, m_sg.mk_empty_seq(pow_head->get_sort()), eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
expr* pow_exp = get_power_exp_expr(pow_head, m_seq);
@ -2377,11 +2401,9 @@ namespace seq {
}
euf::snode* tail = get_tail(var_node, compute_length_expr(prefix_sn).get(), fwd);
euf::snode* replacement = dir_concat(m_sg, prefix_sn, tail, fwd);
nielsen_subst s(var_node, replacement,
mk_rewrite(a.mk_sub(compute_length_expr(var_node), compute_length_expr(prefix_sn))),
eq.m_dep);
nielsen_subst s(var_node, replacement, eq.m_dep);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "det", true);
e->add_side_constraint(mk_constraint(a.mk_ge(compute_length_expr(tail), a.mk_int(0)), eq.m_dep));
e->add_subst(s);
child->apply_subst(m_sg, s);
@ -2412,8 +2434,8 @@ namespace seq {
if (var) {
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_subst s(var, def, nullptr, eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "det", true);
nielsen_subst s(var, def, eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
return true;
@ -2439,8 +2461,8 @@ namespace seq {
euf::snode* var_head = lhead->is_var() ? lhead : (rhead->is_var() ? rhead : nullptr);
if (char_head && var_head) {
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
const nielsen_subst s1(var_head, m_sg.mk_empty_seq(var_head->get_sort()), nullptr, eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "nielsen const 0", true);
const nielsen_subst s1(var_head, m_sg.mk_empty_seq(var_head->get_sort()), eq.m_dep);
e->add_subst(s1);
child->apply_subst(m_sg, s1);
@ -2448,9 +2470,9 @@ namespace seq {
euf::snode* tail = get_tail(var_head, a.mk_int(1), fwd);
euf::snode* replacement = dir_concat(m_sg, char_head, tail, fwd);
child = mk_child(node);
e = mk_edge(node, child, false);
e = mk_edge(node, child, "nielsen const >", false);
e->add_side_constraint(mk_constraint(a.mk_ge(compute_length_expr(tail), a.mk_int(0)), eq.m_dep));
const nielsen_subst s2(var_head, replacement, mk_rewrite(a.mk_sub(compute_length_expr(var_head), a.mk_int(1))), eq.m_dep);
const nielsen_subst s2(var_head, replacement, eq.m_dep);
e->add_subst(s2);
child->apply_subst(m_sg, s2);
return true;
@ -2478,16 +2500,16 @@ namespace seq {
// child 1: x → ε (progress)
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
const nielsen_subst s(lhead, m_sg.mk_empty_seq(lhead->get_sort()), nullptr, eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "nielsen var =l", true);
const nielsen_subst s(lhead, m_sg.mk_empty_seq(lhead->get_sort()), eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
// child 2: y → ε (progress)
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
const nielsen_subst s(rhead, m_sg.mk_empty_seq(rhead->get_sort()), nullptr, eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "nielsen var =r", true);
const nielsen_subst s(rhead, m_sg.mk_empty_seq(rhead->get_sort()), eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
@ -2495,10 +2517,8 @@ namespace seq {
{
euf::snode* replacement = dir_concat(m_sg, rhead, get_tail(lhead, compute_length_expr(rhead).get(), fwd), fwd);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, false);
const nielsen_subst s(lhead, replacement,
mk_rewrite(a.mk_sub(compute_length_expr(lhead), compute_length_expr(rhead))),
eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "nielsen var >", false);
const nielsen_subst s(lhead, replacement, eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
@ -2506,10 +2526,8 @@ namespace seq {
{
euf::snode* replacement = dir_concat(m_sg, lhead, get_tail(rhead, compute_length_expr(lhead).get(), fwd), fwd);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, false);
const nielsen_subst s(rhead, replacement,
mk_rewrite(a.mk_sub(compute_length_expr(rhead), compute_length_expr(lhead))),
eq.m_dep);
nielsen_edge* e = mk_edge(node, child, "nielsen var <", false);
const nielsen_subst s(rhead, replacement, eq.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
@ -2754,7 +2772,7 @@ namespace seq {
// Create single progress child.
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "eq split", true);
// Remove the original equation and add the two new ones.
auto& eqs = child->str_eqs();
@ -3052,16 +3070,16 @@ namespace seq {
// This makes u^n = ε^n = ε for any n.
if (base->is_var()) {
child = mk_child(node);
e = mk_edge(node, child, true);
const nielsen_subst s1(base, m_sg.mk_empty_seq(base->get_sort()), nullptr, dep);
e = mk_edge(node, child, "power power 0", true);
const nielsen_subst s1(base, m_sg.mk_empty_seq(base->get_sort()), dep);
e->add_subst(s1);
child->apply_subst(m_sg, s1);
}
// Branch 2: replace the power token itself with ε (n = 0 semantics)
child = mk_child(node);
e = mk_edge(node, child, true);
const nielsen_subst s2(power, m_sg.mk_empty_seq(power->get_sort()), nullptr, dep);
e = mk_edge(node, child, "power base 0", true);
const nielsen_subst s2(power, m_sg.mk_empty_seq(power->get_sort()), dep);
e->add_subst(s2);
child->apply_subst(m_sg, s2);
@ -3108,13 +3126,13 @@ namespace seq {
// Branch 1 (explored first): n < m (add constraint c ≥ p + 1)
{
nielsen_edge *e = mk_edge(node, mk_child(node), true);
nielsen_edge *e = mk_edge(node, mk_child(node), "power cmp <", true);
const expr_ref n_plus_1(a.mk_add(exp_n, a.mk_int(1)), m);
e->add_side_constraint(mk_constraint(a.mk_ge(exp_m, n_plus_1), eq.m_dep));
}
// Branch 2 (explored second): m <= n (add constraint p ≥ c)
{
nielsen_edge *e = mk_edge(node, mk_child(node), true);
nielsen_edge *e = mk_edge(node, mk_child(node), "power cmp >=", true);
e->add_side_constraint(mk_constraint(a.mk_ge(exp_n, exp_m), eq.m_dep));
}
return true;
@ -3174,13 +3192,13 @@ namespace seq {
// Branch 1: pow_exp < count (i.e., count >= pow_exp + 1)
{
nielsen_edge *e = mk_edge(node, mk_child(node), true);
nielsen_edge *e = mk_edge(node, mk_child(node), "power elim >", true);
const expr_ref pow_plus1(a.mk_add(pow_exp, a.mk_int(1)), m);
e->add_side_constraint(mk_constraint(a.mk_ge(norm_count, pow_plus1), eq.m_dep));
}
// Branch 2: count <= pow_exp (i.e., pow_exp >= count)
{
nielsen_edge *e = mk_edge(node, mk_child(node), true);
nielsen_edge *e = mk_edge(node, mk_child(node), "power elim <=", true);
e->add_side_constraint(mk_constraint(a.mk_ge(pow_exp, norm_count), eq.m_dep));
}
return true;
@ -3216,8 +3234,8 @@ namespace seq {
// Branch 1 (explored first): n = 0 → replace power with ε (progress)
// Side constraint: n = 0
nielsen_node *child = mk_child(node);
nielsen_edge *e = mk_edge(node, child, true);
const nielsen_subst s1(power, m_sg.mk_empty_seq(power->get_sort()), nullptr, eq->m_dep);
nielsen_edge *e = mk_edge(node, child, "unwinding 0", true);
const nielsen_subst s1(power, m_sg.mk_empty_seq(power->get_sort()), eq->m_dep);
e->add_subst(s1);
child->apply_subst(m_sg, s1);
if (exp_n)
@ -3240,8 +3258,8 @@ namespace seq {
euf::snode* replacement = dir_concat(m_sg, base, nested_power_snode, fwd);
child = mk_child(node);
e = mk_edge(node, child, true);
const nielsen_subst s2(power, replacement, nullptr, eq->m_dep);
e = mk_edge(node, child, "unwinding >", true);
const nielsen_subst s2(power, replacement, eq->m_dep);
e->add_subst(s2);
child->apply_subst(m_sg, s2);
if (exp_n)
@ -3374,7 +3392,7 @@ namespace seq {
SASSERT(tail);
nielsen_node* child = mk_child(node);
mk_edge(node, child, true);
mk_edge(node, child, "cycle subs", true);
auto& child_mems = child->str_mems();
for (unsigned k = 0; k < child_mems.size(); ++k) {
@ -3453,8 +3471,8 @@ namespace seq {
nielsen_node* child = mk_child(node);
SASSERT(child->m_str_mem[mi] == mem);
nielsen_edge* e = mk_edge(node, child, false);
const nielsen_subst s(x, xp_xpp, nullptr, mem.m_dep);
nielsen_edge* e = mk_edge(node, child, "cycle decomp", false);
const nielsen_subst s(x, xp_xpp, mem.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
@ -3486,6 +3504,9 @@ namespace seq {
<< " stabilizer=" << mk_pp(stabilizer_re->get_expr(), m)
<< " xpp_re=" << xpp_re << "\n");
#ifdef Z3DEBUG
std::string dot = partial_dfa_to_dot(mem.m_regex, false);
#endif
return true;
}
return false;
@ -3746,7 +3767,7 @@ namespace seq {
for (auto& [m_p, m_q, m_dep] : feasible) {
nielsen_node* child = mk_child(node);
mk_edge(node, child, true);
mk_edge(node, child, "regex fact", true);
// remove the original mem from child
auto& child_mems = child->str_mems();
@ -3881,8 +3902,8 @@ namespace seq {
replacement = prefix_sn ? dir_concat(m_sg, power_snode, prefix_sn, fwd) : power_snode;
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_subst s(var, replacement, nullptr, eq.m_dep); // TODO review - ensure var does not occur in replacement.
nielsen_edge* e = mk_edge(node, child, "power intr", true);
nielsen_subst s(var, replacement, eq.m_dep); // TODO review - ensure var does not occur in replacement.
e->add_subst(s);
child->apply_subst(m_sg, s);
@ -4035,7 +4056,7 @@ namespace seq {
for (unsigned branch = 0; branch < 2; ++branch) {
nielsen_node* child = mk_child(node);
mk_edge(node, child, true);
mk_edge(node, child, "signature split", true);
auto& child_eqs = child->str_eqs();
child_eqs[eq_idx] = child_eqs.back();
@ -4087,7 +4108,7 @@ namespace seq {
// No ite remaining: leaf → create child node with regex updated to r
euf::snode *new_regex_snode = m_sg.mk(r);
nielsen_node *child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "regex if", true);
for (const auto f : cs) {
e->add_side_constraint(constraint(f, mem.m_dep, m));
}
@ -4148,21 +4169,15 @@ namespace seq {
if (mem.is_primitive())
continue;
euf::snode* first = mem.m_str->first();
if (!first || !first->is_var())
continue;
// Compute minterms from the regex
euf::snode_vector minterms;
m_sg.compute_minterms(mem.m_regex, minterms);
VERIFY(!minterms.empty());
SASSERT(first);
// std::cout << "Considering regex: " << spp(mem.m_regex, m) << std::endl;
// Branch 1: x → ε (progress)
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
const nielsen_subst s(first, m_sg.mk_empty_seq(first->get_sort()), nullptr, mem.m_dep);
nielsen_edge* e = mk_edge(node, child, "regex var split", true);
const nielsen_subst s(first, m_sg.mk_empty_seq(first->get_sort()), mem.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
@ -4180,9 +4195,9 @@ namespace seq {
euf::snode* tail = get_tail(first, 1, true);
euf::snode* replacement = m_sg.mk_concat(fresh_char, tail);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, false);
nielsen_edge* e = mk_edge(node, child, "regex var split", false);
const nielsen_subst s(first, replacement, mk_rewrite(a.mk_sub(compute_length_expr(first), a.mk_int(1))), mem.m_dep);
const nielsen_subst s(first, replacement, mem.m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
@ -4267,8 +4282,8 @@ namespace seq {
replacement = prefix_sn ? dir_concat(m_sg, power_m_sn, prefix_sn, fwd) : power_m_sn;
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_subst s(var_head, replacement, nullptr, eq->m_dep); // TODO review - ensure var does not occur in replacement.
nielsen_edge* e = mk_edge(node, child, "power split", true);
nielsen_subst s(var_head, replacement, eq->m_dep); // TODO review - ensure var does not occur in replacement.
e->add_subst(s);
child->apply_subst(m_sg, s);
@ -4291,10 +4306,8 @@ namespace seq {
{
euf::snode* replacement = dir_concat(m_sg, power, var_head, fwd);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, false);
const nielsen_subst s(var_head, replacement,
mk_rewrite(a.mk_sub(compute_length_expr(var_head), compute_length_expr(power))),
eq->m_dep);
nielsen_edge* e = mk_edge(node, child, "power split", false);
const nielsen_subst s(var_head, replacement, eq->m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
}
@ -4331,8 +4344,8 @@ namespace seq {
// Side constraint: n = 0
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
const nielsen_subst s(power, m_sg.mk_empty_seq(power->get_sort()), nullptr, eq->m_dep);
nielsen_edge* e = mk_edge(node, child, "unwinding eq 0", true);
const nielsen_subst s(power, m_sg.mk_empty_seq(power->get_sort()), eq->m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
e->add_side_constraint(mk_constraint(a.mk_ge(exp_n, zero), eq->m_dep));
@ -4346,8 +4359,8 @@ namespace seq {
euf::snode* power_snode = m_sg.mk(power_expr);
euf::snode* replacement = dir_concat(m_sg, base, power_snode, fwd);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, false);
const nielsen_subst s(power, replacement, nullptr, eq->m_dep); // TODO review - ensure var does not occur in replacement.
nielsen_edge* e = mk_edge(node, child, "unwinding eq >", false);
const nielsen_subst s(power, replacement, eq->m_dep); // TODO review - ensure var does not occur in replacement.
e->add_subst(s);
child->apply_subst(m_sg, s);
e->add_side_constraint(mk_constraint(a.mk_ge(exp_n, one), eq->m_dep));
@ -4375,8 +4388,8 @@ namespace seq {
// Side constraint: n = 0
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
const nielsen_subst s(power, m_sg.mk_empty_seq(power->get_sort()), nullptr, mem->m_dep);
nielsen_edge* e = mk_edge(node, child, "unwinding mem 0", true);
const nielsen_subst s(power, m_sg.mk_empty_seq(power->get_sort()), mem->m_dep);
e->add_subst(s);
child->apply_subst(m_sg, s);
e->add_side_constraint(mk_constraint(a.mk_eq(exp_n, zero), mem->m_dep));
@ -4390,8 +4403,8 @@ namespace seq {
euf::snode* replacement = dir_concat(m_sg, base, power_snode, fwd);
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, false);
const nielsen_subst s(power, replacement, nullptr, mem->m_dep); // TODO review - ensure var does not occur in replacement.
nielsen_edge* e = mk_edge(node, child, "unwinding mem >", false);
const nielsen_subst s(power, replacement, mem->m_dep); // TODO review - ensure var does not occur in replacement.
e->add_subst(s);
child->apply_subst(m_sg, s);
e->add_side_constraint(mk_constraint(a.mk_ge(exp_n, one), mem->m_dep));
@ -4433,7 +4446,7 @@ namespace seq {
// Branch 1: |u| < |v|
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "diseq I", true);
child->m_str_deq.pop_back();
expr_ref cmp(this->a.mk_lt(u_len, v_len), m);
m_rw(cmp);
@ -4442,7 +4455,7 @@ namespace seq {
// Branch 2: |v| < |u|
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "diseq II", true);
child->m_str_deq.pop_back();
expr_ref cmp(this->a.mk_lt(v_len, u_len), m);
m_rw(cmp);
@ -4451,7 +4464,7 @@ namespace seq {
// Branch 3: u = wau' && v = wbv' && |u'| = |v'| && a != b
{
nielsen_node* child = mk_child(node);
nielsen_edge* e = mk_edge(node, child, true);
nielsen_edge* e = mk_edge(node, child, "diseq III", true);
child->m_str_deq.pop_back();
child->add_str_eq(u_eq);
child->add_str_eq(v_eq);