3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 19:05:51 +00:00

Merge branch 'master' into polysat

This commit is contained in:
Jakob Rath 2022-09-23 17:14:26 +02:00
commit 1df749ad33
368 changed files with 12363 additions and 6152 deletions

View file

@ -25,7 +25,7 @@ Revision History:
template<class T>
class positive_boolean_algebra {
public:
virtual ~positive_boolean_algebra() {}
virtual ~positive_boolean_algebra() = default;
virtual T mk_false() = 0;
virtual T mk_true() = 0;
virtual T mk_and(T x, T y) = 0;

View file

@ -19,7 +19,7 @@
Extended Linear Simplification (as exploited in Bosphorus AAAI 2019):
- multiply each polynomial by one variable from their orbits.
- The orbit of a varible are the variables that occur in the same monomial as it in some polynomial.
- The orbit of a variable are the variables that occur in the same monomial as it in some polynomial.
- The extended set of polynomials is fed to a linear Gauss Jordan Eliminator that extracts
additional linear equalities.
- Bosphorus uses M4RI to perform efficient GJE to scale on large bit-matrices.
@ -32,7 +32,7 @@
The method seems rather specific to hardware multipliers so not clear it is useful to
generalize.
- find monomials that contain pairs of vanishing polynomials, transitively
withtout actually inlining.
without actually inlining.
Then color polynomial variables w by p, resp, q if they occur in polynomial equalities
w - r = 0, such that all paths in r contain a node colored by p, resp q.
polynomial variables that get colored by both p and q can be set to 0.

View file

@ -61,8 +61,7 @@ namespace dd {
solver::solver(reslimit& lim, pdd_manager& m) :
m(m),
m_limit(lim),
m_conflict(nullptr)
m_limit(lim)
{}
solver::~solver() {
@ -179,9 +178,8 @@ namespace dd {
set[i]->set_index(j++);
}
~scoped_update() {
for (; i < sz; ++i) {
for (; i < sz; ++i)
nextj();
}
set.shrink(j);
}
};
@ -191,23 +189,24 @@ namespace dd {
equation& target = *set[sr.i];
bool changed_leading_term = false;
bool simplified = true;
simplified = !done() && simplifier(target, changed_leading_term);
simplified = !done() && simplifier(target, changed_leading_term);
if (simplified && is_trivial(target)) {
if (simplified && is_trivial(target))
retire(&target);
}
else if (simplified && check_conflict(target)) {
// pushed to solved
}
else if (simplified && changed_leading_term) {
push_equation(to_simplify, target);
if (!m_var2level.empty()) {
if (&m_to_simplify == &set)
sr.nextj();
else
push_equation(to_simplify, target);
if (!m_var2level.empty())
m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1);
}
}
else {
else
sr.nextj();
}
}
}

View file

@ -121,7 +121,7 @@ private:
vector<std::tuple<unsigned, pdd, u_dependency*>> m_subst;
mutable u_dependency_manager m_dep_manager;
equation_vector m_all_eqs;
equation* m_conflict;
equation* m_conflict = nullptr;
bool m_too_complex;
public:
solver(reslimit& lim, pdd_manager& m);

View file

@ -66,7 +66,7 @@ class heap_trie {
unsigned m_ref;
public:
node(node_t t): m_type(t), m_ref(0) {}
virtual ~node() {}
virtual ~node() = default;
node_t type() const { return m_type; }
void inc_ref() { ++m_ref; }
void dec_ref() { SASSERT(m_ref > 0); --m_ref; }

View file

@ -7,7 +7,7 @@
Abstract:
intervals with depedency tracking.
intervals with dependency tracking.
Author:
Nikolaj Bjorner (nbjorner)

View file

@ -7,7 +7,7 @@
Abstract:
intervals with depedency tracking.
intervals with dependency tracking.
Author:
Nikolaj Bjorner (nbjorner)

View file

@ -518,7 +518,7 @@ std::ostream& emonics::display(std::ostream& out, cell* c) const {
bool emonics::invariant() const {
TRACE("nla_solver_mons", display(tout););
// the varible index contains exactly the active monomials
// the variable index contains exactly the active monomials
unsigned mons = 0;
for (lpvar v = 0; v < m_var2index.size(); v++) {
if (is_monic_var(v)) {
@ -546,6 +546,7 @@ bool emonics::invariant() const {
}
CTRACE("nla_solver_mons", !found, tout << "not found v" << v << ": " << m << "\n";);
SASSERT(found);
(void)found;
c = c->m_next;
}
while (c != ht.m_head);

View file

@ -57,7 +57,7 @@ public:
virtual vector<std::pair<mpq, var_index>> coeffs() const = 0;
lar_base_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) :m_kind(kind), m_right_side(right_side), m_active(false), m_j(j) {}
virtual ~lar_base_constraint() {}
virtual ~lar_base_constraint() = default;
lconstraint_kind kind() const { return m_kind; }
mpq const& rhs() const { return m_right_side; }

View file

@ -93,7 +93,7 @@ class lar_solver : public column_namer {
unsigned_vector m_row_bounds_to_replay;
u_set m_basic_columns_with_changed_cost;
// these are basic columns with the value changed, so the the corresponding row in the tableau
// these are basic columns with the value changed, so the corresponding row in the tableau
// does not sum to zero anymore
u_set m_incorrect_columns;
// copy of m_r_solver.inf_set()

View file

@ -49,7 +49,7 @@ namespace lp_api {
m_constraints[1] = ct;
}
virtual ~bound() {}
virtual ~bound() = default;
theory_var get_var() const { return m_var; }

View file

@ -49,6 +49,7 @@ const char* lp_status_to_string(lp_status status) {
case lp_status::TIME_EXHAUSTED: return "TIME_EXHAUSTED";
case lp_status::EMPTY: return "EMPTY";
case lp_status::UNSTABLE: return "UNSTABLE";
case lp_status::CANCELLED: return "CANCELLED";
default:
lp_unreachable();
}

View file

@ -22,7 +22,7 @@ public:
virtual void set_number_of_rows(unsigned m) = 0;
virtual void set_number_of_columns(unsigned n) = 0;
virtual ~matrix() {}
virtual ~matrix() = default;
bool is_equal(const matrix<T, X>& other);
bool operator == (matrix<T, X> const & other) {

View file

@ -20,7 +20,7 @@ Revision History:
#pragma once
// reads an MPS file reperesenting a Mixed Integer Program
// reads an MPS file representing a Mixed Integer Program
#include <functional>
#include <algorithm>
#include <string>

View file

@ -85,7 +85,7 @@ public:
bool is_scalar() const { return type() == expr_type::SCALAR; }
virtual bool is_pure_monomial() const { return false; }
std::string str() const { std::stringstream ss; print(ss); return ss.str(); }
virtual ~nex() {}
virtual ~nex() = default;
virtual bool contains(lpvar j) const { return false; }
virtual unsigned get_degree() const = 0;
// simplifies the expression and also assigns the address of "this" to *e

View file

@ -45,14 +45,19 @@ namespace nla {
if (is_conflicting())
return;
if (propagate_bounds())
return;
try {
if (propagate_bounds())
return;
if (propagate_eqs())
return;
if (propagate_eqs())
return;
if (propagate_factorization())
return;
if (propagate_factorization())
return;
}
catch (...) {
}
if (quota > 1)
quota--;

View file

@ -37,7 +37,7 @@ public:
virtual void apply_from_left(vector<X> & w, lp_settings & settings) = 0;
virtual void apply_from_right(vector<T> & w) = 0;
virtual void apply_from_right(indexed_vector<T> & w) = 0;
virtual ~tail_matrix() {}
virtual ~tail_matrix() = default;
virtual bool is_dense() const = 0;
struct ref_row {
const tail_matrix & m_A;

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,9 @@ namespace opt {
t_eq,
t_lt,
t_le,
t_mod
t_divides,
t_mod,
t_div
};
@ -48,15 +50,23 @@ namespace opt {
return x.m_id < y.m_id;
}
};
bool operator==(var const& other) const {
return m_id == other.m_id && m_coeff == other.m_coeff;
}
bool operator!=(var const& other) const {
return !(*this == other);
}
};
struct row {
row(): m_type(t_le), m_value(0), m_alive(false) {}
vector<var> m_vars; // variables with coefficients
rational m_coeff; // constant in inequality
rational m_mod; // value the term divide
ineq_type m_type; // inequality type
rational m_value; // value of m_vars + m_coeff under interpretation of m_var2value.
bool m_alive; // rows can be marked dead if they have been processed.
vector<var> m_vars; // variables with coefficients
rational m_coeff = rational::zero(); // constant in inequality
rational m_mod = rational::zero(); // value the term divide
ineq_type m_type = t_le; // inequality type
rational m_value = rational::zero(); // value of m_vars + m_coeff under interpretation of m_var2value.
bool m_alive = false; // rows can be marked dead if they have been processed.
unsigned m_id = UINT_MAX; // variable defined by row (used for mod_t and div_t)
void reset() { m_vars.reset(); m_coeff.reset(); m_value.reset(); }
row& normalize();
@ -85,9 +95,9 @@ namespace opt {
static const unsigned m_objective_id = 0;
vector<unsigned_vector> m_var2row_ids;
vector<rational> m_var2value;
bool_vector m_var2is_int;
bool_vector m_var2is_int;
vector<var> m_new_vars;
unsigned_vector m_lub, m_glb, m_mod;
unsigned_vector m_lub, m_glb, m_divides, m_mod, m_div;
unsigned_vector m_above, m_below;
unsigned_vector m_retired_rows;
@ -114,7 +124,7 @@ namespace opt {
void mul_add(bool same_sign, unsigned row_id1, rational const& c, unsigned row_id2);
void mul_add(unsigned x, rational const& a1, unsigned row_src, rational const& a2, unsigned row_dst);
void mul_add(unsigned x, rational a1, unsigned row_src, rational a2, unsigned row_dst);
void mul(unsigned dst, rational const& c);
@ -122,14 +132,18 @@ namespace opt {
void sub(unsigned dst, rational const& c);
void del_var(unsigned dst, unsigned x);
void set_row(unsigned row_id, vector<var> const& coeffs, rational const& c, rational const& m, ineq_type rel);
void set_row(unsigned row_id, vector<var> const& coeffs, rational const& c, rational const& m, ineq_type rel);
void add_lower_bound(unsigned x, rational const& lo);
void add_constraint(vector<var> const& coeffs, rational const& c, rational const& m, ineq_type r);
void add_upper_bound(unsigned x, rational const& hi);
unsigned add_constraint(vector<var> const& coeffs, rational const& c, rational const& m, ineq_type r, unsigned id);
void replace_var(unsigned row_id, unsigned x, rational const& A, unsigned y, rational const& B);
void replace_var(unsigned row_id, unsigned x, rational const& A, unsigned y, rational const& B, unsigned z);
void replace_var(unsigned row_id, unsigned x, rational const& C);
void normalize(unsigned row_id);
@ -138,7 +152,7 @@ namespace opt {
unsigned new_row();
unsigned copy_row(unsigned row_id);
unsigned copy_row(unsigned row_id, unsigned excl = UINT_MAX);
rational n_sign(rational const& b) const;
@ -150,8 +164,10 @@ namespace opt {
def solve_for(unsigned row_id, unsigned x, bool compute_def);
def solve_mod(unsigned x, unsigned_vector const& mod_rows, bool compute_def);
def solve_divides(unsigned x, unsigned_vector const& divide_rows, bool compute_def);
def solve_mod_div(unsigned x, unsigned_vector const& mod_rows, unsigned_vector const& divide_rows, bool compute_def);
bool is_int(unsigned x) const { return m_var2is_int[x]; }
void retire_row(unsigned row_id);
@ -173,6 +189,17 @@ namespace opt {
// add a divisibility constraint. The row should divide m.
void add_divides(vector<var> const& coeffs, rational const& c, rational const& m);
// add sub-expression for modulus
// v = add_mod(coeffs, m) means
// v = coeffs mod m
unsigned add_mod(vector<var> const& coeffs, rational const& c, rational const& m);
// add sub-expression for div
// v = add_div(coeffs, m) means
// v = coeffs div m
unsigned add_div(vector<var> const& coeffs, rational const& c, rational const& m);
// Set the objective function (linear).
void set_objective(vector<var> const& coeffs, rational const& c);

View file

@ -87,7 +87,7 @@ namespace smt {
m_states(states),
m_enter_id(enter_id) {
}
virtual ~pivot_rule_impl() {}
virtual ~pivot_rule_impl() = default;
virtual bool choose_entering_edge() = 0;
virtual pivot_rule rule() const = 0;
};

View file

@ -41,6 +41,10 @@ namespace simplex {
sparse_matrix_ops::kernel(M, K);
}
void kernel_ffe(sparse_matrix<mpq_ext> &M, vector<vector<rational>> &K) {
sparse_matrix_ops::kernel_ffe(M, K);
}
void ensure_rational_solution(simplex<mpq_ext>& S) {
rational delta(1);
for (unsigned i = 0; i < S.get_num_vars(); ++i) {

View file

@ -203,5 +203,6 @@ namespace simplex {
void ensure_rational_solution(simplex<mpq_ext>& s);
void kernel(sparse_matrix<mpq_ext>& s, vector<vector<rational>>& K);
void kernel_ffe(sparse_matrix<mpq_ext> &s, vector<vector<rational>> &K);
};

View file

@ -168,6 +168,7 @@ namespace simplex {
void add_var(row r, numeral const& n, var_t var);
void add(row r, numeral const& n, row src);
void mul(row r, numeral const& n);
void div(row r, numeral const& n);
void neg(row r);
void del(row r);

View file

@ -432,6 +432,25 @@ namespace simplex {
}
}
/**
\brief Set row <- n/row
*/
template <typename Ext>
void sparse_matrix<Ext>::div(row r, numeral const &n) {
SASSERT(!m.is_zero(n));
if (m.is_one(n)) {
// no op
} else if (m.is_minus_one(n)) {
neg(r);
} else {
row_iterator it = row_begin(r);
row_iterator end = row_end(r);
for (; it != end; ++it) {
m.div(it->m_coeff, n, it->m_coeff);
}
}
}
/**
\brief Delete row.
*/

View file

@ -43,7 +43,7 @@ class sparse_matrix_ops {
for (auto [row, row_entry] : M.get_rows(k)) {
if (c[row.id()] != 0) continue;
auto &m_jk = row_entry->m_coeff;
if (mpq_manager<false>::is_zero(m_jk)) continue;
if (m.is_zero(m_jk)) continue;
// D = rational(-1) / m_jk;
m.set(D, m_jk);
@ -68,9 +68,10 @@ class sparse_matrix_ops {
K.push_back(vector<rational>());
for (unsigned i = 0; i < n_vars; ++i) {
if (d[i] > 0) {
auto r = sparse_matrix<mpq_ext>::row(d[i] - 1);
auto r = typename sparse_matrix<Ext>::row(d[i] - 1);
K.back().push_back(rational(M.get_coeff(r, k)));
} else if (i == k)
}
else if (i == k)
K.back().push_back(rational(1));
else
K.back().push_back(rational(0));
@ -81,5 +82,157 @@ class sparse_matrix_ops {
static void kernel(sparse_matrix<mpq_ext> &M, vector<vector<rational>> &K) {
kernel<mpq_ext>(M, K);
}
/// \brief Kernel computation using fraction-free-elimination
///
template <typename Ext>
static void kernel_ffe(sparse_matrix<Ext> &M, vector<vector<rational>> &K) {
using scoped_numeral = typename Ext::scoped_numeral;
/// Based on George Nakos, Peter R. Turner, Robert M. Williams:
/// Fraction-free algorithms for linear and polynomial equations. SIGSAM
/// Bull. 31(3): 11-19 (1997)
vector<unsigned> d, c;
unsigned n_vars = M.num_vars(), n_rows = M.num_rows();
c.resize(n_rows, 0u);
d.resize(n_vars, 0u);
auto &m = M.get_manager();
scoped_numeral m_ik(m);
scoped_numeral m_jk(m);
scoped_numeral last_pv(m);
m.set(last_pv, 1);
for (unsigned k = 0; k < n_vars; ++k) {
d[k] = 0;
for (auto [row, row_entry] : M.get_rows(k)) {
if (c[row.id()] != 0) continue;
auto &m_jk_ref = row_entry->m_coeff;
if (m.is_zero(m_jk_ref))
// XXX: should not happen, the matrix is sparse
continue;
// this a pivot column
m.set(m_jk, m_jk_ref);
// ensure that pivot is negative
if (m.is_pos(m_jk_ref)) { M.neg(row); }
else { m.neg(m_jk); }
// m_jk is abs(M[j]][k])
for (auto row_i : M.get_rows()) {
if (row_i.id() == row.id()) continue;
m.set(m_ik, M.get_coeff(row_i, k));
// row_i *= m_jk
M.mul(row_i, m_jk);
if (!m.is_zero(m_ik)) {
// row_i += m_ik * row
M.add(row_i, m_ik, row);
}
M.div(row_i, last_pv);
}
c[row.id()] = k + 1;
d[k] = row.id() + 1;
m.set(last_pv, m_jk);
break;
}
}
for (unsigned k = 0; k < n_vars; ++k) {
if (d[k] != 0) continue;
K.push_back(vector<rational>());
for (unsigned i = 0; i < n_vars; ++i) {
if (d[i] > 0) {
auto r = typename sparse_matrix<Ext>::row(d[i] - 1);
K.back().push_back(rational(M.get_coeff(r, k)));
}
else if (i == k)
K.back().push_back(rational(last_pv));
else
K.back().push_back(rational(0));
}
}
}
static void kernel_ffe(sparse_matrix<mpq_ext> &M,
vector<vector<rational>> &K) {
kernel_ffe<mpq_ext>(M, K);
}
template <typename Ext>
static void kernel_ffe(sparse_matrix<Ext> &M, sparse_matrix<Ext> &K,
vector<unsigned> &basics) {
using scoped_numeral = typename Ext::scoped_numeral;
/// Based on George Nakos, Peter R. Turner, Robert M. Williams:
/// Fraction-free algorithms for linear and polynomial equations. SIGSAM
/// Bull. 31(3): 11-19 (1997)
vector<unsigned> d, c;
unsigned n_vars = M.num_vars(), n_rows = M.num_rows();
c.resize(n_rows, 0u);
d.resize(n_vars, 0u);
auto &m = M.get_manager();
scoped_numeral m_ik(m);
scoped_numeral m_jk(m);
scoped_numeral last_pv(m);
m.set(last_pv, 1);
for (unsigned k = 0; k < n_vars; ++k) {
d[k] = 0;
for (auto [row, row_entry] : M.get_rows(k)) {
if (c[row.id()] != 0) continue;
auto &m_jk_ref = row_entry->m_coeff;
if (m.is_zero(m_jk_ref))
// XXX: should not happen, the matrix is sparse
continue;
// this a pivot column
m.set(m_jk, m_jk_ref);
// ensure that pivot is negative
if (m.is_pos(m_jk_ref)) { M.neg(row); }
else { m.neg(m_jk); }
// m_jk is abs(M[j]][k])
for (auto row_i : M.get_rows()) {
if (row_i.id() == row.id()) continue;
m.set(m_ik, M.get_coeff(row_i, k));
// row_i *= m_jk
M.mul(row_i, m_jk);
if (!m.is_zero(m_ik)) {
// row_i += m_ik * row
M.add(row_i, m_ik, row);
}
M.div(row_i, last_pv);
}
c[row.id()] = k + 1;
d[k] = row.id() + 1;
m.set(last_pv, m_jk);
break;
}
}
K.ensure_var(n_vars - 1);
for (unsigned k = 0; k < n_vars; ++k) {
if (d[k] != 0) continue;
auto row = K.mk_row();
basics.push_back(k);
for (unsigned i = 0; i < n_vars; ++i) {
if (d[i] > 0) {
auto r = typename sparse_matrix<Ext>::row(d[i] - 1);
K.add_var(row, M.get_coeff(r, k), i);
}
else if (i == k)
K.add_var(row, last_pv, i);
}
}
}
};
} // namespace simplex

View file

@ -39,7 +39,7 @@ namespace subpaving {
class context {
public:
virtual ~context() {}
virtual ~context() = default;
virtual unsynch_mpq_manager & qm() const = 0;

View file

@ -385,7 +385,7 @@ public:
context_t * m_ctx;
public:
node_selector(context_t * ctx):m_ctx(ctx) {}
virtual ~node_selector() {}
virtual ~node_selector() = default;
context_t * ctx() const { return m_ctx; }
@ -403,7 +403,7 @@ public:
context_t * m_ctx;
public:
var_selector(context_t * ctx):m_ctx(ctx) {}
virtual ~var_selector() {}
virtual ~var_selector() = default;
context_t * ctx() const { return m_ctx; }
@ -436,7 +436,7 @@ public:
context_t * m_ctx;
public:
node_splitter(context_t * ctx):m_ctx(ctx) {}
virtual ~node_splitter() {}
virtual ~node_splitter() = default;
context_t * ctx() const { return m_ctx; }
node * mk_node(node * p) { return ctx()->mk_node(p); }