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