this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Guido Tack <tack@gecode.org> 5 * 6 * Contributing authors: 7 * Mikael Lagerkvist <lagerkvist@gecode.org> 8 * 9 * Copyright: 10 * Guido Tack, 2004 11 * Mikael Lagerkivst, 2017 12 * 13 * This file is part of Gecode, the generic constraint 14 * development environment: 15 * http://www.gecode.org 16 * 17 * Permission is hereby granted, free of charge, to any person obtaining 18 * a copy of this software and associated documentation files (the 19 * "Software"), to deal in the Software without restriction, including 20 * without limitation the rights to use, copy, modify, merge, publish, 21 * distribute, sublicense, and/or sell copies of the Software, and to 22 * permit persons to whom the Software is furnished to do so, subject to 23 * the following conditions: 24 * 25 * The above copyright notice and this permission notice shall be 26 * included in all copies or substantial portions of the Software. 27 * 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 32 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 33 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 34 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 * 36 */ 37 38#include <gecode/driver.hh> 39#include <gecode/int.hh> 40#include <gecode/set.hh> 41 42using namespace Gecode; 43 44/// \brief %Options for %Golf example 45class GolfOptions : public Options { 46protected: 47 Driver::IntOption _w; //< Number of weeks 48 Driver::IntOption _g; //< Number of groups 49 Driver::IntOption _s; //< Number of players per group 50public: 51 /// Constructor 52 GolfOptions(void) 53 : Options("Golf"), 54 _w("w","number of weeks",9), 55 _g("g","number of groups",8), 56 _s("s","number of players per group",4) { 57 add(_w); 58 add(_g); 59 add(_s); 60 } 61 /// Return number of weeks 62 int w(void) const { return _w.value(); } 63 /// Return number of groups 64 int g(void) const { return _g.value(); } 65 /// Return number of players per group 66 int s(void) const { return _s.value(); } 67}; 68 69/** 70 * \brief %Example: %Golf tournament 71 * 72 * Schedule a golf tournament. This is problem 010 from csplib. 73 * 74 * Note that "Modeling and Programming with Gecode" uses this example 75 * as a case study. 76 * 77 * \ingroup Example 78 * 79 */ 80class Golf : public Script { 81public: 82 /// Model variants 83 enum { 84 MODEL_PLAIN, ///< A simple model 85 MODEL_SYMMETRY ///< Model with symmetry breaking 86 }; 87 /// Propagation 88 enum { 89 PROP_SET, ///< Propagation of pair play amount using set variables 90 PROP_INT, ///< Propagation of pair play amount using int variables and distinct 91 PROP_MIXED, ///< Propagation of pair play amount using both set and int variables 92 }; 93 int g; ///< Number of groups in a week 94 int s; ///< Number of players in a group 95 int w; ///< Number of weeks 96 97 /// The sets representing the groups 98 SetVarArray groups; 99 100 /// Actual model 101 Golf(const GolfOptions& opt) 102 : Script(opt), 103 g(opt.g()), s(opt.s()), w(opt.w()), 104 groups(*this,g*w,IntSet::empty,0,g*s-1, 105 static_cast<unsigned int>(s),static_cast<unsigned int>(s)) { 106 Matrix<SetVarArray> schedule(groups,g,w); 107 108 // Groups in one week must be disjoint 109 SetVar allPlayers(*this, 0,g*s-1, 0,g*s-1); 110 for (int i=0; i<w; i++) 111 rel(*this, setdunion(schedule.row(i)) == allPlayers); 112 113 // No two golfers play in the same group more than once 114 if (opt.propagation() == PROP_SET || opt.propagation() == PROP_MIXED) { 115 // Cardinality of intersection between two groups is at most one 116 for (int i=0; i<groups.size()-1; i++) 117 for (int j=i+1; j<groups.size(); j++) 118 rel(*this, cardinality(groups[i] & groups[j]) <= 1); 119 } 120 if (opt.propagation() == PROP_INT || opt.propagation() == PROP_MIXED) { 121 // Set up table mapping from pairs (p1,p2) (where p1<p2) of players to 122 // unique integer identifiers 123 int playerCount = g * s; 124 TupleSet ts(3); 125 int pairCount=0; 126 for (int p1=0; p1<playerCount-1; p1++) 127 for (int p2=p1+1; p2<playerCount; p2++) 128 ts.add({p1, p2, pairCount++}); 129 ts.finalize(); 130 131 // Collect pairs of golfers into pairs 132 IntVarArgs pairs; 133 for (int i=0; i<groups.size()-1; i++) { 134 // Channel sorted will ensure that for i<j, group[i]<group[j], 135 // ensuring that the tuple set has a valid mapping. 136 IntVarArgs group(*this, s, 0, playerCount-1); 137 channelSorted(*this, group, groups[i]); 138 // Collect all pairs in current group 139 for (int p1=0; p1<group.size()-1; ++p1) { 140 for (int p2=p1+1; p2<group.size(); ++p2) { 141 IntVar pair(*this, 0, pairCount); 142 143 IntVarArgs args; 144 args << group[p1] << group[p2] << pair; 145 extensional(*this, args, ts); 146 147 pairs << pair; 148 } 149 } 150 } 151 152 // All pairs of golfers (using the unique identifiers) must be different 153 distinct(*this, pairs, opt.ipl()); 154 } 155 156 if (opt.model() == MODEL_SYMMETRY) { 157 158 /* 159 * Redundant constraints and static symmetry breaking from 160 * "Solving Kirkman's Schoolgirl Problem in a Few Seconds" 161 * Nicolas Barnier, Pascal Brisset, Constraints, 10, 7-21, 2005 162 * 163 */ 164 165 // Redundant constraint: 166 // in each week, one player plays in only one group 167 for (int j=0; j<w; j++) { 168 for (int p=0; p < g*s; p++) { 169 BoolVarArgs b(g); 170 for (int i=0; i<g; i++) 171 b[i] = expr(*this, (singleton(p) <= schedule(i,j))); 172 linear(*this, b, IRT_EQ, 1); 173 } 174 } 175 176 // Symmetry breaking: order groups 177 for (int j=0; j<w; j++) { 178 IntVarArgs m(g); 179 for (int i=0; i<g; i++) 180 m[i] = expr(*this, min(schedule(i,j))); 181 rel(*this, m, IRT_LE); 182 } 183 184 // Symmetry breaking: order weeks 185 // minElem(group(w,0)\{0}) < minElem(group(w+1,0)\{0}) 186 { 187 IntVarArgs m(w); 188 for (int i=0; i<w; i++) 189 m[i] = expr(*this, min(schedule(0,i)-IntSet(0,0))); 190 rel(*this, m, IRT_LE); 191 } 192 193 // Symmetry breaking: value symmetry of player numbers 194 precede(*this, groups, IntArgs::create(groups.size(),0)); 195 } 196 197 branch(*this, groups, SET_VAR_MIN_MIN(), SET_VAL_MIN_INC()); 198 } 199 200 /// Print solution 201 virtual void 202 print(std::ostream& os) const { 203 os << "Tournament plan" << std::endl; 204 Matrix<SetVarArray> schedule(groups,g,w); 205 for (int j=0; j<w; j++) { 206 os << "Week " << j << ": " << std::endl << " "; 207 os << schedule.row(j) << std::endl; 208 } 209 } 210 211 /// Constructor for copying \a s 212 Golf(Golf& s) : Script(s), g(s.g), s(s.s), w(s.w) { 213 groups.update(*this, s.groups); 214 } 215 /// Copy during cloning 216 virtual Space* 217 copy(void) { 218 return new Golf(*this); 219 } 220}; 221 222/** \brief Main-function 223 * \relates Golf 224 */ 225int 226main(int argc, char* argv[]) { 227 GolfOptions opt; 228 opt.model(Golf::MODEL_PLAIN); 229 opt.model(Golf::MODEL_PLAIN, "none", "no symmetry breaking"); 230 opt.model(Golf::MODEL_SYMMETRY, "symmetry", "static symmetry breaking"); 231 opt.propagation(Golf::PROP_SET); 232 opt.propagation(Golf::PROP_SET, "set", "Use set intersection cardinality for pair play constraints"); 233 opt.propagation(Golf::PROP_INT, "int", "Use integer distinct for pair play constraints"); 234 opt.propagation(Golf::PROP_MIXED, "mixed", "Use set interesection cardinality and integer distinct for pair play constraints"); 235 opt.ipl(IPL_DOM); 236 opt.solutions(1); 237 opt.parse(argc,argv); 238 Script::run<Golf,DFS,GolfOptions>(opt); 239 return 0; 240} 241 242// STATISTICS: example-any