Generated on Mon Aug 25 11:35:32 2008 for Gecode by doxygen 1.5.6

golf.cc

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Guido Tack, 2004
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-07-11 10:37:06 +0200 (Fri, 11 Jul 2008) $ by $Author: tack $
00011  *     $Revision: 7340 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include "gecode/set.hh"
00039 #include "examples/support.hh"
00040 
00047 
00048 struct Tournament {
00050   int groups;
00052   int playersInGroup;
00054   int weeks;
00055 };
00057 static const Tournament t[]=
00058   { {8,4,9},
00059     {5,3,7},
00060     {4,3,2}
00061   };
00063 static const unsigned int n_examples = sizeof(t) / sizeof(Tournament);
00065 
00074 class Golf : public Example {
00075 public:
00077   enum {
00078     MODEL_PLAIN,   
00079     MODEL_SYMMETRY 
00080   };
00081   enum {
00082     PROP_PLAIN,    
00083     PROP_DECOMPOSE 
00084   };
00085   int groups;          
00086   int playersInGroup;  
00087   int weeks;           
00088   int players;         
00089 
00091   SetVarArray groupsS;
00092 
00094   SetVar& group(int w, int g) {
00095     return groupsS[w*groups+g];
00096   }
00097 
00099   Golf(const SizeOptions& opt) :
00100     groups(t[opt.size()].groups),
00101     playersInGroup(t[opt.size()].playersInGroup),
00102     weeks(t[opt.size()].weeks),
00103     players(groups*playersInGroup),
00104     groupsS(this,groups*weeks,IntSet::empty,0,players-1,
00105             playersInGroup,playersInGroup) {
00106 
00107     SetVar allPlayers(this, 0, players-1, 0, players-1);
00108 
00109     // Groups in one week must be disjoint
00110     for (int w=0; w<weeks; w++) {
00111       SetVarArgs p(groups);
00112       for (int g=0; g < groups; g++)
00113                p[g] = group(w,g);
00114 
00115       rel(this,SOT_DUNION,p,allPlayers);
00116     }
00117 
00118     // No two golfers play in the same group more than once
00119     for (int w=0; w<weeks; w++) {
00120       for (int g=0; g<groups; g++) {
00121         SetVar v = group(w,g);
00122         SetVar vcompl;
00123         if (opt.propagation() == PROP_DECOMPOSE) {
00124           vcompl = SetVar(this,IntSet::empty,
00125                           Set::Limits::min,Set::Limits::max);
00126           rel(this, v, SRT_CMPL, vcompl);
00127         }
00128         for (int i=(w+1)*groups; i<weeks*groups; i++) {
00129           if (opt.propagation() == PROP_PLAIN) {
00130             SetVar atMostOne(this,IntSet::empty,0,players-1,0,1);
00131             rel(this, v, SOT_INTER, groupsS[i], SRT_EQ, atMostOne);
00132           } else {
00133             SetVar atMostOneC(this,IntSet::empty,
00134                               Set::Limits::min,
00135                               Set::Limits::max,
00136                               Set::Limits::card-1,
00137                               Set::Limits::card);
00138             SetVar groupsSiC(this,IntSet::empty,
00139                              Set::Limits::min,Set::Limits::max);
00140             rel(this, groupsS[i], SRT_CMPL, groupsSiC);
00141             rel(this, vcompl, SOT_UNION, groupsSiC, SRT_EQ, atMostOneC);
00142           }
00143         }
00144       }
00145     }
00146 
00147     if (opt.model() == MODEL_SYMMETRY) {
00148 
00149       /*
00150        * Redundant constraints and static symmetry breaking from
00151        * "Solving Kirkman's Schoolgirl Problem in a Few Seconds"
00152        * Nicolas Barnier, Pascal Brisset, Constraints, 10, 7-21, 2005
00153        *
00154        */
00155 
00156       // Redundant constraint:
00157       // in each week, one player plays in only one group
00158       for (int w=0; w < weeks; w++) {
00159          for (int p=0; p < players; p++) {
00160            BoolVarArgs bs(groups);
00161            for (int g=0; g<groups; g++) {
00162             BoolVar b(this,0,1);
00163             dom(this, group(w,g), SRT_SUP, p, b);
00164             bs[g] = b;
00165           }
00166            linear(this, bs, IRT_EQ, 1);
00167          }
00168        }
00169 
00170       // Redundant constraint:
00171       // any two groups has at most one player in common
00172       atmostOne(this, groupsS, playersInGroup);
00173 
00174       // Symmetry breaking: order groups
00175       for (int w=0; w<weeks; w++) {
00176         for (int g=0; g<groups-1; g++) {
00177           IntVar minG1(this, 0, players-1);
00178           IntVar minG2(this, 0, players-1);
00179           SetVar g1 = group(w,g);
00180           SetVar g2 = group(w,g+1);
00181           min(this, g1, minG1);
00182           min(this, g2, minG2);
00183           rel(this, minG1, IRT_LE, minG2);
00184         }
00185       }
00186 
00187       // Symmetry breaking: order weeks
00188       // minElem(group(w,0)\{0}) < minElem(group(w+1,0)\{0})
00189       for (int w=0; w<weeks-1; w++) {
00190         SetVar g1(this, IntSet::empty, 1, players-1);
00191         SetVar g2(this, IntSet::empty, 1, players-1);
00192         rel(this, g1, SOT_DUNION, IntSet(0,0), SRT_EQ, group(w,0));
00193         rel(this, g2, SOT_DUNION, IntSet(0,0), SRT_EQ, group(w+1,0));
00194         IntVar minG1(this, 0, players-1);
00195         IntVar minG2(this, 0, players-1);
00196         min(this, g1, minG1);
00197         min(this, g2, minG2);
00198         rel(this, minG1, IRT_LE, minG2);
00199       }
00200 
00201       // Initialize the dual variables:
00202       // groupsSInv[w*players+p] is player p's group in week w
00203       IntVarArray groupsSInv(this, weeks*players, 0, groups-1);
00204       for (int w=0; w<weeks; w++) {
00205         for (int p=0; p<players; p++) {
00206           SetVar thisPlayer(this, p,p, 0, players-1);
00207           SetVarArgs thisWeek(groups);
00208           for (int g=0; g<groups; g++)
00209             thisWeek[g] = group(w,g);
00210           element(this, thisWeek, groupsSInv[w*players+p], thisPlayer);
00211         }
00212       }
00213 
00214       // Symmetry breaking: order players
00215       // For all p<groups : groupsSInv[w*players+p] <= p
00216       for (int w=0; w<weeks; w++) {
00217         for (int p=0; p<groups; p++) {
00218           rel(this, groupsSInv[w*players+p], IRT_LQ, p);
00219         }
00220       }
00221 
00222     }
00223 
00224     branch(this, groupsS, SET_VAR_MIN_UNKNOWN_ELEM, SET_VAL_MIN);
00225   }
00226 
00228   virtual void
00229   print(std::ostream& os) {
00230     os << "Tournament plan" << std::endl;
00231 
00232     for (int w=0; w<weeks; w++) {
00233       os << "Week " << w << ": " << std::endl << "    ";
00234       for (int g=0; g<groups; g++) {
00235         if (group(w,g).assigned()) {          
00236           bool first = true;
00237           os << "(";
00238           for (SetVarGlbValues glb(group(w,g)); glb(); ++glb) {
00239             if (first) first = false; else os << " ";
00240             os << glb.val();
00241           }
00242           os << ")";          
00243         } else {
00244           os << "(" << group(w,g) << ")";
00245         }
00246         if (g < groups-1) os << " ";
00247         if (g > 0 && g % 4 == 0) os << std::endl << "    ";
00248       }
00249       os << std::endl;
00250     }
00251   }
00252 
00254   Golf(bool share, Golf& s) : Example(share,s),
00255       groups(s.groups), playersInGroup(s.playersInGroup),
00256       weeks(s.weeks), players(s.players) {
00257     groupsS.update(this, share, s.groupsS);
00258   }
00260   virtual Space*
00261   copy(bool share) {
00262     return new Golf(share,*this);
00263   }
00264 
00266   virtual void
00267   getVars(Gecode::Reflection::VarMap& vm, bool registerOnly) {
00268     vm.putArray(this, groupsS, "groupsS", registerOnly);
00269   }
00270 };
00271 
00275 int
00276 main(int argc, char* argv[]) {
00277   SizeOptions opt("Golf");
00278   opt.model(Golf::MODEL_PLAIN);
00279   opt.model(Golf::MODEL_PLAIN, "none", "no symmetry breaking");
00280   opt.model(Golf::MODEL_SYMMETRY, "symmetry", "static symmetry breaking");
00281   opt.propagation(Golf::PROP_PLAIN);
00282   opt.propagation(Golf::PROP_PLAIN, "plain", "intersection constraints");
00283   opt.propagation(Golf::PROP_DECOMPOSE, "decompose",
00284                   "union and complement constraints");
00285   opt.solutions(1);
00286   opt.parse(argc,argv);
00287   if (opt.size() >= n_examples) {
00288     std::cerr << "Error: size must be between 0 and " << n_examples - 1
00289               << std::endl;
00290     return 1;
00291   }
00292   Example::run<Golf,DFS,SizeOptions>(opt);
00293   return 0;
00294 }
00295 
00296 // STATISTICS: example-any
00297