3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-11 03:33:35 +00:00
z3/lib/sat_iff3_finder.cpp
Leonardo de Moura e9eab22e5c Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2012-10-02 11:35:25 -07:00

215 lines
7.5 KiB
C++

/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
sat_iff3_finder.cpp
Abstract:
Find constraints of the form x = l1 = l2
That is, search for clauses of the form
~x \/ l1 \/ ~l2
~x \/ ~l1 \/ l2
x \/ l1 \/ l2
x \/ ~l1 \/ ~l2
The basic idea is to sort the watch lists.
This information can be used to propagate equivalences
during probing (and search).
The initial experiments were disappointing.
Not using it on the solver.
Author:
Leonardo de Moura (leonardo) 2011-06-04.
Revision History:
--*/
#include"sat_iff3_finder.h"
#include"sat_solver.h"
namespace sat {
struct iff3_lt {
bool operator()(watched const & w1, watched const & w2) const {
// keep th binary clauses in the beginning
if (w2.is_binary_clause()) return false;
if (w1.is_binary_clause()) return true;
//
if (w2.is_ternary_clause()) {
if (w1.is_ternary_clause()) {
literal l1_1 = w1.get_literal1();
literal l1_2 = w1.get_literal2();
literal l2_1 = w2.get_literal1();
literal l2_2 = w2.get_literal2();
if (l1_1.index() < l2_1.index()) return true;
if (l1_1.index() > l2_1.index()) return false;
return l1_2.index() < l2_2.index();
}
return false;
}
if (w1.is_ternary_clause()) return true;
return false;
}
};
static void unmark(svector<bool> & marks, literal_vector & to_unmark) {
literal_vector::const_iterator it = to_unmark.begin();
literal_vector::const_iterator end = to_unmark.end();
for (; it != end; ++it) {
marks[it->index()] = false;
}
to_unmark.reset();
}
#define SMALL_WLIST 16
/**
\brief Return true if wlist contains (l1, l2)
It assumes wlist have been sorted using iff3_lt
*/
static bool contains(watch_list const & wlist, literal l1, literal l2) {
watched k(l1, l2);
if (wlist.size() < SMALL_WLIST)
return wlist.contains(k);
iff3_lt lt;
int low = 0;
int high = wlist.size();
while (true) {
int mid = low + ((high - low) / 2);
watched const & m = wlist[mid];
if (m == k)
return true;
if (lt(m, k)) {
low = mid + 1;
}
else {
SASSERT(lt(k, m));
high = mid - 1;
}
if (low > high)
return false;
}
}
iff3_finder::iff3_finder(solver & _s):
s(_s) {
}
void iff3_finder::sort_watches() {
vector<watch_list>::iterator it = s.m_watches.begin();
vector<watch_list>::iterator end = s.m_watches.end();
for (; it != end; ++it) {
watch_list & wlist = *it;
std::stable_sort(wlist.begin(), wlist.end(), iff3_lt());
}
}
void iff3_finder::mk_eq(literal l1, literal l2) {
s.mk_clause(l1, ~l2);
s.mk_clause(~l1, l2);
}
void iff3_finder::operator()() {
TRACE("iff3_finder", tout << "starting iff3_finder\n";);
sort_watches();
unsigned counter = 0;
svector<bool> found;
found.resize(s.num_vars()*2, false);
literal_vector to_unmark;
typedef std::pair<literal, literal> lit_pair;
svector<lit_pair> pairs;
for (bool_var x = 0; x < s.num_vars(); x++) {
literal pos_x(x, false);
literal neg_x(x, true);
watch_list & pos_wlist = s.get_wlist(neg_x);
watch_list & neg_wlist = s.get_wlist(pos_x);
//
TRACE("iff3_finder",
tout << "visiting: " << x << "\n";
tout << "pos:\n";
display(tout, s.m_cls_allocator, pos_wlist);
tout << "\nneg:\n";
display(tout, s.m_cls_allocator, neg_wlist);
tout << "\n--------------\n";);
// traverse the ternary clauses x \/ l1 \/ l2
bool_var curr_v1 = null_bool_var;
watch_list::iterator it = pos_wlist.begin();
watch_list::iterator end = pos_wlist.end();
for (; it != end; ++it) {
if (it->is_binary_clause())
continue;
if (it->is_ternary_clause()) {
literal l1 = it->get_literal1();
if (l1.index() < pos_x.index())
break; // stop
literal l2 = it->get_literal2();
bool_var v1 = l1.var();
if (v1 != curr_v1) {
curr_v1 = v1;
unmark(found, to_unmark);
pairs.reset();
}
if (!l1.sign()) {
if (!found[l2.index()]) {
found[l2.index()] = true;
to_unmark.push_back(l2);
}
}
else {
l2.neg();
if (found[l2.index()]) {
// Found clauses x \/ v1 \/ l2 and x \/ ~v1 \/ ~l2
// So, I have to find the clauses
// ~x \/ v1 \/ ~l2
// ~x \/ ~v1 \/ l2
if (contains(neg_wlist, literal(v1, false), ~l2) &&
contains(neg_wlist, literal(v1, true), l2)) {
// found new iff3
// x = v1 = l2
counter++;
// verbose_stream() << counter << ": " << x << " = " << v1 << " = " << l2 << "\n";
TRACE("iff3_finder", tout << counter << ": " << x << " = " << v1 << " = " << l2 << "\n";);
l1.neg();
svector<lit_pair>::iterator it2 = pairs.begin();
svector<lit_pair>::iterator end2 = pairs.end();
for (; it2 != end2; ++it2) {
if (it2->first == l1) {
// l2 == it2->second
mk_eq(l2, it2->second);
}
else if (it2->second == l1) {
// l2 == it2->first
mk_eq(l2, it2->first);
}
else if (it2->first == l2) {
// l1 == it2->second
mk_eq(l1, it2->second);
}
else if (it2->second == l2) {
// l1 == it2->first
mk_eq(l1, it2->first);
}
}
pairs.push_back(lit_pair(l1, l2));
}
}
}
}
else {
break; // stop, no more ternary clauses from this point
}
}
}
}
};