mirror of
https://github.com/Z3Prover/z3
synced 2025-08-11 05:30:51 +00:00
add Karr linear invariants as transformer
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
3810374cdd
commit
ab73c20757
14 changed files with 830 additions and 56 deletions
612
src/muz_qe/dl_mk_karr_invariants.cpp
Normal file
612
src/muz_qe/dl_mk_karr_invariants.cpp
Normal file
|
@ -0,0 +1,612 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_karr_invariants.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Extract integer linear invariants.
|
||||
|
||||
The linear invariants are extracted according to Karr's method.
|
||||
A short description is in
|
||||
Nikolaj Bjørner, Anca Browne and Zohar Manna. Automatic Generation
|
||||
of Invariants and Intermediate Assertions, in CP 95.
|
||||
|
||||
The algorithm is here adapted to Horn clauses.
|
||||
The idea is to maintain two data-structures for each recursive relation.
|
||||
We call them R and RD
|
||||
- R - set of linear congruences that are true of R.
|
||||
- RD - the dual basis of of solutions for R.
|
||||
|
||||
RD is updated by accumulating basis vectors for solutions
|
||||
to R (the homogeneous dual of R)
|
||||
R is updated from the inhomogeneous dual of RD.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-03-09
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"dl_mk_karr_invariants.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority):
|
||||
rule_transformer::plugin(priority, false),
|
||||
m_ctx(ctx),
|
||||
m(ctx.get_manager()),
|
||||
rm(ctx.get_rule_manager()),
|
||||
a(m) {
|
||||
}
|
||||
|
||||
mk_karr_invariants::~mk_karr_invariants() {
|
||||
obj_map<func_decl, matrix*>::iterator it = m_constraints.begin(), end = m_constraints.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
it = m_dual_constraints.begin();
|
||||
end = m_dual_constraints.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
mk_karr_invariants::matrix& mk_karr_invariants::matrix::operator=(matrix const& other) {
|
||||
reset();
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void mk_karr_invariants::matrix::display(std::ostream& out) const {
|
||||
for (unsigned i = 0; i < A.size(); ++i) {
|
||||
for (unsigned j = 0; j < A[i].size(); ++j) {
|
||||
out << A[i][j] << " ";
|
||||
}
|
||||
out << (eq[i]?" = ":" >= ") << -b[i] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool mk_karr_invariants::is_linear(expr* e, vector<rational>& row, rational& b, rational const& mul) {
|
||||
if (!a.is_int(e)) {
|
||||
return false;
|
||||
}
|
||||
if (is_var(e)) {
|
||||
row[to_var(e)->get_idx()] += mul;
|
||||
return true;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
return false;
|
||||
}
|
||||
rational n;
|
||||
if (a.is_numeral(e, n)) {
|
||||
b += mul*n;
|
||||
return true;
|
||||
}
|
||||
if (a.is_add(e)) {
|
||||
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||
if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
expr* e1, *e2;
|
||||
if (a.is_sub(e, e1, e2)) {
|
||||
return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul);
|
||||
}
|
||||
if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) {
|
||||
return is_linear(e2, row, b, mul*n);
|
||||
}
|
||||
if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) {
|
||||
return is_linear(e1, row, b, mul*n);
|
||||
}
|
||||
if (a.is_uminus(e, e1)) {
|
||||
return is_linear(e1, row, b, -mul);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mk_karr_invariants::matrix* mk_karr_invariants::get_constraints(func_decl* p) {
|
||||
matrix* result = 0;
|
||||
m_constraints.find(p, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
mk_karr_invariants::matrix& mk_karr_invariants::get_dual_constraints(func_decl* p) {
|
||||
matrix* result = 0;
|
||||
if (!m_dual_constraints.find(p, result)) {
|
||||
result = alloc(matrix);
|
||||
m_dual_constraints.insert(p, result);
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
bool mk_karr_invariants::is_eq(expr* e, var*& v, rational& n) {
|
||||
expr* e1, *e2;
|
||||
if (!m.is_eq(e, e1, e2)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_var(e1)) {
|
||||
std::swap(e1, e2);
|
||||
}
|
||||
if (!is_var(e1)) {
|
||||
return false;
|
||||
}
|
||||
v = to_var(e1);
|
||||
if (!a.is_numeral(e2, n)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) {
|
||||
unsigned num_vars = rm.get_var_counter().get_max_var(r)+1;
|
||||
unsigned arity = r.get_decl()->get_arity();
|
||||
unsigned num_columns = arity + num_vars;
|
||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||
unsigned tsz = r.get_tail_size();
|
||||
M.reset();
|
||||
|
||||
for (unsigned i = 0; i < utsz; ++i) {
|
||||
matrix const* Mp = get_constraints(r.get_decl(i));
|
||||
if (!Mp) {
|
||||
return false;
|
||||
}
|
||||
TRACE("dl", Mp->display(tout << "Intersect\n"););
|
||||
intersect_matrix(r.get_tail(i), *Mp, num_columns, M);
|
||||
}
|
||||
|
||||
rational one(1), mone(-1);
|
||||
expr* e1, *e2, *en;
|
||||
var* v, *w;
|
||||
rational n1, n2;
|
||||
expr_ref_vector conjs(m);
|
||||
for (unsigned i = utsz; i < tsz; ++i) {
|
||||
conjs.push_back(r.get_tail(i));
|
||||
}
|
||||
datalog::flatten_and(conjs);
|
||||
|
||||
for (unsigned i = 0; i < conjs.size(); ++i) {
|
||||
expr* e = conjs[i].get();
|
||||
rational b(0);
|
||||
vector<rational> row;
|
||||
row.resize(num_columns, rational(0));
|
||||
bool processed = true;
|
||||
if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) {
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(b);
|
||||
M.eq.push_back(true);
|
||||
}
|
||||
else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) {
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(b);
|
||||
M.eq.push_back(false);
|
||||
}
|
||||
else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) {
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(b + rational(1));
|
||||
M.eq.push_back(false);
|
||||
}
|
||||
else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) {
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(b);
|
||||
M.eq.push_back(false);
|
||||
}
|
||||
else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) {
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(b + rational(1));
|
||||
M.eq.push_back(false);
|
||||
}
|
||||
else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) {
|
||||
if (n1 > n2) {
|
||||
std::swap(n1, n2);
|
||||
}
|
||||
SASSERT(n1 <= n2);
|
||||
row[v->get_idx()] = rational(1);
|
||||
// v - n1 >= 0
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(-n1);
|
||||
M.eq.push_back(false);
|
||||
// -v + n2 >= 0
|
||||
row[v->get_idx()] = rational(-1);
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(n2);
|
||||
M.eq.push_back(false);
|
||||
}
|
||||
else {
|
||||
processed = false;
|
||||
}
|
||||
TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n";);
|
||||
}
|
||||
// intersect with the head predicate.
|
||||
app* head = r.get_head();
|
||||
unsigned sz0 = M.A.size();
|
||||
for (unsigned i = 0; i < arity; ++i) {
|
||||
rational n;
|
||||
expr* arg = head->get_arg(i);
|
||||
if (!a.is_int(arg)) {
|
||||
// no-op
|
||||
}
|
||||
else if (is_var(arg)) {
|
||||
vector<rational> row;
|
||||
row.resize(num_columns, rational(0));
|
||||
unsigned idx = to_var(arg)->get_idx();
|
||||
row[idx] = rational(-1);
|
||||
row[num_vars + i] = rational(1);
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(rational(0));
|
||||
M.eq.push_back(true);
|
||||
}
|
||||
else if (a.is_numeral(arg, n)) {
|
||||
vector<rational> row;
|
||||
row.resize(num_columns, rational(0));
|
||||
row[num_vars + i] = rational(1);
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(-n);
|
||||
M.eq.push_back(true);
|
||||
}
|
||||
else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
if (M.A.size() == sz0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n"););
|
||||
matrix MD;
|
||||
dualizeI(MD, M);
|
||||
M.reset();
|
||||
// project for variables in head.
|
||||
for (unsigned i = 0; i < MD.size(); ++i) {
|
||||
vector<rational> row;
|
||||
row.append(arity, MD.A[i].c_ptr() + num_vars);
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(MD.b[i]);
|
||||
M.eq.push_back(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mk_karr_invariants::intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M) {
|
||||
for (unsigned j = 0; j < Mp.size(); ++j) {
|
||||
rational b = Mp.b[j], n;
|
||||
vector<rational> row;
|
||||
row.resize(num_columns, rational(0));
|
||||
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
||||
expr* arg = p->get_arg(i);
|
||||
if (!a.is_int(arg)) {
|
||||
// no-op
|
||||
}
|
||||
else if (is_var(arg)) {
|
||||
unsigned idx = to_var(arg)->get_idx();
|
||||
row[idx] += Mp.A[j][i];
|
||||
}
|
||||
else if (a.is_numeral(arg, n)) {
|
||||
b += Mp.A[j][i]*n;
|
||||
}
|
||||
else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
M.A.push_back(row);
|
||||
M.b.push_back(b);
|
||||
M.eq.push_back(Mp.eq[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// treat src as a homogeneous matrix.
|
||||
void mk_karr_invariants::dualizeH(matrix& dst, matrix const& src) {
|
||||
dst.reset();
|
||||
if (src.size() == 0) {
|
||||
return;
|
||||
}
|
||||
m_hb.reset();
|
||||
for (unsigned i = 0; i < src.size(); ++i) {
|
||||
vector<rational> v(src.A[i]);
|
||||
v.append(src.b[i]);
|
||||
if (src.eq[i]) {
|
||||
m_hb.add_eq(v, rational(0));
|
||||
}
|
||||
else {
|
||||
m_hb.add_ge(v, rational(0));
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) {
|
||||
m_hb.set_is_int(i);
|
||||
}
|
||||
lbool is_sat = m_hb.saturate();
|
||||
TRACE("dl", m_hb.display(tout););
|
||||
SASSERT(is_sat == l_true);
|
||||
unsigned basis_size = m_hb.get_basis_size();
|
||||
bool first_initial = true;
|
||||
for (unsigned i = 0; i < basis_size; ++i) {
|
||||
bool is_initial;
|
||||
vector<rational> soln;
|
||||
m_hb.get_basis_solution(i, soln, is_initial);
|
||||
if (!is_initial) {
|
||||
dst.b.push_back(soln.back());
|
||||
dst.eq.push_back(true);
|
||||
soln.pop_back();
|
||||
dst.A.push_back(soln);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// treat src as an inhomegeneous matrix.
|
||||
void mk_karr_invariants::dualizeI(matrix& dst, matrix const& src) {
|
||||
m_hb.reset();
|
||||
for (unsigned i = 0; i < src.size(); ++i) {
|
||||
if (src.eq[i]) {
|
||||
m_hb.add_eq(src.A[i], -src.b[i]);
|
||||
}
|
||||
else {
|
||||
m_hb.add_ge(src.A[i], -src.b[i]);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) {
|
||||
m_hb.set_is_int(i);
|
||||
}
|
||||
lbool is_sat = m_hb.saturate();
|
||||
TRACE("dl", m_hb.display(tout););
|
||||
SASSERT(is_sat == l_true);
|
||||
dst.reset();
|
||||
unsigned basis_size = m_hb.get_basis_size();
|
||||
bool first_initial = true;
|
||||
for (unsigned i = 0; i < basis_size; ++i) {
|
||||
bool is_initial;
|
||||
vector<rational> soln;
|
||||
m_hb.get_basis_solution(i, soln, is_initial);
|
||||
if (is_initial && first_initial) {
|
||||
dst.A.push_back(soln);
|
||||
dst.b.push_back(rational(1));
|
||||
dst.eq.push_back(true);
|
||||
first_initial = false;
|
||||
}
|
||||
else if (!is_initial) {
|
||||
dst.A.push_back(soln);
|
||||
dst.b.push_back(rational(0));
|
||||
dst.eq.push_back(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mk_karr_invariants::update_body(rule_set& rules, rule& r){
|
||||
func_decl* p = r.get_decl();
|
||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||
unsigned tsz = r.get_tail_size();
|
||||
app_ref_vector tail(m);
|
||||
for (unsigned i = 0; i < tsz; ++i) {
|
||||
tail.push_back(r.get_tail(i));
|
||||
}
|
||||
for (unsigned i = 0; i < utsz; ++i) {
|
||||
func_decl* q = r.get_decl(i);
|
||||
matrix* N = get_constraints(q);
|
||||
if (!N) {
|
||||
continue;
|
||||
}
|
||||
expr_ref zero(m), lhs(m);
|
||||
zero = a.mk_numeral(rational(0), true);
|
||||
for (unsigned j = 0; j < N->size(); ++j) {
|
||||
rational n;
|
||||
SASSERT(N->A[j].size() == q->get_arity());
|
||||
expr_ref_vector sum(m);
|
||||
for (unsigned k = 0; k < N->A[j].size(); ++k) {
|
||||
n = N->A[j][k];
|
||||
if (!n.is_zero()) {
|
||||
expr* arg = r.get_tail(i)->get_arg(k);
|
||||
sum.push_back(a.mk_mul(a.mk_numeral(n, true), arg));
|
||||
}
|
||||
}
|
||||
n = N->b[j];
|
||||
if (!n.is_zero()) {
|
||||
sum.push_back(a.mk_numeral(n, true));
|
||||
}
|
||||
lhs = a.mk_add(sum.size(), sum.c_ptr());
|
||||
if (N->eq[j]) {
|
||||
tail.push_back(m.mk_eq(lhs, zero));
|
||||
}
|
||||
else {
|
||||
tail.push_back(a.mk_ge(lhs, zero));
|
||||
}
|
||||
}
|
||||
}
|
||||
rule* new_rule = &r;
|
||||
if (tail.size() != tsz) {
|
||||
new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name());
|
||||
}
|
||||
rules.add_rule(new_rule);
|
||||
}
|
||||
|
||||
class mk_karr_invariants::add_invariant_model_converter : public model_converter {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
func_decl_ref_vector m_funcs;
|
||||
ptr_vector<matrix> m_invs;
|
||||
public:
|
||||
|
||||
add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m) {}
|
||||
|
||||
virtual ~add_invariant_model_converter() {
|
||||
for (unsigned i = 0; i < m_invs.size(); ++i) {
|
||||
dealloc(m_invs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void add(func_decl* p, matrix& M) {
|
||||
m_funcs.push_back(p);
|
||||
m_invs.push_back(alloc(matrix, M));
|
||||
}
|
||||
|
||||
virtual void operator()(model_ref & mr) {
|
||||
for (unsigned i = 0; i < m_funcs.size(); ++i) {
|
||||
func_decl* p = m_funcs[i].get();
|
||||
func_interp* f = mr->get_func_interp(p);
|
||||
expr_ref body(m);
|
||||
unsigned arity = p->get_arity();
|
||||
SASSERT(0 < arity);
|
||||
if (f) {
|
||||
matrix const& M = *m_invs[i];
|
||||
mk_body(M, body);
|
||||
SASSERT(f->num_entries() == 0);
|
||||
if (!f->is_partial()) {
|
||||
body = m.mk_and(f->get_else(), body);
|
||||
}
|
||||
}
|
||||
else {
|
||||
f = alloc(func_interp, m, arity);
|
||||
mr->register_decl(p, f);
|
||||
body = m.mk_false(); // fragile: assume that relation was pruned by being infeasible.
|
||||
}
|
||||
f->set_else(body);
|
||||
}
|
||||
}
|
||||
|
||||
virtual model_converter * translate(ast_translation & translator) {
|
||||
add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m);
|
||||
for (unsigned i = 0; i < m_funcs.size(); ++i) {
|
||||
mc->add(translator(m_funcs[i].get()), *m_invs[i]);
|
||||
}
|
||||
return mc;
|
||||
}
|
||||
|
||||
private:
|
||||
void mk_body(matrix const& M, expr_ref& body) {
|
||||
expr_ref_vector conj(m);
|
||||
for (unsigned i = 0; i < M.size(); ++i) {
|
||||
mk_body(M.A[i], M.b[i], M.eq[i], conj);
|
||||
}
|
||||
body = m.mk_and(conj.size(), conj.c_ptr());
|
||||
}
|
||||
|
||||
void mk_body(vector<rational> const& row, rational const& b, bool is_eq, expr_ref_vector& conj) {
|
||||
expr_ref_vector sum(m);
|
||||
expr_ref zero(m), lhs(m);
|
||||
zero = a.mk_numeral(rational(0), true);
|
||||
|
||||
for (unsigned i = 0; i < row.size(); ++i) {
|
||||
if (row[i].is_zero()) {
|
||||
continue;
|
||||
}
|
||||
var* var = m.mk_var(i, a.mk_int());
|
||||
if (row[i].is_one()) {
|
||||
sum.push_back(var);
|
||||
}
|
||||
else {
|
||||
sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var));
|
||||
}
|
||||
}
|
||||
if (!b.is_zero()) {
|
||||
sum.push_back(a.mk_numeral(b, true));
|
||||
}
|
||||
lhs = a.mk_add(sum.size(), sum.c_ptr());
|
||||
if (is_eq) {
|
||||
conj.push_back(m.mk_eq(lhs, zero));
|
||||
}
|
||||
else {
|
||||
conj.push_back(a.mk_ge(lhs, zero));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void mk_karr_invariants::cancel() {
|
||||
rule_transformer::plugin::cancel();
|
||||
m_hb.set_cancel(true);
|
||||
}
|
||||
|
||||
rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
|
||||
if (!m_ctx.get_params().karr()) {
|
||||
return 0;
|
||||
}
|
||||
rule_set::iterator it = source.begin(), end = source.end();
|
||||
for (; it != end; ++it) {
|
||||
rule const& r = **it;
|
||||
if (r.has_negation()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
bool change = true, non_empty = false;
|
||||
while (!m_cancel && change) {
|
||||
change = false;
|
||||
it = source.begin();
|
||||
for (; it != end; ++it) {
|
||||
rule const& r = **it;
|
||||
TRACE("dl", r.display(m_ctx, tout););
|
||||
matrix MD, P;
|
||||
if (!get_transition_relation(r, MD)) {
|
||||
continue;
|
||||
}
|
||||
non_empty = true;
|
||||
func_decl* p = r.get_decl();
|
||||
matrix& ND = get_dual_constraints(p);
|
||||
matrix* N = get_constraints(p);
|
||||
ND.append(MD);
|
||||
dualizeH(P, ND);
|
||||
|
||||
TRACE("dl",
|
||||
MD.display(tout << "MD\n");
|
||||
P.display(tout << "P\n"););
|
||||
|
||||
if (!N) {
|
||||
change = true;
|
||||
N = alloc(matrix, P);
|
||||
m_constraints.insert(p, N);
|
||||
}
|
||||
else if (P.size() != N->size()) {
|
||||
change = true;
|
||||
*N = P;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!non_empty) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_cancel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE("dl",
|
||||
rule_set::decl2rules::iterator git = source.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator gend = source.end_grouped_rules();
|
||||
for (; git != gend; ++git) {
|
||||
func_decl* p = git->m_key;
|
||||
matrix* M = get_constraints(p);
|
||||
tout << p->get_name() << "\n";
|
||||
if (M) {
|
||||
M->display(tout);
|
||||
}
|
||||
});
|
||||
|
||||
rule_set* rules = alloc(rule_set, m_ctx);
|
||||
it = source.begin();
|
||||
for (; it != end; ++it) {
|
||||
update_body(*rules, **it);
|
||||
}
|
||||
if (mc) {
|
||||
add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m);
|
||||
rule_set::decl2rules::iterator git = source.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator gend = source.end_grouped_rules();
|
||||
for (; git != gend; ++git) {
|
||||
func_decl* p = git->m_key;
|
||||
matrix* M = get_constraints(p);
|
||||
if (M) {
|
||||
kmc->add(p, *M);
|
||||
}
|
||||
}
|
||||
mc = concat(mc.get(), kmc);
|
||||
}
|
||||
TRACE("dl", rules->display(tout););
|
||||
return rules;
|
||||
}
|
||||
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue