SCIP-SDP  3.2.0
heur_sdpfracdiving.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of SCIPSDP - a solving framework for mixed-integer */
4 /* semidefinite programs based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2020 Discrete Optimization, TU Darmstadt */
9 /* */
10 /* */
11 /* This program is free software; you can redistribute it and/or */
12 /* modify it under the terms of the GNU Lesser General Public License */
13 /* as published by the Free Software Foundation; either version 3 */
14 /* of the License, or (at your option) any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU Lesser General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
24 /* */
25 /* */
26 /* Based on SCIP - Solving Constraint Integer Programs */
27 /* Copyright (C) 2002-2020 Zuse Institute Berlin */
28 /* SCIP is distributed under the terms of the SCIP Academic Licence, */
29 /* see file COPYING in the SCIP distribution. */
30 /* */
31 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 
38 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
39 
40 /* #define SCIP_DEBUG */
41 /* #define SCIP_MORE_DEBUG */ /* shows all diving decisions */
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "heur_sdpfracdiving.h"
47 #include "relax_sdp.h"
48 
49 /* turn off lint warnings for whole file: */
50 /*lint --e{788,818}*/
51 
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
56 #define HEUR_FREQ -1
57 #define HEUR_FREQOFS 0
58 #define HEUR_MAXDEPTH -1
59 #define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
60 #define HEUR_USESSUBSCIP FALSE /* does the heuristic use a secondary SCIP instance? */
61 
62 
63 /*
64  * Default parameter settings
65  */
66 
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
78 /* locally defined heuristic data */
79 struct SCIP_HeurData
80 {
81  SCIP_SOL* sol;
82  SCIP_Real minreldepth;
83  SCIP_Real maxreldepth;
84  SCIP_Real maxdiveubquot;
86  SCIP_Real maxdiveavgquot;
88  SCIP_Real maxdiveubquotnosol;
89  SCIP_Real maxdiveavgquotnosol;
90  SCIP_Bool backtrack;
91  int nsuccess;
92 };
93 
94 /*
95  * Callback methods
96  */
97 
99 static
100 SCIP_DECL_HEURCOPY(heurCopySdpFracdiving)
101 { /*lint --e{715}*/
102  assert(scip != NULL);
103  assert(heur != NULL);
104  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
105 
106  /* call inclusion method of primal heuristic */
107  SCIP_CALL( SCIPincludeHeurSdpFracdiving(scip) );
108 
109  return SCIP_OKAY;
110 }
111 
113 static
114 SCIP_DECL_HEURFREE(heurFreeSdpFracdiving)
115 { /*lint --e{715}*/
116  SCIP_HEURDATA* heurdata;
117 
118  assert(heur != NULL);
119  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
120  assert(scip != NULL);
121 
122  /* free heuristic data */
123  heurdata = SCIPheurGetData(heur);
124  assert(heurdata != NULL);
125  SCIPfreeMemory(scip, &heurdata);
126  SCIPheurSetData(heur, NULL);
127 
128  return SCIP_OKAY;
129 }
130 
131 
133 static
134 SCIP_DECL_HEURINIT(heurInitSdpFracdiving)
135 { /*lint --e{715}*/
136  SCIP_HEURDATA* heurdata;
137 
138  assert(heur != NULL);
139  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
140 
141  /* get heuristic data */
142  heurdata = SCIPheurGetData(heur);
143  assert(heurdata != NULL);
144 
145  /* create working solution */
146  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
147 
148  /* initialize data */
149  heurdata->nsuccess = 0;
150 
151  return SCIP_OKAY;
152 }
153 
154 
156 static
157 SCIP_DECL_HEUREXIT(heurExitSdpFracdiving)
158 { /*lint --e{715}*/
159  SCIP_HEURDATA* heurdata;
160 
161  assert(heur != NULL);
162  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
163 
164  /* get heuristic data */
165  heurdata = SCIPheurGetData(heur);
166  assert(heurdata != NULL);
167 
168  /* free working solution */
169  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
170 
171  return SCIP_OKAY;
172 }
173 
174 
176 static
177 SCIP_DECL_HEUREXEC(heurExecSdpFracdiving)
178 { /*lint --e{715}*/
179  /* the current bugfix branch (3.2.1) does not have SCIPsolveProbingRelax() -> do nothing */
180 #if ( (SCIP_VERSION > 321 || SCIP_SUBVERSION > 0) )
181  SCIP_HEURDATA* heurdata;
182  SCIP_RELAX* relaxsdp;
183  SCIP_VAR** vars;
184  SCIP_VAR* var;
185  SCIP_VAR** sdpcands;
186  SCIP_Bool cutoff;
187  SCIP_Bool bestcandmayrounddown;
188  SCIP_Bool bestcandmayroundup;
189  SCIP_Bool bestcandroundup;
190  SCIP_Bool mayrounddown;
191  SCIP_Bool mayroundup;
192  SCIP_Bool roundup;
193  SCIP_Bool backtracked;
194  SCIP_Bool backtrack;
195  SCIP_Real* sdpcandssol;
196  SCIP_Real* sdpcandsfrac;
197  SCIP_Real searchubbound;
198  SCIP_Real searchavgbound;
199  SCIP_Real searchbound;
200  SCIP_Real objval;
201  SCIP_Real oldobjval;
202  SCIP_Real obj;
203  SCIP_Real objgain;
204  SCIP_Real bestobjgain;
205  SCIP_Real frac;
206  SCIP_Real bestfrac;
207  int nvars;
208  int nsdpcands;
209  int startnsdpcands;
210  int depth;
211  int maxdepth;
212  int maxdivedepth;
213  int divedepth;
214  int bestcand;
215  int c;
216  int v;
217 
218  assert( heur != NULL );
219  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
220  assert( scip != NULL );
221  assert( result != NULL );
222 
223  *result = SCIP_DELAYED;
224 
225  relaxsdp = SCIPfindRelax(scip, "SDP");
226 
227  /* do not run if relaxation solution is not available */
228  if ( ! SCIPisRelaxSolValid(scip) || SCIPrelaxSdpSolvedProbing(relaxsdp) )
229  return SCIP_OKAY;
230 
231  /* do not call heuristic if node was already detected to be infeasible */
232  if ( nodeinfeasible )
233  return SCIP_OKAY;
234 
235  /* don't dive two times at the same node */
236  if ( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
237  return SCIP_OKAY;
238 
239  *result = SCIP_DIDNOTRUN;
240 
241  /* get heuristic's data */
242  heurdata = SCIPheurGetData(heur);
243  assert( heurdata != NULL );
244 
245  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
246  depth = SCIPgetDepth(scip);
247  maxdepth = SCIPgetMaxDepth(scip);
248  maxdepth = MAX(maxdepth, 30);
249  if ( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
250  return SCIP_OKAY;
251 
252  /* get fractional variables that should be integral */
253  vars = SCIPgetVars(scip);
254  nvars = SCIPgetNVars(scip);
255  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcands, nvars) );
256  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandssol, nvars) );
257  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandsfrac, nvars) );
258 
259  nsdpcands = 0;
260  for (v = 0; v < nvars; ++v)
261  {
262  SCIP_Real val;
263 
264  val = SCIPgetRelaxSolVal(scip, vars[v]);
265  frac = SCIPfeasFrac(scip, val);
266 
267  if ( SCIPvarIsIntegral(vars[v]) && ( ! SCIPisFeasZero(scip, frac) ) )
268  {
269  sdpcands[nsdpcands] = vars[v];
270  sdpcandssol[nsdpcands] = val;
271  sdpcandsfrac[nsdpcands] = frac;
272  ++nsdpcands;
273  }
274  }
275 
276  /* don't try to dive, if there are no fractional variables */
277  if ( nsdpcands == 0 )
278  {
279  SCIPfreeBufferArray(scip, &sdpcandsfrac);
280  SCIPfreeBufferArray(scip, &sdpcandssol);
281  SCIPfreeBufferArray(scip, &sdpcands);
282  return SCIP_OKAY;
283  }
284 
285  /* calculate the objective search bound */
286  if ( SCIPgetNSolsFound(scip) == 0 )
287  {
288  if ( heurdata->maxdiveubquotnosol > 0.0 )
289  searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
290  else
291  searchubbound = SCIPinfinity(scip);
292  if ( heurdata->maxdiveavgquotnosol > 0.0 )
293  searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
294  else
295  searchavgbound = SCIPinfinity(scip);
296  }
297  else
298  {
299  if ( heurdata->maxdiveubquot > 0.0 )
300  searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
301  else
302  searchubbound = SCIPinfinity(scip);
303  if ( heurdata->maxdiveavgquot > 0.0 )
304  searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
305  else
306  searchavgbound = SCIPinfinity(scip);
307  }
308  searchbound = MIN(searchubbound, searchavgbound);
309  if ( SCIPisObjIntegral(scip) )
310  searchbound = SCIPceil(scip, searchbound);
311 
312  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
313  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
314  maxdivedepth = MIN(maxdivedepth, maxdepth);
315  maxdivedepth *= 10;
316 
317  *result = SCIP_DIDNOTFIND;
318 
319  /* start diving */
320  SCIP_CALL( SCIPstartProbing(scip) );
321 
322  /* enables collection of variable statistics during probing */
323  SCIPenableVarHistory(scip);
324 
325  /* get SDP objective value*/
326  objval = SCIPgetRelaxSolObj(scip);
327 
328  SCIPdebugMsg(scip, "(node %"SCIP_LONGINT_FORMAT") executing SDP fracdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
329  SCIPgetNNodes(scip), SCIPgetDepth(scip), nsdpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
330 
331  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
332  * - if possible, we dive at least with the depth 10
333  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
334  */
335  cutoff = FALSE;
336  divedepth = 0;
337  bestcandmayrounddown = FALSE;
338  bestcandmayroundup = FALSE;
339  startnsdpcands = nsdpcands;
340  roundup = FALSE;
341 
342  while ( ! cutoff && nsdpcands > 0
343  && ( divedepth < 10
344  || nsdpcands <= startnsdpcands - divedepth/2
345  || (divedepth < maxdivedepth && objval < searchbound))
346  && ! SCIPisStopped(scip) )
347  {
348  SCIP_CALL( SCIPnewProbingNode(scip) );
349  divedepth++;
350 
351  /* choose variable fixing:
352  * - prefer variables that may not be rounded without destroying SDP feasibility:
353  * - of these variables, round least fractional variable in corresponding direction
354  * - if all remaining fractional variables may be rounded without destroying SDP feasibility:
355  * - round variable with least increasing objective value
356  */
357  bestcand = -1;
358  bestobjgain = SCIPinfinity(scip);
359  bestfrac = SCIP_INVALID;
360  bestcandmayrounddown = TRUE;
361  bestcandmayroundup = TRUE;
362  bestcandroundup = FALSE;
363  for (c = 0; c < nsdpcands; ++c)
364  {
365  var = sdpcands[c];
366  mayrounddown = SCIPvarMayRoundDown(var);
367  mayroundup = SCIPvarMayRoundUp(var);
368  frac = sdpcandsfrac[c];
369  obj = SCIPvarGetObj(var);
370  if ( mayrounddown || mayroundup )
371  {
372  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
373  if( bestcandmayrounddown || bestcandmayroundup )
374  {
375  /* choose rounding direction:
376  * - if variable may be rounded in both directions, round corresponding to the fractionality
377  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
378  * the current fractional solution
379  */
380  if ( mayrounddown && mayroundup )
381  roundup = (frac > 0.5);
382  else
383  roundup = mayrounddown;
384 
385  if ( roundup )
386  {
387  frac = 1.0 - frac;
388  objgain = frac*obj;
389  }
390  else
391  objgain = -frac*obj;
392 
393  /* penalize too small fractions */
394  if ( frac < 0.01 )
395  objgain *= 1000.0;
396 
397  /* prefer decisions on binary variables */
398  if ( !SCIPvarIsBinary(var) )
399  objgain *= 1000.0;
400 
401  /* check, if candidate is new best candidate */
402  if ( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
403  {
404  bestcand = c;
405  bestobjgain = objgain;
406  bestfrac = frac;
407  bestcandmayrounddown = mayrounddown;
408  bestcandmayroundup = mayroundup;
409  bestcandroundup = roundup;
410  }
411  }
412  }
413  else
414  {
415  /* the candidate may not be rounded */
416  if ( frac < 0.5 )
417  roundup = FALSE;
418  else
419  {
420  roundup = TRUE;
421  frac = 1.0 - frac;
422  }
423 
424  /* penalize too small fractions */
425  if ( frac < 0.01 )
426  frac += 10.0;
427 
428  /* prefer decisions on binary variables */
429  if ( !SCIPvarIsBinary(var) )
430  frac *= 1000.0;
431 
432  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
433  if ( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
434  {
435  bestcand = c;
436  bestfrac = frac;
437  bestcandmayrounddown = FALSE;
438  bestcandmayroundup = FALSE;
439  bestcandroundup = roundup;
440  }
441  assert( bestfrac < SCIP_INVALID );
442  }
443  }
444  assert( bestcand != -1 );
445 
446  /* if all candidates are roundable, try to round the solution */
447  if ( bestcandmayrounddown || bestcandmayroundup )
448  {
449  SCIP_Bool success;
450 
451  /* create solution from diving SDP and try to round it */
452  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
453  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
454 
455  if ( success )
456  {
457  SCIPdebugMsg(scip, "SDP fracdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
458 
459  /* try to add solution to SCIP */
460  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
461 
462  /* check, if solution was feasible and good enough */
463  if ( success )
464  {
465  SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
466  *result = SCIP_FOUNDSOL;
467  }
468  }
469  }
470 
471  var = sdpcands[bestcand];
472 
473  backtracked = FALSE;
474  do
475  {
476  backtrack = FALSE;
477  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
478  * occured or variable was fixed by propagation while backtracking => Abort diving!
479  */
480  if ( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
481  {
482  SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
483  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), sdpcandssol[bestcand]);
484  cutoff = TRUE;
485  break;
486  }
487  if ( SCIPisFeasLT(scip, sdpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, sdpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
488  {
489  SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
490  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), sdpcandssol[bestcand]);
491 #if 0
492  assert( backtracked ); /* this may happen if we didn't resolve after propagation, in that case we will also abort (or resolve now and start again?) */
493 #endif
494  break;
495  }
496 
497  /* apply rounding of best candidate */
498  if ( bestcandroundup != backtracked )
499  {
500  /* round variable up */
501 #ifdef SCIP_MORE_DEBUG
502  SCIPdebugMsg(scip, " dive %d/%d: var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
503  divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
504  sdpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
505  SCIPfeasCeil(scip, sdpcandssol[bestcand]), SCIPvarGetUbLocal(var));
506 #endif
507  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, sdpcandssol[bestcand])) );
508  roundup = TRUE;
509  }
510  else
511  {
512  /* round variable down */
513 #ifdef SCIP_MORE_DEBUG
514  SCIPdebugMsg(scip, " dive %d/%d: var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
515  divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
516  sdpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
517  SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, sdpcandssol[bestcand]));
518 #endif
519  SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, sdpcandssol[bestcand])) );
520  roundup = FALSE;
521  }
522 
523  /* apply domain propagation */
524  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
525  if ( !cutoff )
526  {
527  /* resolve the diving SDP */
528  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
529 
530  /* as cutoff doesn't work for relax sdp, we have to check ourselves, if we didn't manage to solve successfully, we abort diving */
531  if (! SCIPrelaxSdpSolvedProbing(relaxsdp))
532  {
533  SCIPdebugMsg(scip, "SDP fracdiving heuristic aborted, as we could not solve one of the diving SDPs.\n");
534 
535  SCIPfreeBufferArray(scip, &sdpcandsfrac);
536  SCIPfreeBufferArray(scip, &sdpcandssol);
537  SCIPfreeBufferArray(scip, &sdpcands);
538 
539  *result = SCIP_DIDNOTRUN;
540  SCIP_CALL( SCIPendProbing(scip) );
541 
542  return SCIP_OKAY;
543  }
544 
545  cutoff = ! SCIPrelaxSdpIsFeasible(relaxsdp);
546  }
547 
548  /* perform backtracking if a cutoff was detected */
549  if ( cutoff && ! backtracked && heurdata->backtrack )
550  {
551 #ifdef SCIP_MORE_DEBUG
552  SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
553 #endif
554  SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
555  SCIP_CALL( SCIPnewProbingNode(scip) );
556  backtracked = TRUE;
557  backtrack = TRUE;
558  }
559  else
560  backtrack = FALSE;
561  }
562  while ( backtrack );
563 
564  if ( !cutoff )
565  {
566  /* get new objective value */
567  oldobjval = objval;
568  objval = SCIPgetRelaxSolObj(scip);
569 
570  /* update pseudo cost values */
571  if ( SCIPisGT(scip, objval, oldobjval) )
572  {
573  if( roundup )
574  {
575  assert(bestcandroundup || backtracked);
576  SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 1.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
577  }
578  else
579  {
580  assert(!bestcandroundup || backtracked);
581  SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 0.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
582  }
583  }
584 
585  /* get new fractional variables */
586  nsdpcands = 0;
587  for (v = 0; v < nvars; ++v)
588  {
589  SCIP_Real val;
590 
591  val = SCIPgetRelaxSolVal(scip, vars[v]);
592  frac = SCIPfeasFrac(scip, val);
593 
594  if ( SCIPvarIsIntegral(vars[v]) && ( ! SCIPisFeasZero(scip, frac) ) )
595  {
596  sdpcands[nsdpcands] = vars[v];
597  sdpcandssol[nsdpcands] = val;
598  sdpcandsfrac[nsdpcands] = frac;
599  ++nsdpcands;
600  }
601  }
602  }
603 #ifdef SCIP_MORE_DEBUG
604  SCIPdebugMsg(scip, " -> objval=%g/%g, nfrac=%d\n", objval, searchbound, nsdpcands);
605 #endif
606  }
607 
608  /* check if a solution has been found */
609  if ( nsdpcands == 0 && !cutoff )
610  {
611  SCIP_Bool success;
612 
613  /* create solution from diving SDP */
614  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
615  SCIPdebugMsg(scip, "SDP fracdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
616 
617  /* try to add solution to SCIP */
618  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
619 
620  /* check, if solution was feasible and good enough */
621  if ( success )
622  {
623  SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
624  *result = SCIP_FOUNDSOL;
625  }
626  }
627 
628  /* end diving */
629  SCIP_CALL( SCIPendProbing(scip) );
630 
631  if ( *result == SCIP_FOUNDSOL )
632  heurdata->nsuccess++;
633 
634  SCIPdebugMsg(scip, "SDP fracdiving heuristic finished\n");
635 
636  SCIPfreeBufferArray(scip, &sdpcandsfrac);
637  SCIPfreeBufferArray(scip, &sdpcandssol);
638  SCIPfreeBufferArray(scip, &sdpcands);
639 
640  return SCIP_OKAY;
641 
642 #else
643  *result = SCIP_DIDNOTRUN;
644 
645  return SCIP_OKAY;
646 #endif
647 }
648 
649 
650 /*
651  * heuristic specific interface methods
652  */
653 
655 SCIP_RETCODE SCIPincludeHeurSdpFracdiving(
656  SCIP* scip
657  )
658 {
659  SCIP_HEURDATA* heurdata;
660  SCIP_HEUR* heur;
661 
662  /* create Fracdiving primal heuristic data */
663  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
664 
665  /* include primal heuristic */
666  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
668  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecSdpFracdiving, heurdata) );
669 
670  assert( heur != NULL );
671 
672  /* set non-NULL pointers to callback methods */
673  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopySdpFracdiving) );
674  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeSdpFracdiving) );
675  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitSdpFracdiving) );
676  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitSdpFracdiving) );
677 
678  /* fracdiving heuristic parameters */
679  SCIP_CALL( SCIPaddRealParam(scip,
680  "heuristics/sdpfracdiving/minreldepth",
681  "minimal relative depth to start diving",
682  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
683  SCIP_CALL( SCIPaddRealParam(scip,
684  "heuristics/sdpfracdiving/maxreldepth",
685  "maximal relative depth to start diving",
686  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
687  SCIP_CALL( SCIPaddRealParam(scip,
688  "heuristics/sdpfracdiving/maxdiveubquot",
689  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
690  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
691  SCIP_CALL( SCIPaddRealParam(scip,
692  "heuristics/sdpfracdiving/maxdiveavgquot",
693  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
694  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
695  SCIP_CALL( SCIPaddRealParam(scip,
696  "heuristics/sdpfracdiving/maxdiveubquotnosol",
697  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
698  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
699  SCIP_CALL( SCIPaddRealParam(scip,
700  "heuristics/sdpfracdiving/maxdiveavgquotnosol",
701  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
702  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
703  SCIP_CALL( SCIPaddBoolParam(scip,
704  "heuristics/sdpfracdiving/backtrack",
705  "use one level of backtracking if infeasibility is encountered?",
706  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
707 
708  return SCIP_OKAY;
709 }
710 
#define HEUR_MAXDEPTH
#define DEFAULT_MAXDIVEUBQUOTNOSOL
#define DEFAULT_MAXDIVEUBQUOT
#define HEUR_DISPCHAR
SDP-relaxator.
#define HEUR_FREQ
#define HEUR_DESC
#define DEFAULT_MAXDIVEAVGQUOTNOSOL
#define HEUR_FREQOFS
static SCIP_DECL_HEUREXIT(heurExitSdpFracdiving)
static SCIP_DECL_HEURINIT(heurInitSdpFracdiving)
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
Definition: relax_sdp.c:5080
#define HEUR_PRIORITY
#define HEUR_USESSUBSCIP
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)
Definition: relax_sdp.c:5097
static SCIP_DECL_HEUREXEC(heurExecSdpFracdiving)
static SCIP_DECL_HEURFREE(heurFreeSdpFracdiving)
#define HEUR_TIMING
static SCIP_DECL_HEURCOPY(heurCopySdpFracdiving)
#define HEUR_NAME
#define DEFAULT_MAXDIVEAVGQUOT