Scippy

SCIP

Solving Constraint Integer Programs

sepa_intobj.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file sepa_intobj.c
17  * @brief integer objective value separator
18  * @author Tobias Achterberg
19  * @author Timo Berthold
20  */
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 #include <string.h>
25 
26 #include "scip/sepa_intobj.h"
27 
28 
29 #define SEPA_NAME "intobj"
30 #define SEPA_DESC "integer objective value separator"
31 #define SEPA_PRIORITY -100
32 #define SEPA_FREQ -1
33 #define SEPA_MAXBOUNDDIST 0.0
34 #define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
35 #define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
36 
37 #define EVENTHDLR_NAME "intobj"
38 #define EVENTHDLR_DESC "objective change event handler for integer objective value separator"
39 
40 
41 /*
42  * Data structures
43  */
44 
45 /** separator data */
46 struct SCIP_SepaData
47 {
48  SCIP_ROW* objrow; /**< objective value inequality */
49  SCIP_VAR* objvar; /**< objective value variable */
50  SCIP_Real setoff; /**< setoff of the inequality */
51 };
52 
53 
54 /*
55  * Local methods
56  */
57 
58 /** creates separator data */
59 static
61  SCIP* scip, /**< SCIP data structure */
62  SCIP_SEPADATA** sepadata /**< pointer to store separator data */
63  )
64 {
65  assert(sepadata != NULL);
66 
67  SCIP_CALL( SCIPallocMemory(scip, sepadata) );
68  (*sepadata)->objrow = NULL;
69  (*sepadata)->objvar = NULL;
70  (*sepadata)->setoff = 0.0;
71 
72  return SCIP_OKAY;
73 }
74 
75 /** frees separator data */
76 static
78  SCIP* scip, /**< SCIP data structure */
79  SCIP_SEPADATA** sepadata /**< pointer to separator data */
80  )
81 {
82  assert(sepadata != NULL);
83  assert(*sepadata != NULL);
84  assert((*sepadata)->objrow == NULL);
85  assert((*sepadata)->objvar == NULL);
86 
87  SCIPfreeMemory(scip, sepadata);
88 
89  return SCIP_OKAY;
90 }
91 
92 /** creates the objective value inequality and the objective value variable, if not yet existing */
93 static
95  SCIP* scip, /**< SCIP data structure */
96  SCIP_SEPA* sepa, /**< separator */
97  SCIP_SEPADATA* sepadata /**< separator data */
98  )
99 {
100  assert(sepadata != NULL);
101 
102  if( sepadata->objrow == NULL )
103  {
104  SCIP_VAR** vars;
105  SCIP_Real obj;
106  SCIP_Real intobjval;
107  int nvars;
108  int v;
109  SCIP_Bool attendobjvarbound;
110 
111  attendobjvarbound = FALSE;
112  /* create and add objective value variable */
113  if( sepadata->objvar == NULL )
114  {
115  SCIP_CALL( SCIPcreateVar(scip, &sepadata->objvar, "objvar", -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
117  SCIP_CALL( SCIPaddVar(scip, sepadata->objvar) );
118  SCIP_CALL( SCIPaddVarLocks(scip, sepadata->objvar, +1, +1) );
119  }
120  else
121  attendobjvarbound = TRUE;
122 
123  /* get problem variables */
124  vars = SCIPgetOrigVars(scip);
125  nvars = SCIPgetNOrigVars(scip);
126 
127  /* create objective value inequality */
129  {
130  if( attendobjvarbound )
131  intobjval = SCIPceil(scip, SCIPgetDualbound(scip)) - SCIPvarGetLbGlobal(sepadata->objvar);
132  else
133  intobjval = SCIPceil(scip, SCIPgetDualbound(scip));
134  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &sepadata->objrow, sepa, "objrow", intobjval, SCIPinfinity(scip),
135  FALSE, !SCIPallVarsInProb(scip), TRUE) );
136  sepadata->setoff = intobjval;
137  }
138  else
139  {
140  if( attendobjvarbound )
141  intobjval = SCIPceil(scip, SCIPgetDualbound(scip)) - SCIPvarGetUbGlobal(sepadata->objvar);
142  else
143  intobjval = SCIPfloor(scip, SCIPgetDualbound(scip));
144  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &sepadata->objrow, sepa, "objrow", -SCIPinfinity(scip), intobjval,
145  FALSE, !SCIPallVarsInProb(scip), TRUE) );
146  sepadata->setoff = intobjval;
147  }
148 
149  SCIP_CALL( SCIPcacheRowExtensions(scip, sepadata->objrow) );
150  for( v = 0; v < nvars; ++v )
151  {
152  obj = SCIPvarGetObj(vars[v]);
153  if( !SCIPisZero(scip, obj) )
154  {
155  SCIP_CALL( SCIPaddVarToRow(scip, sepadata->objrow, vars[v], obj) );
156  }
157  }
158  SCIP_CALL( SCIPaddVarToRow(scip, sepadata->objrow, sepadata->objvar, -1.0) );
159  SCIP_CALL( SCIPflushRowExtensions(scip, sepadata->objrow) );
160 
161  SCIPdebugMessage("created objective value row: ");
162  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, sepadata->objrow, NULL) ) );
163  }
164 
165  return SCIP_OKAY;
166 }
167 
168 /** searches and adds integral objective cuts that separate the given primal solution */
169 static
171  SCIP* scip, /**< SCIP data structure */
172  SCIP_SEPA* sepa, /**< the intobj separator */
173  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
174  SCIP_RESULT* result /**< pointer to store the result */
175  )
176 {
177  SCIP_SEPADATA* sepadata;
178  SCIP_Real objval;
179  SCIP_Real intbound;
180  SCIP_Bool infeasible;
181  SCIP_Bool tightened;
182 
183  assert(result != NULL);
184  assert(*result == SCIP_DIDNOTRUN);
185 
186  /* if the objective value may be fractional, we cannot do anything */
187  if( !SCIPisObjIntegral(scip) )
188  return SCIP_OKAY;
189 
190  *result = SCIP_DIDNOTFIND;
191 
192  /* if the current objective value is integral, there is no integral objective value cut */
193  if( sol == NULL )
194  objval = SCIPretransformObj(scip, SCIPgetLPObjval(scip));
195  else
196  objval = SCIPgetSolOrigObj(scip, sol);
197  if( SCIPisFeasIntegral(scip, objval) )
198  return SCIP_OKAY;
199 
200  sepadata = SCIPsepaGetData(sepa);
201  assert(sepadata != NULL);
202 
203  /* the objective value is fractional: create the objective value inequality, if not yet existing */
204  SCIP_CALL( createObjRow(scip, sepa, sepadata) );
205 
206  /* adjust the bounds of the objective value variable */
208  {
209  intbound = SCIPceil(scip, objval) - sepadata->setoff;
210  SCIP_CALL( SCIPtightenVarLb(scip, sepadata->objvar, intbound, FALSE, &infeasible, &tightened) );
211  SCIPdebugMessage("new objective variable lower bound: <%s>[%g,%g]\n",
212  SCIPvarGetName(sepadata->objvar), SCIPvarGetLbLocal(sepadata->objvar), SCIPvarGetUbLocal(sepadata->objvar));
213  }
214  else
215  {
216  intbound = SCIPfloor(scip, objval) - sepadata->setoff;
217  SCIP_CALL( SCIPtightenVarUb(scip, sepadata->objvar, intbound, FALSE, &infeasible, &tightened) );
218  SCIPdebugMessage("new objective variable upper bound: <%s>[%g,%g]\n",
219  SCIPvarGetName(sepadata->objvar), SCIPvarGetLbLocal(sepadata->objvar), SCIPvarGetUbLocal(sepadata->objvar));
220  }
221 
222  /* add the objective value inequality as a cut to the LP */
223  if( infeasible )
224  *result = SCIP_CUTOFF;
225  else
226  {
227  if( !SCIProwIsInLP(sepadata->objrow) )
228  {
229  SCIP_CALL( SCIPaddCut(scip, sol, sepadata->objrow, FALSE, &infeasible) );
230  }
231  if ( infeasible )
232  *result = SCIP_CUTOFF;
233  else if ( tightened )
234  *result = SCIP_REDUCEDDOM;
235  else
236  *result = SCIP_SEPARATED;
237  }
238 
239  return SCIP_OKAY;
240 }
241 
242 
243 /*
244  * Callback methods of separator
245  */
246 
247 /** copy method for separator plugins (called when SCIP copies plugins) */
248 static
249 SCIP_DECL_SEPACOPY(sepaCopyIntobj)
250 { /*lint --e{715}*/
251  assert(scip != NULL);
252  assert(sepa != NULL);
253  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
254 
255  /* call inclusion method of constraint handler */
257 
258  return SCIP_OKAY;
259 }
260 
261 /** destructor of separator to free user data (called when SCIP is exiting) */
262 static
263 SCIP_DECL_SEPAFREE(sepaFreeIntobj)
264 { /*lint --e{715}*/
265  SCIP_SEPADATA* sepadata;
266 
267  /* free separator data */
268  sepadata = SCIPsepaGetData(sepa);
269  assert(sepadata != NULL);
270 
271  SCIP_CALL( sepadataFree(scip, &sepadata) );
272 
273  SCIPsepaSetData(sepa, NULL);
274 
275  return SCIP_OKAY;
276 }
277 
278 
279 /** deinitialization method of separator (called before transformed problem is freed) */
280 static
281 SCIP_DECL_SEPAEXIT(sepaExitIntobj)
282 { /*lint --e{715}*/
283  SCIP_SEPADATA* sepadata;
284 
285  sepadata = SCIPsepaGetData(sepa);
286  assert(sepadata != NULL);
287 
288  /* release objective variable */
289  if( sepadata->objvar != NULL )
290  {
291  SCIP_CALL( SCIPreleaseVar(scip, &sepadata->objvar) );
292  }
293 
294  return SCIP_OKAY;
295 }
296 
297 
298 /** solving process deinitialization method of separator (called before branch and bound process data is freed) */
299 static
300 SCIP_DECL_SEPAEXITSOL(sepaExitsolIntobj)
301 { /*lint --e{715}*/
302  SCIP_SEPADATA* sepadata;
303 
304  sepadata = SCIPsepaGetData(sepa);
305  assert(sepadata != NULL);
306 
307  /* release objective row */
308  if( sepadata->objrow != NULL )
309  {
310  SCIP_CALL( SCIPreleaseRow(scip, &sepadata->objrow) );
311  }
312 
313  return SCIP_OKAY;
314 }
315 
316 
317 /** LP solution separation method of separator */
318 static
319 SCIP_DECL_SEPAEXECLP(sepaExeclpIntobj)
320 { /*lint --e{715}*/
321 
322  *result = SCIP_DIDNOTRUN;
323 
324  /* only call separator, if we are not close to terminating */
325  if( SCIPisStopped(scip) )
326  return SCIP_OKAY;
327 
328  /* only call separator, if an optimal LP solution is at hand */
330  return SCIP_OKAY;
331 
332  /* only call separator, if there are fractional variables */
333  if( SCIPgetNLPBranchCands(scip) == 0 )
334  return SCIP_OKAY;
335 
336  SCIP_CALL( separateCuts(scip, sepa, NULL, result) );
337 
338  return SCIP_OKAY;
339 }
340 
341 
342 /** arbitrary primal solution separation method of separator */
343 static
344 SCIP_DECL_SEPAEXECSOL(sepaExecsolIntobj)
345 { /*lint --e{715}*/
346 
347  *result = SCIP_DIDNOTRUN;
348 
349  SCIP_CALL( separateCuts(scip, sepa, sol, result) );
350 
351  return SCIP_OKAY;
352 }
353 
354 
355 /*
356  * event handler for objective changes
357  */
358 
359 
360 /** initialization method of event handler (called after problem was transformed) */
361 static
362 SCIP_DECL_EVENTINIT(eventInitIntobj)
363 { /*lint --e{715}*/
365 
366  return SCIP_OKAY;
367 }
368 
369 /** deinitialization method of event handler (called before transformed problem is freed) */
370 static
371 SCIP_DECL_EVENTEXIT(eventExitIntobj)
372 { /*lint --e{715}*/
374 
375  return SCIP_OKAY;
376 }
377 
378 
379 /** execution method of objective change event handler */
380 static
381 SCIP_DECL_EVENTEXEC(eventExecIntobj)
382 { /*lint --e{715}*/
383  SCIP_EVENTHDLRDATA* eventhdlrdata;
384  SCIP_SEPADATA* sepadata;
385  SCIP_VAR* var;
386  SCIP_Real objdelta;
387 
388  eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
389  sepadata = (SCIP_SEPADATA*)eventhdlrdata;
390  assert(sepadata != NULL);
391 
392  /* we don't have anything to do, if the objective value inequality doesn't yet exist */
393  if( sepadata->objrow == NULL )
394  return SCIP_OKAY;
395 
396  var = SCIPeventGetVar(event);
397 
398  switch( SCIPeventGetType(event) )
399  {
401  SCIPdebugMessage("variable <%s> with obj=%g was added to the problem\n", SCIPvarGetName(var), SCIPvarGetObj(var));
402  objdelta = SCIPvarGetObj(var);
403  if( !SCIPisZero(scip, objdelta) )
404  {
405  SCIP_CALL( SCIPaddVarToRow(scip, sepadata->objrow, var, SCIPvarGetObj(var)) );
406  }
407  break;
408 
410  SCIPdebugMessage("variable <%s> changed objective value from %g to %g\n",
412  objdelta = SCIPeventGetNewobj(event) - SCIPeventGetOldobj(event);
413  SCIP_CALL( SCIPaddVarToRow(scip, sepadata->objrow, var, objdelta) );
414  break;
415 
416  default:
417  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
418  return SCIP_INVALIDDATA;
419  }
420 
421  return SCIP_OKAY;
422 }
423 
424 
425 /*
426  * separator specific interface methods
427  */
428 
429 /** creates the integer objective value separator and includes it in SCIP */
431  SCIP* scip /**< SCIP data structure */
432  )
433 {
434  SCIP_SEPADATA* sepadata;
435  SCIP_EVENTHDLRDATA* eventhdlrdata;
436  SCIP_SEPA* sepa;
437  SCIP_EVENTHDLR* eventhdlr;
438 
439  /* create intobj separator data */
440  SCIP_CALL( sepadataCreate(scip, &sepadata) );
441 
442  /* include separator */
445  sepaExeclpIntobj, sepaExecsolIntobj,
446  sepadata) );
447 
448  assert(sepa != NULL);
449 
450  /* set non-NULL pointers to callback methods */
451  SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyIntobj) );
452  SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeIntobj) );
453  SCIP_CALL( SCIPsetSepaExit(scip, sepa, sepaExitIntobj) );
454  SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolIntobj) );
455 
456  /* include event handler for objective change events */
457  eventhdlr = NULL;
458  eventhdlrdata = (SCIP_EVENTHDLRDATA*)sepadata;
460  eventExecIntobj, eventhdlrdata) );
461  assert(eventhdlr != NULL);
462 
463  SCIP_CALL( SCIPsetEventhdlrInit(scip, eventhdlr, eventInitIntobj) );
464  SCIP_CALL( SCIPsetEventhdlrExit(scip, eventhdlr, eventExitIntobj) );
465 
466  return SCIP_OKAY;
467 }
468