/** 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; }
/** 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; }
/** checks if a given branching candidate is better than a previous one and updates the best branching candidate accordingly */ static SCIP_RETCODE updateBestCandidate( SCIP* scip, /**< SCIP data structure */ SCIP_BRANCHRULEDATA* branchruledata, /**< branching rule data */ SCIP_VAR** bestvar, /**< best branching candidate */ SCIP_Real* bestbrpoint, /**< branching point for best branching candidate */ SCIP_Real* bestscore, /**< score of best branching candidate */ SCIP_VAR* cand, /**< branching candidate to consider */ SCIP_Real candscoremin, /**< minimal score of branching candidate */ SCIP_Real candscoremax, /**< maximal score of branching candidate */ SCIP_Real candscoresum, /**< sum of scores of branching candidate */ SCIP_Real candsol /**< proposed branching point of branching candidate */ ) { SCIP_Real candbrpoint; SCIP_Real branchscore; SCIP_Real deltaminus; SCIP_Real deltaplus; SCIP_Real pscostdown; SCIP_Real pscostup; char strategy; assert(scip != NULL); assert(branchruledata != NULL); assert(bestvar != NULL); assert(bestbrpoint != NULL); assert(bestscore != NULL); assert(cand != NULL); /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */ assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) || SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR); if( SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR ) { /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */ SCIP_VAR** multvars; int nmultvars; int i; SCIP_Bool success; SCIP_Real multvarlb; SCIP_Real multvarub; cand = SCIPvarGetProbvar(cand); multvars = SCIPvarGetMultaggrVars(cand); nmultvars = SCIPvarGetMultaggrNVars(cand); /* if we have a candidate branching point, then first register only aggregation variables * for which we can compute a corresponding branching point too (see also comments below) * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol */ success = FALSE; if( candsol != SCIP_INVALID ) /*lint !e777*/ { SCIP_Real* multscalars; SCIP_Real minact; SCIP_Real maxact; SCIP_Real aggrvarsol; SCIP_Real aggrvarsol1; SCIP_Real aggrvarsol2; multscalars = SCIPvarGetMultaggrScalars(cand); /* for computing the branching point, we need the current bounds of the multi-aggregated variable */ minact = SCIPcomputeVarLbLocal(scip, cand); maxact = SCIPcomputeVarUbLocal(scip, cand); for( i = 0; i < nmultvars; ++i ) { /* skip fixed variables */ multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]); multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]); if( SCIPisEQ(scip, multvarlb, multvarub) ) continue; assert(multscalars != NULL); assert(multscalars[i] != 0.0); /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node * will be candsol by a clever choice for the branching point of multvars[i], * but we can try to ensure that at least one of them will be at candsol */ if( multscalars[i] > 0.0 ) { /* cand >= candsol * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i] * = (candsol - maxact) / multscalars[i] + ub(multvars[i]) */ aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub; /* cand <= candsol * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i] * = (candsol - minact) / multscalars[i] + lb(multvars[i]) */ aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb; } else { /* cand >= candsol * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i] * = (candsol - maxact) / multscalars[i] + lb(multvars[i]) */ aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb; /* cand <= candsol * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i] * = (candsol - minact) / multscalars[i] + ub(multvars[i]) */ aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub; } /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i]) * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one * if both are out of bounds, then give up * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???) */ if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) ) { if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) ) continue; else aggrvarsol = aggrvarsol2; } else { if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) ) aggrvarsol = aggrvarsol1; else aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2; } success = TRUE; SCIP_CALL( updateBestCandidate(scip, branchruledata, bestvar, bestbrpoint, bestscore, multvars[i], candscoremin, candscoremax, candscoresum, aggrvarsol) ); } } if( !success ) for( i = 0; i < nmultvars; ++i ) { /* skip fixed variables */ multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]); multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]); if( SCIPisEQ(scip, multvarlb, multvarub) ) continue; SCIP_CALL( updateBestCandidate(scip, branchruledata, bestvar, bestbrpoint, bestscore, multvars[i], candscoremin, candscoremax, candscoresum, SCIP_INVALID) ); } assert(*bestvar != NULL); /* if all variables were fixed, something is strange */ return SCIP_OKAY; } /* select branching point for this variable */ candbrpoint = SCIPgetBranchingPoint(scip, cand, candsol); assert(candbrpoint >= SCIPvarGetLbLocal(cand)); assert(candbrpoint <= SCIPvarGetUbLocal(cand)); /* we cannot branch on a huge value for a discrete variable, because we simply cannot enumerate such huge integer values in floating point * arithmetics */ if( SCIPvarGetType(cand) != SCIP_VARTYPE_CONTINUOUS && (SCIPisHugeValue(scip, candbrpoint) || SCIPisHugeValue(scip, -candbrpoint)) ) return SCIP_OKAY; assert(SCIPvarGetType(cand) == SCIP_VARTYPE_CONTINUOUS || !SCIPisIntegral(scip, candbrpoint)); if( SCIPvarGetType(cand) == SCIP_VARTYPE_CONTINUOUS ) strategy = (branchruledata->strategy == 'u' ? branchruledata->updatestrategy : branchruledata->strategy); else strategy = (branchruledata->strategy == 'u' ? 'l' : branchruledata->strategy); switch( strategy ) { case 'l': if( SCIPisInfinity(scip, SCIPgetSolVal(scip, NULL, cand)) || SCIPgetSolVal(scip, NULL, cand) <= SCIPadjustedVarUb(scip, cand, candbrpoint) ) deltaminus = 0.0; else deltaminus = SCIPgetSolVal(scip, NULL, cand) - SCIPadjustedVarUb(scip, cand, candbrpoint); if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, NULL, cand)) || SCIPgetSolVal(scip, NULL, cand) >= SCIPadjustedVarLb(scip, cand, candbrpoint) ) deltaplus = 0.0; else deltaplus = SCIPadjustedVarLb(scip, cand, candbrpoint) - SCIPgetSolVal(scip, NULL, cand); break; case 'd': if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) ) deltaminus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaminus = SCIPadjustedVarUb(scip, cand, candbrpoint) - SCIPvarGetLbLocal(cand); if( SCIPisInfinity(scip, SCIPvarGetUbLocal(cand)) ) deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaplus = SCIPvarGetUbLocal(cand) - SCIPadjustedVarLb(scip, cand, candbrpoint); break; case 's': if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) ) deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaplus = SCIPadjustedVarUb(scip, cand, candbrpoint) - SCIPvarGetLbLocal(cand); if( SCIPisInfinity(scip, SCIPvarGetUbLocal(cand)) ) deltaminus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaminus = SCIPvarGetUbLocal(cand) - SCIPadjustedVarLb(scip, cand, candbrpoint); break; case 'v': deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); deltaminus = deltaplus; break; default : SCIPerrorMessage("branching strategy %c unknown\n", strategy); SCIPABORT(); return SCIP_INVALIDDATA; /*lint !e527*/ } if( SCIPisInfinity(scip, deltaminus) || SCIPisInfinity(scip, deltaplus) ) { branchscore = SCIPinfinity(scip); } else { pscostdown = SCIPgetVarPseudocostVal(scip, cand, -deltaminus); pscostup = SCIPgetVarPseudocostVal(scip, cand, deltaplus); branchscore = SCIPgetBranchScore(scip, cand, pscostdown, pscostup); assert(!SCIPisNegative(scip, branchscore)); } SCIPdebugMessage("branching score variable <%s>[%g,%g] = %g; wscore = %g; type=%d bestbrscore=%g\n", SCIPvarGetName(cand), SCIPvarGetLbLocal(cand), SCIPvarGetUbLocal(cand), branchscore, WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum), SCIPvarGetType(cand), *bestscore); if( SCIPisInfinity(scip, branchscore) ) branchscore = 0.9*SCIPinfinity(scip); if( SCIPisSumGT(scip, branchscore, *bestscore) ) { (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } else if( SCIPisSumEQ(scip, branchscore, *bestscore) && !(SCIPisInfinity(scip, -SCIPvarGetLbLocal(*bestvar)) && SCIPisInfinity(scip, SCIPvarGetUbLocal(*bestvar))) ) { /* if best candidate so far is not unbounded to both sides, maybe take new candidate */ if( (SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(cand))) && (SCIPisInfinity(scip, -SCIPvarGetLbLocal(*bestvar)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(*bestvar))) ) { /* if both variables are unbounded but one of them is bounded on one side, take the one with the larger bound on this side (hope that this avoids branching on always the same variable) */ if( SCIPvarGetUbLocal(cand) > SCIPvarGetUbLocal(*bestvar) || SCIPvarGetLbLocal(cand) < SCIPvarGetLbLocal(*bestvar) ) { (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } } else if( SCIPvarGetType(*bestvar) == SCIPvarGetType(cand) ) { /* if both have the same type, take the one with larger diameter */ if( SCIPvarGetUbLocal(*bestvar) - SCIPvarGetLbLocal(*bestvar) < SCIPvarGetUbLocal(cand) - SCIPvarGetLbLocal(cand) ) { (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } } else if( SCIPvarGetType(*bestvar) > SCIPvarGetType(cand) ) { /* take the one with better type ("more discrete") */ (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } } return SCIP_OKAY; }
/** returns a score value for the given variable based on the active constraints that the variable appears in */ static SCIP_Real getNActiveConsScore( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< variable to get the score value for */ SCIP_Real* downscore, /**< pointer to store the score for branching downwards */ SCIP_Real* upscore /**< pointer to store the score for branching upwards */ ) { SCIP_COL* col; SCIP_ROW** rows; SCIP_Real* vals; int nrows; int r; int nactrows; SCIP_Real downcoefsum; SCIP_Real upcoefsum; SCIP_Real score; assert(downscore != NULL); assert(upscore != NULL); *downscore = 0.0; *upscore = 0.0; if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN ) return 0.0; col = SCIPvarGetCol(var); assert(col != NULL); rows = SCIPcolGetRows(col); vals = SCIPcolGetVals(col); nrows = SCIPcolGetNLPNonz(col); nactrows = 0; downcoefsum = 0.0; upcoefsum = 0.0; for( r = 0; r < nrows; ++r ) { SCIP_Real activity; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real dualsol; /* calculate number of active constraint sides, i.e., count equations as two */ lhs = SCIProwGetLhs(rows[r]); rhs = SCIProwGetRhs(rows[r]); activity = SCIPgetRowLPActivity(scip, rows[r]); dualsol = SCIProwGetDualsol(rows[r]); if( SCIPisFeasEQ(scip, activity, lhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(rows[r]); if( SCIPisFeasPositive(scip, dualsol) ) { if( coef > 0.0 ) downcoefsum += coef; else upcoefsum -= coef; } } else if( SCIPisFeasEQ(scip, activity, rhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(rows[r]); if( SCIPisFeasNegative(scip, dualsol) ) { if( coef > 0.0 ) upcoefsum += coef; else downcoefsum -= coef; } } } score = 1e-3*nactrows + (downcoefsum + 1e-6) * (upcoefsum + 1e-6); *downscore = -downcoefsum; *upscore = -upcoefsum; return score; }
/** compares the so far best branching candidate with a new candidate and updates best candidate, if new candidate is better */ static void updateBestCandidate( SCIP* scip, /**< SCIP data structure */ SCIP_VAR** bestvar, /**< best branching candidate */ SCIP_Real* bestscore, /**< score of best branching candidate */ SCIP_Real* bestobj, /**< absolute objective value of best branching candidate */ SCIP_Real* bestsol, /**< proposed branching point of best branching candidate */ SCIP_VAR* cand, /**< branching candidate to consider */ SCIP_Real candscore, /**< scoring of branching candidate */ SCIP_Real candsol /**< proposed branching point of branching candidate */ ) { SCIP_Real obj; assert(scip != NULL); assert(bestvar != NULL); assert(bestscore != NULL); assert(bestobj != NULL); assert(*bestobj >= 0.0); assert(cand != NULL); /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */ assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) || SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR); if( SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR ) { /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */ SCIP_VAR** multvars; int nmultvars; int i; SCIP_Bool success; SCIP_Real multvarlb; SCIP_Real multvarub; cand = SCIPvarGetProbvar(cand); multvars = SCIPvarGetMultaggrVars(cand); nmultvars = SCIPvarGetMultaggrNVars(cand); /* if we have a candidate branching point, then first register only aggregation variables * for which we can compute a corresponding branching point too (see also comments below) * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol */ success = FALSE; if( candsol != SCIP_INVALID ) /*lint !e777*/ { SCIP_Real* multscalars; SCIP_Real minact; SCIP_Real maxact; SCIP_Real aggrvarsol; SCIP_Real aggrvarsol1; SCIP_Real aggrvarsol2; multscalars = SCIPvarGetMultaggrScalars(cand); /* for computing the branching point, we need the current bounds of the multi-aggregated variable */ minact = SCIPcomputeVarLbLocal(scip, cand); maxact = SCIPcomputeVarUbLocal(scip, cand); for( i = 0; i < nmultvars; ++i ) { /* skip fixed variables */ multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]); multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]); if( SCIPisEQ(scip, multvarlb, multvarub) ) continue; assert(multscalars != NULL); assert(multscalars[i] != 0.0); /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node * will be candsol by a clever choice for the branching point of multvars[i], * but we can try to ensure that at least one of them will be at candsol */ if( multscalars[i] > 0.0 ) { /* cand >= candsol * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i] * = (candsol - maxact) / multscalars[i] + ub(multvars[i]) */ aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub; /* cand <= candsol * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i] * = (candsol - minact) / multscalars[i] + lb(multvars[i]) */ aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb; } else { /* cand >= candsol * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i] * = (candsol - maxact) / multscalars[i] + lb(multvars[i]) */ aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb; /* cand <= candsol * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i] * = (candsol - minact) / multscalars[i] + ub(multvars[i]) */ aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub; } /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i]) * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one * if both are out of bounds, then give up * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???) */ if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) ) { if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) ) continue; else aggrvarsol = aggrvarsol2; } else { if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) ) aggrvarsol = aggrvarsol1; else aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2; } success = TRUE; updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol, multvars[i], candscore, aggrvarsol); } } if( !success ) for( i = 0; i < nmultvars; ++i ) { /* skip fixed variables */ multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]); multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]); if( SCIPisEQ(scip, multvarlb, multvarub) ) continue; updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol, multvars[i], candscore, SCIP_INVALID); } assert(*bestvar != NULL); /* if all variables were fixed, something is strange */ return; } candscore *= SCIPvarGetBranchFactor(cand); obj = SCIPvarGetObj(cand); obj = REALABS(obj); if( SCIPisInfinity(scip, *bestscore) || (!SCIPisInfinity(scip, candscore) && (SCIPisLT(scip, candscore, *bestscore) || (SCIPisLE(scip, candscore, *bestscore) && obj > *bestobj))) ) { *bestvar = cand; *bestscore = candscore; *bestobj = obj; *bestsol = candsol; } }
/** reads a given xml solution file */ static SCIP_RETCODE readXMLSol( SCIP* scip, /**< SCIP data structure */ const char* filename /**< name of the input file */ ) { SCIP_Bool unknownvariablemessage; SCIP_SOL* sol; SCIP_Bool error; XML_NODE* start; const XML_NODE* varsnode; const XML_NODE* varnode; const char* tag; assert( scip != NULL ); assert( filename != NULL ); /* read xml file */ start = xmlProcess(filename); if( start == NULL ) { SCIPerrorMessage("Some error occured during parsing the XML solution file.\n"); return SCIP_READERROR; } /* create zero solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) ); error = FALSE; /* find variable sections */ tag = "variables"; varsnode = xmlFindNodeMaxdepth(start, tag, 0, 3); if( varsnode == NULL ) { /* free xml data */ xmlFreeNode(start); SCIPerrorMessage("Variable section not found.\n"); return SCIP_READERROR; } /* loop through all variables */ unknownvariablemessage = FALSE; for( varnode = xmlFirstChild(varsnode); varnode != NULL; varnode = xmlNextSibl(varnode) ) { SCIP_VAR* var; const char* varname; const char* varvalue; SCIP_Real value; int nread; /* find variable name */ varname = xmlGetAttrval(varnode, "name"); if( varname == NULL ) { SCIPerrorMessage("Attribute \"name\" of variable not found.\n"); error = TRUE; break; } /* find the variable */ var = SCIPfindVar(scip, varname); if( var == NULL ) { if( !unknownvariablemessage ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "unknown variable <%s> of solution file <%s>\n", varname, filename); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " (further unknown variables are ignored)\n"); unknownvariablemessage = TRUE; } continue; } /* find value of variable */ varvalue = xmlGetAttrval(varnode, "value"); if( varvalue == NULL ) { SCIPerrorMessage("Attribute \"value\" of variable not found.\n"); error = TRUE; break; } /* cast the value */ if( strncasecmp(varvalue, "inv", 3) == 0 ) continue; else if( strncasecmp(varvalue, "+inf", 4) == 0 || strncasecmp(varvalue, "inf", 3) == 0 ) value = SCIPinfinity(scip); else if( strncasecmp(varvalue, "-inf", 4) == 0 ) value = -SCIPinfinity(scip); else { nread = sscanf(varvalue, "%lf", &value); if( nread != 1 ) { SCIPwarningMessage(scip, "invalid solution value <%s> for variable <%s> in XML solution file <%s>\n", varvalue, varname, filename); error = TRUE; break; } } /* set the solution value of the variable, if not multiaggregated */ if( SCIPisTransformed(scip) && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "ignored solution value for multiaggregated variable <%s>\n", SCIPvarGetName(var)); } else { SCIP_RETCODE retcode; retcode = SCIPsetSolVal(scip, sol, var, value); if( retcode == SCIP_INVALIDDATA ) { if( SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_FIXED ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "ignored conflicting solution value for fixed variable <%s>\n", SCIPvarGetName(var)); } else { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "ignored solution value for multiaggregated variable <%s>\n", SCIPvarGetName(var)); } } else { SCIP_CALL( retcode ); } } } if( !error ) { SCIP_Bool stored; /* add and free the solution */ if( SCIPisTransformed(scip) ) { SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, TRUE, TRUE, TRUE, &stored) ); /* display result */ SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "primal solution from solution file <%s> was %s\n", filename, stored ? "accepted" : "rejected - solution is infeasible or objective too poor"); } else { SCIP_CALL( SCIPaddSolFree(scip, &sol, &stored) ); /* display result */ SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "primal solution from solution file <%s> was %s\n", filename, stored ? "accepted as candidate, will be checked when solving starts" : "rejected - solution objective too poor"); } } else { /* free solution */ SCIP_CALL( SCIPfreeSol(scip, &sol) ); /* free xml data */ xmlFreeNode(start); return SCIP_READERROR; } /* free xml data */ xmlFreeNode(start); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecZirounding) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_VAR** zilpcands; SCIP_VAR** slackvars; SCIP_Real* upslacks; SCIP_Real* downslacks; SCIP_Real* activities; SCIP_Real* slackvarcoeffs; SCIP_Bool* rowneedsslackvar; SCIP_ROW** rows; SCIP_Real* lpcandssol; SCIP_Real* solarray; SCIP_Longint nlps; int currentlpcands; int nlpcands; int nimplfracs; int i; int c; int nslacks; int nroundings; SCIP_RETCODE retcode; SCIP_Bool improvementfound; SCIP_Bool numericalerror; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* 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; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation * to number of calls falls below heurdata->stoppercentage */ if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage ) return SCIP_OKAY; /* assure that heuristic has not already been called after the last LP had been solved */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* get fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) ); nlpcands = nlpcands + nimplfracs; /* make sure that there is at least one fractional variable that should be integral */ if( nlpcands == 0 ) return SCIP_OKAY; assert(nlpcands > 0); assert(lpcands != NULL); assert(lpcandssol != NULL); /* get LP rows data */ rows = SCIPgetLPRows(scip); nslacks = SCIPgetNLPRows(scip); /* cannot do anything if LP is empty */ if( nslacks == 0 ) return SCIP_OKAY; assert(rows != NULL); assert(nslacks > 0); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); *result = SCIP_DIDNOTFIND; solarray = NULL; zilpcands = NULL; retcode = SCIP_OKAY; /* copy the current LP solution to the working solution and allocate memory for local data */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &solarray, nlpcands), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &zilpcands, nlpcands), TERMINATE); /* copy necessary data to local arrays */ BMScopyMemoryArray(solarray, lpcandssol, nlpcands); BMScopyMemoryArray(zilpcands, lpcands, nlpcands); /* allocate buffer data arrays */ SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvars, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &upslacks, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &downslacks, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &activities, nslacks), TERMINATE); BMSclearMemoryArray(slackvars, nslacks); BMSclearMemoryArray(slackvarcoeffs, nslacks); BMSclearMemoryArray(rowneedsslackvar, nslacks); numericalerror = FALSE; nroundings = 0; /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */ for( c = 0; c < nlpcands; ++c ) { SCIP_VAR* cand; SCIP_ROW** candrows; int r; int ncandrows; cand = zilpcands[c]; assert(cand != NULL); assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0); candrows = SCIPcolGetRows(SCIPvarGetCol(cand)); ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand)); assert(candrows == NULL || ncandrows > 0); for( r = 0; r < ncandrows; ++r ) { int rowpos; assert(candrows != NULL); /* to please flexelint */ assert(candrows[r] != NULL); rowpos = SCIProwGetLPPos(candrows[r]); if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) ) { rowneedsslackvar[rowpos] = TRUE; SCIPdebugMessage(" Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand)); } } } /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero, * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering */ for( i = 0; i < nslacks; ++i ) { SCIP_ROW* row; SCIP_Real lhs; SCIP_Real rhs; row = rows[i]; assert(row != NULL); lhs = SCIProwGetLhs(row); rhs = SCIProwGetRhs(row); /* get row activity */ activities[i] = SCIPgetRowActivity(scip, row); assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs)); /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */ if( SCIPisInfinity(scip, -lhs) ) downslacks[i] = SCIPinfinity(scip); else downslacks[i] = activities[i] - lhs; if( SCIPisInfinity(scip, rhs) ) upslacks[i] = SCIPinfinity(scip); else upslacks[i] = rhs - activities[i]; SCIPdebugMessage("lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]); /* row is an equation. Try to find a slack variable in the row, i.e., * a continuous variable which occurs only in this row. If no such variable exists, * there is no hope for an IP-feasible solution in this round */ if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] ) { /* @todo: This is only necessary for rows containing fractional variables. */ rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i])); if( slackvars[i] == NULL ) { SCIPdebugMessage("No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row)); goto TERMINATE; } else { SCIP_Real ubslackvar; SCIP_Real lbslackvar; SCIP_Real solvalslackvar; SCIP_Real coeffslackvar; SCIP_Real ubgap; SCIP_Real lbgap; assert(SCIPvarGetType(slackvars[i]) == SCIP_VARTYPE_CONTINUOUS); solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]); ubslackvar = SCIPvarGetUbGlobal(slackvars[i]); lbslackvar = SCIPvarGetLbGlobal(slackvars[i]); coeffslackvar = slackvarcoeffs[i]; assert(!SCIPisFeasZero(scip, coeffslackvar)); ubgap = ubslackvar - solvalslackvar; lbgap = solvalslackvar - lbslackvar; if( SCIPisFeasZero(scip, ubgap) ) ubgap = 0.0; if( SCIPisFeasZero(scip, lbgap) ) lbgap = 0.0; if( SCIPisFeasPositive(scip, coeffslackvar) ) { if( !SCIPisInfinity(scip, lbslackvar) ) upslacks[i] += coeffslackvar * lbgap; else upslacks[i] = SCIPinfinity(scip); if( !SCIPisInfinity(scip, ubslackvar) ) downslacks[i] += coeffslackvar * ubgap; else downslacks[i] = SCIPinfinity(scip); } else { if( !SCIPisInfinity(scip, ubslackvar) ) upslacks[i] -= coeffslackvar * ubgap; else upslacks[i] = SCIPinfinity(scip); if( !SCIPisInfinity(scip, lbslackvar) ) downslacks[i] -= coeffslackvar * lbgap; else downslacks[i] = SCIPinfinity(scip); } SCIPdebugMessage(" Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g \n", SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar, upslacks[i], downslacks[i]); } } /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are * significantly smaller than zero -> terminate */ if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) ) goto TERMINATE; } assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL)); /* initialize number of remaining variables and flag to enter the main loop */ currentlpcands = nlpcands; improvementfound = TRUE; /* iterate over variables as long as there are fractional variables left */ while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) ) { /*lint --e{850}*/ improvementfound = FALSE; nroundings++; SCIPdebugMessage("zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands); /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */ for( c = 0; c < currentlpcands; ++c ) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real upperbound; SCIP_Real lowerbound; SCIP_Real up; SCIP_Real down; SCIP_Real ziup; SCIP_Real zidown; SCIP_Real zicurrent; SCIP_Real shiftval; DIRECTION direction; /* get values from local data */ oldsolval = solarray[c]; var = zilpcands[c]; assert(!SCIPisFeasIntegral(scip, oldsolval)); assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); /* calculate bounds for variable and make sure that there are no numerical inconsistencies */ upperbound = SCIPinfinity(scip); lowerbound = SCIPinfinity(scip); calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror); if( numericalerror ) goto TERMINATE; /* calculate the possible values after shifting */ up = oldsolval + upperbound; down = oldsolval - lowerbound; /* if the variable is integer or implicit binary, do not shift further than the nearest integer */ if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY) { SCIP_Real ceilx; SCIP_Real floorx; ceilx = SCIPfeasCeil(scip, oldsolval); floorx = SCIPfeasFloor(scip, oldsolval); up = MIN(up, ceilx); down = MAX(down, floorx); } /* calculate necessary values */ ziup = getZiValue(scip, up); zidown = getZiValue(scip, down); zicurrent = getZiValue(scip, oldsolval); /* calculate the shifting direction that reduces ZI-value the most, * if both directions improve ZI-value equally, take the direction which improves the objective */ if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) ) { if( SCIPisFeasEQ(scip,ziup, zidown) ) direction = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP; else if( SCIPisFeasLT(scip, zidown, ziup) ) direction = DIRECTION_DOWN; else direction = DIRECTION_UP; /* once a possible shifting direction and value have been found, variable value is updated */ shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval); /* this improves numerical stability in some cases */ if( direction == DIRECTION_UP ) shiftval = MIN(shiftval, upperbound); else shiftval = MIN(shiftval, lowerbound); /* update the solution */ solarray[c] = direction == DIRECTION_UP ? up : down; SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) ); /* update the rows activities and slacks */ SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks, downslacks, activities, slackvars, slackvarcoeffs, nslacks) ); SCIPdebugMessage("zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n", SCIPvarGetIndex(var), oldsolval, shiftval); /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement * might affect many LP rows and their current slacks and thus make further rounding steps possible */ improvementfound = TRUE; } /* if solution value of variable has become feasibly integral due to rounding step, * variable is put at the end of remaining candidates array so as not to be considered in future loops */ if( SCIPisFeasIntegral(scip, solarray[c]) ) { zilpcands[c] = zilpcands[currentlpcands - 1]; solarray[c] = solarray[currentlpcands - 1]; currentlpcands--; /* counter is decreased if end of candidates array has not been reached yet */ if( c < currentlpcands ) c--; } else if( nroundings == heurdata->maxroundingloops - 1 ) goto TERMINATE; } } /* in case that no candidate is left for rounding after the final main loop * the found solution has to be checked for feasibility in the original problem */ if( currentlpcands == 0 ) { SCIP_Bool stored; SCIP_CALL(SCIPtrySol(scip, sol, FALSE, FALSE, TRUE, FALSE, &stored)); if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif SCIPstatisticMessage(" ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol)); *result = SCIP_FOUNDSOL; } } /* free memory for all locally allocated data */ TERMINATE: SCIPfreeBufferArrayNull(scip, &activities); SCIPfreeBufferArrayNull(scip, &rowneedsslackvar); SCIPfreeBufferArrayNull(scip, &slackvarcoeffs); SCIPfreeBufferArrayNull(scip, &downslacks); SCIPfreeBufferArrayNull(scip, &upslacks); SCIPfreeBufferArrayNull(scip, &slackvars); SCIPfreeBufferArrayNull(scip, &zilpcands); SCIPfreeBufferArrayNull(scip, &solarray); return retcode; }
/** problem writing method of reader */ static SCIP_DECL_READERWRITE(readerWriteCip) { /*lint --e{715}*/ SCIP_HASHTABLE* varhash = NULL; SCIP_READERDATA* readerdata; int i; assert(reader != NULL); assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); SCIPinfoMessage(scip, file, "STATISTICS\n"); SCIPinfoMessage(scip, file, " Problem name : %s\n", name); SCIPinfoMessage(scip, file, " Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n", nvars, nbinvars, nintvars, nimplvars, ncontvars); SCIPinfoMessage(scip, file, " Constraints : %d initial, %d maximal\n", startnconss, maxnconss); SCIPinfoMessage(scip, file, "OBJECTIVE\n"); SCIPinfoMessage(scip, file, " Sense : %s\n", objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize"); if( !SCIPisZero(scip, objoffset) ) SCIPinfoMessage(scip, file, " Offset : %+.15g\n", objoffset); if( !SCIPisEQ(scip, objscale, 1.0) ) SCIPinfoMessage(scip, file, " Scale : %.15g\n", objscale); if ( nfixedvars > 0 ) { /* set up hash table for variables that have been written property (used for writing out fixed vars in the right order) */ SCIP_CALL( SCIPhashtableCreate(&varhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * (nvars + nfixedvars)), hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) ); } if ( nvars + nfixedvars > 0 ) { SCIPinfoMessage(scip, file, "VARIABLES\n"); } if( nvars > 0 ) { for( i = 0; i < nvars; ++i ) { SCIP_VAR* var; var = vars[i]; assert( var != NULL ); SCIP_CALL( SCIPprintVar(scip, var, file) ); if ( varhash != NULL ) { /* add free variable to hashtable */ if ( ! SCIPhashtableExists(varhash, (void*) var) ) { SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); } } } } readerdata = SCIPreaderGetData(reader); assert(readerdata != NULL); if( readerdata->writefixedvars && nfixedvars > 0 ) { int nwritten = 0; SCIPinfoMessage(scip, file, "FIXED\n"); /* loop through variables until each has been written after the variables that it depends on have been written; this * requires several runs over the variables, but the depth (= number of loops) is usually small. */ while ( nwritten < nfixedvars ) { SCIPdebugMessage("written %d of %d fixed variables.\n", nwritten, nfixedvars); for (i = 0; i < nfixedvars; ++i) { SCIP_VAR* var; SCIP_VAR* tmpvar; var = fixedvars[i]; assert( var != NULL ); /* skip variables already written */ if ( SCIPhashtableExists(varhash, (void*) var) ) continue; switch ( SCIPvarGetStatus(var) ) { case SCIP_VARSTATUS_FIXED: /* fixed variables can simply be output and added to the hashtable */ SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; break; case SCIP_VARSTATUS_NEGATED: tmpvar = SCIPvarGetNegationVar(var); assert( tmpvar != NULL ); assert( var == SCIPvarGetNegatedVar(tmpvar) ); /* if the negated variable has been written, we can write the current variable */ if ( SCIPhashtableExists(varhash, (void*) tmpvar) ) { SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; } break; case SCIP_VARSTATUS_AGGREGATED: tmpvar = SCIPvarGetAggrVar(var); assert( tmpvar != NULL ); /* if the aggregating variable has been written, we can write the current variable */ if ( SCIPhashtableExists(varhash, (void*) tmpvar) ) { SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; } break; case SCIP_VARSTATUS_MULTAGGR: { SCIP_VAR** aggrvars; int naggrvars; int j; /* get the active representation */ SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) ); naggrvars = SCIPvarGetMultaggrNVars(var); aggrvars = SCIPvarGetMultaggrVars(var); assert(aggrvars != NULL || naggrvars == 0); for (j = 0; j < naggrvars; ++j) { if( !SCIPhashtableExists(varhash, (void*) aggrvars[j]) ) /*lint !e613*/ break; } /* if all multi-aggregating variables have been written, we can write the current variable */ if ( j >= naggrvars ) { SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; } break; } case SCIP_VARSTATUS_ORIGINAL: case SCIP_VARSTATUS_LOOSE: case SCIP_VARSTATUS_COLUMN: SCIPerrorMessage("Only fixed variables are allowed to be present in fixedvars list.\n"); SCIPABORT(); return SCIP_ERROR; /*lint !e527*/ } } } } if( nconss > 0 ) { SCIPinfoMessage(scip, file, "CONSTRAINTS\n"); for( i = 0; i < nconss; ++i ) { SCIP_CALL( SCIPprintCons(scip, conss[i], file) ); SCIPinfoMessage(scip, file, ";\n"); } } SCIPinfoMessage(scip, file, "END\n"); *result = SCIP_SUCCESS; if( nfixedvars > 0 ) SCIPhashtableFree(&varhash); else assert(varhash == NULL); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecOneopt) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* bestsol; /* incumbent solution */ SCIP_SOL* worksol; /* heuristic's working solution */ SCIP_VAR** vars; /* SCIP variables */ SCIP_VAR** shiftcands; /* shiftable variables */ SCIP_ROW** lprows; /* SCIP LP rows */ SCIP_Real* activities; /* row activities for working solution */ SCIP_Real* shiftvals; SCIP_Real lb; SCIP_Real ub; SCIP_Bool localrows; SCIP_Bool valid; int nchgbound; int nbinvars; int nintvars; int nvars; int nlprows; int i; int nshiftcands; int shiftcandssize; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); *result = SCIP_DELAYED; /* we only want to process each solution once */ bestsol = SCIPgetBestSol(scip); if( bestsol == NULL || heurdata->lastsolindex == SCIPsolGetIndex(bestsol) ) return SCIP_OKAY; /* reset the timing mask to its default value (at the root node it could be different) */ if( SCIPgetNNodes(scip) > 1 ) SCIPheurSetTimingmask(heur, HEUR_TIMING); /* get problem variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); nintvars += nbinvars; /* do not run if there are no discrete variables */ if( nintvars == 0 ) { *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } if( heurtiming == SCIP_HEURTIMING_BEFOREPRESOL ) { SCIP* subscip; /* the subproblem created by zeroobj */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_Real* subsolvals; /* solution values of the subproblem */ SCIP_Real timelimit; /* time limit for zeroobj subproblem */ SCIP_Real memorylimit; /* memory limit for zeroobj subproblem */ SCIP_SOL* startsol; SCIP_SOL** subsols; int nsubsols; if( !heurdata->beforepresol ) return SCIP_OKAY; /* check whether there is enough time and memory left */ timelimit = 0.0; memorylimit = 0.0; SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) return SCIP_OKAY; /* initialize the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); /* copy complete SCIP instance */ valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "oneopt", TRUE, FALSE, TRUE, &valid) ); SCIP_CALL( SCIPtransformProb(subscip) ); /* get variable image */ for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* copy the solution */ SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) ); SCIP_CALL( SCIPgetSolVals(scip, bestsol, nvars, vars, subsolvals) ); /* create start solution for the subproblem */ SCIP_CALL( SCIPcreateOrigSol(subscip, &startsol, NULL) ); SCIP_CALL( SCIPsetSolVals(subscip, startsol, nvars, subvars, subsolvals) ); /* try to add new solution to sub-SCIP and free it immediately */ valid = FALSE; SCIP_CALL( SCIPtrySolFree(subscip, &startsol, FALSE, FALSE, FALSE, FALSE, &valid) ); SCIPfreeBufferArray(scip, &subsolvals); SCIPhashmapFree(&varmapfw); /* disable statistic timing inside sub SCIP */ SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) ); /* deactivate basically everything except oneopt in the sub-SCIP */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetHeuristics(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* if necessary, some of the parameters have to be unfixed first */ if( SCIPisParamFixed(subscip, "lp/solvefreq") ) { SCIPwarningMessage(scip, "unfixing parameter lp/solvefreq in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "lp/solvefreq") ); } SCIP_CALL( SCIPsetIntParam(subscip, "lp/solvefreq", -1) ); if( SCIPisParamFixed(subscip, "heuristics/oneopt/freq") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/freq in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/freq") ); } SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/oneopt/freq", 1) ); if( SCIPisParamFixed(subscip, "heuristics/oneopt/forcelpconstruction") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/forcelpconstruction in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/forcelpconstruction") ); } SCIP_CALL( SCIPsetBoolParam(subscip, "heuristics/oneopt/forcelpconstruction", TRUE) ); /* avoid recursive call, which would lead to an endless loop */ if( SCIPisParamFixed(subscip, "heuristics/oneopt/beforepresol") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/beforepresol in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/beforepresol") ); } SCIP_CALL( SCIPsetBoolParam(subscip, "heuristics/oneopt/beforepresol", FALSE) ); if( valid ) { retcode = SCIPsolve(subscip); /* errors in solving the subproblem should not kill the overall solving process; * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in zeroobj heuristic; sub-SCIP terminated with code <%d>\n",retcode); } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif } /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); valid = FALSE; for( i = 0; i < nsubsols && !valid; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &valid) ); if( valid ) *result = SCIP_FOUNDSOL; } /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; } /* we can only work on solutions valid in the transformed space */ if( SCIPsolIsOriginal(bestsol) ) return SCIP_OKAY; if( heurtiming == SCIP_HEURTIMING_BEFORENODE && (SCIPhasCurrentNodeLP(scip) || heurdata->forcelpconstruction) ) { SCIP_Bool cutoff; cutoff = FALSE; SCIP_CALL( SCIPconstructLP(scip, &cutoff) ); SCIP_CALL( SCIPflushLP(scip) ); /* get problem variables again, SCIPconstructLP() might have added new variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); nintvars += nbinvars; } /* we need an LP */ if( SCIPgetNLPRows(scip) == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; nchgbound = 0; /* initialize data */ nshiftcands = 0; shiftcandssize = 8; heurdata->lastsolindex = SCIPsolGetIndex(bestsol); SCIP_CALL( SCIPcreateSolCopy(scip, &worksol, bestsol) ); SCIPsolSetHeur(worksol,heur); SCIPdebugMessage("Starting bound adjustment in 1-opt heuristic\n"); /* maybe change solution values due to global bound changes first */ for( i = nvars - 1; i >= 0; --i ) { SCIP_VAR* var; SCIP_Real solval; var = vars[i]; lb = SCIPvarGetLbGlobal(var); ub = SCIPvarGetUbGlobal(var); solval = SCIPgetSolVal(scip, bestsol,var); /* old solution value is smaller than the actual lower bound */ if( SCIPisFeasLT(scip, solval, lb) ) { /* set the solution value to the global lower bound */ SCIP_CALL( SCIPsetSolVal(scip, worksol, var, lb) ); ++nchgbound; SCIPdebugMessage("var <%s> type %d, old solval %g now fixed to lb %g\n", SCIPvarGetName(var), SCIPvarGetType(var), solval, lb); } /* old solution value is greater than the actual upper bound */ else if( SCIPisFeasGT(scip, solval, SCIPvarGetUbGlobal(var)) ) { /* set the solution value to the global upper bound */ SCIP_CALL( SCIPsetSolVal(scip, worksol, var, ub) ); ++nchgbound; SCIPdebugMessage("var <%s> type %d, old solval %g now fixed to ub %g\n", SCIPvarGetName(var), SCIPvarGetType(var), solval, ub); } } SCIPdebugMessage("number of bound changes (due to global bounds) = %d\n", nchgbound); SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) ); localrows = FALSE; valid = TRUE; /* initialize activities */ for( i = 0; i < nlprows; ++i ) { SCIP_ROW* row; row = lprows[i]; assert(SCIProwGetLPPos(row) == i); if( !SCIProwIsLocal(row) ) { activities[i] = SCIPgetRowSolActivity(scip, row, worksol); SCIPdebugMessage("Row <%s> has activity %g\n", SCIProwGetName(row), activities[i]); if( SCIPisFeasLT(scip, activities[i], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[i], SCIProwGetRhs(row)) ) { valid = FALSE; SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) ); SCIPdebugMessage("row <%s> activity %g violates bounds, lhs = %g, rhs = %g\n", SCIProwGetName(row), activities[i], SCIProwGetLhs(row), SCIProwGetRhs(row)); break; } } else localrows = TRUE; } if( !valid ) { /** @todo try to correct lp rows */ SCIPdebugMessage("Some global bound changes were not valid in lp rows.\n"); goto TERMINATE; } SCIP_CALL( SCIPallocBufferArray(scip, &shiftcands, shiftcandssize) ); SCIP_CALL( SCIPallocBufferArray(scip, &shiftvals, shiftcandssize) ); SCIPdebugMessage("Starting 1-opt heuristic\n"); /* enumerate all integer variables and find out which of them are shiftable */ for( i = 0; i < nintvars; i++ ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { SCIP_Real shiftval; SCIP_Real solval; /* find out whether the variable can be shifted */ solval = SCIPgetSolVal(scip, worksol, vars[i]); shiftval = calcShiftVal(scip, vars[i], solval, activities); /* insert the variable into the list of shifting candidates */ if( !SCIPisFeasZero(scip, shiftval) ) { SCIPdebugMessage(" -> Variable <%s> can be shifted by <%1.1f> \n", SCIPvarGetName(vars[i]), shiftval); if( nshiftcands == shiftcandssize) { shiftcandssize *= 8; SCIP_CALL( SCIPreallocBufferArray(scip, &shiftcands, shiftcandssize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &shiftvals, shiftcandssize) ); } shiftcands[nshiftcands] = vars[i]; shiftvals[nshiftcands] = shiftval; nshiftcands++; } } } /* if at least one variable can be shifted, shift variables sorted by their objective */ if( nshiftcands > 0 ) { SCIP_Real shiftval; SCIP_Real solval; SCIP_VAR* var; /* the case that exactly one variable can be shifted is slightly easier */ if( nshiftcands == 1 ) { var = shiftcands[0]; assert(var != NULL); solval = SCIPgetSolVal(scip, worksol, var); shiftval = shiftvals[0]; assert(!SCIPisFeasZero(scip,shiftval)); SCIPdebugMessage(" Only one shiftcand found, var <%s>, which is now shifted by<%1.1f> \n", SCIPvarGetName(var), shiftval); SCIP_CALL( SCIPsetSolVal(scip, worksol, var, solval+shiftval) ); } else { SCIP_Real* objcoeffs; SCIP_CALL( SCIPallocBufferArray(scip, &objcoeffs, nshiftcands) ); SCIPdebugMessage(" %d shiftcands found \n", nshiftcands); /* sort the variables by their objective, optionally weighted with the shiftval */ if( heurdata->weightedobj ) { for( i = 0; i < nshiftcands; ++i ) objcoeffs[i] = SCIPvarGetObj(shiftcands[i])*shiftvals[i]; } else { for( i = 0; i < nshiftcands; ++i ) objcoeffs[i] = SCIPvarGetObj(shiftcands[i]); } /* sort arrays with respect to the first one */ SCIPsortRealPtr(objcoeffs, (void**)shiftcands, nshiftcands); /* try to shift each variable -> Activities have to be updated */ for( i = 0; i < nshiftcands; ++i ) { var = shiftcands[i]; assert(var != NULL); solval = SCIPgetSolVal(scip, worksol, var); shiftval = calcShiftVal(scip, var, solval, activities); SCIPdebugMessage(" -> Variable <%s> is now shifted by <%1.1f> \n", SCIPvarGetName(vars[i]), shiftval); assert(i > 0 || !SCIPisFeasZero(scip, shiftval)); assert(SCIPisFeasGE(scip, solval+shiftval, SCIPvarGetLbGlobal(var)) && SCIPisFeasLE(scip, solval+shiftval, SCIPvarGetUbGlobal(var))); SCIP_CALL( SCIPsetSolVal(scip, worksol, var, solval+shiftval) ); SCIP_CALL( updateRowActivities(scip, activities, var, shiftval) ); } SCIPfreeBufferArray(scip, &objcoeffs); } /* if the problem is a pure IP, try to install the solution, if it is a MIP, solve LP again to set the continuous * variables to the best possible value */ if( nvars == nintvars || !SCIPhasCurrentNodeLP(scip) || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* since we ignore local rows, we cannot guarantee their feasibility and have to set the checklprows flag to * TRUE if local rows are present */ SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, localrows, &success) ); if( success ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) ); heurdata->lastsolindex = SCIPsolGetIndex(bestsol); *result = SCIP_FOUNDSOL; } } else { SCIP_Bool lperror; #ifdef NDEBUG SCIP_RETCODE retstat; #endif SCIPdebugMessage("shifted solution should be feasible -> solve LP to fix continuous variables to best values\n"); /* start diving to calculate the LP relaxation */ SCIP_CALL( SCIPstartDive(scip) ); /* set the bounds of the variables: fixed for integers, global bounds for continuous */ for( i = 0; i < nvars; ++i ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], SCIPvarGetLbGlobal(vars[i])) ); SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], SCIPvarGetUbGlobal(vars[i])) ); } } /* apply this after global bounds to not cause an error with intermediate empty domains */ for( i = 0; i < nintvars; ++i ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { solval = SCIPgetSolVal(scip, worksol, vars[i]); SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], solval) ); SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], solval) ); } } /* solve LP */ SCIPdebugMessage(" -> old LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip)); /**@todo in case of an MINLP, if SCIPisNLPConstructed() is TRUE, say, rather solve the NLP instead of the LP */ /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ #ifdef NDEBUG retstat = SCIPsolveDiveLP(scip, -1, &lperror, NULL); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Oneopt heuristic; LP solve terminated with code <%d>\n",retstat); } #else SCIP_CALL( SCIPsolveDiveLP(scip, -1, &lperror, NULL) ); #endif SCIPdebugMessage(" -> new LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip)); SCIPdebugMessage(" -> error=%u, status=%d\n", lperror, SCIPgetLPSolstat(scip)); /* check if this is a feasible solution */ if( !lperror && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, worksol) ); SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check solution for feasibility */ if( success ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) ); heurdata->lastsolindex = SCIPsolGetIndex(bestsol); *result = SCIP_FOUNDSOL; } } /* terminate the diving */ SCIP_CALL( SCIPendDive(scip) ); } } SCIPdebugMessage("Finished 1-opt heuristic\n"); SCIPfreeBufferArray(scip, &shiftvals); SCIPfreeBufferArray(scip, &shiftcands); TERMINATE: SCIPfreeBufferArray(scip, &activities); SCIP_CALL( SCIPfreeSol(scip, &worksol) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecSimplerounding) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Longint nlps; int nlpcands; int c; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* on our first call or after each pricing round, calculate the number of roundable variables */ if( heurdata->nroundablevars == -1 || heurtiming == SCIP_HEURTIMING_DURINGPRICINGLOOP ) { SCIP_VAR** vars; int nvars; int nroundablevars; int i; vars = SCIPgetVars(scip); nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); nroundablevars = 0; for( i = 0; i < nvars; ++i ) { if( SCIPvarMayRoundDown(vars[i]) || SCIPvarMayRoundUp(vars[i]) ) nroundablevars++; } heurdata->nroundablevars = nroundablevars; } /* don't call heuristic if there are no roundable variables; except we are called during pricing, in this case we * want to detect a (mixed) integer (LP) solution which is primal feasible */ if( heurdata->nroundablevars == 0 && heurtiming != SCIP_HEURTIMING_DURINGPRICINGLOOP ) return SCIP_OKAY; /* don't call heuristic, if we have already processed the current LP solution */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* get fractional variables, that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL) ); /* only call heuristic, if LP solution is fractional; except we are called during pricing, in this case we * want to detect a (mixed) integer (LP) solution which is primal feasible */ if( nlpcands == 0 && heurtiming != SCIP_HEURTIMING_DURINGPRICINGLOOP ) return SCIP_OKAY; /* don't call heuristic, if there are more fractional variables than roundable ones */ if( nlpcands > heurdata->nroundablevars ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIPdebugMessage("executing simple rounding heuristic: %d fractionals\n", nlpcands); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* round all roundable fractional columns in the corresponding direction as long as no unroundable column was found */ for( c = 0; c < nlpcands; ++c ) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; oldsolval = lpcandssol[c]; assert(!SCIPisFeasIntegral(scip, oldsolval)); var = lpcands[c]; assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); SCIPdebugMessage("simple rounding heuristic: var <%s>, val=%g, rounddown=%u, roundup=%u\n", SCIPvarGetName(var), oldsolval, mayrounddown, mayroundup); /* choose rounding direction */ if( mayrounddown && mayroundup ) { /* we can round in both directions: round in objective function direction */ if( SCIPvarGetObj(var) >= 0.0 ) newsolval = SCIPfeasFloor(scip, oldsolval); else newsolval = SCIPfeasCeil(scip, oldsolval); } else if( mayrounddown ) newsolval = SCIPfeasFloor(scip, oldsolval); else if( mayroundup ) newsolval = SCIPfeasCeil(scip, oldsolval); else break; /* store new solution value */ SCIP_CALL( SCIPsetSolVal(scip, sol, var, newsolval) ); } /* check, if rounding was successful */ if( c == nlpcands ) { SCIP_Bool stored; /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because all fractional * variables were already moved in feasible direction to the next integer */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, FALSE, &stored) ); if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIPprintSol(scip, sol, NULL, FALSE); #endif *result = SCIP_FOUNDSOL; } } return SCIP_OKAY; }
/** returns a score value for the given variable based on the active constraints that the variable appears in */ static SCIP_Real getNActiveConsScore( SCIP* scip, /**< SCIP data structure */ SCIP_SOL* sol, /**< working solution */ SCIP_VAR* var, /**< variable to get the score value for */ SCIP_Real* downscore, /**< pointer to store the score for branching downwards */ SCIP_Real* upscore /**< pointer to store the score for branching upwards */ ) { SCIP_COL* col; SCIP_ROW** rows; SCIP_Real* vals; int nrows; int r; int nactrows; SCIP_Real nlprows; SCIP_Real downcoefsum; SCIP_Real upcoefsum; SCIP_Real score; assert(downscore != NULL); assert(upscore != NULL); *downscore = 0.0; *upscore = 0.0; if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN ) return 0.0; col = SCIPvarGetCol(var); assert(col != NULL); rows = SCIPcolGetRows(col); vals = SCIPcolGetVals(col); nrows = SCIPcolGetNLPNonz(col); nactrows = 0; downcoefsum = 0.0; upcoefsum = 0.0; for( r = 0; r < nrows; ++r ) { SCIP_ROW* row; SCIP_Real activity; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real dualsol; row = rows[r]; /* calculate number of active constraint sides, i.e., count equations as two */ lhs = SCIProwGetLhs(row); rhs = SCIProwGetRhs(row); /* @todo this is suboptimal because activity is calculated by looping over all nonzeros of this row, need to * store LP activities instead (which cannot be retrieved if no LP was solved at this node) */ activity = SCIPgetRowSolActivity(scip, row, sol); dualsol = SCIProwGetDualsol(row); if( SCIPisFeasEQ(scip, activity, lhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(row); if( SCIPisFeasPositive(scip, dualsol) ) { if( coef > 0.0 ) downcoefsum += coef; else upcoefsum -= coef; } } else if( SCIPisFeasEQ(scip, activity, rhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(row); if( SCIPisFeasNegative(scip, dualsol) ) { if( coef > 0.0 ) upcoefsum += coef; else downcoefsum -= coef; } } } /* use the number of LP rows for normalization */ nlprows = (SCIP_Real)SCIPgetNLPRows(scip); upcoefsum /= nlprows; downcoefsum /= nlprows; /* calculate the score using SCIP's branch score. Pass NULL as variable to not have the var branch factor influence * the result */ score = nactrows / nlprows + SCIPgetBranchScore(scip, NULL, downcoefsum, upcoefsum); assert(score <= 3.0); assert(score >= 0.0); *downscore = downcoefsum; *upscore = upcoefsum; return score; }
/** 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; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpStrongcg) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; SCIP_VAR** vars; SCIP_COL** cols; SCIP_ROW** rows; SCIP_Real* varsolvals; SCIP_Real* binvrow; SCIP_Real* cutcoefs; SCIP_Real cutrhs; SCIP_Real cutact; SCIP_Real maxscale; SCIP_Longint maxdnom; int* basisind; int* inds; int ninds; int nvars; int ncols; int nrows; int ncalls; int depth; int maxdepth; int maxsepacuts; int ncuts; int c; int i; int cutrank; SCIP_Bool success; SCIP_Bool cutislocal; char normtype; assert(sepa != NULL); assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); depth = SCIPgetDepth(scip); ncalls = SCIPsepaGetNCallsAtNode(sepa); /* only call separator, if we are not close to terminating */ if( SCIPisStopped(scip) ) return SCIP_OKAY; /* only call the strong CG cut separator a given number of times at each node */ if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot) || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) ) return SCIP_OKAY; /* only call separator, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call separator, if the LP solution is basic */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* only call separator, if there are fractional variables */ if( SCIPgetNLPBranchCands(scip) == 0 ) return SCIP_OKAY; /* get variables data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* get LP data */ SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) ); SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); if( ncols == 0 || nrows == 0 ) return SCIP_OKAY; #if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */ if( ncols >= 50*nrows ) return SCIP_OKAY; if( ncols >= 5*nrows ) { int ncutsfound; ncutsfound = SCIPgetNCutsFound(scip); if( ncutsfound > sepadata->lastncutsfound || !SCIPsepaWasLPDelayed(sepa) ) { sepadata->lastncutsfound = ncutsfound; *result = SCIP_DELAYED; return SCIP_OKAY; } } #endif /* get the type of norm to use for efficacy calculations */ SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &normtype) ); /* set the maximal denominator in rational representation of strong CG cut and the maximal scale factor to * scale resulting cut to integral values to avoid numerical instabilities */ /**@todo find better but still stable strong CG cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */ maxdepth = SCIPgetMaxDepth(scip); if( depth == 0 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/4 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/2 ) { maxdnom = 100; maxscale = 100.0; } else { maxdnom = 10; maxscale = 10.0; } *result = SCIP_DIDNOTFIND; /* allocate temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) ); varsolvals = NULL; /* allocate this later, if needed */ /* get basis indices */ SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* get the maximal number of cuts allowed in a separation round */ if( depth == 0 ) maxsepacuts = sepadata->maxsepacutsroot; else maxsepacuts = sepadata->maxsepacuts; SCIPdebugMessage("searching strong CG cuts: %d cols, %d rows, maxdnom=%" SCIP_LONGINT_FORMAT ", maxscale=%g, maxcuts=%d\n", ncols, nrows, maxdnom, maxscale, maxsepacuts); /* for all basic columns belonging to integer variables, try to generate a strong CG cut */ ncuts = 0; for( i = 0; i < nrows && ncuts < maxsepacuts && !SCIPisStopped(scip) && *result != SCIP_CUTOFF; ++i ) { SCIP_Bool tryrow; tryrow = FALSE; c = basisind[i]; if( c >= 0 ) { SCIP_VAR* var; assert(c < ncols); var = SCIPcolGetVar(cols[c]); if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ) { SCIP_Real primsol; primsol = SCIPcolGetPrimsol(cols[c]); assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/ if( SCIPfeasFrac(scip, primsol) >= MINFRAC ) { SCIPdebugMessage("trying strong CG cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol); tryrow = TRUE; } } } #ifdef SEPARATEROWS else { SCIP_ROW* row; assert(0 <= -c-1 && -c-1 < nrows); row = rows[-c-1]; if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) ) { SCIP_Real primsol; primsol = SCIPgetRowActivity(scip, row); if( SCIPfeasFrac(scip, primsol) >= MINFRAC ) { SCIPdebugMessage("trying strong CG cut for row <%s> [%g]\n", SCIProwGetName(row), primsol); tryrow = TRUE; } } } #endif if( tryrow ) { /* get the row of B^-1 for this basic integer variable with fractional solution value */ SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow, inds, &ninds) ); #ifdef SCIP_DEBUG /* initialize variables, that might not have been initialized in SCIPcalcMIR if success == FALSE */ cutact = 0.0; cutrhs = SCIPinfinity(scip); #endif /* create a strong CG cut out of the weighted LP rows using the B^-1 row as weights */ SCIP_CALL( SCIPcalcStrongCG(scip, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, MINFRAC, MAXFRAC, binvrow, inds, ninds, 1.0, cutcoefs, &cutrhs, &cutact, &success, &cutislocal, &cutrank) ); assert(ALLOWLOCAL || !cutislocal); SCIPdebugMessage(" -> success=%u: %g <= %g\n", success, cutact, cutrhs); /* if successful, convert dense cut into sparse row, and add the row as a cut */ if( success && SCIPisFeasGT(scip, cutact, cutrhs) ) { SCIP_VAR** cutvars; SCIP_Real* cutvals; SCIP_Real cutnorm; int cutlen; /* if this is the first successful cut, get the LP solution for all COLUMN variables */ if( varsolvals == NULL ) { int v; SCIP_CALL( SCIPallocBufferArray(scip, &varsolvals, nvars) ); for( v = 0; v < nvars; ++v ) { if( SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_COLUMN ) varsolvals[v] = SCIPvarGetLPSol(vars[v]); } } assert(varsolvals != NULL); /* get temporary memory for storing the cut as sparse row */ SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars) ); /* store the cut as sparse row, calculate activity and norm of cut */ SCIP_CALL( storeCutInArrays(scip, nvars, vars, cutcoefs, varsolvals, normtype, cutvars, cutvals, &cutlen, &cutact, &cutnorm) ); SCIPdebugMessage(" -> strong CG cut for <%s>: act=%f, rhs=%f, norm=%f, eff=%f, rank=%d\n", c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]), cutact, cutrhs, cutnorm, (cutact - cutrhs)/cutnorm, cutrank); if( SCIPisPositive(scip, cutnorm) && SCIPisEfficacious(scip, (cutact - cutrhs)/cutnorm) ) { SCIP_ROW* cut; char cutname[SCIP_MAXSTRLEN]; /* create the cut */ if( c >= 0 ) (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%d_x%d", SCIPgetNLPs(scip), c); else (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%d_s%d", SCIPgetNLPs(scip), -c-1); SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) ); SCIP_CALL( SCIPaddVarsToRow(scip, cut, cutlen, cutvars, cutvals) ); /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/ SCIProwChgRank(cut, cutrank); assert(success); #ifdef MAKECUTINTEGRAL /* try to scale the cut to integral values */ SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, MAKECONTINTEGRAL, &success) ); #else #ifdef MAKEINTCUTINTEGRAL /* try to scale the cut to integral values if there are no continuous variables * -> leads to an integral slack variable that can later be used for other cuts */ { int k = 0; while ( k < cutlen && SCIPvarIsIntegral(cutvars[k]) ) ++k; if( k == cutlen ) { SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, MAKECONTINTEGRAL, &success) ); } } #endif #endif #ifndef FORCECUTINTEGRAL success = TRUE; #endif if( success ) { if( !SCIPisCutEfficacious(scip, NULL, cut) ) { SCIPdebugMessage(" -> strong CG cut <%s> no longer efficacious: act=%f, rhs=%f, norm=%f, eff=%f\n", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut), SCIPgetCutEfficacy(scip, NULL, cut)); /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/ success = FALSE; } else { SCIP_Bool infeasible; SCIPdebugMessage(" -> found strong CG cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut), SCIPgetCutEfficacy(scip, NULL, cut), SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut)); /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/ SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE, &infeasible) ); if ( infeasible ) *result = SCIP_CUTOFF; else { if( !cutislocal ) { SCIP_CALL( SCIPaddPoolCut(scip, cut) ); } *result = SCIP_SEPARATED; } ncuts++; } } else { SCIPdebugMessage(" -> strong CG cut <%s> couldn't be scaled to integral coefficients: act=%f, rhs=%f, norm=%f, eff=%f\n", cutname, cutact, cutrhs, cutnorm, SCIPgetCutEfficacy(scip, NULL, cut)); } /* release the row */ SCIP_CALL( SCIPreleaseRow(scip, &cut) ); } /* free temporary memory */ SCIPfreeBufferArray(scip, &cutvals); SCIPfreeBufferArray(scip, &cutvars); } } } /* free temporary memory */ SCIPfreeBufferArrayNull(scip, &varsolvals); SCIPfreeBufferArray(scip, &inds); SCIPfreeBufferArray(scip, &binvrow); SCIPfreeBufferArray(scip, &basisind); SCIPfreeBufferArray(scip, &cutcoefs); SCIPdebugMessage("end searching strong CG cuts: found %d cuts\n", ncuts); sepadata->lastncutsfound = SCIPgetNCutsFound(scip); return SCIP_OKAY; }
/** reads a given SCIP solution file, problem has to be transformed in advance */ static SCIP_RETCODE readSol( SCIP* scip, /**< SCIP data structure */ const char* fname /**< name of the input file */ ) { SCIP_SOL* sol; SCIP_FILE* file; SCIP_Bool error; SCIP_Bool unknownvariablemessage; SCIP_Bool stored; SCIP_Bool usevartable; int lineno; assert(scip != NULL); assert(fname != NULL); SCIP_CALL( SCIPgetBoolParam(scip, "misc/usevartable", &usevartable) ); if( !usevartable ) { SCIPerrorMessage("Cannot read solution file if vartable is disabled. Make sure parameter 'misc/usevartable' is set to TRUE.\n"); return SCIP_READERROR; } /* open input file */ file = SCIPfopen(fname, "r"); if( file == NULL ) { SCIPerrorMessage("cannot open file <%s> for reading\n", fname); SCIPprintSysError(fname); return SCIP_NOFILE; } /* create zero solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) ); /* read the file */ error = FALSE; unknownvariablemessage = FALSE; lineno = 0; while( !SCIPfeof(file) && !error ) { char buffer[SCIP_MAXSTRLEN]; char varname[SCIP_MAXSTRLEN]; char valuestring[SCIP_MAXSTRLEN]; char objstring[SCIP_MAXSTRLEN]; SCIP_VAR* var; SCIP_Real value; int nread; /* get next line */ if( SCIPfgets(buffer, (int) sizeof(buffer), file) == NULL ) break; lineno++; /* there are some lines which may preceed the solution information */ if( strncasecmp(buffer, "solution status:", 16) == 0 || strncasecmp(buffer, "objective value:", 16) == 0 || strncasecmp(buffer, "Log started", 11) == 0 || strncasecmp(buffer, "Variable Name", 13) == 0 || strncasecmp(buffer, "All other variables", 19) == 0 || strncasecmp(buffer, "\n", 1) == 0 || strncasecmp(buffer, "NAME", 4) == 0 || strncasecmp(buffer, "ENDATA", 6) == 0 ) /* allow parsing of SOL-format on the MIPLIB 2003 pages */ continue; /* parse the line */ nread = sscanf(buffer, "%s %s %s\n", varname, valuestring, objstring); if( nread < 2 ) { SCIPerrorMessage("Invalid input line %d in solution file <%s>: <%s>.\n", lineno, fname, buffer); error = TRUE; break; } /* find the variable */ var = SCIPfindVar(scip, varname); if( var == NULL ) { if( !unknownvariablemessage ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "unknown variable <%s> in line %d of solution file <%s>\n", varname, lineno, fname); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " (further unknown variables are ignored)\n"); unknownvariablemessage = TRUE; } continue; } /* cast the value */ if( strncasecmp(valuestring, "inv", 3) == 0 ) continue; else if( strncasecmp(valuestring, "+inf", 4) == 0 || strncasecmp(valuestring, "inf", 3) == 0 ) value = SCIPinfinity(scip); else if( strncasecmp(valuestring, "-inf", 4) == 0 ) value = -SCIPinfinity(scip); else { nread = sscanf(valuestring, "%lf", &value); if( nread != 1 ) { SCIPerrorMessage("Invalid solution value <%s> for variable <%s> in line %d of solution file <%s>.\n", valuestring, varname, lineno, fname); error = TRUE; break; } } /* set the solution value of the variable, if not multiaggregated */ if( SCIPisTransformed(scip) && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "ignored solution value for multiaggregated variable <%s>\n", SCIPvarGetName(var)); } else { SCIP_RETCODE retcode; retcode = SCIPsetSolVal(scip, sol, var, value); if( retcode == SCIP_INVALIDDATA ) { if( SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_FIXED ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "ignored conflicting solution value for fixed variable <%s>\n", SCIPvarGetName(var)); } else { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "ignored solution value for multiaggregated variable <%s>\n", SCIPvarGetName(var)); } } else { SCIP_CALL( retcode ); } } } /* close input file */ SCIPfclose(file); if( !error ) { /* add and free the solution */ if( SCIPisTransformed(scip) ) { SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, TRUE, TRUE, TRUE, &stored) ); /* display result */ SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "primal solution from solution file <%s> was %s\n", fname, stored ? "accepted" : "rejected - solution is infeasible or objective too poor"); } else { /* add primal solution to solution candidate storage, frees the solution afterwards */ SCIP_CALL( SCIPaddSolFree(scip, &sol, &stored) ); /* display result */ SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "primal solution from solution file <%s> was %s\n", fname, stored ? "accepted as candidate, will be checked when solving starts" : "rejected - solution objective too poor"); } return SCIP_OKAY; } else { /* free solution */ SCIP_CALL( SCIPfreeSol(scip, &sol) ); return SCIP_READERROR; } }
/** adds problem variables with negative reduced costs to pricing storage */ SCIP_RETCODE SCIPpricestoreAddProbVars( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory buffers */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< dynamic problem statistics */ SCIP_PROB* prob, /**< transformed problem after presolve */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue /**< event queue */ ) { SCIP_VAR* var; SCIP_COL* col; SCIP_Bool root; SCIP_Bool added; int v; int abortpricevars; int maxpricevars; int nfoundvars; assert(pricestore != NULL); assert(set != NULL); assert(stat != NULL); assert(prob != NULL); assert(lp != NULL); assert(lp->solved); assert(tree != NULL); assert(SCIPtreeHasCurrentNodeLP(tree)); assert(prob->nvars >= SCIPlpGetNCols(lp)); /* if all problem variables of status COLUMN are already in the LP, nothing has to be done */ if( prob->ncolvars == SCIPlpGetNCols(lp) ) return SCIP_OKAY; root = (SCIPtreeGetCurrentDepth(tree) == 0); maxpricevars = SCIPsetGetPriceMaxvars(set, root); assert(maxpricevars >= 1); abortpricevars = (int)(set->price_abortfac * maxpricevars); assert(abortpricevars >= maxpricevars); /**@todo test pricing: is abortpricevars a good idea? -> like strong branching, lookahead, ... */ pricestore->nprobpricings++; /* start timing */ SCIPclockStart(pricestore->probpricingtime, set); /* price already existing problem variables */ nfoundvars = 0; for( v = 0; v < prob->nvars && nfoundvars < abortpricevars; ++v ) { var = prob->vars[v]; if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) { col = SCIPvarGetCol(var); assert(col != NULL); assert(col->var == var); assert(col->len >= 0); assert(col->lppos >= -1); assert(col->lpipos >= -1); assert(SCIPcolIsInLP(col) == (col->lpipos >= 0)); if( !SCIPcolIsInLP(col) ) { SCIPdebugMessage("price column variable <%s> in bounds [%g,%g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); /* add variable to pricing storage, if zero is not best bound w.r.t. objective function */ SCIP_CALL( addBoundViolated(pricestore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, &added) ); if( added ) { pricestore->nprobvarsfound++; nfoundvars++; } else if( SCIPcolGetNNonz(col) > 0 ) { SCIP_Real feasibility; /* a column not in LP that doesn't have zero in its bounds was added by bound checking above */ assert(!SCIPsetIsPositive(set, SCIPvarGetLbLocal(col->var))); assert(!SCIPsetIsNegative(set, SCIPvarGetUbLocal(col->var))); if( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_INFEASIBLE ) { /* The LP was proven infeasible, so we have an infeasibility proof by the dual Farkas multipliers y. * The valid inequality y^T A x >= y^T b is violated by all x, especially by the (for this * inequality most feasible solution) x' defined by * x'_i = ub_i, if y^T A_i > 0 * x'_i = lb_i, if y^T A_i <= 0. * Pricing in this case means to add variables i with positive Farkas value, i.e. y^T A_i x'_i > 0 */ feasibility = -SCIPcolGetFarkasValue(col, stat, lp); SCIPdebugMessage(" <%s> Farkas feasibility: %e\n", SCIPvarGetName(col->var), feasibility); } else { /* The dual LP is feasible, and we have a feasible dual solution. Pricing in this case means to * add variables with negative feasibility, that is * - positive reduced costs for variables with negative lower bound * - negative reduced costs for variables with positive upper bound */ feasibility = SCIPcolGetFeasibility(col, set, stat, lp); SCIPdebugMessage(" <%s> reduced cost feasibility: %e\n", SCIPvarGetName(col->var), feasibility); } /* the score is -feasibility / (#nonzeros in column + 1) to prefer short columns * we must add variables with negative feasibility, but in order to not get a too large lower bound * due to missing columns, we better also add variables, that have a very small feasibility */ if( !SCIPsetIsPositive(set, feasibility) ) { SCIP_CALL( SCIPpricestoreAddVar(pricestore, blkmem, set, eventqueue, lp, var, -feasibility / (col->len+1), root) ); pricestore->nprobvarsfound++; nfoundvars++; } } } } } /* stop timing */ SCIPclockStop(pricestore->probpricingtime, set); return SCIP_OKAY; }
/** selects a random active variable from a given list of variables */ static void getRandomVariable( SCIP* scip, /**< SCIP data structure */ SCIP_VAR** cands, /**< array of branching candidates */ SCIP_Real* candssol, /**< relaxation solution values of branching candidates, or NULL */ int ncands, /**< number of branching candidates */ SCIP_VAR** bestcand, /**< buffer to store pointer to best candidate */ SCIP_Real* bestcandsol, /**< buffer to store solution value of best candidate */ unsigned int* seed /**< seed for random number generator */ ) { int idx; int firstidx; assert(scip != NULL); assert(cands != NULL); assert(ncands > 0); assert(bestcand != NULL); assert(bestcandsol != NULL); assert(seed != NULL); idx = SCIPgetRandomInt(0, ncands-1, seed); assert(idx >= 0); /* handle case where cands[idx] is fixed by selecting next idx with unfixed var * this may happen if we are inside a multi-aggregation */ firstidx = idx; while( SCIPisEQ(scip, SCIPvarGetLbLocal(cands[idx]), SCIPvarGetUbLocal(cands[idx])) ) { ++idx; if( idx == ncands ) idx = 0; if( idx == firstidx ) { /* odd: all variables seem to be fixed */ SCIPdebugMessage("Warning: all branching candidates seem to be fixed\n"); return; } } /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */ assert(SCIPvarIsActive(SCIPvarGetProbvar(cands[idx])) || SCIPvarGetStatus(SCIPvarGetProbvar(cands[idx])) == SCIP_VARSTATUS_MULTAGGR); if( SCIPvarGetStatus(SCIPvarGetProbvar(cands[idx])) == SCIP_VARSTATUS_MULTAGGR ) { /* for a multi-aggregated variable, we call the getRandomVariable function recursively with all variables in the multi-aggregation */ SCIP_VAR* cand; cand = SCIPvarGetProbvar(cands[idx]); getRandomVariable(scip, SCIPvarGetMultaggrVars(cand), NULL, SCIPvarGetMultaggrNVars(cand), bestcand, bestcandsol, seed); return; } assert(idx >= 0 && idx < ncands); *bestcand = cands[idx]; assert(*bestcand != NULL); if( candssol != NULL ) *bestcandsol = candssol[idx]; }
/** adds priced variables to the LP */ SCIP_RETCODE SCIPpricestoreApplyVars( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory buffers */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< dynamic problem statistics */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_PROB* prob, /**< transformed problem after presolve */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp /**< LP data */ ) { SCIP_VAR* var; SCIP_COL* col; int v; assert(pricestore != NULL); assert(pricestore->naddedbdviolvars <= pricestore->nbdviolvars); assert(set != NULL); assert(prob != NULL); assert(lp != NULL); assert(tree != NULL); assert(SCIPtreeIsFocusNodeLPConstructed(tree)); SCIPdebugMessage("adding %d variables (%d bound violated and %d priced vars) to %d LP columns\n", SCIPpricestoreGetNVars(pricestore), pricestore->nbdviolvars - pricestore->naddedbdviolvars, pricestore->nvars, SCIPlpGetNCols(lp)); /* add the variables with violated bounds to LP */ for( v = pricestore->naddedbdviolvars; v < pricestore->nbdviolvars; ++v ) { var = pricestore->bdviolvars[v]; assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); assert(SCIPvarGetProbindex(var) >= 0); assert(var->nuses >= 2); /* at least used in pricing storage and in problem */ if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) { /* transform loose variable into column variable */ SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) ); } assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); col = SCIPvarGetCol(var); assert(col != NULL); assert(col->lppos == -1); SCIPdebugMessage("adding bound violated variable <%s> (lb=%g, ub=%g)\n", SCIPvarGetName(var), pricestore->bdviolvarslb[v], pricestore->bdviolvarsub[v]); SCIP_CALL( SCIPlpAddCol(lp, set, col, SCIPtreeGetCurrentDepth(tree)) ); if( !pricestore->initiallp ) pricestore->nvarsapplied++; } pricestore->naddedbdviolvars = pricestore->nbdviolvars; /* add the selected pricing variables to LP */ for( v = 0; v < pricestore->nvars; ++v ) { var = pricestore->vars[v]; assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); assert(SCIPvarGetProbindex(var) >= 0); assert(var->nuses >= 2); /* at least used in pricing storage and in problem */ /* transform variable into column variable, if needed */ if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) { SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) ); } assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); col = SCIPvarGetCol(var); assert(col != NULL); assert(col->lppos == -1); SCIPdebugMessage("adding priced variable <%s> (score=%g)\n", SCIPvarGetName(var), pricestore->scores[v]); SCIP_CALL( SCIPlpAddCol(lp, set, col, SCIPtreeGetCurrentDepth(tree)) ); /* release the variable */ SCIP_CALL( SCIPvarRelease(&pricestore->vars[v], blkmem, set, eventqueue, lp) ); if( !pricestore->initiallp ) pricestore->nvarsapplied++; } /* clear the pricing storage */ pricestore->nvars = 0; return SCIP_OKAY; }
/** gets value of given variable in debugging solution */ static SCIP_RETCODE getSolutionValue( SCIP_SET* set, /**< global SCIP settings */ SCIP_VAR* var, /**< variable to get solution value for */ SCIP_Real* val /**< pointer to store solution value */ ) { SCIP_VAR* solvar; SCIP_Real scalar; SCIP_Real constant; const char* name; int left; int right; int middle; int cmp; assert(set != NULL); assert(var != NULL); assert(val != NULL); SCIP_CALL( readSolution(set) ); SCIPdebugMessage("Now handling variable <%s>, which has status %d, is of type %d, and was deleted: %d, negated: %d, transformed: %d\n", SCIPvarGetName(var), SCIPvarGetStatus(var), SCIPvarGetType(var), SCIPvarIsDeleted(var), SCIPvarIsNegated(var),SCIPvarIsTransformedOrigvar(var)); /* ignore deleted variables */ if( SCIPvarIsDeleted(var) ) { SCIPdebugMessage("**** unknown solution value for deleted variable <%s>\n", SCIPvarGetName(var)); *val = SCIP_UNKNOWN; return SCIP_OKAY; } /* retransform variable onto original variable space */ solvar = var; scalar = 1.0; constant = 0.0; if( SCIPvarIsNegated(solvar) ) { scalar = -1.0; constant = SCIPvarGetNegationConstant(solvar); solvar = SCIPvarGetNegationVar(solvar); } if( SCIPvarIsTransformed(solvar) ) { SCIP_CALL( SCIPvarGetOrigvarSum(&solvar, &scalar, &constant) ); if( solvar == NULL ) { /* if no original counterpart, then maybe someone added a value for the transformed variable, so search for var (or its negation) */ SCIPdebugMessage("variable <%s> has no original counterpart\n", SCIPvarGetName(var)); solvar = var; scalar = 1.0; constant = 0.0; if( SCIPvarIsNegated(solvar) ) { scalar = -1.0; constant = SCIPvarGetNegationConstant(solvar); solvar = SCIPvarGetNegationVar(solvar); } } } /* perform a binary search for the variable */ name = SCIPvarGetName(solvar); left = 0; right = nsolvals-1; while( left <= right ) { middle = (left+right)/2; cmp = strcmp(name, solnames[middle]); if( cmp < 0 ) right = middle-1; else if( cmp > 0 ) left = middle+1; else { *val = scalar * solvals[middle] + constant; return SCIP_OKAY; } } *val = constant; if( *val < SCIPvarGetLbGlobal(var) - 1e-06 || *val > SCIPvarGetUbGlobal(var) + 1e-06 ) { SCIPwarningMessage("invalid solution value %.15g for variable <%s>[%.15g,%.15g]\n", *val, SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)); } return SCIP_OKAY; }