#include // y = min(x_i) // Bounds propagator, not fully consistent template class Minimum : public Propagator, public Checker { public: int const sz; IntView * const x; IntView const y; // Persistent state Tint min_max_var; Tint64_t min_max; Tint64_t min_fixed; // Intermediate state bool lower_change; Minimum(vec > _x, IntView _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& x, IntVar* y) { vec > w; for (int i = 0; i < x.size(); i++) w.push(IntView<>(x[i])); new Minimum<0>(w, IntView<>(y)); } void maximum(vec& x, IntVar* y) { vec > w; for (int i = 0; i < x.size(); i++) w.push(IntView<>(x[i])); new Minimum<1>(w, IntView<>(y)); }