SCIP-SDP  4.0.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-2021 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-2021 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
76 #define DEFAULT_RUNFORLP FALSE
79 /* locally defined heuristic data */
80 struct SCIP_HeurData
81 {
82  SCIP_SOL* sol;
83  SCIP_Real minreldepth;
84  SCIP_Real maxreldepth;
85  SCIP_Real maxdiveubquot;
87  SCIP_Real maxdiveavgquot;
89  SCIP_Real maxdiveubquotnosol;
90  SCIP_Real maxdiveavgquotnosol;
91  SCIP_Bool backtrack;
92  SCIP_Bool runforlp;
93  int nsuccess;
94 };
95 
96 /*
97  * Callback methods
98  */
99 
101 static
102 SCIP_DECL_HEURCOPY(heurCopySdpFracdiving)
103 { /*lint --e{715}*/
104  assert(scip != NULL);
105  assert(heur != NULL);
106  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
107 
108  /* call inclusion method of primal heuristic */
109  SCIP_CALL( SCIPincludeHeurSdpFracdiving(scip) );
110 
111  return SCIP_OKAY;
112 }
113 
115 static
116 SCIP_DECL_HEURFREE(heurFreeSdpFracdiving)
117 { /*lint --e{715}*/
118  SCIP_HEURDATA* heurdata;
119 
120  assert(heur != NULL);
121  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
122  assert(scip != NULL);
123 
124  /* free heuristic data */
125  heurdata = SCIPheurGetData(heur);
126  assert(heurdata != NULL);
127  SCIPfreeBlockMemory(scip, &heurdata);
128  SCIPheurSetData(heur, NULL);
129 
130  return SCIP_OKAY;
131 }
132 
133 
135 static
136 SCIP_DECL_HEURINIT(heurInitSdpFracdiving)
137 { /*lint --e{715}*/
138  SCIP_HEURDATA* heurdata;
139 
140  assert(heur != NULL);
141  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
142 
143  /* get heuristic data */
144  heurdata = SCIPheurGetData(heur);
145  assert(heurdata != NULL);
146 
147  /* create working solution */
148  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
149 
150  /* initialize data */
151  heurdata->nsuccess = 0;
152 
153  return SCIP_OKAY;
154 }
155 
156 
158 static
159 SCIP_DECL_HEUREXIT(heurExitSdpFracdiving)
160 { /*lint --e{715}*/
161  SCIP_HEURDATA* heurdata;
162 
163  assert(heur != NULL);
164  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
165 
166  /* get heuristic data */
167  heurdata = SCIPheurGetData(heur);
168  assert(heurdata != NULL);
169 
170  /* free working solution */
171  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
172 
173  return SCIP_OKAY;
174 }
175 
176 
178 static
179 SCIP_DECL_HEUREXEC(heurExecSdpFracdiving)
180 { /*lint --e{715}*/
181  SCIP_HEURDATA* heurdata;
182  SCIP_CONSHDLR* conshdlrsdp;
183  SCIP_RELAX* relaxsdp;
184  SCIP_VAR** vars;
185  SCIP_VAR* var;
186  SCIP_VAR** sdpcands;
187  SCIP_Bool cutoff;
188  SCIP_Bool bestcandmayrounddown;
189  SCIP_Bool bestcandmayroundup;
190  SCIP_Bool bestcandroundup;
191  SCIP_Bool mayrounddown;
192  SCIP_Bool mayroundup;
193  SCIP_Bool roundup;
194  SCIP_Bool backtracked;
195  SCIP_Bool backtrack;
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;
202  SCIP_Real objval;
203  SCIP_Real oldobjval;
204  SCIP_Real obj;
205  SCIP_Real objgain;
206  SCIP_Real bestobjgain;
207  SCIP_Real frac;
208  SCIP_Real bestfrac;
209  SCIP_SOL* relaxsol = NULL;
210  int freq = -1;
211  int nvars;
212  int nsdpcands;
213  int startnsdpcands;
214  int depth;
215  int maxdepth;
216  int maxdivedepth;
217  int divedepth;
218  int bestcand;
219  int c;
220  int v;
221 
222  assert( heur != NULL );
223  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
224  assert( scip != NULL );
225  assert( result != NULL );
226 
227  *result = SCIP_DELAYED;
228 
229  /* do not call heuristic if node was already detected to be infeasible */
230  if ( nodeinfeasible )
231  return SCIP_OKAY;
232 
233  *result = SCIP_DIDNOTRUN;
234 
235  /* avoid solving for sub-SCIPs, since it is too expensive */
236  if ( SCIPgetSubscipDepth(scip) > 0 )
237  return SCIP_OKAY;
238 
239  /* don't dive two times at the same node */
240  if ( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
241  return SCIP_OKAY;
242 
243  /* get heuristic's data */
244  heurdata = SCIPheurGetData(heur);
245  assert( heurdata != NULL );
246 
247  /* do not run if relaxation solution is not available and we do not want to run for LPs or no LP solution is available */
248  if ( ! SCIPisRelaxSolValid(scip) )
249  {
250  /* exit if we do not want to run for LPs */
251  if ( ! heurdata->runforlp )
252  return SCIP_OKAY;
253 
254  /* exit if LP is not solved */
255  if ( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
256  return SCIP_OKAY;
257 
258  usesdp = FALSE;
259  }
260 
261  relaxsdp = SCIPfindRelax(scip, "SDP");
262  if ( relaxsdp == NULL )
263  return SCIP_OKAY;
264 
265  conshdlrsdp = SCIPfindConshdlr(scip, "SDP");
266  if ( conshdlrsdp == NULL )
267  return SCIP_OKAY;
268 
269  /* exit if there are no SDP constraints */
270  if ( SCIPconshdlrGetNConss(conshdlrsdp) <= 0 )
271  return SCIP_OKAY;
272 
273  /* decide with solution to use */
274  if ( usesdp )
275  {
276  SCIP_CALL( SCIPcreateRelaxSol(scip, &relaxsol, heur) );
277  }
278 
279  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
280  depth = SCIPgetDepth(scip);
281  maxdepth = SCIPgetMaxDepth(scip);
282  maxdepth = MAX(maxdepth, 30);
283  if ( depth < heurdata->minreldepth * maxdepth || depth > heurdata->maxreldepth * maxdepth )
284  return SCIP_OKAY;
285 
286  /* get fractional variables that should be integral */
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) );
292 
293  nsdpcands = 0;
294  for (v = 0; v < nvars; ++v)
295  {
296  SCIP_Real val;
297 
298  val = SCIPgetSolVal(scip, relaxsol, vars[v]);
299  frac = SCIPfeasFrac(scip, val);
300 
301  if ( SCIPvarIsIntegral(vars[v]) && ! SCIPisFeasZero(scip, frac) )
302  {
303  sdpcands[nsdpcands] = vars[v];
304  sdpcandssol[nsdpcands] = val;
305  sdpcandsfrac[nsdpcands] = frac;
306  ++nsdpcands;
307  }
308  }
309 
310  /* get SDP objective value */
311  objval = SCIPgetSolTransObj(scip, relaxsol);
312 
313  /* possibly free relaxtion (LP or SDP) solution */
314  if ( relaxsol != NULL )
315  {
316  SCIP_CALL( SCIPfreeSol(scip, &relaxsol) );
317  }
318 
319  /* don't try to dive, if there are no fractional variables */
320  if ( nsdpcands == 0 )
321  {
322  SCIPfreeBufferArray(scip, &sdpcandsfrac);
323  SCIPfreeBufferArray(scip, &sdpcandssol);
324  SCIPfreeBufferArray(scip, &sdpcands);
325  return SCIP_OKAY;
326  }
327 
328  /* calculate the objective search bound */
329  if ( SCIPgetNSolsFound(scip) == 0 )
330  {
331  if ( heurdata->maxdiveubquotnosol > 0.0 )
332  searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
333  else
334  searchubbound = SCIPinfinity(scip);
335 
336  if ( heurdata->maxdiveavgquotnosol > 0.0 )
337  searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
338  else
339  searchavgbound = SCIPinfinity(scip);
340  }
341  else
342  {
343  if ( heurdata->maxdiveubquot > 0.0 )
344  searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
345  else
346  searchubbound = SCIPinfinity(scip);
347 
348  if ( heurdata->maxdiveavgquot > 0.0 )
349  searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
350  else
351  searchavgbound = SCIPinfinity(scip);
352  }
353  searchbound = MIN(searchubbound, searchavgbound);
354  if ( SCIPisObjIntegral(scip) )
355  searchbound = SCIPceil(scip, searchbound);
356 
357  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
358  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
359  maxdivedepth = MIN(maxdivedepth, maxdepth);
360  maxdivedepth *= 10;
361 
362  *result = SCIP_DIDNOTFIND;
363 
364  /* start diving */
365  SCIP_CALL( SCIPstartProbing(scip) );
366 
367  /* enables collection of variable statistics during probing */
368  SCIPenableVarHistory(scip);
369 
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));
372 
373  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
374  * - if possible, we dive at least with the depth 10
375  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
376  */
377  cutoff = FALSE;
378  divedepth = 0;
379  bestcandmayrounddown = FALSE;
380  bestcandmayroundup = FALSE;
381  startnsdpcands = nsdpcands;
382  roundup = FALSE;
383 
384  if ( ! usesdp )
385  {
386  /* temporarily change relaxator frequency, since otherwise relaxation will not be solved */
387  freq = SCIPrelaxGetFreq(relaxsdp);
388  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", 1) );
389  }
390 
391  while ( ! cutoff && nsdpcands > 0
392  && ( divedepth < 10
393  || nsdpcands <= startnsdpcands - divedepth/2
394  || (divedepth < maxdivedepth && objval < searchbound))
395  && ! SCIPisStopped(scip) )
396  {
397  SCIP_CALL( SCIPnewProbingNode(scip) );
398  divedepth++;
399 
400  /* choose variable fixing:
401  * - prefer variables that may not be rounded without destroying SDP feasibility:
402  * - of these variables, round least fractional variable in corresponding direction
403  * - if all remaining fractional variables may be rounded without destroying SDP feasibility:
404  * - round variable with least increasing objective value
405  */
406  bestcand = -1;
407  bestobjgain = SCIPinfinity(scip);
408  bestfrac = SCIP_INVALID;
409  bestcandmayrounddown = TRUE;
410  bestcandmayroundup = TRUE;
411  bestcandroundup = FALSE;
412 
413  for (c = 0; c < nsdpcands; ++c)
414  {
415  var = sdpcands[c];
416  mayrounddown = SCIPvarMayRoundDown(var);
417  mayroundup = SCIPvarMayRoundUp(var);
418  frac = sdpcandsfrac[c];
419  obj = SCIPvarGetObj(var);
420 
421  if ( mayrounddown || mayroundup )
422  {
423  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
424  if( bestcandmayrounddown || bestcandmayroundup )
425  {
426  /* choose rounding direction:
427  * - if variable may be rounded in both directions, round corresponding to the fractionality
428  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
429  * the current fractional solution
430  */
431  if ( mayrounddown && mayroundup )
432  roundup = (frac > 0.5);
433  else
434  roundup = mayrounddown;
435 
436  if ( roundup )
437  {
438  frac = 1.0 - frac;
439  objgain = frac * obj;
440  }
441  else
442  objgain = - frac * obj;
443 
444  /* penalize too small fractions */
445  if ( frac < 0.01 )
446  objgain *= 1000.0;
447 
448  /* prefer decisions on binary variables */
449  if ( ! SCIPvarIsBinary(var) )
450  objgain *= 1000.0;
451 
452  /* check, if candidate is new best candidate */
453  if ( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
454  {
455  bestcand = c;
456  bestobjgain = objgain;
457  bestfrac = frac;
458  bestcandmayrounddown = mayrounddown;
459  bestcandmayroundup = mayroundup;
460  bestcandroundup = roundup;
461  }
462  }
463  }
464  else
465  {
466  /* the candidate may not be rounded */
467  if ( frac < 0.5 )
468  roundup = FALSE;
469  else
470  {
471  roundup = TRUE;
472  frac = 1.0 - frac;
473  }
474 
475  /* penalize too small fractions */
476  if ( frac < 0.01 )
477  frac += 10.0;
478 
479  /* prefer decisions on binary variables */
480  if ( ! SCIPvarIsBinary(var) )
481  frac *= 1000.0;
482 
483  /* check if candidate is new best candidate: prefer roundable candidates in any case */
484  if ( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
485  {
486  bestcand = c;
487  bestfrac = frac;
488  bestcandmayrounddown = FALSE;
489  bestcandmayroundup = FALSE;
490  bestcandroundup = roundup;
491  }
492  assert( bestfrac < SCIP_INVALID );
493  }
494  }
495  assert( bestcand != -1 );
496 
497  /* if all candidates are roundable, try to round the solution */
498  if ( bestcandmayrounddown || bestcandmayroundup )
499  {
500  SCIP_Bool success;
501 
502  /* create solution from diving SDP and try to round it */
503  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
504  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
505 
506  if ( success )
507  {
508  SCIPdebugMsg(scip, "SDP fracdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
509 
510  /* try to add solution to SCIP */
511  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
512 
513  /* check, if solution was feasible and good enough */
514  if ( success )
515  {
516  SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
517  *result = SCIP_FOUNDSOL;
518  }
519  }
520  }
521 
522  var = sdpcands[bestcand];
523 
524  backtracked = FALSE;
525  do
526  {
527  backtrack = FALSE;
528 
529  /* If the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
530  * occured or variable was fixed by propagation while backtracking => abort diving! */
531  if ( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
532  {
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]);
535  cutoff = TRUE;
536  break;
537  }
538 
539  if ( SCIPisFeasLT(scip, sdpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, sdpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
540  {
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]);
543 #if 0
544  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?) */
545 #endif
546  break;
547  }
548 
549  /* apply rounding of best candidate */
550  if ( bestcandroundup != backtracked )
551  {
552  /* round variable up */
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));
558 #endif
559  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, sdpcandssol[bestcand])) );
560  roundup = TRUE;
561  }
562  else
563  {
564  /* round variable down */
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]));
570 #endif
571  SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, sdpcandssol[bestcand])) );
572  roundup = FALSE;
573  }
574 
575  /* apply domain propagation */
576  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
577  if ( ! cutoff )
578  {
579  /* resolve the diving SDP */
580  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
581 
582  /* make sure that we solved the SDP successfully */
583  if ( ! SCIPrelaxSdpSolvedProbing(relaxsdp) )
584  {
585  SCIPdebugMsg(scip, "SDP fracdiving heuristic aborted, as we could not solve one of the diving SDPs.\n");
586 
587  SCIPfreeBufferArray(scip, &sdpcandsfrac);
588  SCIPfreeBufferArray(scip, &sdpcandssol);
589  SCIPfreeBufferArray(scip, &sdpcands);
590 
591  *result = SCIP_DIDNOTRUN;
592  SCIP_CALL( SCIPendProbing(scip) );
593 
594  /* reset frequency of relaxator */
595  if ( ! usesdp )
596  {
597  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", freq) );
598  }
599 
600  return SCIP_OKAY;
601  }
602 
603  cutoff = ! SCIPrelaxSdpIsFeasible(relaxsdp);
604  }
605 
606  /* perform backtracking if a cutoff was detected */
607  if ( cutoff && ! backtracked && heurdata->backtrack )
608  {
609 #ifdef SCIP_MORE_DEBUG
610  SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
611 #endif
612  SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
613  SCIP_CALL( SCIPnewProbingNode(scip) );
614  backtracked = TRUE;
615  backtrack = TRUE;
616  }
617  else
618  backtrack = FALSE;
619  }
620  while ( backtrack );
621 
622  if ( ! cutoff )
623  {
624  /* get new objective value */
625  oldobjval = objval;
626  objval = SCIPgetRelaxSolObj(scip);
627 
628  /* update pseudo cost values */
629  if ( SCIPisGT(scip, objval, oldobjval) )
630  {
631  if( roundup )
632  {
633  assert(bestcandroundup || backtracked);
634  SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 1.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
635  }
636  else
637  {
638  assert(!bestcandroundup || backtracked);
639  SCIP_CALL( SCIPupdateVarPseudocost(scip, sdpcands[bestcand], 0.0 - sdpcandsfrac[bestcand], objval - oldobjval, 1.0) );
640  }
641  }
642 
643  /* get new fractional variables */
644  nsdpcands = 0;
645  for (v = 0; v < nvars; ++v)
646  {
647  SCIP_Real val;
648 
649  val = SCIPgetRelaxSolVal(scip, vars[v]);
650  frac = SCIPfeasFrac(scip, val);
651 
652  if ( SCIPvarIsIntegral(vars[v]) && ( ! SCIPisFeasZero(scip, frac) ) )
653  {
654  sdpcands[nsdpcands] = vars[v];
655  sdpcandssol[nsdpcands] = val;
656  sdpcandsfrac[nsdpcands] = frac;
657  ++nsdpcands;
658  }
659  }
660  }
661 #ifdef SCIP_MORE_DEBUG
662  SCIPdebugMsg(scip, " -> objval=%g/%g, nfrac=%d\n", objval, searchbound, nsdpcands);
663 #endif
664  }
665 
666  /* check if a solution has been found */
667  if ( nsdpcands == 0 && ! cutoff )
668  {
669  SCIP_Bool success;
670 
671  /* create solution from diving SDP */
672  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
673  SCIPdebugMsg(scip, "SDP fracdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
674 
675  /* try to add solution to SCIP */
676  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
677 
678  /* check, if solution was feasible and good enough */
679  if ( success )
680  {
681  SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
682  *result = SCIP_FOUNDSOL;
683  }
684  }
685 
686  /* end diving */
687  SCIP_CALL( SCIPendProbing(scip) );
688 
689  /* reset frequency of relaxator */
690  if ( ! usesdp )
691  {
692  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", freq) );
693  }
694 
695  if ( *result == SCIP_FOUNDSOL )
696  heurdata->nsuccess++;
697 
698  /* We have to invalidate the relaxation solution, because SCIP will otherwise not check the relaxation solution for feasibility. */
699  SCIP_CALL( SCIPmarkRelaxSolInvalid(scip) );
700 
701  SCIPdebugMsg(scip, "SDP fracdiving heuristic finished\n");
702 
703  SCIPfreeBufferArray(scip, &sdpcandsfrac);
704  SCIPfreeBufferArray(scip, &sdpcandssol);
705  SCIPfreeBufferArray(scip, &sdpcands);
706 
707  return SCIP_OKAY; /*lint !e438*/
708 }
709 
710 
711 /*
712  * heuristic specific interface methods
713  */
714 
716 SCIP_RETCODE SCIPincludeHeurSdpFracdiving(
717  SCIP* scip
718  )
719 {
720  SCIP_HEURDATA* heurdata;
721  SCIP_HEUR* heur;
722 
723  /* create Fracdiving primal heuristic data */
724  SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
725 
726  /* include primal heuristic */
727  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
729  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecSdpFracdiving, heurdata) );
730 
731  assert( heur != NULL );
732 
733  /* set non-NULL pointers to callback methods */
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) );
738 
739  /* fracdiving heuristic parameters */
740  SCIP_CALL( SCIPaddRealParam(scip,
741  "heuristics/" HEUR_NAME "/minreldepth",
742  "minimal relative depth to start diving",
743  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
744 
745  SCIP_CALL( SCIPaddRealParam(scip,
746  "heuristics/" HEUR_NAME "/maxreldepth",
747  "maximal relative depth to start diving",
748  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
749 
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)",
753  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
754 
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)",
758  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
759 
760  SCIP_CALL( SCIPaddRealParam(scip,
761  "heuristics/" HEUR_NAME "/maxdiveubquotnosol",
762  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
763  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
764 
765  SCIP_CALL( SCIPaddRealParam(scip,
766  "heuristics/" HEUR_NAME "/maxdiveavgquotnosol",
767  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
768  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
769 
770  SCIP_CALL( SCIPaddBoolParam(scip,
771  "heuristics/" HEUR_NAME "/backtrack",
772  "use one level of backtracking if infeasibility is encountered?",
773  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
774 
775  SCIP_CALL( SCIPaddBoolParam(scip,
776  "heuristics/" HEUR_NAME "/runforlp",
777  "Should the diving heuristic be applied if we are solving LPs?",
778  &heurdata->runforlp, FALSE, DEFAULT_RUNFORLP, NULL, NULL) );
779 
780  return SCIP_OKAY;
781 }
782 
#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:5579
#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_RUNFORLP
#define DEFAULT_BACKTRACK
#define DEFAULT_MAXRELDEPTH
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
Definition: relax_sdp.c:5596
static SCIP_DECL_HEUREXEC(heurExecSdpFracdiving)
static SCIP_DECL_HEURFREE(heurFreeSdpFracdiving)
#define HEUR_TIMING
static SCIP_DECL_HEURCOPY(heurCopySdpFracdiving)
#define HEUR_NAME
#define DEFAULT_MAXDIVEAVGQUOT