Scippy

SCIP

Solving Constraint Integer Programs

cons_knapsack.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-2023 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_knapsack.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28  * @author Tobias Achterberg
29  * @author Xin Liu
30  * @author Kati Wolter
31  * @author Michael Winkler
32  * @author Tobias Fischer
33  */
34 
35 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36 
37 #include "blockmemshell/memory.h"
38 #include "scip/cons_knapsack.h"
39 #include "scip/cons_linear.h"
40 #include "scip/cons_logicor.h"
41 #include "scip/cons_setppc.h"
42 #include "scip/pub_cons.h"
43 #include "scip/pub_event.h"
44 #include "scip/pub_implics.h"
45 #include "scip/pub_lp.h"
46 #include "scip/pub_message.h"
47 #include "scip/pub_misc.h"
48 #include "scip/pub_misc_select.h"
49 #include "scip/pub_misc_sort.h"
50 #include "scip/pub_sepa.h"
51 #include "scip/pub_var.h"
52 #include "scip/scip_branch.h"
53 #include "scip/scip_conflict.h"
54 #include "scip/scip_cons.h"
55 #include "scip/scip_copy.h"
56 #include "scip/scip_cut.h"
57 #include "scip/scip_event.h"
58 #include "scip/scip_general.h"
59 #include "scip/scip_lp.h"
60 #include "scip/scip_mem.h"
61 #include "scip/scip_message.h"
62 #include "scip/scip_nlp.h"
63 #include "scip/scip_numerics.h"
64 #include "scip/scip_param.h"
65 #include "scip/scip_prob.h"
66 #include "scip/scip_probing.h"
67 #include "scip/scip_sol.h"
68 #include "scip/scip_solvingstats.h"
69 #include "scip/scip_tree.h"
70 #include "scip/scip_var.h"
71 #ifdef WITH_CARDINALITY_UPGRADE
72 #include "scip/cons_cardinality.h"
73 #endif
74 
75 /* constraint handler properties */
76 #define CONSHDLR_NAME "knapsack"
77 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
78 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
79 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
80 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
81 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
82 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
83 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
84  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
85 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
86 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
87 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
88 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
89 
90 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
91 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
92 
93 #define EVENTHDLR_NAME "knapsack"
94 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
95 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
96  | SCIP_EVENTTYPE_UBTIGHTENED \
97  | SCIP_EVENTTYPE_VARFIXED \
98  | SCIP_EVENTTYPE_VARDELETED \
99  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
100 
101 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
103 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
104 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
106 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
107 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
108 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
110 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
111 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
112 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
113 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
114 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
115 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
116  * to best node's dual bound for separating knapsack cuts */
117 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
118 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
119 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
121 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
122 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
124 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
125 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
127 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
128 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
129 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
130  * comparison round */
131 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
132 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
133  * function defining an upper bound and prevent these constraints from
134  * entering the LP */
135 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
136  * function defining a lower bound and prevent these constraints from
137  * entering the LP */
138 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
139 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
141 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
142 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
143 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
144 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
145  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
146 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
147 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
148 #ifdef WITH_CARDINALITY_UPGRADE
149 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
150 #endif
152 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
153 
154 /*
155  * Data structures
156  */
157 
158 /** constraint handler data */
159 struct SCIP_ConshdlrData
160 {
161  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
162  * you have to clear it at the end, exists only in presolving stage */
163  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
164  * you have to clear it at the end, exists only in presolving stage */
165  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
166  * you have to clear it at the end, exists only in presolving stage */
167  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
168  * you have to clear it at the end, exists only in presolving stage */
169  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
170  * you have to clear it at the end, exists only in presolving stage */
171  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
172  * you have to clear it at the end, exists only in presolving stage */
173  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
174  * you have to clear it at the end, exists only in presolving stage */
175  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
176  * you have to clear it at the end, exists only in presolving stage */
177  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
178  * you have to clear it at the end */
179  int ints1size; /**< size of ints1 array */
180  int ints2size; /**< size of ints2 array */
181  int longints1size; /**< size of longints1 array */
182  int longints2size; /**< size of longints2 array */
183  int bools1size; /**< size of bools1 array */
184  int bools2size; /**< size of bools2 array */
185  int bools3size; /**< size of bools3 array */
186  int bools4size; /**< size of bools4 array */
187  int reals1size; /**< size of reals1 array */
188  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
189  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
190  * to best node's dual bound for separating knapsack cuts */
191  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
192  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
193  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
194  int maxsepacuts; /**< maximal number of cuts separated per separation round */
195  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
196  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
197  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
198  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
199  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
200  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
201  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
202  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
203  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
204  * function defining an upper bound and prevent these constraints from
205  * entering the LP */
206  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
207  * function defining a lower bound and prevent these constraints from
208  * entering the LP */
209  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
210  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
211  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
212  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
213 #ifdef WITH_CARDINALITY_UPGRADE
214  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
215  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
216 #endif
217 };
218 
219 
220 /** constraint data for knapsack constraints */
221 struct SCIP_ConsData
222 {
223  SCIP_VAR** vars; /**< variables in knapsack constraint */
224  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
225  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
226  int* cliquepartition; /**< clique indices of the clique partition */
227  int* negcliquepartition; /**< clique indices of the negated clique partition */
228  SCIP_ROW* row; /**< corresponding LP row */
229  SCIP_NLROW* nlrow; /**< corresponding NLP row */
230  int nvars; /**< number of variables in knapsack constraint */
231  int varssize; /**< size of vars, weights, and eventdata arrays */
232  int ncliques; /**< number of cliques in the clique partition */
233  int nnegcliques; /**< number of cliques in the negated clique partition */
234  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
235  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
236  SCIP_Longint capacity; /**< capacity of knapsack */
237  SCIP_Longint weightsum; /**< sum of all weights */
238  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
239  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
240  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
241  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
242  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
243  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
244  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
245  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
246  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
247 };
248 
249 /** event data for bound changes events */
250 struct SCIP_EventData
251 {
252  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
253  SCIP_Longint weight; /**< weight of variable */
254  int filterpos; /**< position of event in variable's event filter */
255 };
256 
257 
258 /** data structure to combine two sorting key values */
259 struct sortkeypair
260 {
261  SCIP_Real key1; /**< first sort key value */
262  SCIP_Real key2; /**< second sort key value */
263 };
264 typedef struct sortkeypair SORTKEYPAIR;
265 
266 /** status of GUB constraint */
267 enum GUBVarstatus
268 {
269  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
270  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
271  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
272  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
273  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
274  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
275 };
276 typedef enum GUBVarstatus GUBVARSTATUS;
278 /** status of variable in GUB constraint */
280 {
281  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
282  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
283  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
284  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
285  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
286  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
287 };
288 typedef enum GUBConsstatus GUBCONSSTATUS;
290 /** data structure of GUB constraints */
292 {
293  int* gubvars; /**< indices of GUB variables in knapsack constraint */
294  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
295  int ngubvars; /**< number of GUB variables */
296  int gubvarssize; /**< size of gubvars array */
297 };
298 typedef struct SCIP_GUBCons SCIP_GUBCONS;
300 /** data structure of a set of GUB constraints */
302 {
303  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
304  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
305  int ngubconss; /**< number of GUB constraints */
306  int nvars; /**< number of variables in knapsack constraint */
307  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
308  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
309 };
310 typedef struct SCIP_GUBSet SCIP_GUBSET;
312 /*
313  * Local methods
314  */
316 /** comparison method for two sorting key pairs */
317 static
318 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
319 {
320  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
321  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
322 
323  if( sortkeypair1->key1 < sortkeypair2->key1 )
324  return -1;
325  else if( sortkeypair1->key1 > sortkeypair2->key1 )
326  return +1;
327  else if( sortkeypair1->key2 < sortkeypair2->key2 )
328  return -1;
329  else if( sortkeypair1->key2 > sortkeypair2->key2 )
330  return +1;
331  else
332  return 0;
333 }
334 
335 /** creates event data */
336 static
338  SCIP* scip, /**< SCIP data structure */
339  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
340  SCIP_CONS* cons, /**< constraint */
341  SCIP_Longint weight /**< weight of variable */
342  )
343 {
344  assert(eventdata != NULL);
346  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
347  (*eventdata)->cons = cons;
348  (*eventdata)->weight = weight;
349 
350  return SCIP_OKAY;
351 }
352 
353 /** frees event data */
354 static
356  SCIP* scip, /**< SCIP data structure */
357  SCIP_EVENTDATA** eventdata /**< pointer to event data */
358  )
359 {
360  assert(eventdata != NULL);
361 
362  SCIPfreeBlockMemory(scip, eventdata);
364  return SCIP_OKAY;
365 }
366 
367 /** sorts items in knapsack with nonincreasing weights */
368 static
369 void sortItems(
370  SCIP_CONSDATA* consdata /**< constraint data */
371  )
372 {
373  assert(consdata != NULL);
374  assert(consdata->nvars == 0 || consdata->vars != NULL);
375  assert(consdata->nvars == 0 || consdata->weights != NULL);
376  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
377  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
378 
379  if( !consdata->sorted )
380  {
381  int pos;
382  int lastcliquenum;
383  int v;
384 
385  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
386  * sorted by first array in non-increasing order via sort template */
388  consdata->weights,
389  (void**)consdata->vars,
390  (void**)consdata->eventdata,
391  consdata->cliquepartition,
392  consdata->negcliquepartition,
393  consdata->nvars);
394 
395  v = consdata->nvars - 1;
396  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
397  while( v >= 0 )
398  {
399  int w = v - 1;
400 
401  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
402  --w;
403 
404  if( v - w > 1 )
405  {
406  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
408  (void**)(&(consdata->vars[w+1])),
409  (void**)(&(consdata->eventdata[w+1])),
410  &(consdata->cliquepartition[w+1]),
411  &(consdata->negcliquepartition[w+1]),
412  SCIPvarComp,
413  v - w);
414  }
415  v = w;
416  }
417 
418  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
419  if( consdata->cliquepartitioned )
420  {
421  lastcliquenum = 0;
422 
423  for( pos = 0; pos < consdata->nvars; ++pos )
424  {
425  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
426  * partition is invalid */
427  if( consdata->cliquepartition[pos] > lastcliquenum )
428  {
429  consdata->cliquepartitioned = FALSE;
430  break;
431  }
432  else if( consdata->cliquepartition[pos] == lastcliquenum )
433  ++lastcliquenum;
434  }
435  }
436  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
437  if( consdata->negcliquepartitioned )
438  {
439  lastcliquenum = 0;
440 
441  for( pos = 0; pos < consdata->nvars; ++pos )
442  {
443  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
444  * partition is invalid */
445  if( consdata->negcliquepartition[pos] > lastcliquenum )
446  {
447  consdata->negcliquepartitioned = FALSE;
448  break;
449  }
450  else if( consdata->negcliquepartition[pos] == lastcliquenum )
451  ++lastcliquenum;
452  }
453  }
454 
455  consdata->sorted = TRUE;
456  }
457 #ifndef NDEBUG
458  {
459  /* check if the weight array is sorted in a non-increasing way */
460  int i;
461  for( i = 0; i < consdata->nvars-1; ++i )
462  assert(consdata->weights[i] >= consdata->weights[i+1]);
463  }
464 #endif
465 }
466 
467 /** calculates a partition of the variables into cliques */
468 static
470  SCIP* scip, /**< SCIP data structure */
471  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
472  SCIP_CONSDATA* consdata, /**< constraint data */
473  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
474  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
475  )
476 {
477  SCIP_Bool ispartitionoutdated;
478  SCIP_Bool isnegpartitionoutdated;
479  assert(consdata != NULL);
480  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
481 
482  /* rerun eventually if number of global cliques increased considerably since last partition */
483  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
484  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
485 
486  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
487  {
488  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
489  consdata->cliquepartitioned = TRUE;
490  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
491  }
492 
493  /* rerun eventually if number of global cliques increased considerably since last negated partition */
494  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
495  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
496 
497  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
498  {
499  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
500  consdata->negcliquepartitioned = TRUE;
501  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
502  }
503  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
504  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
505 
506  return SCIP_OKAY;
507 }
508 
509 /** installs rounding locks for the given variable in the given knapsack constraint */
510 static
512  SCIP* scip, /**< SCIP data structure */
513  SCIP_CONS* cons, /**< knapsack constraint */
514  SCIP_VAR* var /**< variable of constraint entry */
515  )
516 {
517  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
518 
519  return SCIP_OKAY;
520 }
521 
522 /** removes rounding locks for the given variable in the given knapsack constraint */
523 static
525  SCIP* scip, /**< SCIP data structure */
526  SCIP_CONS* cons, /**< knapsack constraint */
527  SCIP_VAR* var /**< variable of constraint entry */
528  )
529 {
530  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
531 
532  return SCIP_OKAY;
533 }
534 
535 /** catches bound change events for variables in knapsack */
536 static
538  SCIP* scip, /**< SCIP data structure */
539  SCIP_CONS* cons, /**< constraint */
540  SCIP_CONSDATA* consdata, /**< constraint data */
541  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
542  )
543 {
544  int i;
546  assert(cons != NULL);
547  assert(consdata != NULL);
548  assert(consdata->nvars == 0 || consdata->vars != NULL);
549  assert(consdata->nvars == 0 || consdata->weights != NULL);
550  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
551 
552  for( i = 0; i < consdata->nvars; i++)
553  {
554  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
555  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
556  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
557  }
558 
559  return SCIP_OKAY;
560 }
561 
562 /** drops bound change events for variables in knapsack */
563 static
565  SCIP* scip, /**< SCIP data structure */
566  SCIP_CONSDATA* consdata, /**< constraint data */
567  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
568  )
569 {
570  int i;
571 
572  assert(consdata != NULL);
573  assert(consdata->nvars == 0 || consdata->vars != NULL);
574  assert(consdata->nvars == 0 || consdata->weights != NULL);
575  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
576 
577  for( i = 0; i < consdata->nvars; i++)
578  {
579  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
580  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
581  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
582  }
583 
584  return SCIP_OKAY;
585 }
586 
587 /** ensures, that vars and vals arrays can store at least num entries */
588 static
590  SCIP* scip, /**< SCIP data structure */
591  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
592  int num, /**< minimum number of entries to store */
593  SCIP_Bool transformed /**< is constraint from transformed problem? */
594  )
595 {
596  assert(consdata != NULL);
597  assert(consdata->nvars <= consdata->varssize);
598 
599  if( num > consdata->varssize )
600  {
601  int newsize;
602 
603  newsize = SCIPcalcMemGrowSize(scip, num);
604  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
605  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
606  if( transformed )
607  {
608  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
609  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
610  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
611  }
612  else
613  {
614  assert(consdata->eventdata == NULL);
615  assert(consdata->cliquepartition == NULL);
616  assert(consdata->negcliquepartition == NULL);
617  }
618  consdata->varssize = newsize;
619  }
620  assert(num <= consdata->varssize);
621 
622  return SCIP_OKAY;
623 }
624 
625 /** updates all weight sums for fixed and unfixed variables */
626 static
627 void updateWeightSums(
628  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
629  SCIP_VAR* var, /**< variable for this weight */
630  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
631  )
632 {
633  assert(consdata != NULL);
634  assert(var != NULL);
636  consdata->weightsum += weightdelta;
637 
638  if( SCIPvarGetLbLocal(var) > 0.5 )
639  consdata->onesweightsum += weightdelta;
640 
641  assert(consdata->weightsum >= 0);
642  assert(consdata->onesweightsum >= 0);
643 }
644 
645 /** creates knapsack constraint data */
646 static
648  SCIP* scip, /**< SCIP data structure */
649  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
650  int nvars, /**< number of variables in knapsack */
651  SCIP_VAR** vars, /**< variables of knapsack */
652  SCIP_Longint* weights, /**< weights of knapsack items */
653  SCIP_Longint capacity /**< capacity of knapsack */
654  )
655 {
656  int v;
657  SCIP_Longint constant;
658 
659  assert(consdata != NULL);
660 
661  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
662 
663  constant = 0L;
664  (*consdata)->vars = NULL;
665  (*consdata)->weights = NULL;
666  (*consdata)->nvars = 0;
667  if( nvars > 0 )
668  {
669  SCIP_VAR** varsbuffer;
670  SCIP_Longint* weightsbuffer;
671  int k;
672 
673  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
674  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
675 
676  k = 0;
677  for( v = 0; v < nvars; ++v )
678  {
679  assert(vars[v] != NULL);
680  assert(SCIPvarIsBinary(vars[v]));
681 
682  /* all weight have to be non negative */
683  assert( weights[v] >= 0 );
684 
685  if( weights[v] > 0 )
686  {
687  /* treat fixed variables as constants if problem compression is enabled */
688  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
689  {
690  /* only if the variable is fixed to 1, we add its weight to the constant */
691  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
692  constant += weights[v];
693  }
694  else
695  {
696  varsbuffer[k] = vars[v];
697  weightsbuffer[k] = weights[v];
698  ++k;
699  }
700  }
701  }
702  assert(k >= 0);
703  assert(constant >= 0);
704 
705  (*consdata)->nvars = k;
706 
707  /* copy the active variables and weights into the constraint data structure */
708  if( k > 0 )
709  {
710  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
711  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
712  }
713 
714  /* free buffer storage */
715  SCIPfreeBufferArray(scip, &weightsbuffer);
716  SCIPfreeBufferArray(scip, &varsbuffer);
717  }
718 
719  (*consdata)->varssize = (*consdata)->nvars;
720  (*consdata)->capacity = capacity - constant;
721  (*consdata)->eventdata = NULL;
722  (*consdata)->cliquepartition = NULL;
723  (*consdata)->negcliquepartition = NULL;
724  (*consdata)->row = NULL;
725  (*consdata)->nlrow = NULL;
726  (*consdata)->weightsum = 0;
727  (*consdata)->onesweightsum = 0;
728  (*consdata)->ncliques = 0;
729  (*consdata)->nnegcliques = 0;
730  (*consdata)->presolvedtiming = 0;
731  (*consdata)->sorted = FALSE;
732  (*consdata)->cliquepartitioned = FALSE;
733  (*consdata)->negcliquepartitioned = FALSE;
734  (*consdata)->ncliqueslastpart = -1;
735  (*consdata)->ncliqueslastnegpart = -1;
736  (*consdata)->merged = FALSE;
737  (*consdata)->cliquesadded = FALSE;
738  (*consdata)->varsdeleted = FALSE;
739  (*consdata)->existmultaggr = FALSE;
740 
741  /* get transformed variables, if we are in the transformed problem */
742  if( SCIPisTransformed(scip) )
743  {
744  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
745 
746  for( v = 0; v < (*consdata)->nvars; v++ )
747  {
748  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
749  assert(var != NULL);
750  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
751  }
752 
753  /* allocate memory for additional data structures */
754  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
755  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
756  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
757  }
758 
759  /* calculate sum of weights and capture variables */
760  for( v = 0; v < (*consdata)->nvars; ++v )
761  {
762  /* calculate sum of weights */
763  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
764 
765  /* capture variables */
766  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
767  }
768  return SCIP_OKAY;
769 }
770 
771 /** frees knapsack constraint data */
772 static
774  SCIP* scip, /**< SCIP data structure */
775  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
776  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
777  )
778 {
779  assert(consdata != NULL);
780  assert(*consdata != NULL);
782  if( (*consdata)->row != NULL )
783  {
784  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
785  }
786  if( (*consdata)->nlrow != NULL )
787  {
788  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
789  }
790  if( (*consdata)->eventdata != NULL )
791  {
792  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
793  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
794  }
795  if( (*consdata)->negcliquepartition != NULL )
796  {
797  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
798  }
799  if( (*consdata)->cliquepartition != NULL )
800  {
801  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
802  }
803  if( (*consdata)->vars != NULL )
804  {
805  int v;
806 
807  /* release variables */
808  for( v = 0; v < (*consdata)->nvars; v++ )
809  {
810  assert((*consdata)->vars[v] != NULL);
811  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
812  }
813 
814  assert( (*consdata)->weights != NULL );
815  assert( (*consdata)->varssize > 0 );
816  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
817  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
818  }
819 
820  SCIPfreeBlockMemory(scip, consdata);
821 
822  return SCIP_OKAY;
823 }
824 
825 /** changes a single weight in knapsack constraint data */
826 static
827 void consdataChgWeight(
828  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
829  int item, /**< item number */
830  SCIP_Longint newweight /**< new weight of item */
831  )
832 {
833  SCIP_Longint oldweight;
834  SCIP_Longint weightdiff;
836  assert(consdata != NULL);
837  assert(0 <= item && item < consdata->nvars);
838 
839  oldweight = consdata->weights[item];
840  weightdiff = newweight - oldweight;
841  consdata->weights[item] = newweight;
842 
843  /* update weight sums for all and fixed variables */
844  updateWeightSums(consdata, consdata->vars[item], weightdiff);
845 
846  if( consdata->eventdata != NULL )
847  {
848  assert(consdata->eventdata[item] != NULL);
849  assert(consdata->eventdata[item]->weight == oldweight);
850  consdata->eventdata[item]->weight = newweight;
851  }
852 
853  consdata->presolvedtiming = 0;
854  consdata->sorted = FALSE;
855 
856  /* recalculate cliques extraction after a weight was increased */
857  if( oldweight < newweight )
858  {
859  consdata->cliquesadded = FALSE;
860  }
861 }
862 
863 /** creates LP row corresponding to knapsack constraint */
864 static
866  SCIP* scip, /**< SCIP data structure */
867  SCIP_CONS* cons /**< knapsack constraint */
868  )
869 {
870  SCIP_CONSDATA* consdata;
871  int i;
872 
873  consdata = SCIPconsGetData(cons);
874  assert(consdata != NULL);
875  assert(consdata->row == NULL);
876 
877  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
878  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
880 
881  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
882  for( i = 0; i < consdata->nvars; ++i )
883  {
884  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
885  }
886  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
887 
888  return SCIP_OKAY;
889 }
890 
891 /** adds linear relaxation of knapsack constraint to the LP */
892 static
894  SCIP* scip, /**< SCIP data structure */
895  SCIP_CONS* cons, /**< knapsack constraint */
896  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
897  )
898 {
899  SCIP_CONSDATA* consdata;
900 
901  assert( cutoff != NULL );
902  *cutoff = FALSE;
903 
904  consdata = SCIPconsGetData(cons);
905  assert(consdata != NULL);
906 
907  if( consdata->row == NULL )
908  {
909  SCIP_CALL( createRelaxation(scip, cons) );
910  }
911  assert(consdata->row != NULL);
912 
913  /* insert LP row as cut */
914  if( !SCIProwIsInLP(consdata->row) )
915  {
916  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
917  SCIPconsGetName(cons), consdata->capacity);
918  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
919  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
920  }
921 
922  return SCIP_OKAY;
923 }
924 
925 /** adds knapsack constraint as row to the NLP, if not added yet */
926 static
928  SCIP* scip, /**< SCIP data structure */
929  SCIP_CONS* cons /**< knapsack constraint */
930  )
931 {
932  SCIP_CONSDATA* consdata;
933 
934  assert(SCIPisNLPConstructed(scip));
936  /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
937  if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
938  return SCIP_OKAY;
939 
940  consdata = SCIPconsGetData(cons);
941  assert(consdata != NULL);
942 
943  if( consdata->nlrow == NULL )
944  {
945  SCIP_Real* coefs;
946  int i;
947 
948  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
949  for( i = 0; i < consdata->nvars; ++i )
950  coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
951 
952  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
953  consdata->nvars, consdata->vars, coefs, NULL,
954  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
955 
956  assert(consdata->nlrow != NULL);
957 
958  SCIPfreeBufferArray(scip, &coefs);
959  }
960 
961  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
962  {
963  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
964  }
965 
966  return SCIP_OKAY;
967 }
968 
969 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
970 static
972  SCIP* scip, /**< SCIP data structure */
973  SCIP_CONS* cons, /**< constraint to check */
974  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
975  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
976  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
977  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
978  )
979 {
980  SCIP_CONSDATA* consdata;
981 
982  assert(violated != NULL);
983 
984  consdata = SCIPconsGetData(cons);
985  assert(consdata != NULL);
986 
987  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
988  SCIPconsGetName(cons), (void*)sol, checklprows);
989 
990  *violated = FALSE;
991 
992  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
993  {
994  SCIP_Real sum;
995  SCIP_Longint integralsum;
996  SCIP_Bool ishuge;
997  SCIP_Real absviol;
998  SCIP_Real relviol;
999  int v;
1000 
1001  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1002  * enforcement
1003  */
1004  if( sol == NULL )
1005  {
1006  SCIP_CALL( SCIPincConsAge(scip, cons) );
1007  }
1008 
1009  sum = 0.0;
1010  integralsum = 0;
1011  /* we perform a more exact comparison if the capacity does not exceed the huge value */
1012  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1013  {
1014  ishuge = TRUE;
1015 
1016  /* sum over all weight times the corresponding solution value */
1017  for( v = consdata->nvars - 1; v >= 0; --v )
1018  {
1019  assert(SCIPvarIsBinary(consdata->vars[v]));
1020  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1021  }
1022  }
1023  else
1024  {
1025  ishuge = FALSE;
1026 
1027  /* sum over all weight for which the variable has a solution value of 1 in feastol */
1028  for( v = consdata->nvars - 1; v >= 0; --v )
1029  {
1030  assert(SCIPvarIsBinary(consdata->vars[v]));
1031 
1032  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1033  integralsum += consdata->weights[v];
1034  }
1035  }
1036 
1037  /* calculate constraint violation and update it in solution */
1038  absviol = ishuge ? sum : (SCIP_Real)integralsum;
1039  absviol -= consdata->capacity;
1040  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1041  if( sol != NULL )
1042  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1043 
1044  if( SCIPisFeasPositive(scip, absviol) )
1045  {
1046  *violated = TRUE;
1047 
1048  /* only reset constraint age if we are in enforcement */
1049  if( sol == NULL )
1050  {
1051  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1052  }
1053 
1054  if( printreason )
1055  {
1056  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1057 
1058  SCIPinfoMessage(scip, NULL, ";\n");
1059  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1060  }
1061  }
1062  }
1063 
1064  return SCIP_OKAY;
1065 }
1066 
1067 /* IDX computes the integer index for the optimal solution array */
1068 #define IDX(j,d) ((j)*(intcap)+(d))
1069 
1070 /** solves knapsack problem in maximization form exactly using dynamic programming;
1071  * if needed, one can provide arrays to store all selected items and all not selected items
1072  *
1073  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1074  *
1075  * @note the algorithm will first compute a greedy solution and terminate
1076  * if the greedy solution is proven to be optimal.
1077  * The dynamic programming algorithm runs with a time and space complexity
1078  * of O(nitems * capacity).
1079  *
1080  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1081  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1082  * to be checked whether they are faster and whether they can reconstruct the solution.
1083  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1084  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1085  * This could be implemented, however, it would be technically a bit cumbersome,
1086  * since one needs the greedy solution and the LP-value for this.
1087  * This is currently only available after the redundant items have already been sorted out.
1088  */
1090  SCIP* scip, /**< SCIP data structure */
1091  int nitems, /**< number of available items */
1092  SCIP_Longint* weights, /**< item weights */
1093  SCIP_Real* profits, /**< item profits */
1094  SCIP_Longint capacity, /**< capacity of knapsack */
1095  int* items, /**< item numbers */
1096  int* solitems, /**< array to store items in solution, or NULL */
1097  int* nonsolitems, /**< array to store items not in solution, or NULL */
1098  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1099  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1100  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1101  SCIP_Bool* success /**< pointer to store if an error occured during solving
1102  * (normally a memory problem) */
1103  )
1104 {
1105  SCIP_RETCODE retcode;
1106  SCIP_Real* tempsort;
1107  SCIP_Real* optvalues;
1108  int intcap;
1109  int d;
1110  int j;
1111  int greedymedianpos;
1112  SCIP_Longint weightsum;
1113  int* myitems;
1114  SCIP_Longint* myweights;
1115  SCIP_Real* realweights;
1116  int* allcurrminweight;
1117  SCIP_Real* myprofits;
1118  int nmyitems;
1119  SCIP_Longint gcd;
1120  SCIP_Longint minweight;
1121  SCIP_Longint maxweight;
1122  int currminweight;
1123  SCIP_Longint greedysolweight;
1124  SCIP_Real greedysolvalue;
1125  SCIP_Real greedyupperbound;
1126  SCIP_Bool eqweights;
1127  SCIP_Bool intprofits;
1128 
1129  assert(weights != NULL);
1130  assert(profits != NULL);
1131  assert(capacity >= 0);
1132  assert(items != NULL);
1133  assert(nitems >= 0);
1134  assert(success != NULL);
1135 
1136  *success = TRUE;
1137 
1138 #ifndef NDEBUG
1139  for( j = nitems - 1; j >= 0; --j )
1140  assert(weights[j] >= 0);
1141 #endif
1142 
1143  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1144 
1145  /* initializing solution value */
1146  if( solval != NULL )
1147  *solval = 0.0;
1148 
1149  /* init solution information */
1150  if( solitems != NULL )
1151  {
1152  assert(items != NULL);
1153  assert(nsolitems != NULL);
1154  assert(nonsolitems != NULL);
1155  assert(nnonsolitems != NULL);
1156 
1157  *nnonsolitems = 0;
1158  *nsolitems = 0;
1159  }
1160 
1161  /* allocate temporary memory */
1162  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1163  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1164  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1165  nmyitems = 0;
1166  weightsum = 0;
1167  minweight = SCIP_LONGINT_MAX;
1168  maxweight = 0;
1169 
1170  /* remove unnecessary items */
1171  for( j = 0; j < nitems; ++j )
1172  {
1173  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1174 
1175  /* item does not fit */
1176  if( weights[j] > capacity )
1177  {
1178  if( solitems != NULL )
1179  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1180  }
1181  /* item is not profitable */
1182  else if( profits[j] <= 0.0 )
1183  {
1184  if( solitems != NULL )
1185  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1186  }
1187  /* item always fits */
1188  else if( weights[j] == 0 )
1189  {
1190  if( solitems != NULL )
1191  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1192 
1193  if( solval != NULL )
1194  *solval += profits[j];
1195  }
1196  /* all important items */
1197  else
1198  {
1199  myweights[nmyitems] = weights[j];
1200  myprofits[nmyitems] = profits[j];
1201  myitems[nmyitems] = items[j];
1202 
1203  /* remember smallest item */
1204  if( myweights[nmyitems] < minweight )
1205  minweight = myweights[nmyitems];
1206 
1207  /* remember bigest item */
1208  if( myweights[nmyitems] > maxweight )
1209  maxweight = myweights[nmyitems];
1210 
1211  weightsum += myweights[nmyitems];
1212  ++nmyitems;
1213  }
1214  }
1215 
1216  intprofits = TRUE;
1217  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1218  for( j = 0; j < nmyitems && intprofits; ++j )
1219  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1220 
1221  /* if no item is left then goto end */
1222  if( nmyitems == 0 )
1223  {
1224  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1225 
1226  goto TERMINATE;
1227  }
1228 
1229  /* if all items fit, we also do not need to do the expensive stuff later on */
1230  if( weightsum > 0 && weightsum <= capacity )
1231  {
1232  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1233 
1234  for( j = nmyitems - 1; j >= 0; --j )
1235  {
1236  if( solitems != NULL )
1237  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1238 
1239  if( solval != NULL )
1240  *solval += myprofits[j];
1241  }
1242 
1243  goto TERMINATE;
1244  }
1245 
1246  assert(0 < minweight && minweight <= capacity );
1247  assert(0 < maxweight && maxweight <= capacity);
1248 
1249  /* make weights relatively prime */
1250  eqweights = TRUE;
1251  if( maxweight > 1 )
1252  {
1253  /* determine greatest common divisor */
1254  gcd = myweights[nmyitems - 1];
1255  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1256  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1257 
1258  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1259 
1260  /* divide by greatest common divisor */
1261  if( gcd > 1 )
1262  {
1263  for( j = nmyitems - 1; j >= 0; --j )
1264  {
1265  myweights[j] /= gcd;
1266  eqweights = eqweights && (myweights[j] == 1);
1267  }
1268  capacity /= gcd;
1269  minweight /= gcd;
1270  }
1271  else
1272  eqweights = FALSE;
1273  }
1274  assert(minweight <= capacity);
1275 
1276  /* if only one item fits, then take the best */
1277  if( minweight > capacity / 2 )
1278  {
1279  int p;
1280 
1281  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1282 
1283  p = nmyitems - 1;
1284 
1285  /* find best item */
1286  for( j = nmyitems - 2; j >= 0; --j )
1287  {
1288  if( myprofits[j] > myprofits[p] )
1289  p = j;
1290  }
1291 
1292  /* update solution information */
1293  if( solitems != NULL )
1294  {
1295  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1296 
1297  solitems[(*nsolitems)++] = myitems[p];
1298  for( j = nmyitems - 1; j >= 0; --j )
1299  {
1300  if( j != p )
1301  nonsolitems[(*nnonsolitems)++] = myitems[j];
1302  }
1303  }
1304  /* update solution value */
1305  if( solval != NULL )
1306  *solval += myprofits[p];
1307 
1308  goto TERMINATE;
1309  }
1310 
1311  /* if all items have the same weight, then take the best */
1312  if( eqweights )
1313  {
1314  SCIP_Real addval = 0.0;
1315 
1316  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1317 
1318  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1319 
1320  /* update solution information */
1321  if( solitems != NULL || solval != NULL )
1322  {
1323  SCIP_Longint i;
1324 
1325  /* if all items would fit we had handled this case before */
1326  assert((SCIP_Longint) nmyitems > capacity);
1327  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1328 
1329  /* take the first best items into the solution */
1330  for( i = capacity - 1; i >= 0; --i )
1331  {
1332  if( solitems != NULL )
1333  solitems[(*nsolitems)++] = myitems[i];
1334  addval += myprofits[i];
1335  }
1336 
1337  if( solitems != NULL )
1338  {
1339  /* the rest are not in the solution */
1340  for( i = nmyitems - 1; i >= capacity; --i )
1341  nonsolitems[(*nnonsolitems)++] = myitems[i];
1342  }
1343  }
1344  /* update solution value */
1345  if( solval != NULL )
1346  {
1347  assert(addval > 0.0);
1348  *solval += addval;
1349  }
1350 
1351  goto TERMINATE;
1352  }
1353 
1354  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1355 
1356  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1357  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1358  */
1359  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1360  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1361 
1362  for( j = 0; j < nmyitems; ++j )
1363  {
1364  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1365  realweights[j] = (SCIP_Real)myweights[j];
1366  }
1367 
1368  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1369  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1370 
1371  SCIPfreeBufferArray(scip, &realweights);
1372  SCIPfreeBufferArray(scip, &tempsort);
1373 
1374  /* initialize values for greedy solution information */
1375  greedysolweight = 0;
1376  greedysolvalue = 0.0;
1377 
1378  /* determine greedy solution */
1379  for( j = 0; j < greedymedianpos; ++j )
1380  {
1381  assert(myweights[j] <= capacity);
1382 
1383  /* update greedy solution weight and value */
1384  greedysolweight += myweights[j];
1385  greedysolvalue += myprofits[j];
1386  }
1387 
1388  assert(0 < greedysolweight && greedysolweight <= capacity);
1389  assert(greedysolvalue > 0.0);
1390 
1391  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1392  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1393  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1394  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1395  if( intprofits )
1396  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1397  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1398  {
1399  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1400 
1401  /* update solution information */
1402  if( solitems != NULL )
1403  {
1404  int l;
1405 
1406  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1407 
1408  /* collect items */
1409  for( l = 0; l < j; ++l )
1410  solitems[(*nsolitems)++] = myitems[l];
1411  for ( ; l < nmyitems; ++l )
1412  nonsolitems[(*nnonsolitems)++] = myitems[l];
1413  }
1414  /* update solution value */
1415  if( solval != NULL )
1416  {
1417  assert(greedysolvalue > 0.0);
1418  *solval += greedysolvalue;
1419  }
1420 
1421  goto TERMINATE;
1422  }
1423 
1424  /* in the following table we do not need the first minweight columns */
1425  capacity -= (minweight - 1);
1426 
1427  /* we can only handle integers */
1428  if( capacity >= INT_MAX )
1429  {
1430  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1431 
1432  *success = FALSE;
1433  goto TERMINATE;
1434  }
1435  assert(capacity < INT_MAX);
1436 
1437  intcap = (int)capacity;
1438  assert(intcap >= 0);
1439  assert(nmyitems > 0);
1440  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1441 
1442  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1443  * computing the size for the allocation
1444  */
1445  if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1446  {
1447  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1448 
1449  *success = FALSE;
1450  goto TERMINATE;
1451  }
1452 
1453  /* allocate temporary memory and check for memory exceedance */
1454  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1455  if( retcode == SCIP_NOMEMORY )
1456  {
1457  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1458 
1459  *success = FALSE;
1460  goto TERMINATE;
1461  }
1462  else
1463  {
1464  SCIP_CALL( retcode );
1465  }
1466 
1467  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1468 
1469  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1470  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1471  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1472  * 'nmyitem' values
1473  */
1474  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1475  assert(myweights[0] - minweight < INT_MAX);
1476  currminweight = (int) (myweights[0] - minweight);
1477  allcurrminweight[0] = currminweight;
1478 
1479  /* fills first row of dynamic programming table with optimal values */
1480  for( d = currminweight; d < intcap; ++d )
1481  optvalues[d] = myprofits[0];
1482 
1483  /* fills dynamic programming table with optimal values */
1484  for( j = 1; j < nmyitems; ++j )
1485  {
1486  int intweight;
1487 
1488  /* compute important part of weight, which will be represented in the table */
1489  intweight = (int)(myweights[j] - minweight);
1490  assert(0 <= intweight && intweight < intcap);
1491 
1492  /* copy all nonzeros from row above */
1493  for( d = currminweight; d < intweight && d < intcap; ++d )
1494  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1495 
1496  /* update corresponding row */
1497  for( d = intweight; d < intcap; ++d )
1498  {
1499  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1500  if( d < currminweight )
1501  optvalues[IDX(j,d)] = myprofits[j];
1502  else
1503  {
1504  SCIP_Real sumprofit;
1505 
1506  if( d - myweights[j] < currminweight )
1507  sumprofit = myprofits[j];
1508  else
1509  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1510 
1511  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1512  }
1513  }
1514 
1515  /* update currminweight */
1516  if( intweight < currminweight )
1517  currminweight = intweight;
1518 
1519  allcurrminweight[j] = currminweight;
1520  }
1521 
1522  /* update optimal solution by following the table */
1523  if( solitems != NULL )
1524  {
1525  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1526  d = intcap - 1;
1527 
1528  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1529 
1530  /* insert all items in (non-) solution vector */
1531  for( j = nmyitems - 1; j > 0; --j )
1532  {
1533  /* if the following condition holds this means all remaining items does not fit anymore */
1534  if( d < allcurrminweight[j] )
1535  {
1536  /* we cannot have exceeded our capacity */
1537  assert((SCIP_Longint) d >= -minweight);
1538  break;
1539  }
1540 
1541  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1542  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1543  {
1544  solitems[(*nsolitems)++] = myitems[j];
1545 
1546  /* check that we do not have an underflow */
1547  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1548  d = (int)(d - myweights[j]);
1549  }
1550  /* collect non-solution items */
1551  else
1552  nonsolitems[(*nnonsolitems)++] = myitems[j];
1553  }
1554 
1555  /* insert remaining items */
1556  if( d >= allcurrminweight[j] )
1557  {
1558  assert(j == 0);
1559  solitems[(*nsolitems)++] = myitems[j];
1560  }
1561  else
1562  {
1563  assert(j >= 0);
1564  assert(d < allcurrminweight[j]);
1565 
1566  for( ; j >= 0; --j )
1567  nonsolitems[(*nnonsolitems)++] = myitems[j];
1568  }
1569 
1570  assert(*nsolitems + *nnonsolitems == nitems);
1571  }
1572 
1573  /* update solution value */
1574  if( solval != NULL )
1575  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1576  SCIPfreeBufferArray(scip, &allcurrminweight);
1577 
1578  /* free all temporary memory */
1579  SCIPfreeBufferArray(scip, &optvalues);
1580 
1581  TERMINATE:
1582  SCIPfreeBufferArray(scip, &myitems);
1583  SCIPfreeBufferArray(scip, &myprofits);
1584  SCIPfreeBufferArray(scip, &myweights);
1585 
1586  return SCIP_OKAY;
1587 }
1588 
1589 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1590  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1591  * selected items
1592  */
1594  SCIP* scip, /**< SCIP data structure */
1595  int nitems, /**< number of available items */
1596  SCIP_Longint* weights, /**< item weights */
1597  SCIP_Real* profits, /**< item profits */
1598  SCIP_Longint capacity, /**< capacity of knapsack */
1599  int* items, /**< item numbers */
1600  int* solitems, /**< array to store items in solution, or NULL */
1601  int* nonsolitems, /**< array to store items not in solution, or NULL */
1602  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1603  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1604  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1605  )
1606 {
1607  SCIP_Real* tempsort;
1608  SCIP_Longint solitemsweight;
1609  SCIP_Real* realweights;
1610  int j;
1611  int criticalindex;
1612 
1613  assert(weights != NULL);
1614  assert(profits != NULL);
1615  assert(capacity >= 0);
1616  assert(items != NULL);
1617  assert(nitems >= 0);
1618 
1619  if( solitems != NULL )
1620  {
1621  *nsolitems = 0;
1622  *nnonsolitems = 0;
1623  }
1624  if( solval != NULL )
1625  *solval = 0.0;
1626 
1627  /* initialize data for median search */
1628  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1629  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1630  for( j = nitems - 1; j >= 0; --j )
1631  {
1632  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1633  realweights[j] = (SCIP_Real)weights[j];
1634  }
1635 
1636  /* partially sort indices such that all elements that are larger than the break item appear first */
1637  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1638 
1639  /* selects items as long as they fit into the knapsack */
1640  solitemsweight = 0;
1641  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1642  {
1643  if( solitems != NULL )
1644  solitems[(*nsolitems)++] = items[j];
1645 
1646  if( solval != NULL )
1647  (*solval) += profits[j];
1648  solitemsweight += weights[j];
1649  }
1650  if ( solitems != NULL )
1651  {
1652  for( ; j < nitems; j++ )
1653  nonsolitems[(*nnonsolitems)++] = items[j];
1654  }
1655 
1656  SCIPfreeBufferArray(scip, &realweights);
1657  SCIPfreeBufferArray(scip, &tempsort);
1658 
1659  return SCIP_OKAY;
1660 }
1661 
1662 #ifdef SCIP_DEBUG
1663 /** prints all nontrivial GUB constraints and their LP solution values */
1664 static
1665 void GUBsetPrint(
1666  SCIP* scip, /**< SCIP data structure */
1667  SCIP_GUBSET* gubset, /**< GUB set data structure */
1668  SCIP_VAR** vars, /**< variables in knapsack constraint */
1669  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1670  )
1671 {
1672  int nnontrivialgubconss;
1673  int c;
1674 
1675  nnontrivialgubconss = 0;
1676 
1677  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1678 
1679  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1680  for( c = 0; c < gubset->ngubconss; c++ )
1681  {
1682  SCIP_Real gubsolval;
1683 
1684  assert(gubset->gubconss[c]->ngubvars >= 0);
1685 
1686  /* nontrivial GUB */
1687  if( gubset->gubconss[c]->ngubvars > 1 )
1688  {
1689  int v;
1690 
1691  gubsolval = 0.0;
1692  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1693 
1694  /* print GUB var */
1695  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1696  {
1697  int currentvar;
1698 
1699  currentvar = gubset->gubconss[c]->gubvars[v];
1700  if( solvals != NULL )
1701  {
1702  gubsolval += solvals[currentvar];
1703  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1704  }
1705  else
1706  {
1707  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1708  }
1709  }
1710 
1711  /* check whether LP solution satisfies the GUB constraint */
1712  if( solvals != NULL )
1713  {
1714  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1715  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1716  }
1717  else
1718  {
1719  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1720  }
1721  nnontrivialgubconss++;
1722  }
1723  }
1724 
1725  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1726 }
1727 #endif
1728 
1729 /** creates an empty GUB constraint */
1730 static
1732  SCIP* scip, /**< SCIP data structure */
1733  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1734  )
1735 {
1736  assert(scip != NULL);
1737  assert(gubcons != NULL);
1738 
1739  /* allocate memory for GUB constraint data structures */
1740  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1741  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1742  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1743  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1744 
1745  (*gubcons)->ngubvars = 0;
1746 
1747  return SCIP_OKAY;
1748 }
1749 
1750 /** frees GUB constraint */
1751 static
1752 void GUBconsFree(
1753  SCIP* scip, /**< SCIP data structure */
1754  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1755  )
1756 {
1757  assert(scip != NULL);
1758  assert(gubcons != NULL);
1759  assert((*gubcons)->gubvars != NULL);
1760  assert((*gubcons)->gubvarsstatus != NULL);
1761 
1762  /* free allocated memory */
1763  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1764  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1765  SCIPfreeBuffer(scip, gubcons);
1766 }
1767 
1768 /** adds variable to given GUB constraint */
1769 static
1771  SCIP* scip, /**< SCIP data structure */
1772  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1773  int var /**< index of given variable in knapsack constraint */
1774  )
1775 {
1776  assert(scip != NULL);
1777  assert(gubcons != NULL);
1778  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1779  assert(gubcons->gubvars != NULL);
1780  assert(gubcons->gubvarsstatus != NULL);
1781  assert(var >= 0);
1782 
1783  /* add variable to GUB constraint */
1784  gubcons->gubvars[gubcons->ngubvars] = var;
1785  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1786  gubcons->ngubvars++;
1787 
1788  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1789  if( gubcons->ngubvars == gubcons->gubvarssize )
1790  {
1791  int newlen;
1792 
1793  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1794  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1795  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1796 
1797  gubcons->gubvarssize = newlen;
1798  }
1799 
1800  return SCIP_OKAY;
1801 }
1802 
1803 /** deletes variable from its current GUB constraint */
1804 static
1806  SCIP* scip, /**< SCIP data structure */
1807  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1808  int var, /**< index of given variable in knapsack constraint */
1809  int gubvarsidx /**< index of the variable in its current GUB constraint */
1810  )
1811 {
1812  assert(scip != NULL);
1813  assert(gubcons != NULL);
1814  assert(var >= 0);
1815  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1816  assert(gubcons->ngubvars >= gubvarsidx+1);
1817  assert(gubcons->gubvars[gubvarsidx] == var);
1818 
1819  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1820  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1821  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1822  gubcons->ngubvars--;
1823 
1824  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1825  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1826  {
1827  int newlen;
1828 
1829  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1830 
1831  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1832  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1833 
1834  gubcons->gubvarssize = newlen;
1835  }
1836 
1837  return SCIP_OKAY;
1838 }
1839 
1840 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1841 static
1843  SCIP* scip, /**< SCIP data structure */
1844  SCIP_GUBSET* gubset, /**< GUB set data structure */
1845  SCIP_VAR** vars, /**< variables in knapsack constraint */
1846  int var, /**< index of given variable in knapsack constraint */
1847  int oldgubcons, /**< index of old GUB constraint of given variable */
1848  int newgubcons /**< index of new GUB constraint of given variable */
1849  )
1851  int oldgubvaridx;
1852  int replacevar;
1853  int j;
1854 
1855  assert(scip != NULL);
1856  assert(gubset != NULL);
1857  assert(var >= 0);
1858  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1859  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1860  assert(oldgubcons != newgubcons);
1861  assert(gubset->gubconssidx[var] == oldgubcons);
1862  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1863  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1864 
1865  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1866 
1867  oldgubvaridx = gubset->gubvarsidx[var];
1868 
1869  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1870  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1871 
1872  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1873  * replacement variable is given by old position of the deleted variable
1874  */
1875  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1876  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1877  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1878 
1879  /* add variable to the end of new GUB constraint */
1880  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1881  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1882 
1883  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1884  gubset->gubconssidx[var] = newgubcons;
1885  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1886 
1887  /* delete old GUB constraint if it became empty */
1888  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1889  {
1890  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1891 #ifdef SCIP_DEBUG
1892  GUBsetPrint(scip, gubset, vars, NULL);
1893 #endif
1894 
1895  /* free old GUB constraint */
1896  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1897 
1898  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1899  if( oldgubcons != gubset->ngubconss-1 )
1900  {
1901  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1902  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1903 
1904  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1905  * replacement GUB is given by old position of the deleted GUB
1906  */
1907  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1908  {
1909  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1910  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1911  }
1912  }
1913 
1914  /* update number of GUB constraints */
1915  gubset->ngubconss--;
1916 
1917  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1918  * (because it was at the end of the GUB constraint array)
1919  */
1920  assert(gubset->gubconssidx[var] == newgubcons
1921  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1922  }
1923 #ifndef NDEBUG
1924  else
1925  assert(gubset->gubconssidx[var] == newgubcons);
1926 #endif
1927 
1928  return SCIP_OKAY;
1929 }
1930 
1931 /** swaps two variables in the same GUB constraint */
1932 static
1933 void GUBsetSwapVars(
1934  SCIP* scip, /**< SCIP data structure */
1935  SCIP_GUBSET* gubset, /**< GUB set data structure */
1936  int var1, /**< first variable to be swapped */
1937  int var2 /**< second variable to be swapped */
1938  )
1939 {
1940  int gubcons;
1941  int var1idx;
1942  GUBVARSTATUS var1status;
1943  int var2idx;
1944  GUBVARSTATUS var2status;
1945 
1946  assert(scip != NULL);
1947  assert(gubset != NULL);
1948 
1949  gubcons = gubset->gubconssidx[var1];
1950  assert(gubcons == gubset->gubconssidx[var2]);
1951 
1952  /* nothing to be done if both variables are the same */
1953  if( var1 == var2 )
1954  return;
1955 
1956  /* swap index and status of variables in GUB constraint */
1957  var1idx = gubset->gubvarsidx[var1];
1958  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1959  var2idx = gubset->gubvarsidx[var2];
1960  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1961 
1962  gubset->gubvarsidx[var1] = var2idx;
1963  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1964  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1965 
1966  gubset->gubvarsidx[var2] = var1idx;
1967  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1968  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1969 }
1970 
1971 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1972 static
1974  SCIP* scip, /**< SCIP data structure */
1975  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1976  int nvars, /**< number of variables in the knapsack constraint */
1977  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1978  SCIP_Longint capacity /**< capacity of knapsack */
1979  )
1980 {
1981  int i;
1982 
1983  assert(scip != NULL);
1984  assert(gubset != NULL);
1985  assert(nvars > 0);
1986  assert(weights != NULL);
1987  assert(capacity >= 0);
1988 
1989  /* allocate memory for GUB set data structures */
1990  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1991  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1992  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1993  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1994  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1995  (*gubset)->ngubconss = nvars;
1996  (*gubset)->nvars = nvars;
1997 
1998  /* initialize the set of GUB constraints */
1999  for( i = 0; i < nvars; i++ )
2000  {
2001  /* assign each variable to a new (trivial) GUB constraint */
2002  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2003  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2004 
2005  /* set status of GUB constraint to initial */
2006  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2007 
2008  (*gubset)->gubconssidx[i] = i;
2009  (*gubset)->gubvarsidx[i] = 0;
2010  assert((*gubset)->gubconss[i]->ngubvars == 1);
2011 
2012  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2013  if( weights[i] > capacity )
2014  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2015  }
2016 
2017  return SCIP_OKAY;
2018 }
2019 
2020 /** frees GUB set data structure */
2021 static
2022 void GUBsetFree(
2023  SCIP* scip, /**< SCIP data structure */
2024  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2025  )
2026 {
2027  int i;
2028 
2029  assert(scip != NULL);
2030  assert(gubset != NULL);
2031  assert((*gubset)->gubconss != NULL);
2032  assert((*gubset)->gubconsstatus != NULL);
2033  assert((*gubset)->gubconssidx != NULL);
2034  assert((*gubset)->gubvarsidx != NULL);
2035 
2036  /* free all GUB constraints */
2037  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2038  {
2039  assert((*gubset)->gubconss[i] != NULL);
2040  GUBconsFree(scip, &(*gubset)->gubconss[i]);
2041  }
2042 
2043  /* free allocated memory */
2044  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2045  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2046  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2047  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2048  SCIPfreeBuffer(scip, gubset);
2049 }
2050 
2051 #ifndef NDEBUG
2052 /** checks whether GUB set data structure is consistent */
2053 static
2055  SCIP* scip, /**< SCIP data structure */
2056  SCIP_GUBSET* gubset, /**< GUB set data structure */
2057  SCIP_VAR** vars /**< variables in the knapsack constraint */
2058  )
2059 {
2060  int i;
2061  int gubconsidx;
2062  int gubvaridx;
2063  SCIP_VAR* var1;
2064  SCIP_VAR* var2;
2065  SCIP_Bool var1negated;
2066  SCIP_Bool var2negated;
2067 
2068  assert(scip != NULL);
2069  assert(gubset != NULL);
2070 
2071  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2072 
2073  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2074  for( i = 0; i < gubset->nvars; i++ )
2075  {
2076  gubconsidx = gubset->gubconssidx[i];
2077  gubvaridx = gubset->gubvarsidx[i];
2078 
2079  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2080  {
2081  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2082  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2083  }
2084  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2085  }
2086 
2087  /* checks for each GUB whether all pairs of its variables have a common clique */
2088  for( i = 0; i < gubset->ngubconss; i++ )
2089  {
2090  int j;
2091 
2092  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2093  {
2094  int k;
2095 
2096  /* get corresponding active problem variable */
2097  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2098  var1negated = FALSE;
2099  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2100 
2101  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2102  {
2103  /* get corresponding active problem variable */
2104  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2105  var2negated = FALSE;
2106  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2107 
2108  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2109  {
2110  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2111  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2112  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2113  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2114  SCIPvarGetName(var1), k,
2115  SCIPvarGetName(var2));
2116  }
2117 
2118  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2119  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2120  }
2121  }
2122  }
2123  SCIPdebugMsg(scip, " --> successful\n");
2124 
2125  return SCIP_OKAY;
2126 }
2127 #endif
2128 
2129 /** calculates a partition of the given set of binary variables into cliques;
2130  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2131  * were assigned to the same clique;
2132  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2133  * the preceding variables was assigned to clique i-1;
2134  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2135  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2136  */
2137 
2138 static
2140  SCIP*const scip, /**< SCIP data structure */
2141  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2142  int const nvars, /**< number of variables in the clique */
2143  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2144  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2145  SCIP_Real* solvals /**< solution values of all given binary variables */
2146  )
2148  SCIP_VAR** tmpvars;
2149  SCIP_VAR** cliquevars;
2150  SCIP_Bool* cliquevalues;
2151  SCIP_Bool* tmpvalues;
2152  int* varseq;
2153  int* sortkeys;
2154  int ncliquevars;
2155  int maxncliquevarscomp;
2156  int nignorevars;
2157  int nvarsused;
2158  int i;
2159 
2160  assert(scip != NULL);
2161  assert(nvars == 0 || vars != NULL);
2162  assert(nvars == 0 || cliquepartition != NULL);
2163  assert(ncliques != NULL);
2164 
2165  if( nvars == 0 )
2166  {
2167  *ncliques = 0;
2168  return SCIP_OKAY;
2169  }
2170 
2171  /* allocate temporary memory for storing the variables of the current clique */
2172  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2173  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2174  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2175  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2176  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2177  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2178 
2179  /* initialize the cliquepartition array with -1 */
2180  /* initialize the tmpvalues array */
2181  for( i = nvars - 1; i >= 0; --i )
2182  {
2183  tmpvalues[i] = TRUE;
2184  cliquepartition[i] = -1;
2185  }
2186 
2187  /* get corresponding active problem variables */
2188  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2189 
2190  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2191  * by nondecreasing number of cliques the variables are in
2192  */
2193  nignorevars = 0;
2194  nvarsused = 0;
2195  for( i = 0; i < nvars; i++ )
2196  {
2197  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2198  {
2199  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2200  varseq[nvars-1-nignorevars] = i;
2201  nignorevars++;
2202  }
2203  else
2204  {
2205  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2206  varseq[nvarsused] = i;
2207  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2208  nvarsused++;
2209  }
2210  }
2211  assert(nvarsused + nignorevars == nvars);
2212 
2213  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2214  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2215 
2216  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2217 
2218  /* calculate the clique partition */
2219  *ncliques = 0;
2220  for( i = 0; i < nvars; ++i )
2221  {
2222  if( cliquepartition[varseq[i]] == -1 )
2223  {
2224  int j;
2225 
2226  /* variable starts a new clique */
2227  cliquepartition[varseq[i]] = *ncliques;
2228  cliquevars[0] = tmpvars[varseq[i]];
2229  cliquevalues[0] = tmpvalues[varseq[i]];
2230  ncliquevars = 1;
2231 
2232  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2233  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2234  */
2235  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2236  {
2237  /* greedily fill up the clique */
2238  for( j = i + 1; j < nvarsused; ++j )
2239  {
2240  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2241  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2242  {
2243  int k;
2244 
2245  /* check if every variable in the actual clique is in clique with the new variable */
2246  for( k = ncliquevars - 1; k >= 0; --k )
2247  {
2248  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2249  cliquevalues[k], TRUE) )
2250  break;
2251  }
2252 
2253  if( k == -1 )
2254  {
2255  /* put the variable into the same clique */
2256  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2257  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2258  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2259  ++ncliquevars;
2260  }
2261  }
2262  }
2263  }
2264 
2265  /* this clique is finished */
2266  ++(*ncliques);
2267  }
2268  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2269 
2270  /* break if we reached the maximal number of comparisons */
2271  if( i * nvars > maxncliquevarscomp )
2272  break;
2273  }
2274  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2275  for( ; i < nvars; ++i )
2276  {
2277  if( cliquepartition[varseq[i]] == -1 )
2278  {
2279  cliquepartition[varseq[i]] = *ncliques;
2280  ++(*ncliques);
2281  }
2282  }
2283 
2284  /* free temporary memory */
2285  SCIPfreeBufferArray(scip, &sortkeys);
2286  SCIPfreeBufferArray(scip, &varseq);
2287  SCIPfreeBufferArray(scip, &tmpvars);
2288  SCIPfreeBufferArray(scip, &tmpvalues);
2289  SCIPfreeBufferArray(scip, &cliquevalues);
2290  SCIPfreeBufferArray(scip, &cliquevars);
2291 
2292  return SCIP_OKAY;
2293 }
2294 
2295 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2296 static
2298  SCIP* scip, /**< SCIP data structure */
2299  SCIP_GUBSET* gubset, /**< GUB set data structure */
2300  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2301  SCIP_Real* solvals /**< solution values of all knapsack variables */
2302  )
2303 {
2304  int* cliquepartition;
2305  int* gubfirstvar;
2306  int ncliques;
2307  int currentgubconsidx;
2308  int newgubconsidx;
2309  int cliqueidx;
2310  int nvars;
2311  int i;
2312 
2313  assert(scip != NULL);
2314  assert(gubset != NULL);
2315  assert(vars != NULL);
2316 
2317  nvars = gubset->nvars;
2318  assert(nvars >= 0);
2319 
2320  /* allocate temporary memory for clique partition */
2321  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2322 
2323  /* compute sophisticated clique partition */
2324  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2325 
2326  /* allocate temporary memory for GUB set data structure */
2327  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2328 
2329  /* translate GUB partition into GUB set data structure */
2330  for( i = 0; i < ncliques; i++ )
2331  {
2332  /* initialize first variable for every GUB */
2333  gubfirstvar[i] = -1;
2334  }
2335  /* move every knapsack variable into GUB defined by clique partition */
2336  for( i = 0; i < nvars; i++ )
2337  {
2338  assert(cliquepartition[i] >= 0);
2339 
2340  cliqueidx = cliquepartition[i];
2341  currentgubconsidx = gubset->gubconssidx[i];
2342  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2343 
2344  /* variable is first element in GUB constraint defined by clique partition */
2345  if( gubfirstvar[cliqueidx] == -1 )
2346  {
2347  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2348  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2349  */
2350  assert(gubset->gubvarsidx[i] == 0);
2351  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2352 
2353  /* remember the first variable found for the current GUB */
2354  gubfirstvar[cliqueidx] = i;
2355  }
2356  /* variable is additional element of GUB constraint defined by clique partition */
2357  else
2358  {
2359  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2360 
2361  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2362  * first variable of this GUB constraint
2363  */
2364  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2365  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2366  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2367 
2368  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2369  }
2370  }
2371 
2372 #ifdef SCIP_DEBUG
2373  /* prints GUB set data structure */
2374  GUBsetPrint(scip, gubset, vars, solvals);
2375 #endif
2376 
2377 #ifndef NDEBUG
2378  /* checks consistency of GUB set data structure */
2379  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2380 #endif
2381 
2382  /* free temporary memory */
2383  SCIPfreeBufferArray(scip, &gubfirstvar);
2384  SCIPfreeBufferArray(scip, &cliquepartition);
2385 
2386  return SCIP_OKAY;
2387 }
2388 
2389 /** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
2390  * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
2391  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2392  */
2393 static
2395  SCIP* scip, /**< SCIP data structure */
2396  SCIP_VAR** vars, /**< variables in knapsack constraint */
2397  int nvars, /**< number of variables in knapsack constraint */
2398  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2399  SCIP_Longint capacity, /**< capacity of knapsack */
2400  SCIP_Real* solvals, /**< solution values of all problem variables */
2401  int* covervars, /**< pointer to store cover variables */
2402  int* noncovervars, /**< pointer to store noncover variables */
2403  int* ncovervars, /**< pointer to store number of cover variables */
2404  int* nnoncovervars, /**< pointer to store number of noncover variables */
2405  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2406  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2407  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2408  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2409  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2410  )
2411 {
2412  SCIP_Longint* transweights;
2413  SCIP_Real* transprofits;
2414  SCIP_Longint transcapacity;
2415  SCIP_Longint fixedonesweight;
2416  SCIP_Longint itemsweight;
2417  SCIP_Bool infeasible;
2418  int* fixedones;
2419  int* fixedzeros;
2420  int* items;
2421  int nfixedones;
2422  int nfixedzeros;
2423  int nitems;
2424  int j;
2425 
2426  assert(scip != NULL);
2427  assert(vars != NULL);
2428  assert(nvars > 0);
2429  assert(weights != NULL);
2430  assert(capacity >= 0);
2431  assert(solvals != NULL);
2432  assert(covervars != NULL);
2433  assert(noncovervars != NULL);
2434  assert(ncovervars != NULL);
2435  assert(nnoncovervars != NULL);
2436  assert(coverweight != NULL);
2437  assert(found != NULL);
2438  assert(ntightened != NULL);
2439  assert(fractional != NULL);
2440 
2441  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2442 
2443  /* allocates temporary memory */
2444  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2445  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2446  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2447  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2448  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2449 
2450  *found = FALSE;
2451  *ncovervars = 0;
2452  *nnoncovervars = 0;
2453  *coverweight = 0;
2454  *fractional = TRUE;
2455 
2456  /* gets the following sets
2457  * N_1 = {j in N : x*_j = 1} (fixedones),
2458  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2459  * N\(N_0 & N_1) (items),
2460  * where x*_j is the solution value of variable x_j
2461  */
2462  nfixedones = 0;
2463  nfixedzeros = 0;
2464  nitems = 0;
2465  fixedonesweight = 0;
2466  itemsweight = 0;
2467  *ntightened = 0;
2468  for( j = 0; j < nvars; j++ )
2469  {
2470  assert(SCIPvarIsBinary(vars[j]));
2471 
2472  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2473  if( weights[j] > capacity )
2474  {
2475  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2476  assert(!infeasible);
2477  (*ntightened)++;
2478  continue;
2479  }
2480 
2481  /* variable x_j has solution value one */
2482  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2483  {
2484  fixedones[nfixedones] = j;
2485  nfixedones++;
2486  fixedonesweight += weights[j];
2487  }
2488  /* variable x_j has solution value zero */
2489  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2490  {
2491  fixedzeros[nfixedzeros] = j;
2492  nfixedzeros++;
2493  }
2494  /* variable x_j has fractional solution value */
2495  else
2496  {
2497  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2498  items[nitems] = j;
2499  nitems++;
2500  itemsweight += weights[j];
2501  }
2502  }
2503  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2504 
2505  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2506  * the separation routine
2507  */
2508  assert(nitems >= 0);
2509  if( nitems == 0 )
2510  {
2511  *fractional = FALSE;
2512  goto TERMINATE;
2513  }
2514  assert(*fractional);
2515 
2516  /* transforms the traditional separation problem (under consideration of the following fixing:
2517  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2518  *
2519  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2520  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2521  * z_j in {0,1}, j in N\(N_0 & N_1)
2522  *
2523  * to a knapsack problem in maximization form by complementing the variables
2524  *
2525  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2526  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2527  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2528  * z_j in {0,1}, j in N\(N_0 & N_1)
2529  */
2530 
2531  /* gets weight and profit of variables in transformed knapsack problem */
2532  for( j = 0; j < nitems; j++ )
2533  {
2534  transweights[j] = weights[items[j]];
2535  transprofits[j] = 1.0 - solvals[items[j]];
2536  }
2537  /* gets capacity of transformed knapsack problem */
2538  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2539 
2540  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2541  * (when variables fixed to zero are not used)
2542  */
2543  if( transcapacity < 0 )
2544  {
2545  assert(!(*found));
2546  goto TERMINATE;
2547  }
2548 
2549  if( modtransused )
2550  {
2551  /* transforms the modified separation problem (under consideration of the following fixing:
2552  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2553  *
2554  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2555  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2556  * z_j in {0,1}, j in N\(N_0 & N_1)
2557  *
2558  * to a knapsack problem in maximization form by complementing the variables
2559  *
2560  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2561  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2562  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2563  * z_j in {0,1}, j in N\(N_0 & N_1)
2564  */
2565 
2566  /* gets weight and profit of variables in modified transformed knapsack problem */
2567  for( j = 0; j < nitems; j++ )
2568  {
2569  transprofits[j] *= weights[items[j]];
2570  assert(SCIPisFeasPositive(scip, transprofits[j]));
2571  }
2572  }
2573 
2574  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2575  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2576  * let z* be the solution, then
2577  * j in C, if z*_j = 0 and
2578  * i in N\C, if z*_j = 1.
2579  */
2580  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2581  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2582  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2583 
2584  /* constructs cover C (sum_{j in C} a_j > a_0) */
2585  for( j = 0; j < *ncovervars; j++ )
2586  {
2587  (*coverweight) += weights[covervars[j]];
2588  }
2589 
2590  /* adds all variables from N_1 to C */
2591  for( j = 0; j < nfixedones; j++ )
2592  {
2593  covervars[*ncovervars] = fixedones[j];
2594  (*ncovervars)++;
2595  (*coverweight) += weights[fixedones[j]];
2596  }
2597 
2598  /* adds all variables from N_0 to N\C */
2599  for( j = 0; j < nfixedzeros; j++ )
2600  {
2601  noncovervars[*nnoncovervars] = fixedzeros[j];
2602  (*nnoncovervars)++;
2603  }
2604  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2605  assert((*coverweight) > capacity);
2606  *found = TRUE;
2607 
2608  TERMINATE:
2609  /* frees temporary memory */
2610  SCIPfreeBufferArray(scip, &items);
2611  SCIPfreeBufferArray(scip, &fixedzeros);
2612  SCIPfreeBufferArray(scip, &fixedones);
2613  SCIPfreeBufferArray(scip, &transprofits);
2614  SCIPfreeBufferArray(scip, &transweights);
2615 
2616  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2617 
2618  return SCIP_OKAY;
2619 }
2620 
2621 #ifndef NDEBUG
2622 /** checks if minweightidx is set correctly
2623  */
2624 static
2626  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2627  SCIP_Longint capacity, /**< capacity of knapsack */
2628  int* covervars, /**< pointer to store cover variables */
2629  int ncovervars, /**< pointer to store number of cover variables */
2630  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2631  int minweightidx, /**< index of variable in cover variables with minimum weight */
2632  int j /**< current index in cover variables */
2633  )
2634 {
2635  SCIP_Longint minweight;
2636  int i;
2637 
2638  assert(weights != NULL);
2639  assert(covervars != NULL);
2640  assert(ncovervars > 0);
2641 
2642  minweight = weights[covervars[minweightidx]];
2643 
2644  /* checks if all cover variables before index j have weight greater than minweight */
2645  for( i = 0; i < j; i++ )
2646  {
2647  assert(weights[covervars[i]] > minweight);
2648  if( weights[covervars[i]] <= minweight )
2649  return FALSE;
2650  }
2651 
2652  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2653  for( i = 0; i < j; i++ )
2654  {
2655  assert(coverweight - weights[covervars[i]] <= capacity);
2656  if( coverweight - weights[covervars[i]] > capacity )
2657  return FALSE;
2658  }
2659  return TRUE;
2660 }
2661 #endif
2662 
2663 
2664 /** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
2665  * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
2666  */
2667 static
2669  SCIP* scip, /**< SCIP data structure */
2670  SCIP_Real* solvals, /**< solution values of all problem variables */
2671  int* covervars, /**< cover variables */
2672  int ncovervars, /**< number of cover variables */
2673  int* varsC1, /**< pointer to store variables in C1 */
2674  int* varsC2, /**< pointer to store variables in C2 */
2675  int* nvarsC1, /**< pointer to store number of variables in C1 */
2676  int* nvarsC2 /**< pointer to store number of variables in C2 */
2677  )
2678 {
2679  int j;
2680 
2681  assert(scip != NULL);
2682  assert(ncovervars >= 0);
2683  assert(solvals != NULL);
2684  assert(covervars != NULL);
2685  assert(varsC1 != NULL);
2686  assert(varsC2 != NULL);
2687  assert(nvarsC1 != NULL);
2688  assert(nvarsC2 != NULL);
2689 
2690  *nvarsC1 = 0;
2691  *nvarsC2 = 0;
2692  for( j = 0; j < ncovervars; j++ )
2693  {
2694  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2695 
2696  /* variable has solution value one */
2697  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2698  {
2699  varsC2[*nvarsC2] = covervars[j];
2700  (*nvarsC2)++;
2701  }
2702  /* variable has solution value less than one */
2703  else
2704  {
2705  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2706  varsC1[*nvarsC1] = covervars[j];
2707  (*nvarsC1)++;
2708  }
2709  }
2710  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2711 }
2712 
2713 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2714  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2715  */
2716 static
2718  SCIP* scip, /**< SCIP data structure */
2719  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2720  int* varsC1, /**< pointer to store variables in C1 */
2721  int* varsC2, /**< pointer to store variables in C2 */
2722  int* nvarsC1, /**< pointer to store number of variables in C1 */
2723  int* nvarsC2 /**< pointer to store number of variables in C2 */
2724  )
2726  SCIP_Real* sortkeysC2;
2727  int j;
2728 
2729  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2730  assert(*nvarsC2 > 0);
2731 
2732  /* allocates temporary memory */
2733  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2734 
2735  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2736  for( j = 0; j < *nvarsC2; j++ )
2737  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2738  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2739 
2740  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2741  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2742  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2743  {
2744  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2745  (*nvarsC1)++;
2746  (*nvarsC2)--;
2747  }
2748 
2749  /* frees temporary memory */
2750  SCIPfreeBufferArray(scip, &sortkeysC2);
2751 
2752  return SCIP_OKAY;
2753 }
2754 
2755 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2756 static
2758  SCIP* scip, /**< SCIP data structure */
2759  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2760  int* varsC1, /**< pointer to store variables in C1 */
2761  int* varsC2, /**< pointer to store variables in C2 */
2762  int* nvarsC1, /**< pointer to store number of variables in C1 */
2763  int* nvarsC2 /**< pointer to store number of variables in C2 */
2764  )
2766  SCIP_Real* sortkeysC2;
2767  int j;
2768 
2769  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2770  assert(*nvarsC2 > 0);
2771 
2772  /* allocates temporary memory */
2773  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2774 
2775  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2776  for( j = 0; j < *nvarsC2; j++ )
2777  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2778  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2779 
2780  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2781  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2782  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2783  (*nvarsC1)++;
2784  (*nvarsC2)--;
2785 
2786  /* frees temporary memory */
2787  SCIPfreeBufferArray(scip, &sortkeysC2);
2788 
2789  return SCIP_OKAY;
2790 }
2791 
2792 
2793 /** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
2794  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2795  * \f$F = (N \setminus C) \setminus F\f$
2796  */
2797 static
2799  SCIP* scip, /**< SCIP data structure */
2800  SCIP_Real* solvals, /**< solution values of all problem variables */
2801  int* noncovervars, /**< noncover variables */
2802  int nnoncovervars, /**< number of noncover variables */
2803  int* varsF, /**< pointer to store variables in F */
2804  int* varsR, /**< pointer to store variables in R */
2805  int* nvarsF, /**< pointer to store number of variables in F */
2806  int* nvarsR /**< pointer to store number of variables in R */
2807  )
2808 {
2809  int j;
2810 
2811  assert(scip != NULL);
2812  assert(nnoncovervars >= 0);
2813  assert(solvals != NULL);
2814  assert(noncovervars != NULL);
2815  assert(varsF != NULL);
2816  assert(varsR != NULL);
2817  assert(nvarsF != NULL);
2818  assert(nvarsR != NULL);
2819 
2820  *nvarsF = 0;
2821  *nvarsR = 0;
2822 
2823  for( j = 0; j < nnoncovervars; j++ )
2824  {
2825  /* variable has solution value zero */
2826  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2827  {
2828  varsR[*nvarsR] = noncovervars[j];
2829  (*nvarsR)++;
2830  }
2831  /* variable has solution value greater than zero */
2832  else
2833  {
2834  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2835  varsF[*nvarsF] = noncovervars[j];
2836  (*nvarsF)++;
2837  }
2838  }
2839  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2840 }
2841 
2842 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2843  * lifting procedure
2844  */
2845 static
2847  SCIP* scip, /**< SCIP data structure */
2848  SCIP_Real* solvals, /**< solution values of all problem variables */
2849  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2850  int* varsF, /**< pointer to store variables in F */
2851  int* varsC2, /**< pointer to store variables in C2 */
2852  int* varsR, /**< pointer to store variables in R */
2853  int nvarsF, /**< number of variables in F */
2854  int nvarsC2, /**< number of variables in C2 */
2855  int nvarsR /**< number of variables in R */
2856  )
2857 {
2858  SORTKEYPAIR** sortkeypairsF;
2859  SORTKEYPAIR* sortkeypairsFstore;
2860  SCIP_Real* sortkeysC2;
2861  SCIP_Real* sortkeysR;
2862  int j;
2863 
2864  assert(scip != NULL);
2865  assert(solvals != NULL);
2866  assert(weights != NULL);
2867  assert(varsF != NULL);
2868  assert(varsC2 != NULL);
2869  assert(varsR != NULL);
2870  assert(nvarsF >= 0);
2871  assert(nvarsC2 >= 0);
2872  assert(nvarsR >= 0);
2873 
2874  /* allocates temporary memory */
2875  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2876  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2877  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2878  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2879 
2880  /* gets sorting key for variables in F corresponding to the following lifting sequence
2881  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2882  * x*_1 >= x*_2 >= ... >= x*_|F|
2883  * in case of equality uses
2884  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2885  */
2886  for( j = 0; j < nvarsF; j++ )
2887  {
2888  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2889  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2890  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2891  }
2892 
2893  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2894  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2895  */
2896  for( j = 0; j < nvarsC2; j++ )
2897  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2898 
2899  /* gets sorting key for variables in R corresponding to the following lifting sequence
2900  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2901  */
2902  for( j = 0; j < nvarsR; j++ )
2903  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2904 
2905  /* sorts F, C2 and R */
2906  if( nvarsF > 0 )
2907  {
2908  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2909  }
2910  if( nvarsC2 > 0 )
2911  {
2912  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2913  }
2914  if( nvarsR > 0)
2915  {
2916  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2917  }
2918 
2919  /* frees temporary memory */
2920  SCIPfreeBufferArray(scip, &sortkeysR);
2921  SCIPfreeBufferArray(scip, &sortkeysC2);
2922  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2923  SCIPfreeBufferArray(scip, &sortkeypairsF);
2924 
2925  return SCIP_OKAY;
2926 }
2927 
2928 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2929  * for the sequential GUB wise lifting procedure
2930  */
2931 static
2933  SCIP* scip, /**< SCIP data structure */
2934  SCIP_GUBSET* gubset, /**< GUB set data structure */
2935  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2936  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2937  int* varsC1, /**< variables in C1 */
2938  int* varsC2, /**< variables in C2 */
2939  int* varsF, /**< variables in F */
2940  int* varsR, /**< variables in R */
2941  int nvarsC1, /**< number of variables in C1 */
2942  int nvarsC2, /**< number of variables in C2 */
2943  int nvarsF, /**< number of variables in F */
2944  int nvarsR, /**< number of variables in R */
2945  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2946  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2947  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2948  int* gubconsGR, /**< pointer to store GUBs in GR */
2949  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2950  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2951  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2952  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2953  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2954  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2955  )
2956 {
2957  SORTKEYPAIR** sortkeypairsGFC1;
2958  SORTKEYPAIR* sortkeypairsGFC1store;
2959  SCIP_Real* sortkeysC1;
2960  SCIP_Real* sortkeysC2;
2961  SCIP_Real* sortkeysR;
2962  int* nC1varsingubcons;
2963  int var;
2964  int gubconsidx;
2965  int varidx;
2966  int ngubconss;
2967  int ngubconsGOC1;
2968  int targetvar;
2969 #ifndef NDEBUG
2970  int nvarsprocessed = 0;
2971 #endif
2972  int i;
2973  int j;
2974 
2975 #if GUBSPLITGNC1GUBS
2976  SCIP_Bool gubconswithF;
2977  int origngubconss;
2978  origngubconss = gubset->ngubconss;
2979 #endif
2980 
2981  assert(scip != NULL);
2982  assert(gubset != NULL);
2983  assert(solvals != NULL);
2984  assert(weights != NULL);
2985  assert(varsC1 != NULL);
2986  assert(varsC2 != NULL);
2987  assert(varsF != NULL);
2988  assert(varsR != NULL);
2989  assert(nvarsC1 > 0);
2990  assert(nvarsC2 >= 0);
2991  assert(nvarsF >= 0);
2992  assert(nvarsR >= 0);
2993  assert(gubconsGC1 != NULL);
2994  assert(gubconsGC2 != NULL);
2995  assert(gubconsGFC1 != NULL);
2996  assert(gubconsGR != NULL);
2997  assert(ngubconsGC1 != NULL);
2998  assert(ngubconsGC2 != NULL);
2999  assert(ngubconsGFC1 != NULL);
3000  assert(ngubconsGR != NULL);
3001  assert(maxgubvarssize != NULL);
3002 
3003  ngubconss = gubset->ngubconss;
3004  ngubconsGOC1 = 0;
3005 
3006  /* GUBs are categorized into different types according to the variables in volved
3007  * - GOC1: involves variables in C1 only -- no C2, R, F
3008  * - GNC1: involves variables in C1 and F (and R) -- no C2
3009  * - GF: involves variables in F (and R) only -- no C1, C2
3010  * - GC2: involves variables in C2 only -- no C1, R, F
3011  * - GR: involves variables in R only -- no C1, C2, F
3012  * which requires splitting GUBs in case they include variable in F and R.
3013  *
3014  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3015  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3016  * - second ordering level is
3017  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3018  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3019  * GR: non-increasing max{ a_k : k in GR_j}
3020  *
3021  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3022  * - GC1: GUBs of category GOC1 and GNC1
3023  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3024  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3025  */
3026 
3027  /* allocates temporary memory */
3028  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3029  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3030  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3031 
3032  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3033  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3034  * - C2: non-increasing a_j
3035  * - R: non-increasing a_j
3036  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3037  */
3038 
3039  /* gets sorting key for variables in C1 corresponding to the following ordering
3040  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3041  */
3042  for( j = 0; j < nvarsC1; j++ )
3043  {
3044  /* gets sortkeys */
3045  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3046 
3047  /* update status of variable in its gub constraint */
3048  gubconsidx = gubset->gubconssidx[varsC1[j]];
3049  varidx = gubset->gubvarsidx[varsC1[j]];
3050  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3051  }
3052 
3053  /* gets sorting key for variables in F corresponding to the following ordering
3054  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3055  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3056  * and updates status of each variable in F in GUB set data structure
3057  */
3058  for( j = 0; j < nvarsF; j++ )
3059  {
3060  /* update status of variable in its gub constraint */
3061  gubconsidx = gubset->gubconssidx[varsF[j]];
3062  varidx = gubset->gubvarsidx[varsF[j]];
3063  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3064  }
3065 
3066  /* gets sorting key for variables in C2 corresponding to the following ordering
3067  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3068  * and updates status of each variable in F in GUB set data structure
3069  */
3070  for( j = 0; j < nvarsC2; j++ )
3071  {
3072  /* gets sortkeys */
3073  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3074 
3075  /* update status of variable in its gub constraint */
3076  gubconsidx = gubset->gubconssidx[varsC2[j]];
3077  varidx = gubset->gubvarsidx[varsC2[j]];
3078  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3079  }
3080 
3081  /* gets sorting key for variables in R corresponding to the following ordering
3082  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3083  * and updates status of each variable in F in GUB set data structure
3084  */
3085  for( j = 0; j < nvarsR; j++ )
3086  {
3087  /* gets sortkeys */
3088  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3089 
3090  /* update status of variable in its gub constraint */
3091  gubconsidx = gubset->gubconssidx[varsR[j]];
3092  varidx = gubset->gubvarsidx[varsR[j]];
3093  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3094  }
3095 
3096  /* sorts C1, F, C2 and R */
3097  assert(nvarsC1 > 0);
3098  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3099 
3100  if( nvarsC2 > 0 )
3101  {
3102  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3103  }
3104  if( nvarsR > 0)
3105  {
3106  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3107  }
3108 
3109  /* frees temporary memory */
3110  SCIPfreeBufferArray(scip, &sortkeysR);
3111  SCIPfreeBufferArray(scip, &sortkeysC2);
3112  SCIPfreeBufferArray(scip, &sortkeysC1);
3113 
3114  /* allocate and initialize temporary memory for sorting GUB constraints */
3115  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3116  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3117  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3118  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3119  for( i = 0; i < ngubconss; i++)
3120  {
3121  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3122  sortkeypairsGFC1[i]->key1 = 0.0;
3123  sortkeypairsGFC1[i]->key2 = 0.0;
3124  }
3125  *ngubconsGC1 = 0;
3126  *ngubconsGC2 = 0;
3127  *ngubconsGFC1 = 0;
3128  *ngubconsGR = 0;
3129  *ngubconscapexceed = 0;
3130  *maxgubvarssize = 0;
3131 
3132 #ifndef NDEBUG
3133  for( i = 0; i < gubset->ngubconss; i++ )
3134  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3135 #endif
3136 
3137  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3138  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3139  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3140  * non-increasing number of variables in F, and
3141  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3142  */
3143  for( i = 0; i < nvarsC1; i++ )
3144  {
3145  int nvarsC1capexceed;
3146 
3147  nvarsC1capexceed = 0;
3148 
3149  var = varsC1[i];
3150  gubconsidx = gubset->gubconssidx[var];
3151  varidx = gubset->gubvarsidx[var];
3152 
3153  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3154  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3155 
3156  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3157  * note that variables in C1 are already sorted by non-decreasing weigth
3158  */
3159  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3160  GUBsetSwapVars(scip, gubset, var, targetvar);
3161  nC1varsingubcons[gubconsidx]++;
3162 
3163  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3164  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3165  {
3166  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3167  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3168  continue;
3169  }
3170 
3171  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3172  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3173  */
3174 #if GUBSPLITGNC1GUBS
3175  gubconswithF = FALSE;
3176 #endif
3177  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3178  {
3179  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3180 
3181  /* C1-variable: update number of C1/capacity exceeding variables */
3182  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3183  {
3184  nvarsC1capexceed++;
3185 #ifndef NDEBUG
3186  nvarsprocessed++;
3187 #endif
3188  }
3189  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3190  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3191  {
3192 #if GUBSPLITGNC1GUBS
3193  gubconswithF = TRUE;
3194 #endif
3195  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3196 
3197  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3198  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3199  }
3200  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3201  {
3202  nvarsC1capexceed++;
3203  }
3204  else
3205  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3206  }
3207 
3208  /* update set of GC1 GUBs */
3209  gubconsGC1[*ngubconsGC1] = gubconsidx;
3210  (*ngubconsGC1)++;
3211 
3212  /* update maximum size of all GUB constraints */
3213  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3214  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3215 
3216  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3217  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3218  {
3219  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3220  ngubconsGOC1++;
3221  }
3222  else
3223  {
3224 #if GUBSPLITGNC1GUBS
3225  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3226  if( !gubconswithF )
3227  {
3228  GUBVARSTATUS movevarstatus;
3229 
3230  assert(gubset->ngubconss < gubset->nvars);
3231 
3232  /* create a new GUB for GR part of splitting */
3233  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3234  gubset->ngubconss++;
3235  ngubconss = gubset->ngubconss;
3236 
3237  /* fill GR with R variables in current GUB */
3238  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3239  {
3240  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3241  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3242  {
3243  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3244  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3245  gubconsidx, ngubconss-1) );
3246  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3247  movevarstatus;
3248  }
3249  }
3250 
3251  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3252  ngubconsGOC1++;
3253 
3254  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3255  gubconsGR[*ngubconsGR] = ngubconss-1;
3256  (*ngubconsGR)++;
3257  }
3258  /* variables in C1, F, and maybe R: GNC1 GUB */
3259  else
3260  {
3261  assert(gubconswithF);
3262 
3263  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3264  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3265  (*ngubconsGFC1)++;
3266  }
3267 #else
3268  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3269  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3270  (*ngubconsGFC1)++;
3271 #endif
3272  }
3273  }
3274 
3275  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3276  * are already sorted correctly
3277  */
3278  for( i = 0; i < nvarsC2; i++ )
3279  {
3280  var = varsC2[i];
3281  gubconsidx = gubset->gubconssidx[var];
3282  varidx = gubset->gubvarsidx[var];
3283 
3284  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3285  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3286  assert(varidx == 0);
3287  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3288  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3289 
3290  /* set status of GC2 GUB */
3291  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3292 
3293  /* update group of GC2 GUBs */
3294  gubconsGC2[*ngubconsGC2] = gubconsidx;
3295  (*ngubconsGC2)++;
3296 
3297  /* update maximum size of all GUB constraints */
3298  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3299  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3300 
3301 #ifndef NDEBUG
3302  nvarsprocessed++;
3303 #endif
3304  }
3305 
3306  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3307  * non-increasing number of variables in F, and
3308  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3309  */
3310  for( i = 0; i < nvarsF; i++ )
3311  {
3312  var = varsF[i];
3313  gubconsidx = gubset->gubconssidx[var];
3314  varidx = gubset->gubvarsidx[var];
3315 
3316  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3317  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3318 
3319 #ifndef NDEBUG
3320  nvarsprocessed++;
3321 #endif
3322 
3323  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3324  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3325  {
3326  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3327  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3328  continue;
3329  }
3330 
3331  /* set status of GF GUB */
3332  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3333 
3334  /* update sorting key of corresponding GFC1 GUB */
3335  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3336  {
3337  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3338  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3339 
3340  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3341  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3342  {
3343  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3344 
3345  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3346  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3347  }
3348  }
3349 
3350  /* update set of GFC1 GUBs */
3351  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3352  (*ngubconsGFC1)++;
3353 
3354  /* update maximum size of all GUB constraints */
3355  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3356  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3357  }
3358 
3359  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3360  * correctly
3361  */
3362  for( i = 0; i < nvarsR; i++ )
3363  {
3364  var = varsR[i];
3365  gubconsidx = gubset->gubconssidx[var];
3366  varidx = gubset->gubvarsidx[var];
3367 
3368  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3369  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3370 
3371 #ifndef NDEBUG
3372  nvarsprocessed++;
3373 #endif
3374 
3375  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3376  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3377  {
3378  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3379  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3380  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3381  continue;
3382  }
3383 
3384  /* set status of GR GUB */
3385  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3386 
3387  /* update set of GR GUBs */
3388  gubconsGR[*ngubconsGR] = gubconsidx;
3389  (*ngubconsGR)++;
3390 
3391  /* update maximum size of all GUB constraints */
3392  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3393  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3394  }
3395  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3396 
3397  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3398  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3399  assert(*ngubconscapexceed >= 0);
3400 #ifndef NDEBUG
3401  {
3402  int check;
3403 
3404  check = 0;
3405 
3406  /* remaining not handled GUBs should only contain capacity exceeding variables */
3407  for( i = 0; i < ngubconss; i++ )
3408  {
3409  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3410  check++;
3411  }
3412  assert(check == *ngubconscapexceed);
3413  }
3414 #endif
3415 
3416  /* sort GFCI GUBs according to computed sorting keys */
3417  if( (*ngubconsGFC1) > 0 )
3418  {
3419  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3420  }
3421 
3422  /* free temporary memory */
3423 #if GUBSPLITGNC1GUBS
3424  ngubconss = origngubconss;
3425 #endif
3426  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3427  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3428  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3429 
3430  return SCIP_OKAY;
3431 }
3432 
3433 /** enlarges minweight table to at least the given length */
3434 static
3436  SCIP* scip, /**< SCIP data structure */
3437  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3438  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3439  int* minweightssize, /**< pointer to current size of minweights table */
3440  int newlen /**< new length of minweights table */
3441  )
3442 {
3443  int j;
3444 
3445  assert(minweightsptr != NULL);
3446  assert(*minweightsptr != NULL);
3447  assert(minweightslen != NULL);
3448  assert(*minweightslen >= 0);
3449  assert(minweightssize != NULL);
3450  assert(*minweightssize >= 0);
3451 
3452  if( newlen > *minweightssize )
3453  {
3454  int newsize;
3455 
3456  /* reallocate table memory */
3457  newsize = SCIPcalcMemGrowSize(scip, newlen);
3458  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3459  *minweightssize = newsize;
3460  }
3461  assert(newlen <= *minweightssize);
3462 
3463  /* initialize new elements */
3464  for( j = *minweightslen; j < newlen; ++j )
3465  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3466  *minweightslen = newlen;
3467 
3468  return SCIP_OKAY;
3469 }
3470 
3471 /** lifts given inequality
3472  * sum_{j in M_1} x_j <= alpha_0
3473  * valid for
3474  * S^0 = { x in {0,1}^|M_1| : sum_{j in M_1} a_j x_j <= a_0 - sum_{j in M_2} a_j }
3475  * to a valid inequality
3476  * sum_{j in M_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in M_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3477  * <= alpha_0 + sum_{j in M_2} alpha_j
3478  * for
3479  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3480  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3481  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3482  * extended weight inequalities.
3483  */
3484 static
3486  SCIP* scip, /**< SCIP data structure */
3487  SCIP_VAR** vars, /**< variables in knapsack constraint */
3488  int nvars, /**< number of variables in knapsack constraint */
3489  int ntightened, /**< number of variables with tightened upper bound */
3490  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3491  SCIP_Longint capacity, /**< capacity of knapsack */
3492  SCIP_Real* solvals, /**< solution values of all problem variables */
3493  int* varsM1, /**< variables in M_1 */
3494  int* varsM2, /**< variables in M_2 */
3495  int* varsF, /**< variables in F */
3496  int* varsR, /**< variables in R */
3497  int nvarsM1, /**< number of variables in M_1 */
3498  int nvarsM2, /**< number of variables in M_2 */
3499  int nvarsF, /**< number of variables in F */
3500  int nvarsR, /**< number of variables in R */
3501  int alpha0, /**< rights hand side of given valid inequality */
3502  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3503  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3504  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3505  )
3506 {
3507  SCIP_Longint* minweights;
3508  SCIP_Real* sortkeys;
3509  SCIP_Longint fixedonesweight;
3510  int minweightssize;
3511  int minweightslen;
3512  int j;
3513  int w;
3514 
3515  assert(scip != NULL);
3516  assert(vars != NULL);
3517  assert(nvars >= 0);
3518  assert(weights != NULL);
3519  assert(capacity >= 0);
3520  assert(solvals != NULL);
3521  assert(varsM1 != NULL);
3522  assert(varsM2 != NULL);
3523  assert(varsF != NULL);
3524  assert(varsR != NULL);
3525  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3526  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3527  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3528  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3529  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3530  assert(alpha0 >= 0);
3531  assert(liftcoefs != NULL);
3532  assert(cutact != NULL);
3533  assert(liftrhs != NULL);
3534 
3535  /* allocates temporary memory */
3536  minweightssize = nvarsM1 + 1;
3537  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3538  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3539 
3540  /* initializes data structures */
3541  BMSclearMemoryArray(liftcoefs, nvars);
3542  *cutact = 0.0;
3543 
3544  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3545  * and calculates activity of the current valid inequality
3546  */
3547  for( j = 0; j < nvarsM1; j++ )
3548  {
3549  assert(liftcoefs[varsM1[j]] == 0);
3550  liftcoefs[varsM1[j]] = 1;
3551  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3552  (*cutact) += solvals[varsM1[j]];
3553  }
3554 
3555  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3556 
3557  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3558  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3559  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3560  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3561  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3562  */
3563  minweights[0] = 0;
3564  for( w = 1; w <= nvarsM1; w++ )
3565  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3566  minweightslen = nvarsM1 + 1;
3567 
3568  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3569  fixedonesweight = 0;
3570  for( j = 0; j < nvarsM2; j++ )
3571  fixedonesweight += weights[varsM2[j]];
3572  assert(fixedonesweight >= 0);
3573 
3574  /* initializes right hand side of lifted valid inequality */
3575  *liftrhs = alpha0;
3576 
3577  /* sequentially up-lifts all variables in F: */
3578  for( j = 0; j < nvarsF; j++ )
3579  {
3580  SCIP_Longint weight;
3581  int liftvar;
3582  int liftcoef;
3583  int z;
3584 
3585  liftvar = varsF[j];
3586  weight = weights[liftvar];
3587  assert(liftvar >= 0 && liftvar < nvars);
3588  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3589  assert(weight > 0);
3590 
3591  /* knapsack problem is infeasible:
3592  * sets z = 0
3593  */
3594  if( capacity - fixedonesweight - weight < 0 )
3595  {
3596  z = 0;
3597  }
3598  /* knapsack problem is feasible:
3599  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3600  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3601  */
3602  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3603  {
3604  z = *liftrhs;
3605  }
3606  /* knapsack problem is feasible:
3607  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3608  */
3609  else
3610  {
3611  int left;
3612  int right;
3613  int middle;
3614 
3615  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3616  left = 0;
3617  right = (*liftrhs) + 1;
3618  while( left < right - 1 )
3619  {
3620  middle = (left + right) / 2;
3621  assert(0 <= middle && middle < minweightslen);
3622  if( minweights[middle] <= capacity - fixedonesweight - weight )
3623  left = middle;
3624  else
3625  right = middle;
3626  }
3627  assert(left == right - 1);
3628  assert(0 <= left && left < minweightslen);
3629  assert(minweights[left] <= capacity - fixedonesweight - weight );
3630  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3631 
3632  /* now z = left */
3633  z = left;
3634  assert(z <= *liftrhs);
3635  }
3636 
3637  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3638  liftcoef = (*liftrhs) - z;
3639  liftcoefs[liftvar] = liftcoef;
3640  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3641 
3642  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3643  if( liftcoef == 0 )
3644  continue;
3645 
3646  /* updates activity of current valid inequality */
3647  (*cutact) += liftcoef * solvals[liftvar];
3648 
3649  /* enlarges current minweight table:
3650  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3651  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3652  * and sets minweights_i[w] = infinity for
3653  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3654  */
3655  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3656 
3657  /* updates minweight table: minweight_i+1[w] =
3658  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3659  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3660  */
3661  for( w = minweightslen - 1; w >= 0; w-- )
3662  {
3663  SCIP_Longint min;
3664  if( w < liftcoef )
3665  {
3666  min = MIN(minweights[w], weight);
3667  minweights[w] = min;
3668  }
3669  else
3670  {
3671  assert(w >= liftcoef);
3672  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3673  minweights[w] = min;
3674  }
3675  }
3676  }
3677  assert(minweights[0] == 0);
3678 
3679  /* sequentially down-lifts all variables in M_2: */
3680  for( j = 0; j < nvarsM2; j++ )
3681  {
3682  SCIP_Longint weight;
3683  int liftvar;
3684  int liftcoef;
3685  int left;
3686  int right;
3687  int middle;
3688  int z;
3689 
3690  liftvar = varsM2[j];
3691  weight = weights[liftvar];
3692  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3693  assert(liftvar >= 0 && liftvar < nvars);
3694  assert(weight > 0);
3695 
3696  /* uses binary search to find
3697  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3698  */
3699  left = 0;
3700  right = minweightslen;
3701  while( left < right - 1 )
3702  {
3703  middle = (left + right) / 2;
3704  assert(0 <= middle && middle < minweightslen);
3705  if( minweights[middle] <= capacity - fixedonesweight + weight )
3706  left = middle;
3707  else
3708  right = middle;
3709  }
3710  assert(left == right - 1);
3711  assert(0 <= left && left < minweightslen);
3712  assert(minweights[left] <= capacity - fixedonesweight + weight );
3713  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3714 
3715  /* now z = left */
3716  z = left;
3717  assert(z >= *liftrhs);
3718 
3719  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3720  liftcoef = z - (*liftrhs);
3721  liftcoefs[liftvar] = liftcoef;
3722  assert(liftcoef >= 0);
3723 
3724  /* updates sum of weights of variables fixed to one */
3725  fixedonesweight -= weight;
3726 
3727  /* updates right-hand side of current valid inequality */
3728  (*liftrhs) += liftcoef;
3729  assert(*liftrhs >= alpha0);
3730 
3731  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3732  if( liftcoef == 0 )
3733  continue;
3734 
3735  /* updates activity of current valid inequality */
3736  (*cutact) += liftcoef * solvals[liftvar];
3737 
3738  /* enlarges current minweight table:
3739  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3740  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3741  * and sets minweights_i[w] = infinity for
3742  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3743  */
3744  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3745 
3746  /* updates minweight table: minweight_i+1[w] =
3747  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3748  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3749  */
3750  for( w = minweightslen - 1; w >= 0; w-- )
3751  {
3752  SCIP_Longint min;
3753  if( w < liftcoef )
3754  {
3755  min = MIN(minweights[w], weight);
3756  minweights[w] = min;
3757  }
3758  else
3759  {
3760  assert(w >= liftcoef);
3761  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3762  minweights[w] = min;
3763  }
3764  }
3765  }
3766  assert(fixedonesweight == 0);
3767  assert(*liftrhs >= alpha0);
3768 
3769  /* sequentially up-lifts all variables in R: */
3770  for( j = 0; j < nvarsR; j++ )
3771  {
3772  SCIP_Longint weight;
3773  int liftvar;
3774  int liftcoef;
3775  int z;
3776 
3777  liftvar = varsR[j];
3778  weight = weights[liftvar];
3779  assert(liftvar >= 0 && liftvar < nvars);
3780  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3781  assert(weight > 0);
3782  assert(capacity - weight >= 0);
3783  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3784 
3785  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3786  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3787  */
3788  if( minweights[*liftrhs] <= capacity - weight )
3789  {
3790  z = *liftrhs;
3791  }
3792  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3793  */
3794  else
3795  {
3796  int left;
3797  int right;
3798  int middle;
3799 
3800  left = 0;
3801  right = (*liftrhs) + 1;
3802  while( left < right - 1)
3803  {
3804  middle = (left + right) / 2;
3805  assert(0 <= middle && middle < minweightslen);
3806  if( minweights[middle] <= capacity - weight )
3807  left = middle;
3808  else
3809  right = middle;
3810  }
3811  assert(left == right - 1);
3812  assert(0 <= left && left < minweightslen);
3813  assert(minweights[left] <= capacity - weight );
3814  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3815 
3816  /* now z = left */
3817  z = left;
3818  assert(z <= *liftrhs);
3819  }
3820 
3821  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3822  liftcoef = (*liftrhs) - z;
3823  liftcoefs[liftvar] = liftcoef;
3824  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3825 
3826  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3827  if( liftcoef == 0 )
3828  continue;
3829 
3830  /* updates activity of current valid inequality */
3831  (*cutact) += liftcoef * solvals[liftvar];
3832 
3833  /* updates minweight table: minweight_i+1[w] =
3834  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3835  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3836  */
3837  for( w = *liftrhs; w >= 0; w-- )
3838  {
3839  SCIP_Longint min;
3840  if( w < liftcoef )
3841  {
3842  min = MIN(minweights[w], weight);
3843  minweights[w] = min;
3844  }
3845  else
3846  {
3847  assert(w >= liftcoef);
3848  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3849  minweights[w] = min;
3850  }
3851  }
3852  }
3853 
3854  /* frees temporary memory */
3855  SCIPfreeBufferArray(scip, &sortkeys);
3856  SCIPfreeBufferArray(scip, &minweights);
3857 
3858  return SCIP_OKAY;
3859 }
3860 
3861 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3862 static
3864  SCIP_Longint val1, /**< first value to add */
3865  SCIP_Longint val2 /**< second value to add */
3866  )
3867 {
3868  assert(val1 >= 0);
3869  assert(val2 >= 0);
3870 
3871  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3872  return SCIP_LONGINT_MAX;
3873  else
3874  {
3875  assert(val1 <= SCIP_LONGINT_MAX - val2);
3876  return (val1 + val2);
3877  }
3878 }
3879 
3880 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3881 static
3883  SCIP_Longint* minweights, /**< minweight table to compute */
3884  SCIP_Longint* finished, /**< given finished table */
3885  SCIP_Longint* unfinished, /**< given unfinished table */
3886  int minweightslen /**< length of minweight, finished, and unfinished tables */
3887  )
3888 {
3889  int w1;
3890  int w2;
3891 
3892  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3893  * note that finished and unfished arrays sorted by non-decreasing weight
3894  */
3895 
3896  /* initialize minweight with w2 = 0 */
3897  w2 = 0;
3898  assert(unfinished[w2] == 0);
3899  for( w1 = 0; w1 < minweightslen; w1++ )
3900  minweights[w1] = finished[w1];
3901 
3902  /* consider w2 = 1, ..., minweightslen-1 */
3903  for( w2 = 1; w2 < minweightslen; w2++ )
3904  {
3905  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3906  break;
3907 
3908  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3909  {
3910  SCIP_Longint temp;
3911 
3912  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3913  if( temp <= minweights[w1+w2] )
3914  minweights[w1+w2] = temp;
3915  }
3916  }
3917 }
3918 
3919 /** lifts given inequality
3920  * sum_{j in C_1} x_j <= alpha_0
3921  * valid for
3922  * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j;
3923  * sum_{j in Q_i} x_j <= 1, forall i in I }
3924  * to a valid inequality
3925  * sum_{j in C_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in C_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3926  * <= alpha_0 + sum_{j in C_2} alpha_j
3927  * for
3928  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0; sum_{j in Q_i} x_j <= 1, forall i in I };
3929  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3930  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3931  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3932  */
3933 static
3935  SCIP* scip, /**< SCIP data structure */
3936  SCIP_GUBSET* gubset, /**< GUB set data structure */
3937  SCIP_VAR** vars, /**< variables in knapsack constraint */
3938  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3939  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3940  SCIP_Longint capacity, /**< capacity of knapsack */
3941  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3942  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3943  int* gubconsGC2, /**< GUBs in GC2 */
3944  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3945  int* gubconsGR, /**< GUBs in GR */
3946  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3947  int ngubconsGC2, /**< number of GUBs in GC2 */
3948  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3949  int ngubconsGR, /**< number of GUBs in GR */
3950  int alpha0, /**< rights hand side of given valid inequality */
3951  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3952  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3953  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3954  int maxgubvarssize /**< maximal size of GUB constraints */
3955  )
3956 {
3957  SCIP_Longint* minweights;
3958  SCIP_Longint* finished;
3959  SCIP_Longint* unfinished;
3960  int* gubconsGOC1;
3961  int* gubconsGNC1;
3962  int* liftgubvars;
3963  SCIP_Longint fixedonesweight;
3964  SCIP_Longint weight;
3965  SCIP_Longint weightdiff1;
3966  SCIP_Longint weightdiff2;
3967  SCIP_Longint min;
3968  int minweightssize;
3969  int minweightslen;
3970  int nvars;
3971  int varidx;
3972  int liftgubconsidx;
3973  int liftvar;
3974  int sumliftcoef;
3975  int liftcoef;
3976  int ngubconsGOC1;
3977  int ngubconsGNC1;
3978  int left;
3979  int right;
3980  int middle;
3981  int nliftgubvars;
3982  int tmplen;
3983  int tmpsize;
3984  int j;
3985  int k;
3986  int w;
3987  int z;
3988 #ifndef NDEBUG
3989  int ngubconss;
3990  int nliftgubC1;
3991 
3992  assert(gubset != NULL);
3993  ngubconss = gubset->ngubconss;
3994 #else
3995  assert(gubset != NULL);
3996 #endif
3997 
3998  nvars = gubset->nvars;
3999 
4000  assert(scip != NULL);
4001  assert(vars != NULL);
4002  assert(nvars >= 0);
4003  assert(weights != NULL);
4004  assert(capacity >= 0);
4005  assert(solvals != NULL);
4006  assert(gubconsGC1 != NULL);
4007  assert(gubconsGC2 != NULL);
4008  assert(gubconsGFC1 != NULL);
4009  assert(gubconsGR != NULL);
4010  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4011  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4012  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4013  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4014  assert(alpha0 >= 0);
4015  assert(liftcoefs != NULL);
4016  assert(cutact != NULL);
4017  assert(liftrhs != NULL);
4018 
4019  minweightssize = ngubconsGC1+1;
4020 
4021  /* allocates temporary memory */
4022  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4023  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4024  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4025  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4026  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4027  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4028 
4029  /* initializes data structures */
4030  BMSclearMemoryArray(liftcoefs, nvars);
4031  *cutact = 0.0;
4032 
4033  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4034  * valid inequality
4035  */
4036  ngubconsGOC1 = 0;
4037  ngubconsGNC1 = 0;
4038  for( j = 0; j < ngubconsGC1; j++ )
4039  {
4040  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4041  {
4042  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4043  ngubconsGOC1++;
4044  }
4045  else
4046  {
4047  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4048  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4049  ngubconsGNC1++;
4050  }
4051  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4052  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4053  {
4054  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4055  assert(varidx >= 0 && varidx < nvars);
4056  assert(liftcoefs[varidx] == 0);
4057 
4058  liftcoefs[varidx] = 1;
4059  (*cutact) += solvals[varidx];
4060  }
4061  assert(k >= 1);
4062  }
4063  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4064  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4065 
4066  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4067  * - finished_i[w] =
4068  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4069  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4070  * sum_{j in Q_k} x_j <= 1
4071  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4072  * - unfinished_i[w] =
4073  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4074  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4075  * sum_{j in Q_k} x_j <= 1
4076  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4077  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4078  */
4079 
4080  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4081  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4082  * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4083  * comes from the first variable in the GUB
4084  */
4085  assert(ngubconsGOC1 <= ngubconsGC1);
4086  finished[0] = 0;
4087  for( w = 1; w <= ngubconsGOC1; w++ )
4088  {
4089  liftgubconsidx = gubconsGOC1[w-1];
4090 
4091  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4092  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4093 
4094  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4095 
4096  assert(varidx >= 0 && varidx < nvars);
4097  assert(liftcoefs[varidx] == 1);
4098 
4099  min = weights[varidx];
4100  finished[w] = finished[w-1] + min;
4101 
4102 #ifndef NDEBUG
4103  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4104  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4105  {
4106  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4107  assert(varidx >= 0 && varidx < nvars);
4108  assert(liftcoefs[varidx] == 1);
4109  assert(weights[varidx] >= min);
4110  }
4111 #endif
4112  }
4113  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4114  finished[w] = SCIP_LONGINT_MAX;
4115 
4116  /* initialize unfinished table; note that variables in GNC1 GUBs
4117  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4118  * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4119  * comes from the first variable in the GUB
4120  */
4121  assert(ngubconsGNC1 <= ngubconsGC1);
4122  unfinished[0] = 0;
4123  for( w = 1; w <= ngubconsGNC1; w++ )
4124  {
4125  liftgubconsidx = gubconsGNC1[w-1];
4126 
4127  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4128  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4129 
4130  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4131 
4132  assert(varidx >= 0 && varidx < nvars);
4133  assert(liftcoefs[varidx] == 1);
4134 
4135  min = weights[varidx];
4136  unfinished[w] = unfinished[w-1] + min;
4137 
4138 #ifndef NDEBUG
4139  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4140  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4141  {
4142  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4143  assert(varidx >= 0 && varidx < nvars);
4144  assert(liftcoefs[varidx] == 1);
4145  assert(weights[varidx] >= min );
4146  }
4147 #endif
4148  }
4149  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4150  unfinished[w] = SCIP_LONGINT_MAX;
4151 
4152  /* initialize minweights table; note that variables in GC1 GUBs
4153  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4154  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4155  * consuming) because is it has to be build using weights from C1 only.
4156  */
4157  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4158  minweights[0] = 0;
4159  for( w = 1; w <= ngubconsGC1; w++ )
4160  {
4161  liftgubconsidx = gubconsGC1[w-1];
4162 
4163  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4164  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4165  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4166 
4167  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4168 
4169  assert(varidx >= 0 && varidx < nvars);
4170  assert(liftcoefs[varidx] == 1);
4171 
4172  min = weights[varidx];
4173  minweights[w] = minweights[w-1] + min;
4174 
4175 #ifndef NDEBUG
4176  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4177  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4178  {
4179  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4180  assert(varidx >= 0 && varidx < nvars);
4181  assert(liftcoefs[varidx] == 1);
4182  assert(weights[varidx] >= min);
4183  }
4184 #endif
4185  }
4186  minweightslen = ngubconsGC1 + 1;
4187 
4188  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4189  fixedonesweight = 0;
4190  for( j = 0; j < ngubconsGC2; j++ )
4191  {
4192  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4193 
4194  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4195  assert(varidx >= 0 && varidx < nvars);
4196  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4197 
4198  fixedonesweight += weights[varidx];
4199  }
4200  assert(fixedonesweight >= 0);
4201 
4202  /* initializes right hand side of lifted valid inequality */
4203  *liftrhs = alpha0;
4204 
4205  /* sequentially up-lifts all variables in GFC1 GUBs */
4206  for( j = 0; j < ngubconsGFC1; j++ )
4207  {
4208  liftgubconsidx = gubconsGFC1[j];
4209  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4210 
4211  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4212  * compute minweight table via updated unfinished table and aleady upto date finished table;
4213  */
4214  k = 0;
4215  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4216  {
4217  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4218  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4219  assert(ngubconsGNC1 > 0);
4220 
4221  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4222  * are considered for the lifting, i.e., not capacity exceeding
4223  */
4224  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4225  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4226  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4227  assert(k >= 1);
4228 
4229  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4230  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4231  */
4232  weight = weights[liftgubvars[0]];
4233 
4234  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4235  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4236  for( w = ngubconsGNC1-1; w >= 1; w-- )
4237  {
4238  weightdiff1 = weightdiff2;
4239  weightdiff2 = unfinished[w] - weight;
4240 
4241  if( unfinished[w] < weightdiff1 )
4242  unfinished[w] = weightdiff1;
4243  else
4244  break;
4245  }
4246  ngubconsGNC1--;
4247 
4248  /* computes minweights table by combining unfished and fished tables */
4249  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4250  assert(minweights[0] == 0);
4251  }
4252  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4253  * are therefore not in the unfinished table
4254  */
4255  else
4256  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4257 
4258 #ifndef NDEBUG
4259  nliftgubC1 = k;
4260 #endif
4261  nliftgubvars = k;
4262  sumliftcoef = 0;
4263 
4264  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4265  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4266  {
4267  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4268  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4269  {
4270  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4271  weight = weights[liftvar];
4272  assert(weight > 0);
4273  assert(liftvar >= 0 && liftvar < nvars);
4274  assert(capacity - weight >= 0);
4275 
4276  /* put variable into array of variables in GUB that are considered for the lifting,
4277  * i.e., not capacity exceeding
4278  */
4279  liftgubvars[nliftgubvars] = liftvar;
4280  nliftgubvars++;
4281 
4282  /* knapsack problem is infeasible:
4283  * sets z = 0
4284  */
4285  if( capacity - fixedonesweight - weight < 0 )
4286  {
4287  z = 0;
4288  }
4289  /* knapsack problem is feasible:
4290  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4291  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4292  */
4293  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4294  {
4295  z = *liftrhs;
4296  }
4297  /* knapsack problem is feasible:
4298  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4299  */
4300  else
4301  {
4302  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4303  left = 0;
4304  right = (*liftrhs) + 1;
4305  while( left < right - 1 )
4306  {
4307  middle = (left + right) / 2;
4308  assert(0 <= middle && middle < minweightslen);
4309  if( minweights[middle] <= capacity - fixedonesweight - weight )
4310  left = middle;
4311  else
4312  right = middle;
4313  }
4314  assert(left == right - 1);
4315  assert(0 <= left && left < minweightslen);
4316  assert(minweights[left] <= capacity - fixedonesweight - weight);
4317  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4318 
4319  /* now z = left */
4320  z = left;
4321  assert(z <= *liftrhs);
4322  }
4323 
4324  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4325  liftcoef = (*liftrhs) - z;
4326  liftcoefs[liftvar] = liftcoef;
4327  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4328 
4329  /* updates activity of current valid inequality */
4330  (*cutact) += liftcoef * solvals[liftvar];
4331 
4332  /* updates sum of all lifting coefficients in GUB */
4333  sumliftcoef += liftcoefs[liftvar];
4334  }
4335  else
4336  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4337  }
4338  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4339  assert(nliftgubvars > nliftgubC1);
4340 
4341  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4342  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4343  * not needed for GF GUBs
4344  */
4345  if( sumliftcoef == 0 )
4346  {
4347  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4348  {
4349  weight = weights[liftgubvars[0]];
4350  /* update finished table and minweights table by applying special case of
4351  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4352  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4353  */
4354  for( w = minweightslen-1; w >= 1; w-- )
4355  {
4356  SCIP_Longint tmpval;
4357 
4358  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4359  finished[w] = MIN(finished[w], tmpval);
4360 
4361  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4362  minweights[w] = MIN(minweights[w], tmpval);
4363  }
4364  }
4365  else
4366  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4367 
4368  continue;
4369  }
4370 
4371  /* enlarges current minweights tables(finished, unfinished, minweights):
4372  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4373  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4374  * and sets minweights_i[w] = infinity for
4375  * w = |gubconsGC1| + sum_{k=1,2,..,i-1}sum_{j in Q_k} alpha_j+1,..,|C1| + sum_{k=1,2,..,i}sum_{j in Q_k} alpha_j
4376  */
4377  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4378  tmpsize = minweightssize;
4379  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4380  tmplen = minweightslen;
4381  tmpsize = minweightssize;
4382  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4383  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4384 
4385  /* update finished table and minweight table;
4386  * note that instead of computing minweight table from updated finished and updated unfinished table again
4387  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4388  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4389  * not needed because only finished table changed at this point and the change was "adding" one weight)
4390  *
4391  * update formular for minweight table is: minweight_i+1[w] =
4392  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4393  * formular for finished table has the same pattern.
4394  */
4395  for( w = minweightslen-1; w >= 0; w-- )
4396  {
4397  SCIP_Longint minminweight;
4398  SCIP_Longint minfinished;
4399 
4400  for( k = 0; k < nliftgubvars; k++ )
4401  {
4402  liftcoef = liftcoefs[liftgubvars[k]];
4403  weight = weights[liftgubvars[k]];
4404 
4405  if( w < liftcoef )
4406  {
4407  minfinished = MIN(finished[w], weight);
4408  minminweight = MIN(minweights[w], weight);
4409 
4410  finished[w] = minfinished;
4411  minweights[w] = minminweight;
4412  }
4413  else
4414  {
4415  SCIP_Longint tmpval;
4416 
4417  assert(w >= liftcoef);
4418 
4419  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4420  minfinished = MIN(finished[w], tmpval);
4421 
4422  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4423  minminweight = MIN(minweights[w], tmpval);
4424 
4425  finished[w] = minfinished;
4426  minweights[w] = minminweight;
4427  }
4428  }
4429  }
4430  assert(minweights[0] == 0);
4431  }
4432  assert(ngubconsGNC1 == 0);
4433 
4434  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4435  * therefore, only work with minweight table from here on
4436  */
4437 
4438  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4439  for( j = 0; j < ngubconsGC2; j++ )
4440  {
4441  liftgubconsidx = gubconsGC2[j];
4442 
4443  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4444  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4445  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4446  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4447 
4448  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4449  weight = weights[liftvar];
4450 
4451  assert(liftvar >= 0 && liftvar < nvars);
4452  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4453  assert(weight > 0);
4454 
4455  /* uses binary search to find
4456  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4457  */
4458  left = 0;
4459  right = minweightslen;
4460  while( left < right - 1 )
4461  {
4462  middle = (left + right) / 2;
4463  assert(0 <= middle && middle < minweightslen);
4464  if( minweights[middle] <= capacity - fixedonesweight + weight )
4465  left = middle;
4466  else
4467  right = middle;
4468  }
4469  assert(left == right - 1);
4470  assert(0 <= left && left < minweightslen);
4471  assert(minweights[left] <= capacity - fixedonesweight + weight);
4472  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4473 
4474  /* now z = left */
4475  z = left;
4476  assert(z >= *liftrhs);
4477 
4478  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4479  liftcoef = z - (*liftrhs);
4480  liftcoefs[liftvar] = liftcoef;
4481  assert(liftcoef >= 0);
4482 
4483  /* updates sum of weights of variables fixed to one */
4484  fixedonesweight -= weight;
4485 
4486  /* updates right-hand side of current valid inequality */
4487  (*liftrhs) += liftcoef;
4488  assert(*liftrhs >= alpha0);
4489 
4490  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4491  if( liftcoef == 0 )
4492  continue;
4493 
4494  /* updates activity of current valid inequality */
4495  (*cutact) += liftcoef * solvals[liftvar];
4496 
4497  /* enlarges current minweight table:
4498  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4499  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4500  * and sets minweights_i[w] = infinity for
4501  * w = |C1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 , ... , |C1| + sum_{k=1,2,...,i}sum_{j in Q_k} alpha_j
4502  */
4503  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4504 
4505  /* updates minweight table: minweight_i+1[w] =
4506  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4507  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4508  */
4509  for( w = minweightslen - 1; w >= 0; w-- )
4510  {
4511  if( w < liftcoef )
4512  {
4513  min = MIN(minweights[w], weight);
4514  minweights[w] = min;
4515  }
4516  else
4517  {
4518  SCIP_Longint tmpval;
4519 
4520  assert(w >= liftcoef);
4521 
4522  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4523  min = MIN(minweights[w], tmpval);
4524  minweights[w] = min;
4525  }
4526  }
4527  }
4528  assert(fixedonesweight == 0);
4529  assert(*liftrhs >= alpha0);
4530 
4531  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4532  for( j = 0; j < ngubconsGR; j++ )
4533  {
4534  liftgubconsidx = gubconsGR[j];
4535 
4536  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4537  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4538 
4539  sumliftcoef = 0;
4540  nliftgubvars = 0;
4541  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4542  {
4543  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4544  {
4545  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4546  weight = weights[liftvar];
4547  assert(weight > 0);
4548  assert(liftvar >= 0 && liftvar < nvars);
4549  assert(capacity - weight >= 0);
4550  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4551 
4552  /* put variable into array of variables in GUB that are considered for the lifting,
4553  * i.e., not capacity exceeding
4554  */
4555  liftgubvars[nliftgubvars] = liftvar;
4556  nliftgubvars++;
4557 
4558  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4559  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4560  */
4561  if( minweights[*liftrhs] <= capacity - weight )
4562  {
4563  z = *liftrhs;
4564  }
4565  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4566  */
4567  else
4568  {
4569  left = 0;
4570  right = (*liftrhs) + 1;
4571  while( left < right - 1 )
4572  {
4573  middle = (left + right) / 2;
4574  assert(0 <= middle && middle < minweightslen);
4575  if( minweights[middle] <= capacity - weight )
4576  left = middle;
4577  else
4578  right = middle;
4579  }
4580  assert(left == right - 1);
4581  assert(0 <= left && left < minweightslen);
4582  assert(minweights[left] <= capacity - weight);
4583  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4584 
4585  /* now z = left */
4586  z = left;
4587  assert(z <= *liftrhs);
4588  }
4589  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4590  liftcoef = (*liftrhs) - z;
4591  liftcoefs[liftvar] = liftcoef;
4592  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4593 
4594  /* updates activity of current valid inequality */
4595  (*cutact) += liftcoef * solvals[liftvar];
4596 
4597  /* updates sum of all lifting coefficients in GUB */
4598  sumliftcoef += liftcoefs[liftvar];
4599  }
4600  else
4601  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4602  }
4603  assert(nliftgubvars >= 1); /* at least one variable is in R */
4604 
4605  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4606  if( sumliftcoef == 0 )
4607  continue;
4608 
4609  /* updates minweight table: minweight_i+1[w] =
4610  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4611  */
4612  for( w = *liftrhs; w >= 0; w-- )
4613  {
4614  for( k = 0; k < nliftgubvars; k++ )
4615  {
4616  liftcoef = liftcoefs[liftgubvars[k]];
4617  weight = weights[liftgubvars[k]];
4618 
4619  if( w < liftcoef )
4620  {
4621  min = MIN(minweights[w], weight);
4622  minweights[w] = min;
4623  }
4624  else
4625  {
4626  SCIP_Longint tmpval;
4627 
4628  assert(w >= liftcoef);
4629 
4630  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4631  min = MIN(minweights[w], tmpval);
4632  minweights[w] = min;
4633  }
4634  }
4635  }
4636  assert(minweights[0] == 0);
4637  }
4638 
4639  /* frees temporary memory */
4640  SCIPfreeBufferArray(scip, &minweights);
4641  SCIPfreeBufferArray(scip, &finished);
4642  SCIPfreeBufferArray(scip, &unfinished);
4643  SCIPfreeBufferArray(scip, &liftgubvars);
4644  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4645  SCIPfreeBufferArray(scip, &gubconsGNC1);
4646 
4647  return SCIP_OKAY;
4648 }
4649 
4650 /** lifts given minimal cover inequality
4651  * \f[
4652  * \sum_{j \in C} x_j \leq |C| - 1
4653  * \f]
4654  * valid for
4655  * \f[
4656  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4657  * \f]
4658  * to a valid inequality
4659  * \f[
4660  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4661  * \f]
4662  * for
4663  * \f[
4664  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4665  * \f]
4666  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4667  */
4668 static
4670  SCIP* scip, /**< SCIP data structure */
4671  SCIP_VAR** vars, /**< variables in knapsack constraint */
4672  int nvars, /**< number of variables in knapsack constraint */
4673  int ntightened, /**< number of variables with tightened upper bound */
4674  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4675  SCIP_Longint capacity, /**< capacity of knapsack */
4676  SCIP_Real* solvals, /**< solution values of all problem variables */
4677  int* covervars, /**< cover variables */
4678  int* noncovervars, /**< noncover variables */
4679  int ncovervars, /**< number of cover variables */
4680  int nnoncovervars, /**< number of noncover variables */
4681  SCIP_Longint coverweight, /**< weight of cover */
4682  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4683  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4684  )
4685 {
4686  SCIP_Longint* maxweightsums;
4687  SCIP_Longint* intervalends;
4688  SCIP_Longint* rhos;
4689  SCIP_Real* sortkeys;
4690  SCIP_Longint lambda;
4691  int j;
4692  int h;
4693 
4694  assert(scip != NULL);
4695  assert(vars != NULL);
4696  assert(nvars >= 0);
4697  assert(weights != NULL);
4698  assert(capacity >= 0);
4699  assert(solvals != NULL);
4700  assert(covervars != NULL);
4701  assert(noncovervars != NULL);
4702  assert(ncovervars > 0 && ncovervars <= nvars);
4703  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4704  assert(ncovervars + nnoncovervars == nvars - ntightened);
4705  assert(liftcoefs != NULL);
4706  assert(cutact != NULL);
4707 
4708  /* allocates temporary memory */
4709  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4710  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4711  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4712  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4713 
4714  /* initializes data structures */
4715  BMSclearMemoryArray(liftcoefs, nvars);
4716  *cutact = 0.0;
4717 
4718  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4719  * and calculates activity of current valid inequality
4720  */
4721  for( j = 0; j < ncovervars; j++ )
4722  {
4723  assert(liftcoefs[covervars[j]] == 0.0);
4724  liftcoefs[covervars[j]] = 1.0;
4725  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4726  (*cutact) += solvals[covervars[j]];
4727  }
4728  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4729 
4730  /* calculates weight excess of cover C */
4731  lambda = coverweight - capacity;
4732  assert(lambda > 0);
4733 
4734  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4735  maxweightsums[0] = 0;
4736  for( h = 1; h <= ncovervars; h++ )
4737  {
4738  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4739  intervalends[h-1] = maxweightsums[h] - lambda;
4740  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4741  }
4742 
4743  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4744  for( j = 0; j < nnoncovervars; j++ )
4745  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4746  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4747 
4748  /* calculates lifting coefficient for all variables in N\C */
4749  h = 0;
4750  for( j = 0; j < nnoncovervars; j++ )
4751  {
4752  int liftvar;
4753  SCIP_Longint weight;
4754  SCIP_Real liftcoef;
4755 
4756  liftvar = noncovervars[j];
4757  weight = weights[liftvar];
4758 
4759  while( intervalends[h] < weight )
4760  h++;
4761 
4762  if( h == 0 )
4763  liftcoef = h;
4764  else
4765  {
4766  if( weight <= intervalends[h-1] + rhos[h] )
4767  {
4768  SCIP_Real tmp1;
4769  SCIP_Real tmp2;
4770  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4771  tmp2 = (SCIP_Real) rhos[1];
4772  liftcoef = h - ( tmp1 / tmp2 );
4773  }
4774  else
4775  liftcoef = h;
4776  }
4777 
4778  /* sets lifting coefficient */
4779  assert(liftcoefs[liftvar] == 0.0);
4780  liftcoefs[liftvar] = liftcoef;
4781 
4782  /* updates activity of current valid inequality */
4783  (*cutact) += liftcoef * solvals[liftvar];
4784  }
4785 
4786  /* frees temporary memory */
4787  SCIPfreeBufferArray(scip, &rhos);
4788  SCIPfreeBufferArray(scip, &intervalends);
4789  SCIPfreeBufferArray(scip, &maxweightsums);
4790  SCIPfreeBufferArray(scip, &sortkeys);
4791 
4792  return SCIP_OKAY;
4793 }
4794 
4795 
4796 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4797  * given knapsack problem
4798 */
4799 static
4801  SCIP* scip, /**< SCIP data structure */
4802  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4803  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4804  SCIP_VAR** vars, /**< variables in knapsack constraint */
4805  int nvars, /**< number of variables in knapsack constraint */
4806  int ntightened, /**< number of variables with tightened upper bound */
4807  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4808  SCIP_Longint capacity, /**< capacity of knapsack */
4809  SCIP_Real* solvals, /**< solution values of all problem variables */
4810  int* mincovervars, /**< mincover variables */
4811  int* nonmincovervars, /**< nonmincover variables */
4812  int nmincovervars, /**< number of mincover variables */
4813  int nnonmincovervars, /**< number of nonmincover variables */
4814  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4815  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4816  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4817  int* ncuts /**< pointer to add up the number of found cuts */
4818  )
4819 {
4820  int* varsC1;
4821  int* varsC2;
4822  int* varsF;
4823  int* varsR;
4824  int nvarsC1;
4825  int nvarsC2;
4826  int nvarsF;
4827  int nvarsR;
4828  SCIP_Real cutact;
4829  int* liftcoefs;
4830  int liftrhs;
4831 
4832  assert( cutoff != NULL );
4833  *cutoff = FALSE;
4834 
4835  /* allocates temporary memory */
4836  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4837  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4838  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4839  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4840  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4841 
4842  /* gets partition (C_1,C_2) of C, i.e. C_1 & C_2 = C and C_1 cap C_2 = emptyset, with C_1 not empty; chooses partition
4843  * as follows
4844  * C_2 = { j in C : x*_j = 1 } and
4845  * C_1 = C\C_2
4846  */
4847  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4848  assert(nvarsC1 + nvarsC2 == nmincovervars);
4849  assert(nmincovervars > 0);
4850  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4851 
4852  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4853  if( nvarsC1 < 2 && nvarsC2 > 0)
4854  {
4855  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4856  assert(nvarsC1 >= 1);
4857  }
4858  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4859 
4860  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4861  * R = { j in N\C : x*_j = 0 } and
4862  * F = (N\C)\F
4863  */
4864  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4865  assert(nvarsF + nvarsR == nnonmincovervars);
4866  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4867 
4868  /* lift cuts without GUB information */
4869  if( gubset == NULL )
4870  {
4871  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4872  * lifting procedure
4873  */
4874  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4875 
4876  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4877  *
4878  * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j }
4879  *
4880  * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4881  *
4882  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4883  *
4884  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4885  * up-lifting for the variables in R according to the second level lifting sequence
4886  */
4887  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4888  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4889  }
4890  /* lift cuts with GUB information */
4891  else
4892  {
4893  int* gubconsGC1;
4894  int* gubconsGC2;
4895  int* gubconsGFC1;
4896  int* gubconsGR;
4897  int ngubconsGC1;
4898  int ngubconsGC2;
4899  int ngubconsGFC1;
4900  int ngubconsGR;
4901  int ngubconss;
4902  int nconstightened;
4903  int maxgubvarssize;
4904 
4905  assert(nvars == gubset->nvars);
4906 
4907  ngubconsGC1 = 0;
4908  ngubconsGC2 = 0;
4909  ngubconsGFC1 = 0;
4910  ngubconsGR = 0;
4911  ngubconss = gubset->ngubconss;
4912  nconstightened = 0;
4913  maxgubvarssize = 0;
4914 
4915  /* allocates temporary memory */
4916  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4917  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4918  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4919  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4920 
4921  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4922  * the GUBs for the sequential GUB wise lifting procedure
4923  */
4924  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4925  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4926  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4927 
4928  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4929  *
4930  * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j,
4931  * sum_{j in Q_i} x_j <= 1, forall i in I }
4932  *
4933  * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4934  *
4935  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0, sum_{j in Q_i} x_j <= 1, forall i in I },
4936  *
4937  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4938  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4939  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4940  */
4941  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4942  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4943  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4944 
4945  /* frees temporary memory */
4946  SCIPfreeBufferArray(scip, &gubconsGR);
4947  SCIPfreeBufferArray(scip, &gubconsGFC1);
4948  SCIPfreeBufferArray(scip, &gubconsGC2);
4949  SCIPfreeBufferArray(scip, &gubconsGC1);
4950  }
4951 
4952  /* checks, if lifting yielded a violated cut */
4953  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4954  {
4955  SCIP_ROW* row;
4956  char name[SCIP_MAXSTRLEN];
4957  int j;
4958 
4959  /* creates LP row */
4960  assert( cons == NULL || sepa == NULL );
4961  if ( cons != NULL )
4962  {
4963  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4964  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4965  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4966  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4967  }
4968  else if ( sepa != NULL )
4969  {
4970  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4971  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4972  }
4973  else
4974  {
4975  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4976  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4977  }
4978 
4979  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4980  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4981  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4982  for( j = 0; j < nvarsC1; j++ )
4983  {
4984  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4985  }
4986  for( j = 0; j < nvarsC2; j++ )
4987  {
4988  if( liftcoefs[varsC2[j]] > 0 )
4989  {
4990  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4991  }
4992  }
4993  for( j = 0; j < nvarsF; j++ )
4994  {
4995  if( liftcoefs[varsF[j]] > 0 )
4996  {
4997  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4998  }
4999  }
5000  for( j = 0; j < nvarsR; j++ )
5001  {
5002  if( liftcoefs[varsR[j]] > 0 )
5003  {
5004  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5005  }
5006  }
5007  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5008 
5009  /* checks, if cut is violated enough */
5010  if( SCIPisCutEfficacious(scip, sol, row) )
5011  {
5012  if( cons != NULL )
5013  {
5014  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5015  }
5016  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5017  (*ncuts)++;
5018  }
5019  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5020  }
5021 
5022  /* frees temporary memory */
5023  SCIPfreeBufferArray(scip, &liftcoefs);
5024  SCIPfreeBufferArray(scip, &varsR);
5025  SCIPfreeBufferArray(scip, &varsF);
5026  SCIPfreeBufferArray(scip, &varsC2);
5027  SCIPfreeBufferArray(scip, &varsC1);
5028 
5029  return SCIP_OKAY;
5030 }
5031 
5032 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5033 static
5035  SCIP* scip, /**< SCIP data structure */
5036  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5037  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5038  SCIP_VAR** vars, /**< variables in knapsack constraint */
5039  int nvars, /**< number of variables in knapsack constraint */
5040  int ntightened, /**< number of variables with tightened upper bound */
5041  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5042  SCIP_Longint capacity, /**< capacity of knapsack */
5043  SCIP_Real* solvals, /**< solution values of all problem variables */
5044  int* feassetvars, /**< variables in feasible set */
5045  int* nonfeassetvars, /**< variables not in feasible set */
5046  int nfeassetvars, /**< number of variables in feasible set */
5047  int nnonfeassetvars, /**< number of variables not in feasible set */
5048  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5049  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5050  int* ncuts /**< pointer to add up the number of found cuts */
5051  )
5052 {
5053  int* varsT1;
5054  int* varsT2;
5055  int* varsF;
5056  int* varsR;
5057  int* liftcoefs;
5058  SCIP_Real cutact;
5059  int nvarsT1;
5060  int nvarsT2;
5061  int nvarsF;
5062  int nvarsR;
5063  int liftrhs;
5064  int j;
5065 
5066  assert( cutoff != NULL );
5067  *cutoff = FALSE;
5068 
5069  /* allocates temporary memory */
5070  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5071  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5072  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5073  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5074  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5075 
5076  /* gets partition (T_1,T_2) of T, i.e. T_1 & T_2 = T and T_1 cap T_2 = emptyset, with T_1 not empty; chooses partition
5077  * as follows
5078  * T_2 = { j in T : x*_j = 1 } and
5079  * T_1 = T\T_2
5080  */
5081  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5082  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5083 
5084  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5085  if( nvarsT1 == 0 && nvarsT2 > 0)
5086  {
5087  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5088  assert(nvarsT1 == 1);
5089  }
5090  assert(nvarsT2 == 0 || nvarsT1 > 0);
5091 
5092  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5093  * R = { j in N\T : x*_j = 0 } and
5094  * F = (N\T)\F
5095  */
5096  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5097  assert(nvarsF + nvarsR == nnonfeassetvars);
5098  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5099 
5100  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5101  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5102  * is included in the sorting routine)
5103  */
5104  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5105 
5106  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5107  *
5108  * S^0 = { x in {0,1}^|T_1| : sum_{j in T_1} a_j x_j <= a_0 - sum_{j in T_2} a_j }
5109  *
5110  * to a valid inequality sum_{j in T_1} x_j + sum_{j in N\T_1} alpha_j x_j <= |T_1| + sum_{j in T_2} alpha_j for
5111  *
5112  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5113  *
5114  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5115  * up-lifting for the variabels in R according to the second level lifting sequence
5116  */
5117  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5118  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5119 
5120  /* checks, if lifting yielded a violated cut */
5121  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5122  {
5123  SCIP_ROW* row;
5124  char name[SCIP_MAXSTRLEN];
5125 
5126  /* creates LP row */
5127  assert( cons == NULL || sepa == NULL );
5128  if( cons != NULL )
5129  {
5130  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5131  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5132  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5133  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5134  }
5135  else if ( sepa != NULL )
5136  {
5137  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5138  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5139  }
5140  else
5141  {
5142  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5143  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5144  }
5145 
5146  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5147  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5148  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5149  for( j = 0; j < nvarsT1; j++ )
5150  {
5151  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5152  }
5153  for( j = 0; j < nvarsT2; j++ )
5154  {
5155  if( liftcoefs[varsT2[j]] > 0 )
5156  {
5157  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5158  }
5159  }
5160  for( j = 0; j < nvarsF; j++ )
5161  {
5162  if( liftcoefs[varsF[j]] > 0 )
5163  {
5164  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5165  }
5166  }
5167  for( j = 0; j < nvarsR; j++ )
5168  {
5169  if( liftcoefs[varsR[j]] > 0 )
5170  {
5171  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5172  }
5173  }
5174  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5175 
5176  /* checks, if cut is violated enough */
5177  if( SCIPisCutEfficacious(scip, sol, row) )
5178  {
5179  if( cons != NULL )
5180  {
5181  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5182  }
5183  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5184  (*ncuts)++;
5185  }
5186  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5187  }
5188 
5189  /* frees temporary memory */
5190  SCIPfreeBufferArray(scip, &liftcoefs);
5191  SCIPfreeBufferArray(scip, &varsR);
5192  SCIPfreeBufferArray(scip, &varsF);
5193  SCIPfreeBufferArray(scip, &varsT2);
5194  SCIPfreeBufferArray(scip, &varsT1);
5195 
5196  return SCIP_OKAY;
5197 }
5198 
5199 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5200 static
5202  SCIP* scip, /**< SCIP data structure */
5203  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5204  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5205  SCIP_VAR** vars, /**< variables in knapsack constraint */
5206  int nvars, /**< number of variables in knapsack constraint */
5207  int ntightened, /**< number of variables with tightened upper bound */
5208  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5209  SCIP_Longint capacity, /**< capacity of knapsack */
5210  SCIP_Real* solvals, /**< solution values of all problem variables */
5211  int* mincovervars, /**< mincover variables */
5212  int* nonmincovervars, /**< nonmincover variables */
5213  int nmincovervars, /**< number of mincover variables */
5214  int nnonmincovervars, /**< number of nonmincover variables */
5215  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5216  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5217  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5218  int* ncuts /**< pointer to add up the number of found cuts */
5219  )
5220 {
5221  SCIP_Real* realliftcoefs;
5222  SCIP_Real cutact;
5223  int liftrhs;
5224 
5225  assert( cutoff != NULL );
5226  *cutoff = FALSE;
5227  cutact = 0.0;
5228 
5229  /* allocates temporary memory */
5230  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5231 
5232  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5233  *
5234  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5235  *
5236  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5237  *
5238  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5239  *
5240  * uses superadditive up-lifting for the variables in N\C.
5241  */
5242  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5243  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5244  liftrhs = nmincovervars - 1;
5245 
5246  /* checks, if lifting yielded a violated cut */
5247  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5248  {
5249  SCIP_ROW* row;
5250  char name[SCIP_MAXSTRLEN];
5251  int j;
5252 
5253  /* creates LP row */
5254  assert( cons == NULL || sepa == NULL );
5255  if ( cons != NULL )
5256  {
5257  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5258  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5259  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5260  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5261  }
5262  else if ( sepa != NULL )
5263  {
5264  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5265  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5266  }
5267  else
5268  {
5269  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5270  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5271  }
5272 
5273  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5274  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5275  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5276  for( j = 0; j < nmincovervars; j++ )
5277  {
5278  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5279  }
5280  for( j = 0; j < nnonmincovervars; j++ )
5281  {
5282  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5283  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5284  {
5285  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5286  }
5287  }
5288  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5289 
5290  /* checks, if cut is violated enough */
5291  if( SCIPisCutEfficacious(scip, sol, row) )
5292  {
5293  if( cons != NULL )
5294  {
5295  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5296  }
5297  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5298  (*ncuts)++;
5299  }
5300  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5301  }
5302 
5303  /* frees temporary memory */
5304  SCIPfreeBufferArray(scip, &realliftcoefs);
5305 
5306  return SCIP_OKAY;
5307 }
5308 
5309 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5310  * to be in C, i.e. in the order of non-increasing (1 - x*_j)/a_j, if the transformed separation problem was used to find
5311  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5312  * note that all variables with x*_j = 1 will be removed last
5313  */
5314 static
5316  SCIP* scip, /**< SCIP data structure */
5317  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5318  SCIP_Longint capacity, /**< capacity of knapsack */
5319  SCIP_Real* solvals, /**< solution values of all problem variables */
5320  int* covervars, /**< pointer to store cover variables */
5321  int* noncovervars, /**< pointer to store noncover variables */
5322  int* ncovervars, /**< pointer to store number of cover variables */
5323  int* nnoncovervars, /**< pointer to store number of noncover variables */
5324  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5325  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5326  )
5327 {
5328  SORTKEYPAIR** sortkeypairs;
5329  SORTKEYPAIR** sortkeypairssorted;
5330  SCIP_Longint minweight;
5331  int nsortkeypairs;
5332  int minweightidx;
5333  int j;
5334  int k;
5335 
5336  assert(scip != NULL);
5337  assert(covervars != NULL);
5338  assert(noncovervars != NULL);
5339  assert(ncovervars != NULL);
5340  assert(*ncovervars > 0);
5341  assert(nnoncovervars != NULL);
5342  assert(*nnoncovervars >= 0);
5343  assert(coverweight != NULL);
5344  assert(*coverweight > 0);
5345  assert(*coverweight > capacity);
5346 
5347  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5348  * order */
5349  nsortkeypairs = *ncovervars;
5350  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5351  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5352 
5353  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5354  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5355  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5356  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5357  */
5358  assert(*ncovervars == nsortkeypairs);
5359  if( modtransused )
5360  {
5361  for( j = 0; j < *ncovervars; j++ )
5362  {
5363  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5364  sortkeypairssorted[j] = sortkeypairs[j];
5365 
5366  sortkeypairs[j]->key1 = solvals[covervars[j]];
5367  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5368  }
5369  }
5370  else
5371  {
5372  for( j = 0; j < *ncovervars; j++ )
5373  {
5374  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5375  sortkeypairssorted[j] = sortkeypairs[j];
5376 
5377  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5378  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5379  }
5380  }
5381  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5382 
5383  /* gets j' with a_j' = min{ a_j : j in C } */
5384  minweightidx = 0;
5385  minweight = weights[covervars[minweightidx]];
5386  for( j = 1; j < *ncovervars; j++ )
5387  {
5388  if( weights[covervars[j]] <= minweight )
5389  {
5390  minweightidx = j;
5391  minweight = weights[covervars[minweightidx]];
5392  }
5393  }
5394  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5395  assert(minweight > 0 && minweight <= *coverweight);
5396 
5397  j = 0;
5398  /* removes variables from C until the remaining variables form a minimal cover */
5399  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5400  {
5401  assert(minweightidx >= j);
5402  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5403 
5404  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5405  if( (*coverweight) - weights[covervars[j]] <= capacity )
5406  {
5407  ++j;
5408  continue;
5409  }
5410 
5411  /* adds j to N\C */
5412  noncovervars[*nnoncovervars] = covervars[j];
5413  (*nnoncovervars)++;
5414 
5415  /* removes j from C */
5416  (*coverweight) -= weights[covervars[j]];
5417  for( k = j; k < (*ncovervars) - 1; k++ )
5418  covervars[k] = covervars[k+1];
5419  (*ncovervars)--;
5420 
5421  /* updates j' with a_j' = min{ a_j : j in C } */
5422  if( j == minweightidx )
5423  {
5424  minweightidx = 0;
5425  minweight = weights[covervars[minweightidx]];
5426  for( k = 1; k < *ncovervars; k++ )
5427  {
5428  if( weights[covervars[k]] <= minweight )
5429  {
5430  minweightidx = k;
5431  minweight = weights[covervars[minweightidx]];
5432  }
5433  }
5434  assert(minweight > 0 && minweight <= *coverweight);
5435  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5436  }
5437  else
5438  {
5439  assert(minweightidx > j);
5440  minweightidx--;
5441  }
5442  /* j needs to stay the same */
5443  }
5444  assert((*coverweight) > capacity);
5445  assert((*coverweight) - minweight <= capacity);
5446 
5447  /* frees temporary memory */
5448  for( j = nsortkeypairs-1; j >= 0; j-- )
5449  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5450  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5451  SCIPfreeBufferArray(scip, &sortkeypairs);
5452 
5453  return SCIP_OKAY;
5454 }
5455 
5456 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5457  * they were chosen to be in C_init:
5458  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5459  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5460  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5461  * and all subsequent feasible sets.
5462  */
5463 static
5465  SCIP* scip, /**< SCIP data structure */
5466  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5467  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5468  SCIP_VAR** vars, /**< variables in knapsack constraint */
5469  int nvars, /**< number of variables in knapsack constraint */
5470  int ntightened, /**< number of variables with tightened upper bound */
5471  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5472  SCIP_Longint capacity, /**< capacity of knapsack */
5473  SCIP_Real* solvals, /**< solution values of all problem variables */
5474  int* covervars, /**< pointer to store cover variables */
5475  int* noncovervars, /**< pointer to store noncover variables */
5476  int* ncovervars, /**< pointer to store number of cover variables */
5477  int* nnoncovervars, /**< pointer to store number of noncover variables */
5478  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5479  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5480  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5481  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5482  int* ncuts /**< pointer to add up the number of found cuts */
5483  )
5484 {
5485  SCIP_Real* sortkeys;
5486  int j;
5487  int k;
5488 
5489  assert(scip != NULL);
5490  assert(covervars != NULL);
5491  assert(noncovervars != NULL);
5492  assert(ncovervars != NULL);
5493  assert(*ncovervars > 0);
5494  assert(nnoncovervars != NULL);
5495  assert(*nnoncovervars >= 0);
5496  assert(coverweight != NULL);
5497  assert(*coverweight > 0);
5498  assert(*coverweight > capacity);
5499  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5500  assert(cutoff != NULL);
5501 
5502  *cutoff = FALSE;
5503 
5504  /* allocates temporary memory */
5505  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5506 
5507  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5508  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5509  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5510  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5511  */
5512  if( modtransused )
5513  {
5514  for( j = 0; j < *ncovervars; j++ )
5515  {
5516  sortkeys[j] = solvals[covervars[j]];
5517  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5518  }
5519  }
5520  else
5521  {
5522  for( j = 0; j < *ncovervars; j++ )
5523  {
5524  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5525  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5526  }
5527  }
5528  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5529 
5530  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5531  * in addition to an extended weight inequality this gives cardinality inequalities */
5532  while( *ncovervars >= 2 )
5533  {
5534  /* adds first element of C_init to N\C_init */
5535  noncovervars[*nnoncovervars] = covervars[0];
5536  (*nnoncovervars)++;
5537 
5538  /* removes first element from C_init */
5539  (*coverweight) -= weights[covervars[0]];
5540  for( k = 0; k < (*ncovervars) - 1; k++ )
5541  covervars[k] = covervars[k+1];
5542  (*ncovervars)--;
5543 
5544  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5545  if( (*coverweight) <= capacity )
5546  {
5547  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5548  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5549  }
5550 
5551  /* stop if cover is too large */
5552  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5553  break;
5554  }
5555 
5556  /* frees temporary memory */
5557  SCIPfreeBufferArray(scip, &sortkeys);
5558 
5559  return SCIP_OKAY;
5560 }
5561 
5562 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5564  SCIP* scip, /**< SCIP data structure */
5565  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5566  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5567  SCIP_VAR** vars, /**< variables in knapsack constraint */
5568  int nvars, /**< number of variables in knapsack constraint */
5569  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5570  SCIP_Longint capacity, /**< capacity of knapsack */
5571  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5572  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5573  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5574  int* ncuts /**< pointer to add up the number of found cuts */
5575  )
5576 {
5577  SCIP_Real* solvals;
5578  int* covervars;
5579  int* noncovervars;
5580  SCIP_Bool coverfound;
5581  SCIP_Bool fractional;
5582  SCIP_Bool modtransused;
5583  SCIP_Longint coverweight;
5584  int ncovervars;
5585  int nnoncovervars;
5586  int ntightened;
5587 
5588  assert(scip != NULL);
5589  assert(capacity >= 0);
5590  assert(cutoff != NULL);
5591  assert(ncuts != NULL);
5592 
5593  *cutoff = FALSE;
5594 
5595  if( nvars == 0 )
5596  return SCIP_OKAY;
5597 
5598  assert(vars != NULL);
5599  assert(nvars > 0);
5600  assert(weights != NULL);
5601 
5602  /* increase age of constraint (age is reset to zero, if a cut was found) */
5603  if( cons != NULL )
5604  {
5605  SCIP_CALL( SCIPincConsAge(scip, cons) );
5606  }
5607 
5608  /* allocates temporary memory */
5609  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5610  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5611  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5612 
5613  /* gets solution values of all problem variables */
5614  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5615 
5616 #ifdef SCIP_DEBUG
5617  {
5618  int i;
5619 
5620  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5621  cons == NULL ? "-" : SCIPconsGetName(cons));
5622  for( i = 0; i < nvars; ++i )
5623  {
5624  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5625  }
5626  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5627  }
5628 #endif
5629 
5630  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5631  */
5632  if( usegubs )
5633  {
5634  SCIP_GUBSET* gubset;
5635 
5636  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5637 
5638  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5639  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5640 
5641  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5642  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5643  assert(gubset->ngubconss <= nvars);
5644 
5645  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5646  * MODIFIED transformed separation problem and taking into account the following fixing:
5647  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5648  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5649  * if one exists
5650  */
5651  modtransused = TRUE;
5652  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5653  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5654 
5655  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5656 
5657  /* if x* is not fractional we stop the separation routine */
5658  if( !fractional )
5659  {
5660  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5661 
5662  /* frees memory for GUB set data structure */
5663  GUBsetFree(scip, &gubset);
5664 
5665  goto TERMINATE;
5666  }
5667 
5668  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5669  if( coverfound )
5670  {
5671  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5672  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5673  */
5674  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5675  &nnoncovervars, &coverweight, modtransused) );
5676 
5677  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5678  if( gubset->ngubconss < nvars )
5679  {
5680  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5681  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5682  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5683  }
5684  else
5685  {
5686  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5687  * GUB information
5688  */
5689  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5690  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5691  }
5692  }
5693 
5694  /* frees memory for GUB set data structure */
5695  GUBsetFree(scip, &gubset);
5696  }
5697  else
5698  {
5699  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5700  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5701  */
5702 
5703  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5704  * MODIFIED transformed separation problem and taking into account the following fixing:
5705  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5706  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5707  * if one exists
5708  */
5709  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5710  modtransused = TRUE;
5711  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5712  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5713  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5714 
5715  /* if x* is not fractional we stop the separation routine */
5716  if( !fractional )
5717  goto TERMINATE;
5718 
5719  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5720  if( coverfound )
5721  {
5722  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5723  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5724  */
5725  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5726  &nnoncovervars, &coverweight, modtransused) );
5727 
5728  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5729  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5730  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5731 
5732  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5733  {
5734  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5735  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5736  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5737  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5738  }
5739  }
5740  }
5741 
5742  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5743  if ( ! (*cutoff) )
5744  {
5745  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5746  * transformed separation problem and taking into account the following fixing:
5747  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5748  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5749  * if one exists
5750  */
5751  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5752  modtransused = FALSE;
5753  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5754  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5755  assert(fractional);
5756  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5757 
5758  /* if no cover was found we stop the separation routine */
5759  if( coverfound )
5760  {
5761  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5762  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5763  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5764  */
5765  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5766  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5767  }
5768  }
5769 
5770  TERMINATE:
5771  /* frees temporary memory */
5772  SCIPfreeBufferArray(scip, &noncovervars);
5773  SCIPfreeBufferArray(scip, &covervars);
5774  SCIPfreeBufferArray(scip, &solvals);
5775 
5776  return SCIP_OKAY;
5777 }
5778 
5779 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5781  SCIP* scip, /**< SCIP data structure */
5782  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5783  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5784  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5785  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5786  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5787  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5788  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5789  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5790  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5791  int* ncuts /**< pointer to add up the number of found cuts */
5792  )
5793 {
5794  SCIP_VAR** binvars;
5795  SCIP_VAR** consvars;
5796  SCIP_Real* binvals;
5797  SCIP_Longint* consvals;
5798  SCIP_Longint minact;
5799  SCIP_Longint maxact;
5800  SCIP_Real intscalar;
5801  SCIP_Bool success;
5802  int nbinvars;
5803  int nconsvars;
5804  int i;
5805 
5806  int* tmpindices;
5807  int tmp;
5808  SCIP_CONSHDLR* conshdlr;
5809  SCIP_CONSHDLRDATA* conshdlrdata;
5810  SCIP_Bool noknapsackconshdlr;
5811  SCIP_Bool usegubs;
5812 
5813  assert(nknapvars > 0);
5814  assert(knapvars != NULL);
5815  assert(cutoff != NULL);
5816 
5817  tmpindices = NULL;
5818 
5819  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5820  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5821 
5822  binvars = SCIPgetVars(scip);
5823 
5824  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5825  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5826 
5827  *cutoff = FALSE;
5828 
5829  if( nbinvars == 0 )
5830  return SCIP_OKAY;
5831 
5832  /* set up data structures */
5833  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5834  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5835 
5836  /* get conshdlrdata to use cleared memory */
5837  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5838  if( conshdlr == NULL )
5839  {
5840  noknapsackconshdlr = TRUE;
5841  usegubs = DEFAULT_USEGUBS;
5842 
5843  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5844  BMSclearMemoryArray(binvals, nbinvars);
5845  }
5846  else
5847  {
5848  noknapsackconshdlr = FALSE;
5849  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5850  assert(conshdlrdata != NULL);
5851  usegubs = conshdlrdata->usegubs;
5852 
5853  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5854 
5855  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5856  * change their types to SCIP_VARTYPE_BINARY during presolving
5857  */
5858  if( conshdlrdata->reals1size == 0 )
5859  {
5860  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5861  conshdlrdata->reals1size = 1;
5862  conshdlrdata->reals1[0] = 0.0;
5863  }
5864 
5865  assert(conshdlrdata->reals1size > 0);
5866 
5867  /* next if condition should normally not be true, because it means that presolving has created more binary
5868  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5869  * transform all integers into their binary representation then it maybe happens
5870  */
5871  if( conshdlrdata->reals1size < nbinvars )
5872  {
5873  int oldsize = conshdlrdata->reals1size;
5874 
5875  conshdlrdata->reals1size = nbinvars;
5876  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5877  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5878  }
5879  binvals = conshdlrdata->reals1;
5880 
5881  /* check for cleared array, all entries have to be zero */
5882 #ifndef NDEBUG
5883  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5884  {
5885  assert(binvals[tmp] == 0);
5886  }
5887 #endif
5888  }
5889 
5890  tmp = 0;
5891 
5892  /* relax continuous knapsack constraint:
5893  * 1. make all variables binary:
5894  * if x_j is continuous or integer variable substitute:
5895  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5896  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5897  * 2. convert coefficients of all variables to positive integers:
5898  * - scale all coefficients a_j to a~_j integral
5899  * - substitute x~_j = 1 - x_j if a~_j < 0
5900  */
5901 
5902  /* replace integer and continuous variables with binary variables */
5903  for( i = 0; i < nknapvars; i++ )
5904  {
5905  SCIP_VAR* var;
5906 
5907  var = knapvars[i];
5908 
5909  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5910  {
5911  SCIP_Real solval;
5912  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5913 
5914  solval = SCIPgetSolVal(scip, sol, var);
5915 
5916  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5917  if( SCIPisFeasLT(scip, solval, 0.0 )
5918  || SCIPisFeasGT(scip, solval, 1.0) )
5919  {
5920  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5921  solval, SCIPvarGetName(var));
5922  goto TERMINATE;
5923  }
5924 
5925  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5926  if( !noknapsackconshdlr )
5927  {
5928  assert(tmpindices != NULL);
5929 
5930  tmpindices[tmp] = SCIPvarGetProbindex(var);
5931  ++tmp;
5932  }
5933  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5934  }
5935  else if( valscale * knapvals[i] > 0.0 )
5936  {
5937  SCIP_VAR** zvlb;
5938  SCIP_Real* bvlb;
5939  SCIP_Real* dvlb;
5940  SCIP_Real bestlbsol;
5941  int bestlbtype;
5942  int nvlb;
5943  int j;
5944 
5945  /* a_j > 0: substitution with lb or vlb */
5946  nvlb = SCIPvarGetNVlbs(var);
5947  zvlb = SCIPvarGetVlbVars(var);
5948  bvlb = SCIPvarGetVlbCoefs(var);
5949  dvlb = SCIPvarGetVlbConstants(var);
5950 
5951  /* search for lb or vlb with maximal bound value */
5952  bestlbsol = SCIPvarGetLbGlobal(var);
5953  bestlbtype = -1;
5954  for( j = 0; j < nvlb; j++ )
5955  {
5956  /* use only numerical stable vlb with binary variable z */
5957  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5958  {
5959  SCIP_Real vlbsol;
5960 
5961  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5962  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5963  {
5964  *cutoff = TRUE;
5965  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5967  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5968  goto TERMINATE;
5969  }
5970 
5971  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5972  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5973  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5974  {
5975  bestlbsol = vlbsol;
5976  bestlbtype = j;
5977  }
5978  }
5979  }
5980 
5981  /* if no lb or vlb with binary variable was found, we have to abort */
5982  if( SCIPisInfinity(scip, -bestlbsol) )
5983  goto TERMINATE;
5984 
5985  if( bestlbtype == -1 )
5986  {
5987  rhs -= valscale * knapvals[i] * bestlbsol;
5988  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5989  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5990  }
5991  else
5992  {
5993  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5994  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5995  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5996 
5997  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5998  goto TERMINATE;
5999 
6000  if( !noknapsackconshdlr )
6001  {
6002  assert(tmpindices != NULL);
6003 
6004  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6005  ++tmp;
6006  }
6007  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6008  valscale * knapvals[i],