// Remove the top node from the heap void CbcTree::pop() { # if CBC_DEBUG_HEAP > 2 CbcNode *node = nodes_.front() ; CbcNodeInfo *info = node->nodeInfo() ; assert(info) ; std::cout << " HEAP: Popping node " << node->nodeNumber() << "(" << std::hex << node << std::dec << ") obj " << node->objectiveValue() << ", ref " << info->decrement(0) << ", todo " << info->numberBranchesLeft() << ", refd by " << info->numberPointingToThis() << "." << std::endl ; # endif # if CBC_DEBUG_HEAP > 0 validateHeap() ; # endif nodes_.front()->setOnTree(false); std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); # if CBC_DEBUG_HEAP > 0 validateHeap() ; # endif }
// Start dive void CbcCompareDefault::startDive(CbcModel * model) { // Get best - using ? criterion double saveWeight = weight_; weight_ = 0.5 * saveWeight_; //0.0; // Switch off to get best startNodeNumber_ = -1; afterNodeNumber_ = -1; CbcNode * best = model->tree()->bestAlternate(); startNodeNumber_ = best->nodeNumber(); // send signal to setComparison setupForDiving_ = true ; /* TODO (review when fixing cleanDive and setComparison) Both afterNodeNumber_ and weight_ must not change after setComparison is invoked, as that will change the behaviour of test(). I replaced the overload on afterNodeNumber_ (magic number -2) with a boolean. Weight_ is more problematic. Either it's correct before calling setComparison, or it needs to be cut from the tie-breaking part of test() during a dive, or there needs to be a new attribute to save and restore it around the dive. Otherwise heap checks fail in debug builds with Visual Studio. Given that weight_ was restored immediately after the call to setComparison, there should be no change in behaviour in terms of calls to test(). -- lh, 100921 -- */ afterNodeNumber_ = model->tree()->maximumNodeNumber(); weight_ = saveWeight ; // redo tree model->tree()->setComparison(*this); setupForDiving_ = false ; }
// Gets best node and takes off heap CbcNode * CbcTreeArray::bestNode(double cutoff) { CbcNode * best = NULL; // See if we want last node or best on heap if (lastNode_) { #ifdef CBCTREE_PRINT printf("Best lastNode_ %x (%x at depth %d) - nodeNumber %d obj %g\n", lastNode_, lastNode_->nodeInfo(), lastNode_->depth(), lastNode_->nodeNumber(), lastNode_->objectiveValue()); #endif assert (lastNode_->onTree()); int nodeNumber = lastNode_->nodeNumber(); bool useLastNode = false; if (nodeNumber + 1 == maximumNodeNumber_) { // diving - look further CbcCompareDefault * compareDefault = dynamic_cast<CbcCompareDefault *> (comparison_.test_); assert (compareDefault); double bestPossible = compareDefault->getBestPossible(); double cutoff = compareDefault->getCutoff(); double objValue = lastNode_->objectiveValue(); if (cutoff < 1.0e20) { if (objValue - bestPossible < 0.999*(cutoff - bestPossible)) useLastNode = true; } else { useLastNode = true; } } if (useLastNode) { lastNode_->setOnTree(false); best = lastNode_; lastNode_ = NULL; assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo()); if (best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo()) assert (best->nodeInfo()->numberBranchesLeft()); if (best->objectiveValue() >= cutoff) { // double check in case node can change its mind! best->checkIsCutoff(cutoff); } lastNodePopped_ = best; return best; } else { // put on tree nodes_.push_back(lastNode_); lastNode_->setNodeNumber(maximumNodeNumber_); maximumNodeNumber_++; lastNode_ = NULL; std::push_heap(nodes_.begin(), nodes_.end(), comparison_); } } while (!best && nodes_.size()) { best = nodes_.front(); if (best) assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo()); if (best && best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo()) assert (best->nodeInfo()->numberBranchesLeft()); if (best && best->objectiveValue() >= cutoff) { // double check in case node can change its mind! best->checkIsCutoff(cutoff); } if (!best || best->objectiveValue() >= cutoff) { // let code get rid of it assert (best); } } lastNodePopped_ = best; #ifdef CBCTREE_PRINT if (best) printf("Heap returning node %x (%x at depth %d) - nodeNumber %d - obj %g\n", best, best->nodeInfo(), best->depth(), best->nodeNumber(), best->objectiveValue()); else printf("Heap returning Null\n"); #endif if (best) { // take off std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); } #ifdef DEBUG_CBC_HEAP if (best) { int n = nodes_.size(); bool good = true; for (int i = 0; i < n; i++) { // temp assert (nodes_[i]); if (!comparison_.compareNodes(nodes_[i], best)) { good = false; CbcNode * x = nodes_[i]; printf("i=%d x is better nun %d depth %d obj %g, best nun %d depth %d obj %g\n", i, x->numberUnsatisfied(), x->depth(), x->objectiveValue(), best->numberUnsatisfied(), best->depth(), best->objectiveValue()); } } if (!good) { // compare best to all int i; for (i = 0; i < n; i++) { CbcNode * x = nodes_[i]; printf("i=%d x is nun %d depth %d obj %g", i, x->numberUnsatisfied(), x->depth(), x->objectiveValue()); if (!comparison_.compareNodes(x, best)) { printf(" - best is worse!\n"); } else { printf("\n"); } } // Now compare amongst rest for (i = 0; i < n; i++) { CbcNode * x = nodes_[i]; printf("For i=%d ", i); for (int j = i + 1; j < n; j++) { CbcNode * y = nodes_[j]; if (!comparison_.compareNodes(x, y)) { printf(" b %d", j); } else { printf(" w %d", j); } } printf("\n"); } assert(good); } } #endif if (best) best->setOnTree(false); return best; }
/* Return the best node from the heap. Note that best is offered a chance (checkIsCutoff) to reevaluate itself and make arbitrary changes. A caller should be prepared to check that the returned node is acceptable. There's quite a bit of suspect code here, much of it disabled in some way. The net effect at present is to return the top node on the heap after offering the node an opportunity to reevaluate itself. Documentation for checkIsCutoff() puts no restrictions on allowable changes. -- lh, 100921 -- */ CbcNode * CbcTree::bestNode(double cutoff) { # if CBC_DEBUG_HEAP > 0 validateHeap() ; # endif /* This code is problematic. As of 100921, there's really no loop. If front() == null, an assert will trigger. checkIsCutoff seems to be work in progress; comments assert that it can make pretty much arbitrary changes to best. If best can change its objective, there's a good possibility the heap is invalid. */ CbcNode * best = NULL; while (!best && nodes_.size()) { best = nodes_.front(); if (best) assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo()); if (best && best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo()) assert (best->nodeInfo()->numberBranchesLeft()); if (best && best->objectiveValue() >= cutoff) { // double check in case node can change its mind! best->checkIsCutoff(cutoff); } if (!best || best->objectiveValue() >= cutoff) { #ifdef JJF_ZERO // take off std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); delete best; best = NULL; #else // let code get rid of it assert (best); #endif } } /* See if the comparison object wants us to do a full scan with the alternative criteria. The net effect is to confirm best by the alternative criteria, or identify a competitor and erase it. This code is problematic. Nulling an arbitrary node will in general break the heap property. Disabled some time ago, as noted in several places. */ if (false && best && comparison_.test_->fullScan()) { CbcNode * saveBest = best; size_t n = nodes_.size(); size_t iBest = -1; for (size_t i = 0; i < n; i++) { // temp assert (nodes_[i]); assert (nodes_[i]->nodeInfo()); if (nodes_[i] && nodes_[i]->objectiveValue() != COIN_DBL_MAX && nodes_[i]->nodeInfo()) assert (nodes_[i]->nodeInfo()->numberBranchesLeft()); if (nodes_[i] && nodes_[i]->objectiveValue() < cutoff && comparison_.alternateTest(best, nodes_[i])) { best = nodes_[i]; iBest = i; } } if (best == saveBest) { // can pop // take off std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); } else { // make impossible nodes_[iBest] = NULL; } } else if (best) { # if CBC_DEBUG_HEAP > 2 CbcNode *node = nodes_.front() ; CbcNodeInfo *info = node->nodeInfo() ; assert(info) ; std::cout << " bestNode: Popping node " << node->nodeNumber() << "(" << std::hex << node << std::dec << ") obj " << node->objectiveValue() << ", ref " << info->decrement(0) << ", todo " << info->numberBranchesLeft() << ", refd by " << info->numberPointingToThis() << "." << std::endl ; # endif // take off std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); } #if CBC_DEBUG_HEAP > 0 validateHeap() ; #endif if (best) best->setOnTree(false); return best; }