1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /*
3 * Main authors:
4 * Mikael Lagerkvist <lagerkvist@gecode.org>
5 *
6 * Copyright:
7 * Mikael Lagerkvist, 2009
8 *
9 * This file is part of Gecode, the generic constraint
10 * development environment:
11 * http://www.gecode.org
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 */
33
34 #include <gecode/driver.hh>
35 #include <gecode/int.hh>
36 #include <gecode/minimodel.hh>
37
38 #include <iomanip>
39
40 using namespace Gecode;
41
42 // Problems
43 namespace {
44 // Problem data
45 extern const int* problems[];
46 // Number of problems
47 extern const unsigned int n_problems;
48 }
49
50 namespace {
51 /**
52 * \brief %Options for car sequencing problems
53 *
54 * \relates CarSequence
55 */
56 class CarOptions : public SizeOptions {
57 private:
58 /// Max slack parameter
59 Driver::UnsignedIntOption _maxstall;
60
61 public:
62 /// Initialize options for example with name \a s
CarOptions(const char * s)63 CarOptions(const char* s)
64 : SizeOptions(s),
65 _maxstall("maxstall", "Maximum numbere of stalls", 30)
66 {
67 // Add options
68 add(_maxstall);
69 }
70 /// Parse options from arguments \a argv (number is \a argc)
parse(int & argc,char * argv[])71 void parse(int& argc, char* argv[]) {
72 SizeOptions::parse(argc,argv);
73 }
74 /// Get max stalls
maxstall(void) const75 int maxstall(void) const { return _maxstall.value(); }
76 };
77
78
79 /**
80 * \brief Propagator that pushes all occurences of a value to the end.
81 *
82 * This propagator uses a variable array \f$x=\langle
83 * x_1,x_2,\ldots,x_n\rangle\f$, a variable \f$y\f$, and a value
84 * \f$val\f$. It It makes sure that the last \f$y\f$ variables of
85 * \f$x\f$ are assigned the value, and that the value does not
86 * appear in the rest of the array. Furthermore, the constriant
87 * ensure that \$fval\$f isnot adjacent to \$fval-1\$f.
88 *
89 * Since the propagator is custom-made for the car sequencing
90 * example, it relies on the fact that the value will be equal to
91 * the upper bound to speed up computation. For example, it can
92 * safely rely on only subscribing to bound events.
93 *
94 * \relates CarSequence
95 */
96 template <class View>
97 class PushToEnd : public NaryOnePropagator<View,Int::PC_INT_BND> {
98 protected:
99 using NaryOnePropagator<View,Int::PC_INT_BND>::x;
100 using NaryOnePropagator<View,Int::PC_INT_BND>::y;
101 int val;
102
103 /// Constructor for cloning \a p
104 PushToEnd(Space& home, PushToEnd& p);
105 /// Constructor for posting
106 PushToEnd(Space& home, ViewArray<View>& x0, View y0, int val0);
107 public:
108 /// Constructor for rewriting \a p during cloning
109 PushToEnd(Space& home, Propagator& p,
110 ViewArray<View>& x0, View y0, int val0);
111 /// Copy propagator during cloning
112 virtual Actor* copy(Space& home);
113 /// Perform propagation
114 virtual ExecStatus propagate(Space& home, const ModEventDelta& med);
115 /// Post propagator
116 static ExecStatus post(Space& home,
117 ViewArray<View>& x0, View y0, int val0);
118 };
119
120 template <class View>
121 inline
PushToEnd(Space & home,ViewArray<View> & x0,View y0,int val0)122 PushToEnd<View>::PushToEnd(Space& home,
123 ViewArray<View>& x0, View y0, int val0)
124 : NaryOnePropagator<View,Int::PC_INT_BND>(home,x0,y0), val(val0) {}
125
126 template <class View>
127 ExecStatus
post(Space & home,ViewArray<View> & x0,View y0,int val0)128 PushToEnd<View>::post(Space& home,
129 ViewArray<View>& x0, View y0, int val0) {
130 (void) new (home) PushToEnd<View>(home,x0,y0,val0);
131 return ES_OK;
132 }
133
134 template <class View>
135 inline
PushToEnd(Space & home,PushToEnd<View> & p)136 PushToEnd<View>::PushToEnd(Space& home, PushToEnd<View>& p)
137 : NaryOnePropagator<View,Int::PC_INT_BND>(home,p), val(p.val) {}
138
139 template <class View>
140 inline
PushToEnd(Space & home,Propagator & p,ViewArray<View> & x0,View y0,int val0)141 PushToEnd<View>::PushToEnd(Space& home, Propagator& p,
142 ViewArray<View>& x0, View y0, int val0)
143 : NaryOnePropagator<View,Int::PC_INT_BND>(home,p,x0,y0), val(val0) {}
144
145 template <class View>
146 Actor*
copy(Space & home)147 PushToEnd<View>::copy(Space& home) {
148 return new (home) PushToEnd<View>(home,*this);
149 }
150
151 template <class View>
152 ExecStatus
propagate(Space & home,const ModEventDelta &)153 PushToEnd<View>::propagate(Space& home, const ModEventDelta&) {
154 // Find number of required positions
155 int min = 0;
156 for (int i = x.size(); i-- && x[i].min() >= val-1; ) {
157 ++min;
158 }
159 // Find number of possible positions
160 int max = 0;
161 {
162 int i = x.size();
163 while (i--) {
164 if (x[i].max() != val) break;
165 ++max;
166 if (max >= y.max()) break;
167 }
168 // No variables later than max can have value val
169 while (i--) {
170 GECODE_ME_CHECK(x[i].le(home, val));
171 }
172 }
173
174 // Constrain y to be in {min..max}
175 GECODE_ME_CHECK(y.gq(home, min));
176 GECODE_ME_CHECK(y.lq(home, max));
177
178 // At least the y.min() last values have value val
179 for (int i = 0, pos = x.size()-1; i < y.min(); ++i, --pos) {
180 GECODE_ME_CHECK(x[pos].eq(home, val));
181 }
182
183 return y.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX;
184 }
185
186 /** \brief Post PushToEnd propagator.
187 */
pushtoend(Space & home,IntVarArgs x,IntVar y,int val)188 void pushtoend(Space& home, IntVarArgs x, IntVar y, int val) {
189 ViewArray<Int::IntView> vx(home, x);
190 Int::IntView vy(y);
191 GECODE_ES_FAIL(PushToEnd<Int::IntView>::post(home, vx, vy, val));
192 }
193
194 }
195
196
197 /**
198 * \brief %Example: Car sequencing
199 *
200 * See problem 1 at http://www.csplib.org/.
201 *
202 * This model uses extra stall-slots instead of violations, as proposed
203 * in "Combining Forces to Solve the Car Sequencing Problem", Perron
204 * and Shaw, CPAIOR 2004.
205 *
206 * \ingroup Example
207 */
208 class CarSequencing : public Script {
209 public:
210 /// Branching variants
211 enum {
212 BRANCH_INORDER, ///< Branch from left to right
213 BRANCH_MIDDLE ///< Branch from middle out
214 };
215 /// Propagation variants
216 enum {
217 PROP_REGULAR, ///< Use regular constraints
218 PROP_CUSTOM ///< Use custom constraint
219 };
220 protected:
221 /// Problem number
222 const int problem;
223 /// Number of cars
224 const int ncars;
225 /// Number of options
226 const int noptions;
227 /// Number of classes
228 const int nclasses;
229 /// Maximum number of stalls
230 const int maxstall;
231 /// Stall number
232 const int stallval;
233 /// End number
234 const int endval;
235 /// Number of stalls (cost to minimize)
236 IntVar nstall;
237 /// Number of end markers
238 IntVar nend;
239 /// Sequence of cars produced
240 IntVarArray s;
241 public:
242 /// Initial model
CarSequencing(const CarOptions & opt)243 CarSequencing(const CarOptions& opt)
244 : Script(opt),
245 problem(opt.size()),
246 ncars(problems[problem][0]),
247 noptions(problems[problem][1]),
248 nclasses(problems[problem][2]),
249 maxstall(opt.maxstall()),
250 stallval(nclasses),
251 endval(nclasses+1),
252 nstall(*this, 0, maxstall),
253 nend(*this, 0, maxstall),
254 s(*this, ncars+maxstall, 0, nclasses+1)
255 {
256 // Read problem
257 const int* probit = problems[problem] + 3;
258
259 // Sequence requirements for the options.
260 IntArgs max(noptions), block(noptions);
261 for (int i = 0; i < noptions; ++i ) {
262 max[i] = *probit++;
263 }
264 for (int i = 0; i < noptions; ++i ) {
265 block[i] = *probit++;
266 }
267 // Number of cars per class
268 IntArgs ncc(nclasses);
269 // What classes require an option
270 IntSetArgs classes(noptions);
271 int** cdata = new int*[noptions];
272 for (int i = noptions; i--; ) cdata[i] = new int[nclasses];
273 int* n = new int[noptions];
274 for (int i = noptions; i--; ) n[i] = 0;
275 // Read data
276 for (int c = 0; c < nclasses; ++c) {
277 probit++;
278 ncc[c] = *probit++;
279 for (int o = 0; o < noptions; ++o) {
280 if (*probit++) {
281 cdata[o][n[o]++] = c;
282 }
283 }
284 }
285 // Transfer specification data to int-sets
286 for (int o = noptions; o--; ) {
287 classes[o] = IntSet(cdata[o], n[o]);
288 delete [] cdata[o];
289 }
290 delete [] cdata;
291 delete [] n;
292
293 // Count the cars
294 {
295 IntSetArgs c(nclasses+2);
296 for (int i = nclasses; i--; ) {
297 c[i] = IntSet(ncc[i], ncc[i]);
298 }
299 c[stallval] = IntSet(0, maxstall);
300 c[ endval] = IntSet(0, maxstall);
301 count(*this, s, c);
302 }
303
304 // Count number of end and stalls
305 count(*this, s, stallval, IRT_EQ, nstall);
306 count(*this, s, endval, IRT_EQ, nend);
307 rel(*this, nstall+nend == maxstall);
308
309 // Make sure nothing is overloaded
310 IntSet one(1, 1);
311 for (int o = noptions; o--; ) {
312 // sb[i] reflects if car s[i] has option o
313 BoolVarArgs sb(s.size());
314 for (int i = s.size(); i--; ) {
315 BoolVar b(*this, 0, 1);
316 dom(*this, s[i], classes[o], b);
317 sb[i] = b;
318 }
319 sequence(*this, sb, one, block[o], 0, max[o]);
320 }
321
322 // End-markers located at end only
323 switch (opt.propagation()) {
324 case PROP_REGULAR: {
325 IntArgs notend(nclasses), notstallend(nclasses+1);
326 for (int i = nclasses; i--; ) {
327 notend[i] = i;
328 notstallend[i] = i;
329 }
330 notstallend[nclasses] = stallval;
331 REG r = *REG(notend) + REG(notstallend) + *REG(endval);
332 extensional(*this, s, r);
333 for (int pos = s.size()-1, i = 0; i < maxstall; ++i, --pos) {
334 rel(*this, (nend > i) >> (s[pos]==endval));
335 }
336 } break;
337 case PROP_CUSTOM: {
338 pushtoend(*this, s, nend, endval);
339 } break;
340 }
341
342
343 // Branching
344 switch (opt.branching()) {
345 case BRANCH_INORDER:
346 branch(*this, s, INT_VAR_NONE(), INT_VAL_MIN());
347 break;
348 case BRANCH_MIDDLE: {
349 IntVarArgs m(s.size());
350 int mid = s.size() / 2;
351 int pos = 0;
352 m[pos++] = s[mid];
353 for (int i = 1; i <= m.size()/2; ++i) {
354 if (mid-i >= 0)
355 m[pos++] = s[mid-i];
356 if (mid+i < s.size())
357 m[pos++] = s[mid+i];
358 }
359 assert(pos == m.size());
360 branch(*this, m, INT_VAR_NONE(), INT_VAL_MIN());
361 break;
362 }
363 }
364 }
365
366 /// Return cost
constrain(const Space & _best)367 virtual void constrain(const Space& _best) {
368 const CarSequencing& best = static_cast<const CarSequencing&>(_best);
369 rel(*this, nstall, IRT_LE, best.nstall.val());
370 }
371
372 /// Print solution
373 virtual void
print(std::ostream & os) const374 print(std::ostream& os) const {
375 int width = nclasses > 9 ? 2 : 1;
376 const char* space = nclasses > 9 ? " " : "";
377 os << "Stall slots=" << nstall
378 << ", End slots=" << nend << std::endl;
379 int i = 0;
380 for (; i < s.size(); ++i) {
381 if (s[i].assigned()) {
382 int v = s[i].val();
383 if (v == endval) break;
384 if (v == stallval) os << space << "_ ";
385 else os << std::setw(width) << v << " ";
386 } else {
387 os << space << "? ";
388 }
389 if ((i+1)%20 == 0) os << std::endl;
390 }
391 if (i%20)
392 os << std::endl;
393 os << std::endl;
394 }
395
396 /// Constructor for cloning \a s
CarSequencing(CarSequencing & cs)397 CarSequencing(CarSequencing& cs)
398 : Script(cs),
399 problem(cs.problem),
400 ncars(cs.ncars),
401 noptions(cs.noptions),
402 nclasses(cs.nclasses),
403 maxstall(cs.maxstall),
404 stallval(cs.stallval),
405 endval(cs.endval)
406 {
407 nstall.update(*this, cs.nstall);
408 nend.update(*this, cs.nend);
409 s.update(*this, cs.s);
410 }
411 /// Copy during cloning
412 virtual Space*
copy(void)413 copy(void) {
414 return new CarSequencing(*this);
415 }
416 };
417
418 /** \brief Main-function
419 * \relates CarSequencing
420 */
421 int
main(int argc,char * argv[])422 main(int argc, char* argv[]) {
423 CarOptions opt("CarSequencing");
424 opt.solutions(0);
425 opt.size(0);
426 opt.branching(CarSequencing::BRANCH_INORDER);
427 opt.branching(CarSequencing::BRANCH_INORDER, "inorder");
428 opt.branching(CarSequencing::BRANCH_MIDDLE, "middle");
429 opt.propagation(CarSequencing::PROP_CUSTOM);
430 opt.propagation(CarSequencing::PROP_REGULAR, "regular");
431 opt.propagation(CarSequencing::PROP_CUSTOM, "custom");
432 opt.parse(argc,argv);
433 if (opt.size() >= n_problems) {
434 std::cerr << "Error: size must be between 0 and "
435 << n_problems-1 << std::endl;
436 return 1;
437 }
438
439 Script::run<CarSequencing,BAB,CarOptions>(opt);
440 return 0;
441 }
442
443
444 namespace {
445 /// Problems from CSPLib
446
447 /// Simple initial example
448 const int p0[] = {
449 10, 5, 6,
450 1, 2, 1, 2, 1,
451 2, 3, 3, 5, 5,
452 0, 1, 1, 0, 1, 1, 0,
453 1, 1, 0, 0, 0, 1, 0,
454 2, 2, 0, 1, 0, 0, 1,
455 3, 2, 0, 1, 0, 1, 0,
456 4, 2, 1, 0, 1, 0, 0,
457 5, 2, 1, 1, 0, 0, 0
458 };
459
460 // ---------------------------------
461 // Problem 4/72 (Regin & Puget // 1)
462 // ---------------------------------
463 const int p1[] = {
464 100, 5, 22,
465 1, 2, 1, 2, 1,
466 2, 3, 3, 5, 5,
467 0, 6, 1, 0, 0, 1, 0,
468 1, 10, 1, 1, 1, 0, 0,
469 2, 2, 1, 1, 0, 0, 1,
470 3, 2, 0, 1, 1, 0, 0,
471 4, 8, 0, 0, 0, 1, 0,
472 5, 15, 0, 1, 0, 0, 0,
473 6, 1, 0, 1, 1, 1, 0,
474 7, 5, 0, 0, 1, 1, 0,
475 8, 2, 1, 0, 1, 1, 0,
476 9, 3, 0, 0, 1, 0, 0,
477 10, 2, 1, 0, 1, 0, 0,
478 11, 1, 1, 1, 1, 0, 1,
479 12, 8, 0, 1, 0, 1, 0,
480 13, 3, 1, 0, 0, 1, 1,
481 14, 10, 1, 0, 0, 0, 0,
482 15, 4, 0, 1, 0, 0, 1,
483 16, 4, 0, 0, 0, 0, 1,
484 17, 2, 1, 0, 0, 0, 1,
485 18, 4, 1, 1, 0, 0, 0,
486 19, 6, 1, 1, 0, 1, 0,
487 20, 1, 1, 0, 1, 0, 1,
488 21, 1, 1, 1, 1, 1, 1,
489 };
490
491 // --------------------------------
492 // Problem 6/76, (Regin & Puget // 2)
493 // --------------------------------
494 const int p2[] = {
495 100, 5, 22,
496 1, 2, 1, 2, 1,
497 2, 3, 3, 5, 5,
498 0, 13, 1, 0, 0, 0, 0,
499 1, 8, 0, 0, 0, 1, 0,
500 2, 7, 0, 1, 0, 0, 0,
501 3, 1, 1, 0, 0, 1, 0,
502 4, 12, 0, 0, 1, 0, 0,
503 5, 5, 0, 1, 0, 1, 0,
504 6, 5, 0, 0, 1, 1, 0,
505 7, 6, 0, 1, 1, 0, 0,
506 8, 3, 1, 0, 0, 0, 1,
507 9, 12, 1, 1, 0, 0, 0,
508 10, 8, 1, 1, 0, 1, 0,
509 11, 2, 1, 0, 0, 1, 1,
510 12, 2, 1, 1, 1, 0, 0,
511 13, 1, 0, 1, 0, 1, 1,
512 14, 4, 1, 0, 1, 0, 0,
513 15, 4, 0, 1, 0, 0, 1,
514 16, 1, 1, 1, 0, 1, 1,
515 17, 2, 1, 0, 1, 1, 0,
516 18, 1, 0, 0, 0, 0, 1,
517 19, 1, 1, 1, 1, 1, 0,
518 20, 1, 1, 1, 0, 0, 1,
519 21, 1, 0, 1, 1, 1, 0,
520 };
521
522 // ---------------------------------
523 // Problem 10/93, (Regin & Puget // 3)
524 // ---------------------------------
525 const int p3[] = {
526 100, 5, 25,
527 1, 2, 1, 2, 1,
528 2, 3, 3, 5, 5,
529 0, 7, 1, 0, 0, 1, 0,
530 1, 11, 1, 1, 0, 0, 0,
531 2, 1, 0, 1, 1, 1, 1,
532 3, 3, 1, 0, 1, 0, 0,
533 4, 15, 0, 1, 0, 0, 0,
534 5, 2, 1, 0, 1, 1, 0,
535 6, 8, 0, 1, 0, 1, 0,
536 7, 5, 0, 0, 1, 0, 0,
537 8, 3, 0, 0, 0, 1, 0,
538 9, 4, 0, 1, 1, 1, 0,
539 10, 5, 1, 0, 0, 0, 0,
540 11, 2, 1, 1, 1, 0, 1,
541 12, 6, 0, 1, 1, 0, 0,
542 13, 2, 0, 0, 1, 0, 1,
543 14, 2, 0, 1, 0, 0, 1,
544 15, 4, 1, 1, 1, 1, 0,
545 16, 3, 1, 0, 0, 0, 1,
546 17, 5, 1, 1, 0, 1, 0,
547 18, 2, 1, 1, 1, 0, 0,
548 19, 4, 1, 1, 0, 0, 1,
549 20, 1, 1, 0, 0, 1, 1,
550 21, 1, 1, 1, 0, 1, 1,
551 22, 1, 0, 1, 0, 1, 1,
552 23, 1, 0, 1, 1, 0, 1,
553 24, 2, 0, 0, 0, 0, 1,
554 };
555
556 // --------------
557 // Problem 16/81,
558 // --------------
559 const int p4[] = {
560 100, 5, 26,
561 1, 2, 1, 2, 1,
562 2, 3, 3, 5, 5,
563 0, 10, 1, 0, 0, 0, 0,
564 1, 2, 0, 0, 0, 0, 1,
565 2, 8, 0, 1, 0, 1, 0,
566 3, 8, 0, 0, 0, 1, 0,
567 4, 6, 0, 1, 1, 0, 0,
568 5, 11, 0, 1, 0, 0, 0,
569 6, 3, 0, 0, 1, 0, 0,
570 7, 2, 0, 0, 1, 1, 0,
571 8, 7, 1, 1, 0, 0, 0,
572 9, 2, 1, 0, 0, 1, 1,
573 10, 4, 1, 0, 1, 0, 0,
574 11, 7, 1, 0, 0, 1, 0,
575 12, 1, 1, 1, 1, 0, 1,
576 13, 3, 0, 1, 1, 1, 0,
577 14, 4, 0, 1, 0, 0, 1,
578 15, 5, 1, 1, 1, 0, 0,
579 16, 2, 1, 1, 0, 0, 1,
580 17, 1, 1, 0, 1, 1, 1,
581 18, 2, 1, 0, 1, 1, 0,
582 19, 3, 1, 0, 0, 0, 1,
583 20, 2, 0, 1, 1, 0, 1,
584 21, 1, 0, 1, 0, 1, 1,
585 22, 3, 1, 1, 0, 1, 0,
586 23, 1, 0, 0, 1, 1, 1,
587 24, 1, 1, 1, 1, 1, 1,
588 25, 1, 1, 1, 1, 1, 0,
589 };
590
591 // ----------------------------------
592 // Problem 19/71, (Regin & Puget // 4)
593 // ----------------------------------
594 const int p5[] = {
595 100, 5, 23,
596 1, 2, 1, 2, 1,
597 2, 3, 3, 5, 5,
598 0, 2, 0, 0, 0, 1, 1,
599 1, 2, 0, 0, 1, 0, 1,
600 2, 5, 0, 1, 1, 1, 0,
601 3, 4, 0, 0, 0, 1, 0,
602 4, 4, 0, 1, 0, 1, 0,
603 5, 1, 1, 1, 0, 0, 1,
604 6, 3, 1, 1, 1, 0, 1,
605 7, 4, 0, 0, 1, 0, 0,
606 8, 19, 0, 1, 0, 0, 0,
607 9, 7, 1, 1, 0, 1, 0,
608 10, 10, 1, 0, 0, 0, 0,
609 11, 1, 0, 0, 1, 1, 0,
610 12, 5, 1, 1, 1, 1, 0,
611 13, 2, 1, 0, 1, 1, 0,
612 14, 6, 1, 1, 0, 0, 0,
613 15, 4, 1, 1, 1, 0, 0,
614 16, 8, 1, 0, 0, 1, 0,
615 17, 1, 1, 0, 0, 0, 1,
616 18, 4, 0, 1, 1, 0, 0,
617 19, 2, 0, 0, 0, 0, 1,
618 20, 4, 0, 1, 0, 0, 1,
619 21, 1, 1, 1, 0, 1, 1,
620 22, 1, 0, 1, 1, 0, 1,
621 };
622
623 const int* problems[] = {
624 &p0[0],
625 &p1[0],
626 &p2[0],
627 &p3[0],
628 &p4[0],
629 &p5[0],
630 };
631
632 /// The number of instances
633 const unsigned int n_problems = sizeof(problems)/sizeof(int*);
634 };
635
636 // STATISTICS: example-any
637
638