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, 2017 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 <cfloat> 35 36namespace Gecode { 37 38 /** 39 * \brief Class for CHB management 40 * 41 * The idea is taken from: Exponential Recency Weighted Average 42 * Branching Heuristic for SAT Solvers, Jia Hui Liang, Vijay Ganesh, 43 * Pascal Poupart, Krzysztof Czarnecki, AAAI 2016, pages 3434-3440. 44 * 45 */ 46 class CHB : public SharedHandle { 47 protected: 48 template<class View> 49 class Recorder; 50 /// View information 51 class Info { 52 public: 53 /// Last failure 54 unsigned long long int lf; 55 /// Q-score 56 double qs; 57 }; 58 /// Object for storing chb information 59 class GECODE_VTABLE_EXPORT Storage : public SharedHandle::Object { 60 public: 61 /// Mutex to synchronize globally shared access 62 GECODE_KERNEL_EXPORT static Support::Mutex m; 63 /// Number of chb values 64 int n; 65 /// Number of failures 66 unsigned long long int nf; 67 /// Alpha value 68 double alpha; 69 /// CHB information 70 Info* chb; 71 /// Initialize CHB info 72 template<class View> 73 Storage(Home home, ViewArray<View>& x, 74 typename BranchTraits<typename View::VarType>::Merit bm); 75 /// Delete object 76 GECODE_KERNEL_EXPORT 77 ~Storage(void); 78 /// Bump failure count and alpha 79 void bump(void); 80 /// Update chb information at position \a i 81 void update(int i, bool failed); 82 }; 83 /// Return object of correct type 84 Storage& object(void) const; 85 /// Set object to \a o 86 void object(Storage& o); 87 /// Update chb value at position \a i 88 void update(int i); 89 /// Acquire mutex 90 void acquire(void); 91 /// Release mutex 92 void release(void); 93 /// Bump failure count and alpha 94 void bump(void); 95 /// Update chb information at position \a i 96 void update(int i, bool failed); 97 public: 98 /// \name Constructors and initialization 99 //@{ 100 /** 101 * \brief Construct as not yet intialized 102 * 103 * The only member functions that can be used on a constructed but not 104 * yet initialized chb storage is init and the assignment operator. 105 * 106 */ 107 CHB(void); 108 /// Copy constructor 109 GECODE_KERNEL_EXPORT 110 CHB(const CHB& a); 111 /// Assignment operator 112 GECODE_KERNEL_EXPORT 113 CHB& operator =(const CHB& a); 114 /// Initialize for views \a x and Q-score as defined by \a bm 115 template<class View> 116 CHB(Home home, ViewArray<View>& x, 117 typename BranchTraits<typename View::VarType>::Merit bm); 118 /// Initialize for views \a x and Q-score as defined by \a bm 119 template<class View> 120 void init(Home home, ViewArray<View>& x, 121 typename BranchTraits<typename View::VarType>::Merit bm); 122 /// Default (empty) chb information 123 GECODE_KERNEL_EXPORT static const CHB def; 124 //@} 125 126 /// Destructor 127 GECODE_KERNEL_EXPORT 128 ~CHB(void); 129 130 /// \name Information access 131 //@{ 132 /// Return chb value at position \a i 133 double operator [](int i) const; 134 /// Return number of chb values 135 int size(void) const; 136 //@} 137 }; 138 139 /// Propagator for recording chb information 140 template<class View> 141 class CHB::Recorder : public NaryPropagator<View,PC_GEN_NONE> { 142 protected: 143 using NaryPropagator<View,PC_GEN_NONE>::x; 144 /// Advisor with index and change information 145 class Idx : public Advisor { 146 protected: 147 /// Index and mark information 148 int _info; 149 public: 150 /// Constructor for creation 151 Idx(Space& home, Propagator& p, Council<Idx>& c, int i); 152 /// Constructor for cloning \a a 153 Idx(Space& home, Idx& a); 154 /// Mark advisor as modified 155 void mark(void); 156 /// Mark advisor as unmodified 157 void unmark(void); 158 /// Whether advisor's view has been marked 159 bool marked(void) const; 160 /// Get index of view 161 int idx(void) const; 162 }; 163 /// Access to chb information 164 CHB chb; 165 /// The advisor council 166 Council<Idx> c; 167 /// Constructor for cloning \a p 168 Recorder(Space& home, Recorder<View>& p); 169 public: 170 /// Constructor for creation 171 Recorder(Home home, ViewArray<View>& x, CHB& chb); 172 /// Copy propagator during cloning 173 virtual Propagator* copy(Space& home); 174 /// Cost function (record so that propagator runs last) 175 virtual PropCost cost(const Space& home, const ModEventDelta& med) const; 176 /// Schedule function 177 virtual void reschedule(Space& home); 178 /// Give advice to propagator 179 virtual ExecStatus advise(Space& home, Advisor& a, const Delta& d); 180 /// Give advice to propagator when \a home has failed 181 virtual void advise(Space& home, Advisor& a); 182 /// Perform propagation 183 virtual ExecStatus propagate(Space& home, const ModEventDelta& med); 184 /// Delete propagator and return its size 185 virtual size_t dispose(Space& home); 186 /// Post chb recorder propagator 187 static ExecStatus post(Home home, ViewArray<View>& x, CHB& chb); 188 }; 189 190 /** 191 * \brief Print chb values enclosed in curly brackets 192 * \relates CHB 193 */ 194 template<class Char, class Traits> 195 std::basic_ostream<Char,Traits>& 196 operator <<(std::basic_ostream<Char,Traits>& os, 197 const CHB& a); 198 199 200 /* 201 * Advisor for chb recorder 202 * 203 */ 204 template<class View> 205 forceinline 206 CHB::Recorder<View>::Idx::Idx(Space& home, Propagator& p, 207 Council<Idx>& c, int i) 208 : Advisor(home,p,c), _info(i << 1) {} 209 template<class View> 210 forceinline 211 CHB::Recorder<View>::Idx::Idx(Space& home, Idx& a) 212 : Advisor(home,a), _info(a._info) { 213 } 214 template<class View> 215 forceinline void 216 CHB::Recorder<View>::Idx::mark(void) { 217 _info |= 1; 218 } 219 template<class View> 220 forceinline bool 221 CHB::Recorder<View>::Idx::marked(void) const { 222 return (_info & 1) != 0; 223 } 224 template<class View> 225 forceinline void 226 CHB::Recorder<View>::Idx::unmark(void) { 227 assert(marked()); 228 _info -= 1; 229 } 230 template<class View> 231 forceinline int 232 CHB::Recorder<View>::Idx::idx(void) const { 233 return _info >> 1; 234 } 235 236 237 /* 238 * Posting of chb recorder propagator 239 * 240 */ 241 template<class View> 242 forceinline 243 CHB::Recorder<View>::Recorder(Home home, ViewArray<View>& x, 244 CHB& chb0) 245 : NaryPropagator<View,PC_GEN_NONE>(home,x), chb(chb0), c(home) { 246 home.notice(*this,AP_DISPOSE); 247 for (int i=0; i<x.size(); i++) 248 if (!x[i].assigned()) 249 x[i].subscribe(home,*new (home) Idx(home,*this,c,i), true); 250 } 251 252 template<class View> 253 forceinline ExecStatus 254 CHB::Recorder<View>::post(Home home, ViewArray<View>& x, CHB& chb) { 255 (void) new (home) Recorder<View>(home,x,chb); 256 return ES_OK; 257 } 258 259 260 /* 261 * CHB value storage 262 * 263 */ 264 template<class View> 265 forceinline 266 CHB::Storage::Storage(Home home, ViewArray<View>& x, 267 typename 268 BranchTraits<typename View::VarType>::Merit bm) 269 : n(x.size()), nf(0U), alpha(Kernel::Config::chb_alpha_init), 270 chb(heap.alloc<Info>(x.size())) { 271 if (bm) { 272 for (int i=0; i<n; i++) { 273 typename View::VarType xi(x[i].varimp()); 274 chb[i].lf = 0U; 275 chb[i].qs = bm(home,xi,i); 276 } 277 } else { 278 for (int i=0; i<n; i++) { 279 chb[i].lf = 0U; 280 chb[i].qs = Kernel::Config::chb_qscore_init; 281 } 282 } 283 } 284 forceinline void 285 CHB::Storage::bump(void) { 286 nf++; 287 if (alpha > Kernel::Config::chb_alpha_limit) { 288 alpha -= Kernel::Config::chb_alpha_decrement; 289 } 290 } 291 forceinline void 292 CHB::Storage::update(int i, bool failed) { 293 if (failed) { 294 chb[i].lf = nf; 295 double reward = 1.0 / (nf - chb[i].lf + 1); 296 chb[i].qs = (1.0 - alpha) * chb[i].qs + alpha * reward; 297 } else { 298 double reward = 0.9 / (nf - chb[i].lf + 1); 299 chb[i].qs = (1.0 - alpha) * chb[i].qs + alpha * reward; 300 } 301 } 302 303 304 /* 305 * CHB 306 * 307 */ 308 309 forceinline CHB::Storage& 310 CHB::object(void) const { 311 return static_cast<CHB::Storage&>(*SharedHandle::object()); 312 } 313 314 forceinline void 315 CHB::object(CHB::Storage& o) { 316 SharedHandle::object(&o); 317 } 318 319 forceinline double 320 CHB::operator [](int i) const { 321 assert((i >= 0) && (i < object().n)); 322 return object().chb[i].qs; 323 } 324 forceinline int 325 CHB::size(void) const { 326 return object().n; 327 } 328 forceinline void 329 CHB::acquire(void) { 330 object().m.acquire(); 331 } 332 forceinline void 333 CHB::release(void) { 334 object().m.release(); 335 } 336 forceinline void 337 CHB::bump(void) { 338 object().bump(); 339 } 340 forceinline void 341 CHB::update(int i, bool failed) { 342 object().update(i,failed); 343 } 344 345 forceinline 346 CHB::CHB(void) {} 347 348 template<class View> 349 forceinline 350 CHB::CHB(Home home, ViewArray<View>& x, 351 typename BranchTraits<typename View::VarType>::Merit bm) { 352 assert(!*this); 353 object(*new Storage(home,x,bm)); 354 (void) Recorder<View>::post(home,x,*this); 355 } 356 template<class View> 357 forceinline void 358 CHB::init(Home home, ViewArray<View>& x, 359 typename BranchTraits<typename View::VarType>::Merit bm) { 360 assert(!*this); 361 object(*new Storage(home,x,bm)); 362 (void) Recorder<View>::post(home,x,*this); 363 } 364 365 template<class Char, class Traits> 366 std::basic_ostream<Char,Traits>& 367 operator <<(std::basic_ostream<Char,Traits>& os, 368 const CHB& chb) { 369 std::basic_ostringstream<Char,Traits> s; 370 s.copyfmt(os); s.width(0); 371 s << '{'; 372 if (chb.size() > 0) { 373 s << chb[0]; 374 for (int i=1; i<chb.size(); i++) 375 s << ", " << chb[i]; 376 } 377 s << '}'; 378 return os << s.str(); 379 } 380 381 382 /* 383 * Propagation for chb recorder 384 * 385 */ 386 template<class View> 387 forceinline 388 CHB::Recorder<View>::Recorder(Space& home, Recorder<View>& p) 389 : NaryPropagator<View,PC_GEN_NONE>(home,p), chb(p.chb) { 390 c.update(home, p.c); 391 } 392 393 template<class View> 394 Propagator* 395 CHB::Recorder<View>::copy(Space& home) { 396 return new (home) Recorder<View>(home, *this); 397 } 398 399 template<class View> 400 inline size_t 401 CHB::Recorder<View>::dispose(Space& home) { 402 // Delete access to chb information 403 home.ignore(*this,AP_DISPOSE); 404 chb.~CHB(); 405 // Cancel remaining advisors 406 for (Advisors<Idx> as(c); as(); ++as) 407 x[as.advisor().idx()].cancel(home,as.advisor(),true); 408 c.dispose(home); 409 (void) NaryPropagator<View,PC_GEN_NONE>::dispose(home); 410 return sizeof(*this); 411 } 412 413 template<class View> 414 PropCost 415 CHB::Recorder<View>::cost(const Space&, const ModEventDelta&) const { 416 return PropCost::record(); 417 } 418 419 template<class View> 420 void 421 CHB::Recorder<View>::reschedule(Space& home) { 422 View::schedule(home,*this,ME_GEN_ASSIGNED); 423 } 424 425 template<class View> 426 ExecStatus 427 CHB::Recorder<View>::advise(Space&, Advisor& a, const Delta&) { 428 static_cast<Idx&>(a).mark(); 429 return ES_NOFIX; 430 } 431 432 template<class View> 433 void 434 CHB::Recorder<View>::advise(Space&, Advisor& a) { 435 static_cast<Idx&>(a).mark(); 436 } 437 438 template<class View> 439 ExecStatus 440 CHB::Recorder<View>::propagate(Space& home, const ModEventDelta&) { 441 // Lock chb information 442 chb.acquire(); 443 if (home.failed()) { 444 chb.bump(); 445 for (Advisors<Idx> as(c); as(); ++as) { 446 int i = as.advisor().idx(); 447 if (as.advisor().marked()) { 448 as.advisor().unmark(); 449 chb.update(i,true); 450 if (x[i].assigned()) 451 as.advisor().dispose(home,c); 452 } 453 } 454 } else { 455 for (Advisors<Idx> as(c); as(); ++as) { 456 int i = as.advisor().idx(); 457 if (as.advisor().marked()) { 458 as.advisor().unmark(); 459 chb.update(i,false); 460 if (x[i].assigned()) 461 as.advisor().dispose(home,c); 462 } 463 } 464 } 465 chb.release(); 466 return c.empty() ? home.ES_SUBSUMED(*this) : ES_FIX; 467 } 468 469 470} 471 472// STATISTICS: kernel-branch