Scippy

SCIP

Solving Constraint Integer Programs

pricer_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 pricer_binpacking.c
17  * @brief Binpacking variable pricer
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  *
21  * This file implements the variable pricer which check if variables exist with negative reduced cost. See
22  * @ref PRICER for more details.
23  *
24  * @page PRICER Pricing new variables
25  *
26  * The task of the pricer is to search for new variables with negative reduced costs. For this, the following integer
27  * program is solved:
28  *
29  * \f[
30  * \begin{array}[t]{rll}
31  * \max & \displaystyle \sum_{i=1}^n (\lambda_S)_i y^\star_i\\
32  * & \\
33  * subject \ to & \displaystyle \sum_{i=0}^n (\lambda_S)_i s_i \leq \kappa \\
34  * & \\
35  * & (\lambda_S)_i \in \{0,1\} & \quad \forall i \in \{ 1, \dots , n \} \\
36  * \end{array}
37  * \f]
38  *
39  * where \f$ (\lambda_S)_i \f$ for \f$i\in\{1,\dots,n\}\f$ are binary variables and \f$y^\star_i\f$ given by the dual
40  * solution of the restricted master problem. See the \ref PROBLEM "problem description" for more details.
41  *
42  * To solve the above integer program, we create a new SCIP instance within SCIP and use the usual functions to create
43  * variables and constraints. Besides, we need the current dual solutions to all set covering constraints (each stands
44  * for one item) which are the objective coefficients of the binary variables. Therefore, we use the function
45  * SCIPgetDualsolSetppc() which returns the dual solutions for the given set covering constraint.
46  *
47  * Since we also want to generate new variables during search, we have to care that we do not generate variables over
48  * and over again. For example, if we branched or fixed a certain packing to zero, we have to make sure that we do not
49  * generate the corresponding variables at that node again. For this, we have to add constraints forbidding to generate
50  * variables which are locally fixed to zero. See the function addFixedVarsConss() for more details. While using the
51  * \ref BRANCHING "Ryan/Foster branching", we also have to ensure that these branching decisions are respected. This is
52  * realized within the function addBranchingDecisionConss().
53  *
54  * @note In case of this binpacking example, the master LP should not get infeasible after branching, because of the way
55  * branching is performed. Therefore, the Farkas pricing is not implemented.
56  * 1. In case of Ryan/Foster branching, the two items are selected in a way such that the sum of the LP values of
57  * all columns/packings containing both items is fractional. Hence, it exists at least one column/packing which
58  * contains both items and also at least one column/packing for each item containing this but not the other
59  * item. That means, branching in the "same" direction stays LP feasible since there exists at least one
60  * column/packing with both items and branching in the "differ" direction stays LP feasible since there exists
61  * at least one column/packing containing one item, but not the other.
62  * 2. In case of variable branching, we only branch on fractional variables. If a variable is fixed to one, there
63  * is no issue. If a variable is fixed to zero, then we know that for each item which is part of that
64  * column/packing, there exists at least one other column/packing containing this particular item due to the
65  * covering constraints.
66  */
67 
68 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
69 
70 #include <assert.h>
71 #include <string.h>
72 
73 #include "scip/cons_knapsack.h"
74 #include "scip/cons_logicor.h"
75 #include "scip/cons_setppc.h"
76 #include "scip/cons_varbound.h"
77 #include "scip/scipdefplugins.h"
78 
79 #include "cons_samediff.h"
80 #include "pricer_binpacking.h"
81 #include "probdata_binpacking.h"
82 #include "vardata_binpacking.h"
83 
84 /**@name Pricer properties
85  *
86  * @{
87  */
88 
89 #define PRICER_NAME "binpacking"
90 #define PRICER_DESC "pricer for binpacking tours"
91 #define PRICER_PRIORITY 0
92 #define PRICER_DELAY TRUE /* only call pricer if all problem variables have non-negative reduced costs */
93 
94 /**@} */
95 
96 
97 /*
98  * Data structures
99  */
100 
101 /** @brief Variable pricer data used in the \ref pricer_binpacking.c "pricer" */
103 {
104  SCIP_CONSHDLR* conshdlr; /**< comstraint handler for "same" and "diff" constraints */
105  SCIP_CONS** conss; /**< set covering constraints for the items */
106  SCIP_Longint* weights; /**< weight of the items */
107  int* ids; /**< array of item ids */
108  int nitems; /**< number of items to be packed */
109  SCIP_Longint capacity; /**< capacity of the bins */
110 };
111 
112 
113 
114 /**@name Local methods
115  *
116  * @{
117  */
118 
119 /** add branching decisions constraints to the sub SCIP */
120 static
122  SCIP* scip, /**< SCIP data structure */
123  SCIP* subscip, /**< pricing SCIP data structure */
124  SCIP_VAR** vars, /**< variable array of the subscuip oder variables */
125  SCIP_CONSHDLR* conshdlr /**< constraint handler for branching data */
126  )
127 {
128  SCIP_CONS** conss;
129  SCIP_CONS* cons;
130  int nconss;
131  int id1;
132  int id2;
133  CONSTYPE type;
134 
135  SCIP_Real vbdcoef;
136  SCIP_Real lhs;
137  SCIP_Real rhs;
138 
139  int c;
140 
141  assert( scip != NULL );
142  assert( subscip != NULL );
143  assert( conshdlr != NULL );
144 
145  /* collect all branching decision constraints */
146  conss = SCIPconshdlrGetConss(conshdlr);
147  nconss = SCIPconshdlrGetNConss(conshdlr);
148 
149  /* loop over all branching decision constraints and apply the branching decision if the corresponding constraint is
150  * active
151  */
152  for( c = 0; c < nconss; ++c )
153  {
154  cons = conss[c];
155 
156  /* ignore constraints which are not active since these are not laying on the current active path of the search
157  * tree
158  */
159  if( !SCIPconsIsActive(cons) )
160  continue;
161 
162  /* collect the two item ids and the branching type (SAME or DIFFER) on which the constraint branched */
163  id1 = SCIPgetItemid1Samediff(scip, cons);
164  id2 = SCIPgetItemid2Samediff(scip, cons);
165  type = SCIPgetTypeSamediff(scip, cons);
166 
167  SCIPdebugMessage("create varbound for %s(%d,%d)\n", type == SAME ? "same" : "diff",
168  SCIPprobdataGetIds(SCIPgetProbData(scip))[id1], SCIPprobdataGetIds(SCIPgetProbData(scip))[id2]);
169 
170  /* depending on the branching type select the correct left and right hand side for the linear constraint which
171  * enforces this branching decision in the pricing problem MIP
172  */
173  if( type == SAME )
174  {
175  lhs = 0.0;
176  rhs = 0.0;
177  vbdcoef = -1.0;
178  }
179  else if( type == DIFFER )
180  {
181  lhs = -SCIPinfinity(scip);
182  rhs = 1.0;
183  vbdcoef = 1.0;
184  }
185  else
186  {
187  SCIPerrorMessage("unknow constraint type <%d>\n, type");
188  return SCIP_INVALIDDATA;
189  }
190 
191  /* add linear (in that case a variable bound) constraint to pricing MIP depending on the branching type:
192  *
193  * - branching type SAME: x1 = x2 <=> x1 - x2 = 0 <=> 0 <= x1 - x2 <= 0
194  *
195  * - branching type DIFFER: x1 + x2 <= 1 <=> -inf <= x1 + x2 <= 1
196  *
197  * note a setppc constraint would be sufficient and even better suitable for such kind of constraint
198  */
199  SCIP_CALL( SCIPcreateConsBasicVarbound(subscip, &cons, SCIPconsGetName(conss[c]),
200  vars[id1], vars[id2], vbdcoef, lhs, rhs) );
201 
202  SCIPdebugPrintCons(subscip, cons, NULL);
203 
204  SCIP_CALL( SCIPaddCons(subscip, cons) );
205  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
206  }
207 
208  return SCIP_OKAY;
209 }
210 
211 /** avoid to generate columns which are fixed to zero; therefore add for each variable which is fixed to zero a
212  * corresponding logicor constraint to forbid this column
213  *
214  * @note variable which are fixed locally to zero should not be generated again by the pricing MIP
215  */
216 static
217 SCIP_RETCODE addFixedVarsConss(
218  SCIP* scip, /**< SCIP data structure */
219  SCIP* subscip, /**< pricing SCIP data structure */
220  SCIP_VAR** vars, /**< variable array of the subscuip */
221  SCIP_CONS** conss, /**< array of setppc constraint for each item one */
222  int nitems /**< number of items */
223  )
224 {
225  SCIP_VAR** origvars;
226  int norigvars;
227 
228  SCIP_CONS* cons;
229  int* consids;
230  int nconsids;
231  int consid;
232  int nvars;
233 
234  SCIP_VAR** logicorvars;
235  SCIP_VAR* var;
236  SCIP_VARDATA* vardata;
237  SCIP_Bool needed;
238  int nlogicorvars;
239 
240  int v;
241  int c;
242  int o;
243 
244  /* collect all variable which are currently existing */
245  origvars = SCIPgetVars(scip);
246  norigvars = SCIPgetNVars(scip);
247 
248  /* loop over all these variables and check if they are fixed to zero */
249  for( v = 0; v < norigvars; ++v )
250  {
251  assert(SCIPvarGetType(origvars[v]) == SCIP_VARTYPE_BINARY);
252 
253  /* if the upper bound is smaller than 0.5 if follows due to the integrality that the binary variable is fixed to zero */
254  if( SCIPvarGetUbLocal(origvars[v]) < 0.5 )
255  {
256  SCIPdebugMessage("variable <%s> glb=[%.15g,%.15g] loc=[%.15g,%.15g] is fixed to zero\n",
257  SCIPvarGetName(origvars[v]), SCIPvarGetLbGlobal(origvars[v]), SCIPvarGetUbGlobal(origvars[v]),
258  SCIPvarGetLbLocal(origvars[v]), SCIPvarGetUbLocal(origvars[v]) );
259 
260  /* coolect the constraints/items the variable belongs to */
261  vardata = SCIPvarGetData(origvars[v]);
262  nconsids = SCIPvardataGetNConsids(vardata);
263  consids = SCIPvardataGetConsids(vardata);
264  needed = TRUE;
265 
266  SCIP_CALL( SCIPallocBufferArray(subscip, &logicorvars, nitems) );
267  nlogicorvars = 0;
268  consid = consids[0];
269  nvars = 0;
270 
271  /* loop over these items and create a linear (logicor) constraint which forbids this item combination in the
272  * pricing problem; thereby check if this item combination is already forbidden
273  */
274  for( c = 0, o = 0; o < nitems && needed; ++o )
275  {
276  assert(o <= consid);
277  cons = conss[o];
278 
279  if( SCIPconsIsEnabled(cons) )
280  {
281  assert( SCIPgetNFixedonesSetppc(scip, cons) == 0 );
282 
283  var = vars[nvars];
284  nvars++;
285  assert(var != NULL);
286 
287  if( o == consid )
288  {
289  SCIP_CALL( SCIPgetNegatedVar(subscip, var, &var) );
290  }
291 
292  logicorvars[nlogicorvars] = var;
293  nlogicorvars++;
294  }
295  else if( o == consid )
296  needed = FALSE;
297 
298  if( o == consid )
299  {
300  c++;
301  if ( c == nconsids )
302  consid = nitems + 100;
303  else
304  {
305  assert(consid < consids[c]);
306  consid = consids[c];
307  }
308  }
309  }
310 
311  if( needed )
312  {
313  SCIP_CALL( SCIPcreateConsBasicLogicor(subscip, &cons, SCIPvarGetName(origvars[v]), nlogicorvars, logicorvars) );
314  SCIP_CALL( SCIPsetConsInitial(subscip, cons, FALSE) );
315 
316  SCIP_CALL( SCIPaddCons(subscip, cons) );
317  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
318  }
319 
320  SCIPfreeBufferArray(subscip, &logicorvars);
321  }
322  }
323 
324  return SCIP_OKAY;
325 }
326 
327 /** initializes the pricing problem for the given capacity */
328 static
329 SCIP_RETCODE initPricing(
330  SCIP* scip, /**< SCIP data structure */
331  SCIP_PRICERDATA* pricerdata, /**< pricer data */
332  SCIP* subscip, /**< pricing SCIP data structure */
333  SCIP_VAR** vars /**< variable array for the items */
334  )
335 {
336  SCIP_CONS** conss;
337  SCIP_Longint* vals;
338  SCIP_CONS* cons;
339  SCIP_VAR* var;
340  SCIP_Longint* weights;
341  SCIP_Longint capacity;
342  SCIP_Real dual;
343 
344  int nitems;
345  int nvars;
346  int c;
347 
348  assert( SCIPgetStage(subscip) == SCIP_STAGE_PROBLEM );
349  assert(pricerdata != NULL);
350 
351  nitems = pricerdata->nitems;
352  conss = pricerdata->conss;
353  weights = pricerdata->weights;
354  capacity = pricerdata->capacity;
355  nvars = 0;
356 
357  SCIP_CALL( SCIPallocBufferArray(subscip, &vals, nitems) );
358 
359  /* create for each order, which is not assigned yet, a variable with objective coefficient */
360  for( c = 0; c < nitems; ++c )
361  {
362  cons = conss[c];
363 
364  /* check if each constraint is setppc constraint */
365  assert( !strncmp( SCIPconshdlrGetName( SCIPconsGetHdlr(cons) ), "setppc", 6) );
366 
367  /* constraints which are (locally) disabled/redundant are not of
368  * interest since the corresponding job is assigned to a packing
369  */
370  if( !SCIPconsIsEnabled(cons) )
371  continue;
372 
373  if( SCIPgetNFixedonesSetppc(scip, cons) == 1 )
374  {
375  /* disable constraint locally */
376  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
377  continue;
378  }
379 
380  /* dual value in original SCIP */
381  dual = SCIPgetDualsolSetppc(scip, cons);
382 
383  SCIP_CALL( SCIPcreateVarBasic(subscip, &var, SCIPconsGetName(cons), 0.0, 1.0, dual, SCIP_VARTYPE_BINARY) );
384  SCIP_CALL( SCIPaddVar(subscip, var) );
385 
386  vals[nvars] = weights[c];
387  vars[nvars] = var;
388  nvars++;
389 
390  /* release variable */
391  SCIP_CALL( SCIPreleaseVar(subscip, &var) );
392  }
393 
394  /* create capacity constraint */
395  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, "capacity", nvars, vars, vals,
396  capacity) );
397 
398  SCIP_CALL( SCIPaddCons(subscip, cons) );
399  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
400 
401  /* add constraint of the branching decisions */
402  SCIP_CALL( addBranchingDecisionConss(scip, subscip, vars, pricerdata->conshdlr) );
403 
404  /* avoid to generate columns which are fixed to zero */
405  SCIP_CALL( addFixedVarsConss(scip, subscip, vars, conss, nitems) );
406 
407  SCIPfreeBufferArray(subscip, &vals);
408 
409  return SCIP_OKAY;
410 }
411 
412 /**@} */
413 
414 /**name Callback methods
415  *
416  * @{
417  */
418 
419 /** destructor of variable pricer to free user data (called when SCIP is exiting) */
420 static
421 SCIP_DECL_PRICERFREE(pricerFreeBinpacking)
422 {
423  SCIP_PRICERDATA* pricerdata;
424 
425  assert(scip != NULL);
426  assert(pricer != NULL);
427 
428  pricerdata = SCIPpricerGetData(pricer);
429 
430  if( pricerdata != NULL)
431  {
432  /* free memory */
433  SCIPfreeMemoryArrayNull(scip, &pricerdata->conss);
434  SCIPfreeMemoryArrayNull(scip, &pricerdata->weights);
435  SCIPfreeMemoryArrayNull(scip, &pricerdata->ids);
436 
437  SCIPfreeMemory(scip, &pricerdata);
438  }
439 
440  return SCIP_OKAY;
441 }
442 
443 
444 /** initialization method of variable pricer (called after problem was transformed) */
445 static
446 SCIP_DECL_PRICERINIT(pricerInitBinpacking)
447 { /*lint --e{715}*/
448  SCIP_PRICERDATA* pricerdata;
449  SCIP_CONS* cons;
450  int c;
451 
452  assert(scip != NULL);
453  assert(pricer != NULL);
454 
455  pricerdata = SCIPpricerGetData(pricer);
456  assert(pricerdata != NULL);
457 
458  /* get transformed constraints */
459  for( c = 0; c < pricerdata->nitems; ++c )
460  {
461  cons = pricerdata->conss[c];
462 
463  /* release original constraint */
464  SCIP_CALL( SCIPreleaseCons(scip, &pricerdata->conss[c]) );
465 
466  /* get transformed constraint */
467  SCIP_CALL( SCIPgetTransformedCons(scip, cons, &pricerdata->conss[c]) );
468 
469  /* capture transformed constraint */
470  SCIP_CALL( SCIPcaptureCons(scip, pricerdata->conss[c]) );
471  }
472 
473  return SCIP_OKAY;
474 }
475 
476 
477 /** solving process deinitialization method of variable pricer (called before branch and bound process data is freed) */
478 static
479 SCIP_DECL_PRICEREXITSOL(pricerExitsolBinpacking)
480 {
481  SCIP_PRICERDATA* pricerdata;
482  int c;
483 
484  assert(scip != NULL);
485  assert(pricer != NULL);
486 
487  pricerdata = SCIPpricerGetData(pricer);
488  assert(pricerdata != NULL);
489 
490  /* get release constraints */
491  for( c = 0; c < pricerdata->nitems; ++c )
492  {
493  /* release constraint */
494  SCIP_CALL( SCIPreleaseCons(scip, &(pricerdata->conss[c])) );
495  }
496 
497  return SCIP_OKAY;
498 }
499 
500 
501 /** reduced cost pricing method of variable pricer for feasible LPs */
502 static
503 SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking)
504 { /*lint --e{715}*/
505  SCIP* subscip;
506  SCIP_PRICERDATA* pricerdata;
507  SCIP_CONS** conss;
508  SCIP_VAR** vars;
509  int* ids;
510  SCIP_Bool addvar;
511 
512  SCIP_SOL** sols;
513  int nsols;
514  int s;
515 
516  int nitems;
517  SCIP_Longint capacity;
518 
519  SCIP_Real timelimit;
520  SCIP_Real memorylimit;
521 
522  assert(scip != NULL);
523  assert(pricer != NULL);
524 
525  (*result) = SCIP_DIDNOTRUN;
526 
527  /* get the pricer data */
528  pricerdata = SCIPpricerGetData(pricer);
529  assert(pricerdata != NULL);
530 
531  capacity = pricerdata->capacity;
532  conss = pricerdata->conss;
533  ids = pricerdata->ids;
534  nitems = pricerdata->nitems;
535 
536  /* get the remaining time and memory limit */
537  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
538  if( !SCIPisInfinity(scip, timelimit) )
539  timelimit -= SCIPgetSolvingTime(scip);
540  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
541  if( !SCIPisInfinity(scip, memorylimit) )
542  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
543 
544  /* initialize SCIP */
545  SCIP_CALL( SCIPcreate(&subscip) );
546  SCIP_CALL( SCIPincludeDefaultPlugins(subscip) );
547 
548  /* create problem in sub SCIP */
549  SCIP_CALL( SCIPcreateProbBasic(subscip, "pricing") );
550  SCIP_CALL( SCIPsetObjsense(subscip, SCIP_OBJSENSE_MAXIMIZE) );
551 
552  /* do not abort subproblem on CTRL-C */
553  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
554 
555  /* disable output to console */
556  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
557 
558  /* set time and memory limit */
559  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
560  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
561 
562  SCIP_CALL( SCIPallocMemoryArray(subscip, &vars, nitems) );
563 
564  /* initialization local pricing problem */
565  SCIP_CALL( initPricing(scip, pricerdata, subscip, vars) );
566 
567  SCIPdebugMessage("solve pricer problem\n");
568 
569  /* solve sub SCIP */
570  SCIP_CALL( SCIPsolve(subscip) );
571 
572  sols = SCIPgetSols(subscip);
573  nsols = SCIPgetNSols(subscip);
574  addvar = FALSE;
575 
576  /* loop over all solutions and create the corresponding column to master if the reduced cost are negative for master,
577  * that is the objective value i greater than 1.0
578  */
579  for( s = 0; s < nsols; ++s )
580  {
581  SCIP_Bool feasible;
582  SCIP_SOL* sol;
583 
584  /* the soultion should be sorted w.r.t. the objective function value */
585  assert(s == 0 || SCIPisFeasGE(subscip, SCIPgetSolOrigObj(subscip, sols[s-1]), SCIPgetSolOrigObj(subscip, sols[s])));
586 
587  sol = sols[s];
588  assert(sol != NULL);
589 
590  /* check if solution is feasible in original sub SCIP */
591  SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE ) );
592 
593  if( !feasible )
594  {
595  SCIPwarningMessage(scip, "solution in pricing problem (capacity <%d>) is infeasible\n", capacity);
596  continue;
597  }
598 
599  /* check if the solution has a value greater than 1.0 */
600  if( SCIPisFeasGT(subscip, SCIPgetSolOrigObj(subscip, sol), 1.0) )
601  {
602  SCIP_VAR* var;
603  SCIP_VARDATA* vardata;
604  int* consids;
605  char strtmp[SCIP_MAXSTRLEN];
606  char name[SCIP_MAXSTRLEN];
607  int nconss;
608  int o;
609  int v;
610 
611  SCIPdebug( SCIP_CALL( SCIPprintSol(subscip, sol, NULL, FALSE) ) );
612 
613  nconss = 0;
614  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "items");
615 
616  SCIP_CALL( SCIPallocBufferArray(scip, &consids, nitems) );
617 
618  /* check which variables are fixed -> which item belongs to this packing */
619  for( o = 0, v = 0; o < nitems; ++o )
620  {
621  if( !SCIPconsIsEnabled(conss[o]) )
622  continue;
623 
624  assert(SCIPgetNFixedonesSetppc(scip, conss[o]) == 0);
625 
626  if( SCIPgetSolVal(subscip, sol, vars[v]) > 0.5 )
627  {
628  (void) SCIPsnprintf(strtmp, SCIP_MAXSTRLEN, "_%d", ids[o]);
629  strcat(name, strtmp);
630 
631  consids[nconss] = o;
632  nconss++;
633  }
634  else
635  assert( SCIPisFeasEQ(subscip, SCIPgetSolVal(subscip, sol, vars[v]), 0.0) );
636 
637  v++;
638  }
639 
640  SCIP_CALL( SCIPvardataCreateBinpacking(scip, &vardata, consids, nconss) );
641 
642  /* create variable for a new column with objective function coefficient 0.0 */
643  SCIP_CALL( SCIPcreateVarBinpacking(scip, &var, name, 1.0, FALSE, TRUE, vardata) );
644 
645  /* add the new variable to the pricer store */
646  SCIP_CALL( SCIPaddPricedVar(scip, var, 1.0) );
647  addvar = TRUE;
648 
649  /* change the upper bound of the binary variable to lazy since the upper bound is already enforced due to
650  * the objective function the set covering constraint; The reason for doing is that, is to avoid the bound
651  * of x <= 1 in the LP relaxation since this bound constraint would produce a dual variable which might have
652  * a positive reduced cost
653  */
654  SCIP_CALL( SCIPchgVarUbLazy(scip, var, 1.0) );
655 
656  /* check which variable are fixed -> which orders belong to this packing */
657  for( v = 0; v < nconss; ++v )
658  {
659  assert(SCIPconsIsEnabled(conss[consids[v]]));
660  SCIP_CALL( SCIPaddCoefSetppc(scip, conss[consids[v]], var) );
661  }
662 
663  SCIPdebug(SCIPprintVar(scip, var, NULL) );
664  SCIP_CALL( SCIPreleaseVar(scip, &var) );
665 
666  SCIPfreeBufferArray(scip, &consids);
667  }
668  else
669  break;
670  }
671 
672  /* free pricer MIP */
673  SCIPfreeMemoryArray(subscip, &vars);
674 
675  if( addvar || SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL )
676  (*result) = SCIP_SUCCESS;
677 
678  /* free sub SCIP */
679  SCIP_CALL( SCIPfree(&subscip) );
680 
681  return SCIP_OKAY;
682 }
683 
684 /** farkas pricing method of variable pricer for infeasible LPs */
685 static
686 SCIP_DECL_PRICERFARKAS(pricerFarkasBinpacking)
687 { /*lint --e{715}*/
688 
689  /** @note In case of this binpacking example, the master LP should not get infeasible after branching, because of the
690  * way branching is performed. Therefore, the Farkas pricing is not implemented.
691  * 1. In case of Ryan/Foster branching, the two items are selected in a way such that the sum of the LP values
692  * of all columns/packings containing both items is fractional. Hence, it exists at least one
693  * column/packing which contains both items and also at least one column/packing for each item containing
694  * this but not the other item. That means, branching in the "same" direction stays LP feasible since there
695  * exists at least one column/packing with both items and branching in the "differ" direction stays LP
696  * feasible since there exists at least one column/packing containing one item, but not the other.
697  * 2. In case of variable branching, we only branch on fractional variables. If a variable is fixed to one,
698  * there is no issue. If a variable is fixed to zero, then we know that for each item which is part of
699  * that column/packing, there exists at least one other column/packing containing this particular item due
700  * to the covering constraints.
701  */
702  SCIPwarningMessage(scip, "Current master LP is infeasible, but Farkas pricing was not implemented\n");
703  SCIPABORT();
704 
705  return SCIP_OKAY; /*lint !e527*/
706 }
707 
708 /**@} */
709 
710 
711 /**@name Interface methods
712  *
713  * @{
714  */
715 
716 /** creates the binpacking variable pricer and includes it in SCIP */
718  SCIP* scip /**< SCIP data structure */
719  )
720 {
721  SCIP_PRICERDATA* pricerdata;
722  SCIP_PRICER* pricer;
723 
724  /* create binpacking variable pricer data */
725  SCIP_CALL( SCIPallocMemory(scip, &pricerdata) );
726 
727  pricerdata->conshdlr = SCIPfindConshdlr(scip, "samediff");
728  assert(pricerdata->conshdlr != NULL);
729 
730  pricerdata->conss = NULL;
731  pricerdata->weights = NULL;
732  pricerdata->ids = NULL;
733  pricerdata->nitems = 0;
734  pricerdata->capacity = 0;
735 
736  /* include variable pricer */
737  SCIP_CALL( SCIPincludePricerBasic(scip, &pricer, PRICER_NAME, PRICER_DESC, PRICER_PRIORITY, PRICER_DELAY,
738  pricerRedcostBinpacking, pricerFarkasBinpacking, pricerdata) );
739 
740  SCIP_CALL( SCIPsetPricerFree(scip, pricer, pricerFreeBinpacking) );
741  SCIP_CALL( SCIPsetPricerInit(scip, pricer, pricerInitBinpacking) );
742  SCIP_CALL( SCIPsetPricerExitsol(scip, pricer, pricerExitsolBinpacking) );
743 
744  /* add binpacking variable pricer parameters */
745  /* TODO: (optional) add variable pricer specific parameters with SCIPaddTypeParam() here */
746 
747  return SCIP_OKAY;
748 }
749 
750 
751 /** added problem specific data to pricer and activates pricer */
753  SCIP* scip, /**< SCIP data structure */
754  SCIP_CONS** conss, /**< set covering constraints for the items */
755  SCIP_Longint* weights, /**< weight of the items */
756  int* ids, /**< array of item ids */
757  int nitems, /**< number of items to be packed */
758  SCIP_Longint capacity /**< capacity of the bins */
759  )
760 {
761  SCIP_PRICER* pricer;
762  SCIP_PRICERDATA* pricerdata;
763  int c;
764 
765  assert(scip != NULL);
766  assert(conss != NULL);
767  assert(weights != NULL);
768  assert(nitems > 0);
769 
770  pricer = SCIPfindPricer(scip, PRICER_NAME);
771  assert(pricer != NULL);
772 
773  pricerdata = SCIPpricerGetData(pricer);
774  assert(pricerdata != NULL);
775 
776  /* copy arrays */
777  SCIP_CALL( SCIPduplicateMemoryArray(scip, &pricerdata->conss, conss, nitems) );
778  SCIP_CALL( SCIPduplicateMemoryArray(scip, &pricerdata->weights, weights, nitems) );
779  SCIP_CALL( SCIPduplicateMemoryArray(scip, &pricerdata->ids, ids, nitems) );
780 
781  pricerdata->nitems = nitems;
782  pricerdata->capacity = capacity;
783 
784  SCIPdebugMessage(" nitems: %d capacity: %"SCIP_LONGINT_FORMAT" \n", nitems, capacity);
785  SCIPdebugMessage(" # profits weights x \n"); /* capture constraints */
786 
787  /* capture all constraints */
788  for( c = 0; c < nitems; ++c )
789  {
790  SCIP_CALL( SCIPcaptureCons(scip, conss[c]) );
791  SCIPdebugPrintf("%4d %3"SCIP_LONGINT_FORMAT"\n", c, weights[c]);
792  }
793 
794  /* activate pricer */
795  SCIP_CALL( SCIPactivatePricer(scip, pricer) );
796 
797  return SCIP_OKAY;
798 }
799 
800 /**@} */
SCIP_RETCODE SCIPpricerBinpackingActivate(SCIP *scip, SCIP_CONS **conss, SCIP_Longint *weights, int *ids, int nitems, SCIP_Longint capacity)
Variable pricer data used in the pricer.
SCIP_Longint capacity
static SCIP_RETCODE addFixedVarsConss(SCIP *scip, SCIP *subscip, SCIP_VAR **vars, SCIP_CONS **conss, int nitems)
static SCIP_DECL_PRICEREXITSOL(pricerExitsolBinpacking)
SCIP_RETCODE SCIPincludePricerBinpacking(SCIP *scip)
SCIP_CONSHDLR * conshdlr
Constraint handler stores the local branching decision data.
Binpacking variable pricer.
SCIP_CONS ** conss
Variable data containing the ids of constraints in which the variable appears.
int * SCIPvardataGetConsids(SCIP_VARDATA *vardata)
static SCIP_DECL_PRICERINIT(pricerInitBinpacking)
#define PRICER_PRIORITY
SCIP_RETCODE SCIPcreateVarBinpacking(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real obj, SCIP_Bool initial, SCIP_Bool removable, SCIP_VARDATA *vardata)
#define PRICER_DELAY
static SCIP_DECL_PRICERFARKAS(pricerFarkasBinpacking)
int SCIPgetItemid2Samediff(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_PRICERFREE(pricerFreeBinpacking)
#define PRICER_DESC
SCIP_RETCODE SCIPvardataCreateBinpacking(SCIP *scip, SCIP_VARDATA **vardata, int *consids, int nconsids)
int * SCIPprobdataGetIds(SCIP_PROBDATA *probdata)
Problem data for binpacking problem.
CONSTYPE SCIPgetTypeSamediff(SCIP *scip, SCIP_CONS *cons)
int SCIPgetItemid1Samediff(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addBranchingDecisionConss(SCIP *scip, SCIP *subscip, SCIP_VAR **vars, SCIP_CONSHDLR *conshdlr)
static SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking)
#define PRICER_NAME
int SCIPvardataGetNConsids(SCIP_VARDATA *vardata)
SCIP_Longint * weights
static SCIP_RETCODE initPricing(SCIP *scip, SCIP_PRICERDATA *pricerdata, SCIP *subscip, SCIP_VAR **vars)
enum ConsType CONSTYPE
Definition: cons_samediff.h:40