Scippy

SCIP

Solving Constraint Integer Programs

probdata_binpacking.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-2016 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 probdata_binpacking.c
17  * @brief Problem data for binpacking problem
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  *
21  * This file handles the main problem data used in that project. For more details see \ref PROBLEMDATA page.
22  *
23  * @page PROBLEMDATA Main problem data
24  *
25  * The problem data is accessible in all plugins. The function SCIPgetProbData() returns the pointer to that
26  * structure. We use this data structure to store all the information of the binpacking problem. Since this structure is
27  * not visible in the other plugins, we implemented setter and getter functions to access this data. The problem data
28  * structure SCIP_ProbData is shown below.
29  *
30  * \code
31  * ** @brief Problem data which is accessible in all places
32  * *
33  * * This problem data is used to store the input of the binpacking instance, all variables which are created, and all
34  * * constraints.
35  * *
36  * struct SCIP_ProbData
37  * {
38  * SCIP_VAR** vars; **< all exiting variables in the problem *
39  * SCIP_CONS** conss; **< set partitioning constraints for each item exactly one *
40  * SCIP_Longint* weights; **< array of item weights *
41  * int* ids; **< array of item ids *
42  * int nvars; **< number of generated variables *
43  * int varssize; **< size of the variable array *
44  * int nitems; **< number of items *
45  * SCIP_Longint capacity; **< bin capacity *
46  * };
47  * \endcode
48  *
49  * The function SCIPprobdataCreate(), which is called in the \ref reader_bpa.c "reader plugin" after the input file was
50  * parsed, initializes the problem data structure and creates the problem in the SCIP environment. For this, it creates
51  * for each item of the binpacking problem one set covering constraint and creates an initial set of variables for the
52  * packings. Note that the set covering constraints have to have the <code>modifiable</code>-flag set to TRUE. This is
53  * necessary to tell the solver that these constraints are not completed yet. This means, during the search new
54  * variables/packings might be added. The solver needs this information because certain reductions are not allowed.
55  * See the body of the function SCIPprobdataCreate() for more details.
56  *
57  * A list of all interface methods can be found in probdata_binpacking.h.
58  */
59 
60 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
61 
62 #include <string.h>
63 
64 #include "probdata_binpacking.h"
65 #include "vardata_binpacking.h"
66 #include "pricer_binpacking.h"
67 
68 #include "scip/cons_setppc.h"
69 #include "scip/scip.h"
70 
71 /** @brief Problem data which is accessible in all places
72  *
73  * This problem data is used to store the input of the binpacking, all variables which are created, and all
74  * constrsaints.
75  */
77 {
78  SCIP_VAR** vars; /**< all exiting variables in the problem */
79  SCIP_CONS** conss; /**< set partitioning constraints for each item exactly one */
80  SCIP_Longint* weights; /**< array of item weights */
81  int* ids; /**< array of item ids */
82  int nvars; /**< number of generated variables */
83  int varssize; /**< size of the variable array */
84  int nitems; /**< number of items */
85  SCIP_Longint capacity; /**< bin capacity */
86 };
87 
88 
89 /**@name Event handler properties
90  *
91  * @{
92  */
93 
94 #define EVENTHDLR_NAME "addedvar"
95 #define EVENTHDLR_DESC "event handler for catching added variables"
96 
97 /**@} */
98 
99 /**@name Callback methods of event handler
100  *
101  * @{
102  */
103 
104 /** execution method of event handler */
105 static
106 SCIP_DECL_EVENTEXEC(eventExecAddedVar)
107 { /*lint --e{715}*/
108  assert(eventhdlr != NULL);
109  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
110  assert(event != NULL);
111  assert(SCIPeventGetType(event) == SCIP_EVENTTYPE_VARADDED);
112 
113  SCIPdebugMessage("exec method of event handler for added variable to probdata\n");
114 
115  /* add new variable to probdata */
116  SCIP_CALL( SCIPprobdataAddVar(scip, SCIPgetProbData(scip), SCIPeventGetVar(event)) );
117 
118  return SCIP_OKAY;
119 }
120 
121 /**@} */
122 
123 
124 /**@name Local methods
125  *
126  * @{
127  */
128 
129 /** creates problem data */
130 static
131 SCIP_RETCODE probdataCreate(
132  SCIP* scip, /**< SCIP data structure */
133  SCIP_PROBDATA** probdata, /**< pointer to problem data */
134  SCIP_VAR** vars, /**< all exist variables */
135  SCIP_CONS** conss, /**< set partitioning constraints for each job exactly one */
136  SCIP_Longint* weights, /**< array containing the item weights */
137  int* ids, /**< array of item ids */
138  int nvars, /**< number of variables */
139  int nitems, /**< number of items */
140  SCIP_Longint capacity /**< bin capacity */
141  )
142 {
143  assert(scip != NULL);
144  assert(probdata != NULL);
145 
146  /* allocate memory */
147  SCIP_CALL( SCIPallocMemory(scip, probdata) );
148 
149  if( nvars > 0 )
150  {
151  /* copy variable array */
152  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*probdata)->vars, vars, nvars) );
153  }
154  else
155  (*probdata)->vars = NULL;
156 
157  /* duplicate arrays */
158  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*probdata)->conss, conss, nitems) );
159  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*probdata)->weights, weights, nitems) );
160  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*probdata)->ids, ids, nitems) );
161 
162  (*probdata)->nvars = nvars;
163  (*probdata)->varssize = nvars;
164  (*probdata)->nitems = nitems;
165  (*probdata)->capacity = capacity;
166 
167  return SCIP_OKAY;
168 }
169 
170 /** frees the memory of the given problem data */
171 static
172 SCIP_RETCODE probdataFree(
173  SCIP* scip, /**< SCIP data structure */
174  SCIP_PROBDATA** probdata /**< pointer to problem data */
175  )
176 {
177  int i;
178 
179  assert(scip != NULL);
180  assert(probdata != NULL);
181 
182  /* release all variables */
183  for( i = 0; i < (*probdata)->nvars; ++i )
184  {
185  SCIP_CALL( SCIPreleaseVar(scip, &(*probdata)->vars[i]) );
186  }
187 
188  /* release all constraints */
189  for( i = 0; i < (*probdata)->nitems; ++i )
190  {
191  SCIP_CALL( SCIPreleaseCons(scip, &(*probdata)->conss[i]) );
192  }
193 
194  /* free memory of arrays */
195  SCIPfreeMemoryArray(scip, &(*probdata)->vars);
196  SCIPfreeMemoryArray(scip, &(*probdata)->conss);
197  SCIPfreeMemoryArray(scip, &(*probdata)->weights);
198  SCIPfreeMemoryArray(scip, &(*probdata)->ids);
199 
200  /* free probdata */
201  SCIPfreeMemory(scip, probdata);
202 
203  return SCIP_OKAY;
204 }
205 
206 /** create initial columns */
207 static
208 SCIP_RETCODE createInitialColumns(
209  SCIP* scip, /**< SCIP data structure */
210  SCIP_PROBDATA* probdata /**< problem data */
211  )
212 {
213  SCIP_CONS** conss;
214  SCIP_VARDATA* vardata;
215  SCIP_VAR* var;
216  char name[SCIP_MAXSTRLEN];
217 
218  int* ids;
219  SCIP_Longint* weights;
220  int nitems;
221 
222  int i;
223 
224  conss = probdata->conss;
225  ids = probdata->ids;
226  weights = probdata->weights;
227  nitems = probdata->nitems;
228 
229  /* create start solution each item in exactly one bin */
230  for( i = 0; i < nitems; ++i )
231  {
232  int a;
233 
234  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "item_%d", ids[i]);
235 
236  SCIPdebugMessage("create variable for item %d with weight = %"SCIP_LONGINT_FORMAT"\n", ids[i], weights[i]);
237 
238  /* create variable for the packing pattern which contains only this item */
239  SCIP_CALL( SCIPcreateVarBinpacking(scip, &var, name, 1.0, TRUE, TRUE, NULL) );
240 
241  /* add variable to the problem */
242  SCIP_CALL( SCIPaddVar(scip, var) );
243 
244  /* store variable in the problme data */
245  SCIP_CALL( SCIPprobdataAddVar(scip, probdata, var) );
246 
247  /* add variable to corresponding set covering constraint */
248  SCIP_CALL( SCIPaddCoefSetppc(scip, conss[i], var) );
249 
250  /* create the variable data for the variable; the variable data contains the information in which constraints the
251  * variable appears */
252  a = i;
253  SCIP_CALL( SCIPvardataCreateBinpacking(scip, &vardata, &a, 1) );
254 
255  /* add the variable data to the variable */
256  SCIPvarSetData(var, vardata);
257 
258  /* change the upper bound of the binary variable to lazy since the upper bound is already enforced
259  * due to the objective function the set covering constraint;
260  * The reason for doing is that, is to avoid the bound of x <= 1 in the LP relaxation since this bound
261  * constraint would produce a dual variable which might have a positive reduced cost
262  */
263  SCIP_CALL( SCIPchgVarUbLazy(scip, var, 1.0) );
264 
265  /* release variable */
266  SCIP_CALL( SCIPreleaseVar(scip, &var) );
267  }
268 
269  return SCIP_OKAY;
270 }
271 
272 /**@} */
273 
274 /**@name Callback methods of problem data
275  *
276  * @{
277  */
278 
279 /** frees user data of original problem (called when the original problem is freed) */
280 static
281 SCIP_DECL_PROBDELORIG(probdelorigBinpacking)
282 {
283  SCIPdebugMessage("free original problem data\n");
284 
285  SCIP_CALL( probdataFree(scip, probdata) );
286 
287  return SCIP_OKAY;
288 }
289 
290 /** creates user data of transformed problem by transforming the original user problem data
291  * (called after problem was transformed) */
292 static
293 SCIP_DECL_PROBTRANS(probtransBinpacking)
294 {
295  /* create transform probdata */
296  SCIP_CALL( probdataCreate(scip, targetdata, sourcedata->vars, sourcedata->conss, sourcedata->weights, sourcedata->ids,
297  sourcedata->nvars, sourcedata->nitems, sourcedata->capacity) );
298 
299  /* transform all constraints */
300  SCIP_CALL( SCIPtransformConss(scip, (*targetdata)->nitems, (*targetdata)->conss, (*targetdata)->conss) );
301 
302  /* transform all variables */
303  SCIP_CALL( SCIPtransformVars(scip, (*targetdata)->nvars, (*targetdata)->vars, (*targetdata)->vars) );
304 
305  return SCIP_OKAY;
306 }
307 
308 /** frees user data of transformed problem (called when the transformed problem is freed) */
309 static
310 SCIP_DECL_PROBDELTRANS(probdeltransBinpacking)
311 {
312  SCIPdebugMessage("free transformed problem data\n");
313 
314  SCIP_CALL( probdataFree(scip, probdata) );
315 
316  return SCIP_OKAY;
317 }
318 
319 /** solving process initialization method of transformed data (called before the branch and bound process begins) */
320 static
321 SCIP_DECL_PROBINITSOL(probinitsolBinpacking)
322 {
323  SCIP_EVENTHDLR* eventhdlr;
324 
325  assert(probdata != NULL);
326 
327  /* catch variable added event */
328  eventhdlr = SCIPfindEventhdlr(scip, "addedvar");
329  assert(eventhdlr != NULL);
330 
331  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_VARADDED, eventhdlr, NULL, NULL) );
332 
333  return SCIP_OKAY;
334 }
335 
336 /** solving process deinitialization method of transformed data (called before the branch and bound data is freed) */
337 static
338 SCIP_DECL_PROBEXITSOL(probexitsolBinpacking)
339 {
340  SCIP_EVENTHDLR* eventhdlr;
341 
342  assert(probdata != NULL);
343 
344  /* drop variable added event */
345  eventhdlr = SCIPfindEventhdlr(scip, "addedvar");
346  assert(eventhdlr != NULL);
347 
348  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_VARADDED, eventhdlr, NULL, -1) );
349 
350 
351  return SCIP_OKAY;
352 }/*lint !e715*/
353 
354 /**@} */
355 
356 
357 /**@name Interface methods
358  *
359  * @{
360  */
361 
362 /** sets up the problem data */
363 SCIP_RETCODE SCIPprobdataCreate(
364  SCIP* scip, /**< SCIP data structure */
365  const char* probname, /**< problem name */
366  int* ids, /**< array of item ids */
367  SCIP_Longint* weights, /**< array containing the item weights */
368  int nitems, /**< number of items */
369  SCIP_Longint capacity /**< bin capacity */
370  )
371 {
372  SCIP_PROBDATA* probdata;
373  SCIP_CONS** conss;
374  char name[SCIP_MAXSTRLEN];
375  int i;
376 
377  assert(scip != NULL);
378 
379  /* create event handler if it does not exist yet */
380  if( SCIPfindEventhdlr(scip, EVENTHDLR_NAME) == NULL )
381  {
382  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecAddedVar, NULL) );
383  }
384 
385  /* create problem in SCIP and add non-NULL callbacks via setter functions */
386  SCIP_CALL( SCIPcreateProbBasic(scip, probname) );
387 
388  SCIP_CALL( SCIPsetProbDelorig(scip, probdelorigBinpacking) );
389  SCIP_CALL( SCIPsetProbTrans(scip, probtransBinpacking) );
390  SCIP_CALL( SCIPsetProbDeltrans(scip, probdeltransBinpacking) );
391  SCIP_CALL( SCIPsetProbInitsol(scip, probinitsolBinpacking) );
392  SCIP_CALL( SCIPsetProbExitsol(scip, probexitsolBinpacking) );
393 
394  /* set objective sense */
395  SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE) );
396 
397  /* tell SCIP that the objective will be always integral */
398  SCIP_CALL( SCIPsetObjIntegral(scip) );
399 
400  SCIP_CALL( SCIPallocBufferArray(scip, &conss, nitems) );
401 
402  /* create set covering constraints for each item */
403  for( i = 0; i < nitems; ++i )
404  {
405  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "item_%d", ids[i]);
406 
407  SCIP_CALL( SCIPcreateConsBasicSetcover(scip, &conss[i], name, 0, NULL) );
408 
409  /* declare constraint modifiable for adding variables during pricing */
410  SCIP_CALL( SCIPsetConsModifiable(scip, conss[i], TRUE) );
411  SCIP_CALL( SCIPaddCons(scip, conss[i]) );
412  }
413 
414  /* create problem data */
415  SCIP_CALL( probdataCreate(scip, &probdata, NULL, conss, weights, ids, 0, nitems, capacity) );
416 
417  SCIP_CALL( createInitialColumns(scip, probdata) );
418 
419  /* set user problem data */
420  SCIP_CALL( SCIPsetProbData(scip, probdata) );
421 
422  SCIP_CALL( SCIPpricerBinpackingActivate(scip, conss, weights, ids, nitems, capacity) );
423 
424  /* free local buffer arrays */
425  SCIPfreeBufferArray(scip, &conss);
426 
427  return SCIP_OKAY;
428 }
429 
430 /** returns array of item ids */
432  SCIP_PROBDATA* probdata /**< problem data */
433  )
434 {
435  return probdata->ids;
436 }
437 
438 /** returns array of item weights */
440  SCIP_PROBDATA* probdata /**< problem data */
441  )
442 {
443  return probdata->weights;
444 }
445 
446 /** returns number of items */
448  SCIP_PROBDATA* probdata /**< problem data */
449  )
450 {
451  return probdata->nitems;
452 }
453 
454 /** returns bin capacity */
456  SCIP_PROBDATA* probdata /**< problem data */
457  )
458 {
459  return probdata->capacity;
460 }
461 
462 /** returns array of all variables itemed in the way they got generated */
464  SCIP_PROBDATA* probdata /**< problem data */
465  )
466 {
467  return probdata->vars;
468 }
469 
470 /** returns number of variables */
472  SCIP_PROBDATA* probdata /**< problem data */
473  )
474 {
475  return probdata->nvars;
476 }
477 
478 /** returns array of set partitioning constrains */
480  SCIP_PROBDATA* probdata /**< problem data */
481  )
482 {
483  return probdata->conss;
484 }
485 
486 /** adds given variable to the problem data */
487 SCIP_RETCODE SCIPprobdataAddVar(
488  SCIP* scip, /**< SCIP data structure */
489  SCIP_PROBDATA* probdata, /**< problem data */
490  SCIP_VAR* var /**< variables to add */
491  )
492 {
493  /* check if enough memory is left */
494  if( probdata->varssize == probdata->nvars )
495  {
496  probdata->varssize = MAX(100, probdata->varssize * 2);
497  SCIP_CALL( SCIPreallocMemoryArray(scip, &probdata->vars, probdata->varssize) );
498  }
499 
500  /* caputure variables */
501  SCIP_CALL( SCIPcaptureVar(scip, var) );
502 
503  probdata->vars[probdata->nvars] = var;
504  probdata->nvars++;
505 
506  SCIPdebugMessage("added variable to probdata; nvars = %d\n", probdata->nvars);
507 
508  return SCIP_OKAY;
509 }
510 
511 /**@} */
#define EVENTHDLR_NAME
SCIP_RETCODE SCIPpricerBinpackingActivate(SCIP *scip, SCIP_CONS **conss, SCIP_Longint *weights, int *ids, int nitems, SCIP_Longint capacity)
SCIP_CONS ** conss
static SCIP_DECL_PROBDELTRANS(probdeltransBinpacking)
Binpacking variable pricer.
SCIP_RETCODE SCIPprobdataCreate(SCIP *scip, const char *probname, int *ids, SCIP_Longint *weights, int nitems, SCIP_Longint capacity)
static SCIP_DECL_PROBEXITSOL(probexitsolBinpacking)
#define EVENTHDLR_DESC
Variable data containing the ids of constraints in which the variable appears.
SCIP_VAR ** SCIPprobdataGetVars(SCIP_PROBDATA *probdata)
Problem data which is accessible in all places.
static SCIP_RETCODE probdataCreate(SCIP *scip, SCIP_PROBDATA **probdata, SCIP_VAR **vars, SCIP_CONS **conss, SCIP_Longint *weights, int *ids, int nvars, int nitems, SCIP_Longint capacity)
static SCIP_DECL_PROBTRANS(probtransBinpacking)
SCIP_RETCODE SCIPcreateVarBinpacking(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real obj, SCIP_Bool initial, SCIP_Bool removable, SCIP_VARDATA *vardata)
SCIP_Longint capacity
SCIP_Longint * SCIPprobdataGetWeights(SCIP_PROBDATA *probdata)
static SCIP_DECL_EVENTEXEC(eventExecAddedVar)
SCIP_Longint SCIPprobdataGetCapacity(SCIP_PROBDATA *probdata)
static SCIP_DECL_PROBINITSOL(probinitsolBinpacking)
SCIP_RETCODE SCIPvardataCreateBinpacking(SCIP *scip, SCIP_VARDATA **vardata, int *consids, int nconsids)
int * SCIPprobdataGetIds(SCIP_PROBDATA *probdata)
Problem data for binpacking problem.
int SCIPprobdataGetNItems(SCIP_PROBDATA *probdata)
SCIP_CONS ** SCIPprobdataGetConss(SCIP_PROBDATA *probdata)
SCIP_RETCODE SCIPprobdataAddVar(SCIP *scip, SCIP_PROBDATA *probdata, SCIP_VAR *var)
int SCIPprobdataGetNVars(SCIP_PROBDATA *probdata)
static SCIP_RETCODE probdataFree(SCIP *scip, SCIP_PROBDATA **probdata)
static SCIP_DECL_PROBDELORIG(probdelorigBinpacking)
SCIP_Longint * weights
static SCIP_RETCODE createInitialColumns(SCIP *scip, SCIP_PROBDATA *probdata)