/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecDistributiondiving) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_DIVESET* diveset; int nlprows; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); nlprows = SCIPgetNLPRows(scip); if( nlprows == 0 ) return SCIP_OKAY; /* terminate if there are no integer variables (note that, e.g., SOS1 variables may be present) */ if( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 ) return SCIP_OKAY; /* select and store the scoring parameter for this call of the heuristic */ if( heurdata->scoreparam == 'r' ) heurdata->score = SCOREPARAM_VALUES[SCIPheurGetNCalls(heur) % SCOREPARAM_VALUESLEN]; else heurdata->score = heurdata->scoreparam; SCIP_CALL( heurdataEnsureArraySize(scip, heurdata, nlprows) ); assert(SCIPheurGetNDivesets(heur) > 0); assert(SCIPheurGetDivesets(heur) != NULL); diveset = SCIPheurGetDivesets(heur)[0]; assert(diveset != NULL); SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible) ); SCIP_CALL( heurdataFreeArrays(scip, heurdata) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecGuideddiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_DIVESET* diveset; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* don't dive, if no feasible solutions exist */ if( SCIPgetNSols(scip) == 0 ) return SCIP_OKAY; /* 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; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* if there are no integer variables (note that, e.g., SOS1 variables may be present) */ if ( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 ) return SCIP_OKAY; assert(SCIPheurGetNDivesets(heur) > 0); assert(SCIPheurGetDivesets(heur) != NULL); diveset = SCIPheurGetDivesets(heur)[0]; assert(diveset != NULL); /* call generic diving algorithm */ SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecActconsdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_DIVESET* diveset; heurdata = SCIPheurGetData(heur); assert(SCIPheurGetNDivesets(heur) > 0); assert(SCIPheurGetDivesets(heur) != NULL); diveset = SCIPheurGetDivesets(heur)[0]; assert(diveset != NULL); *result = SCIP_DIDNOTRUN; /* if there are no integer variables, stop execution */ if( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 ) return SCIP_OKAY; SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecIntdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_VAR** pseudocands; SCIP_VAR** fixcands; SCIP_Real* fixcandscores; SCIP_Real searchubbound; SCIP_Real searchavgbound; SCIP_Real searchbound; SCIP_Real objval; SCIP_Bool lperror; SCIP_Bool cutoff; SCIP_Bool backtracked; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int nfixcands; int nbinfixcands; int depth; int maxdepth; int maxdivedepth; int divedepth; int nextcand; 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; /* 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, 100); 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 unfixed integer variables */ SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &nfixcands, NULL) ); /* don't try to dive, if there are no fractional variables */ if( nfixcands == 0 ) return SCIP_OKAY; /* calculate the objective search bound */ if( SCIPgetNSolsFound(scip) == 0 ) { if( heurdata->maxdiveubquotnosol > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquotnosol > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } else { 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; *result = SCIP_DIDNOTFIND; /* start diving */ SCIP_CALL( SCIPstartProbing(scip) ); /* enables collection of variable statistics during probing */ SCIPenableVarHistory(scip); SCIPdebugMessage("(node %" SCIP_LONGINT_FORMAT ") executing intdiving heuristic: depth=%d, %d non-fixed, dualbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nfixcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound)); /* copy the pseudo candidates into own array, because we want to reorder them */ SCIP_CALL( SCIPduplicateBufferArray(scip, &fixcands, pseudocands, nfixcands) ); /* sort non-fixed variables by non-increasing inference score, but prefer binaries over integers in any case */ SCIP_CALL( SCIPallocBufferArray(scip, &fixcandscores, nfixcands) ); nbinfixcands = 0; for( c = 0; c < nfixcands; ++c ) { SCIP_VAR* var; SCIP_Real score; int colveclen; int left; int right; int i; assert(c >= nbinfixcands); var = fixcands[c]; assert(SCIPvarIsIntegral(var)); colveclen = (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ? SCIPcolGetNNonz(SCIPvarGetCol(var)) : 0); if( SCIPvarIsBinary(var) ) { score = 500.0 * SCIPvarGetNCliques(var, TRUE) + 100.0 * SCIPvarGetNImpls(var, TRUE) + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/100.0; /* shift the non-binary variables one slot to the right */ for( i = c; i > nbinfixcands; --i ) { fixcands[i] = fixcands[i-1]; fixcandscores[i] = fixcandscores[i-1]; } /* put the new candidate into the first nbinfixcands slot */ left = 0; right = nbinfixcands; nbinfixcands++; } else { score = 5.0 * (SCIPvarGetNCliques(var, FALSE) + SCIPvarGetNCliques(var, TRUE)) + SCIPvarGetNImpls(var, FALSE) + SCIPvarGetNImpls(var, TRUE) + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/10000.0; /* put the new candidate in the slots after the binary candidates */ left = nbinfixcands; right = c; } for( i = right; i > left && score > fixcandscores[i-1]; --i ) { fixcands[i] = fixcands[i-1]; fixcandscores[i] = fixcandscores[i-1]; } fixcands[i] = var; fixcandscores[i] = score; SCIPdebugMessage(" <%s>: ncliques=%d/%d, nimpls=%d/%d, inferencescore=%g, colveclen=%d -> score=%g\n", SCIPvarGetName(var), SCIPvarGetNCliques(var, FALSE), SCIPvarGetNCliques(var, TRUE), SCIPvarGetNImpls(var, FALSE), SCIPvarGetNImpls(var, TRUE), SCIPgetVarAvgInferenceScore(scip, var), colveclen, score); } SCIPfreeBufferArray(scip, &fixcandscores); /* get LP objective value */ lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; objval = SCIPgetLPObjval(scip); /* dive as long we are in the given objective, depth and iteration limits, but if possible, we dive at least with * the depth 10 */ lperror = FALSE; cutoff = FALSE; divedepth = 0; nextcand = 0; while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && (divedepth < 10 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound)) && !SCIPisStopped(scip) ) { SCIP_VAR* var; SCIP_Real bestsolval; SCIP_Real bestfixval; int bestcand; SCIP_Longint nnewlpiterations; SCIP_Longint nnewdomreds; /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */ if( SCIPgetDepth(scip) < SCIPgetDepthLimit(scip) ) { SCIP_CALL( SCIPnewProbingNode(scip) ); divedepth++; } else break; nnewlpiterations = 0; nnewdomreds = 0; /* fix binary variable that is closest to 1 in the LP solution to 1; * if all binary variables are fixed, fix integer variable with least fractionality in LP solution */ bestcand = -1; bestsolval = -1.0; bestfixval = 1.0; /* look in the binary variables for fixing candidates */ for( c = nextcand; c < nbinfixcands; ++c ) { SCIP_Real solval; var = fixcands[c]; /* ignore already fixed variables */ if( var == NULL ) continue; if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 ) { fixcands[c] = NULL; continue; } /* get the LP solution value */ solval = SCIPvarGetLPSol(var); if( solval > bestsolval ) { bestcand = c; bestfixval = 1.0; bestsolval = solval; if( SCIPisGE(scip, bestsolval, 1.0) ) { /* we found an unfixed binary variable with LP solution value of 1.0 - there cannot be a better candidate */ break; } else if( SCIPisLE(scip, bestsolval, 0.0) ) { /* the variable is currently at 0.0 - this is the only situation where we want to fix it to 0.0 */ bestfixval = 0.0; } } } /* if all binary variables are fixed, look in the integer variables for a fixing candidate */ if( bestcand == -1 ) { SCIP_Real bestfrac; bestfrac = SCIP_INVALID; for( c = MAX(nextcand, nbinfixcands); c < nfixcands; ++c ) { SCIP_Real solval; SCIP_Real frac; var = fixcands[c]; /* ignore already fixed variables */ if( var == NULL ) continue; if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 ) { fixcands[c] = NULL; continue; } /* get the LP solution value */ solval = SCIPvarGetLPSol(var); frac = SCIPfrac(scip, solval); /* ignore integer variables that are currently integral */ if( SCIPisFeasFracIntegral(scip, frac) ) continue; if( frac < bestfrac ) { bestcand = c; bestsolval = solval; bestfrac = frac; bestfixval = SCIPfloor(scip, bestsolval + 0.5); if( SCIPisZero(scip, bestfrac) ) { /* we found an unfixed integer variable with integral LP solution value */ break; } } } } assert(-1 <= bestcand && bestcand < nfixcands); /* if there is no unfixed candidate left, we are done */ if( bestcand == -1 ) break; var = fixcands[bestcand]; assert(var != NULL); assert(SCIPvarIsIntegral(var)); assert(SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) > 0.5); assert(SCIPisGE(scip, bestfixval, SCIPvarGetLbLocal(var))); assert(SCIPisLE(scip, bestfixval, SCIPvarGetUbLocal(var))); 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], diving aborted \n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); cutoff = TRUE; break; } if( SCIPisFeasLT(scip, bestfixval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestfixval, 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), bestfixval); assert(backtracked); break; } /* apply fixing of best candidate */ SCIPdebugMessage(" dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", %d unfixed: var <%s>, sol=%g, oldbounds=[%g,%g], fixed to %g\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPgetNPseudoBranchCands(scip), SCIPvarGetName(var), bestsolval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval); SCIP_CALL( SCIPfixVarProbing(scip, var, bestfixval) ); /* apply domain propagation */ SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &nnewdomreds) ); if( !cutoff ) { /* if the best candidate was just fixed to its LP value and no domain reduction was found, the LP solution * stays valid, and the LP does not need to be resolved */ if( nnewdomreds > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) ) { /* 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 Intdiving 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 */ nnewlpiterations = SCIPgetNLPIterations(scip) - nlpiterations; heurdata->nlpiterations += nnewlpiterations; /* get LP solution status */ 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) ); /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */ assert(SCIPgetDepthLimit(scip) > SCIPgetDepth(scip)); SCIP_CALL( SCIPnewProbingNode(scip) ); bestfixval = SCIPvarIsBinary(var) ? 1.0 - bestfixval : (SCIPisGT(scip, bestsolval, bestfixval) && SCIPisFeasLE(scip, bestfixval + 1, SCIPvarGetUbLocal(var)) ? bestfixval + 1 : bestfixval - 1); backtracked = TRUE; } else backtracked = FALSE; } while( backtracked ); if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* get new objective value */ objval = SCIPgetLPObjval(scip); if( nnewlpiterations > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) ) { /* we must start again with the first candidate, since the LP solution changed */ nextcand = 0; /* 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("intdiving 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; } } } else nextcand = bestcand+1; /* continue with the next candidate in the following loop */ } SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g\n", lpsolstat, objval, searchbound); } /* free temporary memory */ SCIPfreeBufferArray(scip, &fixcands); /* end diving */ SCIP_CALL( SCIPendProbing(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("intdiving heuristic finished\n"); return SCIP_OKAY; }
/** presolving execution method */ static SCIP_DECL_PRESOLEXEC(presolExecBoundshift) { /*lint --e{715}*/ SCIP_PRESOLDATA* presoldata; SCIP_VAR** scipvars; SCIP_VAR** vars; int nbinvars; int nvars; int v; assert(scip != NULL); assert(presol != NULL); assert(strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0); assert(result != NULL); *result = SCIP_DIDNOTRUN; /* get presolver data */ presoldata = SCIPpresolGetData(presol); assert(presoldata != NULL); /* get the problem variables */ scipvars = SCIPgetVars(scip); nbinvars = SCIPgetNBinVars(scip); nvars = SCIPgetNVars(scip) - nbinvars; if( nvars == 0 ) return SCIP_OKAY; if( SCIPdoNotAggr(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* copy the integer variables into an own array, since adding new integer variables affects the left-most slots in * the array and thereby interferes with our search loop */ SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, &scipvars[nbinvars], nvars) ); /* scan the integer, implicit, and continuous variables for possible conversion */ for( v = nvars - 1; v >= 0; --v ) { SCIP_VAR* var = vars[v]; SCIP_Real lb; SCIP_Real ub; assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY); /* get current variable's bounds */ lb = SCIPvarGetLbGlobal(var); ub = SCIPvarGetUbGlobal(var); assert( SCIPisLE(scip, lb, ub) ); if( SCIPisEQ(scip, lb, ub) ) continue; if( presoldata->integer && !SCIPisIntegral(scip, ub - lb) ) continue; /* check if bounds are shiftable */ if( !SCIPisEQ(scip, lb, 0.0) && /* lower bound != 0.0 */ SCIPisLT(scip, ub, SCIPinfinity(scip)) && /* upper bound != infinity */ SCIPisGT(scip, lb, -SCIPinfinity(scip)) && /* lower bound != -infinity */ #if 0 SCIPisLT(scip, ub - lb, SCIPinfinity(scip)) && /* interval length less than SCIPinfinity(scip) */ #endif SCIPisLT(scip, ub - lb, (SCIP_Real) presoldata->maxshift) ) /* less than max shifting */ { SCIP_VAR* newvar; char newvarname[SCIP_MAXSTRLEN]; SCIP_Bool infeasible; SCIP_Bool redundant; SCIP_Bool aggregated; SCIPdebugMessage("convert range <%s>[%g,%g] to [%g,%g]\n", SCIPvarGetName(var), lb, ub, 0.0, (ub - lb) ); /* create new variable */ (void) SCIPsnprintf(newvarname, SCIP_MAXSTRLEN, "%s_shift", SCIPvarGetName(var)); SCIP_CALL( SCIPcreateVar(scip, &newvar, newvarname, 0.0, (ub - lb), 0.0, SCIPvarGetType(var), SCIPvarIsInitial(var), SCIPvarIsRemovable(var), NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, newvar) ); /* aggregate old variable with new variable */ if( presoldata->flipping ) { if( REALABS(ub) < REALABS(lb) ) { SCIP_CALL( SCIPaggregateVars(scip, var, newvar, 1.0, 1.0, ub, &infeasible, &redundant, &aggregated) ); } else { SCIP_CALL( SCIPaggregateVars(scip, var, newvar, 1.0, -1.0, lb, &infeasible, &redundant, &aggregated) ); } } else { SCIP_CALL( SCIPaggregateVars(scip, var, newvar, 1.0, -1.0, lb, &infeasible, &redundant, &aggregated) ); } assert(!infeasible); assert(redundant); assert(aggregated); SCIPdebugMessage("var <%s> with bounds [%f,%f] has obj %f\n", SCIPvarGetName(newvar),SCIPvarGetLbGlobal(newvar),SCIPvarGetUbGlobal(newvar),SCIPvarGetObj(newvar)); /* release variable */ SCIP_CALL( SCIPreleaseVar(scip, &newvar) ); /* take care of statistic */ (*naggrvars)++; *result = SCIP_SUCCESS; } } /* free temporary memory */ SCIPfreeBufferArray(scip, &vars); return SCIP_OKAY; }
/** reduced cost propagation method for an LP solution */ static SCIP_DECL_PROPEXEC(propExecRedcost) { /*lint --e{715}*/ SCIP_PROPDATA* propdata; SCIP_COL** cols; SCIP_Real requiredredcost; SCIP_Real cutoffbound; SCIP_Real lpobjval; SCIP_Bool propbinvars; SCIP_Bool cutoff; int nchgbds; int ncols; int c; *result = SCIP_DIDNOTRUN; /* in case we have a zero objective function, we skip the reduced cost propagator */ if( SCIPgetNObjVars(scip) == 0 ) return SCIP_OKAY; /* propagator can only be applied during solving stage */ if( SCIPgetStage(scip) < SCIP_STAGE_SOLVING ) return SCIP_OKAY; /* we cannot apply reduced cost fixing, if we want to solve exactly */ /**@todo implement reduced cost fixing with interval arithmetics */ if( SCIPisExactSolve(scip) ) return SCIP_OKAY; /* only call propagator, if the current node has an LP */ if( !SCIPhasCurrentNodeLP(scip) ) return SCIP_OKAY; /* only call propagator, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call propagator, if the current LP is a valid relaxation */ if( !SCIPisLPRelax(scip) ) return SCIP_OKAY; /* we cannot apply reduced cost strengthening, if no simplex basis is available */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* get current cutoff bound */ cutoffbound = SCIPgetCutoffbound(scip); /* reduced cost strengthening can only be applied, if we have a finite cutoff */ if( SCIPisInfinity(scip, cutoffbound) ) return SCIP_OKAY; /* get LP columns */ cols = SCIPgetLPCols(scip); ncols = SCIPgetNLPCols(scip); /* do nothing if the LP has no columns (is empty) */ if( ncols == 0 ) return SCIP_OKAY; /* get propagator data */ propdata = SCIPpropGetData(prop); assert(propdata != NULL); /* chack if all integral variables are fixed and the continuous variables should not be propagated */ if( !propdata->continuous && SCIPgetNPseudoBranchCands(scip) == 0 ) return SCIP_OKAY; /* get LP objective value */ lpobjval = SCIPgetLPObjval(scip); /* check if binary variables should be propagated */ propbinvars = (SCIPgetDepth(scip) == 0) || (cutoffbound - lpobjval < 5 * propdata->maxredcost); /* skip the propagator if the problem has only binary variables and those should not be propagated */ if( !propbinvars && SCIPgetNVars(scip) == SCIPgetNBinVars(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; cutoff = FALSE; nchgbds = 0; /* compute the required reduced cost which are needed for a binary variable to be fixed */ requiredredcost = cutoffbound - lpobjval; SCIPdebugMessage("lpobjval <%g>, cutoffbound <%g>, max reduced <%g>, propgate binary %u, use implics %u\n", lpobjval, cutoffbound, propdata->maxredcost, propbinvars, propdata->usefullimplics); /* check reduced costs for non-basic columns */ for( c = 0; c < ncols && !cutoff; ++c ) { SCIP_VAR* var; var = SCIPcolGetVar(cols[c]); /* skip continuous variables in case the corresponding parameter is set */ if( !propdata->continuous && !SCIPvarIsIntegral(var) ) continue; if( SCIPvarIsBinary(var) ) { if( propbinvars ) { if( SCIPgetDepth(scip) == 0 ) { SCIP_CALL( propagateRootRedcostBinvar(scip, propdata, var, cols[c], cutoffbound, &nchgbds) ); } else { SCIP_CALL( propagateRedcostBinvar(scip, propdata, var, cols[c], requiredredcost, &nchgbds, &cutoff) ); } } } else { SCIP_CALL( propagateRedcostVar(scip, var, cols[c], lpobjval, cutoffbound, &nchgbds) ); } } if( cutoff ) { *result = SCIP_CUTOFF; SCIPdebugMessage("node %"SCIP_LONGINT_FORMAT": detected cutoff\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); } else if( nchgbds > 0 ) { *result = SCIP_REDUCEDDOM; SCIPdebugMessage("node %"SCIP_LONGINT_FORMAT": %d bound changes (max redcost <%g>)\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) , nchgbds, propdata->maxredcost); } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecActconsdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; 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 frac; SCIP_Real bestfrac; 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; SCIP_Real actscore; SCIP_Real downscore; SCIP_Real upscore; SCIP_Real bestactscore; 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; /* 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( SCIPgetNSolsFound(scip) == 0 ) { if( heurdata->maxdiveubquotnosol > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquotnosol > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } else { 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; *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 actconsdiving heuristic: depth=%d, %d fractionals, dualbound=%g, avgbound=%g, cutoffbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPgetAvgDualbound(scip), SCIPretransformObj(scip, SCIPgetCutoffbound(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) ) { divedepth++; SCIP_CALL( SCIPnewProbingNode(scip) ); /* choose variable fixing: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, round variable with least number of locks in corresponding direction * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - round variable with least number of locks in opposite of its feasible rounding direction */ bestcand = -1; bestactscore = -1.0; bestfrac = SCIP_INVALID; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); frac = lpcandsfrac[c]; 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 the fractionality * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution */ if( mayrounddown && mayroundup ) roundup = (frac > 0.5); else roundup = mayrounddown; if( roundup ) frac = 1.0 - frac; actscore = getNActiveConsScore(scip, var, &downscore, &upscore); /* penalize too small fractions */ if( frac < 0.01 ) actscore *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) actscore *= 0.01; /* check, if candidate is new best candidate */ assert(0.0 < frac && frac < 1.0); if( SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) ) { bestcand = c; bestactscore = actscore; bestfrac = frac; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded */ actscore = getNActiveConsScore(scip, var, &downscore, &upscore); roundup = (downscore < upscore); if( roundup ) frac = 1.0 - frac; /* penalize too small fractions */ if( frac < 0.01 ) actscore *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) actscore *= 0.01; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ assert(0.0 < frac && frac < 1.0); if( bestcandmayrounddown || bestcandmayroundup || SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) ) { bestcand = c; bestactscore = actscore; bestfrac = frac; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; bestcandroundup = roundup; } assert(bestfrac < SCIP_INVALID); } } 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("actconsdiving 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; } } } assert(bestcand != -1); 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, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], 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, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand])); SCIP_CALL( SCIPchgVarUbProbing(scip, lpcands[bestcand], 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 Actconsdiving 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/%g, nfrac=%d\n", lpsolstat, objval, searchbound, 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("actconsdiving 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) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") finished actconsdiving heuristic: %d fractionals, dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", objval=%g/%g, lpsolstat=%d, cutoff=%u\n", SCIPgetNNodes(scip), nlpcands, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPretransformObj(scip, objval), SCIPretransformObj(scip, searchbound), lpsolstat, cutoff); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecObjpscostdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_VAR* var; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Real* lpcandsfrac; SCIP_Real primsol; SCIP_Real frac; SCIP_Real pscostquot; SCIP_Real bestpscostquot; SCIP_Real oldobj; SCIP_Real newobj; SCIP_Real objscale; SCIP_Bool bestcandmayrounddown; SCIP_Bool bestcandmayroundup; SCIP_Bool bestcandroundup; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Bool roundup; SCIP_Bool lperror; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int* roundings; int nvars; int varidx; 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; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only apply heuristic, if only a few solutions have been found */ if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols ) return SCIP_OKAY; /* 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 maximal diving depth */ nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); if( SCIPgetNSolsFound(scip) == 0 ) maxdivedepth = (int)(heurdata->depthfacnosol * nvars); else maxdivedepth = (int)(heurdata->depthfac * nvars); maxdivedepth = MIN(maxdivedepth, 10*maxdepth); *result = SCIP_DIDNOTFIND; /* get temporary memory for remembering the current soft roundings */ SCIP_CALL( SCIPallocBufferArray(scip, &roundings, nvars) ); BMSclearMemoryArray(roundings, nvars); /* start diving */ SCIP_CALL( SCIPstartDive(scip) ); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing objpscostdiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%"SCIP_LONGINT_FORMAT", maxdivedepth=%d\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth); /* dive as long we are in the given diving depth and iteration limits and fractional variables exist, but * - if the last objective change was in a direction, that corresponds to a feasible rounding, we continue in any case * - 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; lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; divedepth = 0; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; startnlpcands = nlpcands; while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && nlpcands <= startnlpcands - divedepth/10 && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) ) { SCIP_RETCODE retcode; divedepth++; /* choose variable for objective change: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, change objective value of variable with largest rel. difference of pseudo cost values * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - change objective value of variable with largest rel. difference of pseudo cost values */ bestcand = -1; bestpscostquot = -1.0; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); primsol = lpcandssol[c]; frac = lpcandsfrac[c]; 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 the pseudo cost values * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution */ roundup = FALSE; if( mayrounddown && mayroundup ) calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup); else if( mayrounddown ) calcPscostQuot(scip, var, primsol, frac, +1, &pscostquot, &roundup); else calcPscostQuot(scip, var, primsol, frac, -1, &pscostquot, &roundup); /* prefer variables, that have already been soft rounded but failed to get integral */ varidx = SCIPvarGetProbindex(var); assert(0 <= varidx && varidx < nvars); if( roundings[varidx] != 0 ) pscostquot *= 1000.0; /* check, if candidate is new best candidate */ if( pscostquot > bestpscostquot ) { bestcand = c; bestpscostquot = pscostquot; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */ calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup); /* prefer variables, that have already been soft rounded but failed to get integral */ varidx = SCIPvarGetProbindex(var); assert(0 <= varidx && varidx < nvars); if( roundings[varidx] != 0 ) pscostquot *= 1000.0; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot ) { bestcand = c; bestpscostquot = pscostquot; 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("objpscostdiving 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]; /* check, if the best candidate was already subject to soft rounding */ varidx = SCIPvarGetProbindex(var); assert(0 <= varidx && varidx < nvars); if( roundings[varidx] == +1 ) { /* variable was already soft rounded upwards: hard round it downwards */ SCIP_CALL( SCIPchgVarUbDive(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) ); SCIPdebugMessage(" dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded upwards -> bounds=[%g,%g]\n", divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var)); } else if( roundings[varidx] == -1 ) { /* variable was already soft rounded downwards: hard round it upwards */ SCIP_CALL( SCIPchgVarLbDive(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) ); SCIPdebugMessage(" dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded downwards -> bounds=[%g,%g]\n", divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var)); } else { assert(roundings[varidx] == 0); /* apply soft rounding of best candidate via a change in the objective value */ objscale = divedepth * 1000.0; oldobj = SCIPgetVarObjDive(scip, var); if( bestcandroundup ) { /* soft round variable up: make objective value (more) negative */ if( oldobj < 0.0 ) newobj = objscale * oldobj; else newobj = -objscale * oldobj; newobj = MIN(newobj, -objscale); /* remember, that this variable was soft rounded upwards */ roundings[varidx] = +1; } else { /* soft round variable down: make objective value (more) positive */ if( oldobj > 0.0 ) newobj = objscale * oldobj; else newobj = -objscale * oldobj; newobj = MAX(newobj, objscale); /* remember, that this variable was soft rounded downwards */ roundings[varidx] = -1; } SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) ); SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, bounds=[%g,%g], obj=%g, newobj=%g\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var), oldobj, newobj); } /* resolve the diving LP */ nlpiterations = SCIPgetNLPIterations(scip); retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL); lpsolstat = SCIPgetLPSolstat(scip); /* 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. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY ) { SCIP_CALL( retcode ); } #endif SCIPwarningMessage(scip, "Error while solving LP in Objpscostdiving heuristic; LP solve terminated with code <%d>\n", retcode); SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n"); } if( lperror ) break; /* update iteration count */ heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations; /* get LP solution status and fractional variables, that should be integral */ if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { /* get new fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); } SCIPdebugMessage(" -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands); } /* check if a solution has been found */ if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* create solution from diving LP */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIPdebugMessage("objpscostdiving 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( SCIPendDive(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; /* free temporary memory for remembering the current soft roundings */ SCIPfreeBufferArray(scip, &roundings); SCIPdebugMessage("objpscostdiving heuristic finished\n"); return SCIP_OKAY; }
/** execution method of presolver */ static SCIP_DECL_PRESOLEXEC(presolExecDualagg) { /*lint --e{715}*/ SCIPMILPMATRIX* matrix; SCIP_Bool initialized; SCIP_Bool complete; assert(result != NULL); *result = SCIP_DIDNOTRUN; if( (SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING) || SCIPinProbing(scip) || SCIPisNLPEnabled(scip) ) return SCIP_OKAY; if( SCIPisStopped(scip) || SCIPgetNActivePricers(scip) > 0 ) return SCIP_OKAY; if( SCIPgetNBinVars(scip) == 0 ) return SCIP_OKAY; if( !SCIPallowDualReds(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; matrix = NULL; SCIP_CALL( SCIPmatrixCreate(scip, &matrix, &initialized, &complete) ); /* we only work on pure MIPs currently */ if( initialized && complete ) { AGGRTYPE* aggtypes; SCIP_VAR** binvars; int nvaragg; int ncols; ncols = SCIPmatrixGetNColumns(matrix); nvaragg = 0; SCIP_CALL( SCIPallocBufferArray(scip, &aggtypes, ncols) ); BMSclearMemoryArray(aggtypes, ncols); SCIP_CALL( SCIPallocBufferArray(scip, &binvars, ncols) ); SCIPdebug( BMSclearMemoryArray(binvars, ncols) ); /* search for aggregations */ SCIP_CALL( findUplockAggregations(scip, matrix, &nvaragg, aggtypes, binvars) ); SCIP_CALL( findDownlockAggregations(scip, matrix, &nvaragg, aggtypes, binvars) ); /* apply aggregations, if we found any */ if( nvaragg > 0 ) { int v; for( v = 0; v < ncols; v++ ) { if( aggtypes[v] != NOAGG ) { SCIP_Bool infeasible; SCIP_Bool redundant; SCIP_Bool aggregated; SCIP_Real ub; SCIP_Real lb; ub = SCIPmatrixGetColUb(matrix, v); lb = SCIPmatrixGetColLb(matrix, v); /* aggregate variable */ assert(binvars[v] != NULL); if( aggtypes[v] == BIN0UBOUND ) { SCIP_CALL( SCIPaggregateVars(scip, SCIPmatrixGetVar(matrix, v), binvars[v], 1.0, ub-lb, ub, &infeasible, &redundant, &aggregated) ); } else { assert(aggtypes[v] == BIN0LBOUND); SCIP_CALL( SCIPaggregateVars(scip, SCIPmatrixGetVar(matrix, v), binvars[v], 1.0, lb-ub, lb, &infeasible, &redundant, &aggregated) ); } /* infeasible aggregation */ if( infeasible ) { SCIPdebugMessage(" -> infeasible aggregation\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } if( aggregated ) (*naggrvars)++; } } /* set result pointer */ if( (*naggrvars) > 0 ) *result = SCIP_SUCCESS; } SCIPfreeBufferArray(scip, &binvars); SCIPfreeBufferArray(scip, &aggtypes); } SCIPmatrixFree(scip, &matrix); 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; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecSimplerounding) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Longint nlps; int nlpcands; int c; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* on our first call or after each pricing round, calculate the number of roundable variables */ if( heurdata->nroundablevars == -1 || heurtiming == SCIP_HEURTIMING_DURINGPRICINGLOOP ) { SCIP_VAR** vars; int nvars; int nroundablevars; int i; vars = SCIPgetVars(scip); nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); nroundablevars = 0; for( i = 0; i < nvars; ++i ) { if( SCIPvarMayRoundDown(vars[i]) || SCIPvarMayRoundUp(vars[i]) ) nroundablevars++; } heurdata->nroundablevars = nroundablevars; } /* don't call heuristic if there are no roundable variables; except we are called during pricing, in this case we * want to detect a (mixed) integer (LP) solution which is primal feasible */ if( heurdata->nroundablevars == 0 && heurtiming != SCIP_HEURTIMING_DURINGPRICINGLOOP ) return SCIP_OKAY; /* don't call heuristic, if we have already processed the current LP solution */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* get fractional variables, that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL) ); /* only call heuristic, if LP solution is fractional; except we are called during pricing, in this case we * want to detect a (mixed) integer (LP) solution which is primal feasible */ if( nlpcands == 0 && heurtiming != SCIP_HEURTIMING_DURINGPRICINGLOOP ) return SCIP_OKAY; /* don't call heuristic, if there are more fractional variables than roundable ones */ if( nlpcands > heurdata->nroundablevars ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIPdebugMessage("executing simple rounding heuristic: %d fractionals\n", nlpcands); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* round all roundable fractional columns in the corresponding direction as long as no unroundable column was found */ for( c = 0; c < nlpcands; ++c ) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; oldsolval = lpcandssol[c]; assert(!SCIPisFeasIntegral(scip, oldsolval)); var = lpcands[c]; assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); SCIPdebugMessage("simple rounding heuristic: var <%s>, val=%g, rounddown=%u, roundup=%u\n", SCIPvarGetName(var), oldsolval, mayrounddown, mayroundup); /* choose rounding direction */ if( mayrounddown && mayroundup ) { /* we can round in both directions: round in objective function direction */ if( SCIPvarGetObj(var) >= 0.0 ) newsolval = SCIPfeasFloor(scip, oldsolval); else newsolval = SCIPfeasCeil(scip, oldsolval); } else if( mayrounddown ) newsolval = SCIPfeasFloor(scip, oldsolval); else if( mayroundup ) newsolval = SCIPfeasCeil(scip, oldsolval); else break; /* store new solution value */ SCIP_CALL( SCIPsetSolVal(scip, sol, var, newsolval) ); } /* check, if rounding was successful */ if( c == nlpcands ) { SCIP_Bool stored; /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because all fractional * variables were already moved in feasible direction to the next integer */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, FALSE, &stored) ); if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIPprintSol(scip, sol, NULL, FALSE); #endif *result = SCIP_FOUNDSOL; } } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecLocalbranching) { /*lint --e{715}*/ SCIP_Longint maxnnodes; /* maximum number of subnodes */ SCIP_Longint nsubnodes; /* nodelimit for subscip */ SCIP_HEURDATA* heurdata; SCIP* subscip; /* the subproblem created by localbranching */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_SOL* bestsol; /* best solution so far */ SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */ SCIP_Real timelimit; /* timelimit for subscip (equals remaining time of scip) */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real upperbound; SCIP_Real memorylimit; SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; int nvars; int i; SCIP_Bool success; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* there should be enough binary variables that a local branching constraint makes sense */ if( SCIPgetNBinVars(scip) < 2*heurdata->neighborhoodsize ) return SCIP_OKAY; *result = SCIP_DELAYED; /* only call heuristic, if an IP solution is at hand */ if( SCIPgetNSols(scip) <= 0 ) return SCIP_OKAY; bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); /* only call heuristic, if the best solution comes from transformed problem */ if( SCIPsolIsOriginal(bestsol) ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip, bestsol) < heurdata->nwaitingnodes) return SCIP_OKAY; /* only call heuristic, if the best solution does not come from trivial heuristic */ if( SCIPsolGetHeur(bestsol) != NULL && strcmp(SCIPheurGetName(SCIPsolGetHeur(bestsol)), "trivial") == 0 ) return SCIP_OKAY; /* reset neighborhood and minnodes, if new solution was found */ if( heurdata->lastsol != bestsol ) { heurdata->curneighborhoodsize = heurdata->neighborhoodsize; heurdata->curminnodes = heurdata->minnodes; heurdata->emptyneighborhoodsize = 0; heurdata->callstatus = EXECUTE; heurdata->lastsol = bestsol; } /* if no new solution was found and local branching also seems to fail, just keep on waiting */ if( heurdata->callstatus == WAITFORNEWSOL ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* calculate the maximal number of branching nodes until heuristic is aborted */ maxnnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip)); /* reward local branching if it succeeded often */ maxnnodes = (SCIP_Longint)(maxnnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0))); maxnnodes -= 100 * SCIPheurGetNCalls(heur); /* count the setup costs for the sub-MIP as 100 nodes */ 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 sub problem solving */ if( nsubnodes < heurdata->curminnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIPdebugMessage("running localbranching heuristic ...\n"); /* get the data of the variables and the best solution */ 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)) ); success = FALSE; eventhdlr = NULL; if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_localbranchsub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_localbranchsub", 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_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "localbranchsub", TRUE, FALSE, TRUE, &success) ); 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) ); } /* create event handler for LP events */ SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecLocalbranching, NULL) ); if( eventhdlr == NULL ) { SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n"); return SCIP_PLUGINNOTFOUND; } } SCIPdebugMessage("Copying the plugins was %ssuccessful.\n", success ? "" : "not "); for (i = 0; i < nvars; ++i) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); /* if the subproblem could not be created, free memory and return */ if( !success ) { *result = SCIP_DIDNOTRUN; goto TERMINATE; } /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); #ifndef SCIP_DEBUG /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); #endif /* 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; /* set limits for the subproblem */ heurdata->nodelimit = nsubnodes; SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nsubnodes) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", MAX(10, nsubnodes/10)) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", 3) ); 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 handler; 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 deductions shall be * made for the original SCIP */ if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") ) { SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 500) ); } /* copy the original problem and add the local branching constraint */ if( heurdata->uselprows ) { SCIP_CALL( createSubproblem(scip, subscip, subvars) ); } SCIP_CALL( addLocalBranchingConstraint(scip, subscip, subvars, heurdata) ); /* 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) ); /* catch LP events of sub-SCIP */ if( !heurdata->uselprows ) { assert(eventhdlr != NULL); SCIP_CALL( SCIPtransformProb(subscip) ); SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) ); } /* solve the subproblem */ SCIPdebugMessage("solving local branching subproblem with neighborhoodsize %d and maxnodes %"SCIP_LONGINT_FORMAT"\n", heurdata->curneighborhoodsize, nsubnodes); retcode = SCIPsolve(subscip); /* drop LP events of sub-SCIP */ if( !heurdata->uselprows ) { assert(eventhdlr != NULL); SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) ); } /* 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 local branching heuristic; sub-SCIP terminated with code <%d>\n",retcode); } /* print solving statistics of subproblem if we are in SCIP's debug mode */ SCIPdebug( SCIP_CALL( SCIPprintStatistics(subscip, NULL) ) ); heurdata->usednodes += SCIPgetNNodes(subscip); SCIPdebugMessage("local branching used %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT" nodes\n", SCIPgetNNodes(subscip), nsubnodes); /* 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 ) { SCIPdebugMessage("-> accepted solution of value %g\n", SCIPgetSolOrigObj(subscip, subsols[i])); *result = SCIP_FOUNDSOL; } } /* check the status of the sub-MIP */ switch( SCIPgetStatus(subscip) ) { case SCIP_STATUS_OPTIMAL: case SCIP_STATUS_BESTSOLLIMIT: heurdata->callstatus = WAITFORNEWSOL; /* new solution will immediately be installed at next call */ SCIPdebugMessage(" -> found new solution\n"); break; case SCIP_STATUS_NODELIMIT: case SCIP_STATUS_STALLNODELIMIT: case SCIP_STATUS_TOTALNODELIMIT: heurdata->callstatus = EXECUTE; heurdata->curneighborhoodsize = (heurdata->emptyneighborhoodsize + heurdata->curneighborhoodsize)/2; heurdata->curminnodes *= 2; SCIPdebugMessage(" -> node limit reached: reduced neighborhood to %d, increased minnodes to %d\n", heurdata->curneighborhoodsize, heurdata->curminnodes); if( heurdata->curneighborhoodsize <= heurdata->emptyneighborhoodsize ) { heurdata->callstatus = WAITFORNEWSOL; SCIPdebugMessage(" -> new neighborhood was already proven to be empty: wait for new solution\n"); } break; case SCIP_STATUS_INFEASIBLE: case SCIP_STATUS_INFORUNBD: heurdata->emptyneighborhoodsize = heurdata->curneighborhoodsize; heurdata->curneighborhoodsize += heurdata->curneighborhoodsize/2; heurdata->curneighborhoodsize = MAX(heurdata->curneighborhoodsize, heurdata->emptyneighborhoodsize + 2); heurdata->callstatus = EXECUTE; SCIPdebugMessage(" -> neighborhood is empty: increased neighborhood to %d\n", heurdata->curneighborhoodsize); break; case SCIP_STATUS_UNKNOWN: case SCIP_STATUS_USERINTERRUPT: case SCIP_STATUS_TIMELIMIT: case SCIP_STATUS_MEMLIMIT: case SCIP_STATUS_GAPLIMIT: case SCIP_STATUS_SOLLIMIT: case SCIP_STATUS_UNBOUNDED: default: heurdata->callstatus = WAITFORNEWSOL; SCIPdebugMessage(" -> unexpected sub-MIP status <%d>: waiting for new solution\n", SCIPgetStatus(subscip)); break; } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpRapidlearning) {/*lint --e{715}*/ SCIP* subscip; /* the subproblem created by rapid learning */ SCIP_SEPADATA* sepadata; /* separator's private data */ 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_HASHMAP* varmapbw; /* mapping of sub-SCIP variables to SCIP variables */ SCIP_CONSHDLR** conshdlrs; /* array of constraint handler's that might that might obtain conflicts */ int* oldnconss; /* number of constraints without rapid learning conflicts */ SCIP_Longint nodelimit; /* node limit for the subproblem */ SCIP_Real timelimit; /* time limit for the subproblem */ SCIP_Real memorylimit; /* memory limit for the subproblem */ int nconshdlrs; /* size of conshdlr and oldnconss array */ int nfixedvars; /* number of variables that could be fixed by rapid learning */ int nvars; /* number of variables */ int restartnum; /* maximal number of conflicts that should be created */ int i; /* counter */ SCIP_Bool success; /* was problem creation / copying constraint successful? */ SCIP_RETCODE retcode; /* used for catching sub-SCIP errors in debug mode */ int nconflicts; /* statistic: number of conflicts applied */ int nbdchgs; /* statistic: number of bound changes applied */ int n1startinfers; /* statistic: number of one side infer values */ int n2startinfers; /* statistic: number of both side infer values */ SCIP_Bool soladded; /* statistic: was a new incumbent found? */ SCIP_Bool dualboundchg; /* statistic: was a new dual bound found? */ SCIP_Bool disabledualreductions; /* TRUE, if dual reductions in sub-SCIP are not valid for original SCIP, * e.g., because a constraint could not be copied or a primal solution * could not be copied back */ int ndiscvars; soladded = FALSE; assert(sepa != NULL); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; ndiscvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip)+SCIPgetNImplVars(scip); /* only run when still not fixed binary variables exists */ if( ndiscvars == 0 ) return SCIP_OKAY; /* get separator's data */ sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); /* only run for integer programs */ if( !sepadata->contvars && ndiscvars != SCIPgetNVars(scip) ) return SCIP_OKAY; /* only run if there are few enough continuous variables */ if( sepadata->contvars && SCIPgetNContVars(scip) > sepadata->contvarsquot * SCIPgetNVars(scip) ) return SCIP_OKAY; /* do not run if pricers are present */ if( SCIPgetNActivePricers(scip) > 0 ) return SCIP_OKAY; /* if the separator should be exclusive to the root node, this prevents multiple calls due to restarts */ if( SCIPsepaGetFreq(sepa) == 0 && SCIPsepaGetNCalls(sepa) > 0) return SCIP_OKAY; /* call separator at most once per node */ if( SCIPsepaGetNCallsAtNode(sepa) > 0 ) return SCIP_OKAY; /* do not call rapid learning, if the problem is too big */ if( SCIPgetNVars(scip) > sepadata->maxnvars || SCIPgetNConss(scip) > sepadata->maxnconss ) 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) ); SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; /* copy the subproblem */ SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "rapid", FALSE, FALSE, &success) ); if( sepadata->copycuts ) { /** copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, FALSE) ); } for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) (size_t) SCIPhashmapGetImage(varmapfw, vars[i]); SCIPhashmapFree(&varmapfw); /* this avoids dual presolving */ if( !success ) { for( i = 0; i < nvars; i++ ) { SCIP_CALL( SCIPaddVarLocks(subscip, subvars[i], 1, 1 ) ); } } SCIPdebugMessage("Copying SCIP was%s successful.\n", success ? "" : " not"); /* mimic an FD solver: DFS, no LP solving, 1-FUIP instead of all-FUIP */ SCIP_CALL( SCIPsetIntParam(subscip, "lp/solvefreq", -1) ); SCIP_CALL( SCIPsetIntParam(subscip, "conflict/fuiplevels", 1) ); SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/dfs/stdpriority", INT_MAX/4) ); SCIP_CALL( SCIPsetBoolParam(subscip, "constraints/disableenfops", TRUE) ); SCIP_CALL( SCIPsetIntParam(subscip, "propagating/pseudoobj/freq", -1) ); /* use inference branching */ SCIP_CALL( SCIPsetBoolParam(subscip, "branching/inference/useweightedsum", FALSE) ); /* only create short conflicts */ SCIP_CALL( SCIPsetRealParam(subscip, "conflict/maxvarsfac", 0.05) ); /* set limits for the subproblem */ nodelimit = SCIPgetNLPIterations(scip); nodelimit = MAX(sepadata->minnodes, nodelimit); nodelimit = MIN(sepadata->maxnodes, nodelimit); restartnum = 1000; /* 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) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; if( timelimit <= 0.0 || memorylimit <= 0.0 ) goto TERMINATE; SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit/5) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/restarts", 0) ); SCIP_CALL( SCIPsetIntParam(subscip, "conflict/restartnum", restartnum) ); /* 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) ); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); #ifndef SCIP_DEBUG /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); #endif /* add an objective cutoff */ SCIP_CALL( SCIPsetObjlimit(subscip, SCIPgetUpperbound(scip)) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapbw, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nvars)) ); /* store reversing mapping of variables */ SCIP_CALL( SCIPtransformProb(subscip) ); for( i = 0; i < nvars; ++i) { SCIP_CALL( SCIPhashmapInsert(varmapbw, SCIPvarGetTransVar(subvars[i]), vars[i]) ); } /** allocate memory for constraints storage. Each constraint that will be created from now on will be a conflict. * Therefore, we need to remember oldnconss to get the conflicts from the FD search. */ nconshdlrs = 4; SCIP_CALL( SCIPallocBufferArray(scip, &conshdlrs, nconshdlrs) ); SCIP_CALL( SCIPallocBufferArray(scip, &oldnconss, nconshdlrs) ); /* store number of constraints before rapid learning search */ conshdlrs[0] = SCIPfindConshdlr(subscip, "bounddisjunction"); conshdlrs[1] = SCIPfindConshdlr(subscip, "setppc"); conshdlrs[2] = SCIPfindConshdlr(subscip, "linear"); conshdlrs[3] = SCIPfindConshdlr(subscip, "logicor"); /* redundant constraints might be eliminated in presolving */ SCIP_CALL( SCIPpresolve(subscip)); for( i = 0; i < nconshdlrs; ++i) { if( conshdlrs[i] != NULL ) oldnconss[i] = SCIPconshdlrGetNConss(conshdlrs[i]); } nfixedvars = SCIPgetNFixedVars(scip); /* solve the subproblem */ 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("Error while solving subproblem in rapid learning separator; sub-SCIP terminated with code <%d>\n",retcode); } /* abort solving, if limit of applied conflicts is reached */ if( SCIPgetNConflictConssApplied(subscip) >= restartnum ) { SCIPdebugMessage("finish after %lld successful conflict calls.\n", SCIPgetNConflictConssApplied(subscip)); } /* if the first 20% of the solution process were successful, proceed */ else if( (sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPisFeasLT(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) ) || (sepadata->applybdchgs && SCIPgetNFixedVars(subscip) > nfixedvars) || (sepadata->applyconflicts && SCIPgetNConflictConssApplied(subscip) > 0) ) { SCIPdebugMessage("proceed solving after the first 20%% of the solution process, since:\n"); if( SCIPgetNSols(subscip) > 0 && SCIPisFeasLE(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) ) { SCIPdebugMessage(" - there was a better solution (%f < %f)\n",SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip)); } if( SCIPgetNFixedVars(subscip) > nfixedvars ) { SCIPdebugMessage(" - there were %d variables fixed\n", SCIPgetNFixedVars(scip)-nfixedvars ); } if( SCIPgetNConflictConssFound(subscip) > 0 ) { SCIPdebugMessage(" - there were %lld conflict constraints created\n", SCIPgetNConflictConssApplied(subscip)); } /* set node limit to 100% */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit) ); /* solve the subproblem */ 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("Error while solving subproblem in rapid learning separator; sub-SCIP terminated with code <%d>\n",retcode); } } else { SCIPdebugMessage("do not proceed solving after the first 20%% of the solution process.\n"); } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif disabledualreductions = FALSE; /* check, whether a solution was found */ if( sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPfindHeur(scip, "trysol") != NULL ) { SCIP_HEUR* heurtrysol; 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 was declared to be feasible */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); soladded = FALSE; heurtrysol = SCIPfindHeur(scip, "trysol"); /* sequentially add solutions to trysol heuristic */ for( i = 0; i < nsubsols && !soladded; ++i ) { SCIPdebugMessage("Try to create new solution by copying subscip solution.\n"); SCIP_CALL( createNewSol(scip, subscip, subvars, heurtrysol, subsols[i], &soladded) ); } if( !soladded || !SCIPisEQ(scip, SCIPgetSolOrigObj(subscip, subsols[i-1]), SCIPgetSolOrigObj(subscip, subsols[0])) ) disabledualreductions = TRUE; } /* if the sub problem was solved completely, we update the dual bound */ dualboundchg = FALSE; if( sepadata->applysolved && !disabledualreductions && (SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL || SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE) ) { /* we need to multiply the dualbound with the scaling factor and add the offset, * because this information has been disregarded in the sub-SCIP */ SCIPdebugMessage("Update old dualbound %g to new dualbound %g.\n", SCIPgetDualbound(scip), SCIPgetTransObjscale(scip) * SCIPgetDualbound(subscip) + SCIPgetTransObjoffset(scip)); SCIP_CALL( SCIPupdateLocalDualbound(scip, SCIPgetDualbound(subscip) * SCIPgetTransObjscale(scip) + SCIPgetTransObjoffset(scip)) ); dualboundchg = TRUE; } /* check, whether conflicts were created */ nconflicts = 0; if( sepadata->applyconflicts && !disabledualreductions && SCIPgetNConflictConssApplied(subscip) > 0 ) { SCIP_HASHMAP* consmap; int hashtablesize; assert(SCIPgetNConflictConssApplied(subscip) < (SCIP_Longint) INT_MAX); hashtablesize = (int) SCIPgetNConflictConssApplied(subscip); assert(hashtablesize < INT_MAX/5); hashtablesize *= 5; /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), SCIPcalcHashtableSize(hashtablesize)) ); /* loop over all constraint handlers that might contain conflict constraints */ for( i = 0; i < nconshdlrs; ++i) { /* copy constraints that have been created in FD run */ if( conshdlrs[i] != NULL && SCIPconshdlrGetNConss(conshdlrs[i]) > oldnconss[i] ) { SCIP_CONS** conss; int c; int nconss; nconss = SCIPconshdlrGetNConss(conshdlrs[i]); conss = SCIPconshdlrGetConss(conshdlrs[i]); /* loop over all constraints that have been added in sub-SCIP run, these are the conflicts */ for( c = oldnconss[i]; c < nconss; ++c) { SCIP_CONS* cons; SCIP_CONS* conscopy; cons = conss[c]; assert(cons != NULL); success = FALSE; SCIP_CALL( SCIPgetConsCopy(subscip, scip, cons, &conscopy, conshdlrs[i], varmapbw, consmap, NULL, SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), TRUE, FALSE, SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), FALSE, TRUE, &success) ); if( success ) { nconflicts++; SCIP_CALL( SCIPaddCons(scip, conscopy) ); SCIP_CALL( SCIPreleaseCons(scip, &conscopy) ); } else { SCIPdebugMessage("failed to copy conflict constraint %s back to original SCIP\n", SCIPconsGetName(cons)); } } } } SCIPhashmapFree(&consmap); } /* check, whether tighter global bounds were detected */ nbdchgs = 0; if( sepadata->applybdchgs && !disabledualreductions ) for( i = 0; i < nvars; ++i ) { SCIP_Bool infeasible; SCIP_Bool tightened; assert(SCIPisLE(scip, SCIPvarGetLbGlobal(vars[i]), SCIPvarGetLbGlobal(subvars[i]))); assert(SCIPisLE(scip, SCIPvarGetLbGlobal(subvars[i]), SCIPvarGetUbGlobal(subvars[i]))); assert(SCIPisLE(scip, SCIPvarGetUbGlobal(subvars[i]), SCIPvarGetUbGlobal(vars[i]))); /* update the bounds of the original SCIP, if a better bound was proven in the sub-SCIP */ SCIP_CALL( SCIPtightenVarUb(scip, vars[i], SCIPvarGetUbGlobal(subvars[i]), FALSE, &infeasible, &tightened) ); if( tightened ) nbdchgs++; SCIP_CALL( SCIPtightenVarLb(scip, vars[i], SCIPvarGetLbGlobal(subvars[i]), FALSE, &infeasible, &tightened) ); if( tightened ) nbdchgs++; } n1startinfers = 0; n2startinfers = 0; /* install start values for inference branching */ if( sepadata->applyinfervals && (!sepadata->reducedinfer || soladded || nbdchgs+nconflicts > 0) ) { for( i = 0; i < nvars; ++i ) { SCIP_Real downinfer; SCIP_Real upinfer; SCIP_Real downvsids; SCIP_Real upvsids; SCIP_Real downconflen; SCIP_Real upconflen; /* copy downwards branching statistics */ downvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); downconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); downinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); /* copy upwards branching statistics */ upvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); upconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); upinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); /* memorize statistics */ if( downinfer+downconflen+downvsids > 0.0 || upinfer+upconflen+upvsids != 0 ) n1startinfers++; if( downinfer+downconflen+downvsids > 0.0 && upinfer+upconflen+upvsids != 0 ) n2startinfers++; SCIP_CALL( SCIPinitVarBranchStats(scip, vars[i], 0.0, 0.0, downvsids, upvsids, downconflen, upconflen, downinfer, upinfer, 0.0, 0.0) ); } } SCIPdebugPrintf("XXX Rapidlearning added %d conflicts, changed %d bounds, %s primal solution, %s dual bound improvement.\n", nconflicts, nbdchgs, soladded ? "found" : "no", dualboundchg ? "found" : "no"); SCIPdebugPrintf("YYY Infervalues initialized on one side: %5.2f %% of variables, %5.2f %% on both sides\n", 100.0 * n1startinfers/(SCIP_Real)nvars, 100.0 * n2startinfers/(SCIP_Real)nvars); /* change result pointer */ if( nconflicts > 0 || dualboundchg ) *result = SCIP_CONSADDED; else if( nbdchgs > 0 ) *result = SCIP_REDUCEDDOM; /* free local data */ SCIPfreeBufferArray(scip, &oldnconss); SCIPfreeBufferArray(scip, &conshdlrs); SCIPhashmapFree(&varmapbw); TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); 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) ); /* 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; /* 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); } 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; }
/** 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; }
/** presolving execution method */ static SCIP_DECL_PRESOLEXEC(presolExecInttobinary) { /*lint --e{715}*/ SCIP_VAR** scipvars; SCIP_VAR** vars; int nbinvars; int nintvars; int v; assert(result != NULL); *result = SCIP_DIDNOTRUN; if( SCIPdoNotAggr(scip) ) return SCIP_OKAY; /* get the problem variables */ scipvars = SCIPgetVars(scip); nbinvars = SCIPgetNBinVars(scip); nintvars = SCIPgetNIntVars(scip); if( nintvars == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* copy the integer variables into an own array, since adding binary variables affects the left-most slots in the * array and thereby interferes with our search loop */ SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, &scipvars[nbinvars], nintvars) ); /* scan the integer variables for possible conversion into binaries; * we have to collect the variables first in an own */ for( v = 0; v < nintvars; ++v ) { SCIP_Real lb; SCIP_Real ub; assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_INTEGER); /* get variable's bounds */ lb = SCIPvarGetLbGlobal(vars[v]); ub = SCIPvarGetUbGlobal(vars[v]); /* check if bounds are exactly one apart */ if( SCIPisEQ(scip, lb, ub - 1.0) ) { SCIP_VAR* binvar; char binvarname[SCIP_MAXSTRLEN]; SCIP_Bool infeasible; SCIP_Bool redundant; SCIP_Bool aggregated; SCIPdebugMessage("converting <%s>[%g,%g] into binary variable\n", SCIPvarGetName(vars[v]), lb, ub); /* create binary variable */ (void) SCIPsnprintf(binvarname, SCIP_MAXSTRLEN, "%s_bin", SCIPvarGetName(vars[v])); SCIP_CALL( SCIPcreateVar(scip, &binvar, binvarname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, SCIPvarIsInitial(vars[v]), SCIPvarIsRemovable(vars[v]), NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, binvar) ); /* aggregate integer and binary variable */ SCIP_CALL( SCIPaggregateVars(scip, vars[v], binvar, 1.0, -1.0, lb, &infeasible, &redundant, &aggregated) ); /* release binary variable */ SCIP_CALL( SCIPreleaseVar(scip, &binvar) ); /* it can be the case that this aggregation detects an infeasibility; for example, during the copy of the * variable bounds from the integer variable to the binary variable, infeasibility can be detected; this can * happen because an upper bound or a lower bound of such a variable bound variable was "just" changed and the * varbound constraint handler, who would detect that infeasibility (since it was creating it from a varbound * constraint), was called before that bound change was detected due to the presolving priorities; */ if( infeasible ) { *result = SCIP_CUTOFF; break; } assert(redundant); assert(aggregated); (*nchgvartypes)++; *result = SCIP_SUCCESS; } } /* free temporary memory */ SCIPfreeBufferArray(scip, &vars); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecRootsoldiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_VAR** vars; SCIP_Real* rootsol; SCIP_Real* objchgvals; int* softroundings; int* intvalrounds; int nvars; int nbinvars; int nintvars; int nlpcands; SCIP_LPSOLSTAT lpsolstat; SCIP_Real absstartobjval; SCIP_Real objstep; SCIP_Real alpha; SCIP_Real oldobj; SCIP_Real newobj; SCIP_Bool lperror; SCIP_Bool lpsolchanged; SCIP_Longint nsolsfound; SCIP_Longint ncalls; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int depth; int maxdepth; int maxdivedepth; int divedepth; int startnlpcands; int ncycles; int i; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* 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 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; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only apply heuristic, if only a few solutions have been found */ if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols ) return SCIP_OKAY; /* 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 number of fractional variables, that should be integral */ nlpcands = SCIPgetNLPBranchCands(scip); /* don't try to dive, if there are no fractional variables */ if( nlpcands == 0 ) return SCIP_OKAY; /* calculate the maximal diving depth */ nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); if( SCIPgetNSolsFound(scip) == 0 ) maxdivedepth = (int)(heurdata->depthfacnosol * nvars); else maxdivedepth = (int)(heurdata->depthfac * nvars); maxdivedepth = MAX(maxdivedepth, 10); *result = SCIP_DIDNOTFIND; /* get all variables of LP */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); /* get root solution value of all binary and integer variables */ SCIP_CALL( SCIPallocBufferArray(scip, &rootsol, nbinvars + nintvars) ); for( i = 0; i < nbinvars + nintvars; i++ ) rootsol[i] = SCIPvarGetRootSol(vars[i]); /* get current LP objective value, and calculate length of a single step in an objective coefficient */ absstartobjval = SCIPgetLPObjval(scip); absstartobjval = ABS(absstartobjval); absstartobjval = MAX(absstartobjval, 1.0); objstep = absstartobjval / 10.0; /* initialize array storing the preferred soft rounding directions and counting the integral value rounds */ SCIP_CALL( SCIPallocBufferArray(scip, &softroundings, nbinvars + nintvars) ); BMSclearMemoryArray(softroundings, nbinvars + nintvars); SCIP_CALL( SCIPallocBufferArray(scip, &intvalrounds, nbinvars + nintvars) ); BMSclearMemoryArray(intvalrounds, nbinvars + nintvars); /* allocate temporary memory for buffering objective changes */ SCIP_CALL( SCIPallocBufferArray(scip, &objchgvals, nbinvars + nintvars) ); /* start diving */ SCIP_CALL( SCIPstartDive(scip) ); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing rootsoldiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%"SCIP_LONGINT_FORMAT", maxdivedepth=%d, LPobj=%g, objstep=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth, SCIPgetLPObjval(scip), objstep); lperror = FALSE; divedepth = 0; lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; alpha = heurdata->alpha; ncycles = 0; lpsolchanged = TRUE; startnlpcands = nlpcands; while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && ncycles < 10 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) ) { SCIP_Bool success; int hardroundingidx; int hardroundingdir; SCIP_Real hardroundingoldbd; SCIP_Real hardroundingnewbd; SCIP_Bool boundschanged; SCIP_RETCODE retcode; /* 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("rootsoldiving 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; } } divedepth++; hardroundingidx = -1; hardroundingdir = 0; hardroundingoldbd = 0.0; hardroundingnewbd = 0.0; boundschanged = FALSE; SCIPdebugMessage("dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT":\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations); /* round solution x* from diving LP: * - x~_j = down(x*_j) if x*_j is integer or binary variable and x*_j <= root solution_j * - x~_j = up(x*_j) if x*_j is integer or binary variable and x*_j > root solution_j * - x~_j = x*_j if x*_j is continuous variable * change objective function in diving LP: * - if x*_j is integral, or j is a continuous variable, set obj'_j = alpha * obj_j * - otherwise, set obj'_j = alpha * obj_j + sign(x*_j - x~_j) */ for( i = 0; i < nbinvars + nintvars; i++ ) { SCIP_VAR* var; SCIP_Real solval; var = vars[i]; oldobj = SCIPgetVarObjDive(scip, var); newobj = oldobj; solval = SCIPvarGetLPSol(var); if( SCIPisFeasIntegral(scip, solval) ) { /* if the variable became integral after a soft rounding, count the rounds; after a while, fix it to its * current integral value; * otherwise, fade out the objective value */ if( softroundings[i] != 0 && lpsolchanged ) { intvalrounds[i]++; if( intvalrounds[i] == 5 && SCIPgetVarLbDive(scip, var) < SCIPgetVarUbDive(scip, var) - 0.5 ) { /* use exact integral value, if the variable is only integral within numerical tolerances */ solval = SCIPfloor(scip, solval+0.5); SCIPdebugMessage(" -> fixing <%s> = %g\n", SCIPvarGetName(var), solval); SCIP_CALL( SCIPchgVarLbDive(scip, var, solval) ); SCIP_CALL( SCIPchgVarUbDive(scip, var, solval) ); boundschanged = TRUE; } } else newobj = alpha * oldobj; } else if( solval <= rootsol[i] ) { /* if the variable was soft rounded most of the time downwards, round it downwards by changing the bounds; * otherwise, apply soft rounding by changing the objective value */ softroundings[i]--; if( softroundings[i] <= -10 && hardroundingidx == -1 ) { SCIPdebugMessage(" -> hard rounding <%s>[%g] <= %g\n", SCIPvarGetName(var), solval, SCIPfeasFloor(scip, solval)); hardroundingidx = i; hardroundingdir = -1; hardroundingoldbd = SCIPgetVarUbDive(scip, var); hardroundingnewbd = SCIPfeasFloor(scip, solval); SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd) ); boundschanged = TRUE; } else newobj = alpha * oldobj + objstep; } else { /* if the variable was soft rounded most of the time upwards, round it upwards by changing the bounds; * otherwise, apply soft rounding by changing the objective value */ softroundings[i]++; if( softroundings[i] >= +10 && hardroundingidx == -1 ) { SCIPdebugMessage(" -> hard rounding <%s>[%g] >= %g\n", SCIPvarGetName(var), solval, SCIPfeasCeil(scip, solval)); hardroundingidx = i; hardroundingdir = +1; hardroundingoldbd = SCIPgetVarLbDive(scip, var); hardroundingnewbd = SCIPfeasCeil(scip, solval); SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd) ); boundschanged = TRUE; } else newobj = alpha * oldobj - objstep; } /* remember the objective change */ objchgvals[i] = newobj; } /* apply objective changes if there was no bound change */ if( !boundschanged ) { /* apply cached changes on integer variables */ for( i = 0; i < nbinvars + nintvars; ++i ) { SCIP_VAR* var; var = vars[i]; SCIPdebugMessage(" -> i=%d var <%s>, solval=%g, rootsol=%g, oldobj=%g, newobj=%g\n", i, SCIPvarGetName(var), SCIPvarGetLPSol(var), rootsol[i], SCIPgetVarObjDive(scip, var), objchgvals[i]); SCIP_CALL( SCIPchgVarObjDive(scip, var, objchgvals[i]) ); } /* fade out the objective values of the continuous variables */ for( i = nbinvars + nintvars; i < nvars; i++ ) { SCIP_VAR* var; var = vars[i]; oldobj = SCIPgetVarObjDive(scip, var); newobj = alpha * oldobj; SCIPdebugMessage(" -> i=%d var <%s>, solval=%g, oldobj=%g, newobj=%g\n", i, SCIPvarGetName(var), SCIPvarGetLPSol(var), oldobj, newobj); SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) ); } } SOLVEAGAIN: /* resolve the diving LP */ nlpiterations = SCIPgetNLPIterations(scip); retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror); lpsolstat = SCIPgetLPSolstat(scip); /* 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. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY ) { SCIP_CALL( retcode ); } #endif SCIPwarningMessage(scip, "Error while solving LP in Rootsoldiving heuristic; LP solve terminated with code <%d>\n", retcode); SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n"); } if( lperror ) break; /* update iteration count */ heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations; /* if no LP iterations were performed, we stayed at the same solution -> count this cycling */ lpsolchanged = (SCIPgetNLPIterations(scip) != nlpiterations); if( lpsolchanged ) ncycles = 0; else if( !boundschanged ) /* do not count if integral variables have been fixed */ ncycles++; /* get LP solution status and number of fractional variables, that should be integral */ if( lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE && hardroundingidx != -1 ) { SCIP_VAR* var; var = vars[hardroundingidx]; /* round the hard rounded variable to the opposite direction and resolve the LP */ if( hardroundingdir == -1 ) { SCIPdebugMessage(" -> opposite hard rounding <%s> >= %g\n", SCIPvarGetName(var), hardroundingnewbd + 1.0); SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingoldbd) ); SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd + 1.0) ); } else { SCIPdebugMessage(" -> opposite hard rounding <%s> <= %g\n", SCIPvarGetName(var), hardroundingnewbd - 1.0); SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingoldbd) ); SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd - 1.0) ); } hardroundingidx = -1; goto SOLVEAGAIN; } if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) nlpcands = SCIPgetNLPBranchCands(scip); SCIPdebugMessage(" -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands); } SCIPdebugMessage("---> diving finished: lpsolstat = %d, depth %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT"\n", lpsolstat, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations); /* check if a solution has been found */ if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* create solution from diving LP */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIPdebugMessage("rootsoldiving 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( SCIPendDive(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; /* free temporary memory */ SCIPfreeBufferArray(scip, &objchgvals); SCIPfreeBufferArray(scip, &intvalrounds); SCIPfreeBufferArray(scip, &softroundings); SCIPfreeBufferArray(scip, &rootsol); SCIPdebugMessage("rootsoldiving heuristic finished\n"); return SCIP_OKAY; }