3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-29 11:55:51 +00:00

updates to sorting networks

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-09-23 22:36:19 -05:00
parent 3c4ac9aee5
commit edb3569599
18 changed files with 2070 additions and 170 deletions

View file

@ -24,6 +24,28 @@ Notes:
#ifndef SORTING_NETWORK_H_
#define SORTING_NETWORK_H_
enum sorting_network_encoding {
grouped_at_most_1,
bimander_at_most_1,
ordered_at_most_1
};
inline std::ostream& operator<<(std::ostream& out, sorting_network_encoding enc) {
switch (enc) {
case grouped_at_most_1: return out << "grouped";
case bimander_at_most_1: return out << "bimander";
case ordered_at_most_1: return out << "ordered";
}
return out << "???";
}
struct sorting_network_config {
sorting_network_encoding m_encoding;
sorting_network_config() {
m_encoding = grouped_at_most_1;
}
};
template <typename Ext>
class sorting_network {
typedef typename Ext::vector vect;
@ -88,7 +110,7 @@ Notes:
}
public:
sorting_network(Ext& ext):
sorting_network(Ext& ext):
m_ext(ext),
m_current(&m_currentv),
m_next(&m_nextv)
@ -121,6 +143,7 @@ Notes:
class psort_nw {
typedef typename psort_expr::literal literal;
typedef typename psort_expr::literal_vector literal_vector;
sorting_network_config m_cfg;
class vc {
unsigned v; // number of vertices
@ -185,7 +208,7 @@ Notes:
}
};
psort_nw(psort_expr& c): ctx(c) {}
psort_nw(psort_expr& c, sorting_network_config const& cfg): ctx(c), m_cfg(cfg) {}
literal ge(bool full, unsigned k, unsigned n, literal const* xs) {
if (k > n) {
@ -220,7 +243,17 @@ Notes:
else if (k == 1) {
literal_vector ors;
// scoped_stats _ss(m_stats, k, n);
return mk_at_most_1(full, n, xs, ors, false);
switch (m_cfg.m_encoding) {
case grouped_at_most_1:
return mk_at_most_1(full, n, xs, ors, false);
case bimander_at_most_1:
return mk_at_most_1_bimander(full, n, xs, ors);
case ordered_at_most_1:
return mk_ordered_atmost_1(full, n, xs);
default:
UNREACHABLE();
return xs[0];
}
}
else {
SASSERT(2*k <= n);
@ -278,7 +311,7 @@ Notes:
if (n == 1) {
return ors[0];
}
literal result = fresh();
literal result = fresh("or");
add_implies_or(result, n, ors);
add_or_implies(result, n, ors);
return result;
@ -317,15 +350,26 @@ Notes:
if (ands.size() == 1) {
return ands[0];
}
literal result = fresh();
literal result = fresh("and");
add_implies_and(result, ands);
add_and_implies(result, ands);
return result;
}
literal mk_exactly_1(bool full, unsigned n, literal const* xs) {
TRACE("pb", tout << "exactly 1 with " << n << " arguments " << (full?"full":"not full") << "\n";);
literal_vector ors;
literal r1 = mk_at_most_1(full, n, xs, ors, true);
literal r1;
switch (m_cfg.m_encoding) {
case grouped_at_most_1:
r1 = mk_at_most_1(full, n, xs, ors, true);
break;
case bimander_at_most_1:
r1 = mk_at_most_1_bimander(full, n, xs, ors);
break;
case ordered_at_most_1:
return mk_ordered_exactly_1(full, n, xs);
}
if (full) {
r1 = mk_and(r1, mk_or(ors));
@ -340,12 +384,8 @@ Notes:
TRACE("pb_verbose", tout << (full?"full":"partial") << " ";
for (unsigned i = 0; i < n; ++i) tout << xs[i] << " ";
tout << "\n";);
if (n >= 4 && false) {
return mk_at_most_1_bimander(full, n, xs, ors);
}
literal_vector in(n, xs);
literal result = fresh();
literal result = fresh("at-most-1");
unsigned inc_size = 4;
literal_vector ands;
ands.push_back(result);
@ -387,7 +427,7 @@ Notes:
// xs[0] + ... + xs[n-1] <= 1 => and_x
if (full) {
literal and_i = fresh();
literal and_i = fresh("and");
for (unsigned i = 0; i < n; ++i) {
literal_vector lits;
lits.push_back(and_i);
@ -407,29 +447,6 @@ Notes:
}
#if 0
literal result = fresh();
// result => xs[0] + ... + xs[n-1] <= 1
for (unsigned i = 0; i < n; ++i) {
for (unsigned j = i + 1; j < n; ++j) {
add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j]));
}
}
// xs[0] + ... + xs[n-1] <= 1 => result
for (unsigned i = 0; i < n; ++i) {
literal_vector lits;
lits.push_back(result);
for (unsigned j = 0; j < n; ++j) {
if (j != i) lits.push_back(xs[j]);
}
add_clause(lits);
}
return result;
#endif
#if 1
// r <=> and( or(!xi,!xj))
//
literal_vector ands;
@ -439,30 +456,100 @@ Notes:
}
}
return mk_and(ands);
#else
// r <=> or (and !x_{j != i})
literal_vector ors;
for (unsigned i = 0; i < n; ++i) {
literal_vector ands;
for (unsigned j = 0; j < n; ++j) {
if (j != i) {
ands.push_back(ctx.mk_not(xs[j]));
}
}
ors.push_back(mk_and(ands));
}
return mk_or(ors);
#endif
}
literal mk_ordered_exactly_1(bool full, unsigned n, literal const* xs) {
return mk_ordered_1(full, true, n, xs);
}
literal mk_ordered_atmost_1(bool full, unsigned n, literal const* xs) {
return mk_ordered_1(full, false, n, xs);
}
literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) {
if (n <= 1 && !is_eq) return ctx.mk_true();
if (n == 0) {
return ctx.mk_false();
}
if (n == 1) {
return xs[0];
}
// y0 -> y1
// x0 -> y0
// x1 -> y1
// r, y0 -> ~x1
// r, y1 -> ~x2
// r -> x3 | y1
// r -> ~x3 | ~y1
// x0,x1,x2, .., x_{n-1}, x_n
// y0,y1,y2, .., y_{n-1}
// y_i -> y_{i+1} i = 0, ..., n - 2
// x_i -> y_i i = 0, ..., n - 1
// r, y_i -> ~x_{i+1} i = 0, ..., n - 1
// exactly 1:
// r -> x_n | y_{n-1}
// full (exactly 1):
// two_i -> y_i & x_{i+1}
// zero -> ~x_n
// zero -> ~y_{n-1}
// r | zero | two_0 | ... | two_{n-1}
// full atmost 1:
// r | two | two_0 | ... | two_{n-1}
literal r = fresh("ordered");
literal_vector ys;
for (unsigned i = 0; i + 1 < n; ++i) {
ys.push_back(fresh("y"));
}
for (unsigned i = 0; i + 2 < n; ++i) {
add_clause(ctx.mk_not(ys[i]), ys[i + 1]);
}
for (unsigned i = 0; i + 1 < n; ++i) {
add_clause(ctx.mk_not(xs[i]), ys[i]);
add_clause(ctx.mk_not(r), ctx.mk_not(ys[i]), ctx.mk_not(xs[i + 1]));
}
add_clause(ctx.mk_not(r), ys[n-2], xs[n-1]);
add_clause(ctx.mk_not(r), ctx.mk_not(ys[n-2]), ctx.mk_not(xs[n-1]));
for (unsigned i = 1; i < n - 1; ++i) {
add_clause(ctx.mk_not(ys[i]), xs[i], ys[i-1]);
}
add_clause(ctx.mk_not(ys[0]), xs[0]);
if (full) {
literal_vector twos;
for (unsigned i = 0; i < n - 1; ++i) {
twos.push_back(fresh("two"));
}
add_clause(ctx.mk_not(twos[0]), ys[0]);
add_clause(ctx.mk_not(twos[0]), xs[1]);
for (unsigned i = 1; i < n - 1; ++i) {
add_clause(ctx.mk_not(twos[i]), ys[i], twos[i-1]);
add_clause(ctx.mk_not(twos[i]), xs[i + 1], twos[i-1]);
}
if (is_eq) {
literal zero = fresh("zero");
add_clause(ctx.mk_not(zero), ctx.mk_not(xs[n-1]));
add_clause(ctx.mk_not(zero), ctx.mk_not(ys[n-2]));
add_clause(r, zero, twos.back());
}
else {
add_clause(r, twos.back());
}
}
return r;
}
//
literal mk_at_most_1_bimander(bool full, unsigned n, literal const* xs, literal_vector& ors) {
if (full) {
return mk_at_most_1(full, n, xs, ors, true);
}
literal_vector in(n, xs);
literal result = fresh();
literal result = fresh("bimander");
unsigned inc_size = 2;
literal_vector ands;
for (unsigned i = 0; i < n; i += inc_size) {
@ -477,7 +564,7 @@ Notes:
}
literal_vector bits;
for (unsigned k = 0; k < nbits; ++k) {
bits.push_back(fresh());
bits.push_back(fresh("bit"));
}
for (unsigned i = 0; i < ors.size(); ++i) {
for (unsigned k = 0; k < nbits; ++k) {
@ -539,9 +626,9 @@ Notes:
return ctx.mk_min(a, b);
}
literal fresh() {
literal fresh(char const* n) {
m_stats.m_num_compiled_vars++;
return ctx.fresh();
return ctx.fresh(n);
}
void add_clause(literal l1, literal l2, literal l3) {
literal lits[3] = { l1, l2, l3 };
@ -558,7 +645,6 @@ Notes:
m_stats.m_num_compiled_clauses++;
m_stats.m_num_clause_vars += n;
literal_vector tmp(n, ls);
TRACE("pb_verbose", for (unsigned i = 0; i < n; ++i) tout << ls[i] << " "; tout << "\n";);
ctx.mk_clause(n, tmp.c_ptr());
}
@ -925,7 +1011,7 @@ Notes:
SASSERT(b <= c);
SASSERT(a + b >= c);
for (unsigned i = 0; i < c; ++i) {
out.push_back(fresh());
out.push_back(fresh("dsmerge"));
}
if (m_t != GE) {
for (unsigned i = 0; i < a; ++i) {
@ -983,7 +1069,7 @@ Notes:
SASSERT(m <= n);
literal_vector lits;
for (unsigned i = 0; i < m; ++i) {
out.push_back(fresh());
out.push_back(fresh("dsort"));
}
if (m_t != GE) {
for (unsigned k = 1; k <= m; ++k) {