/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the * score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreGuideddiving) { SCIP_SOL* bestsol; SCIP_Real bestsolval; SCIP_Real obj; SCIP_Real objnorm; SCIP_Real objgain; bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); assert(!SCIPsolIsOriginal(bestsol)); bestsolval = SCIPgetSolVal(scip, bestsol, cand); /* variable should be rounded (guided) into the direction of its incumbent solution value */ if( candsol < bestsolval ) *roundup = TRUE; else *roundup = FALSE; obj = SCIPvarGetObj(cand); objnorm = SCIPgetObjNorm(scip); /* divide by objective norm to normalize obj into [-1,1] */ if( SCIPisPositive(scip, objnorm) ) obj /= objnorm; /* calculate objective gain and fractionality for the selected rounding direction */ if( *roundup ) { candsfrac = 1.0 - candsfrac; objgain = obj * candsfrac; } else objgain = -obj * candsfrac; assert(objgain >= -1.0 && objgain <= 1.0); /* penalize too small fractions */ if( candsfrac < 0.01 ) candsfrac *= 0.1; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(cand) ) candsfrac *= 0.1; /* prefer variables which cannot be rounded by scoring their fractionality */ if( !(SCIPvarMayRoundDown(cand) || SCIPvarMayRoundUp(cand)) ) *score = -candsfrac; else *score = -2.0 - objgain; return SCIP_OKAY; }
static void calcPscostQuot( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< problem variable */ SCIP_Real primsol, /**< primal solution of variable */ SCIP_Real frac, /**< fractionality of variable */ int rounddir, /**< -1: round down, +1: round up, 0: select due to pseudo cost values */ SCIP_Real* pscostquot, /**< pointer to store pseudo cost quotient */ SCIP_Bool* roundup /**< pointer to store whether the variable should be rounded up */ ) { SCIP_Real pscostdown; SCIP_Real pscostup; assert(pscostquot != NULL); assert(roundup != NULL); /* bound fractions to not prefer variables that are nearly integral */ frac = MAX(frac, 0.1); frac = MIN(frac, 0.9); /* get pseudo cost quotient */ pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0-frac); pscostup = SCIPgetVarPseudocostVal(scip, var, 1.0-frac); assert(pscostdown >= 0.0 && pscostup >= 0.0); /* choose rounding direction */ if( rounddir == -1 ) *roundup = FALSE; else if( rounddir == +1 ) *roundup = TRUE; else if( frac < 0.3 ) *roundup = FALSE; else if( frac > 0.7 ) *roundup = TRUE; else if( primsol < SCIPvarGetRootSol(var) - 0.4 ) *roundup = FALSE; else if( primsol > SCIPvarGetRootSol(var) + 0.4 ) *roundup = TRUE; else if( pscostdown < pscostup ) *roundup = FALSE; else *roundup = TRUE; /* calculate pseudo cost quotient */ if( *roundup ) *pscostquot = sqrt(frac) * (1.0+pscostdown) / (1.0+pscostup); else *pscostquot = sqrt(1.0-frac) * (1.0+pscostup) / (1.0+pscostdown); /* prefer decisions on binary variables */ if( SCIPvarIsBinary(var) ) (*pscostquot) *= 1000.0; }
/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the * score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreActconsdiving) { SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Real downscore; SCIP_Real upscore; mayrounddown = SCIPvarMayRoundDown(cand); mayroundup = SCIPvarMayRoundUp(cand); /* first, calculate the variable score */ assert(SCIPdivesetGetWorkSolution(diveset) != NULL); *score = getNActiveConsScore(scip, SCIPdivesetGetWorkSolution(diveset), cand, &downscore, &upscore); /* get the rounding direction: prefer an unroundable direction */ if( mayrounddown && mayroundup ) *roundup = (candsfrac > 0.5); else if( mayrounddown || mayroundup ) *roundup = mayrounddown; else *roundup = (downscore > upscore); if( *roundup ) candsfrac = 1.0 - candsfrac; /* penalize too small fractions */ if( candsfrac < 0.01 ) (*score) *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(cand) ) (*score) *= 0.01; /* penalize variable if it may be rounded */ if( mayrounddown || mayroundup ) *score -= 3.0; assert(!(mayrounddown || mayroundup) || *score <= 0.0); return SCIP_OKAY; }
/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the * score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreFracdiving) { SCIP_Real obj; SCIP_Real objnorm; SCIP_Real objgain; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; /* score fractionality if candidate is an SOS1 variable */ if ( divetype == SCIP_DIVETYPE_SOS1VARIABLE ) { *score = candsfrac; /* 'round' in nonzero direction, i.e., fix the candidates neighbors in the conflict graph to zero */ *roundup = SCIPisFeasPositive(scip, candsol); return SCIP_OKAY; } mayrounddown = SCIPvarMayRoundDown(cand); mayroundup = SCIPvarMayRoundUp(cand); /* choose rounding direction: * - if variable may be rounded in either both or neither direction, 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 = mayrounddown; else *roundup = (candsfrac > 0.5); obj = SCIPvarGetObj(cand); objnorm = SCIPgetObjNorm(scip); /* divide by objective norm to normalize obj into [-1,1] */ if( SCIPisPositive(scip, objnorm) ) obj /= objnorm; /* calculate objective gain and fractionality for the selected rounding direction */ if( *roundup ) { candsfrac = 1.0 - candsfrac; objgain = obj * candsfrac; } else objgain = -obj * candsfrac; assert(objgain >= -1.0 && objgain <= 1.0); /* penalize too small fractions */ if( candsfrac < 0.01 ) candsfrac += 10.0; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(cand) ) candsfrac *= 1000.0; /* prefer variables which cannot be rounded by scoring their fractionality */ if( !(mayrounddown || mayroundup) ) *score = -candsfrac; else *score = -2.0 - objgain; 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; }
/** 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; }
/** read fixed variable */ static SCIP_RETCODE getFixedVariable( SCIP* scip, /**< SCIP data structure */ CIPINPUT* cipinput /**< CIP parsing data */ ) { SCIP_Bool success; SCIP_VAR* var; char* buf; char* endptr; char name[SCIP_MAXSTRLEN]; buf = cipinput->strbuf; if( strncmp(buf, "CONSTRAINTS", 11) == 0 ) cipinput->section = CIP_CONSTRAINTS; else if( strncmp(buf, "END", 3) == 0 ) cipinput->section = CIP_END; if( cipinput->section != CIP_FIXEDVARS ) return SCIP_OKAY; SCIPdebugMessage("parse fixed variable\n"); /* parse the variable */ SCIP_CALL( SCIPparseVar(scip, &var, buf, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL, &endptr, &success) ); if( !success ) { SCIPerrorMessage("syntax error in variable information (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } /* skip intermediate stuff */ buf = endptr; while ( *buf != '\0' && (*buf == ' ' || *buf == ',') ) ++buf; /* check whether variable is fixed */ if ( strncmp(buf, "fixed:", 6) == 0 ) { SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); } else if ( strncmp(buf, "negated:", 8) == 0 ) { SCIP_CONS* lincons; SCIP_VAR* negvar; SCIP_Real vals[2]; SCIP_VAR* vars[2]; buf += 8; /* we can just parse the next variable (ignoring all other information in between) */ SCIP_CALL( SCIPparseVarName(scip, buf, &negvar, &endptr) ); if ( negvar == NULL ) { SCIPerrorMessage("could not parse negated variable (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } assert(SCIPvarIsBinary(var)); assert(SCIPvarIsBinary(negvar)); SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebugMessage("creating negated variable <%s> (of <%s>) ...\n", SCIPvarGetName(var), SCIPvarGetName(negvar) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); /* add linear constraint for negation */ (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "neg_%s", SCIPvarGetName(var) ); vars[0] = var; vars[1] = negvar; vals[0] = 1.0; vals[1] = 1.0; SCIPdebugMessage("coupling constraint:\n"); SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, 2, vars, vals, 1.0, 1.0, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) ); SCIPdebugPrintCons(scip, lincons, NULL); SCIP_CALL( SCIPaddCons(scip, lincons) ); SCIP_CALL( SCIPreleaseCons(scip, &lincons) ); } else if ( strncmp(buf, "aggregated:", 11) == 0 ) { /* handle (multi-)aggregated variables */ SCIP_CONS* lincons; SCIP_Real* vals; SCIP_VAR** vars; SCIP_Real rhs = 0.0; const char* str; int nvarssize = 20; int requsize; int nvars; buf += 11; SCIPdebugMessage("parsing aggregated variable <%s> ...\n", SCIPvarGetName(var)); /* first parse constant */ if ( ! SCIPstrToRealValue(buf, &rhs, &endptr) ) { SCIPerrorMessage("expected constant when aggregated variable information (line: %d):\n%s\n", cipinput->linenumber, buf); cipinput->haserror = TRUE; return SCIP_OKAY; } /* check whether constant is 0.0 */ str = endptr; while ( *str != '\0' && isspace(*str) ) ++str; /* if next char is '<' we found a variable -> constant is 0 */ if ( *str != '<' ) { SCIPdebugMessage("constant: %f\n", rhs); buf = endptr; } else { /* otherwise keep buf */ rhs = 0.0; } /* initialize buffers for storing the variables and values */ SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvarssize) ); SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvarssize) ); vars[0] = var; vals[0] = -1.0; --nvarssize; /* parse linear sum to get variables and coefficients */ SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) ); if ( success && requsize > nvarssize ) { /* realloc buffers and try again */ nvarssize = requsize; SCIP_CALL( SCIPreallocBufferArray(scip, &vars, nvarssize + 1) ); SCIP_CALL( SCIPreallocBufferArray(scip, &vals, nvarssize + 1) ); SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) ); assert( ! success || requsize <= nvarssize); /* if successful, then should have had enough space now */ } if( success ) { /* add aggregated variable */ SCIP_CALL( SCIPaddVar(scip, var) ); /* special handling of variables that seem to be slack variables of indicator constraints */ str = SCIPvarGetName(var); if ( strncmp(str, "indslack", 8) == 0 ) { (void) strcpy(name, "indlin"); (void) strncat(name, str+8, SCIP_MAXSTRLEN-7); } else if ( strncmp(str, "t_indslack", 10) == 0 ) { (void) strcpy(name, "indlin"); (void) strncat(name, str+10, SCIP_MAXSTRLEN-7); } else (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var) ); /* add linear constraint for (multi-)aggregation */ SCIPdebugMessage("coupling constraint:\n"); SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars + 1, vars, vals, -rhs, -rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) ); SCIPdebugPrintCons(scip, lincons, NULL); SCIP_CALL( SCIPaddCons(scip, lincons) ); SCIP_CALL( SCIPreleaseCons(scip, &lincons) ); } else { SCIPwarningMessage(scip, "Could not read (multi-)aggregated variable <%s>: dependent variables unkown - consider changing the order (line: %d):\n%s\n", SCIPvarGetName(var), cipinput->linenumber, buf); } SCIPfreeBufferArray(scip, &vals); SCIPfreeBufferArray(scip, &vars); } else { SCIPerrorMessage("unknown section when parsing variables (line: %d):\n%s\n", cipinput->linenumber, buf); cipinput->haserror = TRUE; return SCIP_OKAY; } SCIP_CALL( SCIPreleaseVar(scip, &var) ); return SCIP_OKAY; }
/** calculate the branching score of a variable, depending on the chosen score parameter */ static SCIP_RETCODE calcBranchScore( SCIP* scip, /**< current SCIP */ SCIP_HEURDATA* heurdata, /**< branch rule data */ SCIP_VAR* var, /**< candidate variable */ SCIP_Real lpsolval, /**< current fractional LP-relaxation solution value */ SCIP_Real* upscore, /**< pointer to store the variable score when branching on it in upward direction */ SCIP_Real* downscore, /**< pointer to store the variable score when branching on it in downward direction */ char scoreparam /**< the score parameter of this heuristic */ ) { SCIP_COL* varcol; SCIP_ROW** colrows; SCIP_Real* rowvals; SCIP_Real varlb; SCIP_Real varub; SCIP_Real squaredbounddiff; /* current squared difference of variable bounds (ub - lb)^2 */ SCIP_Real newub; /* new upper bound if branching downwards */ SCIP_Real newlb; /* new lower bound if branching upwards */ SCIP_Real squaredbounddiffup; /* squared difference after branching upwards (ub - lb')^2 */ SCIP_Real squaredbounddiffdown; /* squared difference after branching downwards (ub' - lb)^2 */ SCIP_Real currentmean; /* current mean value of variable uniform distribution */ SCIP_Real meanup; /* mean value of variable uniform distribution after branching up */ SCIP_Real meandown; /* mean value of variable uniform distribution after branching down*/ SCIP_VARTYPE vartype; int ncolrows; int i; SCIP_Bool onlyactiverows; /* should only rows which are active at the current node be considered? */ assert(scip != NULL); assert(var != NULL); assert(upscore != NULL); assert(downscore != NULL); assert(!SCIPisIntegral(scip, lpsolval) || SCIPvarIsBinary(var)); assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); varcol = SCIPvarGetCol(var); assert(varcol != NULL); colrows = SCIPcolGetRows(varcol); rowvals = SCIPcolGetVals(varcol); ncolrows = SCIPcolGetNNonz(varcol); varlb = SCIPvarGetLbLocal(var); varub = SCIPvarGetUbLocal(var); assert(SCIPisFeasLT(scip, varlb, varub)); vartype = SCIPvarGetType(var); /* calculate mean and variance of variable uniform distribution before and after branching */ currentmean = 0.0; squaredbounddiff = 0.0; SCIPvarCalcDistributionParameters(scip, varlb, varub, vartype, ¤tmean, &squaredbounddiff); /* unfixed binary variables may have an integer solution value in the LP solution, eg, at the presence of indicator constraints */ if( !SCIPvarIsBinary(var) ) { newlb = SCIPfeasCeil(scip, lpsolval); newub = SCIPfeasFloor(scip, lpsolval); } else { newlb = 1.0; newub = 0.0; } /* calculate the variable's uniform distribution after branching up and down, respectively. */ squaredbounddiffup = 0.0; meanup = 0.0; SCIPvarCalcDistributionParameters(scip, newlb, varub, vartype, &meanup, &squaredbounddiffup); /* calculate the distribution mean and variance for a variable with finite lower bound */ squaredbounddiffdown = 0.0; meandown = 0.0; SCIPvarCalcDistributionParameters(scip, varlb, newub, vartype, &meandown, &squaredbounddiffdown); /* initialize the variable's up and down score */ *upscore = 0.0; *downscore = 0.0; onlyactiverows = FALSE; /* loop over the variable rows and calculate the up and down score */ for( i = 0; i < ncolrows; ++i ) { SCIP_ROW* row; SCIP_Real changedrowmean; SCIP_Real rowmean; SCIP_Real rowvariance; SCIP_Real changedrowvariance; SCIP_Real currentrowprob; SCIP_Real newrowprobup; SCIP_Real newrowprobdown; SCIP_Real squaredcoeff; SCIP_Real rowval; int rowinfinitiesdown; int rowinfinitiesup; int rowpos; row = colrows[i]; rowval = rowvals[i]; assert(row != NULL); /* we access the rows by their index */ rowpos = SCIProwGetIndex(row); /* skip non-active rows if the user parameter was set this way */ if( onlyactiverows && SCIPisSumPositive(scip, SCIPgetRowLPFeasibility(scip, row)) ) continue; /* call method to ensure sufficient data capacity */ SCIP_CALL( heurdataEnsureArraySize(scip, heurdata, rowpos) ); /* calculate row activity distribution if this is the first candidate to appear in this row */ if( heurdata->rowmeans[rowpos] == SCIP_INVALID ) /*lint !e777 doesn't like comparing floats for equality */ { rowCalculateGauss(scip, heurdata, row, &heurdata->rowmeans[rowpos], &heurdata->rowvariances[rowpos], &heurdata->rowinfinitiesdown[rowpos], &heurdata->rowinfinitiesup[rowpos]); } /* retrieve the row distribution parameters from the branch rule data */ rowmean = heurdata->rowmeans[rowpos]; rowvariance = heurdata->rowvariances[rowpos]; rowinfinitiesdown = heurdata->rowinfinitiesdown[rowpos]; rowinfinitiesup = heurdata->rowinfinitiesup[rowpos]; assert(!SCIPisNegative(scip, rowvariance)); currentrowprob = SCIProwCalcProbability(scip, row, rowmean, rowvariance, rowinfinitiesdown, rowinfinitiesup); /* get variable's current expected contribution to row activity */ squaredcoeff = SQUARED(rowval); /* first, get the probability change for the row if the variable is branched on upwards. The probability * can only be affected if the variable upper bound is finite */ if( !SCIPisInfinity(scip, varub) ) { int rowinftiesdownafterbranch; int rowinftiesupafterbranch; /* calculate how branching would affect the row parameters */ changedrowmean = rowmean + rowval * (meanup - currentmean); changedrowvariance = rowvariance + squaredcoeff * (squaredbounddiffup - squaredbounddiff); changedrowvariance = MAX(0.0, changedrowvariance); rowinftiesdownafterbranch = rowinfinitiesdown; rowinftiesupafterbranch = rowinfinitiesup; /* account for changes of the row's infinite bound contributions */ if( SCIPisInfinity(scip, -varlb) && rowval < 0.0 ) rowinftiesupafterbranch--; if( SCIPisInfinity(scip, -varlb) && rowval > 0.0 ) rowinftiesdownafterbranch--; assert(rowinftiesupafterbranch >= 0); assert(rowinftiesdownafterbranch >= 0); newrowprobup = SCIProwCalcProbability(scip, row, changedrowmean, changedrowvariance, rowinftiesdownafterbranch, rowinftiesupafterbranch); } else newrowprobup = currentrowprob; /* do the same for the other branching direction */ if( !SCIPisInfinity(scip, varlb) ) { int rowinftiesdownafterbranch; int rowinftiesupafterbranch; changedrowmean = rowmean + rowval * (meandown - currentmean); changedrowvariance = rowvariance + squaredcoeff * (squaredbounddiffdown - squaredbounddiff); changedrowvariance = MAX(0.0, changedrowvariance); rowinftiesdownafterbranch = rowinfinitiesdown; rowinftiesupafterbranch = rowinfinitiesup; /* account for changes of the row's infinite bound contributions */ if( SCIPisInfinity(scip, varub) && rowval > 0.0 ) rowinftiesupafterbranch -= 1; if( SCIPisInfinity(scip, varub) && rowval < 0.0 ) rowinftiesdownafterbranch -= 1; assert(rowinftiesdownafterbranch >= 0); assert(rowinftiesupafterbranch >= 0); newrowprobdown = SCIProwCalcProbability(scip, row, changedrowmean, changedrowvariance, rowinftiesdownafterbranch, rowinftiesupafterbranch); } else newrowprobdown = currentrowprob; /* update the up and down score depending on the chosen scoring parameter */ SCIP_CALL( SCIPupdateDistributionScore(scip, currentrowprob, newrowprobup, newrowprobdown, upscore, downscore, scoreparam) ); SCIPdebugMessage(" Variable %s changes probability of row %s from %g to %g (branch up) or %g;\n", SCIPvarGetName(var), SCIProwGetName(row), currentrowprob, newrowprobup, newrowprobdown); SCIPdebugMessage(" --> new variable score: %g (for branching up), %g (for branching down)\n", *upscore, *downscore); } return SCIP_OKAY; }