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

401 lines
9.4 KiB
C++

#include <chuffed/core/propagator.h>
#include <chuffed/mip/mip.h>
// sum x_i >= c <- r
// Only use scale and minus views. Absorb offsets into c.
template <int S, int R = 0>
class LinearGE : public Propagator {
vec<int> pos;
vec<IntView<2*S> > x;
vec<IntView<2*S+1> > y;
int const c;
BoolView r;
// persistent data
int fix;
int fix_x;
int fix_y;
int64_t fix_sum;
vec<Lit> ps;
public:
LinearGE(vec<int>& a, vec<IntVar*>& _x, int _c, BoolView _r = bv_true) :
pos(_x.size()), c(_c), r(_r), fix(0), fix_x(0), fix_y(0), fix_sum(-c), ps(R+_x.size()) {
priority = 2;
for (int i = 0; i < _x.size(); i++) {
assert(a[i]);
if (a[i] > 0) {
pos[i] = x.size();
x.push(IntView<2*S>(_x[i], a[i]));
_x[i]->attach(this, i, EVENT_U);
} else {
pos[i] = -y.size()-1;
y.push(IntView<2*S+1>(_x[i], -a[i]));
_x[i]->attach(this, i, EVENT_L);
}
}
if (R) r.attach(this, _x.size(), EVENT_L);
}
void wakeup(int i, int c) {
if (!R || !r.isFalse()) pushInQueue();
}
bool propagate() {
if (R && r.isFalse()) return true;
int64_t max_sum = fix_sum;
for (int i = fix_x; i < x.size(); i++) max_sum += x[i].getMax();
for (int i = fix_y; i < y.size(); i++) max_sum += y[i].getMax();
// if (R && max_sum < 0) setDom2(r, setVal, 0, x.size()+y.size());
if (R && max_sum < 0) {
int64_t v = 0;
if (r.setValNotR(v)) {
Reason expl;
if (so.lazy) {
for (int j = 0; j < x.size(); j++) ps[j+1] = x[j].getMaxLit();
for (int j = 0; j < y.size(); j++) ps[j+1+x.size()] = y[j].getMaxLit();
expl = Reason_new(ps);
}
if (!r.setVal(v, expl)) return false;
}
}
if (R && !r.isTrue()) return true;
// for (int i = fix_x; i < x.size(); i++) {
// setDom2(x[i], setMin, x[i].getMax()-max_sum, i);
// }
// for (int i = fix_y; i < y.size(); i++) {
// setDom2(y[i], setMin, y[i].getMax()-max_sum, x.size()+i);
// }
for (int i = fix_x; i < x.size(); i++) {
int64_t v = x[i].getMax()-max_sum;
if (x[i].setMinNotR(v)) {
Reason expl;
if (so.lazy) {
if (R && r.isFixed()) ps[0] = r.getValLit();
for (int j = 0; j < x.size(); j++) ps[j+R] = x[j].getMaxLit();
for (int j = 0; j < y.size(); j++) ps[j+R+x.size()] = y[j].getMaxLit();
ps[R+i] = ps[0];
expl = Reason_new(ps);
}
if (!x[i].setMin(v, expl)) return false;
}
}
for (int i = fix_y; i < y.size(); i++) {
int64_t v = y[i].getMax()-max_sum;
if (y[i].setMinNotR(v)) {
Reason expl;
if (so.lazy) {
if (R && r.isFixed()) ps[0] = r.getValLit();
for (int j = 0; j < x.size(); j++) ps[j+R] = x[j].getMaxLit();
for (int j = 0; j < y.size(); j++) ps[j+R+x.size()] = y[j].getMaxLit();
ps[R+x.size()+i] = ps[0];
expl = Reason_new(ps);
}
if (!y[i].setMin(v, expl)) return false;
}
}
return true;
}
Clause* explain(Lit p, int inf_id) {
if (inf_id == x.size()+y.size()) inf_id = -1;
if (R && r.isFixed()) ps[0] = r.getValLit();
for (int i = 0; i < x.size(); i++) ps[i+R] = x[i].getMaxLit();
for (int i = 0; i < y.size(); i++) ps[i+R+x.size()] = y[i].getMaxLit();
ps[R+inf_id] = ps[0];
return Reason_new(ps);
}
};
//-----
// sum x_i != c <- r
template <int U, int V, int R = 0>
class LinearNE : public Propagator {
int sp;
int const sz;
IntView<U> * x;
IntView<V> * y;
int const c;
BoolView r;
// persistent state
Tint num_unfixed;
Tint64_t sum_fixed;
public:
LinearNE(vec<int>& a, vec<IntVar*>& _x, int _c, BoolView _r = bv_true) :
sz(_x.size()), c(_c), r(_r), num_unfixed(sz), sum_fixed(-c) {
vec<IntView<0> > w;
for (int i = 0; i < a.size(); i++) {
if (a[i] >= 0) w.push(IntView<0>(_x[i], a[i]));
}
sp = w.size();
for (int i = 0; i < a.size(); i++) {
if (a[i] < 0) w.push(IntView<0>(_x[i], -a[i]));
}
x = (IntView<U> *) (IntView<0> *) w;
y = (IntView<V> *) (IntView<0> *) w;
w.release();
for (int i = 0 ; i < sz; i++) x[i].attach(this, i, EVENT_F);
if (R) r.attach(this, sz, EVENT_L);
// printf("LinearNE: %d %d %d %d %d\n", sp, sz, U, V, R);
}
void wakeup(int i, int c) {
if (i < sz) {
num_unfixed = num_unfixed - 1;
if (i < sp) sum_fixed = sum_fixed + x[i].getVal();
else sum_fixed = sum_fixed + y[i].getVal();
}
if (num_unfixed > 1) return;
if (!R || r.isTrue() || (!r.isFixed() && num_unfixed == 0)) pushInQueue();
}
bool propagate() {
if (R && r.isFalse()) return true;
assert(num_unfixed <= 1);
if (num_unfixed == 0) {
if (sum_fixed == 0) {
Clause *m_r = NULL;
if (so.lazy) {
m_r = Reason_new(sz+1);
for (int i = 0; i < sz; i++) (*m_r)[i+1] = x[i].getValLit();
}
return r.setVal(0, m_r);
}
return true;
}
if (R && !r.isTrue()) return true;
assert(num_unfixed == 1);
int k = 0;
while (x[k].isFixed()) k++;
assert(k < sz);
for (int i = k+1; i < sz; i++) assert(x[i].isFixed());
if ((k < sp && x[k].remValNotR(-sum_fixed)) ||
(k >= sp && y[k].remValNotR(-sum_fixed))) {
Clause *m_r = NULL;
if (so.lazy) {
m_r = Reason_new(sz+R);
for (int i = 0; i < k; i++) (*m_r)[i+1] = x[i].getValLit();
for (int i = k+1; i < sz; i++) (*m_r)[i] = x[i].getValLit();
if (R) (*m_r)[sz] = r.getValLit();
}
if (k < sp) { if (!x[k].remVal(-sum_fixed, m_r)) return false; }
else { if (!y[k].remVal(-sum_fixed, m_r)) return false; }
}
return true;
}
};
//-----
// sum a*x rel c
template <int S>
void int_linear(vec<int>& a, vec<IntVar*>& x, IntRelType t, int c) {
vec<int> b; for (int i = 0; i < a.size(); i++) b.push(-a[i]);
switch (t) {
case IRT_EQ:
int_linear<S>(a, x, IRT_GE, c);
int_linear<S>(b, x, IRT_GE, -c);
return;
case IRT_NE:
new LinearNE<2*S,2*S+1>(a, x, c);
return;
case IRT_LE:
int_linear<S>(b, x, IRT_GE, -c);
return;
case IRT_LT:
int_linear<S>(b, x, IRT_GE, -c+1);
return;
case IRT_GE:
new LinearGE<S>(a, x, c);
break;
case IRT_GT:
int_linear<S>(a, x, IRT_GE, c+1);
return;
default: NEVER;
}
assert(t == IRT_GE);
mip->addConstraint(a, x, c, 1e100);
}
//-----
// sum a*x rel c <-> r
template <int S>
void int_linear_reif(vec<int>& a, vec<IntVar*>& x, IntRelType t, int c, BoolView r) {
vec<int> b; for (int i = 0; i < a.size(); i++) b.push(-a[i]);
switch (t) {
case IRT_EQ:
new LinearGE<S,1>(a, x, c, r);
new LinearGE<S,1>(b, x, -c, r);
new LinearNE<2*S,2*S+1,1>(a, x, c, ~r);
break;
case IRT_NE:
int_linear_reif<S>(a, x, IRT_EQ, c, ~r);
break;
case IRT_LE:
int_linear_reif<S>(b, x, IRT_GE, -c, r);
break;
case IRT_LT:
int_linear_reif<S>(b, x, IRT_GE, -c+1, r);
break;
case IRT_GE:
new LinearGE<S,1>(a, x, c, r);
new LinearGE<S,1>(b, x, -c+1, ~r);
break;
case IRT_GT:
int_linear_reif<S>(a, x, IRT_GE, c+1, r);
break;
default: NEVER;
}
}
// sum a*x rel c <-> r
void int_linear(vec<int>& a, vec<IntVar*>& x, IntRelType t, int c, BoolView r) {
assert(a.size() == x.size());
bool scale = false;
double limit = abs(c);
for (int i = 0; i < x.size(); i++) {
assert(a[i]);
if (a[i] != 1 && a[i] != -1) scale = true;
limit += abs(a[i]) * IntVar::max_limit + INT_MAX;
}
if (limit >= INT64_MAX) CHUFFED_ERROR("Linear constraint may overflow, not yet supported\n");
if (x.size() == 1 && !scale) {
if (r.isTrue()) {
if (a[0] == 1) int_rel(x[0], t, c);
if (a[0] == -1) int_rel(x[0], -t, -c);
} else {
if (a[0] == 1) int_rel_reif(x[0], t, c, r);
if (a[0] == -1) int_rel_reif(x[0], -t, -c, r);
}
return;
}
if (x.size() == 2 && !scale) {
if (r.isTrue()) {
if (a[0] == -1 && a[1] == -1 && t != IRT_NE) {
bin_linear(x[0], x[1], -t, -c);
return;
}
if (a[0] == 1 && a[1] == -1) {
int_rel(x[0], t, x[1], c);
return;
}
if (a[0] == -1 && a[1] == 1) {
int_rel(x[1], t, x[0], c);
return;
}
if (a[0] == 1 && a[1] == 1 && t != IRT_NE) {
bin_linear(x[0], x[1], t, c);
return;
}
} else if (a[0] + a[1] == 0) {
if (a[0] == 1 && a[1] == -1) int_rel_reif(x[0], t, x[1], r, c);
if (a[0] == -1 && a[1] == 1) int_rel_reif(x[1], t, x[0], r, c);
return;
}
}
if (r.isTrue()) {
if (scale) int_linear<1>(a, x, t, c);
else int_linear<0>(a, x, t, c);
} else {
if (scale) int_linear_reif<1>(a, x, t, c, r);
else int_linear_reif<0>(a, x, t, c, r);
}
}
void int_linear(vec<IntVar*>& x, IntRelType t, int c, BoolView r) {
vec<int> a(x.size(),1);
int_linear(a, x, t, c, r);
}
void int_linear(vec<int>& _a, vec<IntVar*>& _x, IntRelType t, IntVar* y, BoolView r) {
vec<int> a;
for (int i = 0; i < _a.size(); i++) a.push(_a[i]);
a.push(-1);
vec<IntVar*> x;
for (int i = 0; i < _x.size(); i++) x.push(_x[i]);
x.push(y);
int_linear(a, x, t, 0, r);
}
void int_linear(vec<IntVar*>& x, IntRelType t, IntVar* y, BoolView r) {
vec<int> a(x.size(),1);
int_linear(a, x, t, y, r);
}
void table_GAC(vec<IntVar*>& x, vec<vec<int> >& t);
// sum a*x = c, propagated to domain consistency using table propagator
void int_linear_dom(vec<int>& a, vec<IntVar*>& x, int c) {
assert(a.size() == 3 && x.size() == 3);
for (int i = 0; i < x.size(); i++) x[i]->specialiseToEL();
vec<vec<int> > t;
for (int i = x[0]->getMin(); i <= x[0]->getMax(); i++) {
if (!x[0]->indomain(i)) continue;
for (int j = x[1]->getMin(); j <= x[1]->getMax(); j++) {
if (!x[1]->indomain(j)) continue;
int k = c - a[0]*i + a[1]*j;
if (k%a[2] != 0) continue;
k /= a[2];
if (!x[2]->indomain(k)) continue;
t.push();
t.last().push(i);
t.last().push(j);
t.last().push(k);
}
}
table_GAC(x, t);
}