| 1 | /* $Id: CoinSearchTree.hpp 1372 2011-01-03 23:31:00Z lou $ */ |
| 2 | // Copyright (C) 2006, International Business Machines |
| 3 | // Corporation and others. All Rights Reserved. |
| 4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
| 5 | |
| 6 | #ifndef CoinSearchTree_H |
| 7 | #define CoinSearchTree_H |
| 8 | |
| 9 | #include <vector> |
| 10 | #include <algorithm> |
| 11 | #include <cmath> |
| 12 | #include <string> |
| 13 | |
| 14 | #include "CoinFinite.hpp" |
| 15 | #include "CoinHelperFunctions.hpp" |
| 16 | |
| 17 | // #define DEBUG_PRINT |
| 18 | |
| 19 | //############################################################################# |
| 20 | |
| 21 | class BitVector128 { |
| 22 | friend bool operator<(const BitVector128& b0, const BitVector128& b1); |
| 23 | private: |
| 24 | unsigned int bits_[4]; |
| 25 | public: |
| 26 | BitVector128(); |
| 27 | ~BitVector128() {} |
| 28 | void setBit(int i); |
| 29 | void clearBit(int i); |
| 30 | std::string str() const; |
| 31 | }; |
| 32 | |
| 33 | bool operator<(const BitVector128& b0, const BitVector128& b1); |
| 34 | |
| 35 | //############################################################################# |
| 36 | |
| 37 | /** A class from which the real tree nodes should be derived from. Some of the |
| 38 | data that undoubtedly exist in the real tree node is replicated here for |
| 39 | fast access. This class is used in the various comparison functions. */ |
| 40 | class CoinTreeNode { |
| 41 | protected: |
| 42 | CoinTreeNode() : |
| 43 | depth_(-1), |
| 44 | fractionality_(-1), |
| 45 | quality_(-COIN_DBL_MAX), |
| 46 | true_lower_bound_(-COIN_DBL_MAX), |
| 47 | preferred_() {} |
| 48 | CoinTreeNode(int d, |
| 49 | int f = -1, |
| 50 | double q = -COIN_DBL_MAX, |
| 51 | double tlb = -COIN_DBL_MAX, |
| 52 | BitVector128 p = BitVector128()) : |
| 53 | depth_(d), |
| 54 | fractionality_(f), |
| 55 | quality_(q), |
| 56 | true_lower_bound_(tlb), |
| 57 | preferred_(p) {} |
| 58 | CoinTreeNode(const CoinTreeNode& x) : |
| 59 | depth_(x.depth_), |
| 60 | fractionality_(x.fractionality_), |
| 61 | quality_(x.quality_), |
| 62 | true_lower_bound_(x.true_lower_bound_), |
| 63 | preferred_(x.preferred_) {} |
| 64 | CoinTreeNode& operator=(const CoinTreeNode& x) { |
| 65 | if (this != &x) { |
| 66 | depth_ = x.depth_; |
| 67 | fractionality_ = x.fractionality_; |
| 68 | quality_ = x.quality_; |
| 69 | true_lower_bound_ = x.true_lower_bound_; |
| 70 | preferred_ = x.preferred_; |
| 71 | } |
| 72 | return *this; |
| 73 | } |
| 74 | private: |
| 75 | /// The depth of the node in the tree |
| 76 | int depth_; |
| 77 | /** A measure of fractionality, e.g., the number of unsatisfied |
| 78 | integrality requirements */ |
| 79 | int fractionality_; |
| 80 | /** Some quality for the node. For normal branch-and-cut problems the LP |
| 81 | relaxation value will do just fine. It is probably an OK approximation |
| 82 | even if column generation is done. */ |
| 83 | double quality_; |
| 84 | /** A true lower bound on the node. May be -infinity. For normal |
| 85 | branch-and-cut problems the LP relaxation value is OK. It is different |
| 86 | when column generation is done. */ |
| 87 | double true_lower_bound_; |
| 88 | /** */ |
| 89 | BitVector128 preferred_; |
| 90 | public: |
| 91 | virtual ~CoinTreeNode() {} |
| 92 | |
| 93 | inline int getDepth() const { return depth_; } |
| 94 | inline int getFractionality() const { return fractionality_; } |
| 95 | inline double getQuality() const { return quality_; } |
| 96 | inline double getTrueLB() const { return true_lower_bound_; } |
| 97 | inline BitVector128 getPreferred() const { return preferred_; } |
| 98 | |
| 99 | inline void setDepth(int d) { depth_ = d; } |
| 100 | inline void setFractionality(int f) { fractionality_ = f; } |
| 101 | inline void setQuality(double q) { quality_ = q; } |
| 102 | inline void setTrueLB(double tlb) { true_lower_bound_ = tlb; } |
| 103 | inline void setPreferred(BitVector128 p) { preferred_ = p; } |
| 104 | }; |
| 105 | |
| 106 | //============================================================================== |
| 107 | |
| 108 | class CoinTreeSiblings { |
| 109 | private: |
| 110 | CoinTreeSiblings(); |
| 111 | CoinTreeSiblings& operator=(const CoinTreeSiblings&); |
| 112 | private: |
| 113 | int current_; |
| 114 | int numSiblings_; |
| 115 | CoinTreeNode** siblings_; |
| 116 | public: |
| 117 | CoinTreeSiblings(const int n, CoinTreeNode** nodes) : |
| 118 | current_(0), numSiblings_(n), siblings_(new CoinTreeNode*[n]) |
| 119 | { |
| 120 | CoinDisjointCopyN(nodes, n, siblings_); |
| 121 | } |
| 122 | CoinTreeSiblings(const CoinTreeSiblings& s) : |
| 123 | current_(s.current_), |
| 124 | numSiblings_(s.numSiblings_), |
| 125 | siblings_(new CoinTreeNode*[s.numSiblings_]) |
| 126 | { |
| 127 | CoinDisjointCopyN(s.siblings_, s.numSiblings_, siblings_); |
| 128 | } |
| 129 | ~CoinTreeSiblings() { delete[] siblings_; } |
| 130 | inline CoinTreeNode* currentNode() const { return siblings_[current_]; } |
| 131 | /** returns false if cannot be advanced */ |
| 132 | inline bool advanceNode() { return ++current_ != numSiblings_; } |
| 133 | inline int toProcess() const { return numSiblings_ - current_; } |
| 134 | inline int size() const { return numSiblings_; } |
| 135 | inline void printPref() const { |
| 136 | for (int i = 0; i < numSiblings_; ++i) { |
| 137 | std::string pref = siblings_[i]->getPreferred().str(); |
| 138 | printf("prefs of sibligs: sibling[%i]: %s\n" , i, pref.c_str()); |
| 139 | } |
| 140 | } |
| 141 | }; |
| 142 | |
| 143 | //############################################################################# |
| 144 | |
| 145 | /** Function objects to compare search tree nodes. The comparison function |
| 146 | must return true if the first argument is "better" than the second one, |
| 147 | i.e., it should be processed first. */ |
| 148 | /*@{*/ |
| 149 | /** Depth First Search. */ |
| 150 | struct CoinSearchTreeComparePreferred { |
| 151 | static inline const char* name() { return "CoinSearchTreeComparePreferred" ; } |
| 152 | inline bool operator()(const CoinTreeSiblings* x, |
| 153 | const CoinTreeSiblings* y) const { |
| 154 | const CoinTreeNode* xNode = x->currentNode(); |
| 155 | const CoinTreeNode* yNode = y->currentNode(); |
| 156 | const BitVector128 xPref = xNode->getPreferred(); |
| 157 | const BitVector128 yPref = yNode->getPreferred(); |
| 158 | bool retval = true; |
| 159 | if (xPref < yPref) { |
| 160 | retval = true; |
| 161 | } else if (yPref < xPref) { |
| 162 | retval = false; |
| 163 | } else { |
| 164 | retval = xNode->getQuality() < yNode->getQuality(); |
| 165 | } |
| 166 | #ifdef DEBUG_PRINT |
| 167 | printf("Comparing xpref (%s) and ypref (%s) : %s\n" , |
| 168 | xpref.str().c_str(), ypref.str().c_str(), retval ? "T" : "F" ); |
| 169 | #endif |
| 170 | return retval; |
| 171 | } |
| 172 | }; |
| 173 | |
| 174 | //----------------------------------------------------------------------------- |
| 175 | /** Depth First Search. */ |
| 176 | struct CoinSearchTreeCompareDepth { |
| 177 | static inline const char* name() { return "CoinSearchTreeCompareDepth" ; } |
| 178 | inline bool operator()(const CoinTreeSiblings* x, |
| 179 | const CoinTreeSiblings* y) const { |
| 180 | #if 1 |
| 181 | return x->currentNode()->getDepth() >= y->currentNode()->getDepth(); |
| 182 | #else |
| 183 | if(x->currentNode()->getDepth() > y->currentNode()->getDepth()) |
| 184 | return 1; |
| 185 | if(x->currentNode()->getDepth() == y->currentNode()->getDepth() && |
| 186 | x->currentNode()->getQuality() <= y->currentNode()->getQuality()) |
| 187 | return 1; |
| 188 | return 0; |
| 189 | #endif |
| 190 | } |
| 191 | }; |
| 192 | |
| 193 | //----------------------------------------------------------------------------- |
| 194 | /* Breadth First Search */ |
| 195 | struct CoinSearchTreeCompareBreadth { |
| 196 | static inline const char* name() { return "CoinSearchTreeCompareBreadth" ; } |
| 197 | inline bool operator()(const CoinTreeSiblings* x, |
| 198 | const CoinTreeSiblings* y) const { |
| 199 | return x->currentNode()->getDepth() < y->currentNode()->getDepth(); |
| 200 | } |
| 201 | }; |
| 202 | |
| 203 | //----------------------------------------------------------------------------- |
| 204 | /** Best first search */ |
| 205 | struct CoinSearchTreeCompareBest { |
| 206 | static inline const char* name() { return "CoinSearchTreeCompareBest" ; } |
| 207 | inline bool operator()(const CoinTreeSiblings* x, |
| 208 | const CoinTreeSiblings* y) const { |
| 209 | return x->currentNode()->getQuality() < y->currentNode()->getQuality(); |
| 210 | } |
| 211 | }; |
| 212 | |
| 213 | //############################################################################# |
| 214 | |
| 215 | class CoinSearchTreeBase |
| 216 | { |
| 217 | private: |
| 218 | CoinSearchTreeBase(const CoinSearchTreeBase&); |
| 219 | CoinSearchTreeBase& operator=(const CoinSearchTreeBase&); |
| 220 | |
| 221 | protected: |
| 222 | std::vector<CoinTreeSiblings*> candidateList_; |
| 223 | int numInserted_; |
| 224 | int size_; |
| 225 | |
| 226 | protected: |
| 227 | CoinSearchTreeBase() : candidateList_(), numInserted_(0), size_(0) {} |
| 228 | |
| 229 | virtual void realpop() = 0; |
| 230 | virtual void realpush(CoinTreeSiblings* s) = 0; |
| 231 | virtual void fixTop() = 0; |
| 232 | |
| 233 | public: |
| 234 | virtual ~CoinSearchTreeBase() {} |
| 235 | virtual const char* compName() const = 0; |
| 236 | |
| 237 | inline const std::vector<CoinTreeSiblings*>& getCandidates() const { |
| 238 | return candidateList_; |
| 239 | } |
| 240 | inline bool empty() const { return candidateList_.empty(); } |
| 241 | inline int size() const { return size_; } |
| 242 | inline int numInserted() const { return numInserted_; } |
| 243 | inline CoinTreeNode* top() const { |
| 244 | if (size_ == 0) |
| 245 | return nullptr; |
| 246 | #ifdef DEBUG_PRINT |
| 247 | char output[44]; |
| 248 | output[43] = 0; |
| 249 | candidateList_.front()->currentNode()->getPreferred().print(output); |
| 250 | printf("top's pref: %s\n" , output); |
| 251 | #endif |
| 252 | return candidateList_.front()->currentNode(); |
| 253 | } |
| 254 | /** pop will advance the \c next pointer among the siblings on the top and |
| 255 | then moves the top to its correct position. #realpop is the method |
| 256 | that actually removes the element from the heap */ |
| 257 | inline void pop() { |
| 258 | CoinTreeSiblings* s = candidateList_.front(); |
| 259 | if (!s->advanceNode()) { |
| 260 | realpop(); |
| 261 | delete s; |
| 262 | } else { |
| 263 | fixTop(); |
| 264 | } |
| 265 | --size_; |
| 266 | } |
| 267 | inline void push(int numNodes, CoinTreeNode** nodes, |
| 268 | const bool incrInserted = true) { |
| 269 | CoinTreeSiblings* s = new CoinTreeSiblings(numNodes, nodes); |
| 270 | realpush(s); |
| 271 | if (incrInserted) { |
| 272 | numInserted_ += numNodes; |
| 273 | } |
| 274 | size_ += numNodes; |
| 275 | } |
| 276 | inline void push(const CoinTreeSiblings& sib, |
| 277 | const bool incrInserted = true) { |
| 278 | CoinTreeSiblings* s = new CoinTreeSiblings(sib); |
| 279 | #ifdef DEBUG_PRINT |
| 280 | s->printPref(); |
| 281 | #endif |
| 282 | realpush(s); |
| 283 | if (incrInserted) { |
| 284 | numInserted_ += sib.toProcess(); |
| 285 | } |
| 286 | size_ += sib.size(); |
| 287 | } |
| 288 | }; |
| 289 | |
| 290 | //############################################################################# |
| 291 | |
| 292 | // #define CAN_TRUST_STL_HEAP |
| 293 | #ifdef CAN_TRUST_STL_HEAP |
| 294 | |
| 295 | template <class Comp> |
| 296 | class CoinSearchTree : public CoinSearchTreeBase |
| 297 | { |
| 298 | private: |
| 299 | Comp comp_; |
| 300 | protected: |
| 301 | virtual void realpop() { |
| 302 | candidateList_.pop_back(); |
| 303 | } |
| 304 | virtual void fixTop() { |
| 305 | CoinTreeSiblings* s = top(); |
| 306 | realpop(); |
| 307 | push(s, false); |
| 308 | } |
| 309 | virtual void realpush(CoinTreeSiblings* s) { |
| 310 | nodes_.push_back(s); |
| 311 | std::push_heap(candidateList_.begin(), candidateList_.end(), comp_); |
| 312 | } |
| 313 | public: |
| 314 | CoinSearchTree() : CoinSearchTreeBase(), comp_() {} |
| 315 | CoinSearchTree(const CoinSearchTreeBase& t) : |
| 316 | CoinSearchTreeBase(), comp_() { |
| 317 | candidateList_ = t.getCandidates(); |
| 318 | std::make_heap(candidateList_.begin(), candidateList_.end(), comp_); |
| 319 | numInserted_ = t.numInserted_; |
| 320 | size_ = t.size_; |
| 321 | } |
| 322 | ~CoinSearchTree() {} |
| 323 | const char* compName() const { return Comp::name(); } |
| 324 | }; |
| 325 | |
| 326 | #else |
| 327 | |
| 328 | template <class Comp> |
| 329 | class CoinSearchTree : public CoinSearchTreeBase |
| 330 | { |
| 331 | private: |
| 332 | Comp comp_; |
| 333 | |
| 334 | protected: |
| 335 | virtual void realpop() override { |
| 336 | candidateList_[0] = candidateList_.back(); |
| 337 | candidateList_.pop_back(); |
| 338 | fixTop(); |
| 339 | } |
| 340 | /** After changing data in the top node, fix the heap */ |
| 341 | virtual void fixTop() override { |
| 342 | const size_t size = candidateList_.size(); |
| 343 | if (size > 1) { |
| 344 | CoinTreeSiblings** candidates = &candidateList_[0]; |
| 345 | CoinTreeSiblings* s = candidates[0]; |
| 346 | --candidates; |
| 347 | size_t pos = 1; |
| 348 | size_t ch; |
| 349 | for (ch = 2; ch < size; pos = ch, ch *= 2) { |
| 350 | if (comp_(candidates[ch+1], candidates[ch])) |
| 351 | ++ch; |
| 352 | if (comp_(s, candidates[ch])) |
| 353 | break; |
| 354 | candidates[pos] = candidates[ch]; |
| 355 | } |
| 356 | if (ch == size) { |
| 357 | if (comp_(candidates[ch], s)) { |
| 358 | candidates[pos] = candidates[ch]; |
| 359 | pos = ch; |
| 360 | } |
| 361 | } |
| 362 | candidates[pos] = s; |
| 363 | } |
| 364 | } |
| 365 | virtual void realpush(CoinTreeSiblings* s) override { |
| 366 | candidateList_.push_back(s); |
| 367 | CoinTreeSiblings** candidates = &candidateList_[0]; |
| 368 | --candidates; |
| 369 | size_t pos = candidateList_.size(); |
| 370 | size_t ch; |
| 371 | for (ch = pos/2; ch != 0; pos = ch, ch /= 2) { |
| 372 | if (comp_(candidates[ch], s)) |
| 373 | break; |
| 374 | candidates[pos] = candidates[ch]; |
| 375 | } |
| 376 | candidates[pos] = s; |
| 377 | } |
| 378 | |
| 379 | public: |
| 380 | CoinSearchTree() : CoinSearchTreeBase(), comp_() {} |
| 381 | CoinSearchTree(const CoinSearchTreeBase& t) : |
| 382 | CoinSearchTreeBase(), comp_() { |
| 383 | candidateList_ = t.getCandidates(); |
| 384 | std::sort(candidateList_.begin(), candidateList_.end(), comp_); |
| 385 | numInserted_ = t.numInserted(); |
| 386 | size_ = t.size(); |
| 387 | } |
| 388 | ~CoinSearchTree() {} |
| 389 | const char* compName() const override { return Comp::name(); } |
| 390 | }; |
| 391 | |
| 392 | #endif |
| 393 | |
| 394 | //############################################################################# |
| 395 | |
| 396 | enum CoinNodeAction { |
| 397 | CoinAddNodeToCandidates, |
| 398 | CoinTestNodeForDiving, |
| 399 | CoinDiveIntoNode |
| 400 | }; |
| 401 | |
| 402 | class CoinSearchTreeManager |
| 403 | { |
| 404 | private: |
| 405 | CoinSearchTreeManager(const CoinSearchTreeManager&); |
| 406 | CoinSearchTreeManager& operator=(const CoinSearchTreeManager&); |
| 407 | private: |
| 408 | CoinSearchTreeBase* candidates_; |
| 409 | int numSolution; |
| 410 | /** Whether there is an upper bound or not. The upper bound may have come |
| 411 | as input, not necessarily from a solution */ |
| 412 | bool hasUB_; |
| 413 | |
| 414 | /** variable used to test whether we need to reevaluate search strategy */ |
| 415 | bool recentlyReevaluatedSearchStrategy_; |
| 416 | |
| 417 | public: |
| 418 | CoinSearchTreeManager() : |
| 419 | candidates_(nullptr), |
| 420 | numSolution(0), |
| 421 | recentlyReevaluatedSearchStrategy_(true) |
| 422 | {} |
| 423 | virtual ~CoinSearchTreeManager() { |
| 424 | delete candidates_; |
| 425 | } |
| 426 | |
| 427 | inline void setTree(CoinSearchTreeBase* t) { |
| 428 | delete candidates_; |
| 429 | candidates_ = t; |
| 430 | } |
| 431 | inline CoinSearchTreeBase* getTree() const { |
| 432 | return candidates_; |
| 433 | } |
| 434 | |
| 435 | inline bool empty() const { return candidates_->empty(); } |
| 436 | inline size_t size() const { return candidates_->size(); } |
| 437 | inline size_t numInserted() const { return candidates_->numInserted(); } |
| 438 | inline CoinTreeNode* top() const { return candidates_->top(); } |
| 439 | inline void pop() { candidates_->pop(); } |
| 440 | inline void push(CoinTreeNode* node, const bool incrInserted = true) { |
| 441 | candidates_->push(1, &node, incrInserted); |
| 442 | } |
| 443 | inline void push(const CoinTreeSiblings& s, const bool incrInserted=true) { |
| 444 | candidates_->push(s, incrInserted); |
| 445 | } |
| 446 | inline void push(const int n, CoinTreeNode** nodes, |
| 447 | const bool incrInserted = true) { |
| 448 | candidates_->push(n, nodes, incrInserted); |
| 449 | } |
| 450 | |
| 451 | inline CoinTreeNode* bestQualityCandidate() const { |
| 452 | return candidates_->top(); |
| 453 | } |
| 454 | inline double bestQuality() const { |
| 455 | return candidates_->top()->getQuality(); |
| 456 | } |
| 457 | void newSolution(double solValue); |
| 458 | void reevaluateSearchStrategy(); |
| 459 | }; |
| 460 | |
| 461 | //############################################################################# |
| 462 | |
| 463 | #endif |
| 464 | |