mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 18:05:21 +00:00
241 lines
8.3 KiB
C++
241 lines
8.3 KiB
C++
/*++
|
|
Copyright (c) 2011 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sat_model_converter.cpp
|
|
|
|
Abstract:
|
|
|
|
Low level model converter for SAT solver.
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2011-05-26.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include"sat_model_converter.h"
|
|
#include"sat_clause.h"
|
|
#include"trace.h"
|
|
|
|
namespace sat {
|
|
|
|
model_converter::model_converter() {
|
|
}
|
|
|
|
model_converter::~model_converter() {
|
|
reset();
|
|
}
|
|
|
|
void model_converter::reset() {
|
|
m_entries.finalize();
|
|
}
|
|
|
|
void model_converter::operator()(model & m) const {
|
|
vector<entry>::const_iterator begin = m_entries.begin();
|
|
vector<entry>::const_iterator it = m_entries.end();
|
|
while (it != begin) {
|
|
--it;
|
|
SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef);
|
|
// if it->get_kind() == BLOCK_LIT, then it might be the case that m[it->var()] != l_undef,
|
|
// and the following procedure flips its value.
|
|
bool sat = false;
|
|
bool var_sign;
|
|
literal_vector::const_iterator it2 = it->m_clauses.begin();
|
|
literal_vector::const_iterator end2 = it->m_clauses.end();
|
|
for (; it2 != end2; ++it2) {
|
|
literal l = *it2;
|
|
if (l == null_literal) {
|
|
// end of clause
|
|
if (!sat) {
|
|
m[it->var()] = var_sign ? l_false : l_true;
|
|
break;
|
|
}
|
|
sat = false;
|
|
continue;
|
|
}
|
|
if (sat)
|
|
continue;
|
|
bool sign = l.sign();
|
|
bool_var v = l.var();
|
|
if (v == it->var())
|
|
var_sign = sign;
|
|
if (value_at(l, m) == l_true)
|
|
sat = true;
|
|
else if (!sat && v != it->var() && m[v] == l_undef) {
|
|
// clause can be satisfied by assigning v.
|
|
m[v] = sign ? l_false : l_true;
|
|
sat = true;
|
|
}
|
|
}
|
|
DEBUG_CODE({
|
|
// all clauses must be satisfied
|
|
bool sat = false;
|
|
it2 = it->m_clauses.begin();
|
|
for (; it2 != end2; ++it2) {
|
|
literal l = *it2;
|
|
if (l == null_literal) {
|
|
SASSERT(sat);
|
|
sat = false;
|
|
continue;
|
|
}
|
|
if (sat)
|
|
continue;
|
|
if (value_at(l, m) == l_true)
|
|
sat = true;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief Test if after applying the model converter, all eliminated clauses are
|
|
satisfied by m.
|
|
*/
|
|
bool model_converter::check_model(model const & m) const {
|
|
bool ok = true;
|
|
vector<entry>::const_iterator begin = m_entries.begin();
|
|
vector<entry>::const_iterator it = m_entries.end();
|
|
while (it != begin) {
|
|
--it;
|
|
bool sat = false;
|
|
literal_vector::const_iterator it2 = it->m_clauses.begin();
|
|
literal_vector::const_iterator itbegin = it2;
|
|
literal_vector::const_iterator end2 = it->m_clauses.end();
|
|
for (; it2 != end2; ++it2) {
|
|
literal l = *it2;
|
|
if (l == null_literal) {
|
|
// end of clause
|
|
if (!sat) {
|
|
TRACE("sat_model_bug", tout << "failed eliminated: " << mk_lits_pp(static_cast<unsigned>(it2 - itbegin), itbegin) << "\n";);
|
|
ok = false;
|
|
}
|
|
sat = false;
|
|
itbegin = it2;
|
|
itbegin++;
|
|
continue;
|
|
}
|
|
if (sat)
|
|
continue;
|
|
if (value_at(l, m) == l_true)
|
|
sat = true;
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
model_converter::entry & model_converter::mk(kind k, bool_var v) {
|
|
m_entries.push_back(entry(k, v));
|
|
entry & e = m_entries.back();
|
|
SASSERT(e.var() == v);
|
|
SASSERT(e.get_kind() == k);
|
|
return e;
|
|
}
|
|
|
|
void model_converter::insert(entry & e, clause const & c) {
|
|
SASSERT(c.contains(e.var()));
|
|
SASSERT(m_entries.begin() <= &e);
|
|
SASSERT(&e < m_entries.end());
|
|
unsigned sz = c.size();
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
e.m_clauses.push_back(c[i]);
|
|
}
|
|
e.m_clauses.push_back(null_literal);
|
|
TRACE("sat_mc_bug", tout << "adding: " << c << "\n";);
|
|
}
|
|
|
|
void model_converter::insert(entry & e, literal l1, literal l2) {
|
|
SASSERT(l1.var() == e.var() || l2.var() == e.var());
|
|
SASSERT(m_entries.begin() <= &e);
|
|
SASSERT(&e < m_entries.end());
|
|
e.m_clauses.push_back(l1);
|
|
e.m_clauses.push_back(l2);
|
|
e.m_clauses.push_back(null_literal);
|
|
TRACE("sat_mc_bug", tout << "adding (binary): " << l1 << " " << l2 << "\n";);
|
|
}
|
|
|
|
void model_converter::insert(entry & e, clause_wrapper const & c) {
|
|
SASSERT(c.contains(e.var()));
|
|
SASSERT(m_entries.begin() <= &e);
|
|
SASSERT(&e < m_entries.end());
|
|
unsigned sz = c.size();
|
|
for (unsigned i = 0; i < sz; i++)
|
|
e.m_clauses.push_back(c[i]);
|
|
e.m_clauses.push_back(null_literal);
|
|
TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (unsigned i = 0; i < c.size(); i++) tout << c[i] << " "; tout << "\n";);
|
|
}
|
|
|
|
bool model_converter::check_invariant(unsigned num_vars) const {
|
|
// After a variable v occurs in an entry n and the entry has kind ELIM_VAR,
|
|
// then the variable must not occur in any other entry occurring after it.
|
|
vector<entry>::const_iterator it = m_entries.begin();
|
|
vector<entry>::const_iterator end = m_entries.end();
|
|
for (; it != end; ++it) {
|
|
SASSERT(it->var() < num_vars);
|
|
if (it->get_kind() == ELIM_VAR) {
|
|
svector<entry>::const_iterator it2 = it;
|
|
it2++;
|
|
for (; it2 != end; ++it2) {
|
|
SASSERT(it2->var() != it->var());
|
|
literal_vector::const_iterator it3 = it2->m_clauses.begin();
|
|
literal_vector::const_iterator end3 = it2->m_clauses.end();
|
|
for (; it3 != end3; ++it3) {
|
|
CTRACE("sat_model_converter", it3->var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout););
|
|
SASSERT(it3->var() != it->var());
|
|
SASSERT(*it3 == null_literal || it3->var() < num_vars);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void model_converter::display(std::ostream & out) const {
|
|
out << "(sat::model-converter";
|
|
vector<entry>::const_iterator it = m_entries.begin();
|
|
vector<entry>::const_iterator end = m_entries.end();
|
|
for (; it != end; ++it) {
|
|
out << "\n (" << (it->get_kind() == ELIM_VAR ? "elim" : "blocked") << " " << it->var();
|
|
bool start = true;
|
|
literal_vector::const_iterator it2 = it->m_clauses.begin();
|
|
literal_vector::const_iterator end2 = it->m_clauses.end();
|
|
for (; it2 != end2; ++it2) {
|
|
if (start) {
|
|
out << "\n (";
|
|
start = false;
|
|
}
|
|
else {
|
|
if (*it2 != null_literal)
|
|
out << " ";
|
|
}
|
|
if (*it2 == null_literal) {
|
|
out << ")";
|
|
start = true;
|
|
continue;
|
|
}
|
|
out << *it2;
|
|
}
|
|
out << ")";
|
|
}
|
|
out << ")\n";
|
|
}
|
|
|
|
void model_converter::copy(model_converter const & src) {
|
|
vector<entry>::const_iterator it = src.m_entries.begin();
|
|
vector<entry>::const_iterator end = src.m_entries.end();
|
|
for (; it != end; ++it)
|
|
m_entries.push_back(*it);
|
|
}
|
|
|
|
void model_converter::collect_vars(bool_var_set & s) const {
|
|
vector<entry>::const_iterator it = m_entries.begin();
|
|
vector<entry>::const_iterator end = m_entries.end();
|
|
for (; it != end; ++it) {
|
|
s.insert(it->m_var);
|
|
}
|
|
}
|
|
|
|
};
|