mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
missing new files
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
c0de1e34ac
commit
a0d52e835b
2 changed files with 452 additions and 0 deletions
356
src/smt/smt_farkas_util.cpp
Normal file
356
src/smt/smt_farkas_util.cpp
Normal file
|
@ -0,0 +1,356 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_farkas_util.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Utility for combining inequalities using coefficients obtained from Farkas lemmas.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorne) 2013-11-2.
|
||||
|
||||
Revision History:
|
||||
|
||||
NB. This utility is specialized to proofs generated by the arithmetic solvers.
|
||||
|
||||
--*/
|
||||
|
||||
#include "smt_farkas_util.h"
|
||||
#include "ast_pp.h"
|
||||
#include "th_rewriter.h"
|
||||
#include "bool_rewriter.h"
|
||||
|
||||
|
||||
namespace smt {
|
||||
|
||||
farkas_util::farkas_util(ast_manager& m):
|
||||
m(m),
|
||||
a(m),
|
||||
m_ineqs(m),
|
||||
m_split_literals(false),
|
||||
m_time(0) {
|
||||
}
|
||||
|
||||
void farkas_util::mk_coerce(expr*& e1, expr*& e2) {
|
||||
if (a.is_int(e1) && a.is_real(e2)) {
|
||||
e1 = a.mk_to_real(e1);
|
||||
}
|
||||
else if (a.is_int(e2) && a.is_real(e1)) {
|
||||
e2 = a.mk_to_real(e2);
|
||||
}
|
||||
}
|
||||
|
||||
// TBD: arith_decl_util now supports coercion, so this should be deprecated.
|
||||
app* farkas_util::mk_add(expr* e1, expr* e2) {
|
||||
mk_coerce(e1, e2);
|
||||
return a.mk_add(e1, e2);
|
||||
}
|
||||
|
||||
app* farkas_util::mk_mul(expr* e1, expr* e2) {
|
||||
mk_coerce(e1, e2);
|
||||
return a.mk_mul(e1, e2);
|
||||
}
|
||||
|
||||
app* farkas_util::mk_le(expr* e1, expr* e2) {
|
||||
mk_coerce(e1, e2);
|
||||
return a.mk_le(e1, e2);
|
||||
}
|
||||
|
||||
app* farkas_util::mk_ge(expr* e1, expr* e2) {
|
||||
mk_coerce(e1, e2);
|
||||
return a.mk_gt(e1, e2);
|
||||
}
|
||||
|
||||
app* farkas_util::mk_gt(expr* e1, expr* e2) {
|
||||
mk_coerce(e1, e2);
|
||||
return a.mk_gt(e1, e2);
|
||||
}
|
||||
|
||||
app* farkas_util::mk_lt(expr* e1, expr* e2) {
|
||||
mk_coerce(e1, e2);
|
||||
return a.mk_lt(e1, e2);
|
||||
}
|
||||
|
||||
void farkas_util::mul(rational const& c, expr* e, expr_ref& res) {
|
||||
expr_ref tmp(m);
|
||||
if (c.is_one()) {
|
||||
tmp = e;
|
||||
}
|
||||
else {
|
||||
tmp = mk_mul(a.mk_numeral(c, c.is_int() && a.is_int(e)), e);
|
||||
}
|
||||
res = mk_add(res, tmp);
|
||||
}
|
||||
|
||||
bool farkas_util::is_int_sort(app* c) {
|
||||
SASSERT(m.is_eq(c) || a.is_le(c) || a.is_lt(c) || a.is_gt(c) || a.is_ge(c));
|
||||
SASSERT(a.is_int(c->get_arg(0)) || a.is_real(c->get_arg(0)));
|
||||
return a.is_int(c->get_arg(0));
|
||||
}
|
||||
|
||||
bool farkas_util::is_int_sort() {
|
||||
SASSERT(!m_ineqs.empty());
|
||||
return is_int_sort(m_ineqs[0].get());
|
||||
}
|
||||
|
||||
void farkas_util::normalize_coeffs() {
|
||||
rational l(1);
|
||||
for (unsigned i = 0; i < m_coeffs.size(); ++i) {
|
||||
l = lcm(l, denominator(m_coeffs[i]));
|
||||
}
|
||||
if (!l.is_one()) {
|
||||
for (unsigned i = 0; i < m_coeffs.size(); ++i) {
|
||||
m_coeffs[i] *= l;
|
||||
}
|
||||
}
|
||||
m_normalize_factor = l;
|
||||
}
|
||||
|
||||
app* farkas_util::mk_one() {
|
||||
return a.mk_numeral(rational(1), true);
|
||||
}
|
||||
|
||||
app* farkas_util::fix_sign(bool is_pos, app* c) {
|
||||
expr* x, *y;
|
||||
SASSERT(m.is_eq(c) || a.is_le(c) || a.is_lt(c) || a.is_gt(c) || a.is_ge(c));
|
||||
bool is_int = is_int_sort(c);
|
||||
if (is_int && is_pos && (a.is_lt(c, x, y) || a.is_gt(c, y, x))) {
|
||||
return mk_le(mk_add(x, mk_one()), y);
|
||||
}
|
||||
if (is_int && !is_pos && (a.is_le(c, x, y) || a.is_ge(c, y, x))) {
|
||||
// !(x <= y) <=> x > y <=> x >= y + 1
|
||||
return mk_ge(x, mk_add(y, mk_one()));
|
||||
}
|
||||
if (is_pos) {
|
||||
return c;
|
||||
}
|
||||
if (a.is_le(c, x, y)) return mk_gt(x, y);
|
||||
if (a.is_lt(c, x, y)) return mk_ge(x, y);
|
||||
if (a.is_ge(c, x, y)) return mk_lt(x, y);
|
||||
if (a.is_gt(c, x, y)) return mk_le(x, y);
|
||||
UNREACHABLE();
|
||||
return c;
|
||||
}
|
||||
|
||||
void farkas_util::partition_ineqs() {
|
||||
m_reps.reset();
|
||||
m_his.reset();
|
||||
++m_time;
|
||||
for (unsigned i = 0; i < m_ineqs.size(); ++i) {
|
||||
m_reps.push_back(process_term(m_ineqs[i].get()));
|
||||
}
|
||||
unsigned head = 0;
|
||||
while (head < m_ineqs.size()) {
|
||||
unsigned r = find(m_reps[head]);
|
||||
unsigned tail = head;
|
||||
for (unsigned i = head+1; i < m_ineqs.size(); ++i) {
|
||||
if (find(m_reps[i]) == r) {
|
||||
++tail;
|
||||
if (tail != i) {
|
||||
SASSERT(tail < i);
|
||||
std::swap(m_reps[tail], m_reps[i]);
|
||||
app_ref tmp(m);
|
||||
tmp = m_ineqs[i].get();
|
||||
m_ineqs[i] = m_ineqs[tail].get();
|
||||
m_ineqs[tail] = tmp;
|
||||
std::swap(m_coeffs[tail], m_coeffs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
head = tail + 1;
|
||||
m_his.push_back(head);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned farkas_util::find(unsigned idx) {
|
||||
if (m_ts.size() <= idx) {
|
||||
m_roots.resize(idx+1);
|
||||
m_size.resize(idx+1);
|
||||
m_ts.resize(idx+1);
|
||||
m_roots[idx] = idx;
|
||||
m_ts[idx] = m_time;
|
||||
m_size[idx] = 1;
|
||||
return idx;
|
||||
}
|
||||
if (m_ts[idx] != m_time) {
|
||||
m_size[idx] = 1;
|
||||
m_ts[idx] = m_time;
|
||||
m_roots[idx] = idx;
|
||||
return idx;
|
||||
}
|
||||
while (true) {
|
||||
if (m_roots[idx] == idx) {
|
||||
return idx;
|
||||
}
|
||||
idx = m_roots[idx];
|
||||
}
|
||||
}
|
||||
|
||||
void farkas_util::merge(unsigned i, unsigned j) {
|
||||
i = find(i);
|
||||
j = find(j);
|
||||
if (i == j) {
|
||||
return;
|
||||
}
|
||||
if (m_size[i] > m_size[j]) {
|
||||
std::swap(i, j);
|
||||
}
|
||||
m_roots[i] = j;
|
||||
m_size[j] += m_size[i];
|
||||
}
|
||||
unsigned farkas_util::process_term(expr* e) {
|
||||
unsigned r = e->get_id();
|
||||
ptr_vector<expr> todo;
|
||||
ast_mark mark;
|
||||
todo.push_back(e);
|
||||
while (!todo.empty()) {
|
||||
e = todo.back();
|
||||
todo.pop_back();
|
||||
if (mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
mark.mark(e, true);
|
||||
if (is_uninterp(e)) {
|
||||
merge(r, e->get_id());
|
||||
}
|
||||
if (is_app(e)) {
|
||||
app* a = to_app(e);
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
todo.push_back(a->get_arg(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
expr_ref farkas_util::extract_consequence(unsigned lo, unsigned hi) {
|
||||
bool is_int = is_int_sort();
|
||||
app_ref zero(a.mk_numeral(rational::zero(), is_int), m);
|
||||
expr_ref res(m);
|
||||
res = zero;
|
||||
bool is_strict = false;
|
||||
bool is_eq = true;
|
||||
expr* x, *y;
|
||||
for (unsigned i = lo; i < hi; ++i) {
|
||||
app* c = m_ineqs[i].get();
|
||||
if (m.is_eq(c, x, y)) {
|
||||
mul(m_coeffs[i], x, res);
|
||||
mul(-m_coeffs[i], y, res);
|
||||
}
|
||||
if (a.is_lt(c, x, y) || a.is_gt(c, y, x)) {
|
||||
mul(m_coeffs[i], x, res);
|
||||
mul(-m_coeffs[i], y, res);
|
||||
is_strict = true;
|
||||
is_eq = false;
|
||||
}
|
||||
if (a.is_le(c, x, y) || a.is_ge(c, y, x)) {
|
||||
mul(m_coeffs[i], x, res);
|
||||
mul(-m_coeffs[i], y, res);
|
||||
is_eq = false;
|
||||
}
|
||||
}
|
||||
|
||||
zero = a.mk_numeral(rational::zero(), a.is_int(res));
|
||||
if (is_eq) {
|
||||
res = m.mk_eq(res, zero);
|
||||
}
|
||||
else if (is_strict) {
|
||||
res = mk_lt(res, zero);
|
||||
}
|
||||
else {
|
||||
res = mk_le(res, zero);
|
||||
}
|
||||
res = m.mk_not(res);
|
||||
th_rewriter rw(m);
|
||||
params_ref params;
|
||||
params.set_bool("gcd_rounding", true);
|
||||
rw.updt_params(params);
|
||||
proof_ref pr(m);
|
||||
expr_ref result(m);
|
||||
rw(res, result, pr);
|
||||
fix_dl(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void farkas_util::fix_dl(expr_ref& r) {
|
||||
expr* e;
|
||||
if (m.is_not(r, e)) {
|
||||
r = e;
|
||||
fix_dl(r);
|
||||
r = m.mk_not(r);
|
||||
return;
|
||||
}
|
||||
expr* e1, *e2, *e3, *e4;
|
||||
if ((m.is_eq(r, e1, e2) || a.is_lt(r, e1, e2) || a.is_gt(r, e1, e2) ||
|
||||
a.is_le(r, e1, e2) || a.is_ge(r, e1, e2))) {
|
||||
if (a.is_add(e1, e3, e4) && a.is_mul(e3)) {
|
||||
r = m.mk_app(to_app(r)->get_decl(), a.mk_add(e4,e3), e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void farkas_util::reset() {
|
||||
m_ineqs.reset();
|
||||
m_coeffs.reset();
|
||||
}
|
||||
|
||||
void farkas_util::add(rational const & coef, app * c) {
|
||||
bool is_pos = true;
|
||||
expr* e;
|
||||
while (m.is_not(c, e)) {
|
||||
is_pos = !is_pos;
|
||||
c = to_app(e);
|
||||
}
|
||||
|
||||
if (!coef.is_zero() && !m.is_true(c)) {
|
||||
m_coeffs.push_back(coef);
|
||||
m_ineqs.push_back(fix_sign(is_pos, c));
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref farkas_util::get() {
|
||||
m_normalize_factor = rational::one();
|
||||
expr_ref res(m);
|
||||
if (m_coeffs.empty()) {
|
||||
res = m.mk_false();
|
||||
return res;
|
||||
}
|
||||
bool is_int = is_int_sort();
|
||||
if (is_int) {
|
||||
normalize_coeffs();
|
||||
}
|
||||
|
||||
if (m_split_literals) {
|
||||
// partition equalities into variable disjoint sets.
|
||||
// take the conjunction of these instead of the
|
||||
// linear combination.
|
||||
partition_ineqs();
|
||||
expr_ref_vector lits(m);
|
||||
unsigned lo = 0;
|
||||
for (unsigned i = 0; i < m_his.size(); ++i) {
|
||||
unsigned hi = m_his[i];
|
||||
lits.push_back(extract_consequence(lo, hi));
|
||||
lo = hi;
|
||||
}
|
||||
bool_rewriter(m).mk_or(lits.size(), lits.c_ptr(), res);
|
||||
IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } });
|
||||
}
|
||||
else {
|
||||
res = extract_consequence(0, m_coeffs.size());
|
||||
}
|
||||
|
||||
TRACE("arith",
|
||||
for (unsigned i = 0; i < m_coeffs.size(); ++i) {
|
||||
tout << m_coeffs[i] << " * (" << mk_pp(m_ineqs[i].get(), m) << ") ";
|
||||
}
|
||||
tout << "\n";
|
||||
tout << res << "\n";
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
96
src/smt/smt_farkas_util.h
Normal file
96
src/smt/smt_farkas_util.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_farkas_util.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Utility for combining inequalities using coefficients obtained from Farkas lemmas.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorne) 2013-11-2.
|
||||
|
||||
Revision History:
|
||||
|
||||
NB. This utility is specialized to proofs generated by the arithmetic solvers.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FARKAS_UTIL_H_
|
||||
#define __FARKAS_UTIL_H_
|
||||
|
||||
#include "arith_decl_plugin.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
class farkas_util {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
app_ref_vector m_ineqs;
|
||||
vector<rational> m_coeffs;
|
||||
rational m_normalize_factor;
|
||||
// utilities for separating coefficients
|
||||
bool m_split_literals;
|
||||
unsigned m_time;
|
||||
unsigned_vector m_roots, m_size, m_his, m_reps, m_ts;
|
||||
|
||||
void mk_coerce(expr*& e1, expr*& e2);
|
||||
app* mk_add(expr* e1, expr* e2);
|
||||
app* mk_mul(expr* e1, expr* e2);
|
||||
app* mk_le(expr* e1, expr* e2);
|
||||
app* mk_ge(expr* e1, expr* e2);
|
||||
app* mk_gt(expr* e1, expr* e2);
|
||||
app* mk_lt(expr* e1, expr* e2);
|
||||
void mul(rational const& c, expr* e, expr_ref& res);
|
||||
bool is_int_sort(app* c);
|
||||
bool is_int_sort();
|
||||
void normalize_coeffs();
|
||||
app* mk_one();
|
||||
app* fix_sign(bool is_pos, app* c);
|
||||
void partition_ineqs();
|
||||
unsigned find(unsigned idx);
|
||||
void merge(unsigned i, unsigned j);
|
||||
unsigned process_term(expr* e);
|
||||
expr_ref extract_consequence(unsigned lo, unsigned hi);
|
||||
void fix_dl(expr_ref& r);
|
||||
|
||||
public:
|
||||
farkas_util(ast_manager& m);
|
||||
|
||||
/**
|
||||
\brief Reset state
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
\brief add a multiple of constraint c to the current state
|
||||
*/
|
||||
void add(rational const & coef, app * c);
|
||||
|
||||
/**
|
||||
\brief Extract the complement of premises multiplied by Farkas coefficients.
|
||||
*/
|
||||
expr_ref get();
|
||||
|
||||
/**
|
||||
\brief Coefficients are normalized for integer problems.
|
||||
Retrieve multiplicant for normalization.
|
||||
*/
|
||||
rational const& get_normalize_factor() const { return m_normalize_factor; }
|
||||
|
||||
/**
|
||||
\brief extract one or multiple consequences based on literal partition.
|
||||
Multiple consequences are strongst modulo a partition of variables.
|
||||
Consequence generation under literal partitioning maintains difference logic constraints.
|
||||
That is, if the original constraints are difference logic, then the consequent
|
||||
produced by literal partitioning is also difference logic.
|
||||
*/
|
||||
void set_split_literals(bool f) { m_split_literals = f; }
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue