git-subtree-dir: software/chuffed git-subtree-split: 2ed0c01558d2a5c49c1ce57e048d32c17adf92d3
125 lines
2.7 KiB
C++
125 lines
2.7 KiB
C++
#include <chuffed/core/propagator.h>
|
|
|
|
// y = min(x_i)
|
|
// Bounds propagator, not fully consistent
|
|
|
|
template <int U>
|
|
class Minimum : public Propagator, public Checker {
|
|
public:
|
|
int const sz;
|
|
IntView<U> * const x;
|
|
IntView<U> const y;
|
|
|
|
// Persistent state
|
|
Tint min_max_var;
|
|
Tint64_t min_max;
|
|
Tint64_t min_fixed;
|
|
|
|
// Intermediate state
|
|
bool lower_change;
|
|
|
|
Minimum(vec<IntView<U> > _x, IntView<U> _y) :
|
|
sz(_x.size()), x(_x.release()), y(_y), min_max_var(-1), min_max(INT_MAX),
|
|
min_fixed(INT_MAX), lower_change(false) {
|
|
priority = 1;
|
|
for (int i = 0; i < sz; i++) x[i].attach(this, i, EVENT_LU);
|
|
y.attach(this, sz, EVENT_L);
|
|
}
|
|
|
|
void wakeup(int i, int c) {
|
|
if (i < sz) {
|
|
if (c & EVENT_F) {
|
|
int64_t m = x[i].getVal();
|
|
if (m < min_fixed) min_fixed = m;
|
|
}
|
|
|
|
int64_t m = x[i].getMax();
|
|
if (m < min_max) {
|
|
min_max_var = i;
|
|
min_max = m;
|
|
pushInQueue();
|
|
}
|
|
}
|
|
|
|
if (c & y.getEvent(EVENT_L)) {
|
|
lower_change = true;
|
|
pushInQueue();
|
|
}
|
|
}
|
|
|
|
bool propagate() {
|
|
|
|
// make a less than or equal to min(max(x_i))
|
|
setDom(y, setMax, min_max, x[min_max_var].getMaxLit());
|
|
|
|
if (lower_change) {
|
|
|
|
// make a greater than or equal to min(min(b_i))
|
|
int64_t m = INT64_MAX;
|
|
for (int i = 0; i < sz; i++) {
|
|
int64_t t = x[i].getMin();
|
|
if (t < m) m = t;
|
|
}
|
|
if (y.setMinNotR(m)) {
|
|
Clause *r = NULL;
|
|
if (so.lazy) {
|
|
r = Reason_new(sz+1);
|
|
// Finesse lower bounds
|
|
// Add reason ![y <= m-1] \/ [x_1 <= m-1] \/ ... \/ [x_n <= m-1]
|
|
for (int i = 0; i < sz; i++) (*r)[i+1] = x[i].getFMinLit(m);
|
|
// for (int i = 0; i < sz; i++) (*r)[i+1] = x[i].getLit(m-1, 3);
|
|
}
|
|
if (!y.setMin(m, r)) return false;
|
|
}
|
|
|
|
// make b_i greater than or equal to min(a)
|
|
m = y.getMin();
|
|
Clause *r = NULL;
|
|
if (so.lazy) {
|
|
r = Reason_new(2);
|
|
(*r)[1] = y.getMinLit();
|
|
}
|
|
for (int i = 0; i < sz; i++) {
|
|
if (x[i].setMinNotR(m)) if (!x[i].setMin(m, r)) return false;
|
|
}
|
|
}
|
|
|
|
// Necessary and sufficient conditions for redundancy
|
|
|
|
if (y.getMin() == min_max) satisfied = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
void clearPropState() {
|
|
in_queue = false;
|
|
lower_change = false;
|
|
}
|
|
|
|
bool check() {
|
|
int min = INT_MAX;
|
|
for (int i = 0; i < sz; i++) if (x[i].getShadowVal() < min) min = x[i].getShadowVal();
|
|
return (y.getShadowVal() == min);
|
|
}
|
|
|
|
int checkSatisfied() {
|
|
if (satisfied) return 1;
|
|
if (y.getMin() == min_max) satisfied = true;
|
|
return 2;
|
|
}
|
|
|
|
};
|
|
|
|
void minimum(vec<IntVar*>& x, IntVar* y) {
|
|
vec<IntView<> > w;
|
|
for (int i = 0; i < x.size(); i++) w.push(IntView<>(x[i]));
|
|
new Minimum<0>(w, IntView<>(y));
|
|
}
|
|
|
|
void maximum(vec<IntVar*>& x, IntVar* y) {
|
|
vec<IntView<> > w;
|
|
for (int i = 0; i < x.size(); i++) w.push(IntView<>(x[i]));
|
|
new Minimum<1>(w, IntView<>(y));
|
|
}
|
|
|