git-subtree-dir: software/chuffed git-subtree-split: 2ed0c01558d2a5c49c1ce57e048d32c17adf92d3
727 lines
21 KiB
C++
727 lines
21 KiB
C++
#include <chuffed/core/propagator.h>
|
|
|
|
//-----
|
|
// Absolute propagator
|
|
// y = |x|
|
|
|
|
template <int U = 0, int V = 0>
|
|
class Abs : public Propagator, public Checker {
|
|
public:
|
|
IntView<U> x;
|
|
IntView<V> y;
|
|
|
|
Abs(IntView<U> _x, IntView<V> _y) : x(_x), y(_y) {
|
|
priority = 1;
|
|
x.attach(this, 0, EVENT_LU);
|
|
y.attach(this, 1, EVENT_U);
|
|
}
|
|
|
|
bool propagate() {
|
|
|
|
int64_t l = x.getMin();
|
|
int64_t u = x.getMax();
|
|
|
|
if (l >= 0) {
|
|
setDom(y, setMin, l, x.getMinLit());
|
|
setDom(y, setMax, u, x.getMinLit(), x.getMaxLit());
|
|
} else if (u <= 0) {
|
|
setDom(y, setMin, -u, x.getMaxLit());
|
|
setDom(y, setMax, -l, x.getMaxLit(), x.getMinLit());
|
|
} else {
|
|
// Finesse stronger bound
|
|
int64_t t = (-l > u ? -l : u);
|
|
setDom(y, setMax, t, x.getMaxLit(), x.getMinLit());
|
|
// setDom(y, setMax, t, x.getFMaxLit(t), x.getFMinLit(-t));
|
|
// setDom(y, setMax, t, x.getLit(t+1, 2), x.getLit(-t-1, 3));
|
|
}
|
|
|
|
|
|
setDom(x, setMax, y.getMax(), y.getMaxLit());
|
|
setDom(x, setMin, -y.getMax(), y.getMaxLit());
|
|
|
|
/*
|
|
if (x.isFixed()) {
|
|
if (x.getVal() < 0) {
|
|
setDom(y, setMin, -x.getVal(), x.getMaxLit());
|
|
setDom(y, setMax, -x.getVal(), x.getMinLit());
|
|
} else if (x.getVal() > 0) {
|
|
setDom(y, setMin, x.getVal(), x.getMinLit());
|
|
setDom(y, setMax, x.getVal(), x.getMaxLit());
|
|
} else {
|
|
setDom(y, setVal, 0, x.getMinLit(), x.getMaxLit());
|
|
}
|
|
}
|
|
*/
|
|
|
|
return true;
|
|
}
|
|
|
|
bool check() {
|
|
return ((x.getShadowVal() == y.getShadowVal()) || (x.getShadowVal() == -y.getShadowVal()));
|
|
}
|
|
|
|
};
|
|
|
|
// y = |x|
|
|
|
|
void int_abs(IntVar* x, IntVar* y) {
|
|
int_rel(y, IRT_GE, 0);
|
|
new Abs<>(IntView<>(x), IntView<>(y));
|
|
}
|
|
|
|
|
|
//-----
|
|
// Integer Power propagator
|
|
// z = x ^ y
|
|
|
|
int64_t my_pow(const int64_t base, const int64_t exponent) {
|
|
assert(exponent >= 0);
|
|
if (exponent == 0)
|
|
return 1;
|
|
if (base == 0)
|
|
return 0;
|
|
int64_t z = base;
|
|
for (int i = 1; i < exponent; i++)
|
|
z *= base;
|
|
return z;
|
|
}
|
|
|
|
template <int X = 0, int Y = 0, int Z = 0>
|
|
class PowerPos : public Propagator {
|
|
public:
|
|
IntView<X> x;
|
|
IntView<Y> y;
|
|
IntView<Z> z;
|
|
|
|
PowerPos(IntView<X> _x, IntView<Y> _y, IntView<Z> _z)
|
|
: x(_x), y(_y), z(_z)
|
|
{
|
|
priority = 1;
|
|
assert(x.getMin() >= 0);
|
|
assert(y.getMin() > 0);
|
|
x.attach(this, 0, EVENT_LU);
|
|
y.attach(this, 1, EVENT_LU);
|
|
z.attach(this, 2, EVENT_LU);
|
|
}
|
|
|
|
bool propagate() {
|
|
// Check for case 0
|
|
if (!propagate_case_zero())
|
|
return false;
|
|
// Check for case 1
|
|
if (!propagate_case_one())
|
|
return false;
|
|
// Propagation on z
|
|
if (!propagate_z())
|
|
return false;
|
|
// Propagation on x
|
|
if (!propagate_x())
|
|
return false;
|
|
// Propagation on y
|
|
if (!propagate_y())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// If x = 0 then z = 0. If z = 0 then x = 0.
|
|
bool propagate_case_zero() {
|
|
// x -> z
|
|
if (x.getMax() == 0) {
|
|
setDom(z, setMax, 0, x.getMaxLit());
|
|
}
|
|
// z -> x
|
|
if (z.getMax() == 0) {
|
|
setDom(x, setMax, 0, z.getMaxLit());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// If x = 1 then z = 1. If z = 1 then x = 1.
|
|
bool propagate_case_one() {
|
|
// x -> z
|
|
if (x.getMin() == 1 && x.getMax() == 1) {
|
|
setDom(z, setMax, 1, x.getMinLit(), x.getMaxLit());
|
|
setDom(z, setMin, 1, x.getMinLit(), x.getMaxLit());
|
|
}
|
|
// z -> x
|
|
if (z.getMin() == 1 && z.getMax() == 1) {
|
|
setDom(x, setMax, 1, z.getMinLit(), z.getMaxLit());
|
|
setDom(x, setMin, 1, z.getMinLit(), z.getMaxLit());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Propagation on z
|
|
bool propagate_z() {
|
|
// Propagation on the lower bound
|
|
double z_min_new = pow(x.getMin(), y.getMin());
|
|
if (z_min_new > (double)IntVar::min_limit) {
|
|
setDom(z, setMin, z_min_new, x.getMinLit(), y.getMinLit());
|
|
}
|
|
// Propagation on the upper bound
|
|
double z_max_new = pow(x.getMax(), y.getMax());
|
|
if (z_max_new < (double)IntVar::max_limit) {
|
|
setDom(z, setMax, z_max_new, x.getMaxLit(), y.getMaxLit());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Propagation on x
|
|
bool propagate_x() {
|
|
// Propagation on the lower bound
|
|
double pow_res;
|
|
pow_res = pow(z.getMin(), 1 / (double) y.getMax());
|
|
int64_t x_min_new = ceil(pow_res);
|
|
if (x_min_new > x.getMin()) {
|
|
// Check for numerical errors and correct them
|
|
if (z.getMin() <= my_pow(x_min_new - 1, y.getMax()))
|
|
x_min_new--;
|
|
setDom(x, setMin, x_min_new, z.getMinLit(), y.getMaxLit());
|
|
}
|
|
// Propagation on the upper bound
|
|
pow_res = pow(z.getMax(), 1 / (double) y.getMin());
|
|
int64_t x_max_new = floor(pow_res);
|
|
if (x_max_new < x.getMax()) {
|
|
// Check for numerical errors and correct them
|
|
if (z.getMax() >= my_pow(x_max_new + 1, y.getMin()))
|
|
x_max_new++;
|
|
setDom(x, setMax, x_max_new, z.getMaxLit(), y.getMinLit());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Propagation on y
|
|
bool propagate_y() {
|
|
double log_res;
|
|
// Propagation on the lower bound
|
|
if (z.getMin() > 0 && x.getMax() > 1) {
|
|
log_res = log2(z.getMin()) / log2(x.getMax());
|
|
int64_t y_min_new = ceil(log_res);
|
|
if (y_min_new > y.getMin()) {
|
|
// Check for numerical errors and correct them
|
|
if (z.getMin() <= my_pow(x.getMax(), y_min_new - 1))
|
|
y_min_new--;
|
|
setDom(y, setMin, y_min_new, z.getMinLit(), x.getMaxLit());
|
|
}
|
|
}
|
|
// Propagation on the upper bound
|
|
if (x.getMin() > 1) {
|
|
log_res = log2(z.getMax()) / log2(x.getMin());
|
|
int64_t y_max_new = floor(log_res);
|
|
if (y_max_new < y.getMax()) {
|
|
// Check for numerical errors and correct them
|
|
if (z.getMax() <= my_pow(x.getMin(), y_max_new + 1))
|
|
y_max_new++;
|
|
setDom(x, setMax, y_max_new, z.getMaxLit(), x.getMinLit());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void int_pow(IntVar* x, IntVar* y, IntVar* z) {
|
|
// Since we are dealing with integer the exponent 'y' must be at least -1
|
|
//int_rel(y, IRT_GE, -1);
|
|
if (0 <= x->getMin() && 0 < y->getMin()) {
|
|
int_rel(z, IRT_GE, 0);
|
|
new PowerPos<0,0,0>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
}
|
|
else
|
|
CHUFFED_ERROR("The constraint int_pow is not yet supported for non-negative base and exponent integer!");
|
|
}
|
|
|
|
//-----
|
|
// Times propagator with no assumptions on the variables' bounds
|
|
|
|
// x * y = z
|
|
|
|
template <int X = 0, int Y = 0, int Z = 0>
|
|
class TimesAll : public Propagator {
|
|
public:
|
|
IntView<X> x;
|
|
IntView<Y> y;
|
|
IntView<Z> z;
|
|
|
|
TimesAll(IntView<X> _x, IntView<Y> _y, IntView<Z> _z)
|
|
: x(_x), y(_y), z(_z)
|
|
{
|
|
priority = 1;
|
|
x.attach(this, 0, EVENT_LU);
|
|
y.attach(this, 1, EVENT_LU);
|
|
z.attach(this, 2, EVENT_LU);
|
|
}
|
|
|
|
bool propagate() {
|
|
const int64_t x_min = x.getMin();
|
|
const int64_t x_max = x.getMax();
|
|
const int64_t y_min = y.getMin();
|
|
const int64_t y_max = y.getMax();
|
|
|
|
// Propagating the bounds on z
|
|
if (!propagate_z(x_min, x_max, y_min, y_max))
|
|
return false;
|
|
|
|
const int64_t z_min = z.getMin();
|
|
const int64_t z_max = z.getMax();
|
|
|
|
// Propagating the bounds on x
|
|
if (!propagate_xy(x, y, y_min, y_max, z_min, z_max))
|
|
return false;
|
|
|
|
// Propagating the bounds on y
|
|
if (!propagate_xy(y, x, x_min, x_max, z_min, z_max))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Propagation on the bounds of z
|
|
bool propagate_z(const int64_t x_min, const int64_t x_max, const int64_t y_min, const int64_t y_max) {
|
|
// Computing all possible extreme points of x * y
|
|
int64_t prod_min_min = x_min * y_min;
|
|
int64_t prod_min_max = x_min * y_max;
|
|
int64_t prod_max_min = x_max * y_min;
|
|
int64_t prod_max_max = x_max * y_max;
|
|
|
|
// New lower bound on z
|
|
int64_t z_min_new = std::min(prod_min_min, prod_min_max);
|
|
z_min_new = std::min(z_min_new, prod_max_min);
|
|
z_min_new = std::min(z_min_new, prod_max_max);
|
|
|
|
if (z_min_new > IntVar::min_limit) {
|
|
// TODO Better explanation
|
|
Clause * reason = Reason_new(5);
|
|
(*reason)[1] = x.getMinLit();
|
|
(*reason)[2] = x.getMaxLit();
|
|
(*reason)[3] = y.getMinLit();
|
|
(*reason)[4] = y.getMaxLit();
|
|
setDom(z, setMin, z_min_new, reason);
|
|
}
|
|
|
|
// New upper bound on z
|
|
int64_t z_max_new = std::max(prod_min_min, prod_min_max);
|
|
z_max_new = std::max(z_max_new, prod_max_min);
|
|
z_max_new = std::max(z_max_new, prod_max_max);
|
|
|
|
if (z_max_new < IntVar::max_limit) {
|
|
// TODO Better explanation
|
|
Clause * reason = Reason_new(5);
|
|
(*reason)[1] = x.getMinLit();
|
|
(*reason)[2] = x.getMaxLit();
|
|
(*reason)[3] = y.getMinLit();
|
|
(*reason)[4] = y.getMaxLit();
|
|
setDom(z, setMax, z_max_new, reason);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <int U, int V>
|
|
bool propagate_xy(IntView<U> u, IntView<V> v, const int64_t v_min, const int64_t v_max, const int64_t z_min, const int64_t z_max) {
|
|
if (z_min == 0 && z_max == 0) {
|
|
// The product z equals to 0. Then x must equal to 0 too if y cannot be 0.
|
|
if (v_min > 0 || v_max < 0) {
|
|
// TODO Better explanation
|
|
Clause * reason = Reason_new(5);
|
|
(*reason)[1] = v.getMinLit();
|
|
(*reason)[2] = v.getMaxLit();
|
|
(*reason)[3] = z.getMinLit();
|
|
(*reason)[4] = z.getMaxLit();
|
|
setDom(u, setMin, 0, reason);
|
|
setDom(u, setMax, 0, reason);
|
|
}
|
|
}
|
|
else if (z_min > 0) {
|
|
if (v_min == 0) {
|
|
// TODO Better explanation
|
|
setDom(v, setMin, 1, z.getMinLit());
|
|
}
|
|
else if (v_max == 0) {
|
|
// TODO Better explanation
|
|
setDom(v, setMax, -1, z.getMinLit());
|
|
}
|
|
else {
|
|
if (!propagate_xy_min(u, v, v_min, v_max, z_min, z_max))
|
|
return false;
|
|
if (!propagate_xy_max(u, v, v_min, v_max, z_min, z_max))
|
|
return false;
|
|
}
|
|
}
|
|
else if (z_max < 0) {
|
|
if (v_min == 0) {
|
|
// TODO Better explanation
|
|
setDom(v, setMin, 1, z.getMaxLit());
|
|
}
|
|
else if (v_max == 0) {
|
|
// TODO Better explanation
|
|
setDom(v, setMax, -1, z.getMaxLit());
|
|
}
|
|
else {
|
|
if (!propagate_xy_min(u, v, v_min, v_max, z_min, z_max))
|
|
return false;
|
|
if (!propagate_xy_max(u, v, v_min, v_max, z_min, z_max))
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <int U, int V>
|
|
bool propagate_xy_min(IntView<U> u, IntView<V> v, const int64_t v_min, const int64_t v_max, const int64_t z_min, const int64_t z_max) {
|
|
assert(z_min > 0 || z_max < 0);
|
|
assert(v_min != 0 && v_max != 0);
|
|
// The product z cannot be 0. Then x and y cannot be 0, too.
|
|
// x >= ceil(z / y)
|
|
int64_t u_min_new = 0;
|
|
if (v_max < 0) {
|
|
// Integer variable v is negative
|
|
if (z_min > 0) {
|
|
// Integer variable z is positive
|
|
u_min_new = (z_max - v_max - 1) / v_max;
|
|
}
|
|
else {
|
|
// Integer variable z is negative
|
|
u_min_new = (-z_max - v_min - 1) / -v_min;
|
|
}
|
|
}
|
|
else if (v_min > 0) {
|
|
// Integer variable is positive
|
|
if (z_min > 0) {
|
|
// Integer variable z is positive
|
|
u_min_new = (z_min + v_max - 1) / v_max;
|
|
}
|
|
else {
|
|
// Integer variable z is negative
|
|
u_min_new = (-z_min + v_min - 1) / -v_min;
|
|
}
|
|
}
|
|
else {
|
|
// The domain of integer variable v contains -1 and 1
|
|
u_min_new = std::min(-1 * z_min, z_min);
|
|
u_min_new = std::min(u_min_new, z_max);
|
|
u_min_new = std::min(u_min_new, -1 * z_max);
|
|
}
|
|
|
|
if (u_min_new > u.getMin()) {
|
|
// TODO Better explanation
|
|
Clause * reason = Reason_new(5);
|
|
(*reason)[1] = v.getMinLit();
|
|
(*reason)[2] = v.getMaxLit();
|
|
(*reason)[3] = z.getMinLit();
|
|
(*reason)[4] = z.getMaxLit();
|
|
setDom(u, setMin, (u_min_new == 0 ? 1 : u_min_new), reason);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <int U, int V>
|
|
bool propagate_xy_max(IntView<U> u, IntView<V> v, const int64_t v_min, const int64_t v_max, const int64_t z_min, const int64_t z_max) {
|
|
assert(z_min > 0 || z_max < 0);
|
|
assert(v_min != 0 && v_max != 0);
|
|
// The product z cannot be 0. Then x and y cannot be 0, too.
|
|
// u <= floor(z / v)
|
|
int64_t u_max_new = 0;
|
|
if (v_min < 0 && v_max > 0) {
|
|
// The domain of integer variable v contains -1 and 1
|
|
u_max_new = std::max(-1 * z_min, z_min);
|
|
u_max_new = std::max(u_max_new, z_max);
|
|
u_max_new = std::max(u_max_new, -1 * z_max);
|
|
}
|
|
else {
|
|
u_max_new = (v_max < 0 ? z_min : z_max) / (z_min > 0 ? v_min : v_max);
|
|
}
|
|
|
|
if (u_max_new < u.getMax()) {
|
|
// TODO Better explanation
|
|
Clause * reason = Reason_new(5);
|
|
(*reason)[1] = v.getMinLit();
|
|
(*reason)[2] = v.getMaxLit();
|
|
(*reason)[3] = z.getMinLit();
|
|
(*reason)[4] = z.getMaxLit();
|
|
setDom(u, setMax, (u_max_new == 0 ? -1 : u_max_new), reason);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//-----
|
|
|
|
// x * y = z x, y, z >= 0
|
|
|
|
template <int U = 0, int V = 0, int W = 0>
|
|
class Times : public Propagator, public Checker {
|
|
public:
|
|
IntView<U> x;
|
|
IntView<V> y;
|
|
IntView<W> z;
|
|
|
|
Times(IntView<U> _x, IntView<V> _y, IntView<W> _z) :
|
|
x(_x), y(_y), z(_z) {
|
|
priority = 1;
|
|
assert(x.getMin() >= 0 && y.getMin() >= 0 && z.getMin() >= 0);
|
|
x.attach(this, 0, EVENT_LU);
|
|
y.attach(this, 1, EVENT_LU);
|
|
z.attach(this, 2, EVENT_LU);
|
|
}
|
|
|
|
bool propagate() {
|
|
int64_t x_min = x.getMin(), x_max = x.getMax();
|
|
int64_t y_min = y.getMin(), y_max = y.getMax();
|
|
int64_t z_min = z.getMin(), z_max = z.getMax();
|
|
|
|
// z >= x.min * y.min
|
|
setDom(z, setMin, x_min*y_min, x.getMinLit(), y.getMinLit());
|
|
// z <= x.max * y.max
|
|
if (x_max * y_max < IntVar::max_limit)
|
|
setDom(z, setMax, x_max*y_max, x.getMaxLit(), y.getMaxLit());
|
|
|
|
// x >= ceil(z.min / y.max)
|
|
if (y_max >= 1) {
|
|
setDom(x, setMin, (z_min+y_max-1)/y_max, y.getMaxLit(), z.getMinLit());
|
|
}
|
|
|
|
// x <= floor(z.max / y.min)
|
|
if (y_min >= 1) {
|
|
setDom(x, setMax, z_max/y_min, y.getMinLit(), z.getMaxLit());
|
|
}
|
|
|
|
// y >= ceil(z.min / x.max)
|
|
if (x_max >= 1) {
|
|
setDom(y, setMin, (z_min+x_max-1)/x_max, x.getMaxLit(), z.getMinLit());
|
|
}
|
|
|
|
// y <= floor(z.max / x.min)
|
|
if (x_min >= 1) {
|
|
setDom(y, setMax, z_max/x_min, x.getMinLit(), z.getMaxLit());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool check() {
|
|
return (x.getShadowVal() * y.getShadowVal() == z.getShadowVal());
|
|
}
|
|
|
|
};
|
|
|
|
int get_sign(IntVar* x) {
|
|
if (x->getMin() >= 0) return 1;
|
|
if (x->getMax() <= 0) return -1;
|
|
return 0;
|
|
}
|
|
|
|
// z = x * y
|
|
|
|
void int_times(IntVar* x, IntVar* y, IntVar* z) {
|
|
if (!get_sign(x) || !get_sign(y) || !get_sign(z)) {
|
|
new TimesAll<0,0,0>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
}
|
|
else {
|
|
bool x_flip = (get_sign(x) == -1);
|
|
bool y_flip = (get_sign(y) == -1);
|
|
bool z_flip = (get_sign(z) == -1);
|
|
|
|
if (!x_flip && !y_flip && !z_flip) {
|
|
new Times<0,0,0>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
} else if (!x_flip && y_flip && z_flip) {
|
|
new Times<0,1,1>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
} else if (x_flip && !y_flip && z_flip) {
|
|
new Times<1,0,1>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
} else if (x_flip && y_flip && !z_flip) {
|
|
new Times<1,1,0>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
} else {
|
|
// as: This case is an inconsistency in the model!
|
|
CHUFFED_ERROR("Cannot handle this case\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----
|
|
|
|
// ceil(x / y) = z x, y, z >= 0
|
|
|
|
// x / y <= z
|
|
// x / y > z - 1
|
|
|
|
// floor(x / y) = z <=> ceil(x+1 / y) = z+1
|
|
|
|
template <int U = 0, int V = 0, int W = 0>
|
|
class Divide : public Propagator, public Checker {
|
|
public:
|
|
IntView<U> x;
|
|
IntView<V> y;
|
|
IntView<W> z;
|
|
|
|
Divide(IntView<U> _x, IntView<V> _y, IntView<W> _z) :
|
|
x(_x), y(_y), z(_z) {
|
|
priority = 1;
|
|
assert(x.getMin() >= 0 && y.getMin() >= 1 && z.getMin() >= 0);
|
|
x.attach(this, 0, EVENT_LU);
|
|
y.attach(this, 1, EVENT_LU);
|
|
z.attach(this, 2, EVENT_LU);
|
|
}
|
|
|
|
bool propagate() {
|
|
int64_t x_min = x.getMin(), x_max = x.getMax();
|
|
int64_t y_min = y.getMin(), y_max = y.getMax();
|
|
int64_t z_min = z.getMin(), z_max = z.getMax();
|
|
|
|
// z >= ceil(x.min / y.max)
|
|
setDom(z, setMin, (x_min+y_max-1)/y_max, x.getMinLit(), y.getMaxLit());
|
|
// z <= ceil(x.max / y.min)
|
|
setDom(z, setMax, (x_max+y_min-1)/y_min, x.getMaxLit(), y.getMinLit());
|
|
|
|
// x >= y.min * (z.min - 1) + 1
|
|
setDom(x, setMin, y_min*(z_min-1)+1, y.getMinLit(), z.getMinLit());
|
|
// x <= y.max * z.max
|
|
setDom(x, setMax, y_max*z_max, y.getMaxLit(), z.getMaxLit());
|
|
|
|
// y >= ceil(x.min / z.max)
|
|
if (z_max >= 1) {
|
|
setDom(y, setMin, (x_min+z_max-1)/z_max, x.getMinLit(), z.getMaxLit());
|
|
}
|
|
|
|
// y <= ceil(x.max / z.min-1) - 1
|
|
if (z_min >= 2) {
|
|
setDom(y, setMax, (x_max+z_min-2)/(z_min-1)-1, x.getMaxLit(), z.getMinLit());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool check() {
|
|
return ((int) ceil(x.getShadowVal() / y.getShadowVal()) == z.getShadowVal());
|
|
}
|
|
|
|
};
|
|
|
|
// z = floor(x / y)
|
|
|
|
void int_div(IntVar* x, IntVar* y, IntVar* z) {
|
|
if (!get_sign(x) || !get_sign(y) || !get_sign(z)) {
|
|
CHUFFED_ERROR("Cannot handle non-sign-fixed vars\n");
|
|
}
|
|
bool x_flip = (get_sign(x) == -1);
|
|
bool y_flip = (get_sign(y) == -1);
|
|
bool z_flip = (get_sign(z) == -1);
|
|
|
|
if (!x_flip && !y_flip && !z_flip) {
|
|
// ceil(x+1 / y) = z+1
|
|
new Divide<4,0,4>(IntView<>(x,1,1), IntView<>(y), IntView<>(z,1,1));
|
|
} else if (!x_flip && y_flip && z_flip) {
|
|
// ceil(x / -y) = -z
|
|
new Divide<0,1,1>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
} else if (x_flip && !y_flip && z_flip) {
|
|
// ceil(-x / y) = -z
|
|
new Divide<1,0,1>(IntView<>(x), IntView<>(y), IntView<>(z));
|
|
} else if (x_flip && y_flip && !z_flip) {
|
|
// ceil(-x+1 / -y) = z+1
|
|
new Divide<5,1,4>(IntView<>(x,1,1), IntView<>(y), IntView<>(z,1,1));
|
|
} else {
|
|
CHUFFED_ERROR("Cannot handle this case\n");
|
|
}
|
|
}
|
|
|
|
void int_mod(IntVar* x, IntVar* y, IntVar* z) {
|
|
CHUFFED_ERROR("Not yet supported\n");
|
|
}
|
|
|
|
// z = min(x, y)
|
|
|
|
template <int U>
|
|
class Min2 : public Propagator, public Checker {
|
|
public:
|
|
IntView<U> x, y, z;
|
|
|
|
Min2(IntView<U> _x, IntView<U> _y, IntView<U> _z) :
|
|
x(_x), y(_y), z(_z) {
|
|
priority = 1;
|
|
x.attach(this, 0, EVENT_LU);
|
|
y.attach(this, 1, EVENT_LU);
|
|
z.attach(this, 2, EVENT_L);
|
|
}
|
|
|
|
bool propagate() {
|
|
// make a less than or equal to min(max(b_i))
|
|
|
|
setDom(z, setMax, x.getMax(), x.getMaxLit());
|
|
setDom(z, setMax, y.getMax(), y.getMaxLit());
|
|
|
|
int64_t m = (x.getMin() < y.getMin() ? x.getMin() : y.getMin());
|
|
setDom(z, setMin, m, x.getFMinLit(m), y.getFMinLit(m));
|
|
|
|
setDom(x, setMin, z.getMin(), z.getMinLit());
|
|
setDom(y, setMin, z.getMin(), z.getMinLit());
|
|
|
|
if (z.getMin() == x.getMax() || z.getMin() == y.getMax()) satisfied = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool check() {
|
|
return ((int) std::min(x.getShadowVal(), y.getShadowVal()) == z.getShadowVal());
|
|
}
|
|
|
|
int checkSatisfied() {
|
|
if (satisfied) return 1;
|
|
if (z.getMin() == x.getMax() || z.getMin() == y.getMax()) satisfied = true;
|
|
return 3;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
void int_min(IntVar* x, IntVar* y, IntVar* z) {
|
|
new Min2<0>(IntView<0>(x), IntView<0>(y), IntView<0>(z));
|
|
}
|
|
|
|
void int_max(IntVar* x, IntVar* y, IntVar* z) {
|
|
new Min2<1>(IntView<1>(x), IntView<1>(y), IntView<1>(z));
|
|
}
|
|
|
|
|
|
//-----
|
|
|
|
// z = x + y
|
|
|
|
void int_plus(IntVar* x, IntVar* y, IntVar* z) {
|
|
vec<int> coeffs;
|
|
vec<IntVar*> w;
|
|
coeffs.push(1); w.push(x);
|
|
coeffs.push(1); w.push(y);
|
|
coeffs.push(-1); w.push(z);
|
|
int_linear(coeffs, w, IRT_EQ, 0);
|
|
}
|
|
|
|
//-----
|
|
|
|
// z = x - y
|
|
|
|
void int_minus(IntVar* x, IntVar* y, IntVar* z) {
|
|
int_plus(y, z, x);
|
|
}
|
|
|
|
//-----
|
|
|
|
// y = -x
|
|
|
|
void int_negate(IntVar* x, IntVar* y) {
|
|
bin_linear(x, y, IRT_EQ, 0);
|
|
}
|
|
|
|
|
|
//-----
|
|
|
|
// y = bool2int(x)
|
|
|
|
void bool2int(BoolView x, IntVar* y) {
|
|
int_rel(y, IRT_GE, 0);
|
|
int_rel(y, IRT_LE, 1);
|
|
y->specialiseToEL();
|
|
bool_rel(x, BRT_EQ, BoolView(y->getLit(1,2)));
|
|
}
|
|
|