Skip to content

Commit daaaa67

Browse files
committed
Add argmin/argmax for BoolVar
1 parent 5d278dd commit daaaa67

5 files changed

Lines changed: 339 additions & 2 deletions

File tree

changelog.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ Date: 2019-??-??
6868
[DESCRIPTION]
6969
Let's see.
7070

71+
[ENTRY]
72+
Module: int
73+
What: new
74+
Rank: minor
75+
[DESCRIPTION]
76+
Add BoolVar versions of argmax and argmin.
77+
7178
[ENTRY]
7279
Module: kernel
7380
What: change

gecode/int.hh

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,7 +2611,7 @@ namespace Gecode {
26112611
GECODE_INT_EXPORT void
26122612
argmin(Home home, const IntVarArgs& x, IntVar y, bool tiebreak=true,
26132613
IntPropLevel ipl=IPL_DEF);
2614-
/** \brief Post propagator for \f$ \operatorname{argmin}(x)-o=y\f$
2614+
/** \brief Post propagator for \f$ \operatorname{argmin}(x)+o=y\f$
26152615
*
26162616
* In case of ties, the smallest value for \a y is chosen
26172617
* (provided \a tiebreak is true).
@@ -2635,7 +2635,7 @@ namespace Gecode {
26352635
GECODE_INT_EXPORT void
26362636
argmax(Home home, const IntVarArgs& x, IntVar y, bool tiebreak=true,
26372637
IntPropLevel ipl=IPL_DEF);
2638-
/** \brief Post propagator for \f$ \operatorname{argmax}(x)-o=y\f$
2638+
/** \brief Post propagator for \f$ \operatorname{argmax}(x)+o=y\f$
26392639
*
26402640
* In case of ties, the smallest value for \a y is chosen
26412641
* (provided \a tiebreak is true).
@@ -2647,6 +2647,54 @@ namespace Gecode {
26472647
GECODE_INT_EXPORT void
26482648
argmax(Home home, const IntVarArgs& x, int o, IntVar y, bool tiebreak=true,
26492649
IntPropLevel ipl=IPL_DEF);
2650+
/** \brief Post propagator for \f$ \operatorname{argmin}(x)=y\f$
2651+
*
2652+
* In case of ties, the smallest value for \a y is chosen
2653+
* (provided \a tiebreak is true).
2654+
*
2655+
* If \a x is empty, an exception of type Int::TooFewArguments is thrown.
2656+
* If \a y occurs in \a x, an exception of type Int::ArgumentSame
2657+
* is thrown.
2658+
*/
2659+
GECODE_INT_EXPORT void
2660+
argmin(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak=true,
2661+
IntPropLevel ipl=IPL_DEF);
2662+
/** \brief Post propagator for \f$ \operatorname{argmin}(x)-o=y\f$
2663+
*
2664+
* In case of ties, the smallest value for \a y is chosen
2665+
* (provided \a tiebreak is true).
2666+
*
2667+
* If \a x is empty, an exception of type Int::TooFewArguments is thrown.
2668+
* If \a y occurs in \a x, an exception of type Int::ArgumentSame
2669+
* is thrown.
2670+
*/
2671+
GECODE_INT_EXPORT void
2672+
argmin(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak=true,
2673+
IntPropLevel ipl=IPL_DEF);
2674+
/** \brief Post propagator for \f$ \operatorname{argmax}(x)=y\f$
2675+
*
2676+
* In case of ties, the smallest value for \a y is chosen
2677+
* (provided \a tiebreak is true).
2678+
*
2679+
* If \a x is empty, an exception of type Int::TooFewArguments is thrown.
2680+
* If \a y occurs in \a x, an exception of type Int::ArgumentSame
2681+
* is thrown.
2682+
*/
2683+
GECODE_INT_EXPORT void
2684+
argmax(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak=true,
2685+
IntPropLevel ipl=IPL_DEF);
2686+
/** \brief Post propagator for \f$ \operatorname{argmax}(x)-o=y\f$
2687+
*
2688+
* In case of ties, the smallest value for \a y is chosen
2689+
* (provided \a tiebreak is true).
2690+
*
2691+
* If \a x is empty, an exception of type Int::TooFewArguments is thrown.
2692+
* If \a y occurs in \a x, an exception of type Int::ArgumentSame
2693+
* is thrown.
2694+
*/
2695+
GECODE_INT_EXPORT void
2696+
argmax(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak=true,
2697+
IntPropLevel ipl=IPL_DEF);
26502698

26512699
/** \brief Post propagator for \f$ |x_0|=x_1\f$
26522700
*

gecode/int/arithmetic.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,103 @@ namespace Gecode {
212212
::post(home,ix,yv)));
213213
}
214214

215+
void
216+
argmax(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak,
217+
IntPropLevel) {
218+
using namespace Int;
219+
if (x.size() == 0)
220+
throw TooFewArguments("Int::argmax");
221+
GECODE_POST;
222+
// Constrain y properly
223+
IntView yv(y);
224+
GECODE_ME_FAIL(yv.gq(home,0));
225+
GECODE_ME_FAIL(yv.le(home,x.size()));
226+
// Construct index view array
227+
IdxViewArray<BoolView> ix(home,x.size());
228+
for (int i=x.size(); i--; ) {
229+
ix[i].idx=i; ix[i].view=x[i];
230+
}
231+
if (tiebreak)
232+
GECODE_ES_FAIL((Arithmetic::ArgMax<BoolView,IntView,true>
233+
::post(home,ix,yv)));
234+
else
235+
GECODE_ES_FAIL((Arithmetic::ArgMax<BoolView,IntView,false>
236+
::post(home,ix,yv)));
237+
}
238+
239+
void
240+
argmax(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak,
241+
IntPropLevel) {
242+
using namespace Int;
243+
Limits::nonnegative(o,"Int::argmax");
244+
if (x.size() == 0)
245+
throw TooFewArguments("Int::argmax");
246+
GECODE_POST;
247+
// Constrain y properly
248+
OffsetView yv(y,-o);
249+
GECODE_ME_FAIL(yv.gq(home,0));
250+
GECODE_ME_FAIL(yv.le(home,x.size()));
251+
// Construct index view array
252+
IdxViewArray<BoolView> ix(home,x.size());
253+
for (int i=x.size(); i--; ) {
254+
ix[i].idx=i; ix[i].view=x[i];
255+
}
256+
if (tiebreak)
257+
GECODE_ES_FAIL((Arithmetic::ArgMax<BoolView,OffsetView,true>
258+
::post(home,ix,yv)));
259+
else
260+
GECODE_ES_FAIL((Arithmetic::ArgMax<BoolView,OffsetView,false>
261+
::post(home,ix,yv)));
262+
}
263+
264+
void
265+
argmin(Home home, const BoolVarArgs& x, IntVar y, bool tiebreak,
266+
IntPropLevel) {
267+
using namespace Int;
268+
if (x.size() == 0)
269+
throw TooFewArguments("Int::argmin");
270+
GECODE_POST;
271+
// Constrain y properly
272+
IntView yv(y);
273+
GECODE_ME_FAIL(yv.gq(home,0));
274+
GECODE_ME_FAIL(yv.le(home,x.size()));
275+
// Construct index view array
276+
IdxViewArray<NegBoolView> ix(home,x.size());
277+
for (int i=x.size(); i--; ) {
278+
ix[i].idx=i; ix[i].view=NegBoolView(x[i]);
279+
}
280+
if (tiebreak)
281+
GECODE_ES_FAIL((Arithmetic::ArgMax<NegBoolView,IntView,true>
282+
::post(home,ix,yv)));
283+
else
284+
GECODE_ES_FAIL((Arithmetic::ArgMax<NegBoolView,IntView,false>
285+
::post(home,ix,yv)));
286+
}
287+
288+
void
289+
argmin(Home home, const BoolVarArgs& x, int o, IntVar y, bool tiebreak,
290+
IntPropLevel) {
291+
using namespace Int;
292+
Limits::nonnegative(o,"Int::argmin");
293+
if (x.size() == 0)
294+
throw TooFewArguments("Int::argmin");
295+
GECODE_POST;
296+
// Constrain y properly
297+
OffsetView yv(y,-o);
298+
GECODE_ME_FAIL(yv.gq(home,0));
299+
GECODE_ME_FAIL(yv.le(home,x.size()));
300+
// Construct index view array
301+
IdxViewArray<NegBoolView> ix(home,x.size());
302+
for (int i=x.size(); i--; ) {
303+
ix[i].idx=i; ix[i].view=NegBoolView(x[i]);
304+
}
305+
if (tiebreak)
306+
GECODE_ES_FAIL((Arithmetic::ArgMax<NegBoolView,OffsetView,true>
307+
::post(home,ix,yv)));
308+
else
309+
GECODE_ES_FAIL((Arithmetic::ArgMax<NegBoolView,OffsetView,false>
310+
::post(home,ix,yv)));
311+
}
215312

216313
void
217314
mult(Home home, IntVar x0, IntVar x1, IntVar x2,

gecode/int/idx-view.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ namespace Gecode { namespace Int {
5555
public:
5656
typedef BoolVarArgs argtype;
5757
};
58+
/// VarArg type for Boolean views
59+
template<>
60+
class ViewToVarArg<NegBoolView> {
61+
public:
62+
typedef BoolVarArgs argtype;
63+
};
5864

5965
template<class View>
6066
forceinline IdxView<View>*

test/int/arithmetic.cpp

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,173 @@ namespace Test { namespace Int {
894894
}
895895
};
896896

897+
/// %Test for Boolean argument maximum constraint
898+
class ArgMaxBool : public Test {
899+
protected:
900+
/// Offset to be used
901+
int offset;
902+
/// Whether to use tie-breaking
903+
bool tiebreak;
904+
public:
905+
/// Create and register test
906+
ArgMaxBool(int n, int o, bool tb)
907+
: Test("Arithmetic::ArgMaxBool::"+str(o)+"::"+str(tb)+"::"+str(n),
908+
n+1,0,n+1,
909+
false,tb ? Gecode::IPL_DEF : Gecode::IPL_DOM),
910+
offset(o), tiebreak(tb) {}
911+
/// %Test whether \a x is solution
912+
virtual bool solution(const Assignment& x) const {
913+
int n=x.size()-1;
914+
if ((x[n] < offset) || (x[n] >= n + offset))
915+
return false;
916+
int m=x[0]; int p=0;
917+
if (x[0] > 1)
918+
return false;
919+
for (int i=1; i<n; i++) {
920+
if (x[i] > 1)
921+
return false;
922+
if (x[i] > m) {
923+
p=i; m=x[i];
924+
}
925+
}
926+
return tiebreak ? (p + offset == x[n]) : (m == x[x[n]-offset]);
927+
}
928+
/// Post constraint on \a x
929+
virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) {
930+
int n=x.size()-1;
931+
Gecode::BoolVarArgs m(n);
932+
for (int i=0; i<n; i++)
933+
m[i]=channel(home,x[i]);
934+
Gecode::argmax(home, m, offset, x[n], tiebreak);
935+
}
936+
};
937+
938+
/// %Test for argument maximum constraint with shared variables
939+
class ArgMaxBoolShared : public Test {
940+
protected:
941+
/// Whether to use tie-breaking
942+
bool tiebreak;
943+
public:
944+
/// Create and register test
945+
ArgMaxBoolShared(int n, bool tb)
946+
: Test("Arithmetic::ArgMaxBool::Shared::"+str(tb)+"::"+str(n),n+1,0,n+1,
947+
false),
948+
tiebreak(tb) {
949+
testfix=false;
950+
}
951+
/// %Test whether \a x is solution
952+
virtual bool solution(const Assignment& x) const {
953+
int n=x.size()-1;
954+
if ((x[n] < 0) || (x[n] >= 2*n))
955+
return false;
956+
Gecode::IntArgs y(2*n);
957+
for (int i=0; i<n; i++)
958+
y[2*i+0]=y[2*i+1]=x[i];
959+
int m=y[0]; int p=0;
960+
if (y[0] > 1)
961+
return false;
962+
for (int i=1; i<2*n; i++) {
963+
if (y[i] > 1)
964+
return false;
965+
if (y[i] > m) {
966+
p=i; m=y[i];
967+
}
968+
}
969+
return tiebreak ? (p == x[n]) : (m == y[x[n]]);
970+
}
971+
/// Post constraint on \a x
972+
virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) {
973+
int n=x.size()-1;
974+
Gecode::BoolVarArgs m(2*n);
975+
for (int i=0; i<n; i++)
976+
m[2*i+0]=m[2*i+1]=channel(home,x[i]);
977+
Gecode::argmax(home, m, x[n], tiebreak);
978+
}
979+
};
980+
981+
/// %Test for argument minimum constraint
982+
class ArgMinBool : public Test {
983+
protected:
984+
/// Which offset to use
985+
int offset;
986+
/// Whether to use tie-breaking
987+
bool tiebreak;
988+
public:
989+
/// Create and register test
990+
ArgMinBool(int n, int o, bool tb)
991+
: Test("Arithmetic::ArgMinBool::"+str(o)+"::"+str(tb)+"::"+str(n),
992+
n+1,0,n+1,
993+
false,tb ? Gecode::IPL_DEF : Gecode::IPL_DOM),
994+
offset(o), tiebreak(tb) {}
995+
/// %Test whether \a x is solution
996+
virtual bool solution(const Assignment& x) const {
997+
int n=x.size()-1;
998+
if ((x[n] < offset) || (x[n] >= n + offset))
999+
return false;
1000+
int m=x[0]; int p=0;
1001+
if (x[0] < 0 || x[0] > 1)
1002+
return false;
1003+
for (int i=1; i<n; i++) {
1004+
if (x[i] < 0 || x[i] > 1)
1005+
return false;
1006+
if (x[i] < m) {
1007+
p=i; m=x[i];
1008+
}
1009+
}
1010+
return tiebreak ? (p+offset == x[n]) : (m == x[x[n]-offset]);
1011+
}
1012+
/// Post constraint on \a x
1013+
virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) {
1014+
int n=x.size()-1;
1015+
Gecode::BoolVarArgs m(n);
1016+
for (int i=0; i<n; i++)
1017+
m[i]=channel(home,x[i]);
1018+
Gecode::argmin(home, m, offset, x[n], tiebreak);
1019+
}
1020+
};
8971021

1022+
/// %Test for argument minimum constraint with shared variables
1023+
class ArgMinBoolShared : public Test {
1024+
protected:
1025+
/// Whether to use tie-breaking
1026+
bool tiebreak;
1027+
public:
1028+
/// Create and register test
1029+
ArgMinBoolShared(int n, bool tb)
1030+
: Test("Arithmetic::ArgMinBool::Shared::"+str(tb)+"::"+str(n),n+1,0,n+1,
1031+
false),
1032+
tiebreak(tb) {
1033+
testfix=false;
1034+
}
1035+
/// %Test whether \a x is solution
1036+
virtual bool solution(const Assignment& x) const {
1037+
int n=x.size()-1;
1038+
if ((x[n] < 0) || (x[n] >= 2*n))
1039+
return false;
1040+
Gecode::IntArgs y(2*n);
1041+
for (int i=0; i<n; i++)
1042+
y[2*i+0]=y[2*i+1]=x[i];
1043+
int m=y[0]; int p=0;
1044+
if (y[0] > 1)
1045+
return false;
1046+
for (int i=1; i<2*n; i++) {
1047+
if (y[i] > 1)
1048+
return false;
1049+
if (y[i] < m) {
1050+
p=i; m=y[i];
1051+
}
1052+
}
1053+
return tiebreak ? (p == x[n]) : (m == y[x[n]]);
1054+
}
1055+
/// Post constraint on \a x
1056+
virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) {
1057+
int n=x.size()-1;
1058+
Gecode::BoolVarArgs m(2*n);
1059+
for (int i=0; i<n; i++)
1060+
m[2*i+0]=m[2*i+1]=channel(home,x[i]);
1061+
Gecode::argmin(home, m, x[n], tiebreak);
1062+
}
1063+
};
8981064

8991065
/// Help class to create and register tests
9001066
class Create {
@@ -1069,6 +1235,19 @@ namespace Test { namespace Int {
10691235
(void) new ArgMin(i,0,false);
10701236
(void) new ArgMin(i,1,false);
10711237
(void) new ArgMinShared(i,false);
1238+
1239+
(void) new ArgMaxBool(i,0,true);
1240+
(void) new ArgMaxBool(i,1,true);
1241+
(void) new ArgMaxBoolShared(i,true);
1242+
(void) new ArgMinBool(i,0,true);
1243+
(void) new ArgMinBool(i,1,true);
1244+
(void) new ArgMinBoolShared(i,true);
1245+
(void) new ArgMaxBool(i,0,false);
1246+
(void) new ArgMaxBool(i,1,false);
1247+
(void) new ArgMaxBoolShared(i,false);
1248+
(void) new ArgMinBool(i,0,false);
1249+
(void) new ArgMinBool(i,1,false);
1250+
(void) new ArgMinBoolShared(i,false);
10721251
}
10731252
}
10741253
};

0 commit comments

Comments
 (0)