3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-02-19 23:14:40 +00:00
z3/src/smt/theory_utvpi.h
Nikolaj Bjorner e4697fe18e remove set cardinality operators from array theory. Make final-check use priority levels
Issue #7502 shows that running nlsat eagerly during final check can block quantifier instantiation.
To give space for quantifier instances we introduce two levels for final check such that nlsat is only applied in the second and final level.
2026-02-18 20:56:51 -08:00

365 lines
10 KiB
C++

/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
theory_utvpi.h
Abstract:
use Bellman Ford traversal algorithm for UTVPI.
Author:
Nikolaj Bjorner (nbjorner) 2013-04-26
Revision History:
The implementaton is derived from theory_diff_logic.
--*/
#pragma once
#include "smt/theory_diff_logic.h"
namespace smt {
class utvpi_tester {
ast_manager& m;
arith_util a;
ptr_vector<expr> m_todo;
ast_mark m_mark;
obj_map<expr, rational> m_coeff_map;
rational m_weight;
vector<std::pair<expr*, rational> > m_terms;
public:
utvpi_tester(ast_manager& m);
// test if formula is in the Horn inequality fragment:
bool operator()(expr* fml);
bool operator()(unsigned num_fmls, expr* const* fmls);
// linearize inequality/equality
bool linearize(expr* e);
bool linearize(expr* e1, expr* e2);
// retrieve linearization
vector<std::pair<expr*, rational> > const& get_linearization() const;
rational const& get_weight() const { return m_weight; }
private:
bool linearize();
};
template<typename Ext>
class theory_utvpi : public theory, private Ext {
typedef typename Ext::numeral numeral;
typedef theory_var th_var;
typedef svector<th_var> th_var_vector;
typedef vector<std::pair<th_var, rational> > coeffs;
class assignment_trail;
class parent_trail;
struct GExt : public Ext {
typedef std::pair<literal,unsigned> explanation;
};
class atom {
protected:
bool_var m_bvar;
bool m_true;
int m_pos;
int m_neg;
public:
atom(bool_var bv, int pos, int neg) :
m_bvar(bv), m_true(false),
m_pos(pos), m_neg(neg) {}
bool_var get_bool_var() const { return m_bvar; }
void assign_eh(bool is_true) { m_true = is_true; }
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
int get_pos() const { return m_pos; }
int get_neg() const { return m_neg; }
std::ostream& display(theory_utvpi const& th, std::ostream& out) const;
};
typedef svector<atom> atoms;
struct scope {
unsigned m_atoms_lim;
unsigned m_asserted_atoms_lim;
unsigned m_asserted_qhead_old;
};
struct stats {
unsigned m_num_conflicts;
unsigned m_num_assertions;
unsigned m_num_core2th_eqs;
unsigned m_num_core2th_diseqs;
void reset() {
memset(this, 0, sizeof(*this));
}
stats() {
reset();
}
};
// Functor used to collect the proofs for a conflict due to
// a negative cycle.
class nc_functor {
literal_vector m_antecedents;
unsigned_vector m_coeffs;
theory_utvpi& m_super;
public:
nc_functor(theory_utvpi& s) : m_super(s) {}
void reset() { m_antecedents.reset(); m_coeffs.reset(); }
literal_vector const& get_lits() const { return m_antecedents; }
unsigned_vector const& get_coeffs() const { return m_coeffs; }
void operator()(std::pair<literal,unsigned> const & ex) {
if (ex.first != null_literal) {
m_antecedents.push_back(ex.first);
m_coeffs.push_back(ex.second);
}
}
void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {
m_super.new_edge(src, dst, num_edges, edges);
}
};
stats m_stats;
smt_params m_params;
arith_util a;
arith_eq_adapter m_arith_eq_adapter;
bool m_consistent;
th_var m_izero, m_rzero; //cache the variable representing the zero variable.
dl_graph<GExt> m_graph;
nc_functor m_nc_functor;
atoms m_atoms;
unsigned_vector m_asserted_atoms; // set of asserted atoms
unsigned m_asserted_qhead;
u_map<unsigned> m_bool_var2atom;
svector<scope> m_scopes;
double m_agility;
bool m_lia;
bool m_lra;
bool m_non_utvpi_exprs;
utvpi_tester m_test;
arith_factory * m_factory;
rational m_delta;
struct var_value_hash;
friend struct var_value_hash;
struct var_value_hash {
theory_utvpi & m_th;
var_value_hash(theory_utvpi & th):m_th(th) {}
unsigned operator()(theory_var v) const { return m_th.mk_value(v, false).hash(); }
};
struct var_value_eq;
friend struct var_value_eq;
struct var_value_eq {
theory_utvpi & m_th;
var_value_eq(theory_utvpi & th):m_th(th) {}
bool operator()(theory_var v1, theory_var v2) const { return m_th.mk_value(v1, false) == m_th.mk_value(v2, false) && m_th.is_int(v1) == m_th.is_int(v2); }
};
typedef int_hashtable<var_value_hash, var_value_eq> var_value_table;
var_value_table m_var_value_table;
// Set a conflict due to a negative cycle.
void set_conflict();
void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {}
// Create a new theory variable.
th_var mk_var(enode* n) override;
virtual th_var mk_var(expr* n);
void compute_delta();
void found_non_utvpi_expr(expr * n);
bool is_interpreted(app* n) const {
return n->get_family_id() == get_family_id();
}
public:
theory_utvpi(context& ctx);
~theory_utvpi() override;
theory * mk_fresh(context * new_ctx) override;
char const * get_name() const override { return "utvpi-logic"; }
void init() override { init_zero(); }
/**
\brief See comment in theory::mk_eq_atom
*/
app * mk_eq_atom(expr * lhs, expr * rhs) override { return a.mk_eq(lhs, rhs); }
bool internalize_atom(app * atom, bool gate_ctx) override;
bool internalize_term(app * term) override;
void internalize_eq_eh(app * atom, bool_var v) override;
void assign_eh(bool_var v, bool is_true) override;
void new_eq_eh(th_var v1, th_var v2) override {
m_stats.m_num_core2th_eqs++;
m_arith_eq_adapter.new_eq_eh(v1, v2);
}
bool use_diseqs() const override { return true; }
void new_diseq_eh(th_var v1, th_var v2) override {
m_arith_eq_adapter.new_diseq_eh(v1, v2);
}
void push_scope_eh() override;
void pop_scope_eh(unsigned num_scopes) override;
void restart_eh() override {
m_arith_eq_adapter.restart_eh();
}
void relevant_eh(app* e) override {}
void init_search_eh() override {
m_arith_eq_adapter.init_search_eh();
}
final_check_status final_check_eh(unsigned level) override;
bool is_shared(th_var v) const override {
return false;
}
bool can_propagate() override {
SASSERT(m_asserted_qhead <= m_asserted_atoms.size());
return m_asserted_qhead != m_asserted_atoms.size();
}
void propagate() override;
justification * why_is_diseq(th_var v1, th_var v2) override {
UNREACHABLE();
return nullptr;
}
void reset_eh() override;
void init_model(model_generator & m) override;
model_value_proc * mk_value(enode * n, model_generator & mg) override;
void display(std::ostream & out) const override;
void collect_statistics(::statistics & st) const override;
private:
void init_model();
bool assume_eqs_core();
rational mk_value(theory_var v, bool is_int);
bool is_parity_ok(unsigned v) const;
void enforce_parity();
bool eval(expr* e);
void model_validate();
rational eval_num(expr* e);
bool check_z_consistency();
bool has_shared();
virtual void new_eq_eh(th_var v1, th_var v2, justification& j) {
m_stats.m_num_core2th_eqs++;
new_eq_or_diseq(true, v1, v2, j);
}
virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) {
m_stats.m_num_core2th_diseqs++;
new_eq_or_diseq(false, v1, v2, j);
}
void negate(coeffs& coeffs, rational& weight);
numeral mk_weight(bool is_real, bool is_strict, rational const& w) const;
void mk_coeffs(vector<std::pair<expr*,rational> >const& terms, coeffs& coeffs, rational& w);
void del_atoms(unsigned old_size);
bool propagate_atom(atom const& a);
th_var mk_term(app* n);
th_var mk_num(app* n, rational const& r);
bool is_consistent() const;
th_var expand(bool pos, th_var v, rational & k);
void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just);
bool is_int(theory_var v) const { return a.is_int(get_enode(v)->get_expr()); }
th_var get_zero(sort* s) { return a.is_int(s) ? m_izero : m_rzero; }
th_var get_zero(expr* e) { return get_zero(e->get_sort()); }
void init_zero();
void inc_conflicts();
edge_id add_ineq(vector<std::pair<th_var, rational> > const& terms, numeral const& weight, literal l);
bool enable_edge(edge_id id);
th_var to_var(th_var v) const {
return 2*v;
}
th_var from_var(th_var v) const {
return v/2;
}
th_var pos(th_var v) const {
return v & 0xFFFFFFFE;
}
th_var neg(th_var v) const {
return v | 0x1;
}
};
typedef theory_utvpi<rdl_ext> theory_rutvpi;
typedef theory_utvpi<idl_ext> theory_iutvpi;
};