SCIP-SDP  3.2.0
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-2020 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-2020 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  SCIPdebugMsg(scip, "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  SCIPdebugMsg(scip, "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  /* if after propagation the upper bound is less than the lower bound, the current node is infeasible */
184  if ( SCIPisFeasLT(scip, ub, lb) || SCIPisFeasLT(scip, ub, SCIPvarGetLbLocal(var)) || SCIPisFeasLT(scip, SCIPvarGetUbLocal(var), lb) )
185  {
186  SCIPdebugMsg(scip, "Infeasibility of current node detected by prop_sdpredcost! Updated bounds for variable %s: lb = %f > %f = ub !\n",
187  SCIPvarGetName(var), SCIPisFeasGT(scip, lb, SCIPvarGetLbLocal(var))? lb : SCIPvarGetLbLocal(var),
188  SCIPisFeasLT(scip, ub, SCIPvarGetLbLocal(var)) ? ub : SCIPvarGetUbLocal(var) );
189  *result = SCIP_CUTOFF;
190  return SCIP_OKAY;
191  }
192 
193  /* if the new upper bound is an enhancement, update it */
194  if ( SCIPisFeasLT(scip, ub, SCIPvarGetUbLocal(var)) )
195  {
196  SCIPdebugMsg(scip, "Changing upper bound of variable %s from %f to %f because of prop_sdpredcost \n",
197  SCIPvarGetName(var), SCIPvarGetUbLocal(var), ub);
198  SCIP_CALL( SCIPchgVarUb(scip, var, ub) );
199  *result = SCIP_REDUCEDDOM;
200  }
201 
202  /* if the new lower bound is an enhancement, update it */
203  if ( SCIPisFeasGT(scip, lb, SCIPvarGetLbLocal(var)) )
204  {
205  SCIPdebugMsg(scip, "Changing lower bound of variable %s from %f to %f because of prop_sdpredcost \n",
206  SCIPvarGetName(var), SCIPvarGetLbLocal(var), lb);
207  SCIP_CALL( SCIPchgVarLb(scip, var, lb) );
208  *result = SCIP_REDUCEDDOM;
209  }
210 
211  return SCIP_OKAY;
212 }
213 
215 static
216 SCIP_DECL_PROPEXEC(propExecSdpredcost)
217 {/*lint --e{715}*/
218  int v;
219  int nvars;
220  SCIP_VAR** vars;
221  SCIP_RELAX* relax;
222  SCIP_RESULT varresult;
223  SCIP_Real cutoffbound;
224  SCIP_Real relaxval;
225  SCIP_Bool sdpsolved;
226  SCIP_PROPDATA* propdata;
227  int length;
228 
229  SCIPdebugMsg(scip, "Calling propExecSdpredcost \n");
230 
231  assert( scip != NULL );
232  assert( prop != NULL );
233  assert( result != NULL );
234 
235  /* do not run if propagation w.r.t. objective is not allowed */
236 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
237  if( ! SCIPallowWeakDualReds(scip) )
238  return SCIP_OKAY;
239 #else
240  if( ! SCIPallowObjProp(scip) )
241  return SCIP_OKAY;
242 #endif
243 
244  if ( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
245  {
246  /* we can't run before the relaxator is properly initialized */
247  *result = SCIP_DIDNOTRUN;
248  return SCIP_OKAY;
249  }
250 
251  relax = SCIPfindRelax(scip, "SDP"); /* get SDP relaxation handler */
252  assert( relax != NULL );
253 
254  /* we can only propagate for the last node for which the SDP was solved */
255  if ( SCIPrelaxSdpGetSdpNode(relax) != SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) )
256  {
257  SCIPdebugMsg(scip, "Stopped propExecRedcost because current SDP-relaxation doesn't belong to the node the propagator was called for!\n");
258  *result = SCIP_DIDNOTRUN;
259  return SCIP_OKAY;
260  }
261 
262  /* we can only propagate if the SDP in the last node was solved in its original formulation */
263  if ( ! SCIPrelaxSdpSolvedOrig(relax) )
264  {
265  SCIPdebugMsg(scip, "Stopped propExecRedcost because current SDP-relaxation was solved using a penalty formulation!\n");
266  *result = SCIP_DIDNOTRUN;
267  return SCIP_OKAY;
268  }
269 
270  SCIP_CALL( SCIPrelaxSdpRelaxVal(relax, &sdpsolved, &relaxval) );
271  if ( ! sdpsolved )
272  {
273  SCIPdebugMsg(scip, "Stopped propExecRedcost because SDP-relaxation wasn't properly solved!\n");
274  *result = SCIP_DIDNOTRUN;
275  return SCIP_OKAY;
276  }
277 
278  propdata = SCIPpropGetData(prop);
279  assert( propdata != NULL );
280 
281  *result = SCIP_DIDNOTFIND;
282 
283  nvars = SCIPgetNVars(scip);
284  vars = SCIPgetVars(scip);
285 
286  cutoffbound = SCIPgetCutoffbound(scip);
287 
288  length = nvars;
289 
290  SCIP_CALL( SCIPrelaxSdpGetPrimalBoundVars(relax, propdata->lbvarvals, propdata->ubvarvals, &length) );
291 
292  assert( length == nvars ); /* we should get exactly one value for lower and upper bound-variable per variable in scip */
293 
294  for (v = 0; v < nvars; v++)
295  {
296  if ( SCIPvarIsBinary(vars[v]) && propdata->forbins )
297  {
298  SCIP_CALL( sdpRedcostFixingBinary(scip, vars[v], propdata->lbvarvals[v], propdata->ubvarvals[v], cutoffbound, relaxval, &varresult) );
299 
300  if ( varresult == SCIP_REDUCEDDOM )
301  *result = SCIP_REDUCEDDOM;
302  }
303  else if ( (! SCIPvarIsBinary(vars[v])) && propdata->forintconts )
304  {
305  SCIP_CALL( sdpRedcostFixingIntCont(scip, vars[v], propdata->lbvarvals[v], propdata->ubvarvals[v], cutoffbound, relaxval, &varresult) );
306 
307  if ( varresult == SCIP_REDUCEDDOM )
308  *result = SCIP_REDUCEDDOM;
309  }
310  }
311 
312  return SCIP_OKAY;
313 }
314 
316 static
317 SCIP_DECL_PROPFREE(propFreeSdpredcost)
318 {/*lint --e{715}*/
319  SCIP_PROPDATA* propdata;
320 
321  propdata = SCIPpropGetData(prop);
322  assert( propdata != NULL );
323  SCIPfreeMemory(scip, &propdata);
324 
325  SCIPpropSetData(prop, NULL);
326 
327  return SCIP_OKAY;
328 }
329 
331 static
332 SCIP_DECL_PROPINITSOL(propInitsolSdpredcost)
333 {
334  SCIP_PROPDATA* propdata;
335 
336  propdata = SCIPpropGetData(prop);
337  assert(propdata != NULL);
338 
339  propdata->nvars = SCIPgetNVars(scip);
340  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->lbvarvals), propdata->nvars) );
341  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->ubvarvals), propdata->nvars) );
342 
343  return SCIP_OKAY;
344 }
345 
347 static
348 SCIP_DECL_PROPEXITSOL(propExitsolSdpredcost)
349 {
350  SCIP_PROPDATA* propdata;
351 
352  propdata = SCIPpropGetData(prop);
353  assert( propdata != NULL );
354 
355  SCIPfreeBlockMemoryArrayNull(scip, &(propdata->lbvarvals), propdata->nvars);
356  SCIPfreeBlockMemoryArrayNull(scip, &(propdata->ubvarvals), propdata->nvars);
357 
358  return SCIP_OKAY;
359 }
360 
362 static
363 SCIP_DECL_PROPCOPY(propCopySdpredcost)
364 {
365  assert( scip != NULL );
366  assert( prop != NULL );
367  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
368 
369  /* call inclusion method of constraint handler */
370  SCIP_CALL( SCIPincludePropSdpredcost(scip) );
371 
372  return SCIP_OKAY;
373 }
374 
377  SCIP* scip
378  )
379 {
380  SCIP_PROPDATA* propdata = NULL;
381  SCIP_PROP* prop;
382 
383  /* create propagator data */
384  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
385  propdata->nvars = 0;
386  propdata->lbvarvals = NULL;
387  propdata->ubvarvals = NULL;
388 
389  /* include propagator */
390  SCIP_CALL( SCIPincludePropBasic(scip, &prop, PROP_NAME, PROP_DESC, PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING,
391  propExecSdpredcost, propdata) );
392  assert( prop != NULL );
393 
394  /* set optional callbacks via setter functions */
395  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopySdpredcost) );
396  SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolSdpredcost) );
397  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolSdpredcost) );
398  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeSdpredcost) );
399 
400  /* add additional parameters */
401  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/sdpredcost/forbins", "Should SDP reduced cost fixing be executed for binary variables?",
402  &(propdata->forbins), TRUE, DEFAULT_SDPRCBIN, NULL, NULL) );
403  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/sdpredcost/forintconts", "Should SDP reduced cost fixing be executed for integer and continuous variables?",
404  &(propdata->forintconts), TRUE, DEFAULT_SDPRCINTCONT, NULL, NULL) );
405 
406  return SCIP_OKAY;
407 }
#define DEFAULT_SDPRCBIN
static SCIP_DECL_PROPFREE(propFreeSdpredcost)
static SCIP_DECL_PROPINITSOL(propInitsolSdpredcost)
#define PROP_DELAY
#define PROP_TIMING
#define PROP_FREQ
SDP-relaxator.
SCIP_RETCODE SCIPrelaxSdpRelaxVal(SCIP_RELAX *relax, SCIP_Bool *success, SCIP_Real *objval)
Definition: relax_sdp.c:4997
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:5052
SCIP_Bool SCIPrelaxSdpSolvedOrig(SCIP_RELAX *relax)
Definition: relax_sdp.c:5063
SCIP_RETCODE SCIPrelaxSdpGetPrimalBoundVars(SCIP_RELAX *relax, SCIP_Real *lbvars, SCIP_Real *ubvars, int *arraylength)
Definition: relax_sdp.c:4972
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_DECL_PROPEXITSOL(propExitsolSdpredcost)
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