52 #define HEUR_NAME "sdpfracdiving" 53 #define HEUR_DESC "SDP diving heuristic that chooses fixings w.r.t. the fractionalities" 54 #define HEUR_DISPCHAR 'f' 55 #define HEUR_PRIORITY -1003000 57 #define HEUR_FREQOFS 0 58 #define HEUR_MAXDEPTH -1 59 #define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE 60 #define HEUR_USESSUBSCIP FALSE 67 #define DEFAULT_MINRELDEPTH 0.0 68 #define DEFAULT_MAXRELDEPTH 1.0 69 #define DEFAULT_MAXDIVEUBQUOT 0.8 71 #define DEFAULT_MAXDIVEAVGQUOT 0.0 73 #define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 74 #define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 75 #define DEFAULT_BACKTRACK TRUE 76 #define DEFAULT_RUNFORLP FALSE 83 SCIP_Real minreldepth;
84 SCIP_Real maxreldepth;
85 SCIP_Real maxdiveubquot;
87 SCIP_Real maxdiveavgquot;
89 SCIP_Real maxdiveubquotnosol;
90 SCIP_Real maxdiveavgquotnosol;
104 assert(scip != NULL);
105 assert(heur != NULL);
106 assert(strcmp(SCIPheurGetName(heur),
HEUR_NAME) == 0);
118 SCIP_HEURDATA* heurdata;
120 assert(heur != NULL);
121 assert(strcmp(SCIPheurGetName(heur),
HEUR_NAME) == 0);
122 assert(scip != NULL);
125 heurdata = SCIPheurGetData(heur);
126 assert(heurdata != NULL);
127 SCIPfreeBlockMemory(scip, &heurdata);
128 SCIPheurSetData(heur, NULL);
138 SCIP_HEURDATA* heurdata;
140 assert(heur != NULL);
141 assert(strcmp(SCIPheurGetName(heur),
HEUR_NAME) == 0);
144 heurdata = SCIPheurGetData(heur);
145 assert(heurdata != NULL);
148 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
151 heurdata->nsuccess = 0;
161 SCIP_HEURDATA* heurdata;
163 assert(heur != NULL);
164 assert(strcmp(SCIPheurGetName(heur),
HEUR_NAME) == 0);
167 heurdata = SCIPheurGetData(heur);
168 assert(heurdata != NULL);
171 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
181 SCIP_HEURDATA* heurdata;
182 SCIP_CONSHDLR* conshdlrsdp;
183 SCIP_RELAX* relaxsdp;
188 SCIP_Bool bestcandmayrounddown;
189 SCIP_Bool bestcandmayroundup;
190 SCIP_Bool bestcandroundup;
191 SCIP_Bool mayrounddown;
192 SCIP_Bool mayroundup;
194 SCIP_Bool backtracked;
196 SCIP_Bool usesdp = TRUE;
197 SCIP_Real* sdpcandssol;
198 SCIP_Real* sdpcandsfrac;
199 SCIP_Real searchubbound;
200 SCIP_Real searchavgbound;
201 SCIP_Real searchbound;
206 SCIP_Real bestobjgain;
209 SCIP_SOL* relaxsol = NULL;
222 assert( heur != NULL );
223 assert( strcmp(SCIPheurGetName(heur),
HEUR_NAME) == 0 );
224 assert( scip != NULL );
225 assert( result != NULL );
227 *result = SCIP_DELAYED;
230 if ( nodeinfeasible )
233 *result = SCIP_DIDNOTRUN;
236 if ( SCIPgetSubscipDepth(scip) > 0 )
240 if ( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
244 heurdata = SCIPheurGetData(heur);
245 assert( heurdata != NULL );
248 if ( ! SCIPisRelaxSolValid(scip) )
251 if ( ! heurdata->runforlp )
255 if ( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
261 relaxsdp = SCIPfindRelax(scip,
"SDP");
262 if ( relaxsdp == NULL )
265 conshdlrsdp = SCIPfindConshdlr(scip,
"SDP");
266 if ( conshdlrsdp == NULL )
270 if ( SCIPconshdlrGetNConss(conshdlrsdp) <= 0 )
276 SCIP_CALL( SCIPcreateRelaxSol(scip, &relaxsol, heur) );
280 depth = SCIPgetDepth(scip);
281 maxdepth = SCIPgetMaxDepth(scip);
282 maxdepth = MAX(maxdepth, 30);
283 if ( depth < heurdata->minreldepth * maxdepth || depth > heurdata->maxreldepth * maxdepth )
287 vars = SCIPgetVars(scip);
288 nvars = SCIPgetNVars(scip);
289 SCIP_CALL( SCIPallocBufferArray(scip, &sdpcands, nvars) );
290 SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandssol, nvars) );
291 SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandsfrac, nvars) );
294 for (v = 0; v < nvars; ++v)
298 val = SCIPgetSolVal(scip, relaxsol, vars[v]);
299 frac = SCIPfeasFrac(scip, val);
301 if ( SCIPvarIsIntegral(vars[v]) && ! SCIPisFeasZero(scip, frac) )
303 sdpcands[nsdpcands] = vars[v];
304 sdpcandssol[nsdpcands] = val;
305 sdpcandsfrac[nsdpcands] = frac;
311 objval = SCIPgetSolTransObj(scip, relaxsol);
314 if ( relaxsol != NULL )
316 SCIP_CALL( SCIPfreeSol(scip, &relaxsol) );
320 if ( nsdpcands == 0 )
322 SCIPfreeBufferArray(scip, &sdpcandsfrac);
323 SCIPfreeBufferArray(scip, &sdpcandssol);
324 SCIPfreeBufferArray(scip, &sdpcands);
329 if ( SCIPgetNSolsFound(scip) == 0 )
331 if ( heurdata->maxdiveubquotnosol > 0.0 )
332 searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
334 searchubbound = SCIPinfinity(scip);
336 if ( heurdata->maxdiveavgquotnosol > 0.0 )
337 searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
339 searchavgbound = SCIPinfinity(scip);
343 if ( heurdata->maxdiveubquot > 0.0 )
344 searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
346 searchubbound = SCIPinfinity(scip);
348 if ( heurdata->maxdiveavgquot > 0.0 )
349 searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
351 searchavgbound = SCIPinfinity(scip);
353 searchbound = MIN(searchubbound, searchavgbound);
354 if ( SCIPisObjIntegral(scip) )
355 searchbound = SCIPceil(scip, searchbound);
358 maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
359 maxdivedepth = MIN(maxdivedepth, maxdepth);
362 *result = SCIP_DIDNOTFIND;
365 SCIP_CALL( SCIPstartProbing(scip) );
368 SCIPenableVarHistory(scip);
370 SCIPdebugMsg(scip,
"(node %"SCIP_LONGINT_FORMAT
") executing SDP fracdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
371 SCIPgetNNodes(scip), SCIPgetDepth(scip), nsdpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
379 bestcandmayrounddown = FALSE;
380 bestcandmayroundup = FALSE;
381 startnsdpcands = nsdpcands;
387 freq = SCIPrelaxGetFreq(relaxsdp);
388 SCIP_CALL( SCIPsetIntParam(scip,
"relaxing/SDP/freq", 1) );
391 while ( ! cutoff && nsdpcands > 0
393 || nsdpcands <= startnsdpcands - divedepth/2
394 || (divedepth < maxdivedepth && objval < searchbound))
395 && ! SCIPisStopped(scip) )
397 SCIP_CALL( SCIPnewProbingNode(scip) );
407 bestobjgain = SCIPinfinity(scip);
408 bestfrac = SCIP_INVALID;
409 bestcandmayrounddown = TRUE;
410 bestcandmayroundup = TRUE;
411 bestcandroundup = FALSE;
413 for (c = 0; c < nsdpcands; ++c)
416 mayrounddown = SCIPvarMayRoundDown(var);
417 mayroundup = SCIPvarMayRoundUp(var);
418 frac = sdpcandsfrac[c];
419 obj = SCIPvarGetObj(var);
421 if ( mayrounddown || mayroundup )
424 if( bestcandmayrounddown || bestcandmayroundup )
431 if ( mayrounddown && mayroundup )
432 roundup = (frac > 0.5);
434 roundup = mayrounddown;
439 objgain = frac * obj;
442 objgain = - frac * obj;
449 if ( ! SCIPvarIsBinary(var) )
453 if ( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
456 bestobjgain = objgain;
458 bestcandmayrounddown = mayrounddown;
459 bestcandmayroundup = mayroundup;
460 bestcandroundup = roundup;
480 if ( ! SCIPvarIsBinary(var) )
484 if ( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
488 bestcandmayrounddown = FALSE;
489 bestcandmayroundup = FALSE;
490 bestcandroundup = roundup;
492 assert( bestfrac < SCIP_INVALID );
495 assert( bestcand != -1 );
498 if ( bestcandmayrounddown || bestcandmayroundup )
503 SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
504 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
508 SCIPdebugMsg(scip,
"SDP fracdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
511 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
516 SCIPdebugMsg(scip,
" -> solution was feasible and good enough\n");
517 *result = SCIP_FOUNDSOL;
522 var = sdpcands[bestcand];
531 if ( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
533 SCIPdebugMsg(scip,
"Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
534 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), sdpcandssol[bestcand]);
539 if ( SCIPisFeasLT(scip, sdpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, sdpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
541 SCIPdebugMsg(scip,
"selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
542 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), sdpcandssol[bestcand]);
544 assert( backtracked );
550 if ( bestcandroundup != backtracked )
553 #ifdef SCIP_MORE_DEBUG 554 SCIPdebugMsg(scip,
" dive %d/%d: var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
555 divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
556 sdpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
557 SCIPfeasCeil(scip, sdpcandssol[bestcand]), SCIPvarGetUbLocal(var));
559 SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, sdpcandssol[bestcand])) );
565 #ifdef SCIP_MORE_DEBUG 566 SCIPdebugMsg(scip,
" dive %d/%d: var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
567 divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
568 sdpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
569 SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, sdpcandssol[bestcand]));
571 SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, sdpcandssol[bestcand])) );
576 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
580 SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
585 SCIPdebugMsg(scip,
"SDP fracdiving heuristic aborted, as we could not solve one of the diving SDPs.\n");
587 SCIPfreeBufferArray(scip, &sdpcandsfrac);
588 SCIPfreeBufferArray(scip, &sdpcandssol);
589 SCIPfreeBufferArray(scip, &sdpcands);
591 *result = SCIP_DIDNOTRUN;
592 SCIP_CALL( SCIPendProbing(scip) );
597 SCIP_CALL( SCIPsetIntParam(scip,
"relaxing/SDP/freq", freq) );
607 if ( cutoff && ! backtracked && heurdata->backtrack )
609 #ifdef SCIP_MORE_DEBUG 610 SCIPdebugMsg(scip,
" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
612 SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
613 SCIP_CALL( SCIPnewProbingNode(scip) );
626 objval = SCIPgetRelaxSolObj(scip);
629 if ( SCIPisGT(scip, objval, oldobjval) )
633 assert(bestcandroundup || backtracked);
634 SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 1.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
638 assert(!bestcandroundup || backtracked);
639 SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 0.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
645 for (v = 0; v < nvars; ++v)
649 val = SCIPgetRelaxSolVal(scip, vars[v]);
650 frac = SCIPfeasFrac(scip, val);
652 if ( SCIPvarIsIntegral(vars[v]) && ( ! SCIPisFeasZero(scip, frac) ) )
654 sdpcands[nsdpcands] = vars[v];
655 sdpcandssol[nsdpcands] = val;
656 sdpcandsfrac[nsdpcands] = frac;
661 #ifdef SCIP_MORE_DEBUG 662 SCIPdebugMsg(scip,
" -> objval=%g/%g, nfrac=%d\n", objval, searchbound, nsdpcands);
667 if ( nsdpcands == 0 && ! cutoff )
672 SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
673 SCIPdebugMsg(scip,
"SDP fracdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
676 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
681 SCIPdebugMsg(scip,
" -> solution was feasible and good enough\n");
682 *result = SCIP_FOUNDSOL;
687 SCIP_CALL( SCIPendProbing(scip) );
692 SCIP_CALL( SCIPsetIntParam(scip,
"relaxing/SDP/freq", freq) );
695 if ( *result == SCIP_FOUNDSOL )
696 heurdata->nsuccess++;
699 SCIP_CALL( SCIPmarkRelaxSolInvalid(scip) );
701 SCIPdebugMsg(scip,
"SDP fracdiving heuristic finished\n");
703 SCIPfreeBufferArray(scip, &sdpcandsfrac);
704 SCIPfreeBufferArray(scip, &sdpcandssol);
705 SCIPfreeBufferArray(scip, &sdpcands);
720 SCIP_HEURDATA* heurdata;
724 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
727 SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
731 assert( heur != NULL );
734 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopySdpFracdiving) );
735 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeSdpFracdiving) );
736 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitSdpFracdiving) );
737 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitSdpFracdiving) );
740 SCIP_CALL( SCIPaddRealParam(scip,
742 "minimal relative depth to start diving",
745 SCIP_CALL( SCIPaddRealParam(scip,
747 "maximal relative depth to start diving",
750 SCIP_CALL( SCIPaddRealParam(scip,
751 "heuristics/" HEUR_NAME "/maxdiveubquot",
752 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
755 SCIP_CALL( SCIPaddRealParam(scip,
756 "heuristics/" HEUR_NAME "/maxdiveavgquot",
757 "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
760 SCIP_CALL( SCIPaddRealParam(scip,
761 "heuristics/" HEUR_NAME "/maxdiveubquotnosol",
762 "maximal UBQUOT when no solution was found yet (0.0: no limit)",
765 SCIP_CALL( SCIPaddRealParam(scip,
766 "heuristics/" HEUR_NAME "/maxdiveavgquotnosol",
767 "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
770 SCIP_CALL( SCIPaddBoolParam(scip,
772 "use one level of backtracking if infeasibility is encountered?",
775 SCIP_CALL( SCIPaddBoolParam(scip,
777 "Should the diving heuristic be applied if we are solving LPs?",
#define DEFAULT_MAXDIVEUBQUOTNOSOL
#define DEFAULT_MAXDIVEUBQUOT
#define DEFAULT_MAXDIVEAVGQUOTNOSOL
static SCIP_DECL_HEUREXIT(heurExitSdpFracdiving)
static SCIP_DECL_HEURINIT(heurInitSdpFracdiving)
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
SDP diving heuristic that chooses fixings w.r.t. the fractionalities.
#define DEFAULT_MINRELDEPTH
SCIP_RETCODE SCIPincludeHeurSdpFracdiving(SCIP *scip)
#define DEFAULT_BACKTRACK
#define DEFAULT_MAXRELDEPTH
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
static SCIP_DECL_HEUREXEC(heurExecSdpFracdiving)
static SCIP_DECL_HEURFREE(heurFreeSdpFracdiving)
static SCIP_DECL_HEURCOPY(heurCopySdpFracdiving)
#define DEFAULT_MAXDIVEAVGQUOT