1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker 35a3110598 Squashed 'software/chuffed/' content from commit 2ed0c015
git-subtree-dir: software/chuffed
git-subtree-split: 2ed0c01558d2a5c49c1ce57e048d32c17adf92d3
2021-06-18 09:36:35 +10:00

631 lines
16 KiB
C++

#include <map>
#include <chuffed/core/propagator.h>
// y = a[x-offset]
void array_bool_element(IntVar* _x, vec<bool>& a, BoolView y, int offset) {
_x->specialiseToEL();
IntView<4> x(_x, 1, -offset);
for (int i = 0; i < a.size(); i++) {
sat.addClause(y = a[i], x != i);
}
// Add clause [y != x[i]] \/ [x = i_1] \/ ... \/ [x = i_m]
vec<Lit> ps1;
vec<Lit> ps2;
ps1.push(y);
ps2.push(~y);
for (int i = 0; i < a.size(); i++) {
if (a[i]) ps2.push(x = i);
else ps1.push(x = i);
}
sat.addClause(ps1);
sat.addClause(ps2);
}
//-----
// y = a[x-offset]
void array_int_element(IntVar* _x, vec<int>& a, IntVar* _y, int offset) {
TL_SET(_x, setMin, offset);
TL_SET(_x, setMax, a.size()-1+offset);
vec<int> z;
for (int i = _x->getMin()-offset; i <= _x->getMax()-offset; i++) {
if (!_x->indomain(i+offset)) continue;
if (!_y->indomain(a[i])) continue;
z.push(a[i]);
}
_y->specialiseToSL(z);
_x->specialiseToEL();
IntView<0> y(_y);
IntView<4> x(_x, 1, -offset);
for (int i = 0; i < a.size(); i++) {
sat.addClause(y = a[i], x != i);
}
std::map<int,int> val_to_pss;
// Add clause [y != a[i]] \/ [x = i_1] \/ ... \/ [x = i_m]
vec<vec<Lit> > pss;
for (int i = 0; i < a.size(); i++) {
if (!y.indomain(a[i])) continue;
int index = -1;
std::map<int,int>::iterator it = val_to_pss.find(a[i]);
if (it != val_to_pss.end()) {
index = it->second;
} else {
index = pss.size();
pss.push();
pss[index].push(y != a[i]);
val_to_pss.insert(std::pair<int,int>(a[i], index));
}
if (x.indomain(i)) pss[index].push(x = i);
}
for (int i = 0; i < pss.size(); i++) {
sat.addClause(pss[i]);
}
}
//-----
// y = a[x-offset]
void array_var_bool_element(IntVar* _x, vec<BoolView>& a, BoolView y, int offset) {
_x->specialiseToEL();
IntView<4> x(_x, 1, -offset);
vec<Lit> ps1(a.size()+1);
vec<Lit> ps2(a.size()+1);
// Add clause !y \/ c_1 \/ ... \/ c_n
// Add clause y \/ d_1 \/ ... \/ d_n
ps1[0] = ~y;
ps2[0] = y;
for (int i = 0; i < a.size(); i++) {
BoolView c_i(Lit(sat.newVar(),1));
BoolView d_i(Lit(sat.newVar(),1));
sat.addClause(~c_i, x = i);
sat.addClause(~c_i, a[i]);
sat.addClause(~d_i, x = i);
sat.addClause(~d_i, ~a[i]);
vec<Lit> ps3(3), ps4(3);
ps3[0] = y; ps3[1] = ~a[i]; ps3[2] = (x != i);
sat.addClause(ps3);
ps4[0] = ~y; ps4[1] = a[i]; ps4[2] = (x != i);
sat.addClause(ps4);
ps1[i+1] = c_i;
ps2[i+1] = d_i;
}
sat.addClause(ps1);
sat.addClause(ps2);
}
//-----
// y = a[x]
template <int U = 0, int V = 0, int W = 0>
class IntElemBoundsImp : public Propagator {
BoolView b;
IntView<U> const y;
IntView<V> const x;
vec<IntView<W> > a;
// persistent state
Tchar is_fixed;
Tint min_support;
Tint max_support;
Tint fixed_index;
// intermediate state
bool no_min_support;
bool no_max_support;
public:
IntElemBoundsImp(BoolView _b, IntView<U> _y, IntView<V> _x, vec<IntView<W> >& _a) :
b(_b), y(_y), x(_x), a(_a), is_fixed(false), min_support(-1), max_support(-1), fixed_index(-1),
no_min_support(false), no_max_support(false) {
for (int i = 0; i < a.size(); i++) a[i].attach(this, i, EVENT_LU);
y.attach(this, a.size(), EVENT_LU);
x.attach(this, a.size()+1, EVENT_C);
b.attach(this, a.size()+2, EVENT_F);
}
void wakeup(int i, int c) {
if (i == a.size()+2 && (c & EVENT_F)) {
if (!b.getVal()) {
return;
}
}
if (i == a.size()+1 && (c & EVENT_F)) {
is_fixed = true;
fixed_index = x.getVal();
no_min_support = no_max_support = false;
pushInQueue();
} else if (is_fixed) {
if (i == a.size() || i == fixed_index) pushInQueue();
} else {
if (i < a.size()) {
if (i == min_support && a[i].getMin() > y.getMin()) no_min_support = true;
if (i == max_support && a[i].getMax() < y.getMax()) no_max_support = true;
pushInQueue();
} else if (i == a.size()+1) {
if (!x.indomain(min_support)) { no_min_support = true; pushInQueue(); }
if (!x.indomain(max_support)) { no_max_support = true; pushInQueue(); }
} else pushInQueue();
}
}
bool propagate() {
if (b.isFixed() && b.isFalse()) {
satisfied = true;
return true;
}
// x is out of bounds
if (is_fixed && (fixed_index < 0 || fixed_index >= a.size())) {
return b.setVal(false, x.getValLit());
}
// y = a[fixed_index]
if (is_fixed) {
assert(x.getVal() == fixed_index);
IntView<W>& f = a[fixed_index];
if (b.isFixed()) {
setDom(y, setMin, f.getMin(), Reason_new({b.getValLit(), f.getMinLit(), x.getValLit()}));
setDom(f, setMin, y.getMin(), Reason_new({b.getValLit(), y.getMinLit(), x.getValLit()}));
setDom(y, setMax, f.getMax(), Reason_new({b.getValLit(), f.getMaxLit(), x.getValLit()}));
setDom(f, setMax, y.getMax(), Reason_new({b.getValLit(), y.getMaxLit(), x.getValLit()}));
if (y.isFixed() && f.isFixed()) satisfied = true;
} else if (f.getMin() > y.getMax()) {
Clause* r = Reason_new({x.getValLit(), f.getMinLit(), y.getMaxLit()});
return b.setVal(false, r);
} else if (f.getMax() < y.getMin()) {
Clause* r = Reason_new({x.getValLit(), f.getMaxLit(), y.getMinLit()});
return b.setVal(false, r);
}
return true;
}
if (b.isFixed()) {
for (int i = 0; i < a.size(); i++) {
if (!x.indomain(i)) continue;
if (y.getMax() < a[i].getMin()) {
Clause* r = Reason_new({b.getValLit(), a[i].getMinLit(), y.getMaxLit()});
setDom(x, remVal, i, r);
}
if (y.getMin() > a[i].getMax()) {
Clause* r = Reason_new({b.getValLit(), a[i].getMaxLit(), y.getMinLit()});
setDom(x, remVal, i, r);
}
}
} else {
std::vector<Lit> expl;
bool push_min = false;
bool push_max = false;
int i = 0;
while (i <= a.size()) {
if (!x.indomain(i)) {
expl.push_back(x.getLit(i, 1));
} else if (y.getMax() < a[i].getMin()) {
if (!push_max) {
expl.push_back(y.getMaxLit());
push_max = true;
}
expl.push_back(a[i].getMinLit());
} else if (y.getMin() > a[i].getMax()) {
if (!push_min) {
expl.push_back(y.getMinLit());
push_min = true;
}
expl.push_back(a[i].getMaxLit());
} else {
break;
}
i++;
}
if (i > x.getMax()) {
Clause* r = Reason_new(expl);
return b.setVal(false, r);
}
}
if (no_min_support) {
int64_t old_m = y.getMin();
int64_t new_m = INT64_MAX;
int best = -1;
for (int i = 0; i < a.size(); i++) {
if (!x.indomain(i)) continue;
int64_t cur_m = a[i].getMin();
if (cur_m < new_m) {
best = i;
new_m = cur_m;
if (cur_m <= old_m) break;
}
}
min_support = best;
if (y.setMinNotR(new_m)) {
auto reason = [&] {
Clause *r = NULL;
if (so.lazy) {
r = Reason_new(a.size()+2);
// Finesse lower bounds
for (int i = 0; i < a.size(); i++) {
(*r)[i+2] = x.indomain(i) ? a[i].getFMinLit(new_m) : x.getLit(i, 1);
}
}
return r;
};
if (b.isFixed()) {
Clause* r = reason();
(*r)[1] = b.getValLit();
if (!y.setMin(new_m, r)) {
return false;
}
} else if (y.getMax() < new_m) {
Clause* r = reason();
(*r)[1] = y.getMaxLit();
return b.setVal(false, r);
}
}
no_min_support = false;
}
if (no_max_support) {
int64_t old_m = y.getMax();
int64_t new_m = INT_MIN;
int best = -1;
for (int i = 0; i < a.size(); i++) {
if (!x.indomain(i)) continue;
int64_t cur_m = a[i].getMax();
if (cur_m > new_m) {
best = i;
new_m = cur_m;
if (cur_m >= old_m) break;
}
}
max_support = best;
if (y.setMaxNotR(new_m)) {
auto reason = [&] {
Clause *r = NULL;
if (so.lazy) {
r = Reason_new(a.size()+2);
// Finesse upper bounds
for (int i = 0; i < a.size(); i++) {
(*r)[i+2] = x.indomain(i) ? a[i].getFMaxLit(new_m) : x.getLit(i, 1);
}
}
return r;
};
if (b.isFixed()) {
Clause* r = reason();
(*r)[1] = b.getValLit();
if (!y.setMax(new_m, r)) {
return false;
}
} else if (y.getMin() > new_m) {
Clause* r = reason();
(*r)[1] = y.getMinLit();
return b.setVal(false, r);
}
}
no_max_support = false;
}
return true;
}
void clearPropState() {
in_queue = false;
no_min_support = false;
no_max_support = false;
}
int checkSatisfied() {
if (satisfied) return 1;
if (b.isFixed() && !b.getVal()) {
satisfied = true;
} else if (b.isFixed() && x.isFixed() && y.isFixed() && a[static_cast<int>(x.getVal())].isFixed()) {
satisfied = true;
}
return 3;
}
};
template <int U = 0, int V = 0, int W = 0>
class IntElemBounds : public Propagator {
IntView<U> const y;
IntView<V> const x;
vec<IntView<W> > a;
// persistent state
Tint min_support;
Tint max_support;
Tint fixed_index;
// intermediate state
bool no_min_support;
bool no_max_support;
public:
IntElemBounds(IntView<U> _y, IntView<V> _x, vec<IntView<W> >& _a) :
y(_y), x(_x), a(_a), min_support(-1), max_support(-1), fixed_index(-1),
no_min_support(false), no_max_support(false) {
for (int i = 0; i < a.size(); i++) a[i].attach(this, i, EVENT_LU);
y.attach(this, a.size(), EVENT_LU);
x.attach(this, a.size()+1, EVENT_C);
}
void wakeup(int i, int c) {
if (i == a.size()+1 && (c & EVENT_F)) {
fixed_index = x.getVal();
no_min_support = no_max_support = false;
pushInQueue();
}
if (fixed_index >= 0) {
if (i == a.size() || i == fixed_index) pushInQueue();
} else {
if (i < a.size()) {
if (i == min_support && a[i].getMin() > y.getMin()) no_min_support = true;
if (i == max_support && a[i].getMax() < y.getMax()) no_max_support = true;
pushInQueue();
} else if (i == a.size()+1) {
if (!x.indomain(min_support)) { no_min_support = true; pushInQueue(); }
if (!x.indomain(max_support)) { no_max_support = true; pushInQueue(); }
} else pushInQueue();
}
}
bool propagate() {
// y = a[fixed_index]
if (fixed_index >= 0) {
assert(x.getVal() == fixed_index);
IntView<W>& f = a[fixed_index];
setDom(y, setMin, f.getMin(), f.getMinLit(), x.getValLit());
setDom(f, setMin, y.getMin(), y.getMinLit(), x.getValLit());
setDom(y, setMax, f.getMax(), f.getMaxLit(), x.getValLit());
setDom(f, setMax, y.getMax(), y.getMaxLit(), x.getValLit());
if (y.isFixed() && f.isFixed()) satisfied = true;
return true;
}
for (int i = 0; i < a.size(); i++) {
if (!x.indomain(i)) continue;
if (y.getMax() < a[i].getMin()) setDom(x, remVal, i, y.getMaxLit(), a[i].getMinLit());
if (y.getMin() > a[i].getMax()) setDom(x, remVal, i, y.getMinLit(), a[i].getMaxLit());
}
if (no_min_support) {
int64_t old_m = y.getMin();
int64_t new_m = INT64_MAX;
int best = -1;
for (int i = 0; i < a.size(); i++) {
if (!x.indomain(i)) continue;
int64_t cur_m = a[i].getMin();
if (cur_m < new_m) {
best = i;
new_m = cur_m;
if (cur_m <= old_m) break;
}
}
min_support = best;
if (y.setMinNotR(new_m)) {
Clause *r = NULL;
if (so.lazy) {
r = Reason_new(a.size()+1);
// Finesse lower bounds
for (int i = 0; i < a.size(); i++) {
(*r)[i+1] = x.indomain(i) ? a[i].getFMinLit(new_m) : x.getLit(i, 1);
}
}
if (!y.setMin(new_m, r)) return false;
}
no_min_support = false;
}
if (no_max_support) {
int64_t old_m = y.getMax();
int64_t new_m = INT_MIN;
int best = -1;
for (int i = 0; i < a.size(); i++) {
if (!x.indomain(i)) continue;
int64_t cur_m = a[i].getMax();
if (cur_m > new_m) {
best = i;
new_m = cur_m;
if (cur_m >= old_m) break;
}
}
max_support = best;
if (y.setMaxNotR(new_m)) {
Clause *r = NULL;
if (so.lazy) {
r = Reason_new(a.size()+1);
// Finesse upper bounds
for (int i = 0; i < a.size(); i++) {
(*r)[i+1] = x.indomain(i) ? a[i].getFMaxLit(new_m) : x.getLit(i, 1);
}
}
if (!y.setMax(new_m, r)) return false;
}
no_max_support = false;
}
return true;
}
void clearPropState() {
in_queue = false;
no_min_support = false;
no_max_support = false;
}
int checkSatisfied() {
if (satisfied) return 1;
if (x.isFixed() && y.isFixed() && a[static_cast<int>(x.getVal())].isFixed()) {
satisfied = true;
}
return 3;
}
};
template <int U = 0, int V = 0, int W = 0>
class IntElemDomain : public Propagator {
IntView<U> const y;
IntView<V> const x;
vec<IntView<W> > a;
// persistent state
Tint *num_support;
int **support;
// intermediate state
int *temp_sup;
public:
IntElemDomain(IntView<U> _y, IntView<V> _x, vec<IntView<W> >& _a) :
y(_y), x(_x), a(_a) {
num_support = new Tint[y.getMax()-y.getMin()+1] - y.getMin();
support = new int*[y.getMax()-y.getMin()+1] - y.getMin();
temp_sup = new int[x.getMax()-x.getMin()+1];
vec<int> temp;
for (int v = y.getMin(); v <= y.getMax(); v++) {
temp.clear();
if (y.indomain(v)) {
for (int i = x.getMin(); i <= x.getMax(); i++) {
if (x.indomain(i) && a[i].indomain(v)) temp.push(i);
}
}
num_support[v] = temp.size();
support[v] = new int[temp.size()];
for (int i = 0; i < temp.size(); i++) {
support[v][i] = temp[i];
}
}
for (int i = 0; i < a.size(); i++) a[i].attach(this, i, EVENT_C);
y.attach(this, a.size(), EVENT_C);
x.attach(this, a.size()+1, EVENT_C);
}
bool propagate() {
// propagate holes in y
for (int v = y.getMin(); v <= y.getMax(); v++) {
if (!y.indomain(v)) continue;
int *s = support[v];
int f = 0;
if (num_support[v] > 0) {
if (x.indomain(s[0]) && a[s[0]].indomain(v)) continue;
while (!(x.indomain(s[f]) && a[s[f]].indomain(v)) && ++f < num_support[v]);
}
if (f == num_support[v]) {
// v has no support, remove from y
Clause* r = NULL;
if (so.lazy) {
r = Reason_new(x.getMax() + 4 - x.getMin());
(*r)[1] = x.getMinLit();
(*r)[2] = x.getMaxLit();
for (int i = x.getMin(); i <= x.getMax(); i++) {
//(*r)[3 + i - x.getMin()] = x.indomain(i) ? ~a[i].getLit(v, 0) : ~x.getLit(i, 0);
int reasonIndex = 3 + i - x.getMin();
if(x.indomain(i))
{
Lit l = ~a[i].getLit(v, 0);
(*r)[reasonIndex] = l;
}
else
{
Lit l = ~x.getLit(i, 0);
(*r)[reasonIndex] = l;
}
}
}
if (!y.remVal(v, r)) return false;
} else {
// shift bad supports to back
for (int i = 0; i < f; i++) temp_sup[i] = s[i];
for (int i = f; i < num_support[v]; i++) {
s[i-f] = s[i];
}
s += num_support[v] - f;
for (int i = 0; i < f; i++) s[i] = temp_sup[i];
num_support[v] -= f;
}
}
// propagate holes in x
// just ignore
// propagate holes in a_i
if (x.isFixed()) {
int v = x.getVal();
IntView<W>& f = a[v];
setDom(y, setMin, f.getMin(), f.getMinLit(), x.getValLit());
setDom(f, setMin, y.getMin(), y.getMinLit(), x.getValLit());
setDom(y, setMax, f.getMax(), f.getMaxLit(), x.getValLit());
setDom(f, setMax, y.getMax(), y.getMaxLit(), x.getValLit());
for (typename IntView<W>::iterator i = a[v].begin(); i != a[v].end(); ) {
int w = *i++;
if (!y.indomain(w) && !a[v].remVal(w, so.lazy ? Reason(~y.getLit(w, 0), ~x.getLit(v, 1)) : Reason()))
return false;
}
}
return true;
}
};
// y = a[x-offset]
// bounds consistent version
void array_var_int_element_bound(IntVar* x, vec<IntVar*>& a, IntVar* y, int offset) {
x->specialiseToEL();
vec<IntView<> > w;
for (int i = 0; i < a.size(); i++) w.push(IntView<>(a[i]));
if (offset) new IntElemBounds<0,4,0>(IntView<>(y), IntView<4>(x,1,-offset), w);
else new IntElemBounds<0,0,0>(IntView<>(y), IntView<>(x), w);
}
void array_var_int_element_bound_imp(BoolView b, IntVar* x, vec<IntVar*>& a, IntVar* y, int offset) {
x->specialiseToEL();
vec<IntView<> > w;
for (int i = 0; i < a.size(); i++) w.push(IntView<>(a[i]));
if (offset) new IntElemBoundsImp<0,4,0>(b, IntView<>(y), IntView<4>(x,1,-offset), w);
else new IntElemBoundsImp<0,0,0>(b, IntView<>(y), IntView<>(x), w);
}
// domain consistent version
void array_var_int_element_dom(IntVar* x, vec<IntVar*>& a, IntVar* y, int offset) {
x->initVals();
y->initVals();
vec<IntView<> > w;
for (int i = 0; i < a.size(); i++) {
a[i]->initVals();
w.push(IntView<>(a[i]));
}
if (offset) new IntElemDomain<0,4,0>(IntView<>(y), IntView<4>(x,1,-offset), w);
else new IntElemDomain<0,0,0>(IntView<>(y), IntView<>(x), w);
}