double CbcBranchToFixLots::infeasibility(const OsiBranchingInformation * /*info*/, int &preferredWay) const { preferredWay = -1; CbcNode * node = model_->currentNode(); int depth; if (node) depth = CoinMax(node->depth(), 0); else return 0.0; if (depth_ < 0) { return 0.0; } else if (depth_ > 0) { if ((depth % depth_) != 0) return 0.0; } if (djTolerance_ != -1.234567) { if (!shallWe()) return 0.0; else return 1.0e20; } else { // See if 3 in same row and sum <FIX_IF_LESS? int numberRows = matrixByRow_.getNumRows(); const double * solution = model_->testSolution(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); double bestSum = 1.0; int nBest = -1; OsiSolverInterface * solver = model_->solver(); for (int i = 0; i < numberRows; i++) { int numberUnsatisfied = 0; double sum = 0.0; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (solver->isInteger(iColumn)) { double solValue = solution[iColumn]; if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) { numberUnsatisfied++; sum += solValue; } } } if (numberUnsatisfied >= 3 && sum < FIX_IF_LESS) { // possible if (numberUnsatisfied > nBest || (numberUnsatisfied == nBest && sum < bestSum)) { nBest = numberUnsatisfied; bestSum = sum; } } } if (nBest > 0) return 1.0e20; else return 0.0; } }
void CbcTreeArray::cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective) { int j; int nNodes = size(); int lastNode = nNodes + 1; CbcNode ** nodeArray = new CbcNode * [lastNode]; int * depth = new int [lastNode]; int k = 0; int kDelete = lastNode; bestPossibleObjective = 1.0e100 ; /* Destructively scan the heap. Nodes to be retained go into the front of nodeArray, nodes to be deleted into the back. Store the depth in a correlated array for nodes to be deleted. */ for (j = 0; j < nNodes; j++) { CbcNode * node = nodes_.front(); nodes_.front()->setOnTree(false); std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); double value = node ? node->objectiveValue() : COIN_DBL_MAX; if (node && value >= cutoff) { // double check in case node can change its mind! value = node->checkIsCutoff(cutoff); } if (value >= cutoff || !node->active()) { if (node) { nodeArray[--kDelete] = node; depth[kDelete] = node->depth(); } } else { bestPossibleObjective = CoinMin(bestPossibleObjective, value); nodeArray[k++] = node; } } if (lastNode_) { double value = lastNode_->objectiveValue(); bestPossibleObjective = CoinMin(bestPossibleObjective, value); if (value >= cutoff || !lastNode_->active()) { nodeArray[--kDelete] = lastNode_; depth[kDelete] = lastNode_->depth(); lastNode_ = NULL; } } CbcCompareDefault * compareDefault = dynamic_cast<CbcCompareDefault *> (comparison_.test_); assert (compareDefault); compareDefault->setBestPossible(bestPossibleObjective); compareDefault->setCutoff(cutoff); /* Rebuild the heap using the retained nodes. */ for (j = 0; j < k; j++) { CbcNode * node = nodeArray[j]; node->setOnTree(true); nodes_.push_back(node); std::push_heap(nodes_.begin(), nodes_.end(), comparison_); } /* Sort the list of nodes to be deleted, nondecreasing. */ CoinSort_2(depth + kDelete, depth + lastNode, nodeArray + kDelete); /* Work back from deepest to shallowest. In spite of the name, addCuts1 is just a preparatory step. When it returns, the following will be true: * all cuts are removed from the solver's copy of the constraint system; * lastws will be a basis appropriate for the specified node; * variable bounds will be adjusted to be appropriate for the specified node; * addedCuts_ (returned via addedCuts()) will contain a list of cuts that should be added to the constraint system at this node (but they have not actually been added). Then we scan the cut list for the node. Decrement the reference count for the cut, and if it's gone to 0, really delete it. I don't yet see why the checks for status != basic and addedCuts_[i] != 0 are necessary. When reconstructing a node, these checks are used to skip over loose cuts, excluding them from the reconstituted basis. But here we're just interested in correcting the reference count. Tight/loose should make no difference. Arguably a separate routine should be used in place of addCuts1. It's doing more work than needed, modifying the model to match a subproblem at a node that will be discarded. Then again, we seem to need the basis. */ for (j = lastNode - 1; j >= kDelete; j--) { CbcNode * node = nodeArray[j]; CoinWarmStartBasis *lastws = model->getEmptyBasis() ; model->addCuts1(node, lastws); // Decrement cut counts assert (node); //assert (node->nodeInfo()); int numberLeft = (node->nodeInfo()) ? node->nodeInfo()->numberBranchesLeft() : 0; int i; for (i = 0; i < model->currentNumberCuts(); i++) { // take off node CoinWarmStartBasis::Status status = lastws->getArtifStatus(i + model->numberRowsAtContinuous()); if (status != CoinWarmStartBasis::basic && model->addedCuts()[i]) { if (!model->addedCuts()[i]->decrement(numberLeft)) delete model->addedCuts()[i]; } } // node should not have anything pointing to it if (node->nodeInfo()) node->nodeInfo()->throwAway(); delete node ; delete lastws ; } delete [] nodeArray; delete [] depth; }
// 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; }
void CbcTree::validateHeap () { if (comparison_.test_ == 0) { std::cout << " Invalid heap (no predicate)!" << std::endl ; return ; } std::vector<CbcNode *>::const_iterator curNode,lastNode ; curNode = nodes_.begin() ; lastNode = nodes_.end() ; int curNdx = 0 ; int parNdx = 0 ; if (curNode == lastNode) return ; if (*curNode == 0) { std::cout << " Invalid heap[" << curNdx << "] (null entry)!" << std::endl ; } std::vector<CbcNode *>::const_iterator parent ; std::vector<CbcNode*>::const_iterator &child = curNode ; for (parent = curNode ; ++curNode != lastNode ; ++parent, ++parNdx) { curNdx++ ; if (*parent == 0) { std::cout << " Invalid heap[" << parNdx << "] (parent null entry)!" << std::endl ; curNode++ ; curNdx++ ; continue ; } if (*curNode == 0) { std::cout << " Invalid heap[" << curNdx << "] (left child null entry)!" << std::endl ; } else { if (!check_pred(*comparison_.test_,*parent,*child)) { std::cout << " Invalid heap (left child better)!" << std::endl ; CbcNode *node = *parent ; std::cout << " Parent [" << parNdx << "] (" << std::hex << node << std::dec << ") unsat " << node->numberUnsatisfied() << ", depth " << node->depth() << ", obj " << node->objectiveValue() << "." << std::endl ; node = *child ; std::cout << " Child [" << curNdx << "] (" << std::hex << node << std::dec << ") unsat " << node->numberUnsatisfied() << ", depth " << node->depth() << ", obj " << node->objectiveValue() << "." << std::endl ; } } curNode++ ; curNdx++ ; if (curNode == lastNode) break ; if (*curNode == 0) { std::cout << " Invalid heap[" << curNdx << "] (right child null entry)!" << std::endl ; } else { if (!check_pred(*comparison_.test_,*parent,*child)) { std::cout << " Invalid heap (right child better)!" << std::endl ; CbcNode *node = *parent ; std::cout << " Parent [" << parNdx << "] (" << std::hex << node << std::dec << ") unsat " << node->numberUnsatisfied() << ", depth " << node->depth() << ", obj " << node->objectiveValue() << "." << std::endl ; node = *child ; std::cout << " Child [" << curNdx << "] (" << std::hex << node << std::dec << ") unsat " << node->numberUnsatisfied() << ", depth " << node->depth() << ", obj " << node->objectiveValue() << "." << std::endl ; } } } return ; }
// Gets best node and takes off heap CbcNode * CbcTree::bestNode(double cutoff) { 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 } } // switched off for now if (best && comparison_.test_->fullScan() && false) { CbcNode * saveBest = best; int n = nodes_.size(); int iBest = -1; for (int 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) { // take off #ifdef JJF_ZERO std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); #else realpop(); #endif } #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; }