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 * Copyright: 7 * Christian Schulte, 2006 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 34namespace Gecode { namespace Int { namespace Linear { 35 36 /** 37 * \brief %Set for support information 38 * 39 * Records supported positions of values such that with iteration 40 * the supported values can be reconstructed. 41 * 42 */ 43 class SupportSet { 44 private: 45 /// Bitset for storing support information 46 Support::BitSetBase bs; 47 public: 48 /// Default constructor 49 SupportSet(void); 50 /// Initialize support set with cardinality \a n 51 void init(Region& r, unsigned int n); 52 /// Record that there is support at position \a i 53 void support(unsigned int i); 54 /// Check whether position \arg i has support 55 bool supported(unsigned int i) const; 56 57 private: 58 /// Support-based iterator: iterates values to be removed 59 class ResultIter : public ViewValues<IntView> { 60 protected: 61 /// The support set used 62 const SupportSet& s; 63 /// The current position of the value 64 unsigned int p; 65 public: 66 /// Initialize iterator 67 ResultIter(const SupportSet& s0, const IntView& x); 68 /// Increment to next supported value 69 void operator ++(void); 70 }; 71 72 public: 73 /// Perform tell according to recorded support information on \arg x 74 ModEvent tell(Space& home, IntView& x) const; 75 }; 76 77 /** 78 * \brief Base-class for support-based iterator 79 * 80 */ 81 template<class Val> 82 class SupportIter { 83 protected: 84 /// Integer coefficient for view 85 int a; 86 /// Integer view 87 IntView x; 88 /// Set of support for values in x 89 SupportSet s; 90 /// Current value 91 int c; 92 /// Position of current value 93 unsigned int p; 94 /// Lower bound information for value 95 Val l; 96 /// Upper bound information for value 97 Val u; 98 public: 99 /// Initialize view 100 void init(Region& r, int a, const IntView& x, Val l, Val u); 101 /// Record value at current position as supported 102 void support(void); 103 /// Tell back new variable domain according to support found 104 ModEvent tell(Space& home); 105 }; 106 107 108 /** 109 * \brief Support-based iterator for positive view 110 * 111 */ 112 template<class Val> 113 class PosSupportIter : public SupportIter<Val> { 114 private: 115 /// Iterate ranges of integer view in increasing order 116 IntVarImpFwd i; 117 // Using-declarations for dependant names 118 using SupportIter<Val>::a; 119 using SupportIter<Val>::x; 120 using SupportIter<Val>::s; 121 using SupportIter<Val>::c; 122 using SupportIter<Val>::p; 123 using SupportIter<Val>::l; 124 using SupportIter<Val>::u; 125 public: 126 /// Reset iterator to beginning and adjust \arg d accordingly 127 bool reset(Val& d); 128 /// Adjust \arg d and return true if next value still works 129 bool adjust(Val& d); 130 }; 131 132 133 /** 134 * \brief Support-based iterator for negative view 135 * 136 */ 137 template<class Val> 138 class NegSupportIter : public SupportIter<Val> { 139 private: 140 /// Iterate ranges of integer view in decreasing order 141 IntVarImpBwd i; 142 // Using-declarations for dependant names 143 using SupportIter<Val>::a; 144 using SupportIter<Val>::x; 145 using SupportIter<Val>::s; 146 using SupportIter<Val>::c; 147 using SupportIter<Val>::p; 148 using SupportIter<Val>::l; 149 using SupportIter<Val>::u; 150 public: 151 /// Reset iterator to beginning and adjust \arg d accordingly 152 bool reset(Val& d); 153 /// Adjust \arg d and return true if next value still works 154 bool adjust(Val& d); 155 }; 156 157 158 /* 159 * Support set 160 * 161 */ 162 forceinline 163 SupportSet::SupportSet(void) {} 164 forceinline void 165 SupportSet::init(Region& r, unsigned int n) { 166 bs.init(r,n); 167 } 168 forceinline void 169 SupportSet::support(unsigned int i) { 170 bs.set(i); 171 } 172 forceinline bool 173 SupportSet::supported(unsigned int i) const { 174 return bs.get(i); 175 } 176 177 forceinline 178 SupportSet::ResultIter::ResultIter(const SupportSet& s0, const IntView& x) 179 : ViewValues<IntView>(x), s(s0), p(0) { 180 while (ViewValues<IntView>::operator ()() && s.supported(p)) { 181 ViewValues<IntView>::operator ++(); ++p; 182 } 183 } 184 forceinline void 185 SupportSet::ResultIter::operator ++(void) { 186 do { 187 ViewValues<IntView>::operator ++(); ++p; 188 } while (ViewValues<IntView>::operator ()() && s.supported(p)); 189 } 190 191 192 forceinline ModEvent 193 SupportSet::tell(Space& home, IntView& x) const { 194 switch (bs.status()) { 195 case Support::BSS_NONE: 196 return ME_INT_FAILED; 197 case Support::BSS_ALL: 198 return ME_INT_NONE; 199 case Support::BSS_SOME: 200 { 201 ResultIter i(*this,x); 202 return x.minus_v(home,i); 203 } 204 default: 205 GECODE_NEVER; 206 } 207 return ME_INT_NONE; 208 } 209 210 211 /* 212 * Base-class for support-based iterator 213 * 214 */ 215 template<class Val> 216 forceinline void 217 SupportIter<Val>::init(Region& r, 218 int a0, const IntView& x0, Val l0, Val u0) { 219 a=a0; x=x0; l=l0; u=u0; 220 s.init(r,x.size()); 221 } 222 template<class Val> 223 forceinline void 224 SupportIter<Val>::support(void) { 225 s.support(p); 226 } 227 template<class Val> 228 forceinline ModEvent 229 SupportIter<Val>::tell(Space& home) { 230 return s.tell(home,x); 231 } 232 233 234 /* 235 * Support-based iterator for positive view 236 * 237 */ 238 template<class Val> 239 forceinline bool 240 PosSupportIter<Val>::reset(Val& d) { 241 // Way too small, no value can make it big enough 242 if (d + static_cast<Val>(a)*x.max() < u) 243 return false; 244 // Restart iterator and position of values 245 i.init(x.varimp()); p = 0; 246 // Skip all ranges which are too small 247 while (d + static_cast<Val>(a)*i.max() < u) { 248 p += i.width(); ++i; 249 } 250 // There is at least one range left (check of max) 251 assert(i()); 252 // Initialize current range and adjust value 253 c = i.min(); 254 // Skip all values which are too small 255 while (d + static_cast<Val>(a)*c < u) { 256 p++; c++; 257 } 258 // Adjust to new value 259 d += static_cast<Val>(a) * c; 260 return true; 261 } 262 template<class Val> 263 forceinline bool 264 PosSupportIter<Val>::adjust(Val& d) { 265 // Current value 266 Val v = static_cast<Val>(a) * c; 267 // Subtract current value from d 268 d -= v; 269 // Move to next position (number of value) 270 p++; 271 // Still in the same range 272 if (c < i.max()) { 273 // Decrement current values 274 c += 1; v += a; 275 } else { 276 // Go to next range 277 ++i; 278 if (!i()) 279 return false; 280 c = i.min(); v = static_cast<Val>(a) * c; 281 } 282 // Is d with the current value too large? 283 if (d + v > l) 284 return false; 285 // Update d 286 d += v; 287 return true; 288 } 289 290 291 /* 292 * Support-based iterator for negative view 293 * 294 */ 295 template<class Val> 296 forceinline bool 297 NegSupportIter<Val>::reset(Val& d) { 298 // Way too small, no value can make it big enough 299 if (d + static_cast<Val>(a)*x.min() < u) 300 return false; 301 // Restart iterator and position of values 302 i.init(x.varimp()); p = x.size()-1; 303 // Skip all ranges which are too small 304 while (d + static_cast<Val>(a)*i.min() < u) { 305 p -= i.width(); ++i; 306 } 307 // There is at least one range left (check of max) 308 assert(i()); 309 // Initialize current range 310 c = i.max(); 311 // Skip all values which are too small 312 while (d + static_cast<Val>(a)*c < u) { 313 p--; c--; 314 } 315 // Adjust to new value 316 d += static_cast<Val>(a) * c; 317 return true; 318 } 319 template<class Val> 320 forceinline bool 321 NegSupportIter<Val>::adjust(Val& d) { 322 // Current value 323 Val v = static_cast<Val>(a) * c; 324 // Subtract current value from d 325 d -= v; 326 // Move to next position (number of value) 327 p--; 328 // Still in the same range 329 if (c > i.min()) { 330 // Decrement current values 331 c -= 1; v -= a; 332 } else { 333 // Go to next range 334 ++i; 335 if (!i()) 336 return false; 337 c = i.max(); v = static_cast<Val>(a) * c; 338 } 339 // Is d with the current value too large? 340 if (d + v > l) 341 return false; 342 // Update d 343 d += v; 344 return true; 345 } 346 347 348 349 /* 350 * The domain consisten equality propagator 351 * 352 */ 353 template<class Val, class View> 354 forceinline 355 DomEq<Val,View>::DomEq(Home home, 356 ViewArray<View >& x, ViewArray<View >& y, 357 Val c) 358 : Lin<Val,View,View,PC_INT_DOM>(home,x,y,c) {} 359 360 template<class Val, class View> 361 ExecStatus 362 DomEq<Val,View>::post(Home home, 363 ViewArray<View>& x, ViewArray<View>& y, 364 Val c) { 365 (void) new (home) DomEq<Val,View>(home,x,y,c); 366 return ES_OK; 367 } 368 369 template<class Val, class View> 370 forceinline 371 DomEq<Val,View>::DomEq(Space& home, DomEq<Val,View>& p) 372 : Lin<Val,View,View,PC_INT_DOM>(home,p) {} 373 374 template<class Val, class View> 375 Actor* 376 DomEq<Val,View>::copy(Space& home) { 377 return new (home) DomEq<Val,View>(home,*this); 378 } 379 380 template<class Val, class View> 381 PropCost 382 DomEq<Val,View>::cost(const Space&, const ModEventDelta& med) const { 383 if (View::me(med) != ME_INT_DOM) 384 return PropCost::linear(PropCost::LO, x.size()+y.size()); 385 else 386 return PropCost::crazy(PropCost::HI, x.size()+y.size()); 387 } 388 389 template<class Val, class View> 390 ExecStatus 391 DomEq<Val,View>::propagate(Space& home, const ModEventDelta& med) { 392 if (View::me(med) != ME_INT_DOM) { 393 ExecStatus es = prop_bnd<Val,View,View>(home,med,*this,x,y,c); 394 GECODE_ES_CHECK(es); 395 return home.ES_FIX_PARTIAL(*this,View::med(ME_INT_DOM)); 396 } 397 398 // Value of equation for partial assignment 399 Val d = -c; 400 401 int n = x.size(); 402 int m = y.size(); 403 404 Region r; 405 // Create support-base iterators 406 PosSupportIter<Val>* xp = r.alloc<PosSupportIter<Val> >(n); 407 NegSupportIter<Val>* yp = r.alloc<NegSupportIter<Val> >(m); 408 409 // Initialize views for assignments 410 { 411 Val l = 0; 412 Val u = 0; 413 for (int j=m; j--; ) { 414 yp[j].init(r,-y[j].scale(),y[j].base(),l,u); 415 l += y[j].max(); u += y[j].min(); 416 } 417 for (int i=n; i--; ) { 418 xp[i].init(r,x[i].scale(),x[i].base(),l,u); 419 l -= x[i].min(); u -= x[i].max(); 420 } 421 } 422 423 // Collect support information by iterating assignments 424 { 425 // Force reset of all iterators in first round 426 int i = 0; 427 int j = 0; 428 429 next_i: 430 // Reset all iterators for positive views and update d 431 while (i<n) { 432 if (!xp[i].reset(d)) goto prev_i; 433 i++; 434 } 435 next_j: 436 // Reset all iterators for negative views and update d 437 while (j<m) { 438 if (!yp[j].reset(d)) goto prev_j; 439 j++; 440 } 441 // Check whether current assignment is solution 442 if (d == 0) { 443 // Record support 444 for (int is=0; is<n; is++) xp[is].support(); 445 for (int js=0; js<m; js++) yp[js].support(); 446 } 447 prev_j: 448 // Try iterating to next assignment: negative views 449 while (j>0) { 450 if (yp[j-1].adjust(d)) goto next_j; 451 j--; 452 } 453 prev_i: 454 // Try iterating to next assignment: positive views 455 while (i>0) { 456 if (xp[i-1].adjust(d)) goto next_i; 457 i--; 458 } 459 } 460 461 // Tell back new variable domains 462 bool assigned = true; 463 for (int i=0; i<n; i++) { 464 GECODE_ME_CHECK(xp[i].tell(home)); 465 if (!x[i].assigned()) 466 assigned = false; 467 } 468 for (int j=0; j<m; j++) { 469 GECODE_ME_CHECK(yp[j].tell(home)); 470 if (!y[j].assigned()) 471 assigned = false; 472 } 473 if (assigned) 474 return home.ES_SUBSUMED(*this); 475 return ES_FIX; 476 } 477 478}}} 479 480// STATISTICS: int-prop