this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christopher Mears <chris.mears@monash.edu>
5 *
6 * Copyright:
7 * Christopher Mears, 2012
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/int/ldsb.hh>
35#include <gecode/int/branch.hh>
36
37#include <map>
38
39namespace Gecode { namespace Int { namespace LDSB {
40
41 std::pair<int,int>
42 findVar(int *indices, unsigned int n_values, unsigned int seq_size, int index) {
43 unsigned int seq = 0;
44 unsigned int pos = 0;
45 for (unsigned int i=0U ; i<n_values ; i++) {
46 if (indices[i] == index)
47 return std::pair<int,int>(seq,pos);
48 pos++;
49 if (pos == seq_size) {
50 pos = 0;
51 seq++;
52 }
53 }
54 return std::pair<int,int>(-1,-1);
55 }
56
57}}}
58
59namespace Gecode {
60 using namespace Int::LDSB;
61
62 SymmetryHandle VariableSymmetry(const IntVarArgs& vars) {
63 ArgArray<VarImpBase*> a(vars.size());
64 for (int i = 0 ; i < vars.size() ; i++)
65 a[i] = vars[i].varimp();
66 return SymmetryHandle(new VariableSymmetryObject(a));
67 }
68 SymmetryHandle VariableSymmetry(const BoolVarArgs& vars) {
69 ArgArray<VarImpBase*> a(vars.size());
70 for (int i = 0 ; i < vars.size() ; i++)
71 a[i] = vars[i].varimp();
72 return SymmetryHandle(new VariableSymmetryObject(a));
73 }
74 SymmetryHandle VariableSymmetry(const IntVarArgs& x,
75 const IntArgs& indices) {
76 IntVarArgs xs(indices.size());
77 for (int i = 0 ; i < indices.size() ; i++)
78 xs[i] = x[indices[i]];
79 return VariableSymmetry(xs);
80 }
81 SymmetryHandle ValueSymmetry(const IntArgs& vs) {
82 return SymmetryHandle(new ValueSymmetryObject(IntSet(vs)));
83 }
84 SymmetryHandle ValueSymmetry(const IntSet& vs) {
85 return SymmetryHandle(new ValueSymmetryObject(vs));
86 }
87 SymmetryHandle ValueSymmetry(IntVar x) {
88 return ValueSymmetry(IntSet(x.min(), x.max()));
89 }
90 SymmetryHandle VariableSequenceSymmetry(const IntVarArgs& vars, int ss) {
91 ArgArray<VarImpBase*> a(vars.size());
92 for (int i = 0 ; i < vars.size() ; i++)
93 a[i] = vars[i].varimp();
94 return SymmetryHandle(new VariableSequenceSymmetryObject(a, ss));
95 }
96 SymmetryHandle VariableSequenceSymmetry(const BoolVarArgs& vars, int ss) {
97 ArgArray<VarImpBase*> a(vars.size());
98 for (int i = 0 ; i < vars.size() ; i++)
99 a[i] = vars[i].varimp();
100 return SymmetryHandle(new VariableSequenceSymmetryObject(a, ss));
101 }
102 SymmetryHandle ValueSequenceSymmetry(const IntArgs& vs, int ss) {
103 return SymmetryHandle(new ValueSequenceSymmetryObject(vs, ss));
104 }
105
106 SymmetryHandle values_reflect(int lower, int upper) {
107 int n = (upper-lower+1)/2;
108 IntArgs a(n*2);
109 int i = lower;
110 int j = upper;
111 int k = 0;
112 while (i < j) {
113 a[k] = j;
114 a[n+k] = i;
115 i++;
116 j--;
117 k++;
118 }
119 return ValueSequenceSymmetry(a,n);
120 }
121 SymmetryHandle values_reflect(const IntVar& x) {
122 return values_reflect(x.min(), x.max());
123 }
124}
125
126
127namespace Gecode { namespace Int { namespace LDSB {
128
129 /// Map from variable implementation to index
130 class VariableMap : public std::map<VarImpBase*,int> {};
131
132 /*
133 * The duplication in createIntSym/createBoolSym is undesirable,
134 * and so is the use of dynamic_cast to tell the symmetries
135 * apart.
136 */
137
138 /// Create an integer symmetry implementation from a symmetry handle
139 SymmetryImp<IntView>*
140 createIntSym(Space& home, const SymmetryHandle& s,
141 VariableMap variableMap) {
142 VariableSymmetryObject* varref =
143 dynamic_cast<VariableSymmetryObject*>(s.ref);
144 ValueSymmetryObject* valref =
145 dynamic_cast<ValueSymmetryObject*>(s.ref);
146 VariableSequenceSymmetryObject* varseqref =
147 dynamic_cast<VariableSequenceSymmetryObject*>(s.ref);
148 ValueSequenceSymmetryObject* valseqref =
149 dynamic_cast<ValueSequenceSymmetryObject*>(s.ref);
150 if (varref) {
151 int n = varref->nxs;
152 int* indices = home.alloc<int>(n);
153 for (int i = 0 ; i < n ; i++) {
154 VariableMap::const_iterator index = variableMap.find(varref->xs[i]);
155 if (index == variableMap.end())
156 throw LDSBUnbranchedVariable("VariableSymmetryObject::createInt");
157 indices[i] = index->second;
158 }
159 return new (home) VariableSymmetryImp<IntView>(home, indices, n);
160 }
161 if (valref) {
162 int n = valref->values.size();
163 int *vs = home.alloc<int>(n);
164 int i = 0;
165 for (IntSetValues v(valref->values) ; v() ; ++v) {
166 vs[i] = v.val();
167 i++;
168 }
169 return new (home) ValueSymmetryImp<IntView>(home, vs, n);
170 }
171 if (varseqref) {
172 int n = varseqref->nxs;
173 int* indices = home.alloc<int>(n);
174 for (int i = 0 ; i < n ; i++) {
175 VariableMap::const_iterator index =
176 variableMap.find(varseqref->xs[i]);
177 if (index == variableMap.end())
178 throw LDSBUnbranchedVariable("VariableSequenceSymmetryObject::createInt");
179 indices[i] = index->second;
180 }
181 return new (home) VariableSequenceSymmetryImp<IntView>(home, indices, n,
182 varseqref->seq_size);
183 }
184 if (valseqref) {
185 unsigned int n = valseqref->values.size();
186 int *vs = home.alloc<int>(n);
187 for (unsigned int i = 0 ; i < n ; i++)
188 vs[i] = valseqref->values[i];
189 return new (home) ValueSequenceSymmetryImp<IntView>(home, vs, n,
190 valseqref->seq_size);
191 }
192 GECODE_NEVER;
193 return nullptr;
194 }
195
196 /// Create a boolean symmetry implementation from a symmetry handle
197 SymmetryImp<BoolView>* createBoolSym(Space& home, const SymmetryHandle& s,
198 VariableMap variableMap) {
199 VariableSymmetryObject* varref =
200 dynamic_cast<VariableSymmetryObject*>(s.ref);
201 ValueSymmetryObject* valref =
202 dynamic_cast<ValueSymmetryObject*>(s.ref);
203 VariableSequenceSymmetryObject* varseqref =
204 dynamic_cast<VariableSequenceSymmetryObject*>(s.ref);
205 ValueSequenceSymmetryObject* valseqref =
206 dynamic_cast<ValueSequenceSymmetryObject*>(s.ref);
207 if (varref) {
208 int n = varref->nxs;
209 int* indices = home.alloc<int>(n);
210 for (int i = 0 ; i < n ; i++) {
211 VariableMap::const_iterator index = variableMap.find(varref->xs[i]);
212 if (index == variableMap.end())
213 throw LDSBUnbranchedVariable("VariableSymmetryObject::createBool");
214 indices[i] = index->second;
215 }
216 return new (home) VariableSymmetryImp<BoolView>(home, indices, n);
217 }
218 if (valref) {
219 int n = valref->values.size();
220 int *vs = home.alloc<int>(n);
221 int i = 0;
222 for (IntSetValues v(valref->values) ; v() ; ++v) {
223 vs[i] = v.val();
224 i++;
225 }
226 return new (home) ValueSymmetryImp<BoolView>(home, vs, n);
227 }
228 if (varseqref) {
229 int n = varseqref->nxs;
230 int* indices = home.alloc<int>(n);
231 for (int i = 0 ; i < n ; i++) {
232 VariableMap::const_iterator index =
233 variableMap.find(varseqref->xs[i]);
234 if (index == variableMap.end())
235 throw LDSBUnbranchedVariable("VariableSequenceSymmetryObject::createBool");
236 indices[i] = index->second;
237 }
238 return new (home) VariableSequenceSymmetryImp<BoolView>(home, indices,
239 n, varseqref->seq_size);
240 }
241 if (valseqref) {
242 unsigned int n = valseqref->values.size();
243 int *vs = home.alloc<int>(n);
244 for (unsigned int i = 0 ; i < n ; i++)
245 vs[i] = valseqref->values[i];
246 return new (home) ValueSequenceSymmetryImp<BoolView>(home, vs, n,
247 valseqref->seq_size);
248 }
249 GECODE_NEVER;
250 return nullptr;
251 }
252}}}
253
254namespace Gecode {
255
256 using namespace Int::LDSB;
257
258 void
259 branch(Home home, const IntVarArgs& x,
260 IntVarBranch vars, IntValBranch vals,
261 const Symmetries& syms,
262 IntBranchFilter bf,
263 IntVarValPrint vvp) {
264 using namespace Int;
265 if (home.failed()) return;
266 vars.expand(home,x);
267 ViewArray<IntView> xv(home,x);
268 ViewSel<IntView>* vs[1] = {
269 Branch::viewsel(home,vars)
270 };
271 switch (vals.select()) {
272 case IntValBranch::SEL_SPLIT_MIN:
273 case IntValBranch::SEL_SPLIT_MAX:
274 case IntValBranch::SEL_RANGE_MIN:
275 case IntValBranch::SEL_RANGE_MAX:
276 case IntValBranch::SEL_VALUES_MIN:
277 case IntValBranch::SEL_VALUES_MAX:
278 throw LDSBBadValueSelection("Int::LDSB::branch");
279 break;
280 case IntValBranch::SEL_VAL_COMMIT:
281 if (vals.commit())
282 throw LDSBBadValueSelection("Int::LDSB::branch");
283 // If vals.commit() is valid, it means it will commit with
284 // binary branching, which is OK for LDSB, so we
285 // fall through
286 default:
287 // Construct mapping from each variable in the array to its index
288 // in the array.
289 VariableMap variableMap;
290 for (int i = 0 ; i < x.size() ; i++)
291 variableMap[x[i].varimp()] = i;
292
293 // Convert the modelling-level Symmetries object into an array of
294 // SymmetryImp objects.
295 int n = syms.size();
296 SymmetryImp<IntView>** array =
297 static_cast<Space&>(home).alloc<SymmetryImp<IntView>* >(n);
298 for (int i = 0 ; i < n ; i++) {
299 array[i] = createIntSym(home, syms[i], variableMap);
300 }
301
302 postldsbbrancher<IntView,1,int,2>
303 (home,xv,vs,Branch::valselcommit(home,vals),
304 array,n,bf,vvp);
305 }
306 }
307
308 void
309 branch(Home home, const IntVarArgs& x,
310 TieBreak<IntVarBranch> vars, IntValBranch vals,
311 const Symmetries& syms,
312 IntBranchFilter bf,
313 IntVarValPrint vvp) {
314 using namespace Int;
315 if (home.failed()) return;
316 vars.a.expand(home,x);
317 if ((vars.a.select() == IntVarBranch::SEL_NONE) ||
318 (vars.a.select() == IntVarBranch::SEL_RND))
319 vars.b = INT_VAR_NONE();
320 vars.b.expand(home,x);
321 if ((vars.b.select() == IntVarBranch::SEL_NONE) ||
322 (vars.b.select() == IntVarBranch::SEL_RND))
323 vars.c = INT_VAR_NONE();
324 vars.c.expand(home,x);
325 if ((vars.c.select() == IntVarBranch::SEL_NONE) ||
326 (vars.c.select() == IntVarBranch::SEL_RND))
327 vars.d = INT_VAR_NONE();
328 vars.d.expand(home,x);
329 if (vars.b.select() == IntVarBranch::SEL_NONE) {
330 branch(home,x,vars.a,vals,syms,bf,vvp);
331 } else {
332 // Construct mapping from each variable in the array to its index
333 // in the array.
334 VariableMap variableMap;
335 for (int i = 0 ; i < x.size() ; i++)
336 variableMap[x[i].varimp()] = i;
337
338 // Convert the modelling-level Symmetries object into an array of
339 // SymmetryImp objects.
340 int n = syms.size();
341 SymmetryImp<IntView>** array =
342 static_cast<Space&>(home).alloc<SymmetryImp<IntView>* >(n);
343 for (int i = 0 ; i < n ; i++) {
344 array[i] = createIntSym(home, syms[i], variableMap);
345 }
346
347 ViewArray<IntView> xv(home,x);
348 if (vars.c.select() == IntVarBranch::SEL_NONE) {
349 ViewSel<IntView>* vs[2] = {
350 Branch::viewsel(home,vars.a),Branch::viewsel(home,vars.b)
351 };
352 switch (vals.select()) {
353 case IntValBranch::SEL_SPLIT_MIN:
354 case IntValBranch::SEL_SPLIT_MAX:
355 case IntValBranch::SEL_RANGE_MIN:
356 case IntValBranch::SEL_RANGE_MAX:
357 case IntValBranch::SEL_VALUES_MIN:
358 case IntValBranch::SEL_VALUES_MAX:
359 throw LDSBBadValueSelection("Int::LDSB::branch");
360 break;
361 case IntValBranch::SEL_VAL_COMMIT:
362 if (vals.commit())
363 throw LDSBBadValueSelection("Int::LDSB::branch");
364 // If vals.commit() is valid, it means it will commit with
365 // binary branching, which is OK for LDSB, so we
366 // fall through
367 default:
368 postldsbbrancher<IntView,2,int,2>
369 (home,xv,vs,Branch::valselcommit(home,vals),
370 array,n,bf,vvp);
371 }
372 } else if (vars.d.select() == IntVarBranch::SEL_NONE) {
373 ViewSel<IntView>* vs[3] = {
374 Branch::viewsel(home,vars.a),Branch::viewsel(home,vars.b),
375 Branch::viewsel(home,vars.c)
376 };
377 switch (vals.select()) {
378 case IntValBranch::SEL_SPLIT_MIN:
379 case IntValBranch::SEL_SPLIT_MAX:
380 case IntValBranch::SEL_RANGE_MIN:
381 case IntValBranch::SEL_RANGE_MAX:
382 case IntValBranch::SEL_VALUES_MIN:
383 case IntValBranch::SEL_VALUES_MAX:
384 throw LDSBBadValueSelection("Int::LDSB::branch");
385 break;
386 case IntValBranch::SEL_VAL_COMMIT:
387 if (vals.commit())
388 throw LDSBBadValueSelection("Int::LDSB::branch");
389 // If vals.commit() is valid, it means it will commit with
390 // binary branching, which is OK for LDSB, so we
391 // fall through
392 default:
393 postldsbbrancher<IntView,3,int,2>
394 (home,xv,vs,Branch::valselcommit(home,vals),
395 array,n,bf,vvp);
396 }
397 } else {
398 ViewSel<IntView>* vs[4] = {
399 Branch::viewsel(home,vars.a),Branch::viewsel(home,vars.b),
400 Branch::viewsel(home,vars.c),Branch::viewsel(home,vars.d)
401 };
402 switch (vals.select()) {
403 case IntValBranch::SEL_SPLIT_MIN:
404 case IntValBranch::SEL_SPLIT_MAX:
405 case IntValBranch::SEL_RANGE_MIN:
406 case IntValBranch::SEL_RANGE_MAX:
407 case IntValBranch::SEL_VALUES_MIN:
408 case IntValBranch::SEL_VALUES_MAX:
409 throw LDSBBadValueSelection("Int::LDSB::branch");
410 break;
411 case IntValBranch::SEL_VAL_COMMIT:
412 if (vals.commit())
413 throw LDSBBadValueSelection("Int::LDSB::branch");
414 // If vals.commit() is valid, it means it will commit with
415 // binary branching, which is OK for LDSB, so we
416 // fall through
417 default:
418 postldsbbrancher<IntView,4,int,2>
419 (home,xv,vs,Branch::valselcommit(home,vals),
420 array,n,bf,vvp);
421 }
422 }
423 }
424 }
425
426 void
427 branch(Home home, const BoolVarArgs& x,
428 BoolVarBranch vars, BoolValBranch vals,
429 const Symmetries& syms,
430 BoolBranchFilter bf,
431 BoolVarValPrint vvp) {
432 using namespace Int;
433 if (home.failed()) return;
434 vars.expand(home,x);
435 ViewArray<BoolView> xv(home,x);
436 ViewSel<BoolView>* vs[1] = {
437 Branch::viewsel(home,vars)
438 };
439
440 // Construct mapping from each variable in the array to its index
441 // in the array.
442 VariableMap variableMap;
443 for (int i = 0 ; i < x.size() ; i++)
444 variableMap[x[i].varimp()] = i;
445
446 // Convert the modelling-level Symmetries object into an array of
447 // SymmetryImp objects.
448 int n = syms.size();
449 SymmetryImp<BoolView>** array =
450 static_cast<Space&>(home).alloc<SymmetryImp<BoolView>* >(n);
451 for (int i = 0 ; i < n ; i++) {
452 array[i] = createBoolSym(home, syms[i], variableMap);
453 }
454
455 // Technically these "bad" value selection could in fact work with
456 // LDSB, because they degenerate to binary splitting for
457 // Booleans. Nonetheless, we explicitly forbid them for
458 // consistency with the integer version.
459 switch (vals.select()) {
460 case BoolValBranch::SEL_VAL_COMMIT:
461 if (vals.commit())
462 throw LDSBBadValueSelection("Int::LDSB::branch");
463 // If vals.commit() is valid, it means it will commit with
464 // binary branching, which is OK for LDSB, so we
465 // fall through
466 default:
467 postldsbbrancher<BoolView,1,int,2>
468 (home,xv,vs,Branch::valselcommit(home,vals),array,n,bf,vvp);
469 }
470 }
471
472
473 void
474 branch(Home home, const BoolVarArgs& x,
475 TieBreak<BoolVarBranch> vars, BoolValBranch vals,
476 const Symmetries& syms,
477 BoolBranchFilter bf,
478 BoolVarValPrint vvp) {
479 using namespace Int;
480 if (home.failed()) return;
481 vars.a.expand(home,x);
482 if ((vars.a.select() == BoolVarBranch::SEL_NONE) ||
483 (vars.a.select() == BoolVarBranch::SEL_RND))
484 vars.b = BOOL_VAR_NONE();
485 vars.b.expand(home,x);
486 if ((vars.b.select() == BoolVarBranch::SEL_NONE) ||
487 (vars.b.select() == BoolVarBranch::SEL_RND))
488 vars.c = BOOL_VAR_NONE();
489 vars.c.expand(home,x);
490 if ((vars.c.select() == BoolVarBranch::SEL_NONE) ||
491 (vars.c.select() == BoolVarBranch::SEL_RND))
492 vars.d = BOOL_VAR_NONE();
493 vars.d.expand(home,x);
494 if (vars.b.select() == BoolVarBranch::SEL_NONE) {
495 branch(home,x,vars.a,vals,syms,bf,vvp);
496 } else {
497 // Construct mapping from each variable in the array to its index
498 // in the array.
499 VariableMap variableMap;
500 for (int i = 0 ; i < x.size() ; i++)
501 variableMap[x[i].varimp()] = i;
502
503 // Convert the modelling-level Symmetries object into an array of
504 // SymmetryImp objects.
505 int n = syms.size();
506 SymmetryImp<BoolView>** array =
507 static_cast<Space&>(home).alloc<SymmetryImp<BoolView>* >(n);
508 for (int i = 0 ; i < n ; i++) {
509 array[i] = createBoolSym(home, syms[i], variableMap);
510 }
511
512 // Technically these "bad" value selection could in fact work with
513 // LDSB, because they degenerate to binary splitting for
514 // Booleans. Nonetheless, we explicitly forbid them for
515 // consistency with the integer version.
516 switch (vals.select()) {
517 case BoolValBranch::SEL_VAL_COMMIT:
518 if (vals.commit())
519 throw LDSBBadValueSelection("Int::LDSB::branch");
520 // If vals.commit() is valid, it means it will commit with
521 // binary branching, which is OK for LDSB, so we
522 // fall through
523 default:
524 ;
525 // Do nothing and continue.
526 }
527
528 ViewArray<BoolView> xv(home,x);
529 ValSelCommitBase<BoolView,int>*
530 vsc = Branch::valselcommit(home,vals);
531 if (vars.c.select() == BoolVarBranch::SEL_NONE) {
532 ViewSel<BoolView>* vs[2] = {
533 Branch::viewsel(home,vars.a),Branch::viewsel(home,vars.b)
534 };
535 postldsbbrancher<BoolView,2,int,2>(home,xv,vs,vsc,array,n,bf,vvp);
536 } else if (vars.d.select() == BoolVarBranch::SEL_NONE) {
537 ViewSel<BoolView>* vs[3] = {
538 Branch::viewsel(home,vars.a),Branch::viewsel(home,vars.b),
539 Branch::viewsel(home,vars.c)
540 };
541 postldsbbrancher<BoolView,3,int,2>(home,xv,vs,vsc,array,n,bf,vvp);
542 } else {
543 ViewSel<BoolView>* vs[4] = {
544 Branch::viewsel(home,vars.a),Branch::viewsel(home,vars.b),
545 Branch::viewsel(home,vars.c),Branch::viewsel(home,vars.d)
546 };
547 postldsbbrancher<BoolView,4,int,2>(home,xv,vs,vsc,array,n,bf,vvp);
548 }
549 }
550 }
551
552}
553
554
555
556// STATISTICS: int-branch