SCIP-SDP  3.1.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
prop_sdpredcost.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 
38 /*#define SCIP_DEBUG*/
39 
40 /* TODO: might want to add sdpsolvergaptol to parameters and only cut off / change bounds if values differ by more than gaptol, since
41  * the primal variable values may only be exact up to gaptol
42  */
43 
44 #include "prop_sdpredcost.h"
45 #include "scip/def.h" /* for SCIP_Real, _Bool, ... */
46 #include "relax_sdp.h" /* to get relaxation value */
47 #include "sdpi/sdpi.h" /* to get values of primal variables */
48 
49 #include <string.h>
50 #include <assert.h> /*lint !e451*/
51 
52 /* turn off lint warnings for whole file: */
53 /*lint --e{788,818}*/
54 
59 #define PROP_NAME "sdpredcost"
60 #define PROP_DESC "sdp reduced cost strengthening propagator"
61 #define PROP_TIMING SCIP_PROPTIMING_AFTERLPLOOP
62 #define PROP_PRIORITY +1000000
63 #define PROP_FREQ 1
64 #define PROP_DELAY FALSE
65 #define DEFAULT_SDPRCBIN TRUE
66 #define DEFAULT_SDPRCINTCONT TRUE
71 struct SCIP_PropData
72 {
73  /* these could also be freshly allocated for each node, but allocating them only once saves time */
74  SCIP_Real* lbvarvals;
75  SCIP_Real* ubvarvals;
76  int nvars;
77  SCIP_Bool forbins;
78  SCIP_Bool forintconts;
79 };
80 
87 static
89  SCIP* scip,
90  SCIP_VAR* var,
91  SCIP_Real primallbval,
92  SCIP_Real primalubval,
93  SCIP_Real cutoffbound,
94  SCIP_Real relaxval,
95  SCIP_RESULT* result
96  )
97 {
98  assert( scip != NULL );
99  assert( var != NULL );
100  assert( result != NULL );
101 
102  /* skip binary variable if it is locally fixed */
103  if (SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
104  {
105  *result = SCIP_DIDNOTRUN;
106  return SCIP_OKAY;
107  }
108 
109  /* check if variable can be fixed to zero */
110  if ( SCIPisGT(scip, primallbval, cutoffbound - relaxval) )
111  {
112  SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) );
113  SCIPdebugMessage("Variable %s fixed to zero by reduced cost fixing ! \n", SCIPvarGetName(var));
114  *result = SCIP_REDUCEDDOM;
115 
116  /* check if we would also have to fix the variable to one, in that case, we can cut the node off, as there can't be a new optimal solution */
117  if ( SCIPisGT(scip, primalubval, cutoffbound - relaxval) )
118  {
119  *result = SCIP_CUTOFF;
120  }
121 
122  return SCIP_OKAY;
123  }
124 
125  /* check if variable can be fixed to one */
126  if ( SCIPisGT(scip, primalubval, cutoffbound - relaxval) )
127  {
128  SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) );
129  SCIPdebugMessage("Variable %s fixed to one by reduced cost fixing ! \n", SCIPvarGetName(var));
130  *result = SCIP_REDUCEDDOM;
131  return SCIP_OKAY;
132  }
133 
134  *result = SCIP_DIDNOTFIND;
135  return SCIP_OKAY;
136 }
137 
149 static
151  SCIP* scip,
152  SCIP_VAR* var,
153  SCIP_Real primallbval,
154  SCIP_Real primalubval,
155  SCIP_Real cutoffbound,
156  SCIP_Real relaxval,
157  SCIP_RESULT* result
158  )
159 {
160  SCIP_Real lb;
161  SCIP_Real ub;
162 
163  assert( scip != NULL );
164  assert( var != NULL );
165  assert( result != NULL );
166 
167  *result = SCIP_DIDNOTFIND;
168 
169  /* compute the new lower and upper bound, if we divide by zero (checking > 0 is sufficient, as the variabls are non-negative), the bounds are infinity */
170  ub = SCIPisGT(scip, primallbval, 0.0) ? SCIPvarGetLbLocal(var) + (cutoffbound - relaxval) / primallbval : SCIPinfinity(scip);
171  lb = SCIPisGT(scip, primalubval, 0.0) ? SCIPvarGetUbLocal(var) - (cutoffbound - relaxval) / primalubval : -SCIPinfinity(scip);
172 
173  /* if either bound is infinite, we set it to the corresponding SCIP value */
174  if ( SCIPisInfinity(scip, ub) )
175  ub = SCIPinfinity(scip);
176  else if ( SCIPisInfinity(scip, -ub) )
177  ub = -SCIPinfinity(scip);
178  if ( SCIPisInfinity(scip, lb) )
179  lb = SCIPinfinity(scip);
180  else if ( SCIPisInfinity(scip, -lb) )
181  lb = -SCIPinfinity(scip);
182 
183 
184  /* if after propagation the upper bound is less than the lower bound, the current node is infeasible */
185  if ( SCIPisFeasLT(scip, ub, lb) || SCIPisFeasLT(scip, ub, SCIPvarGetLbLocal(var)) || SCIPisFeasLT(scip, SCIPvarGetUbLocal(var), lb) )
186  {
187  SCIPdebugMessage("Infeasibility of current node detected by prop_sdpredcost! Updated bounds for variable %s: lb = %f > %f = ub !\n",
188  SCIPvarGetName(var), SCIPisFeasGT(scip, lb, SCIPvarGetLbLocal(var))? lb : SCIPvarGetLbLocal(var),
189  SCIPisFeasLT(scip, ub, SCIPvarGetLbLocal(var)) ? ub : SCIPvarGetUbLocal(var) );
190  *result = SCIP_CUTOFF;
191  return SCIP_OKAY;
192  }
193 
194  /* if the new upper bound is an enhancement, update it */
195  if ( SCIPisFeasLT(scip, ub, SCIPvarGetUbLocal(var)) )
196  {
197  SCIPdebugMessage("Changing upper bound of variable %s from %f to %f because of prop_sdpredcost \n",
198  SCIPvarGetName(var), SCIPvarGetUbLocal(var), ub);
199  SCIP_CALL( SCIPchgVarUb(scip, var, ub) );
200  *result = SCIP_REDUCEDDOM;
201  }
202 
203  /* if the new lower bound is an enhancement, update it */
204  if ( SCIPisFeasGT(scip, lb, SCIPvarGetLbLocal(var)) )
205  {
206  SCIPdebugMessage("Changing lower bound of variable %s from %f to %f because of prop_sdpredcost \n",
207  SCIPvarGetName(var), SCIPvarGetLbLocal(var), lb);
208  SCIP_CALL( SCIPchgVarLb(scip, var, lb) );
209  *result = SCIP_REDUCEDDOM;
210  }
211 
212  return SCIP_OKAY;
213 }
214 
216 static
217 SCIP_DECL_PROPEXEC(propExecSdpredcost)
218 {/*lint --e{715}*/
219  int v;
220  int nvars;
221  SCIP_VAR** vars;
222  SCIP_RELAX* relax;
223  SCIP_RESULT varresult;
224  SCIP_Real cutoffbound;
225  SCIP_Real relaxval;
226  SCIP_Bool sdpsolved;
227  SCIP_PROPDATA* propdata;
228  int length;
229 
230  SCIPdebugMessage("Calling propExecSdpredcost \n");
231 
232  assert( scip != NULL );
233  assert( prop != NULL );
234  assert( result != NULL );
235 
236  /* do not run if propagation w.r.t. objective is not allowed */
237  if( !SCIPallowObjProp(scip) )
238  return SCIP_OKAY;
239 
240  if ( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
241  {
242  /* we can't run before the relaxator is properly initialized */
243  *result = SCIP_DIDNOTRUN;
244  return SCIP_OKAY;
245  }
246 
247  relax = SCIPfindRelax(scip, "SDP"); /* get SDP relaxation handler */
248  assert( relax != NULL );
249 
250  /* we can only propagate for the last node for which the SDP was solved */
251  if ( SCIPrelaxSdpGetSdpNode(relax) != SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) )
252  {
253  SCIPdebugMessage("Stopped propExecRedcost because current SDP-relaxation doesn't belong to the node the propagator was called for!\n");
254  *result = SCIP_DIDNOTRUN;
255  return SCIP_OKAY;
256  }
257 
258  /* we can only propagate if the SDP in the last node was solved in its original formulation */
259  if ( ! SCIPrelaxSdpSolvedOrig(relax) )
260  {
261  SCIPdebugMessage("Stopped propExecRedcost because current SDP-relaxation was solved using a penalty formulation!\n");
262  *result = SCIP_DIDNOTRUN;
263  return SCIP_OKAY;
264  }
265 
266  SCIP_CALL( SCIPrelaxSdpRelaxVal(relax, &sdpsolved, &relaxval) );
267  if ( ! sdpsolved )
268  {
269  SCIPdebugMessage("Stopped propExecRedcost because SDP-relaxation wasn't properly solved!\n");
270  *result = SCIP_DIDNOTRUN;
271  return SCIP_OKAY;
272  }
273 
274  propdata = SCIPpropGetData(prop);
275  assert( propdata != NULL );
276 
277  *result = SCIP_DIDNOTFIND;
278 
279  nvars = SCIPgetNVars(scip);
280  vars = SCIPgetVars(scip);
281 
282  cutoffbound = SCIPgetCutoffbound(scip);
283 
284  length = nvars;
285 
286  SCIP_CALL( SCIPrelaxSdpGetPrimalBoundVars(relax, propdata->lbvarvals, propdata->ubvarvals, &length) );
287 
288  assert( length == nvars ); /* we should get exactly one value for lower and upper bound-variable per variable in scip */
289 
290  for (v = 0; v < nvars; v++)
291  {
292  if ( SCIPvarIsBinary(vars[v]) && propdata->forbins )
293  {
294  SCIP_CALL( sdpRedcostFixingBinary(scip, vars[v], propdata->lbvarvals[v], propdata->ubvarvals[v], cutoffbound, relaxval, &varresult) );
295 
296  if ( varresult == SCIP_REDUCEDDOM )
297  *result = SCIP_REDUCEDDOM;
298  }
299  else if ( (! SCIPvarIsBinary(vars[v])) && propdata->forintconts )
300  {
301  SCIP_CALL( sdpRedcostFixingIntCont(scip, vars[v], propdata->lbvarvals[v], propdata->ubvarvals[v], cutoffbound, relaxval, &varresult) );
302 
303  if ( varresult == SCIP_REDUCEDDOM )
304  *result = SCIP_REDUCEDDOM;
305  }
306  }
307 
308  return SCIP_OKAY;
309 }
310 
312 static
313 SCIP_DECL_PROPFREE(propFreeSdpredcost)
314 {/*lint --e{715}*/
315  SCIP_PROPDATA* propdata;
316 
317  propdata = SCIPpropGetData(prop);
318  assert( propdata != NULL );
319  SCIPfreeMemory(scip, &propdata);
320 
321  SCIPpropSetData(prop, NULL);
322 
323  return SCIP_OKAY;
324 }
325 
327 static
328 SCIP_DECL_PROPEXIT(propExitSdpredcost)
329 {
330  SCIP_PROPDATA* propdata;
331 
332  propdata = SCIPpropGetData(prop);
333  assert( propdata != NULL );
334 
335  if ( propdata->lbvarvals != NULL )
336  {
337  SCIPfreeBlockMemoryArrayNull(scip, &(propdata->lbvarvals), propdata->nvars);
338  propdata->lbvarvals = NULL;
339  SCIPfreeBlockMemoryArrayNull(scip, &(propdata->ubvarvals), propdata->nvars);
340  propdata->ubvarvals = NULL;
341  }
342 
343  return SCIP_OKAY;
344 }
345 
347 static
348 SCIP_DECL_PROPINITSOL(propInitsolSdpredcost)
349 {
350  SCIP_PROPDATA* propdata;
351  int nvars;
352 
353  propdata = SCIPpropGetData(prop);
354  assert(propdata != NULL);
355  nvars = SCIPgetNVars(scip);
356 
357  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->lbvarvals), nvars) );
358  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->ubvarvals), nvars) );
359  propdata->nvars = nvars;
360 
361  return SCIP_OKAY;
362 }
363 
365 static
366 SCIP_DECL_PROPCOPY(propCopySdpredcost)
367 {
368  assert( scip != NULL );
369  assert( prop != NULL );
370  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
371 
372  /* call inclusion method of constraint handler */
373  SCIP_CALL( SCIPincludePropSdpredcost(scip) );
374 
375  return SCIP_OKAY;
376 }
377 
380  SCIP* scip
381  )
382 {
383  SCIP_PROPDATA* propdata = NULL;
384  SCIP_PROP* prop;
385 
386  /* create propagator data */
387  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
388  propdata->nvars = 0;
389  propdata->lbvarvals = NULL;
390  propdata->ubvarvals = NULL;
391 
392  /* include propagator */
393  SCIP_CALL( SCIPincludePropBasic(scip, &prop, PROP_NAME, PROP_DESC, PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING,
394  propExecSdpredcost, propdata) );
395  assert( prop != NULL );
396 
397  /* set optional callbacks via setter functions */
398  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopySdpredcost) );
399  SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolSdpredcost) );
400  SCIP_CALL( SCIPsetPropExit(scip, prop, propExitSdpredcost) );
401  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeSdpredcost) );
402 
403  /* add additional parameters */
404  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/sdpredcost/forbins", "Should SDP reduced cost fixing be executed for binary variables?",
405  &(propdata->forbins), TRUE, DEFAULT_SDPRCBIN, NULL, NULL) );
406  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/sdpredcost/forintconts", "Should SDP reduced cost fixing be executed for integer and continuous variables?",
407  &(propdata->forintconts), TRUE, DEFAULT_SDPRCINTCONT, NULL, NULL) );
408 
409  return SCIP_OKAY;
410 }
#define DEFAULT_SDPRCBIN
static SCIP_DECL_PROPFREE(propFreeSdpredcost)
static SCIP_DECL_PROPINITSOL(propInitsolSdpredcost)
#define PROP_DELAY
static SCIP_DECL_PROPEXIT(propExitSdpredcost)
#define PROP_TIMING
#define PROP_FREQ
SDP-relaxator.
SCIP_RETCODE SCIPrelaxSdpRelaxVal(SCIP_RELAX *relax, SCIP_Bool *success, SCIP_Real *objval)
Definition: relax_sdp.c:5175
General interface methods for SDP-preprocessing (mainly fixing variables and removing empty rows/cols...
static SCIP_DECL_PROPEXEC(propExecSdpredcost)
#define PROP_PRIORITY
static SCIP_DECL_PROPCOPY(propCopySdpredcost)
long int SCIPrelaxSdpGetSdpNode(SCIP_RELAX *relax)
Definition: relax_sdp.c:5230
SCIP_Bool SCIPrelaxSdpSolvedOrig(SCIP_RELAX *relax)
Definition: relax_sdp.c:5241
SCIP_RETCODE SCIPrelaxSdpGetPrimalBoundVars(SCIP_RELAX *relax, SCIP_Real *lbvars, SCIP_Real *ubvars, int *arraylength)
Definition: relax_sdp.c:5150
reduced cost / dual fixing for SDPs
static SCIP_RETCODE sdpRedcostFixingIntCont(SCIP *scip, SCIP_VAR *var, SCIP_Real primallbval, SCIP_Real primalubval, SCIP_Real cutoffbound, SCIP_Real relaxval, SCIP_RESULT *result)
#define PROP_NAME
#define PROP_DESC
static SCIP_RETCODE sdpRedcostFixingBinary(SCIP *scip, SCIP_VAR *var, SCIP_Real primallbval, SCIP_Real primalubval, SCIP_Real cutoffbound, SCIP_Real relaxval, SCIP_RESULT *result)
SCIP_RETCODE SCIPincludePropSdpredcost(SCIP *scip)
#define DEFAULT_SDPRCINTCONT