mirror of
https://github.com/Z3Prover/z3
synced 2026-05-20 00:49:33 +00:00
Merge remote-tracking branch 'origin/master' into c3
# Conflicts: # .github/workflows/qf-s-benchmark.lock.yml # .github/workflows/qf-s-benchmark.md # .github/workflows/zipt-code-reviewer.lock.yml # .github/workflows/zipt-code-reviewer.md # .gitignore # src/ast/rewriter/seq_rewriter.cpp # src/test/main.cpp
This commit is contained in:
commit
6a6f9b1892
185 changed files with 16422 additions and 5692 deletions
|
|
@ -1360,6 +1360,7 @@ namespace {
|
|||
// to check it again.
|
||||
get_check_mark(reg) == NOT_CHECKED &&
|
||||
is_ground(m_registers[reg]) &&
|
||||
instr->m_enode != nullptr &&
|
||||
get_pat_lbl_hash(reg) == instr->m_enode->get_lbl_hash();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ namespace smt {
|
|||
if (!m_non_diff_logic_exprs) {
|
||||
TRACE(non_diff_logic, tout << "found non diff logic expression:\n" << mk_pp(n, m) << "\n";);
|
||||
ctx.push_trail(value_trail<bool>(m_non_diff_logic_exprs));
|
||||
IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, m) << ")\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, m) << ")\n";);
|
||||
m_non_diff_logic_exprs = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ template<typename Ext>
|
|||
void theory_diff_logic<Ext>::found_non_diff_logic_expr(expr * n) {
|
||||
if (!m_non_diff_logic_exprs) {
|
||||
TRACE(non_diff_logic, tout << "found non diff logic expression:\n" << mk_pp(n, m) << "\n";);
|
||||
IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, m) << ")\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, m) << ")\n";);
|
||||
ctx.push_trail(value_trail<bool>(m_non_diff_logic_exprs));
|
||||
m_non_diff_logic_exprs = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ class theory_lra::imp {
|
|||
ptr_vector<expr> m_not_handled;
|
||||
ptr_vector<app> m_underspecified;
|
||||
ptr_vector<app> m_bv_terms;
|
||||
ptr_vector<expr> m_mul_defs; // fresh multiplication definition vars
|
||||
vector<ptr_vector<api_bound> > m_use_list; // bounds where variables are used.
|
||||
|
||||
// attributes for incremental version:
|
||||
|
|
@ -267,9 +268,25 @@ class theory_lra::imp {
|
|||
};
|
||||
m_nla->set_relevant(is_relevant);
|
||||
m_nla->updt_params(ctx().get_params());
|
||||
m_nla->get_core().set_add_mul_def_hook([&](unsigned sz, lpvar const* vs) { return add_mul_def(sz, vs); });
|
||||
}
|
||||
}
|
||||
|
||||
lpvar add_mul_def(unsigned sz, lpvar const* vs) {
|
||||
bool is_int = true;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
theory_var tv = lp().local_to_external(vs[i]);
|
||||
is_int &= this->is_int(tv);
|
||||
}
|
||||
sort* srt = is_int ? a.mk_int() : a.mk_real();
|
||||
app_ref c(m.mk_fresh_const("mul!", srt), m);
|
||||
mk_enode(c);
|
||||
theory_var v = mk_var(c);
|
||||
ctx().push_trail(push_back_vector<ptr_vector<expr>>(m_mul_defs));
|
||||
m_mul_defs.push_back(c);
|
||||
return register_theory_var_in_lar_solver(v);
|
||||
}
|
||||
|
||||
void found_unsupported(expr* n) {
|
||||
ctx().push_trail(push_back_vector<ptr_vector<expr>>(m_not_handled));
|
||||
TRACE(arith, tout << "unsupported " << mk_pp(n, m) << "\n");
|
||||
|
|
@ -3983,6 +4000,81 @@ public:
|
|||
return inf_eps(rational(0), inf_rational(ival.x, ival.y));
|
||||
}
|
||||
|
||||
lp::lp_status max_with_lp(theory_var v, lpvar& vi, lp::impq& term_max) {
|
||||
if (!lp().is_feasible() || lp().has_changed_columns())
|
||||
make_feasible();
|
||||
vi = get_lpvar(v);
|
||||
auto st = lp().maximize_term(vi, term_max);
|
||||
if (has_int() && lp().has_inf_int()) {
|
||||
st = lp::lp_status::FEASIBLE;
|
||||
lp().restore_x();
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
// Returns true if NLA handled the result (blocker and result are set).
|
||||
// Returns false if maximize should fall through to the normal status switch.
|
||||
bool max_with_nl(theory_var v, lp::lp_status& st, unsigned level, expr_ref& blocker, inf_eps& result) {
|
||||
if (!m_nla || (st != lp::lp_status::OPTIMAL && st != lp::lp_status::UNBOUNDED))
|
||||
return false;
|
||||
// Save the LP optimum before NLA check may restore x.
|
||||
auto lp_val = value(v);
|
||||
auto lp_ival = get_ivalue(v);
|
||||
auto nla_st = check_nla(level);
|
||||
TRACE(opt, tout << "check_nla returned " << nla_st
|
||||
<< " lp_ival=" << lp_ival << "\n";
|
||||
if (nla_st == FC_CONTINUE) {
|
||||
tout << "LP assignment at maximize optimum:\n";
|
||||
for (unsigned j = 0; j < lp().column_count(); j++) {
|
||||
if (!lp().get_column_value(j).is_zero())
|
||||
tout << " x[" << j << "] = " << lp().get_column_value(j) << "\n";
|
||||
}
|
||||
});
|
||||
switch (nla_st) {
|
||||
case FC_DONE:
|
||||
// NLA satisfied: keep the optimal assignment, return LP value
|
||||
blocker = mk_gt(v);
|
||||
result = lp_val;
|
||||
st = lp::lp_status::FEASIBLE;
|
||||
return true;
|
||||
case FC_CONTINUE:
|
||||
// NLA found the LP optimum violates nonlinear constraints.
|
||||
// Restore x but return the LP optimum value and blocker
|
||||
// as a bound for the optimizer to validate via check_bound().
|
||||
lp().restore_x();
|
||||
blocker = mk_gt(v, lp_ival);
|
||||
result = lp_val;
|
||||
st = lp::lp_status::FEASIBLE;
|
||||
return true;
|
||||
case FC_GIVEUP:
|
||||
lp().restore_x();
|
||||
st = lp::lp_status::UNBOUNDED;
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
theory_lra::inf_eps max_result(theory_var v, lpvar vi, lp::lp_status st, expr_ref& blocker, bool& has_shared) {
|
||||
switch (st) {
|
||||
case lp::lp_status::OPTIMAL:
|
||||
init_variable_values();
|
||||
TRACE(arith, display(tout << st << " v" << v << " vi: " << vi << "\n"););
|
||||
blocker = mk_gt(v);
|
||||
return value(v);
|
||||
case lp::lp_status::FEASIBLE:
|
||||
TRACE(arith, display(tout << st << " v" << v << " vi: " << vi << "\n"););
|
||||
blocker = mk_gt(v);
|
||||
return value(v);
|
||||
default:
|
||||
SASSERT(st == lp::lp_status::UNBOUNDED);
|
||||
TRACE(arith, display(tout << st << " v" << v << " vi: " << vi << "\n"););
|
||||
has_shared = false;
|
||||
blocker = m.mk_false();
|
||||
return inf_eps(rational::one(), inf_rational());
|
||||
}
|
||||
}
|
||||
|
||||
theory_lra::inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) {
|
||||
unsigned level = 2;
|
||||
lp::impq term_max;
|
||||
|
|
@ -3999,55 +4091,21 @@ public:
|
|||
st = lp::lp_status::UNBOUNDED;
|
||||
}
|
||||
else {
|
||||
if (!lp().is_feasible() || lp().has_changed_columns())
|
||||
make_feasible();
|
||||
|
||||
vi = get_lpvar(v);
|
||||
|
||||
st = lp().maximize_term(vi, term_max);
|
||||
|
||||
if (has_int() && lp().has_inf_int()) {
|
||||
st = lp::lp_status::FEASIBLE;
|
||||
lp().restore_x();
|
||||
}
|
||||
if (m_nla && (st == lp::lp_status::OPTIMAL || st == lp::lp_status::UNBOUNDED)) {
|
||||
switch (check_nla(level)) {
|
||||
case FC_DONE:
|
||||
case FC_CONTINUE:
|
||||
st = lp::lp_status::FEASIBLE;
|
||||
break;
|
||||
case FC_GIVEUP:
|
||||
st = lp::lp_status::UNBOUNDED;
|
||||
break;
|
||||
}
|
||||
lp().restore_x();
|
||||
}
|
||||
}
|
||||
switch (st) {
|
||||
case lp::lp_status::OPTIMAL: {
|
||||
init_variable_values();
|
||||
TRACE(arith, display(tout << st << " v" << v << " vi: " << vi << "\n"););
|
||||
auto val = value(v);
|
||||
blocker = mk_gt(v);
|
||||
return val;
|
||||
}
|
||||
case lp::lp_status::FEASIBLE: {
|
||||
auto val = value(v);
|
||||
TRACE(arith, display(tout << st << " v" << v << " vi: " << vi << "\n"););
|
||||
blocker = mk_gt(v);
|
||||
return val;
|
||||
}
|
||||
default:
|
||||
SASSERT(st == lp::lp_status::UNBOUNDED);
|
||||
TRACE(arith, display(tout << st << " v" << v << " vi: " << vi << "\n"););
|
||||
has_shared = false;
|
||||
blocker = m.mk_false();
|
||||
return inf_eps(rational::one(), inf_rational());
|
||||
st = max_with_lp(v, vi, term_max);
|
||||
inf_eps nl_result;
|
||||
if (max_with_nl(v, st, level, blocker, nl_result))
|
||||
return nl_result;
|
||||
}
|
||||
return max_result(v, vi, st, blocker, has_shared);
|
||||
}
|
||||
|
||||
expr_ref mk_gt(theory_var v) {
|
||||
lp::impq val = get_ivalue(v);
|
||||
return mk_gt(v, val);
|
||||
}
|
||||
|
||||
// Overload: create blocker from a saved impq value (used when x has been restored)
|
||||
expr_ref mk_gt(theory_var v, lp::impq const& val) {
|
||||
expr* obj = get_enode(v)->get_expr();
|
||||
rational r = val.x;
|
||||
expr_ref e(m);
|
||||
|
|
|
|||
|
|
@ -345,11 +345,6 @@ final_check_status theory_seq::final_check_eh(unsigned level) {
|
|||
TRACEFIN("regex propagate");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_contains()) {
|
||||
++m_stats.m_propagate_contains;
|
||||
TRACEFIN("propagate_contains");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_fixed_length(true, false)) {
|
||||
++m_stats.m_fixed_length;
|
||||
TRACEFIN("zero_length");
|
||||
|
|
@ -365,6 +360,16 @@ final_check_status theory_seq::final_check_eh(unsigned level) {
|
|||
TRACEFIN("fixed_length");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_fixed_length(false, true)) {
|
||||
++m_stats.m_fixed_length;
|
||||
TRACEFIN("fixed_length");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_contains()) {
|
||||
++m_stats.m_propagate_contains;
|
||||
TRACEFIN("propagate_contains");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_int_string()) {
|
||||
++m_stats.m_int_string;
|
||||
TRACEFIN("int_string");
|
||||
|
|
@ -499,12 +504,6 @@ bool theory_seq::fixed_length(expr* len_e, bool is_zero, bool check_long_strings
|
|||
m_fixed.contains(e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_trail_stack.push(insert_obj_trail<expr>(m_fixed, e));
|
||||
m_fixed.insert(e);
|
||||
|
||||
expr_ref seq(e, m), head(m), tail(m);
|
||||
|
||||
|
||||
TRACE(seq, tout << "Fixed: " << mk_bounded_pp(e, m, 2) << " " << lo << "\n";);
|
||||
literal a = mk_eq(len_e, m_autil.mk_numeral(lo, true), false);
|
||||
|
|
@ -514,6 +513,11 @@ bool theory_seq::fixed_length(expr* len_e, bool is_zero, bool check_long_strings
|
|||
if (!check_long_strings && lo > 20 && !is_zero)
|
||||
return false;
|
||||
|
||||
m_trail_stack.push(insert_obj_trail<expr>(m_fixed, e));
|
||||
m_fixed.insert(e);
|
||||
|
||||
expr_ref seq(e, m), head(m), tail(m);
|
||||
|
||||
if (lo.is_zero()) {
|
||||
seq = m_util.str.mk_empty(e->get_sort());
|
||||
}
|
||||
|
|
@ -2976,7 +2980,7 @@ void theory_seq::add_axiom(literal_vector & lits) {
|
|||
TRACE(seq, ctx.display_literals_verbose(tout << "assert " << lits << " :", lits) << "\n";);
|
||||
|
||||
for (literal lit : lits)
|
||||
if (ctx.get_assignment(lit) == l_true)
|
||||
if (ctx.get_assignment(lit) == l_true && ctx.get_assign_level(lit) == 0)
|
||||
return;
|
||||
|
||||
for (literal lit : lits)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue