SCIP-SDP  2.1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
prop_sdpobbt.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*/
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "prop_sdpobbt.h"
47 #include "relax_sdp.h"
48 
49 /* turn off lint warnings for whole file: */
50 /*lint --e{788,818}*/
51 
52 /* fundamental propagator properties */
53 #define PROP_NAME "sdp-obbt"
54 #define PROP_DESC "optimization-based bound tightening for SDPs"
55 #define PROP_PRIORITY -1100000
56 #define PROP_FREQ -1
57 #define PROP_DELAY FALSE
58 #define PROP_TIMING SCIP_PROPTIMING_AFTERLPLOOP
60 #define DEFAULT_PROPBIN FALSE
61 #define DEFAULT_PROPCONT TRUE
64 /*
65  * Data structures
66  */
67 
69 struct SCIP_PropData
70 {
71  SCIP_Bool propbin;
72  SCIP_Bool propcont;
73  long long int lastnode;
74 };
75 
76 
77 /*
78  * Local methods
79  */
80 
81 /* the current bugfix branch (3.2.1) does not have SCIPsolveProbingRelax() -> do nothing */
82 #if ( (SCIP_VERSION > 321 || SCIP_SUBVERSION > 0) )
83 static
84 SCIP_RETCODE addObjCutoff(
85  SCIP* scip
86  )
87 {
88  SCIP_ROW* row;
89  SCIP_VAR** vars;
90  char rowname[SCIP_MAXSTRLEN];
91  int nvars;
92  int v;
93 
94  assert( scip != NULL );
95  assert( SCIPinProbing(scip) );
96 
97  SCIPdebugMessage("create objective cutoff and add it to the LP-constraints\n");
98 
99  nvars = SCIPgetNVars(scip);
100  vars = SCIPgetVars(scip);
101 
102  /* create objective cutoff row; set local flag to FALSE since primal cutoff is globally valid */
103  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "obbtsdp_objcutoff");
104  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, rowname, -SCIPinfinity(scip), SCIPgetCutoffbound(scip), FALSE, FALSE, FALSE) );
105  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
106 
107  for( v = 0; v < nvars; v++ )
108  {
109  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[v], SCIPvarGetObj(vars[v])) );
110  }
111  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
112 
113  /* add row to the LP-constraints */
114  SCIP_CALL( SCIPaddRowProbing(scip, row) );
115 
116  return SCIP_OKAY;
117 }
118 #endif
119 
120 /*
121  * Callback methods of propagator
122  */
123 
124 
126 static
127 SCIP_DECL_PROPCOPY(propCopySdpObbt)
128 { /*lint --e{715}*/
129  assert( scip != NULL );
130  assert( prop != NULL );
131  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
132 
133  /* call inclusion method of constraint handler */
134  SCIP_CALL( SCIPincludePropSdpObbt(scip) );
135 
136  return SCIP_OKAY;
137 }
138 
139 
141 static
142 SCIP_DECL_PROPFREE(propFreeSdpObbt)
143 {/*lint --e{715}*/
144  SCIP_PROPDATA* propdata;
145 
146  propdata = SCIPpropGetData(prop);
147  assert(propdata != NULL);
148 
149  SCIPfreeMemory(scip, &propdata);
150  SCIPpropSetData(prop, NULL);
151 
152  return SCIP_OKAY;
153 }
154 
156 static
157 SCIP_DECL_PROPEXIT(propExitSdpObbt)
158 { /*lint --e{715}*/
159  SCIP_PROPDATA* propdata;
160 
161  assert( prop != NULL );
162 
163  propdata = SCIPpropGetData(prop);
164 
165  propdata->lastnode = -1; /* we reset this to be able to run again if a new problem is read */
166 
167  return SCIP_OKAY;
168 }
169 
170 
172 static
173 SCIP_DECL_PROPEXEC(propExecSdpObbt)
174 { /*lint --e{715}*/
175  /* the current bugfix branch (3.2.1) does not have SCIPsolveProbingRelax() -> do nothing */
176 #if ( (SCIP_VERSION > 321 || SCIP_SUBVERSION > 0) )
177  int nvars;
178  SCIP_VAR** vars;
179  int v;
180  SCIP_PROPDATA* propdata;
181  SCIP_Real relaxval;
182  SCIP_Bool cutoff;
183  SCIP_Bool oldobjlimitparam;
184  SCIP_Real probingval;
185  SCIP_Bool success;
186  SCIP_RELAX* relaxsdp;
187  /* newbounds and newboundinds save the bound tightenings that should be inserted after probing ends, newboundinds saves the bounds the entries of newbounds
188  * belong to, for this the variables are sorted 1 to nvars (and entry i means vars[i-1]), with negative entry for the lower bound and positive for the upper */
189  SCIP_Real* newbounds;
190  int* newboundinds;
191  int nnewbounds;
192  int i;
193 
194  assert( scip != NULL );
195  assert( prop != NULL );
196  assert( result != NULL );
197 
198  *result = SCIP_DIDNOTRUN;
199 
200  SCIPdebugMessage("Executing propExecSdpObbt! \n");
201 
202  /* if there is no cutoff-bound, we don't want to run */
203  if ( SCIPisInfinity(scip, SCIPgetCutoffbound(scip)) )
204  {
205  SCIPdebugMessage("Aborting propExecSdpObbt because of lack of cutoff-bound!\n");
206  return SCIP_OKAY;
207  }
208 
209  /* do not run in: presolving, repropagation, probing mode, if no objective propagation is allowed */
210  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING || SCIPinRepropagation(scip) || SCIPinProbing(scip) || !SCIPallowObjProp(scip) )
211  {
212  SCIPdebugMessage("Aborting propExecSdpObbt because we are in presolving, repropagation, probing mode or no objective propagation is allowed!\n");
213  return SCIP_OKAY;
214  }
215 
216  vars = SCIPgetVars(scip);
217  nvars = SCIPgetNVars(scip);
218  propdata = SCIPpropGetData(prop);
219 
220  assert( propdata != NULL );
221 
222  if ( SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode )
223  {
224  SCIPdebugMessage("Not running again for node %lld!\n", propdata->lastnode);
225  return SCIP_OKAY;
226  }
227  else
228  {
229  propdata->lastnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
230  }
231 
232  /* start probing */
233  SCIP_CALL( SCIPstartProbing(scip) );
234  SCIPdebugMessage("start probing\n");
235 
236  SCIP_CALL( addObjCutoff(scip) );
237 
238  /* make sure that we don't use the objective cutoff for the changed objective */
239  SCIP_CALL( SCIPgetBoolParam(scip, "relaxing/SDP/objlimit", &oldobjlimitparam) );
240  SCIP_CALL( SCIPsetBoolParam(scip, "relaxing/SDP/objlimit", FALSE) );
241 
242  /* allocate memory to save bounds */
243  SCIP_CALL( SCIPallocBufferArray(scip, &newbounds, 2*nvars) );/*lint !e647*/
244  SCIP_CALL( SCIPallocBufferArray(scip, &newboundinds, 2*nvars) );/*lint !e647*/
245 
246  *result = SCIP_DIDNOTFIND;
247 
248  /* set objective coefficients to zero */
249  for( v = 0; v < nvars; ++v )
250  {
251  SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], 0.0) );
252  }
253 
254  nnewbounds = 0;
255 
256  for (v = 0; v < nvars; v++)
257  {
258  /* do not propagate binary or continous variables if the corresponding flag is set to false */
259  if ( (( ! propdata->propbin ) && SCIPvarIsBinary(vars[v])) || (( ! propdata->propcont ) && ( ! SCIPvarIsIntegral(vars[v]))) )
260  {
261 #ifdef SCIP_MORE_DEBUG
262  if ( SCIPvarIsBinary(vars[v]) )
263  {
264  SCIPdebugMessage("Skipping binary variable %s\n", SCIPvarGetName(vars[v]));
265  }
266  else
267  {
268  SCIPdebugMessage("Skipping continuous variable %s\n", SCIPvarGetName(vars[v]));
269  }
270 #endif
271  continue;
272  }
273 
274  /* get the value of this variable for the current relaxation */
275  relaxval = SCIPgetRelaxSolVal(scip, vars[v]);
276 
277  /* only try obbt for the lower bound if it is not tight for the current relaxation's solution */
278  if ( SCIPisFeasGT(scip, relaxval, SCIPvarGetLbLocal(vars[v])) )
279  {
280  /* set the objective to minimize y_v */
281  SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], 1.0) );
282 
283  /* solve the probing problem */
284  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
285 
286  /* as cutoff doesn't work for relax sdp, we have to check ourselves, if we didn't manage to solve successfully, we abort (as this will
287  * probably not get better for the other variables as we only change the objective */
288  relaxsdp = SCIPfindRelax(scip, "SDP");
289 
290  if (! SCIPrelaxSdpSolvedProbing(relaxsdp))
291  {
292  SCIPdebugMessage("Aborting sdp-obbt, as we were unable to solve a probing sdp!\n");
293  if ( *result != SCIP_REDUCEDDOM )
294  *result = SCIP_DIDNOTRUN;
295  break;
296  }
297 
298  /* if the problem is infeasible, return with cutoff */
299  if ( ! SCIPrelaxSdpIsFeasible(relaxsdp) )
300  {
301  SCIPdebugMessage("Probing sdp infeasible, so there can't be a better solution for this problem!\n");
302  *result = SCIP_CUTOFF;
303  break;
304  }
305 
306  /* check if we managed to tighten the bound */
307  success = FALSE; /* this will be ignored, we check solvedProbing instead */
308  SCIP_CALL( SCIPrelaxSdpRelaxVal(relaxsdp, &success, &probingval) );
309 
310  if ( SCIPisGT(scip, probingval, SCIPvarGetLbLocal(vars[v])) )
311  {
312  /* update bound TODO: check if this works or needs to be done outside of probing */
313  SCIPdebugMessage("Obbt-Sdp tightened lower bound of variable %s from %f to %f !\n",
314  SCIPvarGetName(vars[v]), SCIPvarGetLbLocal(vars[v]), probingval);
315 
316  newbounds[nnewbounds] = probingval;
317  newboundinds[nnewbounds] = -1 * (v+1);
318  nnewbounds++;
319  *result = SCIP_REDUCEDDOM;
320  }
321 #ifdef SCIP_MORE_DEBUG
322  else
323  {
324  SCIPdebugMessage("Obbt-Sdp found lower bound of %f for variable %s, worse than old bound %f !\n",
325  probingval, SCIPvarGetName(vars[v]), SCIPvarGetLbLocal(vars[v]));
326  }
327 #endif
328  }
329 #ifdef SCIP_MORE_DEBUG
330  else
331  {
332  SCIPdebugMessage("Skipping obbt for lower bound %f of variable %s, as current relaxation's solution is tight.\n",
333  SCIPvarGetLbLocal(vars[v]), SCIPvarGetName(vars[v]));
334  }
335 #endif
336 
337  /* only try obbt for the upper bound if it is not tight for the current relaxation's solution */
338  if ( SCIPisFeasLT(scip, relaxval, SCIPvarGetUbLocal(vars[v])) )
339  {
340  /* set the objective to maximize y_v (minimize -y_v) */
341  SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], -1.0) );
342 
343  /* solve the probing problem */
344  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
345 
346  /* as cutoff doesn't work for relax sdp, we have to check ourselves, if we didn't manage to solve successfully, we abort (as this will
347  * probably not get better for the other variables as we only change the objective */
348  relaxsdp = SCIPfindRelax(scip, "SDP");
349 
350  if (! SCIPrelaxSdpSolvedProbing(relaxsdp))
351  {
352  SCIPdebugMessage("Aborting sdp-obbt, as we were unable to solve a probing sdp!\n");
353  if ( *result != SCIP_REDUCEDDOM )
354  *result = SCIP_DIDNOTRUN;
355  break;
356  }
357 
358  /* if the problem is infeasible, return with cutoff */
359  if ( ! SCIPrelaxSdpIsFeasible(relaxsdp) )
360  {
361  SCIPdebugMessage("Probing sdp infeasible, so there can't be a better solution for this problem!\n");
362  *result = SCIP_CUTOFF;
363  break;
364  }
365 
366  /* check if we managed to tighten the bound */
367  success = FALSE; /* this will be ignored, we check solvedProbing instead */
368  SCIP_CALL( SCIPrelaxSdpRelaxVal(relaxsdp, &success, &probingval) );
369 
370  if ( SCIPisLT(scip, -probingval, SCIPvarGetUbLocal(vars[v])) )
371  {
372  /* update bound TODO: check if this works or needs to be done outside of probing */
373  SCIPdebugMessage("Obbt-Sdp tightened upper bound of variable %s from %f to %f !\n",
374  SCIPvarGetName(vars[v]), SCIPvarGetUbLocal(vars[v]), -probingval);
375 
376  newbounds[nnewbounds] = -probingval;
377  newboundinds[nnewbounds] = v + 1;
378  nnewbounds++;
379  *result = SCIP_REDUCEDDOM;
380  }
381 #ifdef SCIP_MORE_DEBUG
382  else
383  {
384  SCIPdebugMessage("Obbt-Sdp found upper bound of %f for variable %s, worse than old bound %f !\n",
385  -probingval, SCIPvarGetName(vars[v]), SCIPvarGetUbLocal(vars[v]));
386  }
387 #endif
388  }
389 #ifdef SCIP_MORE_DEBUG
390  else
391  {
392  SCIPdebugMessage("Skipping obbt for upper bound %f of variable %s, as current relaxation's solution is tight.\n",
393  SCIPvarGetUbLocal(vars[v]), SCIPvarGetName(vars[v]));
394  }
395 #endif
396 
397  /* reset the objective coefficient to zero for the next variable */
398  SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], 0.0) );
399  }
400 
401  SCIP_CALL( SCIPendProbing(scip) );
402  SCIPdebugMessage("end probing\n");
403  SCIP_CALL( SCIPsetBoolParam(scip, "relaxing/SDP/objlimit", oldobjlimitparam) );
404 
405  for (i = 0; i < nnewbounds; i++)
406  {
407  if ( newboundinds[i] < 0)
408  {
409  SCIP_CALL( SCIPchgVarLb(scip, vars[-1 * newboundinds[i] - 1], newbounds[i]) ); /*lint !e679*/
410  }
411  else
412  {
413  SCIP_CALL( SCIPchgVarUb(scip, vars[newboundinds[i] - 1], newbounds[i]) );
414  }
415  }
416 
417  SCIPfreeBufferArray(scip, &newbounds);
418  SCIPfreeBufferArray(scip, &newboundinds);
419 
420  return SCIP_OKAY;
421 
422 #else
423  *result = SCIP_DIDNOTRUN;
424 
425  return SCIP_OKAY;
426 #endif
427 }
428 
429 
430 
431 /*
432  * propagator specific interface methods
433  */
434 
437  SCIP* scip
438  )
439 {
440  SCIP_PROPDATA* propdata;
441  SCIP_PROP* prop;
442 
443  /* create SdpObbt propagator data */
444  propdata = NULL;
445  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
446  propdata->lastnode = -1;
447 
448  /* include propagator */
449  /* use SCIPincludePropBasic() plus setter functions if you want to set callbacks one-by-one and your code should
450  * compile independent of new callbacks being added in future SCIP versions
451  */
452  SCIP_CALL( SCIPincludePropBasic(scip, &prop, PROP_NAME, PROP_DESC, PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING,
453  propExecSdpObbt, propdata) );
454 
455  assert(prop != NULL);
456 
457  /* set optional callbacks via setter functions */
458  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopySdpObbt) );
459  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeSdpObbt) );
460  SCIP_CALL( SCIPsetPropExit(scip, prop, propExitSdpObbt) );
461 
462  /* add SdpObbt propagator parameters */
463  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/propbin",
464  "Should optimization-based bound tightening be performed for binary variables?",
465  &propdata->propbin, TRUE, DEFAULT_PROPBIN, NULL, NULL) );
466 
467  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/propcont",
468  "Should optimization-based bound tightening be performed for continuous variables?",
469  &propdata->propcont, TRUE, DEFAULT_PROPCONT, NULL, NULL) );
470 
471  return SCIP_OKAY;
472 }
#define PROP_TIMING
Definition: prop_sdpobbt.c:58
SCIP_RETCODE SCIPincludePropSdpObbt(SCIP *scip)
Definition: prop_sdpobbt.c:436
#define PROP_NAME
Definition: prop_sdpobbt.c:53
static SCIP_DECL_PROPEXIT(propExitSdpObbt)
Definition: prop_sdpobbt.c:157
static SCIP_DECL_PROPEXEC(propExecSdpObbt)
Definition: prop_sdpobbt.c:173
static SCIP_DECL_PROPCOPY(propCopySdpObbt)
Definition: prop_sdpobbt.c:127
SDP-relaxator.
#define PROP_DESC
Definition: prop_sdpobbt.c:54
optimization-based bound tightening propagator for semidefinite programs
SCIP_RETCODE SCIPrelaxSdpRelaxVal(SCIP_RELAX *relax, SCIP_Bool *success, SCIP_Real *objval)
Definition: relax_sdp.c:1774
#define PROP_FREQ
Definition: prop_sdpobbt.c:56
static SCIP_DECL_PROPFREE(propFreeSdpObbt)
Definition: prop_sdpobbt.c:142
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
Definition: relax_sdp.c:1857
#define DEFAULT_PROPBIN
Definition: prop_sdpobbt.c:60
#define DEFAULT_PROPCONT
Definition: prop_sdpobbt.c:61
#define PROP_PRIORITY
Definition: prop_sdpobbt.c:55
#define PROP_DELAY
Definition: prop_sdpobbt.c:57
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
Definition: relax_sdp.c:1874