this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christian Schulte <schulte@gecode.org>
5 *
6 * Contributing authors:
7 * Guido Tack <tack@gecode.org>
8 *
9 * Copyright:
10 * Christian Schulte, 2003
11 * Guido Tack, 2004
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
38namespace Gecode { namespace Int {
39
40 /*
41 * Range lists
42 *
43 */
44
45#define GECODE_INT_RL2PD(r) reinterpret_cast<ptrdiff_t>(r)
46#define GECODE_INT_PD2RL(p) reinterpret_cast<RangeList*>(p)
47
48 forceinline
49 IntVarImp::RangeList::RangeList(void) {}
50
51 forceinline
52 IntVarImp::RangeList::RangeList(int min, int max)
53 : _min(min), _max(max) {}
54
55 forceinline
56 IntVarImp::RangeList::RangeList(int min, int max, RangeList* p, RangeList* n)
57 : _min(min), _max(max) {
58 _next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(p)^GECODE_INT_RL2PD(n));
59 }
60
61 forceinline IntVarImp::RangeList*
62 IntVarImp::RangeList::next(const RangeList* p) const {
63 return GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^GECODE_INT_RL2PD(p));
64 }
65 forceinline IntVarImp::RangeList*
66 IntVarImp::RangeList::prev(const RangeList* n) const {
67 return GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^GECODE_INT_RL2PD(n));
68 }
69 forceinline void
70 IntVarImp::RangeList::prevnext(RangeList* p, RangeList* n) {
71 _next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(p)^GECODE_INT_RL2PD(n));
72 }
73 forceinline void
74 IntVarImp::RangeList::next(RangeList* o, RangeList* n) {
75 _next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^
76 (GECODE_INT_RL2PD(o)^GECODE_INT_RL2PD(n)));
77 }
78 forceinline void
79 IntVarImp::RangeList::prev(RangeList* o, RangeList* n) {
80 _next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^
81 (GECODE_INT_RL2PD(o)^GECODE_INT_RL2PD(n)));
82 }
83 forceinline void
84 IntVarImp::RangeList::fix(RangeList* n) {
85 _next = n;
86 }
87
88 forceinline void
89 IntVarImp::RangeList::min(int n) {
90 _min = n;
91 }
92 forceinline void
93 IntVarImp::RangeList::max(int n) {
94 _max = n;
95 }
96
97 forceinline int
98 IntVarImp::RangeList::min(void) const {
99 return _min;
100 }
101 forceinline int
102 IntVarImp::RangeList::max(void) const {
103 return _max;
104 }
105 forceinline unsigned int
106 IntVarImp::RangeList::width(void) const {
107 return static_cast<unsigned int>(_max - _min) + 1;
108 }
109
110
111 forceinline void
112 IntVarImp::RangeList::operator delete(void*) {}
113
114 forceinline void
115 IntVarImp::RangeList::operator delete(void*, Space&) {
116 GECODE_NEVER;
117 }
118 forceinline void
119 IntVarImp::RangeList::operator delete(void*, void*) {
120 GECODE_NEVER;
121 }
122
123 forceinline void*
124 IntVarImp::RangeList::operator new(size_t, Space& home) {
125 return home.fl_alloc<sizeof(RangeList)>();
126 }
127
128 forceinline void*
129 IntVarImp::RangeList::operator new(size_t, void* p) {
130 return p;
131 }
132
133 forceinline void
134 IntVarImp::RangeList::dispose(Space& home, RangeList* p, RangeList* l) {
135 RangeList* c = this;
136 while (c != l) {
137 RangeList* n = c->next(p);
138 c->fix(n);
139 p=c; c=n;
140 }
141 home.fl_dispose<sizeof(RangeList)>(this,l);
142 }
143
144 forceinline void
145 IntVarImp::RangeList::dispose(Space& home, RangeList* l) {
146 home.fl_dispose<sizeof(RangeList)>(this,l);
147 }
148
149 forceinline void
150 IntVarImp::RangeList::dispose(Space& home) {
151 home.fl_dispose<sizeof(RangeList)>(this,this);
152 }
153
154#undef GECODE_INT_RL2PD
155#undef GECODE_INT_PD2RL
156
157 /*
158 * Mainitaining range lists for variable domain
159 *
160 */
161
162 forceinline IntVarImp::RangeList*
163 IntVarImp::fst(void) const {
164 return dom.next(nullptr);
165 }
166
167 forceinline void
168 IntVarImp::fst(IntVarImp::RangeList* f) {
169 dom.prevnext(nullptr,f);
170 }
171
172 forceinline IntVarImp::RangeList*
173 IntVarImp::lst(void) const {
174 return _lst;
175 }
176
177 forceinline void
178 IntVarImp::lst(IntVarImp::RangeList* l) {
179 _lst = l;
180 }
181
182 /*
183 * Creation of new variable implementations
184 *
185 */
186
187 forceinline
188 IntVarImp::IntVarImp(Space& home, int min, int max)
189 : IntVarImpBase(home), dom(min,max,nullptr,nullptr), holes(0) {}
190
191 forceinline
192 IntVarImp::IntVarImp(Space& home, const IntSet& d)
193 : IntVarImpBase(home), dom(d.min(),d.max()) {
194 if (d.ranges() > 1) {
195 int n = d.ranges();
196 assert(n >= 2);
197 RangeList* r = home.alloc<RangeList>(n);
198 fst(r); lst(r+n-1);
199 unsigned int h = static_cast<unsigned int>(d.max()-d.min())+1;
200 h -= d.width(0);
201 r[0].min(d.min(0)); r[0].max(d.max(0));
202 r[0].prevnext(nullptr,&r[1]);
203 for (int i = 1; i < n-1; i++) {
204 h -= d.width(i);
205 r[i].min(d.min(i)); r[i].max(d.max(i));
206 r[i].prevnext(&r[i-1],&r[i+1]);
207 }
208 h -= d.width(n-1);
209 r[n-1].min(d.min(n-1)); r[n-1].max(d.max(n-1));
210 r[n-1].prevnext(&r[n-2],nullptr);
211 holes = h;
212 } else {
213 fst(nullptr); holes = 0;
214 }
215 }
216
217
218 /*
219 * Operations on integer variable implementations
220 *
221 */
222
223 forceinline int
224 IntVarImp::min(void) const {
225 return dom.min();
226 }
227 forceinline int
228 IntVarImp::max(void) const {
229 return dom.max();
230 }
231 forceinline int
232 IntVarImp::val(void) const {
233 assert(dom.min() == dom.max());
234 return dom.min();
235 }
236
237 forceinline bool
238 IntVarImp::range(void) const {
239 return fst() == nullptr;
240 }
241 forceinline bool
242 IntVarImp::assigned(void) const {
243 return dom.min() == dom.max();
244 }
245
246
247 forceinline unsigned int
248 IntVarImp::width(void) const {
249 return dom.width();
250 }
251
252 forceinline unsigned int
253 IntVarImp::size(void) const {
254 return dom.width() - holes;
255 }
256
257 forceinline unsigned int
258 IntVarImp::regret_min(void) const {
259 if (fst() == nullptr) {
260 return (dom.min() == dom.max()) ? 0U : 1U;
261 } else if (dom.min() == fst()->max()) {
262 return static_cast<unsigned int>(fst()->next(nullptr)->min()-dom.min());
263 } else {
264 return 1U;
265 }
266 }
267 forceinline unsigned int
268 IntVarImp::regret_max(void) const {
269 if (fst() == nullptr) {
270 return (dom.min() == dom.max()) ? 0U : 1U;
271 } else if (dom.max() == lst()->min()) {
272 return static_cast<unsigned int>(dom.max()-lst()->prev(nullptr)->max());
273 } else {
274 return 1U;
275 }
276 }
277
278
279
280 /*
281 * Tests
282 *
283 */
284
285 forceinline bool
286 IntVarImp::in(int n) const {
287 if ((n < dom.min()) || (n > dom.max()))
288 return false;
289 return (fst() == nullptr) || in_full(n);
290 }
291 forceinline bool
292 IntVarImp::in(long long int n) const {
293 if ((n < dom.min()) || (n > dom.max()))
294 return false;
295 return (fst() == nullptr) || in_full(static_cast<int>(n));
296 }
297
298
299 /*
300 * Accessing rangelists for iteration
301 *
302 */
303
304 forceinline const IntVarImp::RangeList*
305 IntVarImp::ranges_fwd(void) const {
306 return (fst() == nullptr) ? &dom : fst();
307 }
308
309 forceinline const IntVarImp::RangeList*
310 IntVarImp::ranges_bwd(void) const {
311 return (fst() == nullptr) ? &dom : lst();
312 }
313
314
315
316 /*
317 * Support for delta information
318 *
319 */
320 forceinline int
321 IntVarImp::min(const Delta& d) {
322 return static_cast<const IntDelta&>(d).min();
323 }
324 forceinline int
325 IntVarImp::max(const Delta& d) {
326 return static_cast<const IntDelta&>(d).max();
327 }
328 forceinline unsigned int
329 IntVarImp::width(const Delta& d) {
330 return static_cast<const IntDelta&>(d).width();
331 }
332 forceinline bool
333 IntVarImp::any(const Delta& d) {
334 return static_cast<const IntDelta&>(d).any();
335 }
336
337
338 /*
339 * Tell operations (to be inlined: performing bounds checks first)
340 *
341 */
342
343 forceinline ModEvent
344 IntVarImp::gq(Space& home, int n) {
345 if (n <= dom.min()) return ME_INT_NONE;
346 if (n > dom.max()) return fail(home);
347 ModEvent me = gq_full(home,n);
348 GECODE_ASSUME((me == ME_INT_FAILED) |
349 (me == ME_INT_VAL) |
350 (me == ME_INT_BND));
351 return me;
352 }
353 forceinline ModEvent
354 IntVarImp::gq(Space& home, long long int n) {
355 if (n <= dom.min()) return ME_INT_NONE;
356 if (n > dom.max()) return fail(home);
357 ModEvent me = gq_full(home,static_cast<int>(n));
358 GECODE_ASSUME((me == ME_INT_FAILED) |
359 (me == ME_INT_VAL) |
360 (me == ME_INT_BND));
361 return me;
362 }
363
364 forceinline ModEvent
365 IntVarImp::lq(Space& home, int n) {
366 if (n >= dom.max()) return ME_INT_NONE;
367 if (n < dom.min()) return fail(home);
368 ModEvent me = lq_full(home,n);
369 GECODE_ASSUME((me == ME_INT_FAILED) |
370 (me == ME_INT_VAL) |
371 (me == ME_INT_BND));
372 return me;
373 }
374 forceinline ModEvent
375 IntVarImp::lq(Space& home, long long int n) {
376 if (n >= dom.max()) return ME_INT_NONE;
377 if (n < dom.min()) return fail(home);
378 ModEvent me = lq_full(home,static_cast<int>(n));
379 GECODE_ASSUME((me == ME_INT_FAILED) |
380 (me == ME_INT_VAL) |
381 (me == ME_INT_BND));
382 return me;
383 }
384
385 forceinline ModEvent
386 IntVarImp::eq(Space& home, int n) {
387 if ((n < dom.min()) || (n > dom.max()))
388 return fail(home);
389 if ((n == dom.min()) && (n == dom.max()))
390 return ME_INT_NONE;
391 ModEvent me = eq_full(home,n);
392 GECODE_ASSUME((me == ME_INT_FAILED) | (me == ME_INT_VAL));
393 return me;
394 }
395 forceinline ModEvent
396 IntVarImp::eq(Space& home, long long int m) {
397 if ((m < dom.min()) || (m > dom.max()))
398 return fail(home);
399 int n = static_cast<int>(m);
400 if ((n == dom.min()) && (n == dom.max()))
401 return ME_INT_NONE;
402 ModEvent me = eq_full(home,n);
403 GECODE_ASSUME((me == ME_INT_FAILED) | (me == ME_INT_VAL));
404 return me;
405 }
406
407 forceinline ModEvent
408 IntVarImp::nq(Space& home, int n) {
409 if ((n < dom.min()) || (n > dom.max()))
410 return ME_INT_NONE;
411 return nq_full(home,n);
412 }
413 forceinline ModEvent
414 IntVarImp::nq(Space& home, long long int d) {
415 if ((d < dom.min()) || (d > dom.max()))
416 return ME_INT_NONE;
417 return nq_full(home,static_cast<int>(d));
418 }
419
420
421 /*
422 * Forward range iterator for rangelists
423 *
424 */
425
426 forceinline
427 IntVarImpFwd::IntVarImpFwd(void) {}
428 forceinline
429 IntVarImpFwd::IntVarImpFwd(const IntVarImp* x)
430 : p(nullptr), c(x->ranges_fwd()) {}
431 forceinline void
432 IntVarImpFwd::init(const IntVarImp* x) {
433 p=nullptr; c=x->ranges_fwd();
434 }
435
436 forceinline bool
437 IntVarImpFwd::operator ()(void) const {
438 return c != nullptr;
439 }
440 forceinline void
441 IntVarImpFwd::operator ++(void) {
442 const IntVarImp::RangeList* n=c->next(p); p=c; c=n;
443 }
444
445 forceinline int
446 IntVarImpFwd::min(void) const {
447 return c->min();
448 }
449 forceinline int
450 IntVarImpFwd::max(void) const {
451 return c->max();
452 }
453 forceinline unsigned int
454 IntVarImpFwd::width(void) const {
455 return c->width();
456 }
457
458
459 /*
460 * Backward range iterator for rangelists
461 *
462 */
463
464 forceinline
465 IntVarImpBwd::IntVarImpBwd(void) {}
466 forceinline
467 IntVarImpBwd::IntVarImpBwd(const IntVarImp* x)
468 : n(nullptr), c(x->ranges_bwd()) {}
469 forceinline void
470 IntVarImpBwd::init(const IntVarImp* x) {
471 n=nullptr; c=x->ranges_bwd();
472 }
473
474 forceinline bool
475 IntVarImpBwd::operator ()(void) const {
476 return c != nullptr;
477 }
478 forceinline void
479 IntVarImpBwd::operator ++(void) {
480 const IntVarImp::RangeList* p=c->prev(n); n=c; c=p;
481 }
482
483 forceinline int
484 IntVarImpBwd::min(void) const {
485 return c->min();
486 }
487 forceinline int
488 IntVarImpBwd::max(void) const {
489 return c->max();
490 }
491 forceinline unsigned int
492 IntVarImpBwd::width(void) const {
493 return c->width();
494 }
495
496
497 /*
498 * Iterator-based domain operations
499 *
500 */
501 template<class I>
502 forceinline ModEvent
503 IntVarImp::narrow_r(Space& home, I& ri, bool depends) {
504 // Is new domain empty?
505 if (!ri())
506 return fail(home);
507
508 int min0 = ri.min();
509 int max0 = ri.max();
510 ++ri;
511
512 ModEvent me;
513
514 // Is new domain range?
515 if (!ri()) {
516 // Remove possible rangelist (if it was not a range, the domain
517 // must have been narrowed!)
518 if (fst()) {
519 fst()->dispose(home,nullptr,lst());
520 fst(nullptr); holes = 0;
521 }
522 const int min1 = dom.min(); dom.min(min0);
523 const int max1 = dom.max(); dom.max(max0);
524 if ((min0 == min1) && (max0 == max1))
525 return ME_INT_NONE;
526 me = (min0 == max0) ? ME_INT_VAL : ME_INT_BND;
527 goto notify;
528 }
529
530 if (depends || range()) {
531 // Construct new rangelist
532 RangeList* f = new (home) RangeList(min0,max0,nullptr,nullptr);
533 RangeList* l = f;
534 unsigned int s = static_cast<unsigned int>(max0-min0+1);
535 do {
536 RangeList* n = new (home) RangeList(ri.min(),ri.max(),l,nullptr);
537 l->next(nullptr,n);
538 l = n;
539 s += ri.width();
540 ++ri;
541 } while (ri());
542 if (fst() != nullptr)
543 fst()->dispose(home,nullptr,lst());
544 fst(f); lst(l);
545
546 // Check for modification
547 if (size() == s)
548 return ME_INT_NONE;
549
550 const int min1 = dom.min(); min0 = f->min(); dom.min(min0);
551 const int max1 = dom.max(); max0 = l->max(); dom.max(max0);
552 holes = width() - s;
553
554 me = ((min0 == min1) && (max0 == max1)) ? ME_INT_DOM : ME_INT_BND;
555 goto notify;
556 } else {
557 // Set up two sentinel elements
558 RangeList f, l;
559 // Put all ranges between sentinels
560 f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
561 fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
562
563 // Number of values removed (potential holes)
564 unsigned int h = 0;
565 // The previous range
566 RangeList* p = &f;
567 // The current range
568 RangeList* r = f.next(nullptr);
569
570 while (true) {
571 assert((r != &f) && (r != &l));
572 if (r->max() < min0) {
573 // Entire range removed
574 h += r->width();
575 RangeList* n=r->next(p);
576 p->next(r,n); n->prev(r,p);
577 r->dispose(home);
578 r=n;
579 if (r == &l)
580 goto done;
581 } else if ((r->min() == min0) && (r->max() == max0)) {
582 // Range unchanged
583 RangeList* n=r->next(p); p=r; r=n;
584 if (r == &l)
585 goto done;
586 if (!ri())
587 goto done;
588 min0=ri.min(); max0=ri.max(); ++ri;
589 } else {
590 // Range might have been split into many small ranges
591 assert((r->min() <= min0) && (max0 <= r->max()));
592 h += r->width();
593 int end = r->max();
594 // Copy first range
595 r->min(min0); r->max(max0);
596 assert(h > r->width());
597 h -= r->width();
598 {
599 RangeList* n=r->next(p); p=r; r=n;
600 }
601 while (true) {
602 if (!ri())
603 goto done;
604 min0=ri.min(); max0=ri.max(); ++ri;
605 if (max0 > end)
606 break;
607 assert(h > static_cast<unsigned int>(max0-min0+1));
608 h -= max0-min0+1;
609 RangeList* n = new (home) RangeList(min0,max0,p,r);
610 p->next(r,n); r->prev(p,n);
611 p=n;
612 }
613 if (r == &l)
614 goto done;
615 }
616 }
617 done:
618
619 // Remove remaining ranges
620 while (r != &l) {
621 h += r->width();
622 RangeList* n=r->next(p);
623 p->next(r,n); n->prev(r,p);
624 r->dispose(home);
625 r=n;
626 }
627
628 assert((r == &l) && !ri());
629
630 // New first and last ranges
631 RangeList* fn = f.next(nullptr);
632 RangeList* ln = l.prev(nullptr);
633
634 // All ranges pruned?
635 assert(fn != &l);
636
637 // Only a single range left?
638 assert(fn != ln);
639
640 // The number of removed values
641 holes += h;
642 // Unlink sentinel ranges
643 fn->prev(&f,nullptr); ln->next(&l,nullptr);
644 // How many values where removed at the bounds
645 unsigned int b = (static_cast<unsigned int>(fn->min()-dom.min()) +
646 static_cast<unsigned int>(dom.max()-ln->max()));
647 // Set new first and last ranges
648 fst(fn); lst(ln);
649
650 if (b > 0) {
651 assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
652 dom.min(fn->min()); dom.max(ln->max());
653 holes -= b;
654 me = ME_INT_BND; goto notify;
655 }
656
657 if (h > 0) {
658 assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
659 me = ME_INT_DOM; goto notify;
660 }
661 return ME_INT_NONE;
662 }
663 notify:
664 IntDelta d;
665 return notify(home,me,d);
666 }
667
668 template<class I>
669 forceinline ModEvent
670 IntVarImp::inter_r(Space& home, I& i, bool) {
671 IntVarImpFwd j(this);
672 Iter::Ranges::Inter<I,IntVarImpFwd> ij(i,j);
673 return narrow_r(home,ij,true);
674 }
675
676 template<class I>
677 forceinline ModEvent
678 IntVarImp::minus_r(Space& home, I& i, bool depends) {
679 if (depends) {
680 IntVarImpFwd j(this);
681 Iter::Ranges::Diff<IntVarImpFwd,I> ij(j,i);
682 return narrow_r(home,ij,true);
683 }
684
685 // Skip all ranges that are too small
686 while (i() && (i.max() < dom.min()))
687 ++i;
688
689 // Is there no range left or all are too large?
690 if (!i() || (i.min() > dom.max()))
691 return ME_INT_NONE;
692
693 int i_min = i.min();
694 int i_max = i.max();
695 ++i;
696
697 if ((i_min <= dom.min()) && (i_max >= dom.max()))
698 return fail(home);
699
700 if ((i_min > dom.min()) && (i_max >= dom.max()))
701 return lq(home,i_min-1);
702
703 if ((i_min <= dom.min()) && (i_max < dom.max()) &&
704 (!i() || (i.min() > dom.max())))
705 return gq(home,i_max+1);
706
707 // Set up two sentinel elements
708 RangeList f, l;
709 // Put all ranges between sentinels
710 if (range()) {
711 // Create a new rangelist just for simplicity
712 RangeList* n = new (home) RangeList(min(),max(),&f,&l);
713 f.prevnext(nullptr,n); l.prevnext(n,nullptr);
714 } else {
715 // Link the two sentinel elements
716 f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
717 fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
718 }
719
720 // Number of values removed (potential holes)
721 unsigned int h = 0;
722 // The previous range
723 RangeList* p = &f;
724 // The current range
725 RangeList* r = f.next(nullptr);
726
727 while (true) {
728 assert((r != &f) && (r != &l));
729 if (i_min > r->max()) {
730 RangeList* n=r->next(p); p=r; r=n;
731 if (r == &l)
732 break;
733 } else if (i_max < r->min()) {
734 if (!i())
735 break;
736 i_min = i.min();
737 i_max = i.max();
738 ++i;
739 } else if ((i_min <= r->min()) && (r->max() <= i_max)) {
740 // r is included in i: remove entire range r
741 h += r->width();
742 RangeList* n=r->next(p);
743 p->next(r,n); n->prev(r,p);
744 r->dispose(home);
745 r=n;
746 if (r == &l)
747 break;
748 } else if ((i_min > r->min()) && (i_max < r->max())) {
749 // i is included in r: create new range before the current one
750 h += static_cast<unsigned int>(i_max - i_min) + 1;
751 RangeList* n = new (home) RangeList(r->min(),i_min-1,p,r);
752 r->min(i_max+1);
753 p->next(r,n); r->prev(p,n);
754 p=n;
755 if (!i())
756 break;
757 i_min = i.min();
758 i_max = i.max();
759 ++i;
760 } else if (i_max < r->max()) {
761 assert(i_min <= r->min());
762 // i ends before r: adjust minimum of r
763 h += i_max-r->min()+1;
764 r->min(i_max+1);
765 if (!i())
766 break;
767 i_min = i.min();
768 i_max = i.max();
769 ++i;
770 } else {
771 assert((i_max >= r->max()) && (r->min() < i_min));
772 // r ends before i: adjust maximum of r
773 h += r->max()-i_min+1;
774 r->max(i_min-1);
775 RangeList* n=r->next(p); p=r; r=n;
776 if (r == &l)
777 break;
778 }
779 }
780
781 // New first and last ranges
782 RangeList* fn = f.next(nullptr);
783 RangeList* ln = l.prev(nullptr);
784
785 // All ranges pruned?
786 if (fn == &l) {
787 fst(nullptr); lst(nullptr); holes=0;
788 return fail(home);
789 }
790
791 ModEvent me;
792 unsigned int b;
793
794 // Only a single range left?
795 if (fn == ln) {
796 assert(h > 0);
797 dom.min(fn->min()); dom.max(fn->max());
798 fn->dispose(home);
799 fst(nullptr); lst(nullptr);
800 holes = 0;
801 me = assigned() ? ME_INT_VAL : ME_INT_BND;
802 goto notify;
803 }
804
805 // The number of removed values
806 holes += h;
807 // Unlink sentinel ranges
808 fn->prev(&f,nullptr); ln->next(&l,nullptr);
809 // How many values where removed at the bounds
810 b = (static_cast<unsigned int>(fn->min()-dom.min()) +
811 static_cast<unsigned int>(dom.max()-ln->max()));
812 // Set new first and last ranges
813 fst(fn); lst(ln);
814
815 if (b > 0) {
816 assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
817 dom.min(fn->min()); dom.max(ln->max());
818 holes -= b;
819 me = ME_INT_BND; goto notify;
820 }
821
822 if (h > 0) {
823 assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
824 me = ME_INT_DOM; goto notify;
825 }
826
827 return ME_INT_NONE;
828 notify:
829 IntDelta d;
830 return notify(home,me,d);
831 }
832
833 template<class I>
834 forceinline ModEvent
835 IntVarImp::narrow_v(Space& home, I& i, bool depends) {
836 Iter::Values::ToRanges<I> r(i);
837 return narrow_r(home,r,depends);
838 }
839
840 template<class I>
841 forceinline ModEvent
842 IntVarImp::inter_v(Space& home, I& i, bool depends) {
843 Iter::Values::ToRanges<I> r(i);
844 return inter_r(home,r,depends);
845 }
846
847 template<class I>
848 forceinline ModEvent
849 IntVarImp::minus_v(Space& home, I& i, bool depends) {
850 if (depends) {
851 Iter::Values::ToRanges<I> r(i);
852 return minus_r(home, r, true);
853 }
854
855 // Skip all values that are too small
856 while (i() && (i.val() < dom.min()))
857 ++i;
858
859 // Is there no value left or all are too large?
860 if (!i() || (i.val() > dom.max()))
861 return ME_INT_NONE;
862
863 int v = i.val();
864 // Skip values that are the same
865 do {
866 ++i;
867 } while (i() && (i.val() == v));
868
869 // Is there only a single value to be pruned?
870 if (!i() || (i.val() > dom.max()))
871 return nq_full(home,v);
872
873 // Set up two sentinel elements
874 RangeList f, l;
875 // Put all ranges between sentinels
876 if (range()) {
877 // Create a new rangelist just for simplicity
878 RangeList* n = new (home) RangeList(min(),max(),&f,&l);
879 f.prevnext(nullptr,n); l.prevnext(n,nullptr);
880 } else {
881 // Link the two sentinel elements
882 f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
883 fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
884 }
885
886 // Number of values removed (potential holes)
887 unsigned int h = 0;
888 // The previous range
889 RangeList* p = &f;
890 // The current range
891 RangeList* r = f.next(nullptr);
892
893 while (true) {
894 assert((r != &f) && (r != &l));
895 if (v > r->max()) {
896 // Move to next range
897 RangeList* n=r->next(p); p=r; r=n;
898 if (r == &l)
899 break;
900 } else {
901 if ((v == r->min()) && (v == r->max())) {
902 // Remove range
903 h++;
904 RangeList* n=r->next(p);
905 p->next(r,n); n->prev(r,p);
906 r->dispose(home);
907 r=n;
908 if (r == &l)
909 break;
910 } else if (v == r->min()) {
911 h++; r->min(v+1);
912 } else if (v == r->max()) {
913 h++; r->max(v-1);
914 RangeList* n=r->next(p); p=r; r=n;
915 if (r == &l)
916 break;
917 } else if (v > r->min()) {
918 // Create new range before the current one
919 assert(v < r->max());
920 h++;
921 RangeList* n = new (home) RangeList(r->min(),v-1,p,r);
922 r->min(v+1);
923 p->next(r,n); r->prev(p,n);
924 p=n;
925 }
926 if (!i())
927 break;
928 // Move to next value
929 v = i.val(); ++i;
930 }
931 }
932 assert((r == &l) || !i());
933
934 // New first and last ranges
935 RangeList* fn = f.next(nullptr);
936 RangeList* ln = l.prev(nullptr);
937
938 // All ranges pruned?
939 if (fn == &l) {
940 fst(nullptr); lst(nullptr); holes=0;
941 return fail(home);
942 }
943
944 IntDelta d;
945
946 // Only a single range left?
947 if (fn == ln) {
948 assert(h > 0);
949 dom.min(fn->min()); dom.max(fn->max());
950 fn->dispose(home);
951 fst(nullptr); lst(nullptr);
952 holes = 0;
953 if (assigned())
954 return notify(home,ME_INT_VAL,d);
955 else
956 return notify(home,ME_INT_BND,d);
957 }
958
959 // The number of removed values
960 holes += h;
961 // Unlink sentinel ranges
962 fn->prev(&f,nullptr); ln->next(&l,nullptr);
963 // How many values where removed at the bounds
964 unsigned int b = (static_cast<unsigned int>(fn->min()-dom.min()) +
965 static_cast<unsigned int>(dom.max()-ln->max()));
966 // Set new first and last ranges
967 fst(fn); lst(ln);
968
969 if (b > 0) {
970 assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
971 dom.min(fn->min()); dom.max(ln->max());
972 holes -= b;
973 return notify(home,ME_INT_BND,d);
974 }
975
976 if (h > 0) {
977 assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
978 return notify(home,ME_INT_DOM,d);
979 }
980
981 return ME_INT_NONE;
982 }
983
984
985 /*
986 * Copying a variable
987 *
988 */
989
990 forceinline IntVarImp*
991 IntVarImp::copy(Space& home) {
992 return copied() ? static_cast<IntVarImp*>(forward())
993 : perform_copy(home);
994 }
995
996
997 forceinline ModEventDelta
998 IntVarImp::med(ModEvent me) {
999 return IntVarImpBase::med(me);
1000 }
1001
1002}}
1003
1004// STATISTICS: int-var