diff --git a/changelog.in b/changelog.in index 88c093779b..f12c7256ea 100755 --- a/changelog.in +++ b/changelog.in @@ -68,6 +68,13 @@ Date: 2019-??-?? [DESCRIPTION] Let's see. +[ENTRY] +Module: int +What: new +Rank: minor +[DESCRIPTION] +Add BoolVar versions of argmax and argmin. + [ENTRY] Module: kernel What: change diff --git a/gecode/int.hh b/gecode/int.hh index 7b04446e0a..299f775f87 100755 --- a/gecode/int.hh +++ b/gecode/int.hh @@ -2611,7 +2611,7 @@ namespace Gecode { GECODE_INT_EXPORT void argmin(Home home, const IntVarArgs& x, IntVar y, bool tiebreak=true, IntPropLevel ipl=IPL_DEF); - /** \brief Post propagator for \f$ \operatorname{argmin}(x)-o=y\f$ + /** \brief Post propagator for \f$ \operatorname{argmin}(x)+o=y\f$ * * In case of ties, the smallest value for \a y is chosen * (provided \a tiebreak is true). @@ -2635,7 +2635,7 @@ namespace Gecode { GECODE_INT_EXPORT void argmax(Home home, const IntVarArgs& x, IntVar y, bool tiebreak=true, IntPropLevel ipl=IPL_DEF); - /** \brief Post propagator for \f$ \operatorname{argmax}(x)-o=y\f$ + /** \brief Post propagator for \f$ \operatorname{argmax}(x)+o=y\f$ * * In case of ties, the smallest value for \a y is chosen * (provided \a tiebreak is true). @@ -2647,6 +2647,54 @@ namespace Gecode { GECODE_INT_EXPORT void argmax(Home home, const IntVarArgs& x, int o, IntVar y, bool tiebreak=true, IntPropLevel ipl=IPL_DEF); + /** \brief Post propagator for \f$ \operatorname{argmin}(x)=y\f$ + * + * In case of ties, the smallest value for \a y is chosen + * (provided \a tiebreak is true). + * + * If \a x is empty, an exception of type Int::TooFewArguments is thrown. + * If \a y occurs in \a x, an exception of type Int::ArgumentSame + * is thrown. + */ + GECODE_INT_EXPORT void + argmin(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak=true, + IntPropLevel ipl=IPL_DEF); + /** \brief Post propagator for \f$ \operatorname{argmin}(x)-o=y\f$ + * + * In case of ties, the smallest value for \a y is chosen + * (provided \a tiebreak is true). + * + * If \a x is empty, an exception of type Int::TooFewArguments is thrown. + * If \a y occurs in \a x, an exception of type Int::ArgumentSame + * is thrown. + */ + GECODE_INT_EXPORT void + argmin(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak=true, + IntPropLevel ipl=IPL_DEF); + /** \brief Post propagator for \f$ \operatorname{argmax}(x)=y\f$ + * + * In case of ties, the smallest value for \a y is chosen + * (provided \a tiebreak is true). + * + * If \a x is empty, an exception of type Int::TooFewArguments is thrown. + * If \a y occurs in \a x, an exception of type Int::ArgumentSame + * is thrown. + */ + GECODE_INT_EXPORT void + argmax(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak=true, + IntPropLevel ipl=IPL_DEF); + /** \brief Post propagator for \f$ \operatorname{argmax}(x)-o=y\f$ + * + * In case of ties, the smallest value for \a y is chosen + * (provided \a tiebreak is true). + * + * If \a x is empty, an exception of type Int::TooFewArguments is thrown. + * If \a y occurs in \a x, an exception of type Int::ArgumentSame + * is thrown. + */ + GECODE_INT_EXPORT void + argmax(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak=true, + IntPropLevel ipl=IPL_DEF); /** \brief Post propagator for \f$ |x_0|=x_1\f$ * diff --git a/gecode/int/arithmetic.cpp b/gecode/int/arithmetic.cpp index 1cd963aa59..ba5ab3198a 100755 --- a/gecode/int/arithmetic.cpp +++ b/gecode/int/arithmetic.cpp @@ -212,6 +212,103 @@ namespace Gecode { ::post(home,ix,yv))); } + void + argmax(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak, + IntPropLevel) { + using namespace Int; + if (x.size() == 0) + throw TooFewArguments("Int::argmax"); + GECODE_POST; + // Constrain y properly + IntView yv(y); + GECODE_ME_FAIL(yv.gq(home,0)); + GECODE_ME_FAIL(yv.le(home,x.size())); + // Construct index view array + IdxViewArray ix(home,x.size()); + for (int i=x.size(); i--; ) { + ix[i].idx=i; ix[i].view=x[i]; + } + if (tiebreak) + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + else + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + } + + void + argmax(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak, + IntPropLevel) { + using namespace Int; + Limits::nonnegative(o,"Int::argmax"); + if (x.size() == 0) + throw TooFewArguments("Int::argmax"); + GECODE_POST; + // Constrain y properly + OffsetView yv(y,-o); + GECODE_ME_FAIL(yv.gq(home,0)); + GECODE_ME_FAIL(yv.le(home,x.size())); + // Construct index view array + IdxViewArray ix(home,x.size()); + for (int i=x.size(); i--; ) { + ix[i].idx=i; ix[i].view=x[i]; + } + if (tiebreak) + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + else + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + } + + void + argmin(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak, + IntPropLevel) { + using namespace Int; + if (x.size() == 0) + throw TooFewArguments("Int::argmin"); + GECODE_POST; + // Constrain y properly + IntView yv(y); + GECODE_ME_FAIL(yv.gq(home,0)); + GECODE_ME_FAIL(yv.le(home,x.size())); + // Construct index view array + IdxViewArray ix(home,x.size()); + for (int i=x.size(); i--; ) { + ix[i].idx=i; ix[i].view=NegBoolView(x[i]); + } + if (tiebreak) + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + else + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + } + + void + argmin(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak, + IntPropLevel) { + using namespace Int; + Limits::nonnegative(o,"Int::argmin"); + if (x.size() == 0) + throw TooFewArguments("Int::argmin"); + GECODE_POST; + // Constrain y properly + OffsetView yv(y,-o); + GECODE_ME_FAIL(yv.gq(home,0)); + GECODE_ME_FAIL(yv.le(home,x.size())); + // Construct index view array + IdxViewArray ix(home,x.size()); + for (int i=x.size(); i--; ) { + ix[i].idx=i; ix[i].view=NegBoolView(x[i]); + } + if (tiebreak) + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + else + GECODE_ES_FAIL((Arithmetic::ArgMax + ::post(home,ix,yv))); + } void mult(Home home, IntVar x0, IntVar x1, IntVar x2, diff --git a/gecode/int/idx-view.hpp b/gecode/int/idx-view.hpp index c127f1162c..c8fee1ff17 100755 --- a/gecode/int/idx-view.hpp +++ b/gecode/int/idx-view.hpp @@ -55,6 +55,12 @@ namespace Gecode { namespace Int { public: typedef BoolVarArgs argtype; }; + /// VarArg type for Boolean views + template<> + class ViewToVarArg { + public: + typedef BoolVarArgs argtype; + }; template forceinline IdxView* diff --git a/test/int/arithmetic.cpp b/test/int/arithmetic.cpp index b71dc33ba2..001c6f370f 100644 --- a/test/int/arithmetic.cpp +++ b/test/int/arithmetic.cpp @@ -894,7 +894,173 @@ namespace Test { namespace Int { } }; + /// %Test for Boolean argument maximum constraint + class ArgMaxBool : public Test { + protected: + /// Offset to be used + int offset; + /// Whether to use tie-breaking + bool tiebreak; + public: + /// Create and register test + ArgMaxBool(int n, int o, bool tb) + : Test("Arithmetic::ArgMaxBool::"+str(o)+"::"+str(tb)+"::"+str(n), + n+1,0,n+1, + false,tb ? Gecode::IPL_DEF : Gecode::IPL_DOM), + offset(o), tiebreak(tb) {} + /// %Test whether \a x is solution + virtual bool solution(const Assignment& x) const { + int n=x.size()-1; + if ((x[n] < offset) || (x[n] >= n + offset)) + return false; + int m=x[0]; int p=0; + if (x[0] > 1) + return false; + for (int i=1; i 1) + return false; + if (x[i] > m) { + p=i; m=x[i]; + } + } + return tiebreak ? (p + offset == x[n]) : (m == x[x[n]-offset]); + } + /// Post constraint on \a x + virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) { + int n=x.size()-1; + Gecode::BoolVarArgs m(n); + for (int i=0; i= 2*n)) + return false; + Gecode::IntArgs y(2*n); + for (int i=0; i 1) + return false; + for (int i=1; i<2*n; i++) { + if (y[i] > 1) + return false; + if (y[i] > m) { + p=i; m=y[i]; + } + } + return tiebreak ? (p == x[n]) : (m == y[x[n]]); + } + /// Post constraint on \a x + virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) { + int n=x.size()-1; + Gecode::BoolVarArgs m(2*n); + for (int i=0; i= n + offset)) + return false; + int m=x[0]; int p=0; + if (x[0] < 0 || x[0] > 1) + return false; + for (int i=1; i 1) + return false; + if (x[i] < m) { + p=i; m=x[i]; + } + } + return tiebreak ? (p+offset == x[n]) : (m == x[x[n]-offset]); + } + /// Post constraint on \a x + virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) { + int n=x.size()-1; + Gecode::BoolVarArgs m(n); + for (int i=0; i= 2*n)) + return false; + Gecode::IntArgs y(2*n); + for (int i=0; i 1) + return false; + for (int i=1; i<2*n; i++) { + if (y[i] > 1) + return false; + if (y[i] < m) { + p=i; m=y[i]; + } + } + return tiebreak ? (p == x[n]) : (m == y[x[n]]); + } + /// Post constraint on \a x + virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) { + int n=x.size()-1; + Gecode::BoolVarArgs m(2*n); + for (int i=0; i