/** returns a weighted sum of the node's lower bound and estimate value */ static SCIP_Real getNodeselScore( SCIP_NODE* node, /**< branching node */ SCIP_Real estimweight /**< weight of estimate in score */ ) { return (1.0-estimweight) * SCIPnodeGetLowerbound(node) + estimweight * SCIPnodeGetEstimate(node); }
/** node comparison method of node selector */ static SCIP_DECL_NODESELCOMP(nodeselCompBfs) { /*lint --e{715}*/ SCIP_Real lowerbound1; SCIP_Real lowerbound2; assert(nodesel != NULL); assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0); assert(scip != NULL); lowerbound1 = SCIPnodeGetLowerbound(node1); lowerbound2 = SCIPnodeGetLowerbound(node2); if( SCIPisLT(scip, lowerbound1, lowerbound2) ) return -1; else if( SCIPisGT(scip, lowerbound1, lowerbound2) ) return +1; else { SCIP_Real estimate1; SCIP_Real estimate2; estimate1 = SCIPnodeGetEstimate(node1); estimate2 = SCIPnodeGetEstimate(node2); if( (SCIPisInfinity(scip, estimate1) && SCIPisInfinity(scip, estimate2)) || (SCIPisInfinity(scip, -estimate1) && SCIPisInfinity(scip, -estimate2)) || SCIPisEQ(scip, estimate1, estimate2) ) { SCIP_NODETYPE nodetype1; SCIP_NODETYPE nodetype2; nodetype1 = SCIPnodeGetType(node1); nodetype2 = SCIPnodeGetType(node2); if( nodetype1 == SCIP_NODETYPE_CHILD && nodetype2 != SCIP_NODETYPE_CHILD ) return -1; else if( nodetype1 != SCIP_NODETYPE_CHILD && nodetype2 == SCIP_NODETYPE_CHILD ) return +1; else if( nodetype1 == SCIP_NODETYPE_SIBLING && nodetype2 != SCIP_NODETYPE_SIBLING ) return -1; else if( nodetype1 != SCIP_NODETYPE_SIBLING && nodetype2 == SCIP_NODETYPE_SIBLING ) return +1; else { int depth1; int depth2; depth1 = SCIPnodeGetDepth(node1); depth2 = SCIPnodeGetDepth(node2); if( depth1 < depth2 ) return -1; else if( depth1 > depth2 ) return +1; else return 0; } } if( SCIPisLT(scip, estimate1, estimate2) ) return -1; assert(SCIPisGT(scip, estimate1, estimate2)); return +1; } }
/** node selection method of node selector */ static SCIP_DECL_NODESELSELECT(nodeselSelectHybridestim) { /*lint --e{715}*/ SCIP_NODESELDATA* nodeseldata; int minplungedepth; int maxplungedepth; int plungedepth; int bestnodefreq; SCIP_Real maxplungequot; assert(nodesel != NULL); assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0); assert(scip != NULL); assert(selnode != NULL); *selnode = NULL; /* get node selector user data */ nodeseldata = SCIPnodeselGetData(nodesel); assert(nodeseldata != NULL); /* calculate minimal and maximal plunging depth */ minplungedepth = nodeseldata->minplungedepth; maxplungedepth = nodeseldata->maxplungedepth; maxplungequot = nodeseldata->maxplungequot; if( minplungedepth == -1 ) { minplungedepth = SCIPgetMaxDepth(scip)/10; if( SCIPgetNStrongbranchLPIterations(scip) > 2*SCIPgetNNodeLPIterations(scip) ) minplungedepth += 10; if( maxplungedepth >= 0 ) minplungedepth = MIN(minplungedepth, maxplungedepth); } if( maxplungedepth == -1 ) maxplungedepth = SCIPgetMaxDepth(scip)/2; maxplungedepth = MAX(maxplungedepth, minplungedepth); bestnodefreq = (nodeseldata->bestnodefreq == 0 ? INT_MAX : nodeseldata->bestnodefreq); /* check, if we exceeded the maximal plunging depth */ plungedepth = SCIPgetPlungeDepth(scip); if( plungedepth > maxplungedepth ) { /* we don't want to plunge again: select best node from the tree */ SCIPdebugMessage("plungedepth: [%d,%d], cur: %d -> abort plunging\n", minplungedepth, maxplungedepth, plungedepth); if( SCIPgetNNodes(scip) % bestnodefreq == 0 ) *selnode = SCIPgetBestboundNode(scip); else *selnode = SCIPgetBestNode(scip); SCIPdebugMessage(" -> best node : lower=%g\n", *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip)); } else { SCIP_NODE* node; SCIP_Real lowerbound; SCIP_Real cutoffbound; SCIP_Real maxbound; /* get global lower and cutoff bound */ lowerbound = SCIPgetLowerbound(scip); cutoffbound = SCIPgetCutoffbound(scip); /* if we didn't find a solution yet, the cutoff bound is usually very bad: * use only 20% of the gap as cutoff bound */ if( SCIPgetNSolsFound(scip) == 0 ) cutoffbound = lowerbound + 0.2 * (cutoffbound - lowerbound); /* check, if plunging is forced at the current depth */ if( plungedepth < minplungedepth ) maxbound = SCIPinfinity(scip); else { /* calculate maximal plunging bound */ maxbound = lowerbound + maxplungequot * (cutoffbound - lowerbound); } SCIPdebugMessage("plungedepth: [%d,%d], cur: %d, bounds: [%g,%g], maxbound: %g\n", minplungedepth, maxplungedepth, plungedepth, lowerbound, cutoffbound, maxbound); /* we want to plunge again: prefer children over siblings, and siblings over leaves, * but only select a child or sibling, if its estimate is small enough; * prefer using nodes with higher node selection priority assigned by the branching rule */ node = SCIPgetPrioChild(scip); if( node != NULL && SCIPnodeGetEstimate(node) < maxbound ) { *selnode = node; SCIPdebugMessage(" -> selected prio child: estimate=%g\n", SCIPnodeGetEstimate(*selnode)); } else { node = SCIPgetBestChild(scip); if( node != NULL && SCIPnodeGetEstimate(node) < maxbound ) { *selnode = node; SCIPdebugMessage(" -> selected best child: estimate=%g\n", SCIPnodeGetEstimate(*selnode)); } else { node = SCIPgetPrioSibling(scip); if( node != NULL && SCIPnodeGetEstimate(node) < maxbound ) { *selnode = node; SCIPdebugMessage(" -> selected prio sibling: estimate=%g\n", SCIPnodeGetEstimate(*selnode)); } else { node = SCIPgetBestSibling(scip); if( node != NULL && SCIPnodeGetEstimate(node) < maxbound ) { *selnode = node; SCIPdebugMessage(" -> selected best sibling: estimate=%g\n", SCIPnodeGetEstimate(*selnode)); } else { if( SCIPgetNNodes(scip) % bestnodefreq == 0 ) *selnode = SCIPgetBestboundNode(scip); else *selnode = SCIPgetBestNode(scip); SCIPdebugMessage(" -> selected best leaf: estimate=%g\n", *selnode != NULL ? SCIPnodeGetEstimate(*selnode) : SCIPinfinity(scip)); } } } } } return SCIP_OKAY; }
/** Execute the branching of nodes with additional constraints. */ static SCIP_RETCODE Exec( SCIP* scip, /**< SCIP data structure */ SCIP_RESULT* result /**< pointer to store the result */ ) { SCIP_REOPTNODE* reoptnode; SCIP_NODE* curnode; SCIP_REOPTTYPE reopttype; SCIP_Bool localrestart; unsigned int* childids; unsigned int curid; int naddedconss; int nchilds; int childnodessize; int ncreatednodes; int c; assert(scip != NULL ); assert(SCIPisReoptEnabled(scip)); curnode = SCIPgetCurrentNode(scip); assert(curnode != NULL); curid = SCIPnodeGetReoptID(curnode); assert(curid >= 1 || SCIPgetRootNode(scip) == curnode); /* calculate local similarity and delete the induced subtree if the similarity is to low */ localrestart = FALSE; SCIP_CALL( SCIPcheckReoptRestart(scip, curnode, &localrestart) ); ncreatednodes = 0; if( localrestart ) { *result = SCIP_DIDNOTRUN; goto TERMINATE; } SCIPdebugMessage("current node is %lld, ID %u:\n", SCIPnodeGetNumber(curnode), curid); /* get the corresponding node of the reoptimization tree */ reoptnode = SCIPgetReoptnode(scip, curid); assert(reoptnode != NULL); reopttype = (SCIP_REOPTTYPE)SCIPreoptnodeGetType(reoptnode); /* The current node is equal to the root and dual reductions were performed. Since the root has a special role * within the reoptimiziation we have to split the root node into several nodes and move all stored child nodes to * the one representing the root node including all dual reductions as before. * * @note If the type is infsubtree, there cannot exist a child node and the method SCIPapplyReopt adds a global valid * constraint only. */ if( curid == 0 ) { if( reopttype == SCIP_REOPTTYPE_STRBRANCHED || reopttype == SCIP_REOPTTYPE_INFSUBTREE ) { int ncreatedchilds; /* apply the reoptimization at the root node */ SCIP_CALL( SCIPsplitReoptRoot(scip, &ncreatedchilds, &naddedconss) ); if( reopttype == SCIP_REOPTTYPE_INFSUBTREE ) { assert(ncreatedchilds == 0); assert(naddedconss == 1); /* there is nothing to do */ *result = SCIP_DIDNOTRUN; goto TERMINATE; } assert(reopttype == SCIP_REOPTTYPE_STRBRANCHED); assert(ncreatedchilds >= 2); ncreatednodes += ncreatedchilds; /* We decrease the counter by one because after splitting the root node and moving all children to the node * representing the original root with all fixings (caused by dual reductions), we continue reactivating the * original children nodes of the root. Thus, the node containing all the fixings can be replaced by the children * nodes */ --ncreatednodes; } goto REVIVE; } /* if we reach this part of the code the current has to be different to the root node */ assert(curid >= 1); REVIVE: /* get the IDs of all child nodes */ childnodessize = SCIPreoptnodeGetNChildren(reoptnode); SCIP_CALL( SCIPallocBufferArray(scip, &childids, childnodessize) ); SCIP_CALL( SCIPgetReoptChildIDs(scip, curnode, childids, childnodessize, &nchilds) ); if( childnodessize < nchilds ) { childnodessize = SCIPreoptnodeGetNChildren(reoptnode); SCIP_CALL( SCIPreallocBufferArray(scip, &childids, childnodessize) ); SCIP_CALL( SCIPgetReoptChildIDs(scip, curnode, childids, childnodessize, &nchilds) ); } assert(nchilds <= childnodessize); naddedconss = 0; for(c = 0; c < nchilds; c++) { SCIP_NODE** childnodes; SCIP_Bool success; unsigned int childid; int ncreatedchilds; childid = childids[c]; assert(childid >= 1); SCIPdebugMessage("process child at ID %u\n", childid); reoptnode = SCIPgetReoptnode(scip, childid); assert(reoptnode != NULL); reopttype = (SCIP_REOPTTYPE)SCIPreoptnodeGetType(reoptnode); ncreatedchilds = 0; /* check whether node need to be split */ if( reopttype == SCIP_REOPTTYPE_STRBRANCHED || reopttype == SCIP_REOPTTYPE_INFSUBTREE ) { /* by default we assume the node get split into two node (because using a constraint to split the node is * the default case */ childnodessize = 2; } else { /* we only need to reconstruct the node */ childnodessize = 1; } /* allocate buffer */ SCIP_CALL( SCIPallocBufferArray(scip, &childnodes, childnodessize) ); /* apply the reoptimization */ SCIP_CALL( SCIPapplyReopt(scip, reoptnode, childid, SCIPnodeGetEstimate(curnode), childnodes, &ncreatedchilds, &naddedconss, childnodessize, &success) ); if( !success ) { assert(ncreatedchilds > childnodessize); /* reallocate buffer memory */ childnodessize = ncreatedchilds+1; SCIP_CALL( SCIPreallocBufferArray(scip, &childnodes, childnodessize) ); /* apply the reoptimization */ SCIP_CALL( SCIPapplyReopt(scip, reoptnode, childid, SCIPnodeGetEstimate(curnode), childnodes, &ncreatedchilds, &naddedconss, childnodessize, &success) ); } assert(success); /* free buffer memory */ SCIPfreeBufferArray(scip, &childnodes); ncreatednodes += ncreatedchilds; } if( ncreatednodes == 0 ) *result = SCIP_DIDNOTRUN; else *result = SCIP_BRANCHED; /* free the buffer memory */ SCIPfreeBufferArray(scip, &childids); TERMINATE: SCIPdebugMessage("**** finish reoptimizing %d child nodes of node %lld ****\n", ncreatednodes, SCIPnodeGetNumber(curnode)); return SCIP_OKAY; }