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

415 lines
9.1 KiB
C++

#include <chuffed/core/propagator.h>
#include <chuffed/mip/mip.h>
// x >= y <- r
template <int U, int V, int R = 0>
class BinGE : public Propagator {
IntView<U> const x;
IntView<V> const y;
BoolView r;
public:
BinGE(IntView<U> _x, IntView<V> _y, BoolView _r = bv_true) :
x(_x), y(_y), r(_r) {
x.attach(this, 0, EVENT_U);
y.attach(this, 1, EVENT_L);
if (R) r.attach(this, 2, EVENT_L);
}
void wakeup(int i, int c) {
if (!R || !r.isFalse()) pushInQueue();
}
bool propagate() {
if (R && r.isFalse()) return true;
int64_t x_max = x.getMax();
int64_t y_min = y.getMin();
// Can finesse!!
if (R && x_max < y_min) setDom(r, setVal, 0, x.getMaxLit(), y.getMinLit());
if (R && !r.isTrue()) return true;
// Finesses x's lower bound
if (R) setDom(x, setMin, y_min, y.getMinLit(), r.getValLit());
else setDom(x, setMin, y_min, y.getMinLit());
if (R) setDom(y, setMax, x_max, x.getMaxLit(), r.getValLit());
else setDom(y, setMax, x_max, x.getMaxLit());
if (x.getMin() >= y.getMax()) satisfied = true;
return true;
}
int checkSatisfied() {
if (satisfied) return 1;
if (r.isFalse()) { satisfied = true; return 1; }
if (x.getMin() >= y.getMax()) satisfied = true;
return 3;
}
};
//-----
// y != x <- r
template <int U = 0, int V = 0, int R = 0>
class BinNE : public Propagator, public Checker {
public:
IntView<U> x;
IntView<V> y;
BoolView r;
BinNE(IntView<U> _x, IntView<V> _y, BoolView _r = bv_true) :
x(_x), y(_y), r(_r) {
x.attach(this, 0, EVENT_F);
y.attach(this, 1, EVENT_F);
if (R) r.attach(this, 2, EVENT_L);
// printf("BinNE: %d %d %d\n", U, V, R);
}
void wakeup(int i, int c) {
if (!R || !r.isFalse()) pushInQueue();
}
bool propagate() {
if (R && r.isFalse()) return true;
if (x.isFixed() && y.isFixed() && x.getVal() == y.getVal()) {
setDom(r, setVal, 0, x.getValLit(), y.getValLit());
}
if (R && !r.isTrue()) return true;
if (x.isFixed()) {
if (R) setDom(y, remVal, x.getVal(), x.getValLit(), r.getValLit());
else setDom(y, remVal, x.getVal(), x.getValLit());
}
if (y.isFixed()) {
if (R) setDom(x, remVal, y.getVal(), y.getValLit(), r.getValLit());
else setDom(x, remVal, y.getVal(), y.getValLit());
}
return true;
}
bool check() {
if (R) NOT_SUPPORTED;
return (x.getShadowVal() != y.getShadowVal());
}
int checkSatisfied() {
if (satisfied) return 1;
if (r.isFalse()) { satisfied = true; return 1; }
if (x.getMin() > y.getMax() || x.getMax() < y.getMin()) satisfied = true;
return 3;
}
};
//-----
#define BinProp(prop, U, V) \
if (u == U && v == V) { \
if (r.isTrue()) p = new prop<U,V,0>(x,y,r); \
else p = new prop<U,V,1>(x,y,r); \
}
void newBinGE(IntView<> x, IntView<> y, BoolView r = bv_true) {
int u = x.getType(), v = y.getType();
Propagator *p = NULL;
BinProp(BinGE,0,0);
BinProp(BinGE,0,4);
BinProp(BinGE,0,1);
BinProp(BinGE,0,5);
BinProp(BinGE,1,0);
BinProp(BinGE,5,0);
assert(p);
}
void newBinNE(IntView<> x, IntView<> y, BoolView r = bv_true) {
int u = x.getType(), v = y.getType();
Propagator *p = NULL;
BinProp(BinNE,0,0);
BinProp(BinNE,0,4);
assert(p);
}
//-----
// x + y rel c
void bin_linear(IntVar* x, IntVar* y, IntRelType t, int c) {
switch (t) {
case IRT_EQ:
bin_linear(x, y, IRT_LE, c);
bin_linear(x, y, IRT_GE, c);
break;
case IRT_LE:
// x + y <= c <=> (-x+c) >= y
newBinGE(IntView<>(x,-1,c), IntView<>(y));
break;
case IRT_LT:
bin_linear(x, y, IRT_LE, c-1);
break;
case IRT_GE:
// x + y >= c <=> x >= (-y+c)
newBinGE(IntView<>(x), IntView<>(y,-1,c));
break;
case IRT_GT:
bin_linear(x, y, IRT_GE, c+1);
break;
default: NEVER;
}
vec<int> coeffs(2,1);
vec<IntVar*> vars;
vars.push(x); vars.push(y);
switch (t) {
case IRT_EQ:
break;
case IRT_LE:
mip->addConstraint(coeffs, vars, -1e100, c);
break;
case IRT_LT:
break;
case IRT_GE:
mip->addConstraint(coeffs, vars, c, 1e100);
break;
case IRT_GT:
break;
default: NEVER;
}
}
//-----
struct IRR {
IntVar* x; IntRelType t; int c; BoolView r;
IRR(IntVar* _x, IntRelType _t, int _c, BoolView _r) :
x(_x), t(_t), c(_c), r(_r) {}
};
vec<IRR> ircs;
vec<IRR> ihrcs;
//-----
// x rel y + c
void int_rel(IntVar* x, IntRelType t, IntVar* y, int c) {
switch (t) {
case IRT_EQ:
int_rel(x, IRT_LE, y, c);
int_rel(x, IRT_GE, y, c);
break;
case IRT_NE:
newBinNE(IntView<>(x), IntView<>(y,1,c));
break;
case IRT_LE:
// a <= b <=> b >= a
newBinGE(IntView<>(y), IntView<>(x,1,-c));
break;
case IRT_LT:
// a < b <=> b >= (a+1)
newBinGE(IntView<>(y), IntView<>(x,1,1-c));
break;
case IRT_GE:
// a >= b
newBinGE(IntView<>(x), IntView<>(y,1,c));
break;
case IRT_GT:
// a > b <=> a >= (b+1)
newBinGE(IntView<>(x), IntView<>(y,1,1+c));
break;
default: NEVER;
}
vec<int> coeffs;
vec<IntVar*> vars;
coeffs.push(1); coeffs.push(-1);
vars.push(x); vars.push(y);
switch (t) {
case IRT_EQ:
break;
case IRT_NE:
break;
case IRT_LE:
mip->addConstraint(coeffs, vars, -1e100, c);
break;
case IRT_LT:
mip->addConstraint(coeffs, vars, -1e100, c-1);
break;
case IRT_GE:
mip->addConstraint(coeffs, vars, c, 1e100);
break;
case IRT_GT:
mip->addConstraint(coeffs, vars, c+1, 1e100);
break;
default: NEVER;
}
}
//-----
// x rel c
void int_rel(IntVar* x, IntRelType t, int c) {
switch (t) {
case IRT_EQ: TL_SET(x, setVal, c); break;
case IRT_NE: ircs.push(IRR(x, t, c, bv_true)); break;
case IRT_LE: TL_SET(x, setMax, c); break;
case IRT_LT: TL_SET(x, setMax, c-1); break;
case IRT_GE: TL_SET(x, setMin, c); break;
case IRT_GT: TL_SET(x, setMin, c+1); break;
default: NEVER;
}
}
//-----
// x rel y + c <-> r
void int_rel_reif(IntVar* x, IntRelType t, IntVar* y, BoolView r, int c) {
switch (t) {
case IRT_EQ:
newBinGE(IntView<>(x), IntView<>(y,1,c), r);
newBinGE(IntView<>(y), IntView<>(x,1,-c), r);
newBinNE(IntView<>(x), IntView<>(y,1,c), ~r);
break;
case IRT_NE: int_rel_reif(x, IRT_EQ, y, ~r, c); break;
case IRT_LE:
// x <= y <-> r <=> y >= x <- r /\ x >= (y+1) <- !r
newBinGE(IntView<>(y), IntView<>(x,1,-c), r);
newBinGE(IntView<>(x), IntView<>(y,1,1+c), ~r);
break;
case IRT_LT:
// x < y <-> r <=> y >= (x+1) <- r /\ x >= y <- !r
newBinGE(IntView<>(y), IntView<>(x,1,1-c), r);
newBinGE(IntView<>(x), IntView<>(y,1,c), ~r);
break;
case IRT_GE: int_rel_reif(x, IRT_LT, y, ~r, c); break;
case IRT_GT: int_rel_reif(x, IRT_LE, y, ~r, c); break;
default: NEVER;
}
}
//-----
// x rel y + c <- r
void int_rel_half_reif(IntVar* x, IntRelType t, int c, BoolView r) {
ihrcs.push(IRR(x, t, c, r));
}
void int_rel_half_reif(IntVar* x, IntRelType t, IntVar* y, BoolView r, int c) {
switch (t) {
case IRT_EQ:
newBinGE(IntView<>(x), IntView<>(y,1,c), r);
newBinGE(IntView<>(y), IntView<>(x,1,-c), r);
break;
case IRT_NE:
newBinNE(IntView<>(x), IntView<>(y,1,c), r);
break;
case IRT_LE:
newBinGE(IntView<>(y), IntView<>(x,1,-c), r);
break;
case IRT_LT:
newBinGE(IntView<>(y), IntView<>(x,1,1-c), r);
break;
case IRT_GE:
newBinGE(IntView<>(x), IntView<>(y,1,c), r);
break;
case IRT_GT:
newBinGE(IntView<>(x), IntView<>(y,1,1+c), r);
break;
default: NEVER;
}
}
//-----
// x rel c <-> r
void int_rel_reif(IntVar* x, IntRelType t, int c, BoolView r) {
ircs.push(IRR(x, t, c, r));
}
void int_rel_reif_real(IntVar* x, IntRelType t, int c, BoolView r) {
if (r.isTrue() && t == IRT_NE && x->getType() == INT_VAR_EL) {
TL_SET(x, remVal, c); return;
}
if (x->getType() == INT_VAR) {
assert(!so.lazy);
IntVar* v = getConstant(c);
int_rel_reif(x, t, v, r);
return;
}
BoolView b1(x->getLit(c,2)), b2(x->getLit(c,3));
switch (t) {
case IRT_EQ: bool_rel(b1, BRT_AND, b2, r); break;
case IRT_NE: bool_rel(b1, BRT_AND, b2, ~r); break;
case IRT_LE: bool_rel(b2, BRT_EQ, r); break;
case IRT_LT: bool_rel(b1, BRT_EQ, ~r); break;
case IRT_GE: bool_rel(b1, BRT_EQ, r); break;
case IRT_GT: bool_rel(b2, BRT_EQ, ~r); break;
default: NEVER;
}
}
void int_rel_half_reif_real(IntVar* x, IntRelType t, int c, BoolView r) {
if (r.isFalse()) {
return;
}
if (r.isTrue() && t == IRT_NE && x->getType() == INT_VAR_EL) {
TL_SET(x, remVal, c); return;
}
if (x->getType() == INT_VAR) {
assert(!so.lazy);
IntVar* v = getConstant(c);
int_rel_half_reif(x, t, v, r);
return;
}
BoolView b1(x->getLit(c,2)), b2(x->getLit(c,3));
switch (t) {
case IRT_EQ: bool_rel(b2, BRT_OR, ~r); bool_rel(b1, BRT_OR, ~r); break;
case IRT_NE:
{
vec<Lit> ps1; ps1.push(~b1); ps1.push(~b2); ps1.push(~r); sat.addClause(ps1);
vec<Lit> ps2; ps2.push(b1); ps2.push(b2); ps2.push(~r); sat.addClause(ps2);
}
break;
case IRT_LE: bool_rel(b2, BRT_OR, ~r); break;
case IRT_LT: bool_rel(~b1, BRT_OR, ~r); break;
case IRT_GE: bool_rel(b1, BRT_OR, ~r); break;
case IRT_GT: bool_rel(~b2, BRT_OR, ~r); break;
default: NEVER;
}
}
void process_ircs() {
for (int i = 0; i < ircs.size(); i++) {
int_rel_reif_real(ircs[i].x, ircs[i].t, ircs[i].c, ircs[i].r);
}
ircs.clear(true);
for (int j = 0; j < ihrcs.size(); ++j) {
int_rel_half_reif_real(ihrcs[j].x, ihrcs[j].t, ihrcs[j].c, ihrcs[j].r);
}
ihrcs.clear(true);
}