/** branching execution method for fractional LP solutions */ static SCIP_DECL_BRANCHEXECLP(branchExeclpLeastinf) { /*lint --e{715}*/ SCIP_VAR** lpcands; SCIP_Real* lpcandsfrac; int nlpcands; SCIP_Real infeasibility; SCIP_Real score; SCIP_Real obj; SCIP_Real bestscore; SCIP_Real bestobj; int bestcand; int i; assert(branchrule != NULL); assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); assert(scip != NULL); assert(result != NULL); SCIPdebugMessage("Execlp method of leastinf branching\n"); /* get branching candidates */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) ); assert(nlpcands > 0); /* search the least infeasible candidate */ bestscore = SCIP_REAL_MIN; bestobj = 0.0; bestcand = -1; for( i = 0; i < nlpcands; ++i ) { assert(lpcands[i] != NULL); infeasibility = lpcandsfrac[i]; infeasibility = MIN(infeasibility, 1.0-infeasibility); score = 1.0 - infeasibility; score *= SCIPvarGetBranchFactor(lpcands[i]); obj = SCIPvarGetObj(lpcands[i]); obj = REALABS(obj); if( SCIPisGT(scip, score, bestscore) || (SCIPisGE(scip, score, bestscore) && obj > bestobj) ) { bestscore = score; bestobj = obj; bestcand = i; } } assert(bestcand >= 0); SCIPdebugMessage(" -> %d candidates, selected candidate %d: variable <%s> (frac=%g, obj=%g, factor=%g, score=%g)\n", nlpcands, bestcand, SCIPvarGetName(lpcands[bestcand]), lpcandsfrac[bestcand], bestobj, SCIPvarGetBranchFactor(lpcands[bestcand]), bestscore); /* perform the branching */ SCIP_CALL( SCIPbranchVar(scip, lpcands[bestcand], NULL, NULL, NULL) ); *result = SCIP_BRANCHED; return SCIP_OKAY; }
/** gets rank of variable corresponding to row of \f$B^{-1}\f$ */ static int getVarRank( SCIP* scip, /**< SCIP pointer */ SCIP_Real* binvrow, /**< row of \f$B^{-1}\f$ */ SCIP_Real* rowsmaxval, /**< maximal row multiplicator from nonbasic matrix A_N */ SCIP_Real maxweightrange, /**< maximal valid range max(|weights|)/min(|weights|) of row weights */ SCIP_ROW** rows, /**< rows of LP relaxation of scip */ int nrows /**< number of rows */ ) { SCIP_Real maxweight = 0.0; int maxrank = 0; int r; assert( scip != NULL ); assert( binvrow != NULL || nrows == 0 ); assert( rowsmaxval != NULL || nrows == 0 ); assert( rows != NULL || nrows == 0 ); /* compute maximum row weights resulting from multiplication */ for (r = 0; r < nrows; ++r) { SCIP_Real val; val = REALABS(binvrow[r] * rowsmaxval[r]);/*lint !e613*/ if ( SCIPisGT(scip, val, maxweight) ) maxweight = val; } /* compute rank */ for (r = 0; r < nrows; ++r) { SCIP_Real val; int rank; val = REALABS(binvrow[r] * rowsmaxval[r]);/*lint !e613*/ rank = SCIProwGetRank(rows[r]);/*lint !e613*/ if ( rank > maxrank && SCIPisGT(scip, val * maxweightrange, maxweight) ) maxrank = rank; } return maxrank; }
/** node comparison method of node selector */ static SCIP_DECL_NODESELCOMP(nodeselCompHybridestim) { /*lint --e{715}*/ SCIP_NODESELDATA* nodeseldata; SCIP_Real score1; SCIP_Real score2; assert(nodesel != NULL); assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0); assert(scip != NULL); nodeseldata = SCIPnodeselGetData(nodesel); assert(nodeseldata != NULL); score1 = getNodeselScore(node1, nodeseldata->estimweight); score2 = getNodeselScore(node2, nodeseldata->estimweight); if( (SCIPisInfinity(scip, score1) && SCIPisInfinity(scip, score2)) || (SCIPisInfinity(scip, -score1) && SCIPisInfinity(scip, -score2)) || SCIPisEQ(scip, score1, score2) ) { SCIP_NODETYPE nodetype1; SCIP_NODETYPE nodetype2; nodetype1 = SCIPnodeGetType(node1); nodetype2 = SCIPnodeGetType(node2); if( nodetype1 == SCIP_NODETYPE_CHILD && nodetype2 != SCIP_NODETYPE_CHILD ) return -1; else if( nodetype1 != SCIP_NODETYPE_CHILD && nodetype2 == SCIP_NODETYPE_CHILD ) return +1; else if( nodetype1 == SCIP_NODETYPE_SIBLING && nodetype2 != SCIP_NODETYPE_SIBLING ) return -1; else if( nodetype1 != SCIP_NODETYPE_SIBLING && nodetype2 == SCIP_NODETYPE_SIBLING ) return +1; else { int depth1; int depth2; depth1 = SCIPnodeGetDepth(node1); depth2 = SCIPnodeGetDepth(node2); if( depth1 < depth2 ) return -1; else if( depth1 > depth2 ) return +1; else return 0; } } if( SCIPisLT(scip, score1, score2) ) return -1; assert(SCIPisGT(scip, score1, score2)); return +1; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ unsigned int* randseed, /**< a seed value for the random number generator */ SCIP_Bool uselprows /**< should subproblem be created out of the rows in the LP rows? */ ) { SCIP_VAR** vars; /* original scip variables */ SCIP_SOL* sol; /* pool of solutions */ SCIP_Bool* marked; /* array of markers, which variables to fixed */ SCIP_Bool fixingmarker; /* which flag should label a fixed variable? */ int nvars; int nbinvars; int nintvars; int i; int j; int nmarkers; /* get required data of the original problem */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); sol = SCIPgetBestSol(scip); assert(sol != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &marked, nbinvars+nintvars) ); if( minfixingrate > 0.5 ) { nmarkers = nbinvars + nintvars - (int) SCIPfloor(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = FALSE; } else { nmarkers = (int) SCIPceil(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = TRUE; } assert( 0 <= nmarkers && nmarkers <= SCIPceil(scip,(nbinvars+nintvars)/2.0 ) ); j = 0; BMSclearMemoryArray(marked, nbinvars+nintvars); while( j < nmarkers ) { do { i = SCIPgetRandomInt(0, nbinvars+nintvars-1, randseed); } while( marked[i] ); marked[i] = TRUE; j++; } assert( j == nmarkers ); /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { /* fix all randomly marked variables */ if( marked[i] == fixingmarker ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, sol, vars[i]); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); assert(SCIPisLE(scip, lb, ub)); /* due to dual reductions, it may happen that the solution value is not in the variable's domain anymore */ if( SCIPisLT(scip, solval, lb) ) solval = lb; else if( SCIPisGT(scip, solval, ub) ) solval = ub; /* perform the bound change */ if( !SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval) ) { SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) ); } } } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } } SCIPfreeBufferArray(scip, &marked); 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; }
/** node comparison method of node selector */ static SCIP_DECL_NODESELCOMP(nodeselCompBfs) { /*lint --e{715}*/ SCIP_Real lowerbound1; SCIP_Real lowerbound2; assert(nodesel != NULL); assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0); assert(scip != NULL); lowerbound1 = SCIPnodeGetLowerbound(node1); lowerbound2 = SCIPnodeGetLowerbound(node2); if( SCIPisLT(scip, lowerbound1, lowerbound2) ) return -1; else if( SCIPisGT(scip, lowerbound1, lowerbound2) ) return +1; else { SCIP_Real estimate1; SCIP_Real estimate2; estimate1 = SCIPnodeGetEstimate(node1); estimate2 = SCIPnodeGetEstimate(node2); if( (SCIPisInfinity(scip, estimate1) && SCIPisInfinity(scip, estimate2)) || (SCIPisInfinity(scip, -estimate1) && SCIPisInfinity(scip, -estimate2)) || SCIPisEQ(scip, estimate1, estimate2) ) { SCIP_NODETYPE nodetype1; SCIP_NODETYPE nodetype2; nodetype1 = SCIPnodeGetType(node1); nodetype2 = SCIPnodeGetType(node2); if( nodetype1 == SCIP_NODETYPE_CHILD && nodetype2 != SCIP_NODETYPE_CHILD ) return -1; else if( nodetype1 != SCIP_NODETYPE_CHILD && nodetype2 == SCIP_NODETYPE_CHILD ) return +1; else if( nodetype1 == SCIP_NODETYPE_SIBLING && nodetype2 != SCIP_NODETYPE_SIBLING ) return -1; else if( nodetype1 != SCIP_NODETYPE_SIBLING && nodetype2 == SCIP_NODETYPE_SIBLING ) return +1; else { int depth1; int depth2; depth1 = SCIPnodeGetDepth(node1); depth2 = SCIPnodeGetDepth(node2); if( depth1 < depth2 ) return -1; else if( depth1 > depth2 ) return +1; else return 0; } } if( SCIPisLT(scip, estimate1, estimate2) ) return -1; assert(SCIPisGT(scip, estimate1, estimate2)); return +1; } }
/** 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; }
/** perform randomized rounding of the given solution. Domain propagation is optionally applied after every rounding * step */ static SCIP_RETCODE performRandRounding( SCIP* scip, /**< SCIP main data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_SOL* sol, /**< solution to round */ SCIP_VAR** cands, /**< candidate variables */ int ncands, /**< number of candidates */ SCIP_Bool propagate, /**< should the rounding be propagated? */ SCIP_RESULT* result /**< pointer to store the result of the heuristic call */ ) { int c; SCIP_Bool stored; SCIP_VAR** permutedcands; SCIP_Bool cutoff; assert(heurdata != NULL); /* start probing tree before rounding begins */ if( propagate ) { SCIP_CALL( SCIPstartProbing(scip) ); SCIPenableVarHistory(scip); } /* copy and permute the candidate array */ SCIP_CALL( SCIPduplicateBufferArray(scip, &permutedcands, cands, ncands) ); assert(permutedcands != NULL); SCIPpermuteArray((void **)permutedcands, 0, ncands, &heurdata->randseed); cutoff = FALSE; /* loop over candidates and perform randomized rounding and optionally probing. */ for (c = 0; c < ncands && !cutoff; ++c) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Longint ndomreds; SCIP_Real lb; SCIP_Real ub; SCIP_Real ceilval; SCIP_Real floorval; /* get next variable from permuted candidate array */ var = permutedcands[c]; oldsolval = SCIPgetSolVal(scip, sol, var); lb = SCIPvarGetLbLocal(var); ub = SCIPvarGetUbLocal(var); assert( ! SCIPisFeasIntegral(scip, oldsolval) ); assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ); mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); ceilval = SCIPfeasCeil(scip, oldsolval); floorval = SCIPfeasFloor(scip, oldsolval); SCIPdebugMessage("rand rounding heuristic: var <%s>, val=%g, rounddown=%u, roundup=%u\n", SCIPvarGetName(var), oldsolval, mayrounddown, mayroundup); /* abort if rounded ceil and floor value lie outside the variable domain. Otherwise, check if * bounds allow only one rounding direction, anyway */ if( lb > ceilval + 0.5 || ub < floorval - 0.5 ) { cutoff = TRUE; break; } else if( SCIPisFeasEQ(scip, lb, ceilval) ) { /* only rounding up possible */ assert(SCIPisFeasGE(scip, ub, ceilval)); newsolval = ceilval; } else if( SCIPisFeasEQ(scip, ub, floorval) ) { /* only rounding down possible */ assert(SCIPisFeasLE(scip,lb, floorval)); newsolval = floorval; } else if( !heurdata->usesimplerounding || !(mayroundup || mayrounddown) ) { /* the standard randomized rounding */ SCIP_Real randnumber; randnumber = SCIPgetRandomReal(0.0, 1.0, &heurdata->randseed); if( randnumber <= oldsolval - floorval ) newsolval = ceilval; else newsolval = floorval; } /* choose rounding direction, if possible, or use the only direction guaranteed to be feasible */ else if( mayrounddown && mayroundup ) { /* we can round in both directions: round in objective function direction */ if ( SCIPvarGetObj(var) >= 0.0 ) newsolval = floorval; else newsolval = ceilval; } else if( mayrounddown ) newsolval = floorval; else { assert(mayroundup); newsolval = ceilval; } assert(SCIPisFeasLE(scip, lb, newsolval)); assert(SCIPisFeasGE(scip, ub, newsolval)); /* if propagation is enabled, fix the candidate variable to its rounded value and propagate the solution */ if( propagate ) { SCIP_Bool lbadjust; SCIP_Bool ubadjust; lbadjust = SCIPisGT(scip, newsolval, lb); ubadjust = SCIPisLT(scip, newsolval, ub); assert( lbadjust || ubadjust || SCIPisFeasEQ(scip, lb, ub)); /* enter a new probing node if the variable was not already fixed before */ if( lbadjust || ubadjust ) { SCIP_RETCODE retcode; if( SCIPisStopped(scip) ) break; retcode = SCIPnewProbingNode(scip); if( retcode == SCIP_MAXDEPTHLEVEL ) break; SCIP_CALL( retcode ); /* tighten the bounds to fix the variable for the probing node */ if( lbadjust ) { SCIP_CALL( SCIPchgVarLbProbing(scip, var, newsolval) ); } if( ubadjust ) { SCIP_CALL( SCIPchgVarUbProbing(scip, var, newsolval) ); } /* call propagation routines for the reduced problem */ SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) ); } } /* store new solution value */ SCIP_CALL( SCIPsetSolVal(scip, sol, var, newsolval) ); } /* if no cutoff was detected, the solution is a candidate to be checked for feasibility */ if( !cutoff && ! SCIPisStopped(scip) ) { if( SCIPallColsInLP(scip) ) { /* 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, TRUE, &stored) ); } else { /* if there are variables which are not present in the LP, e.g., for * column generation, we need to check their bounds */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &stored) ); } if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif *result = SCIP_FOUNDSOL; } } assert( !propagate || SCIPinProbing(scip) ); /* exit probing mode and free locally allocated memory */ if( propagate ) { SCIP_CALL( SCIPendProbing(scip) ); } SCIPfreeBufferArray(scip, &permutedcands); 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(heurExecTrivial) { /*lint --e{715}*/ SCIP_VAR** vars; SCIP_SOL* lbsol; /* solution where all variables are set to their lower bounds */ SCIP_SOL* ubsol; /* solution where all variables are set to their upper bounds */ SCIP_SOL* zerosol; /* solution where all variables are set to zero */ SCIP_SOL* locksol; /* solution where all variables are set to the bound with the fewer locks */ SCIP_Real large; int nvars; int nbinvars; int i; SCIP_Bool success; SCIP_Bool zerovalid; *result = SCIP_DIDNOTRUN; if( SCIPgetNRuns(scip) > 1 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; success = FALSE; /* initialize data structure */ SCIP_CALL( SCIPcreateSol(scip, &lbsol, heur) ); SCIP_CALL( SCIPcreateSol(scip, &ubsol, heur) ); SCIP_CALL( SCIPcreateSol(scip, &zerosol, heur) ); SCIP_CALL( SCIPcreateSol(scip, &locksol, heur) ); /* determine large value to set variables to */ large = SCIPinfinity(scip); if( !SCIPisInfinity(scip, 0.1 / SCIPfeastol(scip)) ) large = 0.1 / SCIPfeastol(scip); SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) ); /* if the problem is binary, we do not have to check the zero solution, since it is equal to the lower bound * solution */ zerovalid = (nvars != nbinvars); assert(vars != NULL || nvars == 0); for( i = 0; i < nvars; i++ ) { SCIP_Real lb; SCIP_Real ub; assert(vars != NULL); /* this assert is needed for flexelint */ lb = SCIPvarGetLbLocal(vars[i]); ub = SCIPvarGetUbLocal(vars[i]); /* if problem is obviously infeasible due to empty domain, stop */ if( SCIPisGT(scip, lb, ub) ) goto TERMINATE; /* set bounds to sufficient large value */ if( SCIPisInfinity(scip, -lb) ) lb = MIN(-large, ub); if( SCIPisInfinity(scip, ub) ) { SCIP_Real tmp; tmp = SCIPvarGetLbLocal(vars[i]); ub = MAX(tmp, large); } SCIP_CALL( SCIPsetSolVal(scip, lbsol, vars[i], lb) ); SCIP_CALL( SCIPsetSolVal(scip, ubsol, vars[i], ub) ); /* try the zero vector, if it is in the bounds region */ if( zerovalid ) { if( SCIPisLE(scip, lb, 0.0) && SCIPisLE(scip, 0.0, ub) ) { SCIP_CALL( SCIPsetSolVal(scip, zerosol, vars[i], 0.0) ); } else zerovalid = FALSE; } /* set variables to the bound with fewer locks, if tie choose an average value */ if( SCIPvarGetNLocksDown(vars[i]) > SCIPvarGetNLocksUp(vars[i]) ) { SCIP_CALL( SCIPsetSolVal(scip, locksol, vars[i], ub) ); } else if( SCIPvarGetNLocksDown(vars[i]) < SCIPvarGetNLocksUp(vars[i]) ) { SCIP_CALL( SCIPsetSolVal(scip, locksol, vars[i], lb) ); } else { SCIP_Real solval; solval = (lb+ub)/2.0; /* if a tie occurs, roughly every third integer variable will be rounded up */ if( SCIPvarGetType(vars[i]) != SCIP_VARTYPE_CONTINUOUS ) solval = i % 3 == 0 ? SCIPceil(scip,solval) : SCIPfloor(scip,solval); assert(SCIPisFeasLE(scip,SCIPvarGetLbLocal(vars[i]),solval) && SCIPisFeasLE(scip,solval,SCIPvarGetUbLocal(vars[i]))); SCIP_CALL( SCIPsetSolVal(scip, locksol, vars[i], solval) ); } } /* try lower bound solution */ SCIPdebugMessage("try lower bound solution\n"); SCIP_CALL( SCIPtrySol(scip, lbsol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible lower bound solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, lbsol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } /* try upper bound solution */ SCIPdebugMessage("try upper bound solution\n"); SCIP_CALL( SCIPtrySol(scip, ubsol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible upper bound solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, ubsol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } /* try zero solution */ if( zerovalid ) { SCIPdebugMessage("try zero solution\n"); SCIP_CALL( SCIPtrySol(scip, zerosol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible zero solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, zerosol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } } /* try lock solution */ SCIPdebugMessage("try lock solution\n"); SCIP_CALL( SCIPtrySol(scip, locksol, FALSE, FALSE, TRUE, TRUE, &success) ); if( success ) { SCIPdebugMessage("found feasible lock solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, locksol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } TERMINATE: /* free solutions */ SCIP_CALL( SCIPfreeSol(scip, &lbsol) ); SCIP_CALL( SCIPfreeSol(scip, &ubsol) ); SCIP_CALL( SCIPfreeSol(scip, &zerosol) ); SCIP_CALL( SCIPfreeSol(scip, &locksol) ); return SCIP_OKAY; }
/** propagator to force finding the debugging solution */ static SCIP_DECL_PROPEXEC(propExecDebug) { /*lint --e{715}*/ SCIP_VAR** vars; int nvars; int i; assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTFIND; /* check if we are in the original problem and not in a sub MIP */ if( !isSolutionInMip(scip->set) ) return SCIP_OKAY; if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING ) return SCIP_OKAY; /* check if the incumbent solution is at least as good as the debug solution, so we can stop to check the debug solution */ if( debugSolIsAchieved(scip->set) ) return SCIP_OKAY; #if 1 /* solve at least one LP */ if( SCIPgetNLPIterations(scip) == 0 ) return SCIP_OKAY; #endif vars = SCIPgetOrigVars(scip); nvars = SCIPgetNOrigVars(scip); for( i = 0; i < nvars; ++i ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; SCIP_Bool infeasible; SCIP_Bool fixed; SCIP_CALL( getSolutionValue(scip->set, vars[i], &solval) ); if( solval == SCIP_UNKNOWN ) /*lint !e777*/ { SCIPerrorMessage("original variable without debugging solution value\n"); SCIPABORT(); } lb = SCIPvarGetLbGlobal(vars[i]); ub = SCIPvarGetUbGlobal(vars[i]); if( SCIPisLT(scip, solval, lb) || SCIPisGT(scip, solval, ub) ) { SCIPerrorMessage("solution value %.15g of <%s> outside bounds loc=[%.15g,%.15g], glb=[%.15g,%.15g]\n", solval, SCIPvarGetName(vars[i]), lb, ub, SCIPvarGetLbGlobal(vars[i]), SCIPvarGetUbGlobal(vars[i])); SCIPABORT(); } SCIP_CALL( SCIPfixVar(scip, vars[i], solval, &infeasible, &fixed) ); if( infeasible ) *result = SCIP_CUTOFF; else if( fixed ) *result = SCIP_REDUCEDDOM; } return SCIP_OKAY; }