mirror of
https://github.com/Z3Prover/z3
synced 2025-08-04 10:20:23 +00:00
zero-length automaton solution fix
This commit is contained in:
parent
dbb15f65b5
commit
5727950a3c
1 changed files with 100 additions and 48 deletions
|
@ -9811,33 +9811,85 @@ namespace smt {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exact_length_value.is_zero()) {
|
|
||||||
// shortcut
|
// find a consistent automaton for this term
|
||||||
expr_ref lhs(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(rational::zero(), true)), m);
|
bool found = false;
|
||||||
expr_ref rhs(ctx.mk_eq_atom(str, mk_string("")), m);
|
regex_automaton_under_assumptions assumption;
|
||||||
assert_implication(lhs, rhs);
|
if (regex_automaton_assumptions.contains(re) &&
|
||||||
} else {
|
!regex_automaton_assumptions[re].empty()){
|
||||||
// find a consistent automaton for this term
|
for (svector<regex_automaton_under_assumptions>::iterator it = regex_automaton_assumptions[re].begin();
|
||||||
bool found = false;
|
it != regex_automaton_assumptions[re].end(); ++it) {
|
||||||
regex_automaton_under_assumptions assumption;
|
regex_automaton_under_assumptions autA = *it;
|
||||||
if (regex_automaton_assumptions.contains(re) &&
|
rational assumed_upper_bound, assumed_lower_bound;
|
||||||
!regex_automaton_assumptions[re].empty()){
|
bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound);
|
||||||
for (svector<regex_automaton_under_assumptions>::iterator it = regex_automaton_assumptions[re].begin();
|
bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound);
|
||||||
it != regex_automaton_assumptions[re].end(); ++it) {
|
if (!assumes_upper_bound && !assumes_lower_bound) {
|
||||||
regex_automaton_under_assumptions autA = *it;
|
// automaton with no assumptions is always usable
|
||||||
rational assumed_upper_bound, assumed_lower_bound;
|
assumption = autA;
|
||||||
bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound);
|
found = true;
|
||||||
bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound);
|
break;
|
||||||
if (!assumes_upper_bound && !assumes_lower_bound) {
|
}
|
||||||
// automaton with no assumptions is always usable
|
// check consistency of bounds assumptions
|
||||||
assumption = autA;
|
} // foreach(a in regex_automaton_assumptions)
|
||||||
found = true;
|
}
|
||||||
break;
|
if (found) {
|
||||||
|
if (exact_length_value.is_zero()) {
|
||||||
|
// check consistency of 0-length solution with automaton
|
||||||
|
eautomaton * aut = assumption.get_automaton();
|
||||||
|
bool zero_solution = false;
|
||||||
|
unsigned initial_state = aut->init();
|
||||||
|
if (aut->is_final_state(initial_state)) {
|
||||||
|
zero_solution = true;
|
||||||
|
} else {
|
||||||
|
unsigned_vector eps_states;
|
||||||
|
aut->get_epsilon_closure(initial_state, eps_states);
|
||||||
|
for (unsigned_vector::iterator it = eps_states.begin(); it != eps_states.end(); ++it) {
|
||||||
|
unsigned state = *it;
|
||||||
|
if (aut->is_final_state(state)) {
|
||||||
|
zero_solution = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// check consistency of bounds assumptions
|
}
|
||||||
} // foreach(a in regex_automaton_assumptions)
|
|
||||||
}
|
// now check polarity of automaton wrt. original term
|
||||||
if (found) {
|
if ( (current_assignment == l_true && !assumption.get_polarity())
|
||||||
|
|| (current_assignment == l_false && assumption.get_polarity())) {
|
||||||
|
// invert sense
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zero_solution) {
|
||||||
|
TRACE("str", tout << "zero-length solution OK -- asserting empty path constraint" << std::endl;);
|
||||||
|
expr_ref_vector lhs_terms(m);
|
||||||
|
if (current_assignment == l_true) {
|
||||||
|
lhs_terms.push_back(str_in_re);
|
||||||
|
} else {
|
||||||
|
lhs_terms.push_back(m.mk_not(str_in_re));
|
||||||
|
}
|
||||||
|
lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true)));
|
||||||
|
expr_ref lhs(mk_and(lhs_terms), m);
|
||||||
|
expr_ref rhs(ctx.mk_eq_atom(str, mk_string("")), m);
|
||||||
|
assert_implication(lhs, rhs);
|
||||||
|
regex_terms_with_path_constraints.insert(str_in_re);
|
||||||
|
m_trail_stack.push(insert_obj_trail<theory_str, expr>(regex_terms_with_path_constraints, str_in_re));
|
||||||
|
} else {
|
||||||
|
TRACE("str", tout << "zero-length solution not admitted by this automaton -- asserting conflict clause" << std::endl;);
|
||||||
|
expr_ref_vector lhs_terms(m);
|
||||||
|
if (current_assignment == l_true) {
|
||||||
|
lhs_terms.push_back(str_in_re);
|
||||||
|
} else {
|
||||||
|
lhs_terms.push_back(m.mk_not(str_in_re));
|
||||||
|
}
|
||||||
|
lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true)));
|
||||||
|
expr_ref lhs(mk_and(lhs_terms), m);
|
||||||
|
expr_ref conflict(m.mk_not(lhs), m);
|
||||||
|
assert_axiom(conflict);
|
||||||
|
}
|
||||||
|
regex_axiom_add = true;
|
||||||
|
regex_inc_counter(regex_length_attempt_count, re);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
expr_ref pathConstraint(m);
|
expr_ref pathConstraint(m);
|
||||||
expr_ref characterConstraints(m);
|
expr_ref characterConstraints(m);
|
||||||
pathConstraint = generate_regex_path_constraints(str, assumption.get_automaton(), exact_length_value, characterConstraints);
|
pathConstraint = generate_regex_path_constraints(str, assumption.get_automaton(), exact_length_value, characterConstraints);
|
||||||
|
@ -9876,30 +9928,30 @@ namespace smt {
|
||||||
TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;);
|
TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// no automata available, or else all bounds assumptions are invalid
|
|
||||||
unsigned expected_complexity = estimate_regex_complexity(re);
|
|
||||||
if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) {
|
|
||||||
CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold,
|
|
||||||
tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;);
|
|
||||||
eautomaton * aut = m_mk_aut(re);
|
|
||||||
aut->compress();
|
|
||||||
regex_automata.push_back(aut);
|
|
||||||
regex_automaton_under_assumptions new_aut(re, aut, true);
|
|
||||||
if (!regex_automaton_assumptions.contains(re)) {
|
|
||||||
regex_automaton_assumptions.insert(re, svector<regex_automaton_under_assumptions>());
|
|
||||||
}
|
|
||||||
regex_automaton_assumptions[re].push_back(new_aut);
|
|
||||||
TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;);
|
|
||||||
regex_axiom_add = true;
|
|
||||||
find_automaton_initial_bounds(str_in_re, aut);
|
|
||||||
} else {
|
|
||||||
regex_inc_counter(regex_fail_count, str_in_re);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} // !length is zero
|
} else {
|
||||||
|
// no automata available, or else all bounds assumptions are invalid
|
||||||
|
unsigned expected_complexity = estimate_regex_complexity(re);
|
||||||
|
if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) {
|
||||||
|
CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold,
|
||||||
|
tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;);
|
||||||
|
eautomaton * aut = m_mk_aut(re);
|
||||||
|
aut->compress();
|
||||||
|
regex_automata.push_back(aut);
|
||||||
|
regex_automaton_under_assumptions new_aut(re, aut, true);
|
||||||
|
if (!regex_automaton_assumptions.contains(re)) {
|
||||||
|
regex_automaton_assumptions.insert(re, svector<regex_automaton_under_assumptions>());
|
||||||
|
}
|
||||||
|
regex_automaton_assumptions[re].push_back(new_aut);
|
||||||
|
TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;);
|
||||||
|
regex_axiom_add = true;
|
||||||
|
find_automaton_initial_bounds(str_in_re, aut);
|
||||||
|
} else {
|
||||||
|
regex_inc_counter(regex_fail_count, str_in_re);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} // get_len_value()
|
} // get_len_value()
|
||||||
expr_ref str_len(mk_strlen(str), m);
|
expr_ref str_len(mk_strlen(str), m);
|
||||||
rational lower_bound_value;
|
rational lower_bound_value;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue