diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 1491cdb99..11ebf2fbc 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -92,6 +92,7 @@ def_module_params(module_name='smt', ('str.regex_automata_length_attempt_threshold', UINT, 10, 'number of length/path constraint attempts before checking unsatisfiability of regex terms'), ('str.fixed_length_models', BOOL, True, 'use fixed-length equation solver to construct models (Z3str3 only)'), ('str.fixed_length_refinement', BOOL, False, 'use abstraction refinement in fixed-length equation solver (Z3str3 only)'), + ('str.fixed_length_naive_cex', BOOL, True, 'construct naive counterexamples when fixed-length model construction fails for a given length assignment (Z3str3 only)'), ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), diff --git a/src/smt/params/theory_str_params.cpp b/src/smt/params/theory_str_params.cpp index 6eb335ba4..1746f1109 100644 --- a/src/smt/params/theory_str_params.cpp +++ b/src/smt/params/theory_str_params.cpp @@ -39,6 +39,7 @@ void theory_str_params::updt_params(params_ref const & _p) { m_RegexAutomata_LengthAttemptThreshold = p.str_regex_automata_length_attempt_threshold(); m_FixedLengthModels = p.str_fixed_length_models(); m_FixedLengthRefinement = p.str_fixed_length_refinement(); + m_FixedLengthNaiveCounterexamples = p.str_fixed_length_naive_cex(); } #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; @@ -61,4 +62,5 @@ void theory_str_params::display(std::ostream & out) const { DISPLAY_PARAM(m_RegexAutomata_FailedIntersectionThreshold); DISPLAY_PARAM(m_RegexAutomata_LengthAttemptThreshold); DISPLAY_PARAM(m_FixedLengthModels); + DISPLAY_PARAM(m_FixedLengthNaiveCounterexamples); } diff --git a/src/smt/params/theory_str_params.h b/src/smt/params/theory_str_params.h index 27b4a186e..187f76340 100644 --- a/src/smt/params/theory_str_params.h +++ b/src/smt/params/theory_str_params.h @@ -130,6 +130,13 @@ struct theory_str_params { */ bool m_FixedLengthRefinement; + /* + * If FixedLengthNaiveCounterexamples is true and the fixed-length equation solver is enabled, + * Z3str3 will only construct simple counterexamples to block unsatisfiable length assignments + * instead of attempting to learn more complex lessons. + */ + bool m_FixedLengthNaiveCounterexamples; + theory_str_params(params_ref const & p = params_ref()): m_StrongArrangements(true), m_AggressiveLengthTesting(false), @@ -149,7 +156,8 @@ struct theory_str_params { m_RegexAutomata_FailedIntersectionThreshold(10), m_RegexAutomata_LengthAttemptThreshold(10), m_FixedLengthModels(true), - m_FixedLengthRefinement(false) + m_FixedLengthRefinement(false), + m_FixedLengthNaiveCounterexamples(true) { updt_params(p); } diff --git a/src/smt/theory_str_mc.cpp b/src/smt/theory_str_mc.cpp index 829c0653a..3099a29c0 100644 --- a/src/smt/theory_str_mc.cpp +++ b/src/smt/theory_str_mc.cpp @@ -875,29 +875,36 @@ namespace smt { return l_true; } else if (subproblem_status == l_false) { - // TODO replace this with something simpler for now - NOT_IMPLEMENTED_YET(); - TRACE("str_fl", tout << "subsolver found UNSAT; reconstructing unsat core" << std::endl;); - TRACE("str_fl", tout << "unsat core has size " << subsolver.get_unsat_core_size() << std::endl;); - bool negate_pre = false; - for (unsigned i = 0; i < subsolver.get_unsat_core_size(); ++i) { - TRACE("str", tout << "entry " << i << " = " << mk_pp(subsolver.get_unsat_core_expr(i), m) << std::endl;); - rational index; - expr* lhs; - expr* rhs; - std::tie(index, lhs, rhs) = fixed_length_lesson.find(subsolver.get_unsat_core_expr(i)); - TRACE("str_fl", tout << "lesson: " << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << " at index " << index << std::endl;); - cex.push_back(refine(lhs, rhs, index)); - if (index < rational(0)) { - negate_pre = true; + if (m_params.m_FixedLengthNaiveCounterexamples) { + TRACE("str_fl", tout << "subsolver found UNSAT; constructing length counterexample" << std::endl;); + for (auto e : fixed_length_used_len_terms) { + expr * var = &e.get_key(); + cex.push_back(m.mk_eq(u.str.mk_length(var), mk_int(e.get_value()))); } - } - if (negate_pre){ - for (auto ex : precondition) { - cex.push_back(ex); + return l_false; + } else { + TRACE("str_fl", tout << "subsolver found UNSAT; reconstructing unsat core" << std::endl;); + TRACE("str_fl", tout << "unsat core has size " << subsolver.get_unsat_core_size() << std::endl;); + bool negate_pre = false; + for (unsigned i = 0; i < subsolver.get_unsat_core_size(); ++i) { + TRACE("str", tout << "entry " << i << " = " << mk_pp(subsolver.get_unsat_core_expr(i), m) << std::endl;); + rational index; + expr* lhs; + expr* rhs; + std::tie(index, lhs, rhs) = fixed_length_lesson.find(subsolver.get_unsat_core_expr(i)); + TRACE("str_fl", tout << "lesson: " << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << " at index " << index << std::endl;); + cex.push_back(refine(lhs, rhs, index)); + if (index < rational(0)) { + negate_pre = true; + } } + if (negate_pre){ + for (auto ex : precondition) { + cex.push_back(ex); + } + } + return l_false; } - return l_false; } else { // l_undef TRACE("str_fl", tout << "WARNING: subsolver found UNKNOWN" << std::endl;); return l_undef;