/** 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; }
/** try one-opt on given solution */ static SCIP_RETCODE tryOneOpt( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand, /**< values for indicator variables in partial solution */ int* nfoundsols /**< number of solutions found */ ) { SCIP_Bool cutoff; SCIP_Bool lperror; SCIP_Bool stored; SCIP_SOL* sol; int cnt = 0; int i; int c; assert( scip != NULL ); assert( heur != NULL ); assert( heurdata != NULL ); assert( nindconss == 0 || indconss != NULL ); assert( solcand != NULL ); assert( nfoundsols != NULL ); SCIPdebugMessage("Performing one-opt ...\n"); *nfoundsols = 0; SCIP_CALL( SCIPstartProbing(scip) ); for (i = 0; i < nindconss; ++i) { SCIP_VAR* binvar; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[i]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[i]); assert( binvar != NULL ); /* skip constraints with fixed variables */ if ( SCIPvarGetUbLocal(binvar) < 0.5 || SCIPvarGetLbLocal(binvar) > 0.5 ) continue; /* return if the we would exceed the depth limit of the tree */ if( SCIPgetDepthLimit(scip) <= SCIPgetDepth(scip) ) break; /* get rid of all bound changes */ SCIP_CALL( SCIPnewProbingNode(scip) ); ++cnt; /* fix variables */ for (c = 0; c < nindconss; ++c) { SCIP_Bool s; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[c]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[c]); assert( binvar != NULL ); /* fix variables according to solution candidate, except constraint i */ if ( c == i ) s = ! solcand[c]; else s = solcand[c]; if ( ! s ) { if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 ) { SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) ); } } else { if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 ) { SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) ); } } } /* propagate variables */ SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, NULL) ); if ( cutoff ) { SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); continue; } /* solve LP to move continuous variables */ SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) ); /* the LP often reaches the objective limit - we currently do not use such solutions */ if ( lperror || cutoff || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { #ifdef SCIP_DEBUG if ( lperror ) SCIPdebugMessage("An LP error occured.\n"); #endif SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); continue; } /* create solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, heur) ); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* check solution for feasibility */ SCIPdebugMessage("One-opt found solution candidate with value %g.\n", SCIPgetSolTransObj(scip, sol)); /* only check integrality, because we solved an LP */ SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, &stored) ); if ( stored ) ++(*nfoundsols); SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); } SCIP_CALL( SCIPendProbing(scip) ); SCIPdebugMessage("Finished one-opt (tried variables: %d, found sols: %d).\n", cnt, *nfoundsols); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecActconsdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_VAR* var; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Real* lpcandsfrac; SCIP_Real searchubbound; SCIP_Real searchavgbound; SCIP_Real searchbound; SCIP_Real objval; SCIP_Real oldobjval; SCIP_Real frac; SCIP_Real bestfrac; SCIP_Bool bestcandmayrounddown; SCIP_Bool bestcandmayroundup; SCIP_Bool bestcandroundup; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Bool roundup; SCIP_Bool lperror; SCIP_Bool cutoff; SCIP_Bool backtracked; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int nlpcands; int startnlpcands; int depth; int maxdepth; int maxdivedepth; int divedepth; SCIP_Real actscore; SCIP_Real downscore; SCIP_Real upscore; SCIP_Real bestactscore; int bestcand; int c; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* do not call heuristic of node was already detected to be infeasible */ if( nodeinfeasible ) return SCIP_OKAY; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call heuristic, if the LP objective value is smaller than the cutoff bound */ if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) ) return SCIP_OKAY; /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* don't dive two times at the same node */ if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */ depth = SCIPgetDepth(scip); maxdepth = SCIPgetMaxDepth(scip); maxdepth = MAX(maxdepth, 30); if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth ) return SCIP_OKAY; /* calculate the maximal number of LP iterations until heuristic is aborted */ nlpiterations = SCIPgetNNodeLPIterations(scip); ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess; maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations); maxnlpiterations += heurdata->maxlpiterofs; /* don't try to dive, if we took too many LP iterations during diving */ if( heurdata->nlpiterations >= maxnlpiterations ) return SCIP_OKAY; /* allow at least a certain number of LP iterations in this dive */ maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER); /* get fractional variables that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); /* don't try to dive, if there are no fractional variables */ if( nlpcands == 0 ) return SCIP_OKAY; /* calculate the objective search bound */ if( SCIPgetNSolsFound(scip) == 0 ) { if( heurdata->maxdiveubquotnosol > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquotnosol > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } else { if( heurdata->maxdiveubquot > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquot > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } searchbound = MIN(searchubbound, searchavgbound); if( SCIPisObjIntegral(scip) ) searchbound = SCIPceil(scip, searchbound); /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */ maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); maxdivedepth = MIN(maxdivedepth, maxdepth); maxdivedepth *= 10; *result = SCIP_DIDNOTFIND; /* start diving */ SCIP_CALL( SCIPstartProbing(scip) ); /* enables collection of variable statistics during probing */ SCIPenableVarHistory(scip); /* get LP objective value */ lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; objval = SCIPgetLPObjval(scip); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing actconsdiving heuristic: depth=%d, %d fractionals, dualbound=%g, avgbound=%g, cutoffbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPgetAvgDualbound(scip), SCIPretransformObj(scip, SCIPgetCutoffbound(scip)), SCIPretransformObj(scip, searchbound)); /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but * - if possible, we dive at least with the depth 10 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving */ lperror = FALSE; cutoff = FALSE; divedepth = 0; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; startnlpcands = nlpcands; while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound)) && !SCIPisStopped(scip) ) { divedepth++; SCIP_CALL( SCIPnewProbingNode(scip) ); /* choose variable fixing: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, round variable with least number of locks in corresponding direction * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - round variable with least number of locks in opposite of its feasible rounding direction */ bestcand = -1; bestactscore = -1.0; bestfrac = SCIP_INVALID; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); frac = lpcandsfrac[c]; if( mayrounddown || mayroundup ) { /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */ if( bestcandmayrounddown || bestcandmayroundup ) { /* choose rounding direction: * - if variable may be rounded in both directions, round corresponding to the fractionality * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution */ if( mayrounddown && mayroundup ) roundup = (frac > 0.5); else roundup = mayrounddown; if( roundup ) frac = 1.0 - frac; actscore = getNActiveConsScore(scip, var, &downscore, &upscore); /* penalize too small fractions */ if( frac < 0.01 ) actscore *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) actscore *= 0.01; /* check, if candidate is new best candidate */ assert(0.0 < frac && frac < 1.0); if( SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) ) { bestcand = c; bestactscore = actscore; bestfrac = frac; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded */ actscore = getNActiveConsScore(scip, var, &downscore, &upscore); roundup = (downscore < upscore); if( roundup ) frac = 1.0 - frac; /* penalize too small fractions */ if( frac < 0.01 ) actscore *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) actscore *= 0.01; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ assert(0.0 < frac && frac < 1.0); if( bestcandmayrounddown || bestcandmayroundup || SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) ) { bestcand = c; bestactscore = actscore; bestfrac = frac; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; bestcandroundup = roundup; } assert(bestfrac < SCIP_INVALID); } } assert(bestcand != -1); /* if all candidates are roundable, try to round the solution */ if( bestcandmayrounddown || bestcandmayroundup ) { SCIP_Bool success; /* create solution from diving LP and try to round it */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) ); if( success ) { SCIPdebugMessage("actconsdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } } assert(bestcand != -1); var = lpcands[bestcand]; backtracked = FALSE; do { /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have * occured or variable was fixed by propagation while backtracking => Abort diving! */ if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 ) { SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]); cutoff = TRUE; break; } if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) ) { SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]); assert(backtracked); break; } /* apply rounding of best candidate */ if( bestcandroundup == !backtracked ) { /* round variable up */ SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var)); SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) ); } else { /* round variable down */ SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand])); SCIP_CALL( SCIPchgVarUbProbing(scip, lpcands[bestcand], SCIPfeasFloor(scip, lpcandssol[bestcand])) ); } /* apply domain propagation */ SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) ); if( !cutoff ) { /* resolve the diving LP */ /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ #ifdef NDEBUG SCIP_RETCODE retstat; nlpiterations = SCIPgetNLPIterations(scip); retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Actconsdiving heuristic; LP solve terminated with code <%d>\n",retstat); } #else nlpiterations = SCIPgetNLPIterations(scip); SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) ); #endif if( lperror ) break; /* update iteration count */ heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations; /* get LP solution status, objective value, and fractional variables, that should be integral */ lpsolstat = SCIPgetLPSolstat(scip); assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE && (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip))))); } /* perform backtracking if a cutoff was detected */ if( cutoff && !backtracked && heurdata->backtrack ) { SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip)); SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) ); SCIP_CALL( SCIPnewProbingNode(scip) ); backtracked = TRUE; } else backtracked = FALSE; } while( backtracked ); if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { /* get new objective value */ oldobjval = objval; objval = SCIPgetLPObjval(scip); /* update pseudo cost values */ if( SCIPisGT(scip, objval, oldobjval) ) { if( bestcandroundup ) { SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand], objval - oldobjval, 1.0) ); } else { SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand], objval - oldobjval, 1.0) ); } } /* get new fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); } SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g, nfrac=%d\n", lpsolstat, objval, searchbound, nlpcands); } /* check if a solution has been found */ if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* create solution from diving LP */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIPdebugMessage("actconsdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } /* end diving */ SCIP_CALL( SCIPendProbing(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") finished actconsdiving heuristic: %d fractionals, dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", objval=%g/%g, lpsolstat=%d, cutoff=%u\n", SCIPgetNNodes(scip), nlpcands, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPretransformObj(scip, objval), SCIPretransformObj(scip, searchbound), lpsolstat, cutoff); return SCIP_OKAY; }
/** try given solution */ static SCIP_RETCODE trySolCandidate( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand, /**< values for indicator variables in partial solution */ int* nfoundsols /**< number of solutions found */ ) { SCIP_Bool cutoff; SCIP_Bool lperror; SCIP_Bool stored; SCIP_SOL* sol; int c; assert( scip != NULL ); assert( heur != NULL ); assert( heurdata != NULL ); assert( nindconss == 0 || indconss != NULL ); assert( solcand != NULL ); assert( nfoundsols != NULL ); SCIPdebugMessage("Trying to generate feasible solution with indicators from solution candidate ...\n"); *nfoundsols = 0; SCIP_CALL( SCIPstartProbing(scip) ); /* we can stop here if we have already reached the maximal depth */ if( SCIPgetDepthLimit(scip) <= SCIPgetDepth(scip) ) { SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } SCIP_CALL( SCIPnewProbingNode(scip) ); /* fix variables */ for (c = 0; c < nindconss; ++c) { SCIP_VAR* binvar; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[c]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[c]); assert( binvar != NULL ); /* Fix binary variables not in cover to 1 and corresponding slack variables to 0. The other binary variables are fixed to 0. */ if ( ! solcand[c] ) { /* to be sure, check for non-fixed variables */ if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 ) { SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) ); } } else { if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 ) { SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) ); } } } /* propagate variables */ SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, NULL) ); if ( cutoff ) { SCIPdebugMessage("Solution candidate reaches cutoff (in propagation).\n"); SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } /* solve LP to move continuous variables */ SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) ); /* the LP often reaches the objective limit - we currently do not use such solutions */ if ( lperror || cutoff || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { #ifdef SCIP_DEBUG if ( lperror ) SCIPdebugMessage("An LP error occured.\n"); else SCIPdebugMessage("Solution candidate reaches cutoff (in LP solving).\n"); #endif SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } /* create solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, heur) ); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* check solution for feasibility */ #ifdef SCIP_DEBUG SCIPdebugMessage("Found solution candidate with value %g.\n", SCIPgetSolTransObj(scip, sol)); #ifdef SCIP_MORE_DEBUG SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, TRUE, TRUE, TRUE, &stored) ); if ( stored ) { ++(*nfoundsols); SCIPdebugMessage("Solution is feasible and stored.\n"); } else SCIPdebugMessage("Solution was not stored.\n"); #else /* only check integrality, because we solved an LP */ SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, &stored) ); if ( stored ) ++(*nfoundsols); #endif SCIP_CALL( SCIPendProbing(scip) ); /* possibly perform one-opt */ if ( stored && heurdata->oneopt ) { int nfound = 0; assert( *nfoundsols > 0 ); SCIP_CALL( tryOneOpt(scip, heur, heurdata, nindconss, indconss, solcand, &nfound) ); } return SCIP_OKAY; }