/** try given solution */ static SCIP_RETCODE trySolCandidate( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand, /**< values for indicator variables in partial solution */ int* nfoundsols /**< number of solutions found */ ) { SCIP_Bool cutoff; SCIP_Bool lperror; SCIP_Bool stored; SCIP_SOL* sol; int c; assert( scip != NULL ); assert( heur != NULL ); assert( heurdata != NULL ); assert( nindconss == 0 || indconss != NULL ); assert( solcand != NULL ); assert( nfoundsols != NULL ); SCIPdebugMessage("Trying to generate feasible solution with indicators from solution candidate ...\n"); *nfoundsols = 0; SCIP_CALL( SCIPstartProbing(scip) ); /* we can stop here if we have already reached the maximal depth */ if( SCIPgetDepthLimit(scip) <= SCIPgetDepth(scip) ) { SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } SCIP_CALL( SCIPnewProbingNode(scip) ); /* fix variables */ for (c = 0; c < nindconss; ++c) { SCIP_VAR* binvar; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[c]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[c]); assert( binvar != NULL ); /* Fix binary variables not in cover to 1 and corresponding slack variables to 0. The other binary variables are fixed to 0. */ if ( ! solcand[c] ) { /* to be sure, check for non-fixed variables */ if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 ) { SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) ); } } else { if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 ) { SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) ); } } } /* propagate variables */ SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, NULL) ); if ( cutoff ) { SCIPdebugMessage("Solution candidate reaches cutoff (in propagation).\n"); SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } /* solve LP to move continuous variables */ SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) ); /* the LP often reaches the objective limit - we currently do not use such solutions */ if ( lperror || cutoff || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { #ifdef SCIP_DEBUG if ( lperror ) SCIPdebugMessage("An LP error occured.\n"); else SCIPdebugMessage("Solution candidate reaches cutoff (in LP solving).\n"); #endif SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } /* create solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, heur) ); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* check solution for feasibility */ #ifdef SCIP_DEBUG SCIPdebugMessage("Found solution candidate with value %g.\n", SCIPgetSolTransObj(scip, sol)); #ifdef SCIP_MORE_DEBUG SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, TRUE, TRUE, TRUE, &stored) ); if ( stored ) { ++(*nfoundsols); SCIPdebugMessage("Solution is feasible and stored.\n"); } else SCIPdebugMessage("Solution was not stored.\n"); #else /* only check integrality, because we solved an LP */ SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, &stored) ); if ( stored ) ++(*nfoundsols); #endif SCIP_CALL( SCIPendProbing(scip) ); /* possibly perform one-opt */ if ( stored && heurdata->oneopt ) { int nfound = 0; assert( *nfoundsols > 0 ); SCIP_CALL( tryOneOpt(scip, heur, heurdata, nindconss, indconss, solcand, &nfound) ); } return SCIP_OKAY; }
/** initializes visualization information and creates a file for visualization output */ SCIP_RETCODE SCIPvisualInit( SCIP_VISUAL* visual, /**< visualization information */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_MESSAGEHDLR* messagehdlr /**< message handler */ ) { assert( visual != NULL ); assert( set != NULL ); assert( set->visual_vbcfilename != NULL ); assert( set->visual_bakfilename != NULL ); assert( visual->nodenum == NULL ); /* check whether we should initialize VBC output */ if ( set->visual_vbcfilename[0] != '-' || set->visual_vbcfilename[1] != '\0' ) { SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_NORMAL, "storing VBC information in file <%s>\n", set->visual_vbcfilename); visual->vbcfile = fopen(set->visual_vbcfilename, "w"); visual->timestep = 0; visual->lastnode = NULL; visual->lastcolor = SCIP_VBCCOLOR_NONE; visual->userealtime = set->visual_realtime; if( visual->vbcfile == NULL ) { SCIPerrorMessage("error creating file <%s>\n", set->visual_vbcfilename); SCIPprintSysError(set->visual_vbcfilename); return SCIP_FILECREATEERROR; } SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#TYPE: COMPLETE TREE\n"); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#TIME: SET\n"); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#BOUNDS: SET\n"); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#INFORMATION: STANDARD\n"); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#NODE_NUMBER: NONE\n"); } /* check whether we should initialize BAK output */ if ( set->visual_bakfilename[0] != '-' || set->visual_bakfilename[1] != '\0' ) { SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_NORMAL, "storing BAK information in file <%s>\n", set->visual_bakfilename); visual->bakfile = fopen(set->visual_bakfilename, "w"); visual->timestep = 0; visual->lastnode = NULL; visual->lastcolor = SCIP_VBCCOLOR_NONE; visual->userealtime = set->visual_realtime; if ( visual->bakfile == NULL ) { SCIPerrorMessage("error creating file <%s>\n", set->visual_bakfilename); SCIPprintSysError(set->visual_bakfilename); return SCIP_FILECREATEERROR; } } /* possibly init hashmap for nodes */ if ( visual->vbcfile != NULL || visual->bakfile != NULL ) { SCIP_CALL( SCIPhashmapCreate(&visual->nodenum, blkmem, SCIP_HASHSIZE_VBC) ); } return SCIP_OKAY; }
/** updates a node entry in the visualization output file */ SCIP_RETCODE SCIPvisualUpdateChild( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< new node, that was created */ ) { SCIP_VAR* branchvar; SCIP_BOUNDTYPE branchtype; SCIP_Real branchbound; SCIP_Real lowerbound; size_t nodenum; assert( visual != NULL ); assert( stat != NULL ); assert( node != NULL ); /* check whether output should be created */ if ( visual->vbcfile == NULL && visual->bakfile == NULL ) return SCIP_OKAY; /* visualization is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return SCIP_OKAY; /* get node num from hash map */ nodenum = (size_t)SCIPhashmapGetImage(visual->nodenum, node); assert(nodenum > 0); /* get branching information */ getBranchInfo(node, &branchvar, &branchtype, &branchbound); /* determine lower bound */ if ( set->visual_objextern ) lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node)); else lowerbound = SCIPnodeGetLowerbound(node); if ( visual->vbcfile != NULL ) { printTime(visual, stat, TRUE); if( branchvar != NULL ) { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, lowerbound); } else { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), lowerbound); } } if ( visual->bakfile != NULL ) { size_t parentnodenum; SCIP_Real* lpcandsfrac; SCIP_Real sum = 0.0; int nlpcands = 0; char t = 'M'; const char* nodeinfo; int j; /* determine branching type */ if ( branchvar != NULL ) t = (branchtype == SCIP_BOUNDTYPE_LOWER ? 'R' : 'L'); /* get nodenum of parent node from hash map */ parentnodenum = (node->parent != NULL ? (size_t)SCIPhashmapGetImage(visual->nodenum, node->parent) : 0); assert(node->parent == NULL || parentnodenum > 0); /* update info depending on the node type */ switch( SCIPnodeGetType(node) ) { case SCIP_NODETYPE_CHILD: /* the child is a new candidate */ nodeinfo = "candidate"; break; case SCIP_NODETYPE_FOCUSNODE: /* the focus node is updated to a branch node */ nodeinfo = "branched"; /* calculate infeasibility information */ SCIP_CALL( SCIPgetLPBranchCands(set->scip, NULL, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) ); for (j = 0; j < nlpcands; ++j) sum += lpcandsfrac[j]; break; default: SCIPerrorMessage("Error: Unexpected node type <%d> in Update Child Method", SCIPnodeGetType(node)); return SCIP_INVALIDDATA; } /*lint !e788*/ /* append new status line with updated node information to the bakfile */ printTime(visual, stat, FALSE); SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "%s %d %d %c %f %f %d\n", nodeinfo, (int)nodenum, (int)parentnodenum, t, lowerbound, sum, nlpcands); } return SCIP_OKAY; }
/** call writing method */ static SCIP_RETCODE writeBounds( SCIP* scip, /**< SCIP data structure */ FILE* file, /**< file to write to or NULL */ SCIP_Bool writesubmipdualbound/**< write dualbounds of submip roots for all open nodes */ ) { SCIP_NODE** opennodes; int nopennodes; int n; int v; assert(scip != NULL); nopennodes = -1; #ifdef LONGSTATS SCIPinfoMessage(scip, file, "Status after %"SCIP_LONGINT_FORMAT" processed nodes (%d open)\n", SCIPgetNNodes(scip), SCIPgetNNodesLeft(scip)); SCIPinfoMessage(scip, file, "Primalbound: %g\n", SCIPgetPrimalbound(scip)); SCIPinfoMessage(scip, file, "Dualbound: %g\n", SCIPgetDualbound(scip)); #else SCIPinfoMessage(scip, file, "PB %g\n", SCIPgetPrimalbound(scip)); #endif /* get all open nodes and therefor print all dualbounds */ for( v = 2; v >= 0; --v ) { SCIP_NODE* node; switch( v ) { case 2: SCIP_CALL( SCIPgetChildren(scip, &opennodes, &nopennodes) ); break; case 1: SCIP_CALL( SCIPgetSiblings(scip, &opennodes, &nopennodes) ); break; case 0: SCIP_CALL( SCIPgetLeaves(scip, &opennodes, &nopennodes) ); break; default: assert(0); break; } assert(nopennodes >= 0); /* print all node information */ for( n = nopennodes - 1; n >= 0 && !SCIPisStopped(scip); --n ) { node = opennodes[n]; if( writesubmipdualbound ) { SCIP* subscip; SCIP_Bool valid; SCIP_HASHMAP* varmap; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; /* original problem's variables */ int nvars; SCIP_Real submipdb; SCIP_Bool cutoff; SCIP_CALL( SCIPcreate(&subscip) ); SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); submipdb = SCIP_INVALID; valid = FALSE; cutoff = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmap, NULL, "__boundwriting", TRUE, FALSE, TRUE, &valid) ); if( valid ) { SCIP_VAR** branchvars; SCIP_Real* branchbounds; SCIP_BOUNDTYPE* boundtypes; int nbranchvars; int size; size = SCIPnodeGetDepth(node); /* allocate memory for all branching decisions */ SCIP_CALL( SCIPallocBufferArray(scip, &branchvars, size) ); SCIP_CALL( SCIPallocBufferArray(scip, &branchbounds, size) ); SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, size) ); /* we assume that we only have one branching decision at each node */ SCIPnodeGetAncestorBranchings( node, branchvars, branchbounds, boundtypes, &nbranchvars, size ); /* check if did not have enough memory */ if( nbranchvars > size ) { size = nbranchvars; SCIP_CALL( SCIPallocBufferArray(scip, &branchvars, size) ); SCIP_CALL( SCIPallocBufferArray(scip, &branchbounds, size) ); SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, size) ); /* now getting all information */ SCIPnodeGetAncestorBranchings( node, branchvars, branchbounds, boundtypes, &nbranchvars, size ); } /* apply all changes to the submip */ SCIP_CALL( applyDomainChanges(subscip, branchvars, branchbounds, boundtypes, nbranchvars, varmap) ); /* free memory for all branching decisions */ SCIPfreeBufferArray(scip, &boundtypes); SCIPfreeBufferArray(scip, &branchbounds); SCIPfreeBufferArray(scip, &branchvars); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* solve only root node */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) ); /* set cutoffbound as objective limit for subscip */ SCIP_CALL( SCIPsetObjlimit(subscip, SCIPgetCutoffbound(scip)) ); SCIP_CALL( SCIPsolve(subscip) ); cutoff = (SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE); submipdb = SCIPgetDualbound(subscip) * SCIPgetTransObjscale(scip) + SCIPgetTransObjoffset(scip); } #ifdef LONGSTATS SCIPinfoMessage(scip, file, "Node %"SCIP_LONGINT_FORMAT" (depth %d): dualbound: %g, nodesubmiprootdualbound: %g %s\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node), submipdb, cutoff ? "(cutoff)" : ""); #else SCIPinfoMessage(scip, file, "%"SCIP_LONGINT_FORMAT" %d %g %g %s\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node), submipdb, cutoff ? "(cutoff)" : ""); #endif /* free hash map */ SCIPhashmapFree(&varmap); SCIP_CALL( SCIPfree(&subscip) ); } else { #ifdef LONGSTATS SCIPinfoMessage(scip, file, "Node %"SCIP_LONGINT_FORMAT" (depth %d): dualbound: %g\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node)); #else SCIPinfoMessage(scip, file, "%"SCIP_LONGINT_FORMAT" %d %g\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node)); #endif } } } #ifdef LONGSTATS SCIPinfoMessage(scip, file, "\n"); #endif return SCIP_OKAY; }
/** searches and adds integral objective cuts that separate the given primal solution */ static SCIP_RETCODE separateCuts( SCIP* scip, /**< SCIP data structure */ SCIP_SEPA* sepa, /**< the intobj separator */ SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */ SCIP_RESULT* result /**< pointer to store the result */ ) { SCIP_SEPADATA* sepadata; SCIP_Real objval; SCIP_Real intbound; SCIP_Bool infeasible; SCIP_Bool tightened; assert(result != NULL); assert(*result == SCIP_DIDNOTRUN); /* if the objective value may be fractional, we cannot do anything */ if( !SCIPisObjIntegral(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* if the current objective value is integral, there is no integral objective value cut */ if( sol == NULL ) objval = SCIPretransformObj(scip, SCIPgetLPObjval(scip)); else objval = SCIPgetSolOrigObj(scip, sol); if( SCIPisFeasIntegral(scip, objval) ) return SCIP_OKAY; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); /* the objective value is fractional: create the objective value inequality, if not yet existing */ SCIP_CALL( createObjRow(scip, sepa, sepadata) ); /* adjust the bounds of the objective value variable */ if( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ) { intbound = SCIPceil(scip, objval) - sepadata->setoff; SCIP_CALL( SCIPtightenVarLb(scip, sepadata->objvar, intbound, FALSE, &infeasible, &tightened) ); SCIPdebugMessage("new objective variable lower bound: <%s>[%g,%g]\n", SCIPvarGetName(sepadata->objvar), SCIPvarGetLbLocal(sepadata->objvar), SCIPvarGetUbLocal(sepadata->objvar)); } else { intbound = SCIPfloor(scip, objval) - sepadata->setoff; SCIP_CALL( SCIPtightenVarUb(scip, sepadata->objvar, intbound, FALSE, &infeasible, &tightened) ); SCIPdebugMessage("new objective variable upper bound: <%s>[%g,%g]\n", SCIPvarGetName(sepadata->objvar), SCIPvarGetLbLocal(sepadata->objvar), SCIPvarGetUbLocal(sepadata->objvar)); } /* add the objective value inequality as a cut to the LP */ if( infeasible ) *result = SCIP_CUTOFF; else { if( !SCIProwIsInLP(sepadata->objrow) ) { SCIP_CALL( SCIPaddCut(scip, sol, sepadata->objrow, FALSE) ); } if( tightened ) *result = SCIP_REDUCEDDOM; else *result = SCIP_SEPARATED; } return SCIP_OKAY; }
/** adds cuts to the LP and clears separation storage */ SCIP_RETCODE SCIPsepastoreApplyCuts( SCIP_SEPASTORE* sepastore, /**< separation storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_EVENTFILTER* eventfilter, /**< global event filter */ SCIP_Bool root, /**< are we at the root node? */ SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */ ) { SCIP_NODE* node; SCIP_Real mincutorthogonality; int depth; int maxsepacuts; int ncutsapplied; int pos; assert(sepastore != NULL); assert(set != NULL); assert(tree != NULL); assert(lp != NULL); assert(cutoff != NULL); *cutoff = FALSE; SCIPdebugMessage("applying %d cuts\n", sepastore->ncuts); node = SCIPtreeGetCurrentNode(tree); assert(node != NULL); /* get maximal number of cuts to add to the LP */ maxsepacuts = SCIPsetGetSepaMaxcuts(set, root); ncutsapplied = 0; /* get depth of current node */ depth = SCIPnodeGetDepth(node); /* calculate minimal cut orthogonality */ mincutorthogonality = (root ? set->sepa_minorthoroot : set->sepa_minortho); mincutorthogonality = MAX(mincutorthogonality, set->num_epsilon); /* Compute scores for all non-forced cuts and initialize orthogonalities - make sure all cuts are initialized again for the current LP solution */ for( pos = sepastore->nforcedcuts; pos < sepastore->ncuts; pos++ ) { SCIP_CALL( computeScore(sepastore, set, stat, lp, TRUE, pos) ); } /* apply all forced cuts */ for( pos = 0; pos < sepastore->nforcedcuts && !(*cutoff); pos++ ) { SCIP_ROW* cut; cut = sepastore->cuts[pos]; assert(SCIPsetIsInfinity(set, sepastore->scores[pos])); /* if the cut is a bound change (i.e. a row with only one variable), add it as bound change instead of LP row */ if( !SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 ) { SCIPdebugMessage(" -> applying forced cut <%s> as boundchange\n", SCIProwGetName(cut)); SCIP_CALL( sepastoreApplyBdchg(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, cut, cutoff) ); } else { /* add cut to the LP and update orthogonalities */ SCIPdebugMessage(" -> applying forced cut <%s>\n", SCIProwGetName(cut)); /*SCIPdebug(SCIProwPrint(cut, NULL));*/ SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, depth, &ncutsapplied) ); } } /* apply non-forced cuts */ while( ncutsapplied < maxsepacuts && sepastore->ncuts > sepastore->nforcedcuts && !(*cutoff) ) { SCIP_ROW* cut; int bestpos; /* get best non-forced cut */ bestpos = sepastoreGetBestCut(sepastore); assert(sepastore->nforcedcuts <= bestpos && bestpos < sepastore->ncuts); assert(sepastore->scores[bestpos] != SCIP_INVALID ); /*lint !e777*/ assert(sepastore->efficacies[bestpos] != SCIP_INVALID ); /*lint !e777*/ cut = sepastore->cuts[bestpos]; assert(SCIProwIsModifiable(cut) || SCIProwGetNNonz(cut) != 1); /* bound changes are forced cuts */ assert(!SCIPsetIsInfinity(set, sepastore->scores[bestpos])); SCIPdebugMessage(" -> applying cut <%s> (pos=%d/%d, len=%d, efficacy=%g, objparallelism=%g, orthogonality=%g, score=%g)\n", SCIProwGetName(cut), bestpos, sepastore->ncuts, SCIProwGetNNonz(cut), sepastore->efficacies[bestpos], sepastore->objparallelisms[bestpos], sepastore->orthogonalities[bestpos], sepastore->scores[bestpos]); /*SCIPdebug(SCIProwPrint(cut, NULL));*/ /* capture cut such that it is not destroyed in sepastoreDelCut() */ SCIProwCapture(cut); /* release the row and delete the cut (also issuing ROWDELETEDSEPA event) */ SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, bestpos) ); /* Do not add (non-forced) non-violated cuts. * Note: do not take SCIPsetIsEfficacious(), because constraint handlers often add cuts w.r.t. SCIPsetIsFeasPositive(). */ if( SCIPsetIsFeasPositive(set, sepastore->efficacies[bestpos]) ) { /* add cut to the LP and update orthogonalities */ SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, depth, &ncutsapplied) ); } /* release cut */ SCIP_CALL( SCIProwRelease(&cut, blkmem, set, lp) ); } /* clear the separation storage and reset statistics for separation round */ SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) ); return SCIP_OKAY; }
/** creates the guideddiving heuristic and includes it in SCIP */ SCIP_RETCODE SCIPincludeHeurGuideddiving( SCIP* scip /**< SCIP data structure */ ) { SCIP_HEURDATA* heurdata; SCIP_HEUR* heur; /* create Guideddiving primal heuristic data */ SCIP_CALL( SCIPallocMemory(scip, &heurdata) ); /* include primal heuristic */ SCIP_CALL( SCIPincludeHeurBasic(scip, &heur, HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS, HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecGuideddiving, heurdata) ); assert(heur != NULL); /* set non-NULL pointers to callback methods */ SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyGuideddiving) ); SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeGuideddiving) ); SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitGuideddiving) ); SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitGuideddiving) ); /* guideddiving heuristic parameters */ SCIP_CALL( SCIPaddRealParam(scip, "heuristics/guideddiving/minreldepth", "minimal relative depth to start diving", &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/guideddiving/maxreldepth", "maximal relative depth to start diving", &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/guideddiving/maxlpiterquot", "maximal fraction of diving LP iterations compared to node LP iterations", &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddIntParam(scip, "heuristics/guideddiving/maxlpiterofs", "additional number of allowed LP iterations", &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/guideddiving/maxdiveubquot", "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)", &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/guideddiving/maxdiveavgquot", "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)", &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/guideddiving/backtrack", "use one level of backtracking if infeasibility is encountered?", &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecOneopt) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* bestsol; /* incumbent solution */ SCIP_SOL* worksol; /* heuristic's working solution */ SCIP_VAR** vars; /* SCIP variables */ SCIP_VAR** shiftcands; /* shiftable variables */ SCIP_ROW** lprows; /* SCIP LP rows */ SCIP_Real* activities; /* row activities for working solution */ SCIP_Real* shiftvals; SCIP_Real lb; SCIP_Real ub; SCIP_Bool localrows; SCIP_Bool valid; int nchgbound; int nbinvars; int nintvars; int nvars; int nlprows; int i; int nshiftcands; int shiftcandssize; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); *result = SCIP_DELAYED; /* we only want to process each solution once */ bestsol = SCIPgetBestSol(scip); if( bestsol == NULL || heurdata->lastsolindex == SCIPsolGetIndex(bestsol) ) return SCIP_OKAY; /* reset the timing mask to its default value (at the root node it could be different) */ if( SCIPgetNNodes(scip) > 1 ) SCIPheurSetTimingmask(heur, HEUR_TIMING); /* get problem variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); nintvars += nbinvars; /* do not run if there are no discrete variables */ if( nintvars == 0 ) { *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } if( heurtiming == SCIP_HEURTIMING_BEFOREPRESOL ) { SCIP* subscip; /* the subproblem created by zeroobj */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_Real* subsolvals; /* solution values of the subproblem */ SCIP_Real timelimit; /* time limit for zeroobj subproblem */ SCIP_Real memorylimit; /* memory limit for zeroobj subproblem */ SCIP_SOL* startsol; SCIP_SOL** subsols; int nsubsols; if( !heurdata->beforepresol ) return SCIP_OKAY; /* check whether there is enough time and memory left */ timelimit = 0.0; memorylimit = 0.0; SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) return SCIP_OKAY; /* initialize the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); /* copy complete SCIP instance */ valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "oneopt", TRUE, FALSE, TRUE, &valid) ); SCIP_CALL( SCIPtransformProb(subscip) ); /* get variable image */ for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* copy the solution */ SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) ); SCIP_CALL( SCIPgetSolVals(scip, bestsol, nvars, vars, subsolvals) ); /* create start solution for the subproblem */ SCIP_CALL( SCIPcreateOrigSol(subscip, &startsol, NULL) ); SCIP_CALL( SCIPsetSolVals(subscip, startsol, nvars, subvars, subsolvals) ); /* try to add new solution to sub-SCIP and free it immediately */ valid = FALSE; SCIP_CALL( SCIPtrySolFree(subscip, &startsol, FALSE, FALSE, FALSE, FALSE, &valid) ); SCIPfreeBufferArray(scip, &subsolvals); SCIPhashmapFree(&varmapfw); /* disable statistic timing inside sub SCIP */ SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) ); /* deactivate basically everything except oneopt in the sub-SCIP */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetHeuristics(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* if necessary, some of the parameters have to be unfixed first */ if( SCIPisParamFixed(subscip, "lp/solvefreq") ) { SCIPwarningMessage(scip, "unfixing parameter lp/solvefreq in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "lp/solvefreq") ); } SCIP_CALL( SCIPsetIntParam(subscip, "lp/solvefreq", -1) ); if( SCIPisParamFixed(subscip, "heuristics/oneopt/freq") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/freq in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/freq") ); } SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/oneopt/freq", 1) ); if( SCIPisParamFixed(subscip, "heuristics/oneopt/forcelpconstruction") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/forcelpconstruction in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/forcelpconstruction") ); } SCIP_CALL( SCIPsetBoolParam(subscip, "heuristics/oneopt/forcelpconstruction", TRUE) ); /* avoid recursive call, which would lead to an endless loop */ if( SCIPisParamFixed(subscip, "heuristics/oneopt/beforepresol") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/beforepresol in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/beforepresol") ); } SCIP_CALL( SCIPsetBoolParam(subscip, "heuristics/oneopt/beforepresol", FALSE) ); if( valid ) { retcode = SCIPsolve(subscip); /* errors in solving the subproblem should not kill the overall solving process; * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in zeroobj heuristic; sub-SCIP terminated with code <%d>\n",retcode); } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif } /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); valid = FALSE; for( i = 0; i < nsubsols && !valid; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &valid) ); if( valid ) *result = SCIP_FOUNDSOL; } /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; } /* we can only work on solutions valid in the transformed space */ if( SCIPsolIsOriginal(bestsol) ) return SCIP_OKAY; if( heurtiming == SCIP_HEURTIMING_BEFORENODE && (SCIPhasCurrentNodeLP(scip) || heurdata->forcelpconstruction) ) { SCIP_Bool cutoff; cutoff = FALSE; SCIP_CALL( SCIPconstructLP(scip, &cutoff) ); SCIP_CALL( SCIPflushLP(scip) ); /* get problem variables again, SCIPconstructLP() might have added new variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); nintvars += nbinvars; } /* we need an LP */ if( SCIPgetNLPRows(scip) == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; nchgbound = 0; /* initialize data */ nshiftcands = 0; shiftcandssize = 8; heurdata->lastsolindex = SCIPsolGetIndex(bestsol); SCIP_CALL( SCIPcreateSolCopy(scip, &worksol, bestsol) ); SCIPsolSetHeur(worksol,heur); SCIPdebugMessage("Starting bound adjustment in 1-opt heuristic\n"); /* maybe change solution values due to global bound changes first */ for( i = nvars - 1; i >= 0; --i ) { SCIP_VAR* var; SCIP_Real solval; var = vars[i]; lb = SCIPvarGetLbGlobal(var); ub = SCIPvarGetUbGlobal(var); solval = SCIPgetSolVal(scip, bestsol,var); /* old solution value is smaller than the actual lower bound */ if( SCIPisFeasLT(scip, solval, lb) ) { /* set the solution value to the global lower bound */ SCIP_CALL( SCIPsetSolVal(scip, worksol, var, lb) ); ++nchgbound; SCIPdebugMessage("var <%s> type %d, old solval %g now fixed to lb %g\n", SCIPvarGetName(var), SCIPvarGetType(var), solval, lb); } /* old solution value is greater than the actual upper bound */ else if( SCIPisFeasGT(scip, solval, SCIPvarGetUbGlobal(var)) ) { /* set the solution value to the global upper bound */ SCIP_CALL( SCIPsetSolVal(scip, worksol, var, ub) ); ++nchgbound; SCIPdebugMessage("var <%s> type %d, old solval %g now fixed to ub %g\n", SCIPvarGetName(var), SCIPvarGetType(var), solval, ub); } } SCIPdebugMessage("number of bound changes (due to global bounds) = %d\n", nchgbound); SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) ); localrows = FALSE; valid = TRUE; /* initialize activities */ for( i = 0; i < nlprows; ++i ) { SCIP_ROW* row; row = lprows[i]; assert(SCIProwGetLPPos(row) == i); if( !SCIProwIsLocal(row) ) { activities[i] = SCIPgetRowSolActivity(scip, row, worksol); SCIPdebugMessage("Row <%s> has activity %g\n", SCIProwGetName(row), activities[i]); if( SCIPisFeasLT(scip, activities[i], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[i], SCIProwGetRhs(row)) ) { valid = FALSE; SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) ); SCIPdebugMessage("row <%s> activity %g violates bounds, lhs = %g, rhs = %g\n", SCIProwGetName(row), activities[i], SCIProwGetLhs(row), SCIProwGetRhs(row)); break; } } else localrows = TRUE; } if( !valid ) { /** @todo try to correct lp rows */ SCIPdebugMessage("Some global bound changes were not valid in lp rows.\n"); goto TERMINATE; } SCIP_CALL( SCIPallocBufferArray(scip, &shiftcands, shiftcandssize) ); SCIP_CALL( SCIPallocBufferArray(scip, &shiftvals, shiftcandssize) ); SCIPdebugMessage("Starting 1-opt heuristic\n"); /* enumerate all integer variables and find out which of them are shiftable */ for( i = 0; i < nintvars; i++ ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { SCIP_Real shiftval; SCIP_Real solval; /* find out whether the variable can be shifted */ solval = SCIPgetSolVal(scip, worksol, vars[i]); shiftval = calcShiftVal(scip, vars[i], solval, activities); /* insert the variable into the list of shifting candidates */ if( !SCIPisFeasZero(scip, shiftval) ) { SCIPdebugMessage(" -> Variable <%s> can be shifted by <%1.1f> \n", SCIPvarGetName(vars[i]), shiftval); if( nshiftcands == shiftcandssize) { shiftcandssize *= 8; SCIP_CALL( SCIPreallocBufferArray(scip, &shiftcands, shiftcandssize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &shiftvals, shiftcandssize) ); } shiftcands[nshiftcands] = vars[i]; shiftvals[nshiftcands] = shiftval; nshiftcands++; } } } /* if at least one variable can be shifted, shift variables sorted by their objective */ if( nshiftcands > 0 ) { SCIP_Real shiftval; SCIP_Real solval; SCIP_VAR* var; /* the case that exactly one variable can be shifted is slightly easier */ if( nshiftcands == 1 ) { var = shiftcands[0]; assert(var != NULL); solval = SCIPgetSolVal(scip, worksol, var); shiftval = shiftvals[0]; assert(!SCIPisFeasZero(scip,shiftval)); SCIPdebugMessage(" Only one shiftcand found, var <%s>, which is now shifted by<%1.1f> \n", SCIPvarGetName(var), shiftval); SCIP_CALL( SCIPsetSolVal(scip, worksol, var, solval+shiftval) ); } else { SCIP_Real* objcoeffs; SCIP_CALL( SCIPallocBufferArray(scip, &objcoeffs, nshiftcands) ); SCIPdebugMessage(" %d shiftcands found \n", nshiftcands); /* sort the variables by their objective, optionally weighted with the shiftval */ if( heurdata->weightedobj ) { for( i = 0; i < nshiftcands; ++i ) objcoeffs[i] = SCIPvarGetObj(shiftcands[i])*shiftvals[i]; } else { for( i = 0; i < nshiftcands; ++i ) objcoeffs[i] = SCIPvarGetObj(shiftcands[i]); } /* sort arrays with respect to the first one */ SCIPsortRealPtr(objcoeffs, (void**)shiftcands, nshiftcands); /* try to shift each variable -> Activities have to be updated */ for( i = 0; i < nshiftcands; ++i ) { var = shiftcands[i]; assert(var != NULL); solval = SCIPgetSolVal(scip, worksol, var); shiftval = calcShiftVal(scip, var, solval, activities); SCIPdebugMessage(" -> Variable <%s> is now shifted by <%1.1f> \n", SCIPvarGetName(vars[i]), shiftval); assert(i > 0 || !SCIPisFeasZero(scip, shiftval)); assert(SCIPisFeasGE(scip, solval+shiftval, SCIPvarGetLbGlobal(var)) && SCIPisFeasLE(scip, solval+shiftval, SCIPvarGetUbGlobal(var))); SCIP_CALL( SCIPsetSolVal(scip, worksol, var, solval+shiftval) ); SCIP_CALL( updateRowActivities(scip, activities, var, shiftval) ); } SCIPfreeBufferArray(scip, &objcoeffs); } /* if the problem is a pure IP, try to install the solution, if it is a MIP, solve LP again to set the continuous * variables to the best possible value */ if( nvars == nintvars || !SCIPhasCurrentNodeLP(scip) || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* since we ignore local rows, we cannot guarantee their feasibility and have to set the checklprows flag to * TRUE if local rows are present */ SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, localrows, &success) ); if( success ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) ); heurdata->lastsolindex = SCIPsolGetIndex(bestsol); *result = SCIP_FOUNDSOL; } } else { SCIP_Bool lperror; #ifdef NDEBUG SCIP_RETCODE retstat; #endif SCIPdebugMessage("shifted solution should be feasible -> solve LP to fix continuous variables to best values\n"); /* start diving to calculate the LP relaxation */ SCIP_CALL( SCIPstartDive(scip) ); /* set the bounds of the variables: fixed for integers, global bounds for continuous */ for( i = 0; i < nvars; ++i ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], SCIPvarGetLbGlobal(vars[i])) ); SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], SCIPvarGetUbGlobal(vars[i])) ); } } /* apply this after global bounds to not cause an error with intermediate empty domains */ for( i = 0; i < nintvars; ++i ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { solval = SCIPgetSolVal(scip, worksol, vars[i]); SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], solval) ); SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], solval) ); } } /* solve LP */ SCIPdebugMessage(" -> old LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip)); /**@todo in case of an MINLP, if SCIPisNLPConstructed() is TRUE, say, rather solve the NLP instead of the LP */ /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ #ifdef NDEBUG retstat = SCIPsolveDiveLP(scip, -1, &lperror, NULL); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Oneopt heuristic; LP solve terminated with code <%d>\n",retstat); } #else SCIP_CALL( SCIPsolveDiveLP(scip, -1, &lperror, NULL) ); #endif SCIPdebugMessage(" -> new LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip)); SCIPdebugMessage(" -> error=%u, status=%d\n", lperror, SCIPgetLPSolstat(scip)); /* check if this is a feasible solution */ if( !lperror && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, worksol) ); SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check solution for feasibility */ if( success ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) ); heurdata->lastsolindex = SCIPsolGetIndex(bestsol); *result = SCIP_FOUNDSOL; } } /* terminate the diving */ SCIP_CALL( SCIPendDive(scip) ); } } SCIPdebugMessage("Finished 1-opt heuristic\n"); SCIPfreeBufferArray(scip, &shiftvals); SCIPfreeBufferArray(scip, &shiftcands); TERMINATE: SCIPfreeBufferArray(scip, &activities); SCIP_CALL( SCIPfreeSol(scip, &worksol) ); return SCIP_OKAY; }
/** creates the oneopt primal heuristic and includes it in SCIP */ SCIP_RETCODE SCIPincludeHeurOneopt( SCIP* scip /**< SCIP data structure */ ) { SCIP_HEURDATA* heurdata; SCIP_HEUR* heur; /* create Oneopt primal heuristic data */ SCIP_CALL( SCIPallocMemory(scip, &heurdata) ); /* include primal heuristic */ SCIP_CALL( SCIPincludeHeurBasic(scip, &heur, HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS, HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecOneopt, heurdata) ); assert(heur != NULL); /* set non-NULL pointers to callback methods */ SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyOneopt) ); SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeOneopt) ); SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolOneopt) ); SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolOneopt) ); SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitOneopt) ); /* add oneopt primal heuristic parameters */ SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/oneopt/weightedobj", "should the objective be weighted with the potential shifting value when sorting the shifting candidates?", &heurdata->weightedobj, TRUE, DEFAULT_WEIGHTEDOBJ, NULL, NULL) ); SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/oneopt/duringroot", "should the heuristic be called before and during the root node?", &heurdata->duringroot, TRUE, DEFAULT_DURINGROOT, NULL, NULL) ); SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/oneopt/forcelpconstruction", "should the construction of the LP be forced even if LP solving is deactivated?", &heurdata->forcelpconstruction, TRUE, DEFAULT_FORCELPCONSTRUCTION, NULL, NULL) ); SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/oneopt/beforepresol", "should the heuristic be called before presolving?", &heurdata->beforepresol, TRUE, DEFAULT_BEFOREPRESOL, NULL, NULL) ); 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; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecTrivial) { /*lint --e{715}*/ SCIP_VAR** vars; SCIP_SOL* lbsol; /* solution where all variables are set to their lower bounds */ SCIP_SOL* ubsol; /* solution where all variables are set to their upper bounds */ SCIP_SOL* zerosol; /* solution where all variables are set to zero */ SCIP_SOL* locksol; /* solution where all variables are set to the bound with the fewer locks */ SCIP_Real large; int nvars; int nbinvars; int i; SCIP_Bool success; SCIP_Bool zerovalid; *result = SCIP_DIDNOTRUN; if( SCIPgetNRuns(scip) > 1 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; success = FALSE; /* initialize data structure */ SCIP_CALL( SCIPcreateSol(scip, &lbsol, heur) ); SCIP_CALL( SCIPcreateSol(scip, &ubsol, heur) ); SCIP_CALL( SCIPcreateSol(scip, &zerosol, heur) ); SCIP_CALL( SCIPcreateSol(scip, &locksol, heur) ); /* determine large value to set variables to */ large = SCIPinfinity(scip); if( !SCIPisInfinity(scip, 0.1 / SCIPfeastol(scip)) ) large = 0.1 / SCIPfeastol(scip); SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) ); /* if the problem is binary, we do not have to check the zero solution, since it is equal to the lower bound * solution */ zerovalid = (nvars != nbinvars); assert(vars != NULL || nvars == 0); for( i = 0; i < nvars; i++ ) { SCIP_Real lb; SCIP_Real ub; assert(vars != NULL); /* this assert is needed for flexelint */ lb = SCIPvarGetLbLocal(vars[i]); ub = SCIPvarGetUbLocal(vars[i]); /* if problem is obviously infeasible due to empty domain, stop */ if( SCIPisGT(scip, lb, ub) ) goto TERMINATE; /* set bounds to sufficient large value */ if( SCIPisInfinity(scip, -lb) ) lb = MIN(-large, ub); if( SCIPisInfinity(scip, ub) ) { SCIP_Real tmp; tmp = SCIPvarGetLbLocal(vars[i]); ub = MAX(tmp, large); } SCIP_CALL( SCIPsetSolVal(scip, lbsol, vars[i], lb) ); SCIP_CALL( SCIPsetSolVal(scip, ubsol, vars[i], ub) ); /* try the zero vector, if it is in the bounds region */ if( zerovalid ) { if( SCIPisLE(scip, lb, 0.0) && SCIPisLE(scip, 0.0, ub) ) { SCIP_CALL( SCIPsetSolVal(scip, zerosol, vars[i], 0.0) ); } else zerovalid = FALSE; } /* set variables to the bound with fewer locks, if tie choose an average value */ if( SCIPvarGetNLocksDown(vars[i]) > SCIPvarGetNLocksUp(vars[i]) ) { SCIP_CALL( SCIPsetSolVal(scip, locksol, vars[i], ub) ); } else if( SCIPvarGetNLocksDown(vars[i]) < SCIPvarGetNLocksUp(vars[i]) ) { SCIP_CALL( SCIPsetSolVal(scip, locksol, vars[i], lb) ); } else { SCIP_Real solval; solval = (lb+ub)/2.0; /* if a tie occurs, roughly every third integer variable will be rounded up */ if( SCIPvarGetType(vars[i]) != SCIP_VARTYPE_CONTINUOUS ) solval = i % 3 == 0 ? SCIPceil(scip,solval) : SCIPfloor(scip,solval); assert(SCIPisFeasLE(scip,SCIPvarGetLbLocal(vars[i]),solval) && SCIPisFeasLE(scip,solval,SCIPvarGetUbLocal(vars[i]))); SCIP_CALL( SCIPsetSolVal(scip, locksol, vars[i], solval) ); } } /* try lower bound solution */ SCIPdebugMessage("try lower bound solution\n"); SCIP_CALL( SCIPtrySol(scip, lbsol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible lower bound solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, lbsol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } /* try upper bound solution */ SCIPdebugMessage("try upper bound solution\n"); SCIP_CALL( SCIPtrySol(scip, ubsol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible upper bound solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, ubsol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } /* try zero solution */ if( zerovalid ) { SCIPdebugMessage("try zero solution\n"); SCIP_CALL( SCIPtrySol(scip, zerosol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible zero solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, zerosol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } } /* try lock solution */ SCIPdebugMessage("try lock solution\n"); SCIP_CALL( SCIPtrySol(scip, locksol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible lock solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, locksol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } TERMINATE: /* free solutions */ SCIP_CALL( SCIPfreeSol(scip, &lbsol) ); SCIP_CALL( SCIPfreeSol(scip, &ubsol) ); SCIP_CALL( SCIPfreeSol(scip, &zerosol) ); SCIP_CALL( SCIPfreeSol(scip, &locksol) ); return SCIP_OKAY; }
static SCIP_RETCODE fromCommandLine( SCIP* scip, /**< SCIP data structure */ const char* filename /**< input file name */ ) { SCIP_RETCODE retcode; /******************** * Problem Creation * ********************/ /** @note The message handler should be only fed line by line such the message has the chance to add string in front * of each message */ SCIPinfoMessage(scip, NULL, "\n"); SCIPinfoMessage(scip, NULL, "read problem <%s>\n", filename); SCIPinfoMessage(scip, NULL, "============\n"); SCIPinfoMessage(scip, NULL, "\n"); retcode = SCIPreadProb(scip, filename, NULL); switch( retcode ) { case SCIP_NOFILE: SCIPinfoMessage(scip, NULL, "file <%s> not found\n", filename); return SCIP_OKAY; case SCIP_PLUGINNOTFOUND: SCIPinfoMessage(scip, NULL, "no reader for input file <%s> available\n", filename); return SCIP_OKAY; case SCIP_READERROR: SCIPinfoMessage(scip, NULL, "error reading file <%s>\n", filename); return SCIP_OKAY; default: SCIP_CALL( retcode ); } /*lint !e788*/ /******************* * Problem Solving * *******************/ /* solve problem */ SCIPinfoMessage(scip, NULL, "\nsolve problem\n"); SCIPinfoMessage(scip, NULL, "=============\n\n"); SCIP_CALL( SCIPsolve(scip) ); SCIPinfoMessage(scip, NULL, "\nprimal solution:\n"); SCIPinfoMessage(scip, NULL, "================\n\n"); SCIP_CALL( SCIPprintBestSol(scip, NULL, FALSE) ); /************** * Statistics * **************/ SCIPinfoMessage(scip, NULL, "\nStatistics\n"); SCIPinfoMessage(scip, NULL, "==========\n\n"); SCIP_CALL( SCIPprintStatistics(scip, NULL) ); return SCIP_OKAY; }
/** try one-opt on given solution */ static SCIP_RETCODE tryOneOpt( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand, /**< values for indicator variables in partial solution */ int* nfoundsols /**< number of solutions found */ ) { SCIP_Bool cutoff; SCIP_Bool lperror; SCIP_Bool stored; SCIP_SOL* sol; int cnt = 0; int i; int c; assert( scip != NULL ); assert( heur != NULL ); assert( heurdata != NULL ); assert( nindconss == 0 || indconss != NULL ); assert( solcand != NULL ); assert( nfoundsols != NULL ); SCIPdebugMessage("Performing one-opt ...\n"); *nfoundsols = 0; SCIP_CALL( SCIPstartProbing(scip) ); for (i = 0; i < nindconss; ++i) { SCIP_VAR* binvar; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[i]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[i]); assert( binvar != NULL ); /* skip constraints with fixed variables */ if ( SCIPvarGetUbLocal(binvar) < 0.5 || SCIPvarGetLbLocal(binvar) > 0.5 ) continue; /* return if the we would exceed the depth limit of the tree */ if( SCIPgetDepthLimit(scip) <= SCIPgetDepth(scip) ) break; /* get rid of all bound changes */ SCIP_CALL( SCIPnewProbingNode(scip) ); ++cnt; /* fix variables */ for (c = 0; c < nindconss; ++c) { SCIP_Bool s; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[c]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[c]); assert( binvar != NULL ); /* fix variables according to solution candidate, except constraint i */ if ( c == i ) s = ! solcand[c]; else s = solcand[c]; if ( ! s ) { if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 ) { SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) ); } } else { if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 ) { SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) ); } } } /* propagate variables */ SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, NULL) ); if ( cutoff ) { SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); continue; } /* solve LP to move continuous variables */ SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) ); /* the LP often reaches the objective limit - we currently do not use such solutions */ if ( lperror || cutoff || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { #ifdef SCIP_DEBUG if ( lperror ) SCIPdebugMessage("An LP error occured.\n"); #endif SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); continue; } /* create solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, heur) ); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* check solution for feasibility */ SCIPdebugMessage("One-opt found solution candidate with value %g.\n", SCIPgetSolTransObj(scip, sol)); /* only check integrality, because we solved an LP */ SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, &stored) ); if ( stored ) ++(*nfoundsols); SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); } SCIP_CALL( SCIPendProbing(scip) ); SCIPdebugMessage("Finished one-opt (tried variables: %d, found sols: %d).\n", cnt, *nfoundsols); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecIndicator) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; int nfoundsols = 0; assert( heur != NULL ); assert( scip != NULL ); assert( result != NULL ); *result = SCIP_DIDNOTRUN; if ( SCIPgetSubscipDepth(scip) > 0 ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* call heuristic, if solution candidate is available */ if ( heurdata->solcand != NULL ) { assert( heurdata->nindconss > 0 ); assert( heurdata->indconss != NULL ); /* The heuristic will only be successful if there are no integral variables and no binary variables except the * indicator variables. */ if ( SCIPgetNIntVars(scip) > 0 || heurdata->nindconss < SCIPgetNBinVars(scip) ) return SCIP_OKAY; SCIP_CALL( trySolCandidate(scip, heur, heurdata, heurdata->nindconss, heurdata->indconss, heurdata->solcand, &nfoundsols) ); if ( nfoundsols > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; /* free memory */ SCIPfreeBlockMemoryArray(scip, &(heurdata->solcand), heurdata->nindconss); SCIPfreeBlockMemoryArray(scip, &(heurdata->indconss), heurdata->nindconss); } else { SCIP_CONS** indconss; SCIP_Bool* solcand; SCIP_SOL* bestsol; int nindconss; int i; if ( heurdata->indicatorconshdlr == NULL ) return SCIP_OKAY; /* check whether a new best solution has been found */ bestsol = SCIPgetBestSol(scip); if ( bestsol == heurdata->lastsol ) return SCIP_OKAY; heurdata->lastsol = bestsol; /* avoid solutions produced by this heuristic */ if ( SCIPsolGetHeur(bestsol) == heur ) return SCIP_OKAY; /* The heuristic will only be successful if there are no integral variables and no binary variables except the * indicator variables. */ if ( SCIPgetNIntVars(scip) > 0 || SCIPconshdlrGetNConss(heurdata->indicatorconshdlr) < SCIPgetNBinVars(scip) ) return SCIP_OKAY; nindconss = SCIPconshdlrGetNConss(heurdata->indicatorconshdlr); if ( nindconss == 0 ) return SCIP_OKAY; indconss = SCIPconshdlrGetConss(heurdata->indicatorconshdlr); assert( indconss != NULL ); /* fill solutin candidate */ SCIP_CALL( SCIPallocBufferArray(scip, &solcand, nindconss) ); for (i = 0; i < nindconss; ++i) { SCIP_VAR* binvar; SCIP_Real val; solcand[i] = FALSE; if ( SCIPconsIsActive(indconss[i]) ) { binvar = SCIPgetBinaryVarIndicator(indconss[i]); assert( binvar != NULL ); val = SCIPgetSolVal(scip, bestsol, binvar); assert( SCIPisFeasIntegral(scip, val) ); if ( val > 0.5 ) solcand[i] = TRUE; } } SCIPdebugMessage("Trying to improve best solution of value %f.\n", SCIPgetSolOrigObj(scip, bestsol) ); /* try one-opt heuristic */ SCIP_CALL( tryOneOpt(scip, heur, heurdata, nindconss, indconss, solcand, &nfoundsols) ); if ( nfoundsols > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; SCIPfreeBufferArray(scip, &solcand); } return SCIP_OKAY; }
/** adds cut stored as LP row to separation storage and captures it; * if the cut should be forced to be used, an infinite score has to be used */ static SCIP_RETCODE sepastoreAddCut( SCIP_SEPASTORE* sepastore, /**< separation storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics data */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */ SCIP_LP* lp, /**< LP data */ SCIP_SOL* sol, /**< primal solution that was separated, or NULL for LP solution */ SCIP_ROW* cut, /**< separated cut */ SCIP_Bool forcecut, /**< should the cut be forced to enter the LP? */ SCIP_Bool root /**< are we at the root node? */ ) { SCIP_Real cutefficacy; SCIP_Real cutobjparallelism; SCIP_Real cutscore; int pos; assert(sepastore != NULL); assert(sepastore->nforcedcuts <= sepastore->ncuts); assert(set != NULL); assert(cut != NULL); assert(sol != NULL || !SCIProwIsInLP(cut)); assert(!SCIPsetIsInfinity(set, -SCIProwGetLhs(cut)) || !SCIPsetIsInfinity(set, SCIProwGetRhs(cut))); assert(eventqueue != NULL); assert(eventfilter != NULL); /* in the root node, every local cut is a global cut, and global cuts are nicer in many ways...*/ if( root && SCIProwIsLocal(cut) ) { SCIPdebugMessage("change local flag of cut <%s> to FALSE due to addition in root node\n", SCIProwGetName(cut)); SCIP_CALL( SCIProwChgLocal(cut, FALSE) ); assert(!SCIProwIsLocal(cut)); } /* check cut for redundancy * in each separation round, make sure that at least one (even redundant) cut enters the LP to avoid cycling */ if( !forcecut && sepastore->ncuts > 0 && sepastoreIsCutRedundant(sepastore, set, stat, cut) ) return SCIP_OKAY; /* if only one cut is currently present in the cut store, it could be redundant; in this case, it can now be removed * again, because now a non redundant cut enters the store */ if( sepastore->ncuts == 1 && sepastoreIsCutRedundant(sepastore, set, stat, sepastore->cuts[0]) ) { /* check, if the row deletions from separation storage events are tracked * if so, issue ROWDELETEDSEPA event */ if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 ) { SCIP_EVENT* event; SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[0]) ); SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) ); } SCIP_CALL( SCIProwRelease(&sepastore->cuts[0], blkmem, set, lp) ); sepastore->ncuts = 0; sepastore->nforcedcuts = 0; } /* a cut is forced to enter the LP if * - we construct the initial LP, or * - it has infinite score factor, or * - it is a bound change * if it is a non-forced cut and no cuts should be added, abort */ forcecut = forcecut || sepastore->initiallp || sepastore->forcecuts || (!SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1); if( !forcecut && SCIPsetGetSepaMaxcuts(set, root) == 0 ) return SCIP_OKAY; /* get enough memory to store the cut */ SCIP_CALL( sepastoreEnsureCutsMem(sepastore, set, sepastore->ncuts+1) ); assert(sepastore->ncuts < sepastore->cutssize); if( forcecut ) { cutefficacy = SCIPsetInfinity(set); cutscore = SCIPsetInfinity(set); cutobjparallelism = 1.0; } else { /* initialize values to invalid (will be initialized during cut filtering) */ cutefficacy = SCIP_INVALID; cutscore = SCIP_INVALID; /* initialize parallelism to objective (constant throughout filtering) */ if( set->sepa_objparalfac > 0.0 ) cutobjparallelism = SCIProwGetObjParallelism(cut, set, lp); else cutobjparallelism = 0.0; /* no need to calculate it */ } SCIPdebugMessage("adding cut <%s> to separation storage of size %d (forcecut=%u, len=%d)\n", SCIProwGetName(cut), sepastore->ncuts, forcecut, SCIProwGetNNonz(cut)); /*SCIPdebug(SCIProwPrint(cut, NULL));*/ /* capture the cut */ SCIProwCapture(cut); /* add cut to arrays */ if( forcecut ) { /* make room at the beginning of the array for forced cut */ pos = sepastore->nforcedcuts; sepastore->cuts[sepastore->ncuts] = sepastore->cuts[pos]; sepastore->efficacies[sepastore->ncuts] = sepastore->efficacies[pos]; sepastore->objparallelisms[sepastore->ncuts] = sepastore->objparallelisms[pos]; sepastore->orthogonalities[sepastore->ncuts] = sepastore->orthogonalities[pos]; sepastore->scores[sepastore->ncuts] = sepastore->scores[pos]; sepastore->nforcedcuts++; } else pos = sepastore->ncuts; sepastore->cuts[pos] = cut; sepastore->efficacies[pos] = cutefficacy; sepastore->objparallelisms[pos] = cutobjparallelism; sepastore->orthogonalities[pos] = 1.0; sepastore->scores[pos] = cutscore; sepastore->ncuts++; /* check, if the row addition to separation storage events are tracked * if so, issue ROWADDEDSEPA event */ if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWADDEDSEPA) != 0 ) { SCIP_EVENT* event; SCIP_CALL( SCIPeventCreateRowAddedSepa(&event, blkmem, cut) ); SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) ); } return SCIP_OKAY; }
/* Read SAT formula in "CNF File Format". * * The specification is taken from the * * Satisfiability Suggested Format * * Online available at http://www.intellektik.informatik.tu-darmstadt.de/SATLIB/Benchmarks/SAT/satformat.ps * * The method reads all files of CNF format. Other formats (SAT, SATX, SATE) are not supported. */ static SCIP_RETCODE readCnf( SCIP* scip, /**< SCIP data structure */ SCIP_FILE* file /**< input file */ ) { SCIP_RETCODE retcode; SCIP_VAR** vars; SCIP_VAR** clausevars; SCIP_CONS* cons; int* varsign; char* tok; char* nexttok; char line[MAXLINELEN]; char format[SCIP_MAXSTRLEN]; char varname[SCIP_MAXSTRLEN]; char s[SCIP_MAXSTRLEN]; SCIP_Bool initialconss; SCIP_Bool dynamicconss; SCIP_Bool dynamiccols; SCIP_Bool dynamicrows; SCIP_Bool useobj; int linecount; int clauselen; int clausenum; int nvars; int nclauses; int varnum; int v; assert(scip != NULL); assert(file != NULL); retcode = SCIP_OKAY; linecount = 0; /* read header */ SCIP_CALL( readCnfLine(scip, file, line, (int) sizeof(line), &linecount) ); if( *line != 'p' ) { readError(scip, linecount, "problem declaration line expected"); return SCIP_READERROR; } if( sscanf(line, "p %8s %d %d", format, &nvars, &nclauses) != 3 ) { readError(scip, linecount, "invalid problem declaration (must be 'p cnf <nvars> <nclauses>')"); return SCIP_READERROR; } if( strcmp(format, "cnf") != 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid format tag <%s> (must be 'cnf')", format); readError(scip, linecount, s); return SCIP_READERROR; } if( nvars <= 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid number of variables <%d> (must be positive)", nvars); readError(scip, linecount, s); return SCIP_READERROR; } if( nclauses <= 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid number of clauses <%d> (must be positive)", nclauses); readError(scip, linecount, s); return SCIP_READERROR; } /* get parameter values */ SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &initialconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &dynamicconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &dynamicrows) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/useobj", &useobj) ); /* get temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &clausevars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) ); /* create the variables */ for( v = 0; v < nvars; ++v ) { (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "x%d", v+1); SCIP_CALL( SCIPcreateVar(scip, &vars[v], varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, vars[v]) ); varsign[v] = 0; } /* read clauses */ clausenum = 0; clauselen = 0; do { retcode = readCnfLine(scip, file, line, (int) sizeof(line), &linecount); if( retcode != SCIP_OKAY ) goto TERMINATE; if( *line != '\0' && *line != '%' ) { tok = SCIPstrtok(line, " \f\n\r\t", &nexttok); while( tok != NULL ) { /* parse literal and check for errors */ if( sscanf(tok, "%d", &v) != 1 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid literal <%s>", tok); readError(scip, linecount, s); retcode = SCIP_READERROR; goto TERMINATE; } /* interpret literal number: v == 0: end of clause, v < 0: negated literal, v > 0: positive literal */ if( v == 0 ) { /* end of clause: construct clause and add it to SCIP */ if( clauselen == 0 ) readWarning(scip, linecount, "empty clause detected in line -- problem infeasible"); clausenum++; (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "c%d", clausenum); if( SCIPfindConshdlr(scip, "logicor") != NULL ) { /* if the constraint handler logicor exit create a logicor constraint */ SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, s, clauselen, clausevars, initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); } else if( SCIPfindConshdlr(scip, "setppc") != NULL ) { /* if the constraint handler logicor does not exit but constraint * handler setppc create a setppc constraint */ SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, s, clauselen, clausevars, initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); } else { /* if none of the previous constraint handler exits create a linear * constraint */ SCIP_Real* vals; int i; SCIP_CALL( SCIPallocBufferArray(scip, &vals, clauselen) ); for( i = 0; i < clauselen; ++i ) vals[i] = 1.0; SCIP_CALL( SCIPcreateConsLinear(scip, &cons, s, clauselen, clausevars, vals, 1.0, SCIPinfinity(scip), initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); SCIPfreeBufferArray(scip, &vals); } SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); clauselen = 0; } else if( v >= -nvars && v <= nvars ) { if( clauselen >= nvars ) { readError(scip, linecount, "too many literals in clause"); retcode = SCIP_READERROR; goto TERMINATE; } /* add literal to clause */ varnum = ABS(v)-1; if( v < 0 ) { SCIP_CALL( SCIPgetNegatedVar(scip, vars[varnum], &clausevars[clauselen]) ); varsign[varnum]--; } else { clausevars[clauselen] = vars[varnum]; varsign[varnum]++; } clauselen++; } else { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid variable number <%d>", ABS(v)); readError(scip, linecount, s); retcode = SCIP_READERROR; goto TERMINATE; } /* get next token */ tok = SCIPstrtok(NULL, " \f\n\r\t", &nexttok); } } } while( *line != '\0' && *line != '%' ); /* check for additional literals */ if( clauselen > 0 ) { SCIPwarningMessage(scip, "found %d additional literals after last clause\n", clauselen); } /* check number of clauses */ if( clausenum != nclauses ) { SCIPwarningMessage(scip, "expected %d clauses, but found %d\n", nclauses, clausenum); } TERMINATE: /* change objective values and release variables */ SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); for( v = 0; v < nvars; ++v ) { if( useobj ) { SCIP_CALL( SCIPchgVarObj(scip, vars[v], (SCIP_Real)varsign[v]) ); } SCIP_CALL( SCIPreleaseVar(scip, &vars[v]) ); } /* free temporary memory */ SCIPfreeBufferArray(scip, &varsign); SCIPfreeBufferArray(scip, &clausevars); SCIPfreeBufferArray(scip, &vars); return retcode; }
/** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */ static SCIP_RETCODE sepastoreApplyBdchg( SCIP_SEPASTORE* sepastore, /**< separation storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_ROW* cut, /**< cut with a single variable */ SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */ ) { SCIP_COL** cols; SCIP_Real* vals; SCIP_VAR* var; SCIP_Real lhs; SCIP_Real rhs; assert(sepastore != NULL); assert(!SCIProwIsModifiable(cut)); assert(SCIProwGetNNonz(cut) == 1); assert(cutoff != NULL); *cutoff = FALSE; /* get the single variable and its coefficient of the cut */ cols = SCIProwGetCols(cut); assert(cols != NULL); var = SCIPcolGetVar(cols[0]); vals = SCIProwGetVals(cut); assert(vals != NULL); assert(!SCIPsetIsZero(set, vals[0])); /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */ if( SCIPsetIsFeasZero(set, vals[0]) ) return SCIP_OKAY; /* get the left hand side of the cut and convert it to a bound */ lhs = SCIProwGetLhs(cut); if( !SCIPsetIsInfinity(set, -lhs) ) { lhs -= SCIProwGetConstant(cut); if( vals[0] > 0.0 ) { /* coefficient is positive -> lhs corresponds to lower bound */ SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, lhs/vals[0], cutoff) ); } else { /* coefficient is negative -> lhs corresponds to upper bound */ SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, lhs/vals[0], cutoff) ); } } /* get the right hand side of the cut and convert it to a bound */ rhs = SCIProwGetRhs(cut); if( !SCIPsetIsInfinity(set, rhs) ) { rhs -= SCIProwGetConstant(cut); if( vals[0] > 0.0 ) { /* coefficient is positive -> rhs corresponds to upper bound */ SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, rhs/vals[0], cutoff) ); } else { /* coefficient is negative -> rhs corresponds to lower bound */ SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, rhs/vals[0], cutoff) ); } } /* count the bound change as applied cut */ if( !sepastore->initiallp ) sepastore->ncutsapplied++; return SCIP_OKAY; }
/** creates the xyz propagator and includes it in SCIP */ SCIP_RETCODE SCIPincludePropXyz( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROPDATA* propdata; SCIP_PROP* prop; /* create xyz propagator data */ propdata = NULL; /* TODO: (optional) create propagator specific data here */ prop = NULL; /* include propagator */ #if 0 /* use SCIPincludeProp() if you want to set all callbacks explicitly and realize (by getting compiler errors) when * new callbacks are added in future SCIP versions */ SCIP_CALL( SCIPincludeProp(scip, PROP_NAME, PROP_DESC, PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING, PROP_PRESOL_PRIORITY, PROP_PRESOL_MAXROUNDS, PROP_PRESOL_DELAY, propCopyXyz, propFreeXyz, propInitXyz, propExitXyz, propInitpreXyz, propExitpreXyz, propInitsolXyz, propExitsolXyz, propPresolXyz, propExecXyz, propRespropXyz, propdata) ); #else /* use SCIPincludePropBasic() plus setter functions if you want to set callbacks one-by-one and your code should * compile independent of new callbacks being added in future SCIP versions */ SCIP_CALL( SCIPincludePropBasic(scip, &prop, PROP_NAME, PROP_DESC, PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING, propExecXyz, propdata) ); assert(prop != NULL); /* set optional callbacks via setter functions */ SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyXyz) ); SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeXyz) ); SCIP_CALL( SCIPsetPropInit(scip, prop, propInitXyz) ); SCIP_CALL( SCIPsetPropExit(scip, prop, propExitXyz) ); SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolXyz) ); SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolXyz) ); SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreXyz) ); SCIP_CALL( SCIPsetPropExitpre(scip, prop, propExitpreXyz) ); SCIP_CALL( SCIPsetPropPresol(scip, prop, propPresolXyz, PROP_PRESOL_PRIORITY, PROP_PRESOL_MAXROUNDS, PROP_PRESOL_DELAY) ); SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropXyz) ); #endif /* add xyz propagator parameters */ /* TODO: (optional) add propagator specific parameters with SCIPaddTypeParam() here */ return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecGuideddiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_SOL* bestsol; SCIP_VAR* var; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Real* lpcandsfrac; SCIP_Real searchubbound; SCIP_Real searchavgbound; SCIP_Real searchbound; SCIP_Real objval; SCIP_Real oldobjval; SCIP_Real obj; SCIP_Real objgain; SCIP_Real bestobjgain; SCIP_Real frac; SCIP_Real bestfrac; SCIP_Real solval; SCIP_Real bestsolval; SCIP_Bool bestcandmayrounddown; SCIP_Bool bestcandmayroundup; SCIP_Bool bestcandroundup; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Bool roundup; SCIP_Bool lperror; SCIP_Bool cutoff; SCIP_Bool backtracked; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int nlpcands; int startnlpcands; int depth; int maxdepth; int maxdivedepth; int divedepth; int bestcand; int c; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* do not call heuristic of node was already detected to be infeasible */ if( nodeinfeasible ) return SCIP_OKAY; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call heuristic, if the LP objective value is smaller than the cutoff bound */ if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) ) return SCIP_OKAY; /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* don't dive two times at the same node */ if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* don't dive, if no feasible solutions exist */ if( SCIPgetNSols(scip) == 0 ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */ depth = SCIPgetDepth(scip); maxdepth = SCIPgetMaxDepth(scip); maxdepth = MAX(maxdepth, 30); if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth ) return SCIP_OKAY; /* calculate the maximal number of LP iterations until heuristic is aborted */ nlpiterations = SCIPgetNNodeLPIterations(scip); ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess; maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations); maxnlpiterations += heurdata->maxlpiterofs; /* don't try to dive, if we took too many LP iterations during diving */ if( heurdata->nlpiterations >= maxnlpiterations ) return SCIP_OKAY; /* allow at least a certain number of LP iterations in this dive */ maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER); /* get fractional variables that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); /* don't try to dive, if there are no fractional variables */ if( nlpcands == 0 ) return SCIP_OKAY; /* calculate the objective search bound */ if( heurdata->maxdiveubquot > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquot > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); searchbound = MIN(searchubbound, searchavgbound); if( SCIPisObjIntegral(scip) ) searchbound = SCIPceil(scip, searchbound); /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */ maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); maxdivedepth = MIN(maxdivedepth, maxdepth); maxdivedepth *= 10; /* get best solution that should guide the search; if this solution lives in the original variable space, * we cannot use it since it might violate the global bounds of the current problem */ if( SCIPsolIsOriginal(SCIPgetBestSol(scip)) ) return SCIP_OKAY; /* store a copy of the best solution */ SCIP_CALL( SCIPcreateSolCopy(scip, &bestsol, SCIPgetBestSol(scip)) ); *result = SCIP_DIDNOTFIND; /* start diving */ SCIP_CALL( SCIPstartProbing(scip) ); /* enables collection of variable statistics during probing */ SCIPenableVarHistory(scip); /* get LP objective value */ lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; objval = SCIPgetLPObjval(scip); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing guideddiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound)); /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but * - if possible, we dive at least with the depth 10 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving */ lperror = FALSE; cutoff = FALSE; divedepth = 0; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; startnlpcands = nlpcands; while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound)) && !SCIPisStopped(scip) ) { SCIP_CALL( SCIPnewProbingNode(scip) ); divedepth++; /* choose variable fixing: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, round a variable to its value in direction of incumbent solution, and choose the * variable that is closest to its rounded value * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - round variable in direction that destroys LP feasibility (other direction is checked by SCIProundSol()) * - round variable with least increasing objective value */ bestcand = -1; bestobjgain = SCIPinfinity(scip); bestfrac = SCIP_INVALID; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); solval = lpcandssol[c]; frac = lpcandsfrac[c]; obj = SCIPvarGetObj(var); bestsolval = SCIPgetSolVal(scip, bestsol, var); /* select default rounding direction */ roundup = (solval < bestsolval); if( mayrounddown || mayroundup ) { /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */ if( bestcandmayrounddown || bestcandmayroundup ) { /* choose rounding direction: * - if variable may be rounded in both directions, round corresponding to its value in incumbent solution * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution with SCIProundSol() */ if( !mayrounddown || !mayroundup ) roundup = mayrounddown; if( roundup ) { frac = 1.0 - frac; objgain = frac*obj; } else objgain = -frac*obj; /* penalize too small fractions */ if( frac < 0.01 ) objgain *= 1000.0; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) objgain *= 1000.0; /* check, if candidate is new best candidate */ if( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) ) { bestcand = c; bestobjgain = objgain; bestfrac = frac; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded */ if( roundup ) frac = 1.0 - frac; /* penalize too small fractions */ if( frac < 0.01 ) frac += 10.0; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) frac *= 1000.0; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ if( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac ) { bestcand = c; bestfrac = frac; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; bestcandroundup = roundup; } } } assert(bestcand != -1); /* if all candidates are roundable, try to round the solution */ if( bestcandmayrounddown || bestcandmayroundup ) { SCIP_Bool success; /* create solution from diving LP and try to round it */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) ); if( success ) { SCIPdebugMessage("guideddiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } } var = lpcands[bestcand]; backtracked = FALSE; do { /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have * occured or variable was fixed by propagation while backtracking => Abort diving! */ if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 ) { SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]); cutoff = TRUE; break; } if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) ) { SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]); assert(backtracked); break; } /* apply rounding of best candidate */ if( bestcandroundup == !backtracked ) { /* round variable up */ SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, bestsol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetSolVal(scip, bestsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var)); SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) ); } else { /* round variable down */ SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, bestsol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetSolVal(scip, bestsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand])); SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) ); } /* apply domain propagation */ SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) ); if( !cutoff ) { /* resolve the diving LP */ /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ #ifdef NDEBUG SCIP_RETCODE retstat; nlpiterations = SCIPgetNLPIterations(scip); retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Guideddiving heuristic; LP solve terminated with code <%d>\n",retstat); } #else nlpiterations = SCIPgetNLPIterations(scip); SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) ); #endif if( lperror ) break; /* update iteration count */ heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations; /* get LP solution status, objective value, and fractional variables, that should be integral */ lpsolstat = SCIPgetLPSolstat(scip); assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE && (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip))))); } /* perform backtracking if a cutoff was detected */ if( cutoff && !backtracked && heurdata->backtrack ) { SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip)); SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) ); SCIP_CALL( SCIPnewProbingNode(scip) ); backtracked = TRUE; } else backtracked = FALSE; } while( backtracked ); if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { /* get new objective value */ oldobjval = objval; objval = SCIPgetLPObjval(scip); /* update pseudo cost values */ if( SCIPisGT(scip, objval, oldobjval) ) { if( bestcandroundup ) { SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand], objval - oldobjval, 1.0) ); } else { SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand], objval - oldobjval, 1.0) ); } } /* get new fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); } SCIPdebugMessage(" -> lpsolstat=%d, objval=%g, nfrac=%d\n", lpsolstat, objval, nlpcands); } /* check if a solution has been found */ if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* create solution from diving LP */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIPdebugMessage("guideddiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } /* end diving */ SCIP_CALL( SCIPendProbing(scip) ); /* free copied best solution */ SCIP_CALL( SCIPfreeSol(scip, &bestsol) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("guideddiving heuristic finished\n"); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecMutation) { /*lint --e{715}*/ SCIP_Longint maxnnodes; SCIP_Longint nsubnodes; /* node limit for the subproblem */ SCIP_HEURDATA* heurdata; /* heuristic's data */ SCIP* subscip; /* the subproblem created by mutation */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real maxnnodesr; SCIP_Real memorylimit; SCIP_Real timelimit; /* timelimit for the subproblem */ SCIP_Real upperbound; int nvars; /* number of original problem's variables */ int i; SCIP_Bool success; SCIP_RETCODE retcode; assert( heur != NULL ); assert( scip != NULL ); assert( result != NULL ); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); *result = SCIP_DELAYED; /* only call heuristic, if feasible solution is available */ if( SCIPgetNSols(scip) <= 0 ) return SCIP_OKAY; /* only call heuristic, if the best solution comes from transformed problem */ assert( SCIPgetBestSol(scip) != NULL ); if( SCIPsolIsOriginal(SCIPgetBestSol(scip)) ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip,SCIPgetBestSol(scip)) < heurdata->nwaitingnodes) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* only call heuristic, if discrete variables are present */ if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 ) return SCIP_OKAY; /* calculate the maximal number of branching nodes until heuristic is aborted */ maxnnodesr = heurdata->nodesquot * SCIPgetNNodes(scip); /* reward mutation if it succeeded often, count the setup costs for the sub-MIP as 100 nodes */ maxnnodesr *= 1.0 + 2.0 * (SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur) + 1.0); maxnnodes = (SCIP_Longint) maxnnodesr - 100 * SCIPheurGetNCalls(heur); maxnnodes += heurdata->nodesofs; /* determine the node limit for the current process */ nsubnodes = maxnnodes - heurdata->usednodes; nsubnodes = MIN(nsubnodes, heurdata->maxnodes); /* check whether we have enough nodes left to call subproblem solving */ if( nsubnodes < heurdata->minnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initializing the subproblem */ SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_mutationsub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_mutationsub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_Bool valid; valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "rens", TRUE, FALSE, TRUE, &valid) ); if( heurdata->copycuts ) { /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } SCIPdebugMessage("Copying the SCIP instance was %s complete.\n", valid ? "" : "not "); } for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); /* create a new problem, which fixes variables with same value in bestsol and LP relaxation */ SCIP_CALL( createSubproblem(scip, subscip, subvars, heurdata->minfixingrate, &heurdata->randseed, heurdata->uselprows, &success) ); /* terminate if it was not possible to create the subproblem */ if( !success ) { SCIPdebugMessage("Could not create the subproblem -> skip call\n"); goto TERMINATE; } /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) goto TERMINATE; /* disable statistic timing inside sub SCIP */ SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) ); /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nsubnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ if( !SCIPisParamFixed(subscip, "conflict/useprop") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useinflp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useboundlp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usesb") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usepseudo") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); } /* employ a limit on the number of enforcement rounds in the quadratic constraint handlers; this fixes the issue that * sometimes the quadratic constraint handler needs hundreds or thousands of enforcement rounds to determine the * feasibility status of a single node without fractional branching candidates by separation (namely for uflquad * instances); however, the solution status of the sub-SCIP might get corrupted by this; hence no decutions shall be * made for the original SCIP */ if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") ) { SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 10) ); } /* add an objective cutoff */ cutoff = SCIPinfinity(scip); assert( !SCIPisInfinity(scip, SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip, -1.0 * SCIPgetLowerbound(scip)) ) { cutoff = (1 - heurdata->minimprove) * SCIPgetUpperbound(scip) + heurdata->minimprove * SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound(scip) >= 0 ) cutoff = (1 - heurdata->minimprove) * SCIPgetUpperbound(scip); else cutoff = (1 + heurdata->minimprove) * SCIPgetUpperbound(scip); } cutoff = MIN(upperbound, cutoff); SCIP_CALL(SCIPsetObjlimit(subscip, cutoff)); /* solve the subproblem */ SCIPdebugMessage("Solve Mutation subMIP\n"); retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in Mutation heuristic; sub-SCIP terminated with code <%d>\n",retcode); } else { /* transfer variable statistics from sub-SCIP */ SCIP_CALL( SCIPmergeVariableStatistics(subscip, scip, subvars, vars, nvars) ); } heurdata->usednodes += SCIPgetNNodes(subscip); /* check, whether a solution was found */ if( SCIPgetNSols(subscip) > 0 ) { SCIP_SOL** subsols; int nsubsols; /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); } if( success ) *result = SCIP_FOUNDSOL; } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** call writing method */ static SCIP_RETCODE writeBoundsFocusNode( SCIP* scip, /**< SCIP data structure */ SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */ ) { FILE* file; SCIP_Bool writesubmipdualbound; SCIP_NODE* node; assert(scip != NULL); assert(eventhdlrdata != NULL); file = eventhdlrdata->file; writesubmipdualbound = eventhdlrdata->writesubmipdualbound; node = SCIPgetCurrentNode(scip); /* do not process probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return SCIP_OKAY; /* do not process cutoff nodes */ if( SCIPisInfinity(scip, SCIPgetNodeDualbound(scip, node)) ) return SCIP_OKAY; if( !SCIPisEQ(scip, eventhdlrdata->lastpb, SCIPgetPrimalbound(scip)) ) { #ifdef LONGSTATS SCIPinfoMessage(scip, file, "Status after %"SCIP_LONGINT_FORMAT" processed nodes (%d open)\n", SCIPgetNNodes(scip), SCIPgetNNodesLeft(scip)); SCIPinfoMessage(scip, file, "Primalbound: %g\n", SCIPgetPrimalbound(scip)); SCIPinfoMessage(scip, file, "Dualbound: %g\n", SCIPgetDualbound(scip)); #else SCIPinfoMessage(scip, file, "PB %g\n", SCIPgetPrimalbound(scip)); #endif eventhdlrdata->lastpb = SCIPgetPrimalbound(scip); } if( writesubmipdualbound ) { SCIP* subscip; SCIP_Bool valid; SCIP_Real submipdb; SCIP_Bool cutoff; SCIP_CALL( SCIPcreate(&subscip) ); submipdb = SCIP_INVALID; valid = FALSE; cutoff = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, NULL, NULL, "__boundwriting", FALSE, FALSE, TRUE, &valid) ); if( valid ) { /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* solve only root node */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) ); #if 0 /* disable heuristics in subscip */ SCIP_CALL( SCIPsetHeuristics(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); #endif /* set cutoffbound as objective limit for subscip */ SCIP_CALL( SCIPsetObjlimit(subscip, SCIPgetCutoffbound(scip)) ); SCIP_CALL( SCIPsolve(subscip) ); cutoff = (SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE); submipdb = SCIPgetDualbound(subscip) * SCIPgetTransObjscale(scip) + SCIPgetTransObjoffset(scip); } #ifdef LONGSTATS SCIPinfoMessage(scip, file, "Node %"SCIP_LONGINT_FORMAT" (depth %d): dualbound: %g, nodesubmiprootdualbound: %g %s\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node), submipdb, cutoff ? "(cutoff)" : ""); #else SCIPinfoMessage(scip, file, "%"SCIP_LONGINT_FORMAT" %d %g %g %s\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node), submipdb, cutoff ? "(cutoff)" : ""); #endif SCIP_CALL( SCIPfree(&subscip) ); } else { #ifdef LONGSTATS SCIPinfoMessage(scip, file, "Node %"SCIP_LONGINT_FORMAT" (depth %d): dualbound: %g\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node)); #else SCIPinfoMessage(scip, file, "%"SCIP_LONGINT_FORMAT" %d %g\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPgetNodeDualbound(scip, node)); #endif } #ifdef LONGSTATS SCIPinfoMessage(scip, file, "\n"); #endif return SCIP_OKAY; }
/** creates the mutation primal heuristic and includes it in SCIP */ SCIP_RETCODE SCIPincludeHeurMutation( SCIP* scip /**< SCIP data structure */ ) { SCIP_HEURDATA* heurdata; SCIP_HEUR* heur; /* create Mutation primal heuristic data */ SCIP_CALL( SCIPallocMemory(scip, &heurdata) ); /* include primal heuristic */ SCIP_CALL( SCIPincludeHeurBasic(scip, &heur, HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS, HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecMutation, heurdata) ); assert(heur != NULL); /* set non-NULL pointers to callback methods */ SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyMutation) ); SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeMutation) ); SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitMutation) ); /* add mutation primal heuristic parameters */ SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nodesofs", "number of nodes added to the contingent of the total nodes", &heurdata->nodesofs, FALSE, DEFAULT_NODESOFS, 0, INT_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxnodes", "maximum number of nodes to regard in the subproblem", &heurdata->maxnodes, TRUE, DEFAULT_MAXNODES, 0, INT_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/minnodes", "minimum number of nodes required to start the subproblem", &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0, INT_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/nwaitingnodes", "number of nodes without incumbent change that heuristic should wait", &heurdata->nwaitingnodes, TRUE, DEFAULT_NWAITINGNODES, 0, INT_MAX, NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquot", "contingent of sub problem nodes in relation to the number of nodes of the original problem", &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minfixingrate", "percentage of integer variables that have to be fixed", &heurdata->minfixingrate, FALSE, DEFAULT_MINFIXINGRATE, SCIPsumepsilon(scip), 1.0-SCIPsumepsilon(scip), NULL, NULL) ); SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minimprove", "factor by which " HEUR_NAME " should at least improve the incumbent", &heurdata->minimprove, TRUE, DEFAULT_MINIMPROVE, 0.0, 1.0, NULL, NULL) ); SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/uselprows", "should subproblem be created out of the rows in the LP rows?", &heurdata->uselprows, TRUE, DEFAULT_USELPROWS, NULL, NULL) ); SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/copycuts", "if uselprows == FALSE, should all active cuts from cutpool be copied to constraints in subproblem?", &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) ); return SCIP_OKAY; }
/** execution method of event handler */ static SCIP_DECL_EVENTEXEC(eventExecBoundwriting) { /*lint --e{715}*/ SCIP_EVENTHDLRDATA* eventhdlrdata; assert(scip != NULL); assert(eventhdlr != NULL); assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); assert(event != NULL); assert(((SCIPeventGetType(event) & SCIP_EVENTTYPE_NODESOLVED) == SCIP_EVENTTYPE_NODEFEASIBLE) || ((SCIPeventGetType(event) & SCIP_EVENTTYPE_NODESOLVED) == SCIP_EVENTTYPE_NODEINFEASIBLE) || ((SCIPeventGetType(event) & SCIP_EVENTTYPE_NODESOLVED) == SCIP_EVENTTYPE_NODEBRANCHED)); SCIPdebugMessage("exec method of event handler for writing primal- and dualbounds\n"); eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); assert(eventhdlrdata != NULL); #ifdef ONEFILE /* check if we need to open the file */ if( strlen(eventhdlrdata->filename) > 0 && !eventhdlrdata->isopen ) { assert(eventhdlrdata->file == NULL); assert(eventhdlrdata->oldfilename[0] == '\0'); eventhdlrdata->file = fopen(eventhdlrdata->filename, "w"); (void)strncpy(eventhdlrdata->oldfilename, eventhdlrdata->filename, SCIP_MAXSTRLEN); if( eventhdlrdata->file == NULL ) { SCIPerrorMessage("cannot create file <%s> for writing\n", eventhdlrdata->filename); SCIPprintSysError(eventhdlrdata->filename); return SCIP_FILECREATEERROR; } eventhdlrdata->isopen = TRUE; #ifdef LONGSTATS SCIPinfoMessage(scip, eventhdlrdata->file, "Problem: %s (%d Original Constraints, %d Original Variables)\n", SCIPgetProbName(scip), SCIPgetNOrigConss(scip), SCIPgetNOrigVars(scip) ); SCIPinfoMessage(scip, eventhdlrdata->file, "\t (%d Presolved Constraints, %d Presolved Variables, (%d binary, %d integer, %d implicit integer, %d continuous))\n", SCIPgetNConss(scip), SCIPgetNVars(scip), SCIPgetNBinVars(scip), SCIPgetNIntVars(scip), SCIPgetNImplVars(scip), SCIPgetNContVars(scip)); SCIPinfoMessage(scip, eventhdlrdata->file, "\n"); #endif } #endif /* call writing only at right moment */ if( eventhdlrdata->freq == 0 || (SCIPgetNNodes(scip) % eventhdlrdata->freq) != 0 ) return SCIP_OKAY; #ifndef ONEFILE if( strlen(eventhdlrdata->filename) > 0 ) { char name[SCIP_MAXSTRLEN]; char number[SCIP_MAXSTRLEN]; char* pch; int n; assert(eventhdlrdata->file == NULL); assert(!eventhdlrdata->isopen); if( eventhdlrdata->oldfilename[0] == '\0' ) (void)strncpy(eventhdlrdata->oldfilename, eventhdlrdata->filename, SCIP_MAXSTRLEN); /* find last '.' to append filenumber */ pch=strrchr(eventhdlrdata->filename,'.'); assert(eventhdlrdata->filenumber > 0); n=sprintf(number, "%"SCIP_LONGINT_FORMAT"", eventhdlrdata->filenumber * eventhdlrdata->freq); assert(n > 0); assert(n < SCIP_MAXSTRLEN); /* if no point is found, extend directly */ if( pch == NULL ) { (void)strncpy(name, eventhdlrdata->filename, (unsigned int)(SCIP_MAXSTRLEN - n)); strncat(name, number, (unsigned int)n); } else { int len; if( (pch-(eventhdlrdata->filename)) > (SCIP_MAXSTRLEN - n) ) /*lint !e776*/ len = SCIP_MAXSTRLEN - n; else len = (int) (pch-(eventhdlrdata->filename)); (void)strncpy(name, eventhdlrdata->filename, (unsigned int)len); name[len] = '\0'; strncat(name, number, (unsigned int)n); assert(len+n < SCIP_MAXSTRLEN); name[len+n] = '\0'; if( len + n + strlen(&(eventhdlrdata->filename[len])) < SCIP_MAXSTRLEN ) /*lint !e776*/ { strncat(name, &(eventhdlrdata->filename[len]), strlen(&(eventhdlrdata->filename[len]))); name[strlen(eventhdlrdata->filename)+n] = '\0'; } } eventhdlrdata->file = fopen(name, "w"); if( eventhdlrdata->file == NULL ) { SCIPerrorMessage("cannot create file <%s> for writing\n", eventhdlrdata->filename); SCIPprintSysError(eventhdlrdata->filename); return SCIP_FILECREATEERROR; } eventhdlrdata->isopen = TRUE; #ifdef LONGSTATS SCIPinfoMessage(scip, eventhdlrdata->file, "Problem: %s (%d Original Constraints, %d Original Variables)\n", SCIPgetProbName(scip), SCIPgetNOrigConss(scip), SCIPgetNOrigVars(scip) ); SCIPinfoMessage(scip, eventhdlrdata->file, "\t (%d Active Constraints, %d Active Variables, (%d binary, %d integer, %d implicit integer, %d continuous))\n", SCIPgetNConss(scip), SCIPgetNVars(scip), SCIPgetNBinVars(scip), SCIPgetNIntVars(scip), SCIPgetNImplVars(scip), SCIPgetNContVars(scip)); SCIPinfoMessage(scip, eventhdlrdata->file, "\n"); #endif } #endif #ifndef NDEBUG /* check the filename did not change during the solving */ if( strlen(eventhdlrdata->filename) > 0 && eventhdlrdata->isopen ) { char tmp[SCIP_MAXSTRLEN]; (void)strncpy(tmp, eventhdlrdata->filename, SCIP_MAXSTRLEN); /* the name should stay the same */ assert(strcmp(tmp, eventhdlrdata->oldfilename) == 0); } #endif #ifdef FOCUSNODE /* call writing method */ SCIP_CALL( writeBoundsFocusNode(scip, eventhdlrdata) ); #else /* call writing method */ SCIP_CALL( writeBounds(scip, eventhdlrdata->file, eventhdlrdata->writesubmipdualbound) ); #endif #ifndef ONEFILE if( strlen(eventhdlrdata->filename) > 0 ) { assert(eventhdlrdata->isopen); (void) fclose(eventhdlrdata->file); eventhdlrdata->isopen = FALSE; eventhdlrdata->file = NULL; ++(eventhdlrdata->filenumber); } #endif return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ unsigned int* randseed, /**< a seed value for the random number generator */ SCIP_Bool uselprows, /**< should subproblem be created out of the rows in the LP rows? */ SCIP_Bool* success /**< used to store whether the creation of the subproblem worked */ ) { SCIP_VAR** vars; /* original scip variables */ SCIP_SOL* sol; /* pool of solutions */ SCIP_Bool* marked; /* array of markers, which variables to fixed */ SCIP_Bool fixingmarker; /* which flag should label a fixed variable? */ int nvars; int nbinvars; int nintvars; int i; int j; int nmarkers; int maxiters; *success = TRUE; /* get required data of the original problem */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); sol = SCIPgetBestSol(scip); assert(sol != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &marked, nbinvars+nintvars) ); if( minfixingrate > 0.5 ) { nmarkers = nbinvars + nintvars - (int) SCIPfloor(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = FALSE; } else { nmarkers = (int) SCIPceil(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = TRUE; } assert( 0 <= nmarkers && nmarkers <= SCIPceil(scip,(nbinvars+nintvars)/2.0 ) ); j = 0; BMSclearMemoryArray(marked, nbinvars+nintvars); /* leave the loop after at most that many iterations * @todo change this method to a single random permutation, which is guaranteed to succeed, and maybe even faster */ maxiters = 3 * (nbinvars + nintvars); while( j < nmarkers && maxiters > 0 ) { do { i = SCIPgetRandomInt(0, nbinvars+nintvars-1, randseed); --maxiters; } while( marked[i] && maxiters > 0 ); j = marked[i] ? j : j+1; marked[i] = TRUE; } /* abort if it was not possible to fix enough variables */ if( j < nmarkers ) { *success = FALSE; assert(maxiters == 0); goto TERMINATE; } assert( j == nmarkers ); /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { /* fix all randomly marked variables */ if( marked[i] == fixingmarker ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, sol, vars[i]); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); assert(SCIPisLE(scip, lb, ub)); /* due to dual reductions, it may happen that the solution value is not in the variable's domain anymore */ if( SCIPisLT(scip, solval, lb) ) solval = lb; else if( SCIPisGT(scip, solval, ub) ) solval = ub; /* perform the bound change */ if( !SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval) ) { SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) ); } } } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } } TERMINATE: SCIPfreeBufferArray(scip, &marked); return SCIP_OKAY; }
/** creates the objective value inequality and the objective value variable, if not yet existing */ static SCIP_RETCODE createObjRow( SCIP* scip, /**< SCIP data structure */ SCIP_SEPA* sepa, /**< separator */ SCIP_SEPADATA* sepadata /**< separator data */ ) { assert(sepadata != NULL); if( sepadata->objrow == NULL ) { SCIP_VAR** vars; SCIP_Real obj; SCIP_Real intobjval; int nvars; int v; SCIP_Bool attendobjvarbound; attendobjvarbound = FALSE; /* create and add objective value variable */ if( sepadata->objvar == NULL ) { SCIP_CALL( SCIPcreateVar(scip, &sepadata->objvar, "objvar", -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_IMPLINT, FALSE, TRUE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, sepadata->objvar) ); SCIP_CALL( SCIPaddVarLocks(scip, sepadata->objvar, +1, +1) ); } else attendobjvarbound = TRUE; /* get problem variables */ vars = SCIPgetOrigVars(scip); nvars = SCIPgetNOrigVars(scip); /* create objective value inequality */ if( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ) { if( attendobjvarbound ) intobjval = SCIPceil(scip, SCIPgetDualbound(scip)) - SCIPvarGetLbGlobal(sepadata->objvar); else intobjval = SCIPceil(scip, SCIPgetDualbound(scip)); SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &sepadata->objrow, sepa, "objrow", intobjval, SCIPinfinity(scip), FALSE, !SCIPallVarsInProb(scip), TRUE) ); sepadata->setoff = intobjval; } else { if( attendobjvarbound ) intobjval = SCIPceil(scip, SCIPgetDualbound(scip)) - SCIPvarGetUbGlobal(sepadata->objvar); else intobjval = SCIPfloor(scip, SCIPgetDualbound(scip)); SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &sepadata->objrow, sepa, "objrow", -SCIPinfinity(scip), intobjval, FALSE, !SCIPallVarsInProb(scip), TRUE) ); sepadata->setoff = intobjval; } SCIP_CALL( SCIPcacheRowExtensions(scip, sepadata->objrow) ); for( v = 0; v < nvars; ++v ) { obj = SCIPvarGetObj(vars[v]); if( !SCIPisZero(scip, obj) ) { SCIP_CALL( SCIPaddVarToRow(scip, sepadata->objrow, vars[v], obj) ); } } SCIP_CALL( SCIPaddVarToRow(scip, sepadata->objrow, sepadata->objvar, -1.0) ); SCIP_CALL( SCIPflushRowExtensions(scip, sepadata->objrow) ); SCIPdebugMessage("created objective value row: "); SCIPdebug( SCIP_CALL( SCIPprintRow(scip, sepadata->objrow, NULL) ) ); } return SCIP_OKAY; }
/** evaluates command line parameters and runs GCG appropriately in the given SCIP instance */ static SCIP_RETCODE SCIPprocessGCGShellArguments( SCIP* scip, /**< SCIP data structure */ int argc, /**< number of shell parameters */ char** argv, /**< array with shell parameters */ const char* defaultsetname /**< name of default settings file */ ) { /*lint --e{850}*/ char* probname = NULL; char* decname = NULL; char* settingsname = NULL; char* mastersetname = NULL; char* logname = NULL; SCIP_Bool quiet; SCIP_Bool paramerror; SCIP_Bool interactive; int i; /******************** * Parse parameters * ********************/ quiet = FALSE; paramerror = FALSE; interactive = FALSE; for( i = 1; i < argc; ++i ) { if( strcmp(argv[i], "-l") == 0 ) { i++; if( i < argc ) logname = argv[i]; else { SCIPinfoMessage(scip, NULL, "missing log filename after parameter '-l'\n"); paramerror = TRUE; } } else if( strcmp(argv[i], "-q") == 0 ) quiet = TRUE; else if( strcmp(argv[i], "-s") == 0 ) { i++; if( i < argc ) settingsname = argv[i]; else { SCIPinfoMessage(scip, NULL, "missing settings filename after parameter '-s'\n"); paramerror = TRUE; } } else if( strcmp(argv[i], "-m") == 0 ) { i++; if( i < argc ) mastersetname = argv[i]; else { SCIPinfoMessage(scip, NULL, "missing master settings filename after parameter '-m'\n"); paramerror = TRUE; } } else if( strcmp(argv[i], "-f") == 0 ) { i++; if( i < argc ) probname = argv[i]; else { SCIPinfoMessage(scip, NULL, "missing problem filename after parameter '-f'\n"); paramerror = TRUE; } } else if( strcmp(argv[i], "-d") == 0 ) { i++; if( i < argc ) decname = argv[i]; else { SCIPinfoMessage(scip, NULL, "missing decomposition filename after parameter '-d'\n"); paramerror = TRUE; } } else if( strcmp(argv[i], "-c") == 0 ) { i++; if( i < argc ) { SCIP_CALL( SCIPaddDialogInputLine(scip, argv[i]) ); interactive = TRUE; } else { SCIPinfoMessage(scip, NULL, "missing command line after parameter '-c'\n"); paramerror = TRUE; } } else if( strcmp(argv[i], "-b") == 0 ) { i++; if( i < argc ) { SCIP_FILE* file; file = SCIPfopen(argv[i], "r"); if( file == NULL ) { SCIPinfoMessage(scip, NULL, "cannot read command batch file <%s>\n", argv[i]); SCIPprintSysError(argv[i]); paramerror = TRUE; } else { while( !SCIPfeof(file) ) { char buffer[SCIP_MAXSTRLEN]; (void)SCIPfgets(buffer, sizeof(buffer), file); if( buffer[0] != '\0' ) { SCIP_CALL( SCIPaddDialogInputLine(scip, buffer) ); } } SCIPfclose(file); interactive = TRUE; } } else { SCIPinfoMessage(scip, NULL, "missing command batch filename after parameter '-b'\n"); paramerror = TRUE; } } else { SCIPinfoMessage(scip, NULL, "invalid parameter <%s>\n", argv[i]); paramerror = TRUE; } } if( interactive && probname != NULL ) { SCIPinfoMessage(scip, NULL, "cannot mix batch mode '-c' and '-b' with file mode '-f'\n"); paramerror = TRUE; } if( probname == NULL && decname != NULL ) { SCIPinfoMessage(scip, NULL, "cannot read decomposition file without given problem\n"); paramerror = TRUE; } if( !paramerror ) { /*********************************** * create log file message handler * ***********************************/ if( quiet ) { SCIPsetMessagehdlrQuiet(scip, quiet); } if( logname != NULL ) { SCIPsetMessagehdlrLogfile(scip, logname); } /*********************************** * Version and library information * ***********************************/ SCIPprintVersion(scip, NULL); SCIPinfoMessage(scip, NULL, "\n"); SCIPprintExternalCodes(scip, NULL); SCIPinfoMessage(scip, NULL, "\n"); /***************** * Load settings * *****************/ if( settingsname != NULL ) { SCIP_CALL( readParams(scip, settingsname) ); } else if( defaultsetname != NULL ) { SCIP_CALL( readParams(scip, defaultsetname) ); } if( mastersetname != NULL ) { SCIP_CALL( readParams(GCGrelaxGetMasterprob(scip), mastersetname) ); } /************** * Start SCIP * **************/ if( probname != NULL ) { SCIP_CALL( fromCommandLine(scip, probname, decname) ); } else { SCIPinfoMessage(scip, NULL, "\n"); SCIP_CALL( SCIPstartInteraction(scip) ); } } else { SCIPinfoMessage(scip, NULL, "\nsyntax: %s [-l <logfile>] [-q] [-s <settings>] [-f <problem>] [-m <mastersettings>] [-d <decomposition>] [-b <batchfile>] [-c \"command\"]\n" " -l <logfile> : copy output into log file\n" " -q : suppress screen messages\n" " -s <settings> : load parameter settings (.set) file\n" " -m <mastersettings> : load master parameter settings (.set) file\n" " -f <problem> : load and solve problem file\n" " -d <decomposition> : load decomposition file\n" " -b <batchfile> : load and execute dialog command batch file (can be used multiple times)\n" " -c \"command\" : execute single line of dialog commands (can be used multiple times)\n\n", argv[0]); } return SCIP_OKAY; }
/** creates a new node entry in the visualization output file */ SCIP_RETCODE SCIPvisualNewChild( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< new node, that was created */ ) { SCIP_VAR* branchvar; SCIP_BOUNDTYPE branchtype; SCIP_Real branchbound; SCIP_Real lowerbound; size_t parentnodenum; size_t nodenum; assert( visual != NULL ); assert( stat != NULL ); assert( node != NULL ); /* visualization is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return SCIP_OKAY; /* check whether output should be created */ if ( visual->vbcfile == NULL && visual->bakfile == NULL ) return SCIP_OKAY; /* insert mapping node -> nodenum into hash map */ if( stat->ncreatednodesrun >= (SCIP_Longint)INT_MAX ) { SCIPerrorMessage("too many nodes to store in the visualization file\n"); return SCIP_INVALIDDATA; } nodenum = (size_t)stat->ncreatednodesrun; assert(nodenum > 0); SCIP_CALL( SCIPhashmapInsert(visual->nodenum, node, (void*)nodenum) ); /* get nodenum of parent node from hash map */ parentnodenum = (node->parent != NULL ? (size_t)SCIPhashmapGetImage(visual->nodenum, node->parent) : 0); assert(node->parent == NULL || parentnodenum > 0); /* get branching information */ getBranchInfo(node, &branchvar, &branchtype, &branchbound); /* determine lower bound */ if ( set->visual_objextern ) lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node)); else lowerbound = SCIPnodeGetLowerbound(node); if ( visual->vbcfile != NULL ) { printTime(visual, stat, TRUE); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "N %d %d %d\n", (int)parentnodenum, (int)nodenum, SCIP_VBCCOLOR_UNSOLVED); printTime(visual, stat, TRUE); if( branchvar != NULL ) { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, lowerbound); } else { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), lowerbound); } } /* For BAK, not all available information is available here. Use SCIPvisualUpdateChild() instead */ return SCIP_OKAY; }
/** presolving execution method */ static SCIP_DECL_PRESOLEXEC(presolExecTrivial) { /*lint --e{715}*/ SCIP_VAR** vars; int nvars; int v; assert(result != NULL); *result = SCIP_DIDNOTFIND; /* get the problem variables */ vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); /* scan the variables for trivial bound reductions * (loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array) */ for( v = nvars-1; v >= 0; --v ) { SCIP_Real lb; SCIP_Real ub; SCIP_Bool infeasible; SCIP_Bool fixed; /* get variable's bounds */ lb = SCIPvarGetLbGlobal(vars[v]); ub = SCIPvarGetUbGlobal(vars[v]); /* is variable integral? */ if( SCIPvarGetType(vars[v]) != SCIP_VARTYPE_CONTINUOUS ) { SCIP_Real newlb; SCIP_Real newub; /* round fractional bounds on integer variables */ newlb = SCIPfeasCeil(scip, lb); newub = SCIPfeasFloor(scip, ub); /* check bounds on variable for infeasibility */ if( newlb > newub + 0.5 ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible: integral variable <%s> has bounds [%.17f,%.17f] rounded to [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub, newlb, newub); *result = SCIP_CUTOFF; return SCIP_OKAY; } /* fix variables with equal bounds */ if( newlb > newub - 0.5 ) { SCIPdebugMessage("fixing integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub, newlb, newub); SCIP_CALL( SCIPfixVar(scip, vars[v], newlb, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } assert(fixed); (*nfixedvars)++; } else { /* round fractional bounds */ if( !SCIPisFeasEQ(scip, lb, newlb) ) { SCIPdebugMessage("rounding lower bound of integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub, newlb, ub); SCIP_CALL( SCIPchgVarLb(scip, vars[v], newlb) ); (*nchgbds)++; } if( !SCIPisFeasEQ(scip, ub, newub) ) { SCIPdebugMessage("rounding upper bound of integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), newlb, ub, newlb, newub); SCIP_CALL( SCIPchgVarUb(scip, vars[v], newub) ); (*nchgbds)++; } } } else { /* check bounds on continuous variable for infeasibility */ if( SCIPisFeasGT(scip, lb, ub) ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible: continuous variable <%s> has bounds [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub); *result = SCIP_CUTOFF; return SCIP_OKAY; } /* fix variables with equal bounds */ if( SCIPisEQ(scip, lb, ub) ) { SCIP_Real fixval; #ifdef FIXSIMPLEVALUE fixval = SCIPselectSimpleValue(lb - 0.9 * SCIPepsilon(scip), ub + 0.9 * SCIPepsilon(scip), MAXDNOM); #else fixval = (lb + ub)/2; #endif SCIPdebugMessage("fixing continuous variable <%s>[%.17f,%.17f] to %.17f\n", SCIPvarGetName(vars[v]), lb, ub, fixval); SCIP_CALL( SCIPfixVar(scip, vars[v], fixval, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } assert(fixed); (*nfixedvars)++; } } } return SCIP_OKAY; }
/** includes default SCIP plugins into SCIP */ SCIP_RETCODE SCIPincludeDefaultPlugins( SCIP* scip /**< SCIP data structure */ ) { SCIP_NLPI* nlpi; SCIP_CALL( SCIPincludeConshdlrNonlinear(scip) ); /* nonlinear must be before linear, quadratic, abspower, and and due to constraint upgrading */ SCIP_CALL( SCIPincludeConshdlrQuadratic(scip) ); /* quadratic must be before linear due to constraint upgrading */ SCIP_CALL( SCIPincludeConshdlrLinear(scip) ); /* linear must be before its specializations due to constraint upgrading */ SCIP_CALL( SCIPincludeConshdlrAbspower(scip) ); /* absolute power needs to be after quadratic and nonlinear due to constraint upgrading */ SCIP_CALL( SCIPincludeConshdlrAnd(scip) ); SCIP_CALL( SCIPincludeConshdlrBivariate(scip) ); /* bivariate needs to be after quadratic and nonlinear due to constraint upgrading */ SCIP_CALL( SCIPincludeConshdlrBounddisjunction(scip) ); SCIP_CALL( SCIPincludeConshdlrConjunction(scip) ); SCIP_CALL( SCIPincludeConshdlrCountsols(scip) ); SCIP_CALL( SCIPincludeConshdlrCumulative(scip) ); SCIP_CALL( SCIPincludeConshdlrDisjunction(scip) ); SCIP_CALL( SCIPincludeConshdlrIndicator(scip) ); SCIP_CALL( SCIPincludeConshdlrIntegral(scip) ); SCIP_CALL( SCIPincludeConshdlrKnapsack(scip) ); SCIP_CALL( SCIPincludeConshdlrLinking(scip) ); SCIP_CALL( SCIPincludeConshdlrLogicor(scip) ); SCIP_CALL( SCIPincludeConshdlrOr(scip) ); SCIP_CALL( SCIPincludeConshdlrOrbitope(scip) ); SCIP_CALL( SCIPincludeConshdlrPseudoboolean(scip) ); SCIP_CALL( SCIPincludeConshdlrSetppc(scip) ); SCIP_CALL( SCIPincludeConshdlrSOC(scip) ); /* SOC needs to be after quadratic due to constraint upgrading */ SCIP_CALL( SCIPincludeConshdlrSOS1(scip) ); SCIP_CALL( SCIPincludeConshdlrSOS2(scip) ); SCIP_CALL( SCIPincludeConshdlrSuperindicator(scip) ); SCIP_CALL( SCIPincludeConshdlrVarbound(scip) ); SCIP_CALL( SCIPincludeConshdlrXor(scip) ); SCIP_CALL( SCIPincludeReaderBnd(scip) ); SCIP_CALL( SCIPincludeReaderCcg(scip) ); SCIP_CALL( SCIPincludeReaderCip(scip) ); SCIP_CALL( SCIPincludeReaderCnf(scip) ); SCIP_CALL( SCIPincludeReaderFix(scip) ); SCIP_CALL( SCIPincludeReaderFzn(scip) ); SCIP_CALL( SCIPincludeReaderGms(scip) ); SCIP_CALL( SCIPincludeReaderLp(scip) ); SCIP_CALL( SCIPincludeReaderMps(scip) ); SCIP_CALL( SCIPincludeReaderOpb(scip) ); SCIP_CALL( SCIPincludeReaderOsil(scip) ); SCIP_CALL( SCIPincludeReaderPip(scip) ); SCIP_CALL( SCIPincludeReaderPpm(scip) ); SCIP_CALL( SCIPincludeReaderPbm(scip) ); SCIP_CALL( SCIPincludeReaderRlp(scip) ); SCIP_CALL( SCIPincludeReaderSol(scip) ); SCIP_CALL( SCIPincludeReaderWbo(scip) ); SCIP_CALL( SCIPincludeReaderZpl(scip) ); SCIP_CALL( SCIPincludePresolBoundshift(scip) ); SCIP_CALL( SCIPincludePresolComponents(scip) ); SCIP_CALL( SCIPincludePresolConvertinttobin(scip) ); SCIP_CALL( SCIPincludePresolDomcol(scip) ); SCIP_CALL( SCIPincludePresolDualinfer(scip) ); SCIP_CALL( SCIPincludePresolGateextraction(scip) ); SCIP_CALL( SCIPincludePresolImplics(scip) ); SCIP_CALL( SCIPincludePresolInttobinary(scip) ); SCIP_CALL( SCIPincludePresolTrivial(scip) ); SCIP_CALL( SCIPincludeNodeselBfs(scip) ); SCIP_CALL( SCIPincludeNodeselBreadthfirst(scip) ); SCIP_CALL( SCIPincludeNodeselDfs(scip) ); SCIP_CALL( SCIPincludeNodeselEstimate(scip) ); SCIP_CALL( SCIPincludeNodeselHybridestim(scip) ); SCIP_CALL( SCIPincludeNodeselRestartdfs(scip) ); SCIP_CALL( SCIPincludeNodeselUct(scip) ); SCIP_CALL( SCIPincludeBranchruleAllfullstrong(scip) ); SCIP_CALL( SCIPincludeBranchruleCloud(scip) ); SCIP_CALL( SCIPincludeBranchruleFullstrong(scip) ); SCIP_CALL( SCIPincludeBranchruleInference(scip) ); SCIP_CALL( SCIPincludeBranchruleLeastinf(scip) ); SCIP_CALL( SCIPincludeBranchruleMostinf(scip) ); SCIP_CALL( SCIPincludeBranchrulePscost(scip) ); SCIP_CALL( SCIPincludeBranchruleRandom(scip) ); SCIP_CALL( SCIPincludeBranchruleRelpscost(scip) ); SCIP_CALL( SCIPincludeHeurActconsdiving(scip) ); SCIP_CALL( SCIPincludeHeurClique(scip) ); SCIP_CALL( SCIPincludeHeurCoefdiving(scip) ); SCIP_CALL( SCIPincludeHeurCrossover(scip) ); SCIP_CALL( SCIPincludeHeurDins(scip) ); SCIP_CALL( SCIPincludeHeurDualval(scip) ); SCIP_CALL( SCIPincludeHeurFeaspump(scip) ); SCIP_CALL( SCIPincludeHeurFixandinfer(scip) ); SCIP_CALL( SCIPincludeHeurFracdiving(scip) ); SCIP_CALL( SCIPincludeHeurGuideddiving(scip) ); SCIP_CALL( SCIPincludeHeurZeroobj(scip) ); SCIP_CALL( SCIPincludeHeurIntdiving(scip) ); SCIP_CALL( SCIPincludeHeurIntshifting(scip) ); SCIP_CALL( SCIPincludeHeurLinesearchdiving(scip) ); SCIP_CALL( SCIPincludeHeurLocalbranching(scip) ); SCIP_CALL( SCIPincludeHeurNlpdiving(scip) ); SCIP_CALL( SCIPincludeHeurMutation(scip) ); SCIP_CALL( SCIPincludeHeurObjpscostdiving(scip) ); SCIP_CALL( SCIPincludeHeurOctane(scip) ); SCIP_CALL( SCIPincludeHeurOneopt(scip) ); SCIP_CALL( SCIPincludeHeurProximity(scip) ); SCIP_CALL( SCIPincludeHeurPscostdiving(scip) ); SCIP_CALL( SCIPincludeHeurRandrounding(scip) ); SCIP_CALL( SCIPincludeHeurRens(scip) ); SCIP_CALL( SCIPincludeHeurRins(scip) ); SCIP_CALL( SCIPincludeHeurRootsoldiving(scip) ); SCIP_CALL( SCIPincludeHeurRounding(scip) ); SCIP_CALL( SCIPincludeHeurShiftandpropagate(scip) ); SCIP_CALL( SCIPincludeHeurShifting(scip) ); SCIP_CALL( SCIPincludeHeurSimplerounding(scip) ); SCIP_CALL( SCIPincludeHeurSubNlp(scip) ); SCIP_CALL( SCIPincludeHeurTrivial(scip) ); SCIP_CALL( SCIPincludeHeurTrySol(scip) ); SCIP_CALL( SCIPincludeHeurTwoopt(scip) ); SCIP_CALL( SCIPincludeHeurUndercover(scip) ); SCIP_CALL( SCIPincludeHeurVbounds(scip) ); SCIP_CALL( SCIPincludeHeurVeclendiving(scip) ); SCIP_CALL( SCIPincludeHeurZirounding(scip) ); SCIP_CALL( SCIPincludePropDualfix(scip) ); SCIP_CALL( SCIPincludePropGenvbounds(scip) ); SCIP_CALL( SCIPincludePropObbt(scip) ); SCIP_CALL( SCIPincludePropProbing(scip) ); SCIP_CALL( SCIPincludePropPseudoobj(scip) ); SCIP_CALL( SCIPincludePropRedcost(scip) ); SCIP_CALL( SCIPincludePropRootredcost(scip) ); SCIP_CALL( SCIPincludePropVbounds(scip) ); SCIP_CALL( SCIPincludeSepaCGMIP(scip) ); SCIP_CALL( SCIPincludeSepaClique(scip) ); SCIP_CALL( SCIPincludeSepaClosecuts(scip) ); SCIP_CALL( SCIPincludeSepaCmir(scip) ); SCIP_CALL( SCIPincludeSepaFlowcover(scip) ); SCIP_CALL( SCIPincludeSepaGomory(scip) ); SCIP_CALL( SCIPincludeSepaImpliedbounds(scip) ); SCIP_CALL( SCIPincludeSepaIntobj(scip) ); SCIP_CALL( SCIPincludeSepaMcf(scip) ); SCIP_CALL( SCIPincludeSepaOddcycle(scip) ); SCIP_CALL( SCIPincludeSepaRapidlearning(scip) ); SCIP_CALL( SCIPincludeSepaStrongcg(scip) ); SCIP_CALL( SCIPincludeSepaZerohalf(scip) ); SCIP_CALL( SCIPincludeDispDefault(scip) ); /* include NLPI's, if available */ SCIP_CALL( SCIPcreateNlpSolverIpopt(SCIPblkmem(scip), &nlpi) ); if( nlpi != NULL ) { SCIP_CALL( SCIPincludeNlpi(scip, nlpi) ); SCIP_CALL( SCIPincludeExternalCodeInformation(scip, SCIPgetSolverNameIpopt(), SCIPgetSolverDescIpopt()) ); } SCIP_CALL( SCIPdebugIncludeProp(scip) ); /*lint !e506 !e774*/ return SCIP_OKAY; }
/** starts SCIP */ static SCIP_RETCODE fromCommandLine( SCIP* scip, /**< SCIP data structure */ const char* filename /**< input file name */ ) { /******************** * Problem Creation * ********************/ std::cout << std::endl << "read problem <" << filename << ">" << std::endl; std::cout << "============" << std::endl << std::endl; SCIP_CALL( SCIPreadProb(scip, filename, NULL) ); /******************* * Problem Solving * *******************/ /* solve problem */ std::cout << "solve problem" << std::endl; std::cout << "=============" << std::endl; SCIP_CALL( SCIPsolve(scip) ); std::cout << std::endl << "primal solution:" << std::endl; std::cout << "================" << std::endl << std::endl; SCIP_CALL( SCIPprintBestSol(scip, NULL, FALSE) ); /************** * Statistics * **************/ //std::cout << std::endl << "Statistics" << std::endl; //std::cout << "==========" << std::endl << std::endl; //SCIP_CALL( SCIPprintStatistics(scip, NULL) ); std::cout << "==========" << std::endl << std::endl; /* double OBJVAL; int items=SCIPgetNVars(scip); double *x; x = new double[items]; SCIP_CALL(complementarity_knapsack(scip,x,&OBJVAL)); SCIP_VAR** vars=SCIPgetVars(scip); cout << "Solution vector: " << endl; for(int j=0;j<items;j++) { cout << SCIPvarGetName(vars[j]) << "\t" << x[j] << endl; } cout << endl; cout << "Objective value = "<< OBJVAL << endl; */ SCIP_CALL(complementarity_knapsack(scip)); return SCIP_OKAY; }