SCIP-SDP  3.1.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
heur_sdprand.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-2018 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-2018 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 
39 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
40 /*#define SCIP_DEBUG*/
41 #include <assert.h>
42 #include <string.h>
43 
44 #include "heur_sdprand.h"
45 #include "relax_sdp.h"
46 
47 /* turn off lint warnings for whole file: */
48 /*lint --e{788,818}*/
49 
50 #define HEUR_NAME "sdprand"
51 #define HEUR_DESC "randomized rounding heuristic for SDPs"
52 #define HEUR_DISPCHAR '~'
53 #define HEUR_PRIORITY -1001000
54 #define HEUR_FREQ 1
55 #define HEUR_FREQOFS 0
56 #define HEUR_MAXDEPTH -1
57 #define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
58 #define HEUR_USESSUBSCIP FALSE /* does the heuristic use a secondary SCIP instance? */
59 
60 
61 /*
62  * Default parameter settings
63  */
64 
65 #define DEFAULT_NROUNDS 2
66 #define DEFAULT_GENERALINTS FALSE
67 #define DEFAULT_RANDSEED 211
69 /* locally defined heuristic data */
70 struct SCIP_HeurData
71 {
72  SCIP_SOL* sol;
73  int nrounds;
74  SCIP_RANDNUMGEN* randnumgen;
75  SCIP_Bool generalints;
76 };
77 
78 
79 /*
80  * Callback methods
81  */
82 
84 static
85 SCIP_DECL_HEURCOPY(heurCopySdprand)
86 { /*lint --e{715}*/
87  assert( scip != NULL );
88  assert( heur != NULL );
89  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
90 
91  /* call inclusion method of primal heuristic */
92  SCIP_CALL( SCIPincludeHeurSdpRand(scip) );
93 
94  return SCIP_OKAY;
95 }
96 
98 static
99 SCIP_DECL_HEURFREE(heurFreeSdprand)
100 { /*lint --e{715}*/
101  SCIP_HEURDATA* heurdata;
102 
103  assert( heur != NULL );
104  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
105  assert( scip != NULL );
106 
107  /* free heuristic data */
108  heurdata = SCIPheurGetData(heur);
109  assert(heurdata != NULL);
110  SCIPfreeMemory(scip, &heurdata);
111  SCIPheurSetData(heur, NULL);
112 
113  return SCIP_OKAY;
114 }
115 
117 static
118 SCIP_DECL_HEURINIT(heurInitSdprand)
119 { /*lint --e{715}*/
120  SCIP_HEURDATA* heurdata;
121 
122  assert( heur != NULL );
123  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
124 
125  /* get heuristic data */
126  heurdata = SCIPheurGetData(heur);
127  assert( heurdata != NULL );
128 
129  /* create working solution and random number generator */
130  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
131  SCIP_CALL( SCIPcreateRandom(scip, &(heurdata->randnumgen), SCIPinitializeRandomSeed(scip, DEFAULT_RANDSEED), TRUE) );
132 
133  return SCIP_OKAY;
134 }
135 
137 static
138 SCIP_DECL_HEUREXIT(heurExitSdprand)
139 { /*lint --e{715}*/
140  SCIP_HEURDATA* heurdata;
141 
142  assert( heur != NULL );
143  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
144 
145  /* get heuristic data */
146  heurdata = SCIPheurGetData(heur);
147  assert( heurdata != NULL );
148 
149  /* free working solution and random number generator*/
150  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
151  SCIPfreeRandom(scip, &(heurdata->randnumgen));
152 
153  return SCIP_OKAY;
154 }
155 
157 static
158 SCIP_DECL_HEUREXEC(heurExecSdprand)
159 { /*lint --e{715}*/
160  /* the current bugfix branch (3.2.1) does not have SCIPsolveProbingRelax() -> do nothing */
161 #if ( (SCIP_VERSION > 321 || SCIP_SUBVERSION > 0) )
162  SCIP_HEURDATA* heurdata;
163  SCIP_RELAX* relaxsdp;
164  SCIP_Real* sdpcandssol;
165  SCIP_VAR** sdpcands;
166  SCIP_VAR** vars;
167  int nsdpcands = 0;
168  int ncontvars;
169  int nvars;
170  int iter;
171  int v;
172 
173  assert( heur != NULL );
174  assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
175  assert( scip != NULL );
176  assert( result != NULL );
177 
178  *result = SCIP_DELAYED;
179 
180  /* do not run if relaxation solution is not available */
181  if ( ! SCIPisRelaxSolValid(scip) )
182  return SCIP_OKAY;
183 
184  /* do not call heuristic if node was already detected to be infeasible */
185  if ( nodeinfeasible )
186  return SCIP_OKAY;
187 
188  *result = SCIP_DIDNOTRUN;
189 
190  /* get heuristic data */
191  heurdata = SCIPheurGetData(heur);
192  assert( heurdata != NULL );
193 
194  /* only run if there are no general integer variables or the corresponding parameter is set */
195  if ( (! heurdata->generalints) && SCIPgetNIntVars(scip) > 0 )
196  return SCIP_OKAY;
197 
198  /* get relaxator - exit if not found (use LP randomized rounding) */
199  relaxsdp = SCIPfindRelax(scip, "SDP");
200  if ( relaxsdp == NULL )
201  return SCIP_OKAY;
202 
203  /* get number of continuous variables */
204  ncontvars = SCIPgetNContVars(scip) + SCIPgetNImplVars(scip);
205 
206  /* save old SDP solution */
207  vars = SCIPgetVars(scip);
208  nvars = SCIPgetNVars(scip);
209  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcands, nvars) );
210  SCIP_CALL( SCIPallocBufferArray(scip, &sdpcandssol, nvars) );
211  if ( ncontvars == 0)
212  {
213  /* in this case we do not need to solve an SDP again, so we only need to save the fractional values */
214  for (v = 0; v < nvars; ++v)
215  {
216  SCIP_Real val;
217 
218  val = SCIPgetRelaxSolVal(scip, vars[v]);
219  if ( SCIPvarIsIntegral(vars[v]) && ! SCIPisFeasIntegral(scip, val) )
220  {
221  sdpcands[nsdpcands] = vars[v];
222  sdpcandssol[nsdpcands] = val;
223  ++nsdpcands;
224  }
225  }
226  }
227  else
228  {
229  /* if there are continuous variables, we need to save all values to later be able to fix all current integer values */
230  for (v = 0; v < nvars; ++v)
231  {
232  SCIP_Real val;
233 
234  val = SCIPgetRelaxSolVal(scip, vars[v]);
235  sdpcands[v] = vars[v];
236  sdpcandssol[v] = val;
237  if ( SCIPvarIsIntegral(vars[v]) && ! SCIPisFeasIntegral(scip, val) )
238  {
239  ++nsdpcands;
240  }
241  }
242  }
243 
244  /* do not proceed, if there are no fractional variables */
245  if ( nsdpcands == 0 )
246  {
247  SCIPfreeBufferArray(scip, &sdpcandssol);
248  SCIPfreeBufferArray(scip, &sdpcands);
249  return SCIP_OKAY;
250  }
251 
252  *result = SCIP_DIDNOTFIND;
253 
254  SCIPdebugMessage("node %"SCIP_LONGINT_FORMAT") executing SDP randomized rounding heuristic: depth=%d, %d fractionals.\n",
255  SCIPgetNNodes(scip), SCIPgetDepth(scip), nsdpcands);
256 
257  /* perform rounding rounds */
258  for (iter = 0; iter < heurdata->nrounds; ++iter)
259  {
260  SCIP_Bool success;
261  SCIP_Bool cutoff;
262  SCIP_VAR* var;
263  SCIP_Real r;
264  int cnt = 0;
265 
266  /* if there are no continuous variables, we can simply try the solution */
267  if ( ncontvars == 0 )
268  {
269  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
270 
271  /* set values */
272  for (v = 0; v < nsdpcands; ++v)
273  {
274  var = sdpcands[v];
275  assert( SCIPvarIsIntegral(var) );
276 
277  /* if the variable is not fixed and its value is fractional */
278  if ( SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5 && ! SCIPisFeasIntegral(scip, sdpcandssol[v]) )
279  {
280  r = SCIPrandomGetReal(heurdata->randnumgen, 0.0, 1.0);
281 
282  /* depending on random value, set variable to 0 or 1 */
283  if ( SCIPfeasFrac(scip, sdpcandssol[v]) <= r )
284  {
285  SCIP_CALL( SCIPsetSolVal(scip, heurdata->sol, var, SCIPfeasFloor(scip, sdpcandssol[v])) );
286  }
287  else
288  {
289  SCIP_CALL( SCIPsetSolVal(scip, heurdata->sol, var, SCIPfeasCeil(scip, sdpcandssol[v])) );
290  }
291  }
292  }
293 
294  /* try to add solution to SCIP - do not need to check integrality here */
295  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, TRUE, &success) );
296 
297  if ( success )
298  SCIPdebugMessage("Iteration %d: found solution for full binary instance.\n", iter);
299  else
300  SCIPdebugMessage("Iteration %d: solution not feasible for full binary instance.\n", iter);
301  }
302  else
303  {
304  /* if there are continuous variables, we need to solve a final SDP */
305  SCIP_CALL( SCIPstartProbing(scip) );
306 
307  for (v = 0; v < nvars; ++v)
308  {
309  SCIP_Real val;
310 
311  var = vars[v];
312  val = sdpcandssol[v];
313 
314  /* if the variable is not fixed and its value is fractional */
315  if ( SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5 && SCIPvarIsIntegral(var) && ! SCIPisFeasIntegral(scip, val) )
316  {
317  r = SCIPrandomGetReal(heurdata->randnumgen, 0.0, 1.0);
318 
319  /* depending on random value, fix variable to 0 or 1 */
320  if ( val <= r )
321  {
322  SCIP_CALL( SCIPchgVarUbProbing(scip, var, 0.0) );
323  }
324  else
325  {
326  SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.0) );
327  }
328  ++cnt;
329  }
330  else if ( SCIPvarIsIntegral(var) && SCIPisFeasIntegral(scip, val) && SCIPisFeasGT(scip, val, SCIPvarGetLbLocal(var)) )
331  {
332  /* if an integral variable already attained an integer value, we fix it */
333  SCIP_CALL( SCIPchgVarLbProbing(scip, var, val) );
334  ++cnt;
335  }
336  else if ( SCIPvarIsIntegral(var) && SCIPisFeasIntegral(scip, val) && SCIPisFeasLT(scip, val, SCIPvarGetUbLocal(var)) )
337  {
338  /* if an integral variable already attained an integer value, we fix it */
339  SCIP_CALL( SCIPchgVarUbProbing(scip, var, val) );
340  ++cnt;
341  }
342  }
343 
344  /* if no value was changed */
345  if ( cnt == 0 )
346  {
347  /* We can exit since there will be no chance to be successful in future runs. */
348  SCIPdebugMessage("Iteration %d: All variables were fixed or their values were integral -> exit.\n", iter);
349  break;
350  }
351 
352  /* apply domain propagation (use parameter settings for maximal number of rounds) */
353  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
354  if ( ! cutoff )
355  {
356  /* solve SDP */
357  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
358 
359  /* if solving was successfull */
360  if (SCIPrelaxSdpSolvedProbing(relaxsdp) && SCIPrelaxSdpIsFeasible(relaxsdp) )
361  {
362  /* check solution */
363  SCIP_CALL( SCIPlinkRelaxSol(scip, heurdata->sol) );
364 
365  /* try to add solution to SCIP: check all constraints, including integrality */
366  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, TRUE, TRUE, TRUE, TRUE, &success) );
367  /* check, if solution was feasible and good enough */
368  if ( success )
369  {
370  SCIPdebugMessage("Iteration %d: solution was feasible and good enough.\n", iter);
371  *result = SCIP_FOUNDSOL;
372  }
373  else
374  SCIPdebugMessage("Iteration %d: solution was not feasible.\n", iter);
375  }
376  }
377 
378  /* free local problem */
379  SCIP_CALL( SCIPendProbing(scip) );
380 
381  if ( SCIPisStopped(scip) )
382  break;
383  }
384  }
385 
386  SCIPfreeBufferArray(scip, &sdpcandssol);
387  SCIPfreeBufferArray(scip, &sdpcands);
388 
389  SCIPdebugMessage("finished randomized rounding heuristic.\n");
390 
391  return SCIP_OKAY;
392 
393 #else
394  *result = SCIP_DIDNOTRUN;
395 
396  return SCIP_OKAY;
397 #endif
398 }
399 
400 
401 /*
402  * heuristic specific interface methods
403  */
404 
407  SCIP* scip
408  )
409 {
410  SCIP_HEURDATA* heurdata;
411  SCIP_HEUR* heur;
412 
413  /* create Fracdiving primal heuristic data */
414  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
415 
416  /* include primal heuristic */
417  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
419  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecSdprand, heurdata) );
420 
421  assert( heur != NULL );
422 
423  /* set non-NULL pointers to callback methods */
424  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopySdprand) );
425  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeSdprand) );
426  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitSdprand) );
427  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitSdprand) );
428 
429  /* fracdiving heuristic parameters */
430  SCIP_CALL( SCIPaddIntParam(scip,
431  "heuristics/sdprand/nrounds",
432  "number of rounding rounds",
433  &heurdata->nrounds, FALSE, DEFAULT_NROUNDS, 0, 10000, NULL, NULL) );
434  SCIP_CALL( SCIPaddBoolParam(scip,
435  "heuristics/sdprand/generalints",
436  "Should randomized rounding also be applied if there are general integer variables and not only binary variables ?",
437  &heurdata->generalints, FALSE, DEFAULT_GENERALINTS, NULL, NULL) );
438 
439  return SCIP_OKAY;
440 }
#define HEUR_DESC
Definition: heur_sdprand.c:51
static SCIP_DECL_HEUREXEC(heurExecSdprand)
Definition: heur_sdprand.c:158
#define HEUR_MAXDEPTH
Definition: heur_sdprand.c:56
SDP-relaxator.
#define DEFAULT_NROUNDS
Definition: heur_sdprand.c:65
static SCIP_DECL_HEURFREE(heurFreeSdprand)
Definition: heur_sdprand.c:99
#define HEUR_PRIORITY
Definition: heur_sdprand.c:53
SCIP_RETCODE SCIPincludeHeurSdpRand(SCIP *scip)
Definition: heur_sdprand.c:406
#define DEFAULT_RANDSEED
Definition: heur_sdprand.c:67
#define HEUR_NAME
Definition: heur_sdprand.c:50
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
Definition: relax_sdp.c:5258
#define DEFAULT_GENERALINTS
Definition: heur_sdprand.c:66
#define HEUR_DISPCHAR
Definition: heur_sdprand.c:52
static SCIP_DECL_HEURINIT(heurInitSdprand)
Definition: heur_sdprand.c:118
#define HEUR_FREQOFS
Definition: heur_sdprand.c:55
randomized rounding heuristic for SDPs
static SCIP_DECL_HEURCOPY(heurCopySdprand)
Definition: heur_sdprand.c:85
#define HEUR_FREQ
Definition: heur_sdprand.c:54
static SCIP_DECL_HEUREXIT(heurExitSdprand)
Definition: heur_sdprand.c:138
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
Definition: relax_sdp.c:5275
#define HEUR_USESSUBSCIP
Definition: heur_sdprand.c:58
#define HEUR_TIMING
Definition: heur_sdprand.c:57