SCIP-SDP  2.1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 programms based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2016 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-2016 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_VAR** vars;
183  SCIP_VAR* var;
184  SCIP_VAR** sdpcands;
185  SCIP_Bool cutoff;
186  SCIP_Bool bestcandmayrounddown;
187  SCIP_Bool bestcandmayroundup;
188  SCIP_Bool bestcandroundup;
189  SCIP_Bool mayrounddown;
190  SCIP_Bool mayroundup;
191  SCIP_Bool roundup;
192  SCIP_Bool backtracked;
193  SCIP_Bool backtrack;
194  SCIP_Real* sdpcandssol;
195  SCIP_Real* sdpcandsfrac;
196  SCIP_Real searchubbound;
197  SCIP_Real searchavgbound;
198  SCIP_Real searchbound;
199  SCIP_Real objval;
200  SCIP_Real oldobjval;
201  SCIP_Real obj;
202  SCIP_Real objgain;
203  SCIP_Real bestobjgain;
204  SCIP_Real frac;
205  SCIP_Real bestfrac;
206  int nvars;
207  int nsdpcands;
208  int startnsdpcands;
209  int depth;
210  int maxdepth;
211  int maxdivedepth;
212  int divedepth;
213  int bestcand;
214  int c;
215  int v;
216 
217  assert( heur != NULL );
218  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
219  assert( scip != NULL );
220  assert( result != NULL );
221 
222  *result = SCIP_DELAYED;
223 
224  /* do not run if relaxation solution is not available */
225  if ( ! SCIPisRelaxSolValid(scip) )
226  return SCIP_OKAY;
227 
228  /* do not call heuristic if node was already detected to be infeasible */
229  if ( nodeinfeasible )
230  return SCIP_OKAY;
231 
232  /* don't dive two times at the same node */
233  if ( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
234  return SCIP_OKAY;
235 
236  *result = SCIP_DIDNOTRUN;
237 
238  /* get heuristic's data */
239  heurdata = SCIPheurGetData(heur);
240  assert( heurdata != NULL );
241 
242  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
243  depth = SCIPgetDepth(scip);
244  maxdepth = SCIPgetMaxDepth(scip);
245  maxdepth = MAX(maxdepth, 30);
246  if ( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
247  return SCIP_OKAY;
248 
249  /* get fractional variables that should be integral */
250  vars = SCIPgetVars(scip);
251  nvars = SCIPgetNVars(scip);
252  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcands, nvars) );
253  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandssol, nvars) );
254  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandsfrac, nvars) );
255 
256  nsdpcands = 0;
257  for (v = 0; v < nvars; ++v)
258  {
259  SCIP_Real val;
260 
261  val = SCIPgetRelaxSolVal(scip, vars[v]);
262  frac = SCIPfeasFrac(scip, val);
263 
264  if ( SCIPvarIsIntegral(vars[v]) && ( ! SCIPisFeasZero(scip, frac) ) )
265  {
266  sdpcands[nsdpcands] = vars[v];
267  sdpcandssol[nsdpcands] = val;
268  sdpcandsfrac[nsdpcands] = frac;
269  ++nsdpcands;
270  }
271  }
272 
273  /* don't try to dive, if there are no fractional variables */
274  if ( nsdpcands == 0 )
275  {
276  SCIPfreeBufferArray(scip, &sdpcandsfrac);
277  SCIPfreeBufferArray(scip, &sdpcandssol);
278  SCIPfreeBufferArray(scip, &sdpcands);
279  return SCIP_OKAY;
280  }
281 
282  /* calculate the objective search bound */
283  if ( SCIPgetNSolsFound(scip) == 0 )
284  {
285  if ( heurdata->maxdiveubquotnosol > 0.0 )
286  searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
287  else
288  searchubbound = SCIPinfinity(scip);
289  if ( heurdata->maxdiveavgquotnosol > 0.0 )
290  searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
291  else
292  searchavgbound = SCIPinfinity(scip);
293  }
294  else
295  {
296  if ( heurdata->maxdiveubquot > 0.0 )
297  searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
298  else
299  searchubbound = SCIPinfinity(scip);
300  if ( heurdata->maxdiveavgquot > 0.0 )
301  searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
302  else
303  searchavgbound = SCIPinfinity(scip);
304  }
305  searchbound = MIN(searchubbound, searchavgbound);
306  if ( SCIPisObjIntegral(scip) )
307  searchbound = SCIPceil(scip, searchbound);
308 
309  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
310  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
311  maxdivedepth = MIN(maxdivedepth, maxdepth);
312  maxdivedepth *= 10;
313 
314  *result = SCIP_DIDNOTFIND;
315 
316  /* start diving */
317  SCIP_CALL( SCIPstartProbing(scip) );
318 
319  /* enables collection of variable statistics during probing */
320  SCIPenableVarHistory(scip);
321 
322  /* get SDP objective value*/
323  objval = SCIPgetRelaxSolObj(scip);
324 
325  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing SDP fracdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
326  SCIPgetNNodes(scip), SCIPgetDepth(scip), nsdpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
327 
328  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
329  * - if possible, we dive at least with the depth 10
330  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
331  */
332  cutoff = FALSE;
333  divedepth = 0;
334  bestcandmayrounddown = FALSE;
335  bestcandmayroundup = FALSE;
336  startnsdpcands = nsdpcands;
337  roundup = FALSE;
338 
339  while ( ! cutoff && nsdpcands > 0
340  && ( divedepth < 10
341  || nsdpcands <= startnsdpcands - divedepth/2
342  || (divedepth < maxdivedepth && objval < searchbound))
343  && ! SCIPisStopped(scip) )
344  {
345  SCIP_CALL( SCIPnewProbingNode(scip) );
346  divedepth++;
347 
348  /* choose variable fixing:
349  * - prefer variables that may not be rounded without destroying SDP feasibility:
350  * - of these variables, round least fractional variable in corresponding direction
351  * - if all remaining fractional variables may be rounded without destroying SDP feasibility:
352  * - round variable with least increasing objective value
353  */
354  bestcand = -1;
355  bestobjgain = SCIPinfinity(scip);
356  bestfrac = SCIP_INVALID;
357  bestcandmayrounddown = TRUE;
358  bestcandmayroundup = TRUE;
359  bestcandroundup = FALSE;
360  for (c = 0; c < nsdpcands; ++c)
361  {
362  var = sdpcands[c];
363  mayrounddown = SCIPvarMayRoundDown(var);
364  mayroundup = SCIPvarMayRoundUp(var);
365  frac = sdpcandsfrac[c];
366  obj = SCIPvarGetObj(var);
367  if ( mayrounddown || mayroundup )
368  {
369  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
370  if( bestcandmayrounddown || bestcandmayroundup )
371  {
372  /* choose rounding direction:
373  * - if variable may be rounded in both directions, round corresponding to the fractionality
374  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
375  * the current fractional solution
376  */
377  if ( mayrounddown && mayroundup )
378  roundup = (frac > 0.5);
379  else
380  roundup = mayrounddown;
381 
382  if ( roundup )
383  {
384  frac = 1.0 - frac;
385  objgain = frac*obj;
386  }
387  else
388  objgain = -frac*obj;
389 
390  /* penalize too small fractions */
391  if ( frac < 0.01 )
392  objgain *= 1000.0;
393 
394  /* prefer decisions on binary variables */
395  if ( !SCIPvarIsBinary(var) )
396  objgain *= 1000.0;
397 
398  /* check, if candidate is new best candidate */
399  if ( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
400  {
401  bestcand = c;
402  bestobjgain = objgain;
403  bestfrac = frac;
404  bestcandmayrounddown = mayrounddown;
405  bestcandmayroundup = mayroundup;
406  bestcandroundup = roundup;
407  }
408  }
409  }
410  else
411  {
412  /* the candidate may not be rounded */
413  if ( frac < 0.5 )
414  roundup = FALSE;
415  else
416  {
417  roundup = TRUE;
418  frac = 1.0 - frac;
419  }
420 
421  /* penalize too small fractions */
422  if ( frac < 0.01 )
423  frac += 10.0;
424 
425  /* prefer decisions on binary variables */
426  if ( !SCIPvarIsBinary(var) )
427  frac *= 1000.0;
428 
429  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
430  if ( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
431  {
432  bestcand = c;
433  bestfrac = frac;
434  bestcandmayrounddown = FALSE;
435  bestcandmayroundup = FALSE;
436  bestcandroundup = roundup;
437  }
438  assert( bestfrac < SCIP_INVALID );
439  }
440  }
441  assert( bestcand != -1 );
442 
443  /* if all candidates are roundable, try to round the solution */
444  if ( bestcandmayrounddown || bestcandmayroundup )
445  {
446  SCIP_Bool success;
447 
448  /* create solution from diving SDP and try to round it */
449  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
450  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
451 
452  if ( success )
453  {
454  SCIPdebugMessage("SDP fracdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
455 
456  /* try to add solution to SCIP */
457  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
458 
459  /* check, if solution was feasible and good enough */
460  if ( success )
461  {
462  SCIPdebugMessage(" -> solution was feasible and good enough\n");
463  *result = SCIP_FOUNDSOL;
464  }
465  }
466  }
467 
468  var = sdpcands[bestcand];
469 
470  backtracked = FALSE;
471  do
472  {
473  backtrack = FALSE;
474  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
475  * occured or variable was fixed by propagation while backtracking => Abort diving!
476  */
477  if ( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
478  {
479  SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
480  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), sdpcandssol[bestcand]);
481  cutoff = TRUE;
482  break;
483  }
484  if ( SCIPisFeasLT(scip, sdpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, sdpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
485  {
486  SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
487  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), sdpcandssol[bestcand]);
488 #if 0
489  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?) */
490 #endif
491  break;
492  }
493 
494  /* apply rounding of best candidate */
495  if ( bestcandroundup != backtracked )
496  {
497  /* round variable up */
498 #ifdef SCIP_MORE_DEBUG
499  SCIPdebugMessage(" dive %d/%d: var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
500  divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
501  sdpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
502  SCIPfeasCeil(scip, sdpcandssol[bestcand]), SCIPvarGetUbLocal(var));
503 #endif
504  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, sdpcandssol[bestcand])) );
505  roundup = TRUE;
506  }
507  else
508  {
509  /* round variable down */
510 #ifdef SCIP_MORE_DEBUG
511  SCIPdebugMessage(" dive %d/%d: var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
512  divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
513  sdpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
514  SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, sdpcandssol[bestcand]));
515 #endif
516  SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, sdpcandssol[bestcand])) );
517  roundup = FALSE;
518  }
519 
520  /* apply domain propagation */
521  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
522  if ( !cutoff )
523  {
524  SCIP_RELAX* relaxsdp;
525 
526  /* resolve the diving SDP */
527  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
528 
529  /* as cutoff doesn't work for relax sdp, we have to check ourselves, if we didn't manage to solve successfully, we abort diving */
530  relaxsdp = SCIPfindRelax(scip, "SDP");
531 
532  /* if solving was unsuccessfull, abort */
533  if (! SCIPrelaxSdpSolvedProbing(relaxsdp))
534  {
535  SCIPdebugMessage("SDP fracdiving heuristic aborted, as we could not solve one of the diving SDPs.\n");
536 
537  SCIPfreeBufferArray(scip, &sdpcandsfrac);
538  SCIPfreeBufferArray(scip, &sdpcandssol);
539  SCIPfreeBufferArray(scip, &sdpcands);
540 
541  *result = SCIP_DIDNOTRUN;
542  SCIP_CALL( SCIPendProbing(scip) );
543 
544  return SCIP_OKAY;
545  }
546 
547  cutoff = ! SCIPrelaxSdpIsFeasible(relaxsdp);
548  }
549 
550  /* perform backtracking if a cutoff was detected */
551  if ( cutoff && ! backtracked && heurdata->backtrack )
552  {
553 #ifdef SCIP_MORE_DEBUG
554  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
555 #endif
556  SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
557  SCIP_CALL( SCIPnewProbingNode(scip) );
558  backtracked = TRUE;
559  backtrack = TRUE;
560  }
561  else
562  backtrack = FALSE;
563  }
564  while ( backtrack );
565 
566  if ( !cutoff )
567  {
568  /* get new objective value */
569  oldobjval = objval;
570  objval = SCIPgetRelaxSolObj(scip);
571 
572  /* update pseudo cost values */
573  if ( SCIPisGT(scip, objval, oldobjval) )
574  {
575  if( roundup )
576  {
577  assert(bestcandroundup || backtracked);
578  SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 1.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
579  }
580  else
581  {
582  assert(!bestcandroundup || backtracked);
583  SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 0.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
584  }
585  }
586 
587  /* get new fractional variables */
588  nsdpcands = 0;
589  for (v = 0; v < nvars; ++v)
590  {
591  SCIP_Real val;
592 
593  val = SCIPgetRelaxSolVal(scip, vars[v]);
594  frac = SCIPfeasFrac(scip, val);
595 
596  if ( SCIPvarIsIntegral(vars[v]) && ( ! SCIPisFeasZero(scip, frac) ) )
597  {
598  sdpcands[nsdpcands] = vars[v];
599  sdpcandssol[nsdpcands] = val;
600  sdpcandsfrac[nsdpcands] = frac;
601  ++nsdpcands;
602  }
603  }
604  }
605 #ifdef SCIP_MORE_DEBUG
606  SCIPdebugMessage(" -> objval=%g/%g, nfrac=%d\n", objval, searchbound, nsdpcands);
607 #endif
608  }
609 
610  /* check if a solution has been found */
611  if ( nsdpcands == 0 && !cutoff )
612  {
613  SCIP_Bool success;
614 
615  /* create solution from diving SDP */
616  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
617  SCIPdebugMessage("SDP fracdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
618 
619  /* try to add solution to SCIP */
620  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
621 
622  /* check, if solution was feasible and good enough */
623  if ( success )
624  {
625  SCIPdebugMessage(" -> solution was feasible and good enough\n");
626  *result = SCIP_FOUNDSOL;
627  }
628  }
629 
630  /* end diving */
631  SCIP_CALL( SCIPendProbing(scip) );
632 
633  if ( *result == SCIP_FOUNDSOL )
634  heurdata->nsuccess++;
635 
636  SCIPdebugMessage("SDP fracdiving heuristic finished\n");
637 
638  SCIPfreeBufferArray(scip, &sdpcandsfrac);
639  SCIPfreeBufferArray(scip, &sdpcandssol);
640  SCIPfreeBufferArray(scip, &sdpcands);
641 
642  return SCIP_OKAY;
643 
644 #else
645  *result = SCIP_DIDNOTRUN;
646 
647  return SCIP_OKAY;
648 #endif
649 }
650 
651 
652 /*
653  * heuristic specific interface methods
654  */
655 
657 SCIP_RETCODE SCIPincludeHeurSdpFracdiving(
658  SCIP* scip
659  )
660 {
661  SCIP_HEURDATA* heurdata;
662  SCIP_HEUR* heur;
663 
664  /* create Fracdiving primal heuristic data */
665  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
666 
667  /* include primal heuristic */
668  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
670  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecSdpFracdiving, heurdata) );
671 
672  assert( heur != NULL );
673 
674  /* set non-NULL pointers to callback methods */
675  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopySdpFracdiving) );
676  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeSdpFracdiving) );
677  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitSdpFracdiving) );
678  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitSdpFracdiving) );
679 
680  /* fracdiving heuristic parameters */
681  SCIP_CALL( SCIPaddRealParam(scip,
682  "heuristics/sdpfracdiving/minreldepth",
683  "minimal relative depth to start diving",
684  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
685  SCIP_CALL( SCIPaddRealParam(scip,
686  "heuristics/sdpfracdiving/maxreldepth",
687  "maximal relative depth to start diving",
688  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
689  SCIP_CALL( SCIPaddRealParam(scip,
690  "heuristics/sdpfracdiving/maxdiveubquot",
691  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
692  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
693  SCIP_CALL( SCIPaddRealParam(scip,
694  "heuristics/sdpfracdiving/maxdiveavgquot",
695  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
696  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
697  SCIP_CALL( SCIPaddRealParam(scip,
698  "heuristics/sdpfracdiving/maxdiveubquotnosol",
699  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
700  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
701  SCIP_CALL( SCIPaddRealParam(scip,
702  "heuristics/sdpfracdiving/maxdiveavgquotnosol",
703  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
704  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
705  SCIP_CALL( SCIPaddBoolParam(scip,
706  "heuristics/sdpfracdiving/backtrack",
707  "use one level of backtracking if infeasibility is encountered?",
708  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
709 
710  return SCIP_OKAY;
711 }
712 
#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:1857
#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:1874
static SCIP_DECL_HEUREXEC(heurExecSdpFracdiving)
static SCIP_DECL_HEURFREE(heurFreeSdpFracdiving)
#define HEUR_TIMING
static SCIP_DECL_HEURCOPY(heurCopySdpFracdiving)
#define HEUR_NAME
#define DEFAULT_MAXDIVEAVGQUOT