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-2016 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_knapsack.c
17  * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
18  * @author Tobias Achterberg
19  * @author Xin Liu
20  * @author Kati Wolter
21  * @author Michael Winkler
22  */
23 
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25 
26 #include <assert.h>
27 #include <string.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 
32 #include "scip/cons_knapsack.h"
33 #include "scip/cons_linear.h"
34 #include "scip/cons_logicor.h"
35 #include "scip/cons_setppc.h"
36 #include "scip/pub_misc.h"
37 
38 /* constraint handler properties */
39 #define CONSHDLR_NAME "knapsack"
40 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
41 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
42 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
43 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
44 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
45 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
46 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
47  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
48 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
49 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
50 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
51 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
52 
53 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
54 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
55 
56 #define EVENTHDLR_NAME "knapsack"
57 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
58 
59 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
60 
61 #if 0
62 #define MAX_DYNPROG_CAPACITY 10000 /**< maximal capacity of knapsack to apply dynamic programming */
63 #endif
64 
65 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
66 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
67 
68 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
69 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
70 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
71 
72 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
73 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
74 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
75 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
76 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
77 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
78  * to best node's dual bound for separating knapsack cuts */
79 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
80 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
81 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
82 
83 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
84 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
85 
86 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
87 #define HASHSIZE_KNAPSACKCONS 131101 /**< minimal size of hash table in linear constraint tables */
88 
89 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
90 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
91 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
92  * comparison round */
93 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
94 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
95  * function defining an upper bound and prevent these constraints from
96  * entering the LP */
97 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
98  * function defining a lower bound and prevent these constraints from
99  * entering the LP */
100 
101 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
103 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
104 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
105 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
106 
107 
108 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
109 
110 /*
111  * Data structures
112  */
113 
114 /** constraint handler data */
115 struct SCIP_ConshdlrData
116 {
117  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
118  * you have to clear it at the end, exists only in presolving stage */
119  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
120  * you have to clear it at the end, exists only in presolving stage */
121  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
122  * you have to clear it at the end, exists only in presolving stage */
123  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
124  * you have to clear it at the end, exists only in presolving stage */
125  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
126  * you have to clear it at the end, exists only in presolving stage */
127  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
128  * you have to clear it at the end, exists only in presolving stage */
129  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
130  * you have to clear it at the end, exists only in presolving stage */
131  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
132  * you have to clear it at the end, exists only in presolving stage */
133  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
134  * you have to clear it at the end */
135  int ints1size; /**< size of ints1 array */
136  int ints2size; /**< size of ints2 array */
137  int longints1size; /**< size of longints1 array */
138  int longints2size; /**< size of longints2 array */
139  int bools1size; /**< size of bools1 array */
140  int bools2size; /**< size of bools2 array */
141  int bools3size; /**< size of bools3 array */
142  int bools4size; /**< size of bools4 array */
143  int reals1size; /**< size of reals1 array */
144  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
145  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
146  * to best node's dual bound for separating knapsack cuts */
147  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
148  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
149  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
150  int maxsepacuts; /**< maximal number of cuts separated per separation round */
151  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
152  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
153  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
154  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
155  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
156  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
157  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
158  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
159  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
160  * function defining an upper bound and prevent these constraints from
161  * entering the LP */
162  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
163  * function defining a lower bound and prevent these constraints from
164  * entering the LP */
165 };
166 
167 
168 /** constraint data for knapsack constraints */
169 struct SCIP_ConsData
170 {
171  SCIP_VAR** vars; /**< variables in knapsack constraint */
172  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
173  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
174  int* cliquepartition; /**< clique indices of the clique partition */
175  int* negcliquepartition; /**< clique indices of the negated clique partition */
176  SCIP_ROW* row; /**< corresponding LP row */
177  int nvars; /**< number of variables in knapsack constraint */
178  int varssize; /**< size of vars, weights, and eventdata arrays */
179  int ncliques; /**< number of cliques in the clique partition */
180  int nnegcliques; /**< number of cliques in the negated clique partition */
181  SCIP_Longint capacity; /**< capacity of knapsack */
182  SCIP_Longint weightsum; /**< sum of all weights */
183  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
184  unsigned int propagated:1; /**< is the knapsack constraint already propagated? */
185  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
186  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
187  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
188  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
189  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
190  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
191  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
192  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
193 };
194 
195 
196 /** event data for bound changes events */
197 struct SCIP_EventData
198 {
199  SCIP_CONSDATA* consdata; /**< knapsack constraint data to process the bound change for */
200  SCIP_Longint weight; /**< weight of variable */
201  int filterpos; /**< position of event in variable's event filter */
202 };
203 
204 
205 /** data structure to combine two sorting key values */
206 struct sortkeypair
207 {
208  SCIP_Real key1; /**< first sort key value */
209  SCIP_Real key2; /**< second sort key value */
210 };
211 typedef struct sortkeypair SORTKEYPAIR;
212 
213 /** status of GUB constraint */
214 enum GUBVarstatus
215 {
216  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
217  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
218  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
219  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
220  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
221  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
222 };
225 /** status of variable in GUB constraint */
227 {
228  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
229  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
230  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
231  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
232  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
233  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
234 };
237 /** data structure of GUB constraints */
239 {
240  int* gubvars; /**< indices of GUB variables in knapsack constraint */
241  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
242  int ngubvars; /**< number of GUB variables */
243  int gubvarssize; /**< size of gubvars array */
244 };
245 typedef struct SCIP_GUBCons SCIP_GUBCONS;
246 
247 /** data structure of a set of GUB constraints */
249 {
250  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
251  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
252  int ngubconss; /**< number of GUB constraints */
253  int nvars; /**< number of variables in knapsack constraint */
254  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
255  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
256 };
257 typedef struct SCIP_GUBSet SCIP_GUBSET;
259 /*
260  * Local methods
261  */
263 /** comparison method for two sorting key pairs */
264 static
265 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
266 {
267  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
268  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
269 
270  if( sortkeypair1->key1 < sortkeypair2->key1 )
271  return -1;
272  else if( sortkeypair1->key1 > sortkeypair2->key1 )
273  return +1;
274  else if( sortkeypair1->key2 < sortkeypair2->key2 )
275  return -1;
276  else if( sortkeypair1->key2 > sortkeypair2->key2 )
277  return +1;
278  else
279  return 0;
280 }
281 
282 /** creates event data */
283 static
285  SCIP* scip, /**< SCIP data structure */
286  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
287  SCIP_CONSDATA* consdata, /**< constraint data */
288  SCIP_Longint weight /**< weight of variable */
289  )
290 {
291  assert(eventdata != NULL);
292 
293  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
294  (*eventdata)->consdata = consdata;
295  (*eventdata)->weight = weight;
296 
297  return SCIP_OKAY;
298 }
299 
300 /** frees event data */
301 static
303  SCIP* scip, /**< SCIP data structure */
304  SCIP_EVENTDATA** eventdata /**< pointer to event data */
305  )
306 {
307  assert(eventdata != NULL);
308 
309  SCIPfreeBlockMemory(scip, eventdata);
310 
311  return SCIP_OKAY;
312 }
313 
314 /** sorts items in knapsack with nonincreasing weights */
315 static
316 void sortItems(
317  SCIP_CONSDATA* consdata /**< constraint data */
318  )
319 {
320  assert(consdata != NULL);
321  assert(consdata->nvars == 0 || consdata->vars != NULL);
322  assert(consdata->nvars == 0 || consdata->weights != NULL);
323  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
324  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
325 
326  if( !consdata->sorted )
327  {
328  int pos;
329  int lastcliquenum;
330  int v;
331 
332  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
333  * sorted by first array in non-increasing order via sort template */
335  consdata->weights,
336  (void**)consdata->vars,
337  (void**)consdata->eventdata,
338  consdata->cliquepartition,
339  consdata->negcliquepartition,
340  consdata->nvars);
341 
342  v = consdata->nvars - 1;
343  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
344  while( v >= 0 )
345  {
346  int w = v - 1;
347 
348  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
349  --w;
350 
351  if( v - w > 1 )
352  {
353  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
355  (void**)(&(consdata->vars[w+1])),
356  (void**)(&(consdata->eventdata[w+1])),
357  &(consdata->cliquepartition[w+1]),
358  &(consdata->negcliquepartition[w+1]),
359  SCIPvarComp,
360  v - w);
361  }
362  v = w;
363  }
364 
365  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
366  if( consdata->cliquepartitioned )
367  {
368  lastcliquenum = 0;
369 
370  for( pos = 0; pos < consdata->nvars; ++pos )
371  {
372  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
373  * partition is invalid */
374  if( consdata->cliquepartition[pos] > lastcliquenum )
375  {
376  consdata->cliquepartitioned = FALSE;
377  break;
378  }
379  else if( consdata->cliquepartition[pos] == lastcliquenum )
380  ++lastcliquenum;
381  }
382  }
383  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
384  if( consdata->negcliquepartitioned )
385  {
386  lastcliquenum = 0;
387 
388  for( pos = 0; pos < consdata->nvars; ++pos )
389  {
390  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
391  * partition is invalid */
392  if( consdata->negcliquepartition[pos] > lastcliquenum )
393  {
394  consdata->negcliquepartitioned = FALSE;
395  break;
396  }
397  else if( consdata->negcliquepartition[pos] == lastcliquenum )
398  ++lastcliquenum;
399  }
400  }
401 
402  consdata->sorted = TRUE;
403  }
404 #ifndef NDEBUG
405  {
406  /* check if the weight array is sorted in a non-increasing way */
407  int i;
408  for( i = 0; i < consdata->nvars-1; ++i )
409  assert(consdata->weights[i] >= consdata->weights[i+1]);
410  }
411 #endif
412 }
413 
414 /** calculates a partition of the variables into cliques */
415 static
417  SCIP* scip, /**< SCIP data structure */
418  SCIP_CONSDATA* consdata, /**< constraint data */
419  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
420  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
421  )
422 {
423  assert(consdata != NULL);
424  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
425 
426  if( normalclique && !consdata->cliquepartitioned )
427  {
428  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
429  consdata->cliquepartitioned = TRUE;
430  }
431 
432  if( negatedclique && !consdata->negcliquepartitioned )
433  {
434  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
435  consdata->negcliquepartitioned = TRUE;
436  }
437 
438  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
439  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
440 
441  return SCIP_OKAY;
442 }
443 
444 /** installs rounding locks for the given variable in the given knapsack constraint */
445 static
447  SCIP* scip, /**< SCIP data structure */
448  SCIP_CONS* cons, /**< knapsack constraint */
449  SCIP_VAR* var /**< variable of constraint entry */
450  )
451 {
452  /* rounding up may violate the constraint */
453  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
454 
455  return SCIP_OKAY;
456 }
457 
458 /** removes rounding locks for the given variable in the given knapsack constraint */
459 static
461  SCIP* scip, /**< SCIP data structure */
462  SCIP_CONS* cons, /**< knapsack constraint */
463  SCIP_VAR* var /**< variable of constraint entry */
464  )
465 {
466  /* rounding up may violate the constraint */
467  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
468 
469  return SCIP_OKAY;
470 }
471 
472 /** catches bound change events for variables in knapsack */
473 static
475  SCIP* scip, /**< SCIP data structure */
476  SCIP_CONSDATA* consdata, /**< constraint data */
477  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
478  )
479 {
480  int i;
482  assert(consdata != NULL);
483  assert(consdata->nvars == 0 || consdata->vars != NULL);
484  assert(consdata->nvars == 0 || consdata->weights != NULL);
485  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
486 
487  for( i = 0; i < consdata->nvars; i++)
488  {
489  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], consdata, consdata->weights[i]) );
490  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i],
493  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
494  }
495 
496  return SCIP_OKAY;
497 }
498 
499 /** drops bound change events for variables in knapsack */
500 static
502  SCIP* scip, /**< SCIP data structure */
503  SCIP_CONSDATA* consdata, /**< constraint data */
504  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
505  )
506 {
507  int i;
509  assert(consdata != NULL);
510  assert(consdata->nvars == 0 || consdata->vars != NULL);
511  assert(consdata->nvars == 0 || consdata->weights != NULL);
512  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
513 
514  for( i = 0; i < consdata->nvars; i++)
515  {
516  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i],
519  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
520  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
521  }
522 
523  return SCIP_OKAY;
524 }
525 
526 /** ensures, that vars and vals arrays can store at least num entries */
527 static
529  SCIP* scip, /**< SCIP data structure */
530  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
531  int num, /**< minimum number of entries to store */
532  SCIP_Bool transformed /**< is constraint from transformed problem? */
533  )
534 {
535  assert(consdata != NULL);
536  assert(consdata->nvars <= consdata->varssize);
537 
538  if( num > consdata->varssize )
539  {
540  int newsize;
541 
542  newsize = SCIPcalcMemGrowSize(scip, num);
543  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
544  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
545  if( transformed )
546  {
547  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
548  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
549  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
550  }
551  else
552  {
553  assert(consdata->eventdata == NULL);
554  assert(consdata->cliquepartition == NULL);
555  assert(consdata->negcliquepartition == NULL);
556  }
557  consdata->varssize = newsize;
558  }
559  assert(num <= consdata->varssize);
560 
561  return SCIP_OKAY;
562 }
563 
564 /** creates knapsack constraint data */
565 static
567  SCIP* scip, /**< SCIP data structure */
568  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
569  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
570  int nvars, /**< number of variables in knapsack */
571  SCIP_VAR** vars, /**< variables of knapsack */
572  SCIP_Longint* weights, /**< weights of knapsack items */
573  SCIP_Longint capacity /**< capacity of knapsack */
574  )
575 {
576  int v;
577 
578  assert(consdata != NULL);
579 
580  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
581  if( nvars > 0 )
582  {
583  int k;
584 
585  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
586  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weights, nvars) );
587 
588  k = 0;
589  for( v = 0; v < nvars; ++v )
590  {
591  assert(vars[v] != NULL);
592 
593  /* all weight have to be not negative */
594  assert( weights[v] >= 0 );
595 
596  if( weights[v] > 0 )
597  {
598  (*consdata)->vars[k] = vars[v];
599  (*consdata)->weights[k] = weights[v];
600  ++k;
601  }
602  }
603  assert(k >= 0);
604 
605  (*consdata)->nvars = k;
606  if( k < nvars )
607  {
608  if( k > 0 )
609  {
610  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(*consdata)->vars, nvars, k) );
611  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(*consdata)->weights, nvars, k) );
612  }
613  else
614  {
615  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, nvars);
616  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, nvars);
617 
618  (*consdata)->vars = NULL;
619  (*consdata)->weights = NULL;
620  assert( (*consdata)->nvars == 0 );
621  }
622  }
623  }
624  else
625  {
626  (*consdata)->vars = NULL;
627  (*consdata)->weights = NULL;
628  (*consdata)->nvars = 0;
629  }
630 
631  /* capacity has to be greater or equal to zero */
632  assert( capacity >= 0 );
633 
634  (*consdata)->varssize = (*consdata)->nvars;
635  (*consdata)->capacity = capacity;
636  (*consdata)->eventdata = NULL;
637  (*consdata)->cliquepartition = NULL;
638  (*consdata)->negcliquepartition = NULL;
639  (*consdata)->row = NULL;
640  (*consdata)->weightsum = 0;
641  (*consdata)->onesweightsum = 0;
642  (*consdata)->ncliques = 0;
643  (*consdata)->nnegcliques = 0;
644  (*consdata)->propagated = FALSE;
645  (*consdata)->presolvedtiming = 0;
646  (*consdata)->sorted = FALSE;
647  (*consdata)->cliquepartitioned = FALSE;
648  (*consdata)->negcliquepartitioned = FALSE;
649  (*consdata)->merged = FALSE;
650  (*consdata)->cliquesadded = FALSE;
651  (*consdata)->varsdeleted = FALSE;
652  (*consdata)->existmultaggr = FALSE;
653 
654  /* get transformed variables, if we are in the transformed problem */
655  if( SCIPisTransformed(scip) )
656  {
657  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
658 
659  for( v = 0; v < (*consdata)->nvars; v++ )
660  {
661  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
662  assert(var != NULL);
663  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
664  }
665 
666  /* allocate memory for additional data structures */
667  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
668  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
669  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
670 
671  /* catch events for variables */
672  SCIP_CALL( catchEvents(scip, *consdata, eventhdlr) );
673  }
674 
675  /* calculate sum of weights and capture variables */
676  for( v = 0; v < (*consdata)->nvars; ++v )
677  {
678  (*consdata)->weightsum += (*consdata)->weights[v];
679  if( SCIPvarGetLbLocal((*consdata)->vars[v]) > 0.5 )
680  (*consdata)->onesweightsum += (*consdata)->weights[v];
681 
682  /* capture variables */
683  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
684  }
685 
686  return SCIP_OKAY;
687 }
688 
689 /** frees knapsack constraint data */
690 static
692  SCIP* scip, /**< SCIP data structure */
693  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
694  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
695  )
696 {
697  assert(consdata != NULL);
698  assert(*consdata != NULL);
699 
700  if( (*consdata)->row != NULL )
701  {
702  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
703  }
704  if( (*consdata)->eventdata != NULL )
705  {
706  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
707  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
708  }
709  if( (*consdata)->negcliquepartition != NULL )
710  {
711  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
712  }
713  if( (*consdata)->cliquepartition != NULL )
714  {
715  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
716  }
717  if( (*consdata)->vars != NULL )
718  {
719  int v;
720 
721  /* release variables */
722  for( v = 0; v < (*consdata)->nvars; v++ )
723  {
724  assert((*consdata)->vars[v] != NULL);
725  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
726  }
727 
728  assert( (*consdata)->weights != NULL );
729  assert( (*consdata)->varssize > 0 );
730  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
731  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
732  }
733 
734  SCIPfreeBlockMemory(scip, consdata);
735 
736  return SCIP_OKAY;
737 }
738 
739 /** changes a single weight in knapsack constraint data */
740 static
741 void consdataChgWeight(
742  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
743  int item, /**< item number */
744  SCIP_Longint newweight /**< new weight of item */
745  )
746 {
747  SCIP_Longint oldweight;
749  assert(consdata != NULL);
750  assert(0 <= item && item < consdata->nvars);
751 
752  oldweight = consdata->weights[item];
753  consdata->weights[item] = newweight;
754  consdata->weightsum += (newweight - oldweight);
755 
756  if( SCIPvarGetLbLocal(consdata->vars[item]) > 0.5 )
757  consdata->onesweightsum += (newweight - oldweight);
758 
759  if( consdata->eventdata != NULL )
760  {
761  assert(consdata->eventdata[item] != NULL);
762  assert(consdata->eventdata[item]->weight == oldweight);
763  consdata->eventdata[item]->weight = newweight;
764  }
765 
766  consdata->propagated = FALSE;
767  consdata->presolvedtiming = 0;
768  consdata->sorted = FALSE;
769 
770  /* recalculate cliques extraction after a weight was increased */
771  if( oldweight < newweight )
772  {
773  consdata->cliquesadded = FALSE;
774  }
775 }
776 
777 /** creates LP row corresponding to knapsack constraint */
778 static
780  SCIP* scip, /**< SCIP data structure */
781  SCIP_CONS* cons /**< knapsack constraint */
782  )
783 {
784  SCIP_CONSDATA* consdata;
785  int i;
787  consdata = SCIPconsGetData(cons);
788  assert(consdata != NULL);
789  assert(consdata->row == NULL);
790 
791  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, SCIPconsGetHdlr(cons), SCIPconsGetName(cons),
792  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
794 
795  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
796  for( i = 0; i < consdata->nvars; ++i )
797  {
798  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
799  }
800  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
801 
802  return SCIP_OKAY;
803 }
804 
805 /** adds linear relaxation of knapsack constraint to the LP */
806 static
808  SCIP* scip, /**< SCIP data structure */
809  SCIP_CONS* cons, /**< knapsack constraint */
810  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
811  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
812  )
813 {
814  SCIP_CONSDATA* consdata;
815 
816  assert( cutoff != NULL );
817  *cutoff = FALSE;
818 
819  consdata = SCIPconsGetData(cons);
820  assert(consdata != NULL);
821 
822  if( consdata->row == NULL )
823  {
824  SCIP_CALL( createRelaxation(scip, cons) );
825  }
826  assert(consdata->row != NULL);
827 
828  /* insert LP row as cut */
829  if( !SCIProwIsInLP(consdata->row) )
830  {
831  SCIPdebugMessage("adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
832  SCIPconsGetName(cons), consdata->capacity);
833  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
834  SCIP_CALL( SCIPaddCut(scip, sol, consdata->row, FALSE, cutoff) );
835  }
836 
837  return SCIP_OKAY;
838 }
839 
840 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
841 static
843  SCIP* scip, /**< SCIP data structure */
844  SCIP_CONS* cons, /**< constraint to check */
845  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
846  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
847  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
848  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
849  )
850 {
851  SCIP_CONSDATA* consdata;
852 
853  assert(violated != NULL);
854 
855  consdata = SCIPconsGetData(cons);
856  assert(consdata != NULL);
857 
858  SCIPdebugMessage("checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
859  SCIPconsGetName(cons), (void*)sol, checklprows);
860 
861  *violated = FALSE;
862 
863  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
864  {
865  SCIP_Real sum;
866  SCIP_Longint integralsum;
867  SCIP_Bool ishuge;
868  int v;
869 
870  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
871  * enforcement
872  */
873  if( sol == NULL )
874  {
875  SCIP_CALL( SCIPincConsAge(scip, cons) );
876  }
877 
878  sum = 0.0;
879  integralsum = 0;
880  /* we perform an more exact comparison if the capacity does not exceed the huge value */
881  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
882  {
883  ishuge = TRUE;
884 
885  /* sum over all weight times the corresponding solution value */
886  for( v = consdata->nvars - 1; v >= 0; --v )
887  {
888  assert(SCIPvarIsBinary(consdata->vars[v]));
889  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
890  }
891  }
892  else
893  {
894  ishuge = FALSE;
895 
896  /* sum over all weight for which the variable has a solution value of 1 in feastol */
897  for( v = consdata->nvars - 1; v >= 0; --v )
898  {
899  assert(SCIPvarIsBinary(consdata->vars[v]));
900 
901  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
902  integralsum += consdata->weights[v];
903  }
904  }
905 
906  if( (!ishuge && integralsum > consdata->capacity) || (ishuge && SCIPisFeasGT(scip, sum, (SCIP_Real)consdata->capacity)) )
907  {
908  *violated = TRUE;
909 
910  /* only reset constraint age if we are in enforcement */
911  if( sol == NULL )
912  {
913  SCIP_CALL( SCIPresetConsAge(scip, cons) );
914  }
915 
916  if( printreason )
917  {
918  SCIP_Real viol = ishuge ? sum : (SCIP_Real)integralsum;
919 
920  viol -= consdata->capacity;
921  assert(viol > 0);
922 
923  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
924 
925  SCIPinfoMessage(scip, NULL, ";\n");
926  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", viol);
927  }
928  }
929  }
930 
931  return SCIP_OKAY;
932 }
933 
934 /* IDX computes the integer index for the optimal solution array */
935 #define IDX(j,d) ((j)*(intcap)+(d))
936 
937 /** solves knapsack problem in maximization form exactly using dynamic programming;
938  * if needed, one can provide arrays to store all selected items and all not selected items
939  *
940  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part as well
941  */
943  SCIP* scip, /**< SCIP data structure */
944  int nitems, /**< number of available items */
945  SCIP_Longint* weights, /**< item weights */
946  SCIP_Real* profits, /**< item profits */
947  SCIP_Longint capacity, /**< capacity of knapsack */
948  int* items, /**< item numbers */
949  int* solitems, /**< array to store items in solution, or NULL */
950  int* nonsolitems, /**< array to store items not in solution, or NULL */
951  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
952  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
953  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
954  SCIP_Bool* success /**< pointer to store if an error occured during solving(normally a memory
955  * problem) */
956  )
957 {
958  SCIP_RETCODE retcode;
959  SCIP_Real* tempsort;
960  SCIP_Real* optvalues;
961  int intcap;
962  int d;
963  int j;
964  SCIP_Longint weightsum;
965  int* myitems;
966  SCIP_Longint* myweights;
967  int* allcurrminweight;
968  SCIP_Real* myprofits;
969  int nmyitems;
970  SCIP_Longint gcd;
971  SCIP_Longint minweight;
972  SCIP_Longint maxweight;
973  int currminweight;
974  SCIP_Longint greedycap;
975  SCIP_Longint greedysolweight;
976  SCIP_Real greedysolvalue;
977  SCIP_Bool eqweights;
978  SCIP_Bool isoptimal;
979  const size_t maxsize_t = (size_t)(-1);
980 
981  assert(weights != NULL);
982  assert(profits != NULL);
983  assert(capacity >= 0);
984  assert(items != NULL);
985  assert(nitems >= 0);
986  assert(success != NULL);
987 
988  *success = TRUE;
989 
990 #ifndef NDEBUG
991  for( j = nitems - 1; j >= 0; --j )
992  assert(weights[j] >= 0);
993 #endif
994 
995  SCIPdebugMessage("Solving knapsack exactly.\n");
996 
997  /* initializing solution value */
998  if( solval != NULL )
999  *solval = 0.0;
1000 
1001  /* produces optimal solution by following the table */
1002  if( solitems != NULL)
1003  {
1004  assert(items != NULL);
1005  assert(nsolitems != NULL);
1006  assert(nonsolitems != NULL);
1007  assert(nnonsolitems != NULL);
1008 
1009  *nnonsolitems = 0;
1010  *nsolitems = 0;
1011  }
1012 
1013  /* allocate temporary memory */
1014  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1015  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1016  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1017  nmyitems = 0;
1018  weightsum = 0;
1019  minweight = SCIP_LONGINT_MAX;
1020  maxweight = 0;
1021 
1022  /* remove unnecessary items */
1023  for( j = 0; j < nitems; ++j )
1024  {
1025  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1026  /* items does not fit */
1027  if( weights[j] > capacity )
1028  {
1029  if( solitems != NULL)
1030  {
1031  nonsolitems[*nnonsolitems] = items[j];
1032  ++(*nnonsolitems);
1033  }
1034  }
1035  /* items we does not want */
1036  else if( profits[j] <= 0.0 )
1037  {
1038  if( solitems != NULL)
1039  {
1040  nonsolitems[*nnonsolitems] = items[j];
1041  ++(*nnonsolitems);
1042  }
1043  }
1044  /* items which always fit */
1045  else if( weights[j] == 0 )
1046  {
1047  if( solitems != NULL)
1048  {
1049  solitems[*nsolitems] = items[j];
1050  ++(*nsolitems);
1051  }
1052  if( solval != NULL )
1053  *solval += profits[j];
1054  }
1055  /* all important items */
1056  else
1057  {
1058  myweights[nmyitems] = weights[j];
1059  myprofits[nmyitems] = profits[j];
1060  myitems[nmyitems] = items[j];
1061 
1062  /* remember smallest item */
1063  if( myweights[nmyitems] < minweight )
1064  minweight = myweights[nmyitems];
1065 
1066  /* remember bigest item */
1067  if( myweights[nmyitems] > maxweight )
1068  maxweight = myweights[nmyitems];
1069 
1070  weightsum += myweights[nmyitems];
1071  ++nmyitems;
1072  }
1073  }
1074 
1075  /* no item is left then goto end */
1076  if( nmyitems == 0 )
1077  {
1078  SCIPdebugMessage("After preprocessing no items are left.\n");
1079 
1080  goto TERMINATE;
1081  }
1082  /* if all items fit, we also do not need to do the expensive stuff later on */
1083  else if( weightsum > 0 && weightsum <= capacity )
1084  {
1085  SCIPdebugMessage("After preprocessing all items fit into knapsack.\n");
1086 
1087  for( j = nmyitems - 1; j >= 0; --j )
1088  {
1089  if( solitems != NULL )
1090  {
1091  solitems[*nsolitems] = myitems[j];
1092  ++(*nsolitems);
1093  }
1094  if( solval != NULL )
1095  *solval += myprofits[j];
1096  }
1097 
1098  goto TERMINATE;
1099  }
1100 
1101  assert(minweight > 0);
1102  assert(maxweight > 0);
1103 
1104  if( maxweight > 1 )
1105  {
1106  /* determine greatest common divisor */
1107  gcd = myweights[nmyitems - 1];
1108  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1109  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1110 
1111  SCIPdebugMessage("Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1112 
1113  /* divide by greatest common divisor */
1114  if( gcd > 1 )
1115  {
1116  eqweights = TRUE;
1117  for( j = nmyitems - 1; j >= 0; --j )
1118  {
1119  myweights[j] /= gcd;
1120  eqweights = eqweights && (myweights[j] == 1);
1121  }
1122  capacity /= gcd;
1123  minweight /= gcd;
1124  }
1125  else
1126  eqweights = FALSE;
1127  }
1128  else
1129  {
1130  assert(maxweight == 1);
1131  eqweights = TRUE;
1132  }
1133 
1134  assert(minweight <= capacity);
1135 
1136  /* only one item fits, than take the best */
1137  if( minweight > capacity / 2 )
1138  {
1139  int p;
1140 
1141  SCIPdebugMessage("Only one item fits into knapsack, so take the best.\n");
1142 
1143  p = nmyitems - 1;
1144 
1145  /* find best item */
1146  for( j = nmyitems - 2; j >= 0; --j )
1147  if( myprofits[j] > myprofits[p] )
1148  p = j;
1149 
1150  /* update solution information */
1151  if( solitems != NULL)
1152  {
1153  solitems[*nsolitems] = myitems[p];
1154  ++(*nsolitems);
1155  for( j = nmyitems - 1; j >= 0; --j )
1156  if( j != p )
1157  {
1158  nonsolitems[*nnonsolitems] = myitems[j];
1159  ++(*nnonsolitems);
1160  }
1161  }
1162  /* update solution value */
1163  if( solval != NULL )
1164  *solval += myprofits[p];
1165 
1166  goto TERMINATE;
1167  }
1168 
1169  /* all items have the same weight, than take the best */
1170  if( eqweights )
1171  {
1172  SCIP_Real addval;
1173 
1174  SCIPdebugMessage("All weights are equal, so take the best.\n");
1175 
1176  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1177 
1178  addval = 0.0;
1179  /* update solution information */
1180  if( solitems != NULL || solval != NULL )
1181  {
1182  SCIP_Longint i;
1183 
1184  /* if all items would fit we had handled this case before */
1185  assert((SCIP_Longint) nmyitems > capacity);
1186 
1187  /* take the first best items into the solution */
1188  for( i = capacity - 1; i >= 0; --i )
1189  {
1190  if( solitems != NULL)
1191  {
1192  assert(nonsolitems != NULL);
1193  solitems[*nsolitems] = myitems[i];
1194  ++(*nsolitems);
1195  }
1196  addval += myprofits[i];
1197  }
1198 
1199  if( solitems != NULL)
1200  {
1201  assert(nonsolitems != NULL);
1202 
1203  /* the rest are not in the solution */
1204  for( i = nmyitems - 1; i >= capacity; --i )
1205  {
1206  nonsolitems[*nnonsolitems] = myitems[i];
1207  ++(*nnonsolitems);
1208  }
1209  }
1210  }
1211  /* update solution value */
1212  if( solval != NULL )
1213  {
1214  assert(addval > 0.0);
1215  *solval += addval;
1216  }
1217 
1218  goto TERMINATE;
1219  }
1220 
1221  /* in the following table we do not need the first minweight columns */
1222  capacity -= (minweight - 1);
1223 
1224  /* we can only handle integers */
1225  if( capacity >= INT_MAX )
1226  {
1227  SCIPdebugMessage("Capacity is to big, so we cannot handle it here.\n");
1228 
1229  *success = FALSE;
1230  goto TERMINATE;
1231  }
1232  assert(capacity < INT_MAX);
1233 
1234  intcap = (int)capacity;
1235  assert(intcap >= 0);
1236  assert(nmyitems > 0);
1237  assert(sizeof(size_t) >= sizeof(int)); /* no following conversion should be messed up */
1238 
1239  /* this condition checks if we will try to allocate a correct number of bytes and do not have an overflow, while
1240  * computing the size for the allocation
1241  */
1242  if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (maxsize_t / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1243  {
1244  SCIPdebugMessage("Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1245 
1246  *success = FALSE;
1247  goto TERMINATE;
1248  }
1249 
1250  /* allocate temporary memory and check for memory exceeding */
1251  /* @note we do allocate normal memory instead of buffer memory, because the buffer, will not be deleted directly and
1252  * might be a really huge block of memory which we will not use later on
1253  */
1254  retcode = SCIPallocMemoryArray(scip, &optvalues, nmyitems * intcap);
1255  if( retcode == SCIP_NOMEMORY )
1256  {
1257  SCIPdebugMessage("Did not get enough memory.\n");
1258 
1259  *success = FALSE;
1260  goto TERMINATE;
1261  }
1262  else
1263  {
1264  SCIP_CALL( retcode );
1265  }
1266 
1267  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1268  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only use for greedy solution
1269  */
1270  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1271  for( j = nmyitems - 1; j >= 0; --j )
1272  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1273 
1274  SCIPsortDownRealLongRealInt(tempsort, myweights, myprofits, myitems, nmyitems);
1275 
1276  /* initialize values for greedy solution information */
1277  greedysolweight = 0;
1278  greedysolvalue = 0.0;
1279  isoptimal = TRUE;
1280  greedycap = capacity + (minweight - 1);
1281 
1282  SCIPdebugMessage("Determine greedy solution.\n");
1283 
1284  /* determine greedy solution */
1285  for( j = 0; j < nmyitems; ++j )
1286  {
1287  assert(myweights[j] <= greedycap);
1288 
1289  /* take all fitting items */
1290  if( myweights[j] + greedysolweight <= greedycap )
1291  {
1292  /* update greedy solution weight and value */
1293  greedysolweight += myweights[j];
1294  greedysolvalue += myprofits[j];
1295  continue;
1296  }
1297  else if( greedysolweight < greedycap )
1298  isoptimal = FALSE;
1299  break;
1300  }
1301  assert(greedysolweight > 0);
1302  assert(greedysolvalue > 0.0);
1303 
1304  /* greedy solution is optimal */
1305  if( isoptimal )
1306  {
1307  assert(greedysolweight == greedycap);
1308 
1309  SCIPdebugMessage("Greedy solution is optimal.\n");
1310 
1311  greedysolweight = 0;
1312 
1313  /* update solution information */
1314  if( solitems != NULL)
1315  {
1316  /* take the first best items into the solution */
1317  for( j = 0; j < nmyitems; ++j )
1318  {
1319  /* take all fitting items */
1320  if( myweights[j] + greedysolweight <= greedycap )
1321  {
1322  solitems[*nsolitems] = myitems[j];
1323  ++(*nsolitems);
1324  greedysolweight += myweights[j];
1325  }
1326  else
1327  {
1328  nonsolitems[*nnonsolitems] = myitems[j];
1329  ++(*nnonsolitems);
1330  }
1331  }
1332  }
1333  /* update solution value */
1334  if( solval != NULL )
1335  {
1336  assert(greedysolvalue > 0.0);
1337  *solval += greedysolvalue;
1338  }
1339 
1340  SCIPfreeBufferArray(scip, &tempsort);
1341  SCIPfreeMemoryArray(scip, &optvalues);
1342 
1343  goto TERMINATE;
1344  }
1345 
1346  SCIPdebugMessage("Start real exact algorithm.\n");
1347 
1348  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1349  * all values entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1350  * invalid, a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1351  * 'nmyitem' values
1352  */
1353  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1354  assert(myweights[0] - minweight < INT_MAX);
1355  currminweight = (int) (myweights[0] - minweight);
1356  allcurrminweight[0] = currminweight;
1357 
1358  /* fills first row of dynamic programming table with optimal values */
1359  for( d = currminweight; d < intcap; ++d )
1360  optvalues[d] = myprofits[0];
1361  /* fills dynamic programming table with optimal values */
1362  for( j = 1; j < nmyitems; ++j )
1363  {
1364  int intweight;
1365 
1366  /* compute important part of weight, which will be represented in the table */
1367  intweight = (int)(myweights[j] - minweight);
1368  assert(0 <= intweight && intweight < intcap);
1369 
1370  /* copy all nonzeros from row above */
1371  for( d = currminweight; d < intweight && d < intcap; ++d )
1372  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1373 
1374  /* update corresponding row */
1375  for( d = intweight; d < intcap; ++d )
1376  {
1377  /* if index d is smaller the the current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should
1378  * be 0
1379  */
1380  if( d < currminweight )
1381  {
1382  optvalues[IDX(j,d)] = myprofits[j];
1383  }
1384  else
1385  {
1386  SCIP_Real sumprofit;
1387 
1388  if( d - myweights[j] < currminweight )
1389  sumprofit = myprofits[j];
1390  else
1391  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1392 
1393  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1394  }
1395  }
1396  /* update currminweight */
1397  if( intweight < currminweight )
1398  currminweight = intweight;
1399 
1400  allcurrminweight[j] = currminweight;
1401  }
1402 
1403  /* update optimal solution by following the table */
1404  if( solitems != NULL)
1405  {
1406  d = intcap - 1;
1407 
1408  SCIPdebugMessage("Fill the solution vector after solving exactly.\n");
1409 
1410  /* insert all items in (non-) solution vector */
1411  for( j = nmyitems - 1; j > 0; --j )
1412  {
1413  /* if we cannot find any item anymore which is in our solution stop, if the following condition holds this
1414  * means all remaining items does not fit anymore
1415  */
1416  if( d < allcurrminweight[j] )
1417  {
1418  /* we cannot have exceeded our capacity */
1419  assert((SCIP_Longint) d >= -minweight);
1420  break;
1421  }
1422  /* collect solution items, first condition means that no next item can fit anymore, but this does */
1423  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1424  {
1425  solitems[*nsolitems] = myitems[j];
1426  ++(*nsolitems);
1427 
1428  /* check that we do not have an underflow */
1429  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1430  d = (int)(d - myweights[j]);
1431  }
1432  /* collect non-solution items */
1433  else
1434  {
1435  nonsolitems[*nnonsolitems] = myitems[j];
1436  ++(*nnonsolitems);
1437  }
1438  }
1439 
1440  /* insert remaining items */
1441  if( d >= allcurrminweight[j] )
1442  {
1443  assert(j == 0);
1444  solitems[*nsolitems] = myitems[j];
1445  ++(*nsolitems);
1446  }
1447  else
1448  {
1449  assert(j >= 0);
1450  assert(d < allcurrminweight[j]);
1451 
1452  for( ; j >= 0; --j )
1453  {
1454  nonsolitems[*nnonsolitems] = myitems[j];
1455  ++(*nnonsolitems);
1456  }
1457  }
1458 
1459  assert(*nsolitems + *nnonsolitems == nitems);
1460  }
1461 
1462  /* update solution value */
1463  if( solval != NULL )
1464  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1465 
1466  SCIPfreeBufferArray(scip, &allcurrminweight);
1467 
1468  /* free all temporary memory */
1469  SCIPfreeBufferArray(scip, &tempsort);
1470  SCIPfreeMemoryArray(scip, &optvalues);
1471 
1472  TERMINATE:
1473  SCIPfreeBufferArray(scip, &myitems);
1474  SCIPfreeBufferArray(scip, &myprofits);
1475  SCIPfreeBufferArray(scip, &myweights);
1476 
1477  return SCIP_OKAY;
1478 }
1479 
1480 
1481 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1482  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1483  * selected items
1484  */
1486  SCIP* scip, /**< SCIP data structure */
1487  int nitems, /**< number of available items */
1488  SCIP_Longint* weights, /**< item weights */
1489  SCIP_Real* profits, /**< item profits */
1490  SCIP_Longint capacity, /**< capacity of knapsack */
1491  int* items, /**< item numbers */
1492  int* solitems, /**< array to store items in solution, or NULL */
1493  int* nonsolitems, /**< array to store items not in solution, or NULL */
1494  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1495  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1496  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1497  )
1498 {
1499  SCIP_Real* tempsort;
1500  SCIP_Longint solitemsweight;
1501  int j;
1502 
1503  assert(weights != NULL);
1504  assert(profits != NULL);
1505  assert(capacity >= 0);
1506  assert(items != NULL);
1507  assert(nitems >= 0);
1508 
1509  if( solitems != NULL )
1510  {
1511  *nsolitems = 0;
1512  *nnonsolitems = 0;
1513  }
1514  if( solval != NULL )
1515  *solval = 0.0;
1516 
1517  /* sort items (plus corresponding arrays weights and profits) such that
1518  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n
1519  */
1520  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1521  for( j = nitems - 1; j >= 0; --j )
1522  {
1523  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1524  }
1525  SCIPsortDownRealLongRealInt(tempsort, weights, profits, items, nitems);
1526 
1527  /* selects items as long as they fit into the knapsack */
1528  solitemsweight = 0;
1529  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; j++ )
1530  {
1531  if( solitems != NULL )
1532  {
1533  solitems[*nsolitems] = items[j];
1534  (*nsolitems)++;
1535  }
1536  if( solval != NULL )
1537  (*solval) += profits[j];
1538  solitemsweight += weights[j];
1539  }
1540  for( ; j < nitems && solitems != NULL; j++ )
1541  {
1542  nonsolitems[*nnonsolitems] = items[j];
1543  (*nnonsolitems)++;
1544  }
1545 
1546  SCIPfreeBufferArray(scip, &tempsort);
1547 
1548  return SCIP_OKAY;
1549 }
1550 
1551 #ifndef NDEBUG
1552 /** returns, whether the the arrays transweights, transprofits and items are sorted such that
1553  * p_1 / w_1 >= p_2 / w_2 >= ... >= p_n / w_n and these arrays are not changed
1554  */
1555 static
1557  SCIP* scip, /**< SCIP data structure */
1558  int nitems, /**< number of available items */
1559  SCIP_Longint* transweights, /**< item weights */
1560  SCIP_Real* transprofits, /**< item profits */
1561  int* items, /**< item numbers */
1562  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1563  SCIP_Real* solvals, /**< solution values of all problem variables */
1564  SCIP_Bool modtransused /**< TRUE for mod trans sepa prob was used to find cover */
1565  )
1566 {
1567  int j;
1568 
1569  assert(scip != NULL);
1570  assert(nitems >= 0);
1571  assert(weights != NULL);
1572  assert(solvals != NULL);
1573  assert(transweights != NULL);
1574  assert(transprofits != NULL);
1575 
1576  for( j = 1; j < nitems; j++ )
1577  {
1578  assert(SCIPisFeasGE(scip, transprofits[j-1]/transweights[j-1], transprofits[j]/transweights[j]));
1579  if( SCIPisFeasLT(scip, transprofits[j-1]/transweights[j-1], transprofits[j]/transweights[j]) )
1580  return FALSE;
1581  assert(weights[items[j]] == transweights[j]);
1582  if( weights[items[j]] != transweights[j] )
1583  return FALSE;
1584  if( modtransused )
1585  {
1586  assert(SCIPisFeasEQ(scip, (1.0 - solvals[items[j]]) * weights[items[j]], transprofits[j]));
1587  if( !SCIPisFeasEQ(scip, (1.0 - solvals[items[j]]) * weights[items[j]], transprofits[j]) )
1588  return FALSE;
1589  }
1590  else
1591  {
1592  assert(SCIPisFeasEQ(scip, (1.0 - solvals[items[j]]), transprofits[j]));
1593  if( !SCIPisFeasEQ(scip, (1.0 - solvals[items[j]]), transprofits[j]) )
1594  return FALSE;
1595 
1596  }
1597  }
1598  return TRUE;
1599 }
1600 #endif
1601 
1602 #ifdef SCIP_DEBUG
1603 /** prints all nontrivial GUB constraints and their LP solution values */
1604 static
1605 void GUBsetPrint(
1606  SCIP* scip, /**< SCIP data structure */
1607  SCIP_GUBSET* gubset, /**< GUB set data structure */
1608  SCIP_VAR** vars, /**< variables in knapsack constraint */
1609  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1610  )
1611 {
1612  int nnontrivialgubconss;
1613  int c;
1614 
1615  nnontrivialgubconss = 0;
1616 
1617  SCIPdebugMessage(" Nontrivial GUBs of current GUB set:\n");
1618 
1619  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1620  for( c = 0; c < gubset->ngubconss; c++ )
1621  {
1622  SCIP_Real gubsolval;
1623 
1624  assert(gubset->gubconss[c]->ngubvars >= 0);
1625 
1626  /* nontrivial GUB */
1627  if( gubset->gubconss[c]->ngubvars > 1 )
1628  {
1629  int v;
1630 
1631  gubsolval = 0.0;
1632  SCIPdebugMessage(" GUB<%d>:\n", c);
1633 
1634  /* print GUB var */
1635  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1636  {
1637  int currentvar;
1638 
1639  currentvar = gubset->gubconss[c]->gubvars[v];
1640  if( solvals != NULL )
1641  {
1642  gubsolval += solvals[currentvar];
1643  SCIPdebugMessage(" +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1644  }
1645  else
1646  {
1647  SCIPdebugMessage(" +<%s>\n", SCIPvarGetName(vars[currentvar]));
1648  }
1649  }
1650 
1651  /* check whether LP solution satisfies the GUB constraint */
1652  if( solvals != NULL )
1653  {
1654  SCIPdebugMessage(" =%4.2f <= 1 %s\n", gubsolval,
1655  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1656  }
1657  else
1658  {
1659  SCIPdebugMessage(" <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1660  }
1661  nnontrivialgubconss++;
1662  }
1663  }
1664 
1665  SCIPdebugMessage(" --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1666 }
1667 #endif
1668 
1669 /** creates an empty GUB constraint */
1670 static
1672  SCIP* scip, /**< SCIP data structure */
1673  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1674  )
1675 {
1676  assert(scip != NULL);
1677  assert(gubcons != NULL);
1679  /* allocate memory for GUB constraint data structures */
1680  SCIP_CALL( SCIPallocMemory(scip, gubcons) );
1681  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1682  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1683  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1684 
1685  (*gubcons)->ngubvars = 0;
1686 
1687  return SCIP_OKAY;
1688 }
1689 
1690 /** frees GUB constraint */
1691 static
1693  SCIP* scip, /**< SCIP data structure */
1694  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1695  )
1696 {
1697  assert(scip != NULL);
1698  assert(gubcons != NULL);
1699  assert((*gubcons)->gubvars != NULL);
1700  assert((*gubcons)->gubvarsstatus != NULL);
1701 
1702  /* free allocated memory */
1703  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1704  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1705  SCIPfreeMemory(scip, gubcons);
1706 
1707  return SCIP_OKAY;
1708 }
1709 
1710 /** adds variable to given GUB constraint */
1711 static
1713  SCIP* scip, /**< SCIP data structure */
1714  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1715  int var /**< index of given variable in knapsack constraint */
1716  )
1717 {
1718  assert(scip != NULL);
1719  assert(gubcons != NULL);
1720  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1721  assert(gubcons->gubvars != NULL);
1722  assert(gubcons->gubvarsstatus != NULL);
1723  assert(var >= 0);
1724 
1725  /* add variable to GUB constraint */
1726  gubcons->gubvars[gubcons->ngubvars] = var;
1727  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1728  gubcons->ngubvars++;
1729 
1730  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1731  if( gubcons->ngubvars == gubcons->gubvarssize )
1732  {
1733  int newlen;
1734 
1735  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1736  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1737  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1738 
1739  gubcons->gubvarssize = newlen;
1740  }
1741 
1742  return SCIP_OKAY;
1743 }
1744 
1745 /** deletes variable from its current GUB constraint */
1746 static
1748  SCIP* scip, /**< SCIP data structure */
1749  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1750  int var, /**< index of given variable in knapsack constraint */
1751  int gubvarsidx /**< index of the variable in its current GUB constraint */
1752  )
1753 {
1754  assert(scip != NULL);
1755  assert(gubcons != NULL);
1756  assert(var >= 0);
1757  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1758  assert(gubcons->ngubvars >= gubvarsidx+1);
1759  assert(gubcons->gubvars[gubvarsidx] == var);
1760 
1761  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1762  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1763  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1764  gubcons->ngubvars--;
1765 
1766  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1767  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1768  {
1769  int newlen;
1770 
1771  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1772 
1773  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1774  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1775 
1776  gubcons->gubvarssize = newlen;
1777  }
1778 
1779  return SCIP_OKAY;
1780 }
1781 
1782 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1783 static
1785  SCIP* scip, /**< SCIP data structure */
1786  SCIP_GUBSET* gubset, /**< GUB set data structure */
1787  SCIP_VAR** vars, /**< variables in knapsack constraint */
1788  int var, /**< index of given variable in knapsack constraint */
1789  int oldgubcons, /**< index of old GUB constraint of given variable */
1790  int newgubcons /**< index of new GUB constraint of given variable */
1791  )
1792 {
1793  int oldgubvaridx;
1794  int replacevar;
1795  int j;
1796 
1797  assert(scip != NULL);
1798  assert(gubset != NULL);
1799  assert(var >= 0);
1800  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1801  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1802  assert(oldgubcons != newgubcons);
1803  assert(gubset->gubconssidx[var] == oldgubcons);
1804  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1805  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1806 
1807  SCIPdebugMessage(" moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1808 
1809  oldgubvaridx = gubset->gubvarsidx[var];
1810 
1811  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1812  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1813 
1814  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1815  * replacement variable is given by old position of the deleted variable
1816  */
1817  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1818  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1819  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1820 
1821  /* add variable to the end of new GUB constraint */
1822  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1823  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1824 
1825  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1826  gubset->gubconssidx[var] = newgubcons;
1827  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1828 
1829  /* delete old GUB constraint if it became empty */
1830  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1831  {
1832  SCIPdebugMessage("deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1833 #ifdef SCIP_DEBUG
1834  GUBsetPrint(scip, gubset, vars, NULL);
1835 #endif
1836 
1837  /* free old GUB constraint */
1838  SCIP_CALL( GUBconsFree(scip, &gubset->gubconss[oldgubcons]) );
1839 
1840  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1841  if( oldgubcons != gubset->ngubconss-1 )
1842  {
1843  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1844  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1845 
1846  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1847  * replacement GUB is given by old position of the deleted GUB
1848  */
1849  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1850  {
1851  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1852  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1853  }
1854  }
1855 
1856  /* update number of GUB constraints */
1857  gubset->ngubconss--;
1858 
1859  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1860  * (because it was at the end of the GUB constraint array)
1861  */
1862  assert(gubset->gubconssidx[var] == newgubcons
1863  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1864  }
1865 #ifndef NDEBUG
1866  else
1867  assert(gubset->gubconssidx[var] == newgubcons);
1868 #endif
1869 
1870  return SCIP_OKAY;
1871 }
1872 
1873 /** swaps two variables in the same GUB constraint */
1874 static
1875 void GUBsetSwapVars(
1876  SCIP* scip, /**< SCIP data structure */
1877  SCIP_GUBSET* gubset, /**< GUB set data structure */
1878  int var1, /**< first variable to be swapped */
1879  int var2 /**< second variable to be swapped */
1880  )
1881 {
1882  int gubcons;
1883  int var1idx;
1884  GUBVARSTATUS var1status;
1885  int var2idx;
1886  GUBVARSTATUS var2status;
1887 
1888  assert(scip != NULL);
1889  assert(gubset != NULL);
1890 
1891  gubcons = gubset->gubconssidx[var1];
1892  assert(gubcons == gubset->gubconssidx[var2]);
1893 
1894  /* nothing to be done if both variables are the same */
1895  if( var1 == var2 )
1896  return;
1897 
1898  /* swap index and status of variables in GUB constraint */
1899  var1idx = gubset->gubvarsidx[var1];
1900  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1901  var2idx = gubset->gubvarsidx[var2];
1902  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1903 
1904  gubset->gubvarsidx[var1] = var2idx;
1905  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1906  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1907 
1908  gubset->gubvarsidx[var2] = var1idx;
1909  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1910  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1911 }
1912 
1913 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1914 static
1916  SCIP* scip, /**< SCIP data structure */
1917  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1918  int nvars, /**< number of variables in the knapsack constraint */
1919  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1920  SCIP_Longint capacity /**< capacity of knapsack */
1921  )
1923  int i;
1924 
1925  assert(scip != NULL);
1926  assert(gubset != NULL);
1927  assert(nvars > 0);
1928  assert(weights != NULL);
1929  assert(capacity >= 0);
1930 
1931  /* allocate memory for GUB set data structures */
1932  SCIP_CALL( SCIPallocMemory(scip, gubset) );
1933  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1934  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1935  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1936  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1937  (*gubset)->ngubconss = nvars;
1938  (*gubset)->nvars = nvars;
1939 
1940  /* initialize the set of GUB constraints */
1941  for( i = 0; i < nvars; i++ )
1942  {
1943  /* assign each variable to a new (trivial) GUB constraint */
1944  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1945  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1946 
1947  /* set status of GUB constraint to initial */
1948  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1949 
1950  (*gubset)->gubconssidx[i] = i;
1951  (*gubset)->gubvarsidx[i] = 0;
1952  assert((*gubset)->gubconss[i]->ngubvars == 1);
1953 
1954  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1955  if( weights[i] > capacity )
1956  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1957 
1958  }
1959 
1960  return SCIP_OKAY;
1961 }
1962 
1963 /** frees GUB set data structure */
1964 static
1966  SCIP* scip, /**< SCIP data structure */
1967  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1968  )
1969 {
1970  int i;
1971 
1972  assert(scip != NULL);
1973  assert(gubset != NULL);
1974  assert((*gubset)->gubconss != NULL);
1975  assert((*gubset)->gubconsstatus != NULL);
1976  assert((*gubset)->gubconssidx != NULL);
1977  assert((*gubset)->gubvarsidx != NULL);
1978 
1979  /* free all GUB constraints */
1980  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1981  {
1982  assert((*gubset)->gubconss[i] != NULL);
1983  SCIP_CALL( GUBconsFree(scip, &(*gubset)->gubconss[i]) );
1984  }
1985 
1986  /* free allocated memory */
1987  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1988  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1989  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1990  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
1991  SCIPfreeMemory(scip, gubset);
1992 
1993  return SCIP_OKAY;
1994 }
1995 
1996 #ifndef NDEBUG
1997 /** checks whether GUB set data structure is consistent */
1998 static
2000  SCIP* scip, /**< SCIP data structure */
2001  SCIP_GUBSET* gubset, /**< GUB set data structure */
2002  SCIP_VAR** vars /**< variables in the knapsack constraint */
2003  )
2004 {
2005  int i;
2006  int gubconsidx;
2007  int gubvaridx;
2008  SCIP_VAR* var1;
2009  SCIP_VAR* var2;
2010  SCIP_Bool var1negated;
2011  SCIP_Bool var2negated;
2012 
2013  assert(scip != NULL);
2014  assert(gubset != NULL);
2015 
2016  SCIPdebugMessage(" GUB set consistency check:\n");
2017 
2018  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2019  for( i = 0; i < gubset->nvars; i++ )
2020  {
2021  gubconsidx = gubset->gubconssidx[i];
2022  gubvaridx = gubset->gubvarsidx[i];
2023 
2024  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2025  {
2026  SCIPdebugMessage(" var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2027  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2028  }
2029  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2030  }
2031 
2032  /* checks for each GUB whether all pairs of its variables have a common clique */
2033  for( i = 0; i < gubset->ngubconss; i++ )
2034  {
2035  int j;
2036 
2037  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2038  {
2039  int k;
2040 
2041  /* get corresponding active problem variable */
2042  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2043  var1negated = FALSE;
2044  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2045 
2046  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2047  {
2048  /* get corresponding active problem variable */
2049  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2050  var2negated = FALSE;
2051  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2052 
2053  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2054  {
2055  SCIPdebugMessage(" GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2056  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2057  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2058  SCIPdebugMessage(" GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2059  SCIPvarGetName(var1), k,
2060  SCIPvarGetName(var2));
2061  }
2062 
2063  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2064  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2065  }
2066  }
2067  }
2068  SCIPdebugMessage(" --> successful\n");
2069 
2070  return SCIP_OKAY;
2071 }
2072 #endif
2073 
2074 /** calculates a partition of the given set of binary variables into cliques;
2075  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2076  * were assigned to the same clique;
2077  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2078  * the preceding variables was assigned to clique i-1;
2079  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2080  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2081  */
2082 #define MAXNCLIQUEVARSCOMP 1000000
2083 static
2085  SCIP*const scip, /**< SCIP data structure */
2086  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2087  int const nvars, /**< number of variables in the clique */
2088  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2089  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2090  SCIP_Real* solvals /**< solution values of all given binary variables */
2091  )
2092 {
2093  SCIP_VAR** tmpvars;
2094  SCIP_VAR** cliquevars;
2095  SCIP_Bool* cliquevalues;
2096  SCIP_Bool* tmpvalues;
2097  int* varseq;
2098  int* sortkeys;
2099  int ncliquevars;
2100  int maxncliquevarscomp;
2101  int nignorevars;
2102  int nvarsused;
2103  int i;
2104 
2105  assert(scip != NULL);
2106  assert(nvars == 0 || vars != NULL);
2107  assert(nvars == 0 || cliquepartition != NULL);
2108  assert(ncliques != NULL);
2109 
2110  if( nvars == 0 )
2111  {
2112  *ncliques = 0;
2113  return SCIP_OKAY;
2114  }
2115 
2116  /* allocate temporary memory for storing the variables of the current clique */
2117  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2118  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2119  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2120  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2121  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2122  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2123  ncliquevars = 0;
2124 
2125  /* initialize the cliquepartition array with -1 */
2126  /* initialize the tmpvalues array */
2127  for( i = nvars - 1; i >= 0; --i )
2128  {
2129  tmpvalues[i] = TRUE;
2130  cliquepartition[i] = -1;
2131  }
2132 
2133  /* get corresponding active problem variables */
2134  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2135 
2136  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2137  * by nondecreasing number of cliques the variables are in
2138  */
2139  nignorevars = 0;
2140  nvarsused = 0;
2141  for( i = 0; i < nvars; i++ )
2142  {
2143  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2144  {
2145  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2146  varseq[nvars-1-nignorevars] = i;
2147  nignorevars++;
2148  }
2149  else
2150  {
2151  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2152  varseq[nvarsused] = i;
2153  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2154  nvarsused++;
2155  }
2156  }
2157  assert(nvarsused + nignorevars == nvars);
2158 
2159  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2160  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2161 
2162  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2163 
2164  /* calculate the clique partition */
2165  *ncliques = 0;
2166  for( i = 0; i < nvars; ++i )
2167  {
2168  if( cliquepartition[varseq[i]] == -1 )
2169  {
2170  int j;
2171 
2172  /* variable starts a new clique */
2173  cliquepartition[varseq[i]] = *ncliques;
2174  cliquevars[0] = tmpvars[varseq[i]];
2175  cliquevalues[0] = tmpvalues[varseq[i]];
2176  ncliquevars = 1;
2177 
2178  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2179  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2180  */
2181  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2182  {
2183  /* greedily fill up the clique */
2184  for( j = i + 1; j < nvarsused; ++j )
2185  {
2186  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2187  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2188  {
2189  int k;
2190 
2191  /* check if every variable in the actual clique is in clique with the new variable */
2192  for( k = ncliquevars - 1; k >= 0; --k )
2193  {
2194  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2195  cliquevalues[k], TRUE) )
2196  break;
2197  }
2198 
2199  if( k == -1 )
2200  {
2201  /* put the variable into the same clique */
2202  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2203  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2204  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2205  ++ncliquevars;
2206  }
2207  }
2208  }
2209  }
2210 
2211  /* this clique is finished */
2212  ++(*ncliques);
2213  }
2214  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2215 
2216  /* break if we reached the maximal number of comparisons */
2217  if( i * nvars > maxncliquevarscomp )
2218  break;
2219  }
2220  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2221  for( ; i < nvars; ++i )
2222  {
2223  if( cliquepartition[varseq[i]] == -1 )
2224  {
2225  cliquepartition[varseq[i]] = *ncliques;
2226  ++(*ncliques);
2227  }
2228  }
2229 
2230  /* free temporary memory */
2231  SCIPfreeBufferArray(scip, &sortkeys);
2232  SCIPfreeBufferArray(scip, &varseq);
2233  SCIPfreeBufferArray(scip, &tmpvars);
2234  SCIPfreeBufferArray(scip, &tmpvalues);
2235  SCIPfreeBufferArray(scip, &cliquevalues);
2236  SCIPfreeBufferArray(scip, &cliquevars);
2237 
2238  return SCIP_OKAY;
2239 }
2240 
2241 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2242 static
2244  SCIP* scip, /**< SCIP data structure */
2245  SCIP_GUBSET* gubset, /**< GUB set data structure */
2246  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2247  SCIP_Real* solvals /**< solution values of all knapsack variables */
2248  )
2249 {
2250  int* cliquepartition;
2251  int* gubfirstvar;
2252  int ncliques;
2253  int currentgubconsidx;
2254  int newgubconsidx;
2255  int cliqueidx;
2256  int nvars;
2257  int i;
2258 
2259  assert(scip != NULL);
2260  assert(gubset != NULL);
2261  assert(vars != NULL);
2262 
2263  nvars = gubset->nvars;
2264  assert(nvars >= 0);
2265 
2266  /* allocate temporary memory for clique partition */
2267  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2268 
2269  /* compute sophisticated clique partition */
2270  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2271 
2272  /* allocate temporary memory for GUB set data structure */
2273  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2274 
2275  /* translate GUB partition into GUB set data structure */
2276  for( i = 0; i < ncliques; i++ )
2277  {
2278  /* initialize first variable for every GUB */
2279  gubfirstvar[i] = -1;
2280  }
2281  /* move every knapsack variable into GUB defined by clique partition */
2282  for( i = 0; i < nvars; i++ )
2283  {
2284  assert(cliquepartition[i] >= 0);
2285 
2286  cliqueidx = cliquepartition[i];
2287  currentgubconsidx = gubset->gubconssidx[i];
2288  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2289 
2290  /* variable is first element in GUB constraint defined by clique partition */
2291  if( gubfirstvar[cliqueidx] == -1 )
2292  {
2293  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2294  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2295  */
2296  assert(gubset->gubvarsidx[i] == 0);
2297  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2298 
2299  /* remember the first variable found for the current GUB */
2300  gubfirstvar[cliqueidx] = i;
2301  }
2302  /* variable is additional element of GUB constraint defined by clique partition */
2303  else
2304  {
2305  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2306 
2307  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2308  * first variable of this GUB constraint
2309  */
2310  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2311  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2312  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2313 
2314  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2315  }
2316  }
2317 
2318 #ifdef SCIP_DEBUG
2319  /* prints GUB set data structure */
2320  GUBsetPrint(scip, gubset, vars, solvals);
2321 #endif
2322 
2323 #ifndef NDEBUG
2324  /* checks consistency of GUB set data structure */
2325  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2326 #endif
2327 
2328  /* free temporary memory */
2329  SCIPfreeBufferArray(scip, &gubfirstvar);
2330  SCIPfreeBufferArray(scip, &cliquepartition);
2331 
2332  return SCIP_OKAY;
2333 }
2334 
2335 /** 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$
2336  * 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
2337  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2338  */
2339 static
2341  SCIP* scip, /**< SCIP data structure */
2342  SCIP_VAR** vars, /**< variables in knapsack constraint */
2343  int nvars, /**< number of variables in knapsack constraint */
2344  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2345  SCIP_Longint capacity, /**< capacity of knapsack */
2346  SCIP_Real* solvals, /**< solution values of all problem variables */
2347  int* covervars, /**< pointer to store cover variables */
2348  int* noncovervars, /**< pointer to store noncover variables */
2349  int* ncovervars, /**< pointer to store number of cover variables */
2350  int* nnoncovervars, /**< pointer to store number of noncover variables */
2351  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2352  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2353  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2354  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2355  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2356  )
2357 {
2358  SCIP_Longint* transweights;
2359  SCIP_Real* transprofits;
2360  SCIP_Longint transcapacity;
2361  SCIP_Longint fixedonesweight;
2362  SCIP_Longint itemsweight;
2363  SCIP_Bool infeasible;
2364  int* fixedones;
2365  int* fixedzeros;
2366  int* items;
2367  int nfixedones;
2368  int nfixedzeros;
2369  int nitems;
2370  int j;
2371 
2372  assert(scip != NULL);
2373  assert(vars != NULL);
2374  assert(nvars > 0);
2375  assert(weights != NULL);
2376  assert(capacity >= 0);
2377  assert(solvals != NULL);
2378  assert(covervars != NULL);
2379  assert(noncovervars != NULL);
2380  assert(ncovervars != NULL);
2381  assert(nnoncovervars != NULL);
2382  assert(coverweight != NULL);
2383  assert(found != NULL);
2384  assert(ntightened != NULL);
2385  assert(fractional != NULL);
2386 
2387  SCIPdebugMessage(" get cover for knapsack constraint\n");
2388 
2389  /* allocates temporary memory */
2390  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2391  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2392  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2393  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2394  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2395 
2396  *found = FALSE;
2397  *ncovervars = 0;
2398  *nnoncovervars = 0;
2399  *coverweight = 0;
2400  *fractional = TRUE;
2401 
2402  /* gets the following sets
2403  * N_1 = {j in N : x*_j = 1} (fixedones),
2404  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2405  * N\(N_0 & N_1) (items),
2406  * where x*_j is the solution value of variable x_j
2407  */
2408  nfixedones = 0;
2409  nfixedzeros = 0;
2410  nitems = 0;
2411  fixedonesweight = 0;
2412  itemsweight = 0;
2413  *ntightened = 0;
2414  for( j = 0; j < nvars; j++ )
2415  {
2416  assert(SCIPvarIsBinary(vars[j]));
2417 
2418  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2419  if( weights[j] > capacity )
2420  {
2421  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2422  assert(!infeasible);
2423  (*ntightened)++;
2424  continue;
2425  }
2426 
2427  /* variable x_j has solution value one */
2428  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2429  {
2430  fixedones[nfixedones] = j;
2431  nfixedones++;
2432  fixedonesweight += weights[j];
2433  }
2434  /* variable x_j has solution value zero */
2435  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2436  {
2437  fixedzeros[nfixedzeros] = j;
2438  nfixedzeros++;
2439  }
2440  /* variable x_j has fractional solution value */
2441  else
2442  {
2443  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2444  items[nitems] = j;
2445  nitems++;
2446  itemsweight += weights[j];
2447  }
2448  }
2449  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2450 
2451  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2452  * the separation routine
2453  */
2454  assert(nitems >= 0);
2455  if( nitems == 0 )
2456  {
2457  *fractional = FALSE;
2458  goto TERMINATE;
2459  }
2460  assert(*fractional);
2461 
2462  /* transforms the traditional separation problem (under consideration of the following fixing:
2463  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2464  *
2465  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2466  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2467  * z_j in {0,1}, j in N\(N_0 & N_1)
2468  *
2469  * to a knapsack problem in maximization form by complementing the variables
2470  *
2471  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2472  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2473  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2474  * z_j in {0,1}, j in N\(N_0 & N_1)
2475  */
2476 
2477  /* gets weight and profit of variables in transformed knapsack problem */
2478  for( j = 0; j < nitems; j++ )
2479  {
2480  transweights[j] = weights[items[j]];
2481  transprofits[j] = 1.0 - solvals[items[j]];
2482  }
2483  /* gets capacity of transformed knapsack problem */
2484  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2485 
2486  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2487  * (when variables fixed to zero are not used)
2488  */
2489  if( transcapacity < 0 )
2490  {
2491  assert(!(*found));
2492  goto TERMINATE;
2493  }
2494 
2495  if( modtransused )
2496  {
2497  /* transforms the modified separation problem (under consideration of the following fixing:
2498  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2499  *
2500  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2501  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2502  * z_j in {0,1}, j in N\(N_0 & N_1)
2503  *
2504  * to a knapsack problem in maximization form by complementing the variables
2505  *
2506  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2507  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2508  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2509  * z_j in {0,1}, j in N\(N_0 & N_1)
2510  */
2511 
2512  /* gets weight and profit of variables in modified transformed knapsack problem */
2513  for( j = 0; j < nitems; j++ )
2514  {
2515  transprofits[j] *= weights[items[j]];
2516  assert(SCIPisFeasPositive(scip, transprofits[j]));
2517  }
2518  }
2519 
2520  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2521  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2522  * let z* be the solution, then
2523  * j in C, if z*_j = 0 and
2524  * i in N\C, if z*_j = 1.
2525  */
2526  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2527  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2528  assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));
2529 
2530  /* constructs cover C (sum_{j in C} a_j > a_0) */
2531  for( j = 0; j < *ncovervars; j++ )
2532  {
2533  (*coverweight) += weights[covervars[j]];
2534  }
2535 
2536  /* adds all variables from N_1 to C */
2537  for( j = 0; j < nfixedones; j++ )
2538  {
2539  covervars[*ncovervars] = fixedones[j];
2540  (*ncovervars)++;
2541  (*coverweight) += weights[fixedones[j]];
2542  }
2543 
2544  /* adds all variables from N_0 to N\C */
2545  for( j = 0; j < nfixedzeros; j++ )
2546  {
2547  noncovervars[*nnoncovervars] = fixedzeros[j];
2548  (*nnoncovervars)++;
2549  }
2550  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2551  assert((*coverweight) > capacity);
2552  *found = TRUE;
2553 
2554  TERMINATE:
2555  /* frees temporary memory */
2556  SCIPfreeBufferArray(scip, &items);
2557  SCIPfreeBufferArray(scip, &fixedzeros);
2558  SCIPfreeBufferArray(scip, &fixedones);
2559  SCIPfreeBufferArray(scip, &transprofits);
2560  SCIPfreeBufferArray(scip, &transweights);
2561 
2562  SCIPdebugMessage(" get cover for knapsack constraint -- end\n");
2563 
2564  return SCIP_OKAY;
2565 }
2566 
2567 #ifndef NDEBUG
2568 /** checks if minweightidx is set correctly
2569  */
2570 static
2572  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2573  SCIP_Longint capacity, /**< capacity of knapsack */
2574  int* covervars, /**< pointer to store cover variables */
2575  int ncovervars, /**< pointer to store number of cover variables */
2576  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2577  int minweightidx, /**< index of variable in cover variables with minimum weight */
2578  int j /**< current index in cover variables */
2579  )
2580 {
2581  SCIP_Longint minweight;
2582  int i;
2583 
2584  assert(weights != NULL);
2585  assert(covervars != NULL);
2586  assert(ncovervars > 0);
2587 
2588  minweight = weights[covervars[minweightidx]];
2589 
2590  /* checks if all cover variables before index j have weight greater than minweight */
2591  for( i = 0; i < j; i++ )
2592  {
2593  assert(weights[covervars[i]] > minweight);
2594  if( weights[covervars[i]] <= minweight )
2595  return FALSE;
2596  }
2597 
2598  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2599  for( i = 0; i < j; i++ )
2600  {
2601  assert(coverweight - weights[covervars[i]] <= capacity);
2602  if( coverweight - weights[covervars[i]] > capacity )
2603  return FALSE;
2604  }
2605  return TRUE;
2606 }
2607 #endif
2608 
2609 
2610 /** 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$,
2611  * 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$
2612  */
2613 static
2615  SCIP* scip, /**< SCIP data structure */
2616  SCIP_Real* solvals, /**< solution values of all problem variables */
2617  int* covervars, /**< cover variables */
2618  int ncovervars, /**< number of cover variables */
2619  int* varsC1, /**< pointer to store variables in C1 */
2620  int* varsC2, /**< pointer to store variables in C2 */
2621  int* nvarsC1, /**< pointer to store number of variables in C1 */
2622  int* nvarsC2 /**< pointer to store number of variables in C2 */
2623  )
2624 {
2625  int j;
2626 
2627  assert(scip != NULL);
2628  assert(ncovervars >= 0);
2629  assert(solvals != NULL);
2630  assert(covervars != NULL);
2631  assert(varsC1 != NULL);
2632  assert(varsC2 != NULL);
2633  assert(nvarsC1 != NULL);
2634  assert(nvarsC2 != NULL);
2635 
2636  *nvarsC1 = 0;
2637  *nvarsC2 = 0;
2638  for( j = 0; j < ncovervars; j++ )
2639  {
2640  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2641 
2642  /* variable has solution value one */
2643  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2644  {
2645  varsC2[*nvarsC2] = covervars[j];
2646  (*nvarsC2)++;
2647  }
2648  /* variable has solution value less than one */
2649  else
2650  {
2651  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2652  varsC1[*nvarsC1] = covervars[j];
2653  (*nvarsC1)++;
2654  }
2655  }
2656  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2657 }
2658 
2659 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2660  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2661  */
2662 static
2664  SCIP* scip, /**< SCIP data structure */
2665  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2666  int* varsC1, /**< pointer to store variables in C1 */
2667  int* varsC2, /**< pointer to store variables in C2 */
2668  int* nvarsC1, /**< pointer to store number of variables in C1 */
2669  int* nvarsC2 /**< pointer to store number of variables in C2 */
2670  )
2671 {
2672  SCIP_Real* sortkeysC2;
2673  int j;
2674 
2675  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2676  assert(*nvarsC2 > 0);
2677 
2678  /* allocates temporary memory */
2679  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2680 
2681  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2682  for( j = 0; j < *nvarsC2; j++ )
2683  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2684  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2685 
2686  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2687  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2688  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2689  {
2690  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2691  (*nvarsC1)++;
2692  (*nvarsC2)--;
2693  }
2694 
2695  /* frees temporary memory */
2696  SCIPfreeBufferArray(scip, &sortkeysC2);
2697 
2698  return SCIP_OKAY;
2699 }
2700 
2701 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2702 static
2704  SCIP* scip, /**< SCIP data structure */
2705  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2706  int* varsC1, /**< pointer to store variables in C1 */
2707  int* varsC2, /**< pointer to store variables in C2 */
2708  int* nvarsC1, /**< pointer to store number of variables in C1 */
2709  int* nvarsC2 /**< pointer to store number of variables in C2 */
2710  )
2711 {
2712  SCIP_Real* sortkeysC2;
2713  int j;
2714 
2715  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2716  assert(*nvarsC2 > 0);
2717 
2718  /* allocates temporary memory */
2719  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2720 
2721  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2722  for( j = 0; j < *nvarsC2; j++ )
2723  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2724  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2725 
2726  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2727  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2728  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2729  (*nvarsC1)++;
2730  (*nvarsC2)--;
2731 
2732  /* frees temporary memory */
2733  SCIPfreeBufferArray(scip, &sortkeysC2);
2734 
2735  return SCIP_OKAY;
2736 }
2737 
2738 
2739 /** 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$
2740  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2741  * \f$F = (N \setminus C) \setminus F\f$
2742  */
2743 static
2745  SCIP* scip, /**< SCIP data structure */
2746  SCIP_Real* solvals, /**< solution values of all problem variables */
2747  int* noncovervars, /**< noncover variables */
2748  int nnoncovervars, /**< number of noncover variables */
2749  int* varsF, /**< pointer to store variables in F */
2750  int* varsR, /**< pointer to store variables in R */
2751  int* nvarsF, /**< pointer to store number of variables in F */
2752  int* nvarsR /**< pointer to store number of variables in R */
2753  )
2754 {
2755  int j;
2756 
2757  assert(scip != NULL);
2758  assert(nnoncovervars >= 0);
2759  assert(solvals != NULL);
2760  assert(noncovervars != NULL);
2761  assert(varsF != NULL);
2762  assert(varsR != NULL);
2763  assert(nvarsF != NULL);
2764  assert(nvarsR != NULL);
2765 
2766  *nvarsF = 0;
2767  *nvarsR = 0;
2768 
2769  for( j = 0; j < nnoncovervars; j++ )
2770  {
2771  /* variable has solution value zero */
2772  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2773  {
2774  varsR[*nvarsR] = noncovervars[j];
2775  (*nvarsR)++;
2776  }
2777  /* variable has solution value greater than zero */
2778  else
2779  {
2780  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2781  varsF[*nvarsF] = noncovervars[j];
2782  (*nvarsF)++;
2783  }
2784  }
2785  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2786 }
2787 
2788 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2789  * lifting procedure
2790  */
2791 static
2793  SCIP* scip, /**< SCIP data structure */
2794  SCIP_Real* solvals, /**< solution values of all problem variables */
2795  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2796  int* varsF, /**< pointer to store variables in F */
2797  int* varsC2, /**< pointer to store variables in C2 */
2798  int* varsR, /**< pointer to store variables in R */
2799  int nvarsF, /**< number of variables in F */
2800  int nvarsC2, /**< number of variables in C2 */
2801  int nvarsR /**< number of variables in R */
2802  )
2803 {
2804  SORTKEYPAIR** sortkeypairsF;
2805  SORTKEYPAIR* sortkeypairsFstore;
2806  SCIP_Real* sortkeysC2;
2807  SCIP_Real* sortkeysR;
2808  int j;
2809 
2810  assert(scip != NULL);
2811  assert(solvals != NULL);
2812  assert(weights != NULL);
2813  assert(varsF != NULL);
2814  assert(varsC2 != NULL);
2815  assert(varsR != NULL);
2816  assert(nvarsF >= 0);
2817  assert(nvarsC2 >= 0);
2818  assert(nvarsR >= 0);
2819 
2820  /* allocates temporary memory */
2821  SCIP_CALL( SCIPallocMemoryArray(scip, &sortkeypairsF, nvarsF) );
2822  SCIP_CALL( SCIPallocMemoryArray(scip, &sortkeypairsFstore, nvarsF) );
2823  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2824  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2825 
2826  /* gets sorting key for variables in F corresponding to the following lifting sequence
2827  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2828  * x*_1 >= x*_2 >= ... >= x*_|F|
2829  * in case of equality uses
2830  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2831  */
2832  for( j = 0; j < nvarsF; j++ )
2833  {
2834  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2835  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2836  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2837  }
2838 
2839  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2840  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2841  */
2842  for( j = 0; j < nvarsC2; j++ )
2843  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2844 
2845  /* gets sorting key for variables in R corresponding to the following lifting sequence
2846  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2847  */
2848  for( j = 0; j < nvarsR; j++ )
2849  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2850 
2851  /* sorts F, C2 and R */
2852  if( nvarsF > 0 )
2853  {
2854  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2855  }
2856  if( nvarsC2 > 0 )
2857  {
2858  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2859  }
2860  if( nvarsR > 0)
2861  {
2862  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2863  }
2864 
2865  /* frees temporary memory */
2866  SCIPfreeBufferArray(scip, &sortkeysR);
2867  SCIPfreeBufferArray(scip, &sortkeysC2);
2868  SCIPfreeMemoryArray(scip, &sortkeypairsFstore);
2869  SCIPfreeMemoryArray(scip, &sortkeypairsF);
2870 
2871  return SCIP_OKAY;
2872 }
2873 
2874 /** categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2875  * for the sequential GUB wise lifting procedure
2876  */
2877 static
2879  SCIP* scip, /**< SCIP data structure */
2880  SCIP_GUBSET* gubset, /**< GUB set data structure */
2881  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2882  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2883  int* varsC1, /**< variables in C1 */
2884  int* varsC2, /**< variables in C2 */
2885  int* varsF, /**< variables in F */
2886  int* varsR, /**< variables in R */
2887  int nvarsC1, /**< number of variables in C1 */
2888  int nvarsC2, /**< number of variables in C2 */
2889  int nvarsF, /**< number of variables in F */
2890  int nvarsR, /**< number of variables in R */
2891  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2892  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2893  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2894  int* gubconsGR, /**< pointer to store GUBs in GR */
2895  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2896  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2897  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2898  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2899  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2900  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2901  )
2902 {
2903 #if 0 /* not required */
2904  SORTKEYPAIR** sortkeypairsF;
2905 #endif
2906  SORTKEYPAIR** sortkeypairsGFC1;
2907  SORTKEYPAIR* sortkeypairsGFC1store;
2908  SCIP_Real* sortkeysC1;
2909  SCIP_Real* sortkeysC2;
2910  SCIP_Real* sortkeysR;
2911  int* nC1varsingubcons;
2912  int var;
2913  int gubconsidx;
2914  int varidx;
2915  int ngubconss;
2916  int ngubconsGOC1;
2917  int targetvar;
2918  int nvarsprocessed;
2919  int i;
2920  int j;
2921 
2922 #if GUBSPLITGNC1GUBS
2923  SCIP_Bool gubconswithF;
2924  int origngubconss;
2925  origngubconss = gubset->ngubconss;
2926 #endif
2927 
2928  assert(scip != NULL);
2929  assert(gubset != NULL);
2930  assert(solvals != NULL);
2931  assert(weights != NULL);
2932  assert(varsC1 != NULL);
2933  assert(varsC2 != NULL);
2934  assert(varsF != NULL);
2935  assert(varsR != NULL);
2936  assert(nvarsC1 > 0);
2937  assert(nvarsC2 >= 0);
2938  assert(nvarsF >= 0);
2939  assert(nvarsR >= 0);
2940  assert(gubconsGC1 != NULL);
2941  assert(gubconsGC2 != NULL);
2942  assert(gubconsGFC1 != NULL);
2943  assert(gubconsGR != NULL);
2944  assert(ngubconsGC1 != NULL);
2945  assert(ngubconsGC2 != NULL);
2946  assert(ngubconsGFC1 != NULL);
2947  assert(ngubconsGR != NULL);
2948  assert(maxgubvarssize != NULL);
2949 
2950  ngubconss = gubset->ngubconss;
2951  nvarsprocessed = 0;
2952  ngubconsGOC1 = 0;
2953 
2954  /* GUBs are categorized into different types according to the variables in volved
2955  * - GOC1: involves variables in C1 only -- no C2, R, F
2956  * - GNC1: involves variables in C1 and F (and R) -- no C2
2957  * - GF: involves variables in F (and R) only -- no C1, C2
2958  * - GC2: involves variables in C2 only -- no C1, R, F
2959  * - GR: involves variables in R only -- no C1, C2, F
2960  * which requires splitting GUBs in case they include variable in F and R.
2961  *
2962  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2963  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2964  * - second ordering level is
2965  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2966  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2967  * GR: non-increasing max{ a_k : k in GR_j}
2968  *
2969  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2970  * - GC1: GUBs of category GOC1 and GNC1
2971  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2972  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2973  */
2974 
2975  /* allocates temporary memory */
2976  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2977 #if 0 /* not required */
2978  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2979 #endif
2980  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2981  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2982 
2983 
2984  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2985  * - F: non-increasing x*_j and non-increasing a_j in case of equality
2986  * - C2: non-increasing a_j
2987  * - R: non-increasing a_j
2988  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2989  */
2990 
2991  /* gets sorting key for variables in C1 corresponding to the following ordering
2992  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
2993  */
2994  for( j = 0; j < nvarsC1; j++ )
2995  {
2996  /* gets sortkeys */
2997  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
2998 
2999  /* update status of variable in its gub constraint */
3000  gubconsidx = gubset->gubconssidx[varsC1[j]];
3001  varidx = gubset->gubvarsidx[varsC1[j]];
3002  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3003  }
3004 
3005  /* gets sorting key for variables in F corresponding to the following ordering
3006  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3007  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3008  * and updates status of each variable in F in GUB set data structure
3009  */
3010  for( j = 0; j < nvarsF; j++ )
3011  {
3012 #if 0 /* not required */
3013  /* gets sortkeys */
3014  SCIP_CALL( SCIPallocBuffer(scip, &sortkeypairsF[j]) );
3015  sortkeypairsF[j]->key1 = solvals[varsF[j]];
3016  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
3017 #endif
3018 
3019  /* update status of variable in its gub constraint */
3020  gubconsidx = gubset->gubconssidx[varsF[j]];
3021  varidx = gubset->gubvarsidx[varsF[j]];
3022  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3023  }
3024 
3025  /* gets sorting key for variables in C2 corresponding to the following ordering
3026  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3027  * and updates status of each variable in F in GUB set data structure
3028  */
3029  for( j = 0; j < nvarsC2; j++ )
3030  {
3031  /* gets sortkeys */
3032  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3033 
3034  /* update status of variable in its gub constraint */
3035  gubconsidx = gubset->gubconssidx[varsC2[j]];
3036  varidx = gubset->gubvarsidx[varsC2[j]];
3037  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3038  }
3039 
3040  /* gets sorting key for variables in R corresponding to the following ordering
3041  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3042  * and updates status of each variable in F in GUB set data structure
3043  */
3044  for( j = 0; j < nvarsR; j++ )
3045  {
3046  /* gets sortkeys */
3047  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3048 
3049  /* update status of variable in its gub constraint */
3050  gubconsidx = gubset->gubconssidx[varsR[j]];
3051  varidx = gubset->gubvarsidx[varsR[j]];
3052  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3053  }
3054 
3055  /* sorts C1, F, C2 and R */
3056  if( nvarsC1 > 0 )
3057  {
3058  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3059  }
3060 #if 0 /* not required */
3061  if( nvarsF > 0 )
3062  {
3063  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
3064  }
3065 #endif
3066  if( nvarsC2 > 0 )
3067  {
3068  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3069  }
3070  if( nvarsR > 0)
3071  {
3072  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3073  }
3074 
3075  /* frees temporary memory */
3076  SCIPfreeBufferArray(scip, &sortkeysR);
3077  SCIPfreeBufferArray(scip, &sortkeysC2);
3078 #if 0 /* not required */
3079  for( j = nvarsF-1; j >= 0; j-- )
3080  SCIPfreeBuffer(scip, &sortkeypairsF[j]);
3081  SCIPfreeBufferArray(scip, &sortkeypairsF);
3082 #endif
3083  SCIPfreeBufferArray(scip, &sortkeysC1);
3084 
3085  /* allocate and initialize temporary memory for sorting GUB constraints */
3086  SCIP_CALL( SCIPallocMemoryArray(scip, &sortkeypairsGFC1, ngubconss) );
3087  SCIP_CALL( SCIPallocMemoryArray(scip, &sortkeypairsGFC1store, ngubconss) );
3088  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3089  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3090  for( i = 0; i < ngubconss; i++)
3091  {
3092  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3093  sortkeypairsGFC1[i]->key1 = 0.0;
3094  sortkeypairsGFC1[i]->key2 = 0.0;
3095  }
3096  *ngubconsGC1 = 0;
3097  *ngubconsGC2 = 0;
3098  *ngubconsGFC1 = 0;
3099  *ngubconsGR = 0;
3100  *ngubconscapexceed = 0;
3101  *maxgubvarssize = 0;
3102 
3103 #ifndef NDEBUG
3104  for( i = 0; i < gubset->ngubconss; i++ )
3105  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3106 #endif
3107 
3108  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3109  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3110  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3111  * non-increasing number of variables in F, and
3112  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3113  */
3114  for( i = 0; i < nvarsC1; i++ )
3115  {
3116  int nvarsC1capexceed;
3117 
3118  nvarsC1capexceed = 0;
3119 
3120  var = varsC1[i];
3121  gubconsidx = gubset->gubconssidx[var];
3122  varidx = gubset->gubvarsidx[var];
3123 
3124  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3125  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3126 
3127  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3128  * note that variables in C1 are already sorted by non-decreasing weigth
3129  */
3130  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3131  GUBsetSwapVars(scip, gubset, var, targetvar);
3132  nC1varsingubcons[gubconsidx]++;
3133 
3134  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3135  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3136  {
3137  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3138  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3139  continue;
3140  }
3141 
3142  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3143  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3144  */
3145 #if GUBSPLITGNC1GUBS
3146  gubconswithF = FALSE;
3147 #endif
3148  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3149  {
3150  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3151 
3152  /* C1-variable: update number of C1/capacity exceeding variables */
3153  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3154  {
3155  nvarsC1capexceed++;
3156  nvarsprocessed++;
3157  }
3158  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3159  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3160  {
3161 #if GUBSPLITGNC1GUBS
3162  gubconswithF = TRUE;
3163 #endif
3164  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3165 
3166  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3167  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3168  }
3169  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3170  {
3171  nvarsC1capexceed++;
3172  }
3173  else
3174  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3175  }
3176 
3177  /* update set of GC1 GUBs */
3178  gubconsGC1[*ngubconsGC1] = gubconsidx;
3179  (*ngubconsGC1)++;
3180 
3181  /* update maximum size of all GUB constraints */
3182  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3183  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3184 
3185  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3186  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3187  {
3188  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3189  ngubconsGOC1++;
3190  }
3191  else
3192  {
3193 #if GUBSPLITGNC1GUBS
3194  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3195  if( !gubconswithF )
3196  {
3197  GUBVARSTATUS movevarstatus;
3198 
3199  assert(gubset->ngubconss < gubset->nvars);
3200 
3201  /* create a new GUB for GR part of splitting */
3202  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3203  gubset->ngubconss++;
3204  ngubconss = gubset->ngubconss;
3205 
3206  /* fill GR with R variables in current GUB */
3207  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3208  {
3209  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3210  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3211  {
3212  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3213  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3214  gubconsidx, ngubconss-1) );
3215  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3216  movevarstatus;
3217  }
3218  }
3219 
3220  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3221  ngubconsGOC1++;
3222 
3223  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3224  gubconsGR[*ngubconsGR] = ngubconss-1;
3225  (*ngubconsGR)++;
3226  }
3227  /* variables in C1, F, and maybe R: GNC1 GUB */
3228  else
3229  {
3230  assert(gubconswithF);
3231 
3232  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3233  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3234  (*ngubconsGFC1)++;
3235  }
3236 #else
3237  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3238  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3239  (*ngubconsGFC1)++;
3240 #endif
3241  }
3242  }
3243 
3244  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3245  * are already sorted correctly
3246  */
3247  for( i = 0; i < nvarsC2; i++ )
3248  {
3249  var = varsC2[i];
3250  gubconsidx = gubset->gubconssidx[var];
3251  varidx = gubset->gubvarsidx[var];
3252 
3253  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3254  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3255  assert(varidx == 0);
3256  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3257  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3258 
3259  /* set status of GC2 GUB */
3260  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3261 
3262  /* update group of GC2 GUBs */
3263  gubconsGC2[*ngubconsGC2] = gubconsidx;
3264  (*ngubconsGC2)++;
3265 
3266  /* update maximum size of all GUB constraints */
3267  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3268  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3269 
3270  nvarsprocessed++;
3271  }
3272 
3273  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3274  * non-increasing number of variables in F, and
3275  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3276  */
3277  for( i = 0; i < nvarsF; i++ )
3278  {
3279  var = varsF[i];
3280  gubconsidx = gubset->gubconssidx[var];
3281  varidx = gubset->gubvarsidx[var];
3282 
3283  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3284  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3285 
3286  nvarsprocessed++;
3287 
3288  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3289  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3290  {
3291  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3292  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3293  continue;
3294  }
3295 
3296  /* set status of GF GUB */
3297  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3298 
3299  /* update sorting key of corresponding GFC1 GUB */
3300  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3301  {
3302  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3303  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3304 
3305  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3306  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3307  {
3308  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3309 
3310  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3311  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3312  }
3313  }
3314 
3315  /* update set of GFC1 GUBs */
3316  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3317  (*ngubconsGFC1)++;
3318 
3319  /* update maximum size of all GUB constraints */
3320  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3321  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3322  }
3323 
3324  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3325  * correctly
3326  */
3327  for( i = 0; i < nvarsR; i++ )
3328  {
3329  var = varsR[i];
3330  gubconsidx = gubset->gubconssidx[var];
3331  varidx = gubset->gubvarsidx[var];
3332 
3333  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3334  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3335 
3336  nvarsprocessed++;
3337 
3338  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3339  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3340  {
3341  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3342  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3343  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3344  continue;
3345  }
3346 
3347  /* set status of GR GUB */
3348  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3349 
3350  /* update set of GR GUBs */
3351  gubconsGR[*ngubconsGR] = gubconsidx;
3352  (*ngubconsGR)++;
3353 
3354  /* update maximum size of all GUB constraints */
3355  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3356  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3357  }
3358  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3359 
3360  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3361  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3362  assert(*ngubconscapexceed >= 0);
3363 #ifndef NDEBUG
3364  {
3365  int check;
3366 
3367  check = 0;
3368 
3369  /* remaining not handled GUBs should only contain capacity exceeding variables */
3370  for( i = 0; i < ngubconss; i++ )
3371  {
3372  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3373  check++;
3374  }
3375  assert(check == *ngubconscapexceed);
3376  }
3377 #endif
3378 
3379  /* sort GFCI GUBs according to computed sorting keys */
3380  if( (*ngubconsGFC1) > 0 )
3381  {
3382  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3383  }
3384 
3385  /* free temporary memory */
3386 #if GUBSPLITGNC1GUBS
3387  ngubconss = origngubconss;
3388 #endif
3389  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3390  SCIPfreeMemoryArray(scip, &sortkeypairsGFC1store);
3391  SCIPfreeMemoryArray(scip, &sortkeypairsGFC1);
3392 
3393  return SCIP_OKAY;
3394 }
3395 
3396 /** enlarges minweight table to at least the given length */
3397 static
3399  SCIP* scip, /**< SCIP data structure */
3400  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3401  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3402  int* minweightssize, /**< pointer to current size of minweights table */
3403  int newlen /**< new length of minweights table */
3404  )
3406  int j;
3407 
3408  assert(minweightsptr != NULL);
3409  assert(*minweightsptr != NULL);
3410  assert(minweightslen != NULL);
3411  assert(*minweightslen >= 0);
3412  assert(minweightssize != NULL);
3413  assert(*minweightssize >= 0);
3414 
3415  if( newlen > *minweightssize )
3416  {
3417  int newsize;
3418 
3419  /* reallocate table memory */
3420  newsize = SCIPcalcMemGrowSize(scip, newlen);
3421  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3422  *minweightssize = newsize;
3423  }
3424  assert(newlen <= *minweightssize);
3425 
3426  /* initialize new elements */
3427  for( j = *minweightslen; j < newlen; ++j )
3428  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3429  *minweightslen = newlen;
3430 
3431  return SCIP_OKAY;
3432 }
3433 
3434 /** lifts given inequality
3435  * sum_{j in M_1} x_j <= alpha_0
3436  * valid for
3437  * 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 }
3438  * to a valid inequality
3439  * 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
3440  * <= alpha_0 + sum_{j in M_2} alpha_j
3441  * for
3442  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3443  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3444  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3445  * extended weight inequalities.
3446  */
3447 static
3449  SCIP* scip, /**< SCIP data structure */
3450  SCIP_VAR** vars, /**< variables in knapsack constraint */
3451  int nvars, /**< number of variables in knapsack constraint */
3452  int ntightened, /**< number of variables with tightened upper bound */
3453  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3454  SCIP_Longint capacity, /**< capacity of knapsack */
3455  SCIP_Real* solvals, /**< solution values of all problem variables */
3456  int* varsM1, /**< variables in M_1 */
3457  int* varsM2, /**< variables in M_2 */
3458  int* varsF, /**< variables in F */
3459  int* varsR, /**< variables in R */
3460  int nvarsM1, /**< number of variables in M_1 */
3461  int nvarsM2, /**< number of variables in M_2 */
3462  int nvarsF, /**< number of variables in F */
3463  int nvarsR, /**< number of variables in R */
3464  int alpha0, /**< rights hand side of given valid inequality */
3465  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3466  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3467  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3468  )
3469 {
3470  SCIP_Longint* minweights;
3471  SCIP_Real* sortkeys;
3472  SCIP_Longint fixedonesweight;
3473  int minweightssize;
3474  int minweightslen;
3475  int j;
3476  int w;
3477 
3478  assert(scip != NULL);
3479  assert(vars != NULL);
3480  assert(nvars >= 0);
3481  assert(weights != NULL);
3482  assert(capacity >= 0);
3483  assert(solvals != NULL);
3484  assert(varsM1 != NULL);
3485  assert(varsM2 != NULL);
3486  assert(varsF != NULL);
3487  assert(varsR != NULL);
3488  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3489  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3490  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3491  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3492  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3493  assert(alpha0 >= 0);
3494  assert(liftcoefs != NULL);
3495  assert(cutact != NULL);
3496  assert(liftrhs != NULL);
3497 
3498  /* allocates temporary memory */
3499  minweightssize = nvarsM1 + 1;
3500  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3501  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3502 
3503  /* initializes data structures */
3504  BMSclearMemoryArray(liftcoefs, nvars);
3505  *cutact = 0.0;
3506 
3507  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3508  * and calculates activity of the current valid inequality
3509  */
3510  for( j = 0; j < nvarsM1; j++ )
3511  {
3512  assert(liftcoefs[varsM1[j]] == 0);
3513  liftcoefs[varsM1[j]] = 1;
3514  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3515  (*cutact) += solvals[varsM1[j]];
3516  }
3517 
3518  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3519 
3520  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3521  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3522  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3523  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3524  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3525  */
3526  minweights[0] = 0;
3527  for( w = 1; w <= nvarsM1; w++ )
3528  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3529  minweightslen = nvarsM1 + 1;
3530 
3531  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3532  fixedonesweight = 0;
3533  for( j = 0; j < nvarsM2; j++ )
3534  fixedonesweight += weights[varsM2[j]];
3535  assert(fixedonesweight >= 0);
3536 
3537  /* initializes right hand side of lifted valid inequality */
3538  *liftrhs = alpha0;
3539 
3540  /* sequentially up-lifts all variables in F: */
3541  for( j = 0; j < nvarsF; j++ )
3542  {
3543  SCIP_Longint weight;
3544  int liftvar;
3545  int liftcoef;
3546  int z;
3547 
3548  liftvar = varsF[j];
3549  weight = weights[liftvar];
3550  assert(liftvar >= 0 && liftvar < nvars);
3551  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3552  assert(weight > 0);
3553 
3554  /* knapsack problem is infeasible:
3555  * sets z = 0
3556  */
3557  if( capacity - fixedonesweight - weight < 0 )
3558  {
3559  z = 0;
3560  }
3561  /* knapsack problem is feasible:
3562  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3563  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3564  */
3565  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3566  {
3567  z = *liftrhs;
3568  }
3569  /* knapsack problem is feasible:
3570  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3571  */
3572  else
3573  {
3574  int left;
3575  int right;
3576  int middle;
3577 
3578  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3579  left = 0;
3580  right = (*liftrhs) + 1;
3581  while( left < right - 1 )
3582  {
3583  middle = (left + right) / 2;
3584  assert(0 <= middle && middle < minweightslen);
3585  if( minweights[middle] <= capacity - fixedonesweight - weight )
3586  left = middle;
3587  else
3588  right = middle;
3589  }
3590  assert(left == right - 1);
3591  assert(0 <= left && left < minweightslen);
3592  assert(minweights[left] <= capacity - fixedonesweight - weight );
3593  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3594 
3595  /* now z = left */
3596  z = left;
3597  assert(z <= *liftrhs);
3598  }
3599 
3600  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3601  liftcoef = (*liftrhs) - z;
3602  liftcoefs[liftvar] = liftcoef;
3603  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3604 
3605  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3606  if( liftcoef == 0 )
3607  continue;
3608 
3609  /* updates activity of current valid inequality */
3610  (*cutact) += liftcoef * solvals[liftvar];
3611 
3612  /* enlarges current minweight table:
3613  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3614  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3615  * and sets minweights_i[w] = infinity for
3616  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3617  */
3618  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3619 
3620  /* updates minweight table: minweight_i+1[w] =
3621  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3622  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3623  */
3624  for( w = minweightslen - 1; w >= 0; w-- )
3625  {
3626  SCIP_Longint min;
3627  if( w < liftcoef )
3628  {
3629  min = MIN(minweights[w], weight);
3630  minweights[w] = min;
3631  }
3632  else
3633  {
3634  assert(w >= liftcoef);
3635  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3636  minweights[w] = min;
3637  }
3638  }
3639  }
3640  assert(minweights[0] == 0);
3641 
3642  /* sequentially down-lifts all variables in M_2: */
3643  for( j = 0; j < nvarsM2; j++ )
3644  {
3645  SCIP_Longint weight;
3646  int liftvar;
3647  int liftcoef;
3648  int left;
3649  int right;
3650  int middle;
3651  int z;
3652 
3653  liftvar = varsM2[j];
3654  weight = weights[liftvar];
3655  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3656  assert(liftvar >= 0 && liftvar < nvars);
3657  assert(weight > 0);
3658 
3659  /* uses binary search to find
3660  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3661  */
3662  left = 0;
3663  right = minweightslen;
3664  while( left < right - 1 )
3665  {
3666  middle = (left + right) / 2;
3667  assert(0 <= middle && middle < minweightslen);
3668  if( minweights[middle] <= capacity - fixedonesweight + weight )
3669  left = middle;
3670  else
3671  right = middle;
3672  }
3673  assert(left == right - 1);
3674  assert(0 <= left && left < minweightslen);
3675  assert(minweights[left] <= capacity - fixedonesweight + weight );
3676  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3677 
3678  /* now z = left */
3679  z = left;
3680  assert(z >= *liftrhs);
3681 
3682  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3683  liftcoef = z - (*liftrhs);
3684  liftcoefs[liftvar] = liftcoef;
3685  assert(liftcoef >= 0);
3686 
3687  /* updates sum of weights of variables fixed to one */
3688  fixedonesweight -= weight;
3689 
3690  /* updates right-hand side of current valid inequality */
3691  (*liftrhs) += liftcoef;
3692  assert(*liftrhs >= alpha0);
3693 
3694  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3695  if( liftcoef == 0 )
3696  continue;
3697 
3698  /* updates activity of current valid inequality */
3699  (*cutact) += liftcoef * solvals[liftvar];
3700 
3701  /* enlarges current minweight table:
3702  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3703  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3704  * and sets minweights_i[w] = infinity for
3705  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3706  */
3707  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3708 
3709  /* updates minweight table: minweight_i+1[w] =
3710  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3711  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3712  */
3713  for( w = minweightslen - 1; w >= 0; w-- )
3714  {
3715  SCIP_Longint min;
3716  if( w < liftcoef )
3717  {
3718  min = MIN(minweights[w], weight);
3719  minweights[w] = min;
3720  }
3721  else
3722  {
3723  assert(w >= liftcoef);
3724  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3725  minweights[w] = min;
3726  }
3727  }
3728  }
3729  assert(fixedonesweight == 0);
3730  assert(*liftrhs >= alpha0);
3731 
3732  /* sequentially up-lifts all variables in R: */
3733  for( j = 0; j < nvarsR; j++ )
3734  {
3735  SCIP_Longint weight;
3736  int liftvar;
3737  int liftcoef;
3738  int z;
3739 
3740  liftvar = varsR[j];
3741  weight = weights[liftvar];
3742  assert(liftvar >= 0 && liftvar < nvars);
3743  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3744  assert(weight > 0);
3745  assert(capacity - weight >= 0);
3746  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3747 
3748  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3749  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3750  */
3751  if( minweights[*liftrhs] <= capacity - weight )
3752  {
3753  z = *liftrhs;
3754  }
3755  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3756  */
3757  else
3758  {
3759  int left;
3760  int right;
3761  int middle;
3762 
3763  left = 0;
3764  right = (*liftrhs) + 1;
3765  while( left < right - 1)
3766  {
3767  middle = (left + right) / 2;
3768  assert(0 <= middle && middle < minweightslen);
3769  if( minweights[middle] <= capacity - weight )
3770  left = middle;
3771  else
3772  right = middle;
3773  }
3774  assert(left == right - 1);
3775  assert(0 <= left && left < minweightslen);
3776  assert(minweights[left] <= capacity - weight );
3777  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3778 
3779  /* now z = left */
3780  z = left;
3781  assert(z <= *liftrhs);
3782  }
3783 
3784  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3785  liftcoef = (*liftrhs) - z;
3786  liftcoefs[liftvar] = liftcoef;
3787  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3788 
3789  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3790  if( liftcoef == 0 )
3791  continue;
3792 
3793  /* updates activity of current valid inequality */
3794  (*cutact) += liftcoef * solvals[liftvar];
3795 
3796  /* updates minweight table: minweight_i+1[w] =
3797  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3798  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3799  */
3800  for( w = *liftrhs; w >= 0; w-- )
3801  {
3802  SCIP_Longint min;
3803  if( w < liftcoef )
3804  {
3805  min = MIN(minweights[w], weight);
3806  minweights[w] = min;
3807  }
3808  else
3809  {
3810  assert(w >= liftcoef);
3811  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3812  minweights[w] = min;
3813  }
3814  }
3815  }
3816 
3817  /* frees temporary memory */
3818  SCIPfreeBufferArray(scip, &sortkeys);
3819  SCIPfreeBufferArray(scip, &minweights);
3820 
3821  return SCIP_OKAY;
3822 }
3823 
3824 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3825 static
3827  SCIP_Longint val1, /**< first value to add */
3828  SCIP_Longint val2 /**< second value to add */
3829  )
3830 {
3831  assert(val1 >= 0);
3832  assert(val2 >= 0);
3834  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3835  return SCIP_LONGINT_MAX;
3836  else
3837  {
3838  assert(val1 <= SCIP_LONGINT_MAX - val2);
3839  return (val1 + val2);
3840  }
3841 }
3842 
3843 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3844 static
3846  SCIP_Longint* minweights, /**< minweight table to compute */
3847  SCIP_Longint* finished, /**< given finished table */
3848  SCIP_Longint* unfinished, /**< given unfinished table */
3849  int minweightslen /**< length of minweight, finished, and unfinished tables */
3850  )
3851 {
3852  int w1;
3853  int w2;
3854 
3855  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3856  * note that finished and unfished arrays sorted by non-decreasing weight
3857  */
3858 
3859  /* initialize minweight with w2 = 0 */
3860  w2 = 0;
3861  assert(unfinished[w2] == 0);
3862  for( w1 = 0; w1 < minweightslen; w1++ )
3863  minweights[w1] = finished[w1];
3864 
3865  /* consider w2 = 1, ..., minweightslen-1 */
3866  for( w2 = 1; w2 < minweightslen; w2++ )
3867  {
3868  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3869  break;
3870 
3871  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3872  {
3873  SCIP_Longint temp;
3874 
3875  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3876  if( temp <= minweights[w1+w2] )
3877  minweights[w1+w2] = temp;
3878  }
3879  }
3880 }
3881 
3882 /** lifts given inequality
3883  * sum_{j in C_1} x_j <= alpha_0
3884  * valid for
3885  * 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;
3886  * sum_{j in Q_i} x_j <= 1, forall i in I }
3887  * to a valid inequality
3888  * 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
3889  * <= alpha_0 + sum_{j in C_2} alpha_j
3890  * for
3891  * 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 };
3892  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3893  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3894  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3895  */
3896 static
3898  SCIP* scip, /**< SCIP data structure */
3899  SCIP_GUBSET* gubset, /**< GUB set data structure */
3900  SCIP_VAR** vars, /**< variables in knapsack constraint */
3901  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3902  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3903  SCIP_Longint capacity, /**< capacity of knapsack */
3904  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3905  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3906  int* gubconsGC2, /**< GUBs in GC2 */
3907  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3908  int* gubconsGR, /**< GUBs in GR */
3909  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3910  int ngubconsGC2, /**< number of GUBs in GC2 */
3911  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3912  int ngubconsGR, /**< number of GUBs in GR */
3913  int alpha0, /**< rights hand side of given valid inequality */
3914  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3915  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3916  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3917  int maxgubvarssize /**< maximal size of GUB constraints */
3918  )
3919 {
3920  SCIP_Longint* minweights;
3921  SCIP_Longint* finished;
3922  SCIP_Longint* unfinished;
3923  int* gubconsGOC1;
3924  int* gubconsGNC1;
3925  int* liftgubvars;
3926  SCIP_Longint fixedonesweight;
3927  SCIP_Longint weight;
3928  SCIP_Longint weightdiff1;
3929  SCIP_Longint weightdiff2;
3930  SCIP_Longint min;
3931  int minweightssize;
3932  int minweightslen;
3933  int nvars;
3934  int varidx;
3935  int liftgubconsidx;
3936  int liftvar;
3937  int sumliftcoef;
3938  int liftcoef;
3939  int ngubconsGOC1;
3940  int ngubconsGNC1;
3941  int left;
3942  int right;
3943  int middle;
3944  int nliftgubvars;
3945  int tmplen;
3946  int tmpsize;
3947  int j;
3948  int k;
3949  int w;
3950  int z;
3951 #ifndef NDEBUG
3952  int ngubconss;
3953  int nliftgubC1;
3954 
3955  ngubconss = gubset->ngubconss;
3956 #endif
3957  nvars = gubset->nvars;
3958 
3959  assert(scip != NULL);
3960  assert(gubset != NULL);
3961  assert(vars != NULL);
3962  assert(nvars >= 0);
3963  assert(weights != NULL);
3964  assert(capacity >= 0);
3965  assert(solvals != NULL);
3966  assert(gubconsGC1 != NULL);
3967  assert(gubconsGC2 != NULL);
3968  assert(gubconsGFC1 != NULL);
3969  assert(gubconsGR != NULL);
3970  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3971  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3972  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3973  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3974  assert(alpha0 >= 0);
3975  assert(liftcoefs != NULL);
3976  assert(cutact != NULL);
3977  assert(liftrhs != NULL);
3978 
3979  minweightssize = ngubconsGC1+1;
3980 
3981  /* allocates temporary memory */
3982  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3983  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3984  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3985  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3986  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3987  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3988 
3989  /* initializes data structures */
3990  BMSclearMemoryArray(liftcoefs, nvars);
3991  *cutact = 0.0;
3992 
3993  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
3994  * valid inequality
3995  */
3996  ngubconsGOC1 = 0;
3997  ngubconsGNC1 = 0;
3998  for( j = 0; j < ngubconsGC1; j++ )
3999  {
4000  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4001  {
4002  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4003  ngubconsGOC1++;
4004  }
4005  else
4006  {
4007  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4008  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4009  ngubconsGNC1++;
4010  }
4011  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4012  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4013  {
4014  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4015  assert(varidx >= 0 && varidx < nvars);
4016  assert(liftcoefs[varidx] == 0);
4017 
4018  liftcoefs[varidx] = 1;
4019  (*cutact) += solvals[varidx];
4020  }
4021  assert(k >= 1);
4022  }
4023  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4024  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4025 
4026  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4027  * - finished_i[w] =
4028  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4029  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4030  * sum_{j in Q_k} x_j <= 1
4031  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4032  * - unfinished_i[w] =
4033  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4034  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4035  * sum_{j in Q_k} x_j <= 1
4036  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4037  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4038  */
4039 
4040  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4041  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4042  * 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
4043  * comes from the first variable in the GUB
4044  */
4045  assert(ngubconsGOC1 <= ngubconsGC1);
4046  finished[0] = 0;
4047  for( w = 1; w <= ngubconsGOC1; w++ )
4048  {
4049  liftgubconsidx = gubconsGOC1[w-1];
4050 
4051  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4052  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4053 
4054  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4055 
4056  assert(varidx >= 0 && varidx < nvars);
4057  assert(liftcoefs[varidx] == 1);
4058 
4059  min = weights[varidx];
4060  finished[w] = finished[w-1] + min;
4061 
4062 #ifndef NDEBUG
4063  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4064  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4065  {
4066  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4067  assert(varidx >= 0 && varidx < nvars);
4068  assert(liftcoefs[varidx] == 1);
4069  assert(weights[varidx] >= min);
4070  }
4071 #endif
4072  }
4073  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4074  finished[w] = SCIP_LONGINT_MAX;
4075 
4076  /* initialize unfinished table; note that variables in GNC1 GUBs
4077  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4078  * 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
4079  * comes from the first variable in the GUB
4080  */
4081  assert(ngubconsGNC1 <= ngubconsGC1);
4082  unfinished[0] = 0;
4083  for( w = 1; w <= ngubconsGNC1; w++ )
4084  {
4085  liftgubconsidx = gubconsGNC1[w-1];
4086 
4087  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4088  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4089 
4090  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4091 
4092  assert(varidx >= 0 && varidx < nvars);
4093  assert(liftcoefs[varidx] == 1);
4094 
4095  min = weights[varidx];
4096  unfinished[w] = unfinished[w-1] + min;
4097 
4098 #ifndef NDEBUG
4099  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4100  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4101  {
4102  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4103  assert(varidx >= 0 && varidx < nvars);
4104  assert(liftcoefs[varidx] == 1);
4105  assert(weights[varidx] >= min );
4106  }
4107 #endif
4108  }
4109  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4110  unfinished[w] = SCIP_LONGINT_MAX;
4111 
4112  /* initialize minweights table; note that variables in GC1 GUBs
4113  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4114  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4115  * consuming) because is it has to be build using weights from C1 only.
4116  */
4117  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4118  minweights[0] = 0;
4119  for( w = 1; w <= ngubconsGC1; w++ )
4120  {
4121  liftgubconsidx = gubconsGC1[w-1];
4122 
4123  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4124  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4125  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4126 
4127  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4128 
4129  assert(varidx >= 0 && varidx < nvars);
4130  assert(liftcoefs[varidx] == 1);
4131 
4132  min = weights[varidx];
4133  minweights[w] = minweights[w-1] + min;
4134 
4135 #ifndef NDEBUG
4136  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4137  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4138  {
4139  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4140  assert(varidx >= 0 && varidx < nvars);
4141  assert(liftcoefs[varidx] == 1);
4142  assert(weights[varidx] >= min);
4143  }
4144 #endif
4145  }
4146  minweightslen = ngubconsGC1 + 1;
4147 
4148  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4149  fixedonesweight = 0;
4150  for( j = 0; j < ngubconsGC2; j++ )
4151  {
4152  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4153 
4154  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4155  assert(varidx >= 0 && varidx < nvars);
4156  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4157 
4158  fixedonesweight += weights[varidx];
4159  }
4160  assert(fixedonesweight >= 0);
4161 
4162  /* initializes right hand side of lifted valid inequality */
4163  *liftrhs = alpha0;
4164 
4165  /* sequentially up-lifts all variables in GFC1 GUBs */
4166  for( j = 0; j < ngubconsGFC1; j++ )
4167  {
4168  liftgubconsidx = gubconsGFC1[j];
4169  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4170 
4171  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4172  * compute minweight table via updated unfinished table and aleady upto date finished table;
4173  */
4174  k = 0;
4175  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4176  {
4177  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4178  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4179  assert(ngubconsGNC1 > 0);
4180 
4181  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4182  * are considered for the lifting, i.e., not capacity exceeding
4183  */
4184  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4185  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4186  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4187  assert(k >= 1);
4188 
4189  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4190  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4191  */
4192  weight = weights[liftgubvars[0]];
4193 
4194  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4195  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4196  for( w = ngubconsGNC1-1; w >= 1; w-- )
4197  {
4198  weightdiff1 = weightdiff2;
4199  weightdiff2 = unfinished[w] - weight;
4200 
4201  if( unfinished[w] < weightdiff1 )
4202  unfinished[w] = weightdiff1;
4203  else
4204  break;
4205  }
4206  ngubconsGNC1--;
4207 
4208  /* computes minweights table by combining unfished and fished tables */
4209  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4210  assert(minweights[0] == 0);
4211  }
4212  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4213  * are therefore not in the unfinished table
4214  */
4215  else
4216  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4217 
4218 #ifndef NDEBUG
4219  nliftgubC1 = k;
4220 #endif
4221  nliftgubvars = k;
4222  sumliftcoef = 0;
4223 
4224  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4225  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4226  {
4227  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4228  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4229  {
4230  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4231  weight = weights[liftvar];
4232  assert(weight > 0);
4233  assert(liftvar >= 0 && liftvar < nvars);
4234  assert(capacity - weight >= 0);
4235 
4236  /* put variable into array of variables in GUB that are considered for the lifting,
4237  * i.e., not capacity exceeding
4238  */
4239  liftgubvars[nliftgubvars] = liftvar;
4240  nliftgubvars++;
4241 
4242  /* knapsack problem is infeasible:
4243  * sets z = 0
4244  */
4245  if( capacity - fixedonesweight - weight < 0 )
4246  {
4247  z = 0;
4248  }
4249  /* knapsack problem is feasible:
4250  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4251  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4252  */
4253  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4254  {
4255  z = *liftrhs;
4256  }
4257  /* knapsack problem is feasible:
4258  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4259  */
4260  else
4261  {
4262  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4263  left = 0;
4264  right = (*liftrhs) + 1;
4265  while( left < right - 1 )
4266  {
4267  middle = (left + right) / 2;
4268  assert(0 <= middle && middle < minweightslen);
4269  if( minweights[middle] <= capacity - fixedonesweight - weight )
4270  left = middle;
4271  else
4272  right = middle;
4273  }
4274  assert(left == right - 1);
4275  assert(0 <= left && left < minweightslen);
4276  assert(minweights[left] <= capacity - fixedonesweight - weight);
4277  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4278 
4279  /* now z = left */
4280  z = left;
4281  assert(z <= *liftrhs);
4282  }
4283 
4284  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4285  liftcoef = (*liftrhs) - z;
4286  liftcoefs[liftvar] = liftcoef;
4287  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4288 
4289  /* updates activity of current valid inequality */
4290  (*cutact) += liftcoef * solvals[liftvar];
4291 
4292  /* updates sum of all lifting coefficients in GUB */
4293  sumliftcoef += liftcoefs[liftvar];
4294  }
4295  else
4296  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4297  }
4298  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4299  assert(nliftgubvars > nliftgubC1);
4300 
4301  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4302  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4303  * not needed for GF GUBs
4304  */
4305  if( sumliftcoef == 0 )
4306  {
4307  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4308  {
4309  weight = weights[liftgubvars[0]];
4310  /* update finished table and minweights table by applying special case of
4311  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4312  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4313  */
4314  for( w = minweightslen-1; w >= 1; w-- )
4315  {
4316  SCIP_Longint tmpval;
4317 
4318  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4319  finished[w] = MIN(finished[w], tmpval);
4320 
4321  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4322  minweights[w] = MIN(minweights[w], tmpval);
4323  }
4324  }
4325  else
4326  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4327 
4328  continue;
4329  }
4330 
4331  /* enlarges current minweights tables(finished, unfinished, minweights):
4332  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4333  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4334  * and sets minweights_i[w] = infinity for
4335  * 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
4336  */
4337  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4338  tmpsize = minweightssize;
4339  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4340  tmplen = minweightslen;
4341  tmpsize = minweightssize;
4342  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4343  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4344 
4345  /* update finished table and minweight table;
4346  * note that instead of computing minweight table from updated finished and updated unfinished table again
4347  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4348  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4349  * not needed because only finished table changed at this point and the change was "adding" one weight)
4350  *
4351  * update formular for minweight table is: minweight_i+1[w] =
4352  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4353  * formular for finished table has the same pattern.
4354  */
4355  for( w = minweightslen-1; w >= 0; w-- )
4356  {
4357  SCIP_Longint minminweight;
4358  SCIP_Longint minfinished;
4359 
4360  for( k = 0; k < nliftgubvars; k++ )
4361  {
4362  liftcoef = liftcoefs[liftgubvars[k]];
4363  weight = weights[liftgubvars[k]];
4364 
4365  if( w < liftcoef )
4366  {
4367  minfinished = MIN(finished[w], weight);
4368  minminweight = MIN(minweights[w], weight);
4369 
4370  finished[w] = minfinished;
4371  minweights[w] = minminweight;
4372  }
4373  else
4374  {
4375  SCIP_Longint tmpval;
4376 
4377  assert(w >= liftcoef);
4378 
4379  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4380  minfinished = MIN(finished[w], tmpval);
4381 
4382  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4383  minminweight = MIN(minweights[w], tmpval);
4384 
4385  finished[w] = minfinished;
4386  minweights[w] = minminweight;
4387  }
4388  }
4389  }
4390  assert(minweights[0] == 0);
4391  }
4392  assert(ngubconsGNC1 == 0);
4393 
4394  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4395  * therefore, only work with minweight table from here on
4396  */
4397 
4398  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4399  for( j = 0; j < ngubconsGC2; j++ )
4400  {
4401  liftgubconsidx = gubconsGC2[j];
4402 
4403  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4404  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4405  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4406  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4407 
4408  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4409  weight = weights[liftvar];
4410 
4411  assert(liftvar >= 0 && liftvar < nvars);
4412  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4413  assert(weight > 0);
4414 
4415  /* uses binary search to find
4416  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4417  */
4418  left = 0;
4419  right = minweightslen;
4420  while( left < right - 1 )
4421  {
4422  middle = (left + right) / 2;
4423  assert(0 <= middle && middle < minweightslen);
4424  if( minweights[middle] <= capacity - fixedonesweight + weight )
4425  left = middle;
4426  else
4427  right = middle;
4428  }
4429  assert(left == right - 1);
4430  assert(0 <= left && left < minweightslen);
4431  assert(minweights[left] <= capacity - fixedonesweight + weight);
4432  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4433 
4434  /* now z = left */
4435  z = left;
4436  assert(z >= *liftrhs);
4437 
4438  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4439  liftcoef = z - (*liftrhs);
4440  liftcoefs[liftvar] = liftcoef;
4441  assert(liftcoef >= 0);
4442 
4443  /* updates sum of weights of variables fixed to one */
4444  fixedonesweight -= weight;
4445 
4446  /* updates right-hand side of current valid inequality */
4447  (*liftrhs) += liftcoef;
4448  assert(*liftrhs >= alpha0);
4449 
4450  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4451  if( liftcoef == 0 )
4452  continue;
4453 
4454  /* updates activity of current valid inequality */
4455  (*cutact) += liftcoef * solvals[liftvar];
4456 
4457  /* enlarges current minweight table:
4458  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4459  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4460  * and sets minweights_i[w] = infinity for
4461  * 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
4462  */
4463  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4464 
4465  /* updates minweight table: minweight_i+1[w] =
4466  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4467  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4468  */
4469  for( w = minweightslen - 1; w >= 0; w-- )
4470  {
4471  if( w < liftcoef )
4472  {
4473  min = MIN(minweights[w], weight);
4474  minweights[w] = min;
4475  }
4476  else
4477  {
4478  SCIP_Longint tmpval;
4479 
4480  assert(w >= liftcoef);
4481 
4482  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4483  min = MIN(minweights[w], tmpval);
4484  minweights[w] = min;
4485  }
4486  }
4487  }
4488  assert(fixedonesweight == 0);
4489  assert(*liftrhs >= alpha0);
4490 
4491  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4492  for( j = 0; j < ngubconsGR; j++ )
4493  {
4494  liftgubconsidx = gubconsGR[j];
4495 
4496  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4497  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4498 
4499  sumliftcoef = 0;
4500  nliftgubvars = 0;
4501  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4502  {
4503  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4504  {
4505  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4506  weight = weights[liftvar];
4507  assert(weight > 0);
4508  assert(liftvar >= 0 && liftvar < nvars);
4509  assert(capacity - weight >= 0);
4510  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4511 
4512  /* put variable into array of variables in GUB that are considered for the lifting,
4513  * i.e., not capacity exceeding
4514  */
4515  liftgubvars[nliftgubvars] = liftvar;
4516  nliftgubvars++;
4517 
4518  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4519  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4520  */
4521  if( minweights[*liftrhs] <= capacity - weight )
4522  {
4523  z = *liftrhs;
4524  }
4525  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4526  */
4527  else
4528  {
4529  left = 0;
4530  right = (*liftrhs) + 1;
4531  while( left < right - 1 )
4532  {
4533  middle = (left + right) / 2;
4534  assert(0 <= middle && middle < minweightslen);
4535  if( minweights[middle] <= capacity - weight )
4536  left = middle;
4537  else
4538  right = middle;
4539  }
4540  assert(left == right - 1);
4541  assert(0 <= left && left < minweightslen);
4542  assert(minweights[left] <= capacity - weight);
4543  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4544 
4545  /* now z = left */
4546  z = left;
4547  assert(z <= *liftrhs);
4548  }
4549  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4550  liftcoef = (*liftrhs) - z;
4551  liftcoefs[liftvar] = liftcoef;
4552  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4553 
4554  /* updates activity of current valid inequality */
4555  (*cutact) += liftcoef * solvals[liftvar];
4556 
4557  /* updates sum of all lifting coefficients in GUB */
4558  sumliftcoef += liftcoefs[liftvar];
4559  }
4560  else
4561  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4562  }
4563  assert(nliftgubvars >= 1); /* at least one variable is in R */
4564 
4565  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4566  if( sumliftcoef == 0 )
4567  continue;
4568 
4569  /* updates minweight table: minweight_i+1[w] =
4570  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4571  */
4572  for( w = *liftrhs; w >= 0; w-- )
4573  {
4574  for( k = 0; k < nliftgubvars; k++ )
4575  {
4576  liftcoef = liftcoefs[liftgubvars[k]];
4577  weight = weights[liftgubvars[k]];
4578 
4579  if( w < liftcoef )
4580  {
4581  min = MIN(minweights[w], weight);
4582  minweights[w] = min;
4583  }
4584  else
4585  {
4586  SCIP_Longint tmpval;
4587 
4588  assert(w >= liftcoef);
4589 
4590  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4591  min = MIN(minweights[w], tmpval);
4592  minweights[w] = min;
4593  }
4594  }
4595  }
4596  assert(minweights[0] == 0);
4597  }
4598 
4599  /* frees temporary memory */
4600  SCIPfreeBufferArray(scip, &minweights);
4601  SCIPfreeBufferArray(scip, &finished);
4602  SCIPfreeBufferArray(scip, &unfinished);
4603  SCIPfreeBufferArray(scip, &liftgubvars);
4604  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4605  SCIPfreeBufferArray(scip, &gubconsGNC1);
4606 
4607  return SCIP_OKAY;
4608 }
4609 
4610 /** lifts given minimal cover inequality
4611  * \f[
4612  * \sum_{j \in C} x_j \leq |C| - 1
4613  * \f]
4614  * valid for
4615  * \f[
4616  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4617  * \f]
4618  * to a valid inequality
4619  * \f[
4620  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4621  * \f]
4622  * for
4623  * \f[
4624  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4625  * \f]
4626  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4627  */
4628 static
4630  SCIP* scip, /**< SCIP data structure */
4631  SCIP_VAR** vars, /**< variables in knapsack constraint */
4632  int nvars, /**< number of variables in knapsack constraint */
4633  int ntightened, /**< number of variables with tightened upper bound */
4634  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4635  SCIP_Longint capacity, /**< capacity of knapsack */
4636  SCIP_Real* solvals, /**< solution values of all problem variables */
4637  int* covervars, /**< cover variables */
4638  int* noncovervars, /**< noncover variables */
4639  int ncovervars, /**< number of cover variables */
4640  int nnoncovervars, /**< number of noncover variables */
4641  SCIP_Longint coverweight, /**< weight of cover */
4642  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4643  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4644  )
4645 {
4646  SCIP_Longint* maxweightsums;
4647  SCIP_Longint* intervalends;
4648  SCIP_Longint* rhos;
4649  SCIP_Real* sortkeys;
4650  SCIP_Longint lambda;
4651  int j;
4652  int h;
4653 
4654  assert(scip != NULL);
4655  assert(vars != NULL);
4656  assert(nvars >= 0);
4657  assert(weights != NULL);
4658  assert(capacity >= 0);
4659  assert(solvals != NULL);
4660  assert(covervars != NULL);
4661  assert(noncovervars != NULL);
4662  assert(ncovervars > 0 && ncovervars <= nvars);
4663  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4664  assert(ncovervars + nnoncovervars == nvars - ntightened);
4665  assert(liftcoefs != NULL);
4666  assert(cutact != NULL);
4667 
4668  /* allocates temporary memory */
4669  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4670  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4671  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4672  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4673 
4674  /* initializes data structures */
4675  BMSclearMemoryArray(liftcoefs, nvars);
4676  *cutact = 0.0;
4677 
4678  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4679  * and calculates activity of current valid inequality
4680  */
4681  for( j = 0; j < ncovervars; j++ )
4682  {
4683  assert(liftcoefs[covervars[j]] == 0.0);
4684  liftcoefs[covervars[j]] = 1.0;
4685  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4686  (*cutact) += solvals[covervars[j]];
4687  }
4688  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4689 
4690  /* calculates weight excess of cover C */
4691  lambda = coverweight - capacity;
4692  assert(lambda > 0);
4693 
4694  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4695  maxweightsums[0] = 0;
4696  for( h = 1; h <= ncovervars; h++ )
4697  {
4698  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4699  intervalends[h-1] = maxweightsums[h] - lambda;
4700  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4701  }
4702 
4703  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4704  for( j = 0; j < nnoncovervars; j++ )
4705  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4706  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4707 
4708  /* calculates lifting coefficient for all variables in N\C */
4709  h = 0;
4710  for( j = 0; j < nnoncovervars; j++ )
4711  {
4712  int liftvar;
4713  SCIP_Longint weight;
4714  SCIP_Real liftcoef;
4715 
4716  liftvar = noncovervars[j];
4717  weight = weights[liftvar];
4718 
4719  while( intervalends[h] < weight )
4720  h++;
4721 
4722  if( h == 0 )
4723  liftcoef = h;
4724  else
4725  {
4726  if( weight <= intervalends[h-1] + rhos[h] )
4727  {
4728  SCIP_Real tmp1;
4729  SCIP_Real tmp2;
4730  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4731  tmp2 = (SCIP_Real) rhos[1];
4732  liftcoef = h - ( tmp1 / tmp2 );
4733  }
4734  else
4735  liftcoef = h;
4736  }
4737 
4738  /* sets lifting coefficient */
4739  assert(liftcoefs[liftvar] == 0.0);
4740  liftcoefs[liftvar] = liftcoef;
4741 
4742  /* updates activity of current valid inequality */
4743  (*cutact) += liftcoef * solvals[liftvar];
4744  }
4745 
4746  /* frees temporary memory */
4747  SCIPfreeBufferArray(scip, &rhos);
4748  SCIPfreeBufferArray(scip, &intervalends);
4749  SCIPfreeBufferArray(scip, &maxweightsums);
4750  SCIPfreeBufferArray(scip, &sortkeys);
4751 
4752  return SCIP_OKAY;
4753 }
4754 
4755 
4756 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4757  * given knapsack problem
4758 */
4759 static
4761  SCIP* scip, /**< SCIP data structure */
4762  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4763  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4764  SCIP_VAR** vars, /**< variables in knapsack constraint */
4765  int nvars, /**< number of variables in knapsack constraint */
4766  int ntightened, /**< number of variables with tightened upper bound */
4767  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4768  SCIP_Longint capacity, /**< capacity of knapsack */
4769  SCIP_Real* solvals, /**< solution values of all problem variables */
4770  int* mincovervars, /**< mincover variables */
4771  int* nonmincovervars, /**< nonmincover variables */
4772  int nmincovervars, /**< number of mincover variables */
4773  int nnonmincovervars, /**< number of nonmincover variables */
4774  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4775  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4776  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4777  int* ncuts /**< pointer to add up the number of found cuts */
4778  )
4779 {
4780  int* varsC1;
4781  int* varsC2;
4782  int* varsF;
4783  int* varsR;
4784  int nvarsC1;
4785  int nvarsC2;
4786  int nvarsF;
4787  int nvarsR;
4788  SCIP_Real cutact;
4789  int* liftcoefs;
4790  int liftrhs;
4791 
4792  assert( cutoff != NULL );
4793  *cutoff = FALSE;
4794 
4795  /* allocates temporary memory */
4796  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4797  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4798  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4799  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4800  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4801 
4802  /* 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
4803  * as follows
4804  * C_2 = { j in C : x*_j = 1 } and
4805  * C_1 = C\C_2
4806  */
4807  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4808  assert(nvarsC1 + nvarsC2 == nmincovervars);
4809  assert(nmincovervars > 0);
4810  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4811 
4812  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4813  if( nvarsC1 < 2 && nvarsC2 > 0)
4814  {
4815  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4816  assert(nvarsC1 >= 1);
4817  }
4818  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4819 
4820  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4821  * R = { j in N\C : x*_j = 0 } and
4822  * F = (N\C)\F
4823  */
4824  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4825  assert(nvarsF + nvarsR == nnonmincovervars);
4826  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4827 
4828  /* lift cuts without GUB information */
4829  if( gubset == NULL )
4830  {
4831  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4832  * lifting procedure
4833  */
4834  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4835 
4836  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4837  *
4838  * 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 }
4839  *
4840  * 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
4841  *
4842  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4843  *
4844  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4845  * up-lifting for the variables in R according to the second level lifting sequence
4846  */
4847  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4848  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4849  }
4850  /* lift cuts with GUB information */
4851  else
4852  {
4853  int* gubconsGC1;
4854  int* gubconsGC2;
4855  int* gubconsGFC1;
4856  int* gubconsGR;
4857  int ngubconsGC1;
4858  int ngubconsGC2;
4859  int ngubconsGFC1;
4860  int ngubconsGR;
4861  int ngubconss;
4862  int nconstightened;
4863  int maxgubvarssize;
4864 
4865  assert(nvars == gubset->nvars);
4866 
4867  ngubconsGC1 = 0;
4868  ngubconsGC2 = 0;
4869  ngubconsGFC1 = 0;
4870  ngubconsGR = 0;
4871  ngubconss = gubset->ngubconss;
4872  nconstightened = 0;
4873  maxgubvarssize = 0;
4874 
4875  /* allocates temporary memory */
4876  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4877  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4878  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4879  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4880 
4881  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4882  * the GUBs for the sequential GUB wise lifting procedure
4883  */
4884  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4885  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4886  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4887 
4888  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4889  *
4890  * 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,
4891  * sum_{j in Q_i} x_j <= 1, forall i in I }
4892  *
4893  * 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
4894  *
4895  * 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 },
4896  *
4897  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4898  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4899  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4900  */
4901  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4902  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4903  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4904 
4905  /* frees temporary memory */
4906  SCIPfreeBufferArray(scip, &gubconsGR);
4907  SCIPfreeBufferArray(scip, &gubconsGFC1);
4908  SCIPfreeBufferArray(scip, &gubconsGC2);
4909  SCIPfreeBufferArray(scip, &gubconsGC1);
4910  }
4911 
4912  /* checks, if lifting yielded a violated cut */
4913  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4914  {
4915  SCIP_ROW* row;
4916  char name[SCIP_MAXSTRLEN];
4917  int j;
4918 
4919  /* creates LP row */
4920  assert( cons == NULL || sepa == NULL );
4921  if ( cons != NULL )
4922  {
4923  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4924  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4925  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4926  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4927  }
4928  else if ( sepa != NULL )
4929  {
4930  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4931  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4932  }
4933  else
4934  {
4935  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
4936  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4937  }
4938 
4939  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4940  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4941  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4942  for( j = 0; j < nvarsC1; j++ )
4943  {
4944  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4945  }
4946  for( j = 0; j < nvarsC2; j++ )
4947  {
4948  if( liftcoefs[varsC2[j]] > 0 )
4949  {
4950  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4951  }
4952  }
4953  for( j = 0; j < nvarsF; j++ )
4954  {
4955  if( liftcoefs[varsF[j]] > 0 )
4956  {
4957  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4958  }
4959  }
4960  for( j = 0; j < nvarsR; j++ )
4961  {
4962  if( liftcoefs[varsR[j]] > 0 )
4963  {
4964  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4965  }
4966  }
4967  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4968 
4969  /* checks, if cut is violated enough */
4970  if( SCIPisCutEfficacious(scip, sol, row) )
4971  {
4972  if( cons != NULL )
4973  {
4974  SCIP_CALL( SCIPresetConsAge(scip, cons) );
4975  }
4976  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
4977  (*ncuts)++;
4978  }
4979  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4980  }
4981 
4982  /* frees temporary memory */
4983  SCIPfreeBufferArray(scip, &liftcoefs);
4984  SCIPfreeBufferArray(scip, &varsR);
4985  SCIPfreeBufferArray(scip, &varsF);
4986  SCIPfreeBufferArray(scip, &varsC2);
4987  SCIPfreeBufferArray(scip, &varsC1);
4988 
4989  return SCIP_OKAY;
4990 }
4991 
4992 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
4993 static
4995  SCIP* scip, /**< SCIP data structure */
4996  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
4997  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4998  SCIP_VAR** vars, /**< variables in knapsack constraint */
4999  int nvars, /**< number of variables in knapsack constraint */
5000  int ntightened, /**< number of variables with tightened upper bound */
5001  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5002  SCIP_Longint capacity, /**< capacity of knapsack */
5003  SCIP_Real* solvals, /**< solution values of all problem variables */
5004  int* feassetvars, /**< variables in feasible set */
5005  int* nonfeassetvars, /**< variables not in feasible set */
5006  int nfeassetvars, /**< number of variables in feasible set */
5007  int nnonfeassetvars, /**< number of variables not in feasible set */
5008  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5009  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5010  int* ncuts /**< pointer to add up the number of found cuts */
5011  )
5012 {
5013  int* varsT1;
5014  int* varsT2;
5015  int* varsF;
5016  int* varsR;
5017  int* liftcoefs;
5018  SCIP_Real cutact;
5019  int nvarsT1;
5020  int nvarsT2;
5021  int nvarsF;
5022  int nvarsR;
5023  int liftrhs;
5024  int j;
5025 
5026  assert( cutoff != NULL );
5027  *cutoff = FALSE;
5028 
5029  /* allocates temporary memory */
5030  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5031  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5032  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5033  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5034  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5035 
5036  /* 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
5037  * as follows
5038  * T_2 = { j in T : x*_j = 1 } and
5039  * T_1 = T\T_2
5040  */
5041  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5042  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5043 
5044  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5045  if( nvarsT1 == 0 && nvarsT2 > 0)
5046  {
5047  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5048  assert(nvarsT1 == 1);
5049  }
5050  assert(nvarsT2 == 0 || nvarsT1 > 0);
5051 
5052  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5053  * R = { j in N\T : x*_j = 0 } and
5054  * F = (N\T)\F
5055  */
5056  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5057  assert(nvarsF + nvarsR == nnonfeassetvars);
5058  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5059 
5060  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5061  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5062  * is included in the sorting routine)
5063  */
5064  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5065 
5066  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5067  *
5068  * 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 }
5069  *
5070  * 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
5071  *
5072  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5073  *
5074  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5075  * up-lifting for the variabels in R according to the second level lifting sequence
5076  */
5077  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5078  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5079 
5080  /* checks, if lifting yielded a violated cut */
5081  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5082  {
5083  SCIP_ROW* row;
5084  char name[SCIP_MAXSTRLEN];
5085 
5086  /* creates LP row */
5087  assert( cons == NULL || sepa == NULL );
5088  if( cons != NULL )
5089  {
5090  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5091  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5092  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5093  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5094  }
5095  else if ( sepa != NULL )
5096  {
5097  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5098  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5099  }
5100  else
5101  {
5102  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
5103  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5104  }
5105 
5106  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5107  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5108  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5109  for( j = 0; j < nvarsT1; j++ )
5110  {
5111  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5112  }
5113  for( j = 0; j < nvarsT2; j++ )
5114  {
5115  if( liftcoefs[varsT2[j]] > 0 )
5116  {
5117  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5118  }
5119  }
5120  for( j = 0; j < nvarsF; j++ )
5121  {
5122  if( liftcoefs[varsF[j]] > 0 )
5123  {
5124  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5125  }
5126  }
5127  for( j = 0; j < nvarsR; j++ )
5128  {
5129  if( liftcoefs[varsR[j]] > 0 )
5130  {
5131  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5132  }
5133  }
5134  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5135 
5136  /* checks, if cut is violated enough */
5137  if( SCIPisCutEfficacious(scip, sol, row) )
5138  {
5139  if( cons != NULL )
5140  {
5141  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5142  }
5143  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
5144  (*ncuts)++;
5145  }
5146  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5147  }
5148 
5149  /* frees temporary memory */
5150  SCIPfreeBufferArray(scip, &liftcoefs);
5151  SCIPfreeBufferArray(scip, &varsR);
5152  SCIPfreeBufferArray(scip, &varsF);
5153  SCIPfreeBufferArray(scip, &varsT2);
5154  SCIPfreeBufferArray(scip, &varsT1);
5155 
5156  return SCIP_OKAY;
5157 }
5158 
5159 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5160 static
5162  SCIP* scip, /**< SCIP data structure */
5163  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5164  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5165  SCIP_VAR** vars, /**< variables in knapsack constraint */
5166  int nvars, /**< number of variables in knapsack constraint */
5167  int ntightened, /**< number of variables with tightened upper bound */
5168  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5169  SCIP_Longint capacity, /**< capacity of knapsack */
5170  SCIP_Real* solvals, /**< solution values of all problem variables */
5171  int* mincovervars, /**< mincover variables */
5172  int* nonmincovervars, /**< nonmincover variables */
5173  int nmincovervars, /**< number of mincover variables */
5174  int nnonmincovervars, /**< number of nonmincover variables */
5175  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5176  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5177  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5178  int* ncuts /**< pointer to add up the number of found cuts */
5179  )
5180 {
5181  SCIP_Real* realliftcoefs;
5182  SCIP_Real cutact;
5183  int liftrhs;
5184 
5185  assert( cutoff != NULL );
5186  *cutoff = FALSE;
5187  cutact = 0.0;
5188 
5189  /* allocates temporary memory */
5190  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5191 
5192  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5193  *
5194  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5195  *
5196  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5197  *
5198  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5199  *
5200  * uses superadditive up-lifting for the variables in N\C.
5201  */
5202  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5203  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5204  liftrhs = nmincovervars - 1;
5205 
5206  /* checks, if lifting yielded a violated cut */
5207  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5208  {
5209  SCIP_ROW* row;
5210  char name[SCIP_MAXSTRLEN];
5211  int j;
5212 
5213  /* creates LP row */
5214  assert( cons == NULL || sepa == NULL );
5215  if ( cons != NULL )
5216  {
5217  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5218  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5219  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5220  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5221  }
5222  else if ( sepa != NULL )
5223  {
5224  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5225  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5226  }
5227  else
5228  {
5229  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%" SCIP_LONGINT_FORMAT "", *ncuts);
5230  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5231  }
5232 
5233  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5234  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5235  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5236  for( j = 0; j < nmincovervars; j++ )
5237  {
5238  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5239  }
5240  for( j = 0; j < nnonmincovervars; j++ )
5241  {
5242  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5243  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5244  {
5245  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5246  }
5247  }
5248  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5249 
5250  /* checks, if cut is violated enough */
5251  if( SCIPisCutEfficacious(scip, sol, row) )
5252  {
5253  if( cons != NULL )
5254  {
5255  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5256  }
5257  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
5258  (*ncuts)++;
5259  }
5260  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5261  }
5262 
5263  /* frees temporary memory */
5264  SCIPfreeBufferArray(scip, &realliftcoefs);
5265 
5266  return SCIP_OKAY;
5267 }
5268 
5269 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5270  * 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
5271  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5272  * note that all variables with x*_j = 1 will be removed last
5273  */
5274 static
5276  SCIP* scip, /**< SCIP data structure */
5277  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5278  SCIP_Longint capacity, /**< capacity of knapsack */
5279  SCIP_Real* solvals, /**< solution values of all problem variables */
5280  int* covervars, /**< pointer to store cover variables */
5281  int* noncovervars, /**< pointer to store noncover variables */
5282  int* ncovervars, /**< pointer to store number of cover variables */
5283  int* nnoncovervars, /**< pointer to store number of noncover variables */
5284  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5285  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5286  )
5287 {
5288  SORTKEYPAIR** sortkeypairs;
5289  SCIP_Longint minweight;
5290  int nsortkeypairs;
5291  int minweightidx;
5292  int j;
5293  int k;
5294 
5295  assert(scip != NULL);
5296  assert(covervars != NULL);
5297  assert(noncovervars != NULL);
5298  assert(ncovervars != NULL);
5299  assert(*ncovervars > 0);
5300  assert(nnoncovervars != NULL);
5301  assert(*nnoncovervars >= 0);
5302  assert(coverweight != NULL);
5303  assert(*coverweight > 0);
5304  assert(*coverweight > capacity);
5305 
5306  /* allocates temporary memory */
5307  nsortkeypairs = *ncovervars;
5308  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &sortkeypairs, nsortkeypairs) );
5309 
5310  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5311  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5312  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5313  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5314  */
5315  assert(*ncovervars == nsortkeypairs);
5316  if( modtransused )
5317  {
5318  for( j = 0; j < *ncovervars; j++ )
5319  {
5320  SCIP_CALL( SCIPallocBlockMemory(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5321 
5322  sortkeypairs[j]->key1 = solvals[covervars[j]];
5323  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5324  }
5325  }
5326  else
5327  {
5328  for( j = 0; j < *ncovervars; j++ )
5329  {
5330  SCIP_CALL( SCIPallocBlockMemory(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5331 
5332  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5333  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5334  }
5335  }
5336  SCIPsortPtrInt((void**)sortkeypairs, covervars, compSortkeypairs, *ncovervars);
5337 
5338  /* gets j' with a_j' = min{ a_j : j in C } */
5339  minweightidx = 0;
5340  minweight = weights[covervars[minweightidx]];
5341  for( j = 1; j < *ncovervars; j++ )
5342  {
5343  if( weights[covervars[j]] <= minweight )
5344  {
5345  minweightidx = j;
5346  minweight = weights[covervars[minweightidx]];
5347  }
5348  }
5349  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5350  assert(minweight > 0 && minweight <= *coverweight);
5351 
5352  j = 0;
5353  /* removes variables from C until the remaining variables form a minimal cover */
5354  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5355  {
5356  assert(minweightidx >= j);
5357  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5358 
5359  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5360  if( (*coverweight) - weights[covervars[j]] <= capacity )
5361  {
5362  ++j;
5363  continue;
5364  }
5365 
5366  /* adds j to N\C */
5367  noncovervars[*nnoncovervars] = covervars[j];
5368  (*nnoncovervars)++;
5369 
5370  /* removes j from C */
5371  (*coverweight) -= weights[covervars[j]];
5372  for( k = j; k < (*ncovervars) - 1; k++ )
5373  covervars[k] = covervars[k+1];
5374  (*ncovervars)--;
5375 
5376  /* updates j' with a_j' = min{ a_j : j in C } */
5377  if( j == minweightidx )
5378  {
5379  minweightidx = 0;
5380  minweight = weights[covervars[minweightidx]];
5381  for( k = 1; k < *ncovervars; k++ )
5382  {
5383  if( weights[covervars[k]] <= minweight )
5384  {
5385  minweightidx = k;
5386  minweight = weights[covervars[minweightidx]];
5387  }
5388  }
5389  assert(minweight > 0 && minweight <= *coverweight);
5390  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5391  }
5392  else
5393  {
5394  assert(minweightidx > j);
5395  minweightidx--;
5396  }
5397  /* j needs to stay the same */
5398  }
5399  assert((*coverweight) > capacity);
5400  assert((*coverweight) - minweight <= capacity);
5401 
5402  /* frees temporary memory */
5403  for( j = nsortkeypairs-1; j >= 0; j-- )
5404  SCIPfreeBlockMemory(scip, &(sortkeypairs[j])); /*lint !e866 */
5405  SCIPfreeBlockMemoryArray(scip, &sortkeypairs, nsortkeypairs);
5406 
5407  return SCIP_OKAY;
5408 }
5409 
5410 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5411  * they were chosen to be in C_init:
5412  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5413  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5414  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5415  * and all subsequent feasible sets.
5416  */
5417 static
5419  SCIP* scip, /**< SCIP data structure */
5420  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5421  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5422  SCIP_VAR** vars, /**< variables in knapsack constraint */
5423  int nvars, /**< number of variables in knapsack constraint */
5424  int ntightened, /**< number of variables with tightened upper bound */
5425  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5426  SCIP_Longint capacity, /**< capacity of knapsack */
5427  SCIP_Real* solvals, /**< solution values of all problem variables */
5428  int* covervars, /**< pointer to store cover variables */
5429  int* noncovervars, /**< pointer to store noncover variables */
5430  int* ncovervars, /**< pointer to store number of cover variables */
5431  int* nnoncovervars, /**< pointer to store number of noncover variables */
5432  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5433  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5434  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5435  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5436  int* ncuts /**< pointer to add up the number of found cuts */
5437  )
5438 {
5439  SCIP_Real* sortkeys;
5440  int j;
5441  int k;
5442 
5443  assert(scip != NULL);
5444  assert(covervars != NULL);
5445  assert(noncovervars != NULL);
5446  assert(ncovervars != NULL);
5447  assert(*ncovervars > 0);
5448  assert(nnoncovervars != NULL);
5449  assert(*nnoncovervars >= 0);
5450  assert(coverweight != NULL);
5451  assert(*coverweight > 0);
5452  assert(*coverweight > capacity);
5453  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5454  assert(cutoff != NULL);
5455 
5456  *cutoff = FALSE;
5457 
5458  /* allocates temporary memory */
5459  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5460 
5461  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5462  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5463  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5464  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5465  */
5466  if( modtransused )
5467  {
5468  for( j = 0; j < *ncovervars; j++ )
5469  {
5470  sortkeys[j] = solvals[covervars[j]];
5471  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5472  }
5473  }
5474  else
5475  {
5476  for( j = 0; j < *ncovervars; j++ )
5477  {
5478  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5479  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5480  }
5481  }
5482  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5483 
5484  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5485  * in addition to an extended weight inequality this gives cardinality inequalities */
5486  while( *ncovervars >= 2 )
5487  {
5488  /* adds first element of C_init to N\C_init */
5489  noncovervars[*nnoncovervars] = covervars[0];
5490  (*nnoncovervars)++;
5491 
5492  /* removes first element from C_init */
5493  (*coverweight) -= weights[covervars[0]];
5494  for( k = 0; k < (*ncovervars) - 1; k++ )
5495  covervars[k] = covervars[k+1];
5496  (*ncovervars)--;
5497 
5498  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5499  if( (*coverweight) <= capacity )
5500  {
5501  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5502  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5503  }
5504 
5505  /* stop if cover is too large */
5506  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5507  break;
5508  }
5509 
5510  /* frees temporary memory */
5511  SCIPfreeBufferArray(scip, &sortkeys);
5512 
5513  return SCIP_OKAY;
5514 }
5515 
5516 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5518  SCIP* scip, /**< SCIP data structure */
5519  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5520  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5521  SCIP_VAR** vars, /**< variables in knapsack constraint */
5522  int nvars, /**< number of variables in knapsack constraint */
5523  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5524  SCIP_Longint capacity, /**< capacity of knapsack */
5525  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5526  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5527  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5528  int* ncuts /**< pointer to add up the number of found cuts */
5529  )
5530 {
5531  SCIP_Real* solvals;
5532  int* covervars;
5533  int* noncovervars;
5534  SCIP_Bool coverfound;
5535  SCIP_Bool fractional;
5536  SCIP_Bool modtransused;
5537  SCIP_Longint coverweight;
5538  int ncovervars;
5539  int nnoncovervars;
5540  int ntightened;
5541 
5542  assert(scip != NULL);
5543  assert(capacity >= 0);
5544  assert(cutoff != NULL);
5545  assert(ncuts != NULL);
5546 
5547  *cutoff = FALSE;
5548 
5549  if( nvars == 0 )
5550  return SCIP_OKAY;
5551 
5552  assert(vars != NULL);
5553  assert(nvars > 0);
5554  assert(weights != NULL);
5555 
5556  /* increase age of constraint (age is reset to zero, if a cut was found) */
5557  if( cons != NULL )
5558  {
5559  SCIP_CALL( SCIPincConsAge(scip, cons) );
5560  }
5561 
5562  /* allocates temporary memory */
5563  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5564  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5565  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5566 
5567  /* gets solution values of all problem variables */
5568  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5569 
5570 #ifdef SCIP_DEBUG
5571  {
5572  int i;
5573 
5574  SCIPdebugMessage("separate cuts for knapsack constraint originated by cons <%s>:\n",
5575  cons == NULL ? "-" : SCIPconsGetName(cons));
5576  for( i = 0; i < nvars; ++i )
5577  {
5578  SCIPdebugPrintf("%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5579  }
5580  SCIPdebugPrintf(" <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5581  }
5582 #endif
5583 
5584  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5585  */
5586  if( usegubs )
5587  {
5588  SCIP_GUBSET* gubset;
5589 
5590  SCIPdebugMessage("separate LMCI1-GUB cuts:\n");
5591 
5592  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5593  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5594 
5595  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5596  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5597  assert(gubset->ngubconss <= nvars);
5598 
5599  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5600  * MODIFIED transformed separation problem and taking into account the following fixing:
5601  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5602  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5603  * if one exists
5604  */
5605  modtransused = TRUE;
5606  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5607  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5608 
5609  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5610 
5611  /* if x* is not fractional we stop the separation routine */
5612  if( !fractional )
5613  {
5614  SCIPdebugMessage(" LMCI1-GUB terminated by no variable with fractional LP value.\n");
5615 
5616  /* frees memory for GUB set data structure */
5617  SCIP_CALL( GUBsetFree(scip, &gubset) );
5618 
5619  goto TERMINATE;
5620  }
5621 
5622  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5623  if( coverfound )
5624  {
5625  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5626  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5627  */
5628  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5629  &nnoncovervars, &coverweight, modtransused) );
5630 
5631  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5632  if( gubset->ngubconss < nvars )
5633  {
5634  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5635  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5636  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5637  }
5638  else
5639  {
5640  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5641  * GUB information
5642  */
5643  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5644  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5645  }
5646  }
5647 
5648  /* frees memory for GUB set data structure */
5649  SCIP_CALL( GUBsetFree(scip, &gubset) );
5650  }
5651  else
5652  {
5653  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5654  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5655  */
5656 
5657  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5658  * MODIFIED transformed separation problem and taking into account the following fixing:
5659  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5660  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5661  * if one exists
5662  */
5663  SCIPdebugMessage("separate LMCI1 cuts:\n");
5664  modtransused = TRUE;
5665  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5666  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5667  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5668 
5669  /* if x* is not fractional we stop the separation routine */
5670  if( !fractional )
5671  goto TERMINATE;
5672 
5673  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5674  if( coverfound )
5675  {
5676  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5677  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5678  */
5679  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5680  &nnoncovervars, &coverweight, modtransused) );
5681 
5682  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5683  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5684  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5685 
5686  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5687  {
5688  SCIPdebugMessage("separate LMCI2 cuts:\n");
5689  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5690  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5691  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5692  }
5693  }
5694  }
5695 
5696  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5697  if ( ! (*cutoff) )
5698  {
5699  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5700  * transformed separation problem and taking into account the following fixing:
5701  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5702  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5703  * if one exists
5704  */
5705  SCIPdebugMessage("separate LEWI cuts:\n");
5706  modtransused = FALSE;
5707  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5708  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5709  assert(fractional);
5710  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5711 
5712  /* if no cover was found we stop the separation routine */
5713  if( coverfound )
5714  {
5715  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5716  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5717  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5718  */
5719  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5720  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5721  }
5722  }
5723 
5724  TERMINATE:
5725  /* frees temporary memory */
5726  SCIPfreeBufferArray(scip, &noncovervars);
5727  SCIPfreeBufferArray(scip, &covervars);
5728  SCIPfreeBufferArray(scip, &solvals);
5729 
5730  return SCIP_OKAY;
5731 }
5732 
5733 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5735  SCIP* scip, /**< SCIP data structure */
5736  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5737  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5738  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5739  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5740  SCIP_Real* knapvals, /**< coefficient of the variables in the continuous knapsack constraint */
5741  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5742  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5743  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5744  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5745  int* ncuts /**< pointer to add up the number of found cuts */
5746  )
5747 {
5748  SCIP_VAR** binvars;
5749  SCIP_VAR** consvars;
5750  SCIP_Real* binvals;
5751  SCIP_Longint* consvals;
5752  SCIP_Longint minact;
5753  SCIP_Longint maxact;
5754  SCIP_Real intscalar;
5755  SCIP_Bool success;
5756  int nbinvars;
5757  int nconsvars;
5758  int i;
5759 
5760  int* tmpindices;
5761  int tmp;
5762  SCIP_CONSHDLR* conshdlr;
5763  SCIP_CONSHDLRDATA* conshdlrdata;
5764  SCIP_Bool noknapsackconshdlr;
5765  SCIP_Bool usegubs;
5766 
5767  assert(nknapvars > 0);
5768  assert(knapvars != NULL);
5769  assert(cutoff != NULL);
5770 
5771  tmpindices = NULL;
5772 
5773  SCIPdebugMessage("separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5774  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5775 
5776  binvars = SCIPgetVars(scip);
5777 
5778  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5779  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5780 
5781  *cutoff = FALSE;
5782 
5783  if( nbinvars == 0 )
5784  return SCIP_OKAY;
5785 
5786  /* set up data structures */
5787  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5788  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5789 
5790  /* get conshdlrdata to use cleared memory */
5791  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5792  if( conshdlr == NULL )
5793  {
5794  noknapsackconshdlr = TRUE;
5795  usegubs = DEFAULT_USEGUBS;
5796 
5797  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5798  BMSclearMemoryArray(binvals, nbinvars);
5799  }
5800  else
5801  {
5802  noknapsackconshdlr = FALSE;
5803  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5804  assert(conshdlrdata != NULL);
5805  usegubs = conshdlrdata->usegubs;
5806 
5807  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5808 
5809  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5810  * change their types to SCIP_VARTYPE_BINARY during presolving
5811  */
5812  if( conshdlrdata->reals1size == 0 )
5813  {
5814  conshdlrdata->reals1size = 1;
5815  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->reals1, 1) );
5816  conshdlrdata->reals1[0] = 0.0;
5817  }
5818 
5819  assert(conshdlrdata->reals1size > 0);
5820 
5821  /* next if condition should normally not be true, because it means that presolving has created more binary
5822  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5823  * transform all integers into their binary representation then it maybe happens
5824  */
5825  if( conshdlrdata->reals1size < nbinvars )
5826  {
5827  int oldsize;
5828  oldsize = conshdlrdata->reals1size;
5829 
5830  while( conshdlrdata->reals1size < nbinvars )
5831  conshdlrdata->reals1size *= 2;
5832  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size) );
5833  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5834  }
5835  binvals = conshdlrdata->reals1;
5836 
5837  /* check for cleared array, all entries have to be zero */
5838 #ifndef NDEBUG
5839  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5840  {
5841  assert(binvals[tmp] == 0);
5842  }
5843 #endif
5844  }
5845 
5846  tmp = 0;
5847 
5848  /* relax continuous knapsack constraint:
5849  * 1. make all variables binary:
5850  * if x_j is continuous or integer variable substitute:
5851  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5852  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5853  * 2. convert coefficients of all variables to positive integers:
5854  * - scale all coefficients a_j to a~_j integral
5855  * - substitute x~_j = 1 - x_j if a~_j < 0
5856  */
5857 
5858  /* replace integer and continuous variables with binary variables */
5859  for( i = 0; i < nknapvars; i++ )
5860  {
5861  SCIP_VAR* var;
5862 
5863  var = knapvars[i];
5864 
5865  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5866  {
5867  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5868  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5869  if( !noknapsackconshdlr )
5870  {
5871  assert(tmpindices != NULL);
5872 
5873  tmpindices[tmp] = SCIPvarGetProbindex(var);
5874  ++tmp;
5875  }
5876  SCIPdebugMessage(" -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5877  }
5878  else if( valscale * knapvals[i] > 0.0 )
5879  {
5880  SCIP_VAR** zvlb;
5881  SCIP_Real* bvlb;
5882  SCIP_Real* dvlb;
5883  SCIP_Real bestlbsol;
5884  int bestlbtype;
5885  int nvlb;
5886  int j;
5887 
5888  /* a_j > 0: substitution with lb or vlb */
5889  nvlb = SCIPvarGetNVlbs(var);
5890  zvlb = SCIPvarGetVlbVars(var);
5891  bvlb = SCIPvarGetVlbCoefs(var);
5892  dvlb = SCIPvarGetVlbConstants(var);
5893 
5894  /* search for lb or vlb with maximal bound value */
5895  bestlbsol = SCIPvarGetLbGlobal(var);
5896  bestlbtype = -1;
5897  for( j = 0; j < nvlb; j++ )
5898  {
5899  /* use only numerical stable vlb with binary variable z */
5900  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5901  {
5902  SCIP_Real vlbsol;
5903 
5904  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5905  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5906  {
5907  *cutoff = TRUE;
5908  SCIPdebugMessage("variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5910  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5911  goto TERMINATE;
5912  }
5913 
5914  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5915  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5916  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5917  {
5918  bestlbsol = vlbsol;
5919  bestlbtype = j;
5920  }
5921  }
5922  }
5923 
5924  /* if no lb or vlb with binary variable was found, we have to abort */
5925  if( SCIPisInfinity(scip, -bestlbsol) )
5926  goto TERMINATE;
5927 
5928  if( bestlbtype == -1 )
5929  {
5930  rhs -= valscale * knapvals[i] * bestlbsol;
5931  SCIPdebugMessage(" -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5932  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5933  }
5934  else
5935  {
5936  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5937  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5938  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5939 
5940  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5941  goto TERMINATE;
5942 
5943  if( !noknapsackconshdlr )
5944  {
5945  assert(tmpindices != NULL);
5946 
5947  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5948  ++tmp;
5949  }
5950  SCIPdebugMessage(" -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5951  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5952  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5953  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5954  }
5955  }
5956  else
5957  {
5958  SCIP_VAR** zvub;
5959  SCIP_Real* bvub;
5960  SCIP_Real* dvub;
5961  SCIP_Real bestubsol;
5962  int bestubtype;
5963  int nvub;
5964  int j;
5965 
5966  assert(valscale * knapvals[i] < 0.0);
5967 
5968  /* a_j < 0: substitution with ub or vub */
5969  nvub = SCIPvarGetNVubs(var);
5970  zvub = SCIPvarGetVubVars(var);
5971  bvub = SCIPvarGetVubCoefs(var);
5972  dvub = SCIPvarGetVubConstants(var);
5973 
5974  /* search for ub or vub with minimal bound value */
5975  bestubsol = SCIPvarGetUbGlobal(var);
5976  bestubtype = -1;
5977  for( j = 0; j < nvub; j++ )
5978  {
5979  /* use only numerical stable vub with active binary variable z */
5980  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
5981  {
5982  SCIP_Real vubsol;
5983 
5984  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
5985  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
5986  {
5987  *cutoff = TRUE;
5988  SCIPdebugMessage("variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
5990  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
5991  goto TERMINATE;
5992  }
5993 
5994  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
5995  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
5996  if( SCIPisLE(scip, vubsol, bestubsol) )
5997  {
5998  bestubsol = vubsol;
5999  bestubtype = j;
6000  }
6001  }
6002  }
6003 
6004  /* if no ub or vub with binary variable was found, we have to abort */
6005  if( SCIPisInfinity(scip, bestubsol) )
6006  goto TERMINATE;
6007 
6008  if( bestubtype == -1 )
6009  {
6010  rhs -= valscale * knapvals[i] * bestubsol;
6011  SCIPdebugMessage(" -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6012  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6013  }
6014  else
6015  {
6016  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6017  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6018  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6019 
6020  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6021  goto TERMINATE;
6022 
6023  if( !noknapsackconshdlr )
6024  {
6025  assert(tmpindices != NULL);
6026 
6027  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6028  ++tmp;
6029  }
6030  SCIPdebugMessage(" -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6031  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6032  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6033  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6034  }
6035  }
6036  }
6037 
6038  /* convert coefficients of all (now binary) variables to positive integers:
6039  * - make all coefficients integral
6040  * - make all coefficients positive (substitute negated variable)
6041  */
6042  nconsvars = 0;
6043 
6044  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6045  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6046  */
6048  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6049  SCIPdebugMessage(" -> intscalar = %.15g\n", intscalar);
6050 
6051  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6052  if( !success )
6053  intscalar = 1.0;
6054 
6055  /* make all coefficients integral and positive:
6056  * - scale a~_j = a_j * intscalar
6057  * - substitute x~_j = 1 - x_j if a~_j < 0
6058  */
6059  rhs = rhs*intscalar;
6060 
6061  SCIPdebugMessage(" -> rhs = %.15g\n", rhs);
6062  minact = 0;
6063  maxact = 0;
6064  for( i = 0; i < nbinvars; i++ )
6065  {
6066  SCIP_VAR* var;
6067  SCIP_Longint val;
6068 
6069  val = (SCIP_Longint)SCIPfloor(scip, binvals[i]*intscalar);
6070  if( val == 0 )
6071  continue;
6072 
6073  if( val > 0 )
6074  {
6075  var = binvars[i];
6076  SCIPdebugMessage(" -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6077  val, SCIPvarGetName(var), binvals[i], rhs);
6078  }
6079  else
6080  {
6081  assert(val < 0);
6082 
6083  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6084  val = -val;
6085  rhs += val;
6086  SCIPdebugMessage(" -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6087  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6088  }
6089 
6090  if( SCIPvarGetLbLocal(var) > 0.5 )
6091  minact += val;
6092  if( SCIPvarGetUbLocal(var) > 0.5 )
6093  maxact += val;
6094  consvals[nconsvars] = val;
6095  consvars[nconsvars] = var;
6096  nconsvars++;
6097  }
6098 
6099  if( nconsvars > 0 )
6100  {
6101  SCIP_Longint capacity;
6102 
6103  assert(consvars != NULL);
6104  assert(consvals != NULL);
6105  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6106 
6107 #ifdef SCIP_DEBUG
6108  {
6109  SCIP_Real act;
6110 
6111  SCIPdebugMessage(" -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6112  act = 0.0;
6113  for( i = 0; i < nconsvars; ++i )
6114  {
6115  SCIPdebugPrintf(" %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6116  SCIPgetSolVal(scip, sol, consvars[i]));
6117  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6118  }
6119  SCIPdebugPrintf(" <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6120  capacity, rhs, act, minact, maxact);
6121  }
6122 #endif
6123 
6124  if( minact > capacity )
6125  {
6126  SCIPdebugMessage("minactivity of knapsack relaxation implies local cutoff\n");
6127  *cutoff = TRUE;
6128  goto TERMINATE;
6129  }
6130 
6131  if( maxact > capacity )
6132  {
6133  /* separate lifted cut from relaxed knapsack constraint */
6134  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6135  }
6136  }
6137 
6138  TERMINATE:
6139  /* free data structures */
6140  if( noknapsackconshdlr)
6141  {
6142  SCIPfreeBufferArray(scip, &binvals);
6143  }
6144  else
6145  {
6146  /* clear binvals */
6147  for( --tmp; tmp >= 0; --tmp)
6148  {
6149  assert(tmpindices != NULL);
6150  binvals[tmpindices[tmp]] = 0;
6151  }
6152  SCIPfreeBufferArray(scip, &tmpindices);
6153  }
6154  SCIPfreeBufferArray(scip, &consvals);
6155  SCIPfreeBufferArray(scip, &consvars);
6156 
6157  return SCIP_OKAY;
6158 }
6159 
6160 /** separates given knapsack constraint */
6161 static
6163  SCIP* scip, /**< SCIP data structure */
6164  SCIP_CONS* cons, /**< knapsack constraint */
6165  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6166  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6167  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6168  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6169  int* ncuts /**< pointer to add up the number of found cuts */
6170  )
6171 {
6172  SCIP_CONSDATA* consdata;
6173  SCIP_Bool violated;
6174 
6175  assert(ncuts != NULL);
6176  assert(cutoff != NULL);
6177  *cutoff = FALSE;
6178 
6179  consdata = SCIPconsGetData(cons);
6180  assert(consdata != NULL);
6181 
6182  SCIPdebugMessage("separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6183 
6184  /* check knapsack constraint itself for feasibility */
6185  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6186 
6187  if( violated )
6188  {
6189  /* add knapsack constraint as LP row to the LP */
6190  SCIP_CALL( addRelaxation(scip, cons, sol, cutoff) );
6191  (*ncuts)++;
6192  }
6193  else if( sepacuts )
6194  {
6195  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6196  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6197  }
6198 
6199  return SCIP_OKAY;
6200 }
6201 
6202 /** adds coefficient to constraint data */
6203 static
6205  SCIP* scip, /**< SCIP data structure */
6206  SCIP_CONS* cons, /**< knapsack constraint */
6207  SCIP_VAR* var, /**< variable to add to knapsack */
6208  SCIP_Longint weight /**< weight of variable in knapsack */
6209  )
6210 {
6211  SCIP_CONSDATA* consdata;
6212 
6213  consdata = SCIPconsGetData(cons);
6214  assert(consdata != NULL);
6215  assert(SCIPvarIsBinary(var));
6216  assert(weight > 0);
6217 
6218  /* add the new coefficient to the LP row */
6219  if( consdata->row != NULL )
6220  {
6221  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6222  }
6223 
6224  /* check for fixed variable */
6225  if( SCIPvarGetLbGlobal(var) > 0.5 )
6226  {
6227  /* variable is fixed to one: reduce capacity */
6228  consdata->capacity -= weight;
6229  }
6230  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6231  {
6232  SCIP_Bool negated;
6233 
6234  /* get binary representative of variable */
6235  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6236 
6237  /* insert coefficient */
6238  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6239  consdata->vars[consdata->nvars] = var;
6240  consdata->weights[consdata->nvars] = weight;
6241  consdata->nvars++;
6242 
6243  /* capture variable */
6244  SCIP_CALL( SCIPcaptureVar(scip, var) );
6245 
6246  /* install the rounding locks of variable */
6247  SCIP_CALL( lockRounding(scip, cons, var) );
6248 
6249  /* catch events */
6250  if( SCIPconsIsTransformed(cons) )
6251  {
6252  SCIP_CONSHDLRDATA* conshdlrdata;
6253 
6254  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6255  assert(conshdlrdata != NULL);
6256  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], consdata, weight) );
6257  SCIP_CALL( SCIPcatchVarEvent(scip, var,
6260  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6261  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6262 
6263  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6264  consdata->existmultaggr = TRUE;
6265  }
6266 
6267  /* update weight sums */
6268  consdata->weightsum += weight;
6269  if( SCIPvarGetLbLocal(var) > 0.5 )
6270  consdata->onesweightsum += weight;
6271 
6272  consdata->sorted = FALSE;
6273  consdata->cliquepartitioned = FALSE;
6274  consdata->negcliquepartitioned = FALSE;
6275  consdata->merged = FALSE;
6276  }
6277  consdata->propagated = FALSE;
6278  consdata->presolvedtiming = 0;
6279  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6280 
6281  return SCIP_OKAY;
6282 }
6283 
6284 /** deletes coefficient at given position from constraint data */
6285 static
6287  SCIP* scip, /**< SCIP data structure */
6288  SCIP_CONS* cons, /**< knapsack constraint */
6289  int pos /**< position of coefficient to delete */
6290  )
6291 {
6292  SCIP_CONSDATA* consdata;
6293  SCIP_VAR* var;
6294 
6295  consdata = SCIPconsGetData(cons);
6296  assert(consdata != NULL);
6297  assert(0 <= pos && pos < consdata->nvars);
6298 
6299  var = consdata->vars[pos];
6300  assert(var != NULL);
6301  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6302 
6303  /* delete the coefficient from the LP row */
6304  if( consdata->row != NULL )
6305  {
6306  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6307  }
6308 
6309  /* remove the rounding locks of variable */
6310  SCIP_CALL( unlockRounding(scip, cons, var) );
6311 
6312  /* drop events */
6313  if( SCIPconsIsTransformed(cons) )
6314  {
6315  SCIP_CONSHDLRDATA* conshdlrdata;
6316 
6317  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6318  assert(conshdlrdata != NULL);
6319  SCIP_CALL( SCIPdropVarEvent(scip, var,
6322  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6323  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6324  }
6325 
6326  /* update weight sums */
6327  consdata->weightsum -= consdata->weights[pos];
6328  if( SCIPvarGetLbLocal(var) > 0.5 )
6329  consdata->onesweightsum -= consdata->weights[pos];
6330  assert(consdata->weightsum >= 0);
6331  assert(consdata->onesweightsum >= 0);
6332 
6333  /* move the last variable to the free slot */
6334  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6335  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6336  if( consdata->eventdata != NULL )
6337  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6338 
6339  /* release variable */
6340  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6341 
6342  consdata->propagated = FALSE;
6343  consdata->presolvedtiming = 0;
6344  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6345 
6346  /* try to use old clique partitions */
6347  if( consdata->cliquepartitioned )
6348  {
6349  assert(consdata->cliquepartition != NULL);
6350  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6351  * change the clique number */
6352  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6353  {
6354  int oldcliqenum;
6355 
6356  oldcliqenum = consdata->cliquepartition[pos];
6357  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6358 
6359  /* the following if and else cases assure that we have increasing clique numbers */
6360  if( consdata->cliquepartition[pos] > pos )
6361  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6362  else
6363  {
6364  int i;
6365  int cliquenumbefore;
6366 
6367  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6368  * occurs the same as the old one is still in the cliquepartition */
6369  if( oldcliqenum > consdata->cliquepartition[pos] )
6370  {
6371  for( i = 0; i < consdata->nvars; ++i )
6372  if( oldcliqenum == consdata->cliquepartition[i] )
6373  break;
6374  else if( oldcliqenum < consdata->cliquepartition[i] )
6375  {
6376  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6377  break;
6378  }
6379  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6380  * the biggest index, so decrease the number of cliques
6381  */
6382  if( i == consdata->nvars )
6383  --(consdata->ncliques);
6384  }
6385  /* if the old clique number was smaller than the new one we have to check the front for an element with
6386  * clique number minus 1 */
6387  else if( oldcliqenum < consdata->cliquepartition[pos] )
6388  {
6389  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6390  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6391 
6392  if( i < cliquenumbefore )
6393  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6394  }
6395  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6396  else if( pos == consdata->nvars - 1)
6397  {
6398  cliquenumbefore = consdata->cliquepartition[pos];
6399  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6400 
6401  if( i < cliquenumbefore )
6402  --(consdata->ncliques);
6403  }
6404  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6405  }
6406  }
6407  else
6408  --(consdata->ncliques);
6409  }
6410 
6411  if( consdata->negcliquepartitioned )
6412  {
6413  assert(consdata->negcliquepartition != NULL);
6414  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6415  * change the clique number */
6416  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6417  {
6418  int oldcliqenum;
6419 
6420  oldcliqenum = consdata->negcliquepartition[pos];
6421  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6422 
6423  /* the following if and else cases assure that we have increasing clique numbers */
6424  if( consdata->negcliquepartition[pos] > pos )
6425  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6426  else
6427  {
6428  int i;
6429  int cliquenumbefore;
6430 
6431  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6432  * occurs, the same as the old one occurs */
6433  if( oldcliqenum > consdata->negcliquepartition[pos] )
6434  {
6435  for( i = 0; i < consdata->nvars; ++i )
6436  if( oldcliqenum == consdata->negcliquepartition[i] )
6437  break;
6438  else if( oldcliqenum < consdata->negcliquepartition[i] )
6439  {
6440  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6441  break;
6442  }
6443  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6444  * the biggest index, so decrease the number of negated cliques
6445  */
6446  if( i == consdata->nvars )
6447  --(consdata->nnegcliques);
6448  }
6449  /* if the old clique number was smaller than the new one we have to check the front for an element with
6450  * clique number minus 1 */
6451  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6452  {
6453  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6454  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6455 
6456  if( i < cliquenumbefore )
6457  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6458  }
6459  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6460  else if( pos == consdata->nvars - 1)
6461  {
6462  cliquenumbefore = consdata->negcliquepartition[pos];
6463  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6464 
6465  if( i < cliquenumbefore )
6466  --(consdata->nnegcliques);
6467  }
6468  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6469  }
6470  }
6471  else
6472  --(consdata->nnegcliques);
6473  }
6474 
6475  --(consdata->nvars);
6476 
6477  return SCIP_OKAY;
6478 }
6479 
6480 /** removes all items with weight zero from knapsack constraint */
6481 static
6483  SCIP* scip, /**< SCIP data structure */
6484  SCIP_CONS* cons /**< knapsack constraint */
6485  )
6486 {
6487  SCIP_CONSDATA* consdata;
6488  int v;
6490  consdata = SCIPconsGetData(cons);
6491  assert(consdata != NULL);
6492 
6493  for( v = consdata->nvars-1; v >= 0; --v )
6494  {
6495  if( consdata->weights[v] == 0 )
6496  {
6497  SCIP_CALL( delCoefPos(scip, cons, v) );
6498  }
6499  }
6500 
6501  return SCIP_OKAY;
6502 }
6503 
6504 /* perform deletion of variables in all constraints of the constraint handler */
6505 static
6507  SCIP* scip, /**< SCIP data structure */
6508  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6509  SCIP_CONS** conss, /**< array of constraints */
6510  int nconss /**< number of constraints */
6511  )
6512 {
6513  SCIP_CONSDATA* consdata;
6514  int i;
6515  int v;
6516 
6517  assert(scip != NULL);
6518  assert(conshdlr != NULL);
6519  assert(conss != NULL);
6520  assert(nconss >= 0);
6521  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6522 
6523  /* iterate over all constraints */
6524  for( i = 0; i < nconss; i++ )
6525  {
6526  consdata = SCIPconsGetData(conss[i]);
6527 
6528  /* constraint is marked, that some of its variables were deleted */
6529  if( consdata->varsdeleted )
6530  {
6531  /* iterate over all variables of the constraint and delete them from the constraint */
6532  for( v = consdata->nvars - 1; v >= 0; --v )
6533  {
6534  if( SCIPvarIsDeleted(consdata->vars[v]) )
6535  {
6536  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6537  }
6538  }
6539  consdata->varsdeleted = FALSE;
6540  }
6541  }
6542 
6543  return SCIP_OKAY;
6544 }
6545 
6546 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6547 static
6549  SCIP* scip, /**< SCIP data structure */
6550  SCIP_CONS* cons, /**< knapsack constraint */
6551  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6552  )
6553 {
6554  SCIP_CONSDATA* consdata;
6555  int v;
6556  int prev;
6557 
6558  assert(scip != NULL);
6559  assert(cons != NULL);
6560  assert(cutoff != NULL);
6561 
6562  consdata = SCIPconsGetData(cons);
6563  assert(consdata != NULL);
6564 
6565  *cutoff = FALSE;
6566 
6567  if( consdata->merged )
6568  return SCIP_OKAY;
6569 
6570  if( consdata->nvars <= 1 )
6571  {
6572  consdata->merged = TRUE;
6573  return SCIP_OKAY;
6574  }
6575 
6576  assert(consdata->vars != NULL || consdata->nvars == 0);
6577 
6578  /* sorting array after indices of variables, that's only for faster merging */
6579  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6580  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6581 
6582  /* knapsack-sorting (decreasing weights) now lost */
6583  consdata->sorted = FALSE;
6584 
6585  v = consdata->nvars - 1;
6586  prev = v - 1;
6587  /* loop backwards through the items: deletion only affects rear items */
6588  while( prev >= 0 )
6589  {
6590  SCIP_VAR* var1;
6591  SCIP_VAR* var2;
6592  SCIP_Bool negated1;
6593  SCIP_Bool negated2;
6594 
6595  negated1 = FALSE;
6596  negated2 = FALSE;
6597 
6598  var1 = consdata->vars[v];
6599  assert(SCIPvarIsBinary(var1));
6600  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6602  {
6603  var1 = SCIPvarGetNegatedVar(var1);
6604  negated1 = TRUE;
6605  }
6606  assert(var1 != NULL);
6607 
6608  var2 = consdata->vars[prev];
6609  assert(SCIPvarIsBinary(var2));
6610  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6612  {
6613  var2 = SCIPvarGetNegatedVar(var2);
6614  negated2 = TRUE;
6615  }
6616  assert(var2 != NULL);
6617 
6618  if( var1 == var2 )
6619  {
6620  /* both variables are either active or negated */
6621  if( negated1 == negated2 )
6622  {
6623  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6624  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6625  SCIP_CALL( delCoefPos(scip, cons, v) );
6626  }
6627  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6628  * and delete item of smaller weight
6629  */
6630  else if( consdata->weights[v] == consdata->weights[prev] )
6631  {
6632  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6633  consdata->capacity -= consdata->weights[v];
6634  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6635  SCIP_CALL( delCoefPos(scip, cons, prev) );
6636 
6637  --prev;
6638  }
6639  else if( consdata->weights[v] < consdata->weights[prev] )
6640  {
6641  consdata->capacity -= consdata->weights[v];
6642  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6643  assert(consdata->weights[prev] > 0);
6644  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6645  }
6646  else
6647  {
6648  consdata->capacity -= consdata->weights[prev];
6649  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6650  assert(consdata->weights[v] > 0);
6651  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6652  /* restore order iff necessary */
6653  if( consdata->nvars != v ) /* otherwise the order still stands */
6654  {
6655  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6656  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6657  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6658  --prev;
6659  else /* we need to let v at the same position*/
6660  {
6661  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6662  /* don't decrease v, the same variable may exist up front */
6663  --prev;
6664  continue;
6665  }
6666  }
6667  }
6668  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6669  }
6670  v = prev;
6671  --prev;
6672  }
6673 
6674  consdata->merged = TRUE;
6675 
6676  /* check infeasibility */
6677  if( consdata->onesweightsum > consdata->capacity )
6678  {
6679  SCIPdebugMessage("merge multiples detected cutoff.\n");
6680  *cutoff = TRUE;
6681  return SCIP_OKAY;
6682  }
6683 
6684  return SCIP_OKAY;
6685 }
6686 
6687 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6688  * fixings (dual reductions)
6689  */
6690 static
6692  SCIP* scip, /**< SCIP data structure */
6693  SCIP_CONS* cons, /**< knapsack constraint */
6694  int* nfixedvars, /**< pointer to count number of fixings */
6695  int* ndelconss, /**< pointer to count number of deleted constraints */
6696  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6697  )
6699  SCIP_CONSDATA* consdata;
6700  SCIP_VAR** vars;
6701  SCIP_Real* profits;
6702  int* solitems;
6703  int* nonsolitems;
6704  int* items;
6705  SCIP_Real solval;
6706  SCIP_Bool infeasible;
6707  SCIP_Bool tightened;
6708  SCIP_Bool applicable;
6709  int nsolitems;
6710  int nnonsolitems;
6711  int nvars;
6712  int v;
6713 
6714  assert(!SCIPconsIsModifiable(cons));
6715 
6716  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6717  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6718  * added to the problems have the check flag set to FALSE
6719  */
6720  if( !SCIPconsIsChecked(cons) )
6721  return SCIP_OKAY;
6722 
6723  consdata = SCIPconsGetData(cons);
6724  assert(consdata != NULL);
6725 
6726  nvars = consdata->nvars;
6727  vars = consdata->vars;
6728 
6729  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6730  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6731  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6732  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6733 
6734  applicable = TRUE;
6735 
6736  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6737  * collect object values which are the profits of the knapsack problem
6738  */
6739  for( v = 0; v < nvars; ++v )
6740  {
6741  SCIP_VAR* var;
6742  SCIP_Bool negated;
6743 
6744  var = vars[v];
6745  assert(var != NULL);
6746 
6747  /* the variable should not be (globally) fixed */
6748  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6749 
6750  if( SCIPvarGetNLocksDown(var) > 0 || SCIPvarGetNLocksUp(var) > 1 )
6751  {
6752  applicable = FALSE;
6753  break;
6754  }
6755 
6756  negated = FALSE;
6757 
6758  /* get the active variable */
6759  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6760  assert(SCIPvarIsActive(var));
6761 
6762  if( negated )
6763  profits[v] = SCIPvarGetObj(var);
6764  else
6765  profits[v] = -SCIPvarGetObj(var);
6766 
6767  SCIPdebugMessage("variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6768  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6769  items[v] = v;
6770  }
6771 
6772  if( applicable )
6773  {
6774  SCIP_Bool success;
6775 
6776  SCIPdebugMessage("the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6777  SCIPdebugPrintCons(scip, cons, NULL);
6778 
6779  /* solve knapsack problem exactly */
6780  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6781  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6782 
6783  if( success )
6784  {
6785  SCIP_VAR* var;
6786 
6787  /* apply solution of the knapsack as dual reductions */
6788  for( v = 0; v < nsolitems; ++v )
6789  {
6790  var = vars[solitems[v]];
6791  assert(var != NULL);
6792 
6793  SCIPdebugMessage("variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6795  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6796  assert(!infeasible);
6797  assert(tightened);
6798  (*nfixedvars)++;
6799  }
6800 
6801  for( v = 0; v < nnonsolitems; ++v )
6802  {
6803  var = vars[nonsolitems[v]];
6804  assert(var != NULL);
6805 
6806  SCIPdebugMessage("variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6808  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6809  assert(!infeasible);
6810  assert(tightened);
6811  (*nfixedvars)++;
6812  }
6813 
6814  SCIP_CALL( SCIPdelCons(scip, cons) );
6815  (*ndelconss)++;
6816  (*deleted) = TRUE;
6817  }
6818  }
6819 
6820  SCIPfreeBufferArray(scip, &nonsolitems);
6821  SCIPfreeBufferArray(scip, &solitems);
6822  SCIPfreeBufferArray(scip, &items);
6823  SCIPfreeBufferArray(scip, &profits);
6824 
6825  return SCIP_OKAY;
6826 }
6827 
6828 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6829  * constraint enters the LP by setting the initial and separated flag to FALSE
6830  */
6831 static
6833  SCIP* scip, /**< SCIP data structure */
6834  SCIP_CONS* cons, /**< knapsack constraint */
6835  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6836  )
6837 {
6838  SCIP_CONSDATA* consdata;
6839  SCIP_VAR** vars;
6840  SCIP_VAR* var;
6841  SCIP_Real offset;
6842  SCIP_Real scale;
6843  SCIP_Real objval;
6844  SCIP_Bool applicable;
6845  SCIP_Bool negated;
6846  int nobjvars;
6847  int nvars;
6848  int v;
6849 
6850  assert(scip != NULL);
6851  assert(cons != NULL);
6852  assert(conshdlrdata != NULL);
6853 
6854  consdata = SCIPconsGetData(cons);
6855  assert(consdata != NULL);
6856 
6857  nvars = consdata->nvars;
6858  nobjvars = SCIPgetNObjVars(scip);
6859 
6860  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6861  * and/or separated flag is set to FALSE
6862  */
6863  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6864  return SCIP_OKAY;
6865 
6866  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6867  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6868  */
6869  if( nobjvars == 0 )
6870  return SCIP_OKAY;
6871 
6872  vars = consdata->vars;
6873  applicable = TRUE;
6874  offset = 0.0;
6875  scale = 1.0;
6876 
6877  for( v = 0; v < nvars && applicable; ++v )
6878  {
6879  negated = FALSE;
6880  var = vars[v];
6881  assert(vars != NULL);
6882 
6883  if( SCIPvarIsNegated(var) )
6884  {
6885  negated = TRUE;
6886  var = SCIPvarGetNegatedVar(var);
6887  assert(var != NULL);
6888  }
6889 
6890  objval = SCIPvarGetObj(var);
6891 
6892  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6893  if( SCIPisZero(scip, objval) )
6894  applicable = FALSE;
6895  else
6896  {
6897  SCIP_Real weight;
6898 
6899  weight = (SCIP_Real)consdata->weights[v];
6900 
6901  if( negated )
6902  {
6903  if( v == 0 )
6904  {
6905  /* the first variable defines the scale */
6906  scale = weight / -objval;
6907 
6908  offset += weight;
6909  }
6910  else if( SCIPisEQ(scip, -objval * scale, weight) )
6911  offset += weight;
6912  else
6913  applicable = FALSE;
6914  }
6915  else if( v == 0 )
6916  {
6917  /* the first variable define the scale */
6918  scale = weight / objval;
6919  }
6920  else if( !SCIPisEQ(scip, objval * scale, weight) )
6921  applicable = FALSE;
6922  }
6923  }
6924 
6925  if( applicable )
6926  {
6927  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6928  {
6929  SCIP_Real cutoffbound;
6930 
6931  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6932  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6933  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6934 
6935  cutoffbound = (consdata->capacity - offset) / scale;
6936 
6937  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6938  * still excepted
6939  */
6940  cutoffbound += SCIPcutoffbounddelta(scip);
6941 
6942  SCIPdebugMessage("constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6943  SCIPconsGetName(cons), cutoffbound);
6944 
6945  if( cutoffbound < SCIPgetCutoffbound(scip) )
6946  {
6947  SCIPdebugMessage("update cutoff bound <%g>\n", cutoffbound);
6948 
6949  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6950  }
6951  else
6952  {
6953  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6954  * propagation
6955  */
6956  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6957  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6958  }
6959  }
6960  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6961  {
6962  SCIP_Real lowerbound;
6963 
6964  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6965  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6966  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6967 
6968  lowerbound = (consdata->capacity - offset) / scale;
6969 
6970  SCIPdebugMessage("constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6971  SCIPconsGetName(cons), lowerbound);
6972 
6973  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6974  }
6975  }
6976 
6977  return SCIP_OKAY;
6978 }
6979 
6980 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6981  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
6982 static
6984  SCIP* scip, /**< SCIP data structure */
6985  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
6986  SCIP_VAR** vars, /**< array for sorted variables */
6987  SCIP_Longint* weights, /**< array for sorted weights */
6988  int* cliquestartposs, /**< starting position array for each clique */
6989  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
6990  )
6991 {
6992  SCIP_VAR** origvars;
6993  int norigvars;
6994  SCIP_Longint* origweights;
6995  int* cliquepartition;
6996  int ncliques;
6997 
6998  SCIP_VAR*** varpointers;
6999  SCIP_Longint** weightpointers;
7000  int* cliquecount;
7001 
7002  int nextpos;
7003  int c;
7004  int v;
7005 
7006  assert(scip != NULL);
7007  assert(consdata != NULL);
7008  assert(vars != NULL);
7009  assert(weights != NULL);
7010  assert(cliquestartposs != NULL);
7011 
7012  origweights = consdata->weights;
7013  origvars = consdata->vars;
7014  norigvars = consdata->nvars;
7015 
7016  assert(origvars != NULL || norigvars == 0);
7017  assert(origweights != NULL || norigvars == 0);
7018 
7019  if( norigvars == 0 )
7020  return SCIP_OKAY;
7021 
7022  if( usenegatedclique )
7023  {
7024  assert(consdata->negcliquepartitioned);
7025 
7026  cliquepartition = consdata->negcliquepartition;
7027  ncliques = consdata->nnegcliques;
7028  }
7029  else
7030  {
7031  assert(consdata->cliquepartitioned);
7032 
7033  cliquepartition = consdata->cliquepartition;
7034  ncliques = consdata->ncliques;
7035  }
7036 
7037  assert(cliquepartition != NULL);
7038  assert(ncliques > 0);
7039 
7040  /* we first count all clique items and alloc temporary memory for a bucket sort */
7041  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7042  BMSclearMemoryArray(cliquecount, ncliques);
7043 
7044  /* first we count for each clique the number of elements */
7045  for( v = norigvars - 1; v >= 0; --v )
7046  {
7047  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7048  ++(cliquecount[cliquepartition[v]]);
7049  }
7050 
7051  /*@todo: maybe it is better to put largest cliques up front */
7052 
7053 #ifndef NDEBUG
7054  BMSclearMemoryArray(vars, norigvars);
7055  BMSclearMemoryArray(weights, norigvars);
7056 #endif
7057  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7058  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7059 
7060  nextpos = 0;
7061  /* now we initialize all start pointers for each clique, so they will be ordered */
7062  for( c = 0; c < ncliques; ++c )
7063  {
7064  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7065  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7066  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7067  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7068  * vars[7]
7069  *
7070  */
7071  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7072  cliquestartposs[c] = nextpos;
7073  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7074  assert(cliquecount[c] > 0);
7075  nextpos += cliquecount[c];
7076  assert(nextpos > 0);
7077  }
7078  assert(nextpos == norigvars);
7079  cliquestartposs[c] = nextpos;
7080 
7081  /* now we copy all variable and weights to the right order */
7082  for( v = 0; v < norigvars; ++v )
7083  {
7084  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7085  ++(varpointers[cliquepartition[v]]);
7086  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7087  ++(weightpointers[cliquepartition[v]]);
7088  }
7089 #ifndef NDEBUG
7090  for( v = 0; v < norigvars; ++v )
7091  {
7092  assert(vars[v] != NULL);
7093  assert(weights[v] > 0);
7094  }
7095 #endif
7096 
7097  /* free temporary memory */
7098  SCIPfreeBufferArray(scip, &weightpointers);
7099  SCIPfreeBufferArray(scip, &varpointers);
7100  SCIPfreeBufferArray(scip, &cliquecount);
7101 
7102  return SCIP_OKAY;
7103 }
7104 
7105 /** propagation method for knapsack constraints */
7106 static
7108  SCIP* scip, /**< SCIP data structure */
7109  SCIP_CONS* cons, /**< knapsack constraint */
7110  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7111  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7112  int* nfixedvars, /**< pointer to count number of fixings */
7113  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7114  )
7115 {
7116  SCIP_CONSDATA* consdata;
7117  SCIP_Bool infeasible;
7118  SCIP_Bool tightened;
7119  SCIP_Longint zerosweightsum;
7120  SCIP_Longint* secondmaxweights;
7121  SCIP_Longint minweightsum;
7122 
7123  int nvars;
7124  int i;
7125  int nnegcliques;
7126 
7127  SCIP_VAR** myvars;
7128  SCIP_Longint* myweights;
7129  int* cliquestartposs;
7130  SCIP_Longint localminweightsum;
7131  SCIP_Bool foundmax;
7132  int c;
7133 
7134  assert(scip != NULL);
7135  assert(cons != NULL);
7136  assert(cutoff != NULL);
7137  assert(redundant != NULL);
7138  assert(nfixedvars != NULL);
7139 
7140  consdata = SCIPconsGetData(cons);
7141  assert(consdata != NULL);
7142 
7143  *cutoff = FALSE;
7144  *redundant = FALSE;
7145 
7146  /* check, if constraint is already propagated */
7147  if( consdata->propagated )
7148  return SCIP_OKAY;
7149 
7150  SCIPdebugMessage("propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7151 
7152  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7153  if( !SCIPinRepropagation(scip) )
7154  {
7155  SCIP_CALL( SCIPincConsAge(scip, cons) );
7156  }
7157 
7158  /* we need a merged constraint cause without it the negated clique information could be invalid */
7159  usenegatedclique = usenegatedclique && consdata->merged;
7160  nnegcliques = -1;
7161 
7162  /* init for debugging */
7163  myvars = NULL;
7164  myweights = NULL;
7165  cliquestartposs = NULL;
7166  secondmaxweights = NULL;
7167  do
7168  {
7169  zerosweightsum = 0;
7170  nvars = consdata->nvars;
7171 
7172  minweightsum = 0;
7173  localminweightsum = 0;
7174 
7175  /* make sure, the items are sorted by non-increasing weight */
7176  sortItems(consdata);
7177 
7178  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7179  * a negated clique means, that at most one of the clique variables can be zero
7180  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W(C) ), where W(C) is the maximal weight of C
7181  *
7182  * if for i \in C (a negated clique) minweightsum - wi + W(C) > capacity => xi = 1
7183  * since replacing i with the element of maximal weight leads to infeasibility
7184  */
7185  if( usenegatedclique && nvars > 0 )
7186  {
7187  /* compute clique partitions */
7188  SCIP_CALL( calcCliquepartition(scip, consdata, FALSE, TRUE) );
7189  nnegcliques = consdata->nnegcliques;
7190 
7191  /* if we have no real negated cliques we can stop here */
7192  if( nnegcliques == nvars )
7193  break;
7194 
7195  /* allocate temporary memory and initialize it */
7196  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7197  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7198  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7199  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7200  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7201 
7202  /* resort variables to avoid quadratic algorithm later on */
7203  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7204 
7205  c = 0;
7206  foundmax = FALSE;
7207  i = 0;
7208 
7209  while( i < nvars )
7210  {
7211  /* ignore variables of the negated clique which are fixed to one since these are counted in
7212  * consdata->onesweightsum
7213  */
7214 
7215  /* if there are only one variable negated cliques left we can stop */
7216  if( nnegcliques - c == nvars - i )
7217  {
7218  minweightsum += localminweightsum;
7219  localminweightsum = 0;
7220  break;
7221  }
7222 
7223  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7224  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7225  * other clique variables to one
7226  */
7227  if( cliquestartposs[c] == i )
7228  {
7229  assert(myweights[i] > 0);
7230  ++c;
7231  minweightsum += localminweightsum;
7232  localminweightsum = 0;
7233  foundmax = TRUE;
7234 
7235  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7236  foundmax = FALSE;
7237 
7238  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7239  {
7240  ++i;
7241  continue;
7242  }
7243  }
7244 
7245  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7246  {
7247  assert(myweights[i] > 0);
7248 
7249  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7250  {
7251  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7252 
7253  if( !foundmax )
7254  {
7255  foundmax = TRUE;
7256 
7257  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7258  cliquestartposs[c - 1] = i;
7259  ++i;
7260 
7261  continue;
7262  }
7263  /* memorize second max weight for each clique */
7264  if( secondmaxweights[c - 1] == 0 )
7265  secondmaxweights[c - 1] = myweights[i];
7266 
7267  localminweightsum += myweights[i];
7268  }
7269  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7270  else
7271  {
7272  int v;
7273  /* fix all other variables of the negated clique to 1 */
7274  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7275  {
7276  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7277  {
7278  SCIPdebugMessage(" -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7279  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7280 
7281  if( infeasible )
7282  {
7283  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7284 
7285  /* analyze the infeasibility if conflict analysis is applicable */
7287  {
7288  /* conflict analysis can only be applied in solving stage */
7289  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7290 
7291  /* initialize the conflict analysis */
7293 
7294  /* add the two variables which are fixed to zero within a negated clique */
7295  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7296  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7297 
7298  /* start the conflict analysis */
7299  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7300  }
7301  *cutoff = TRUE;
7302  break;
7303  }
7304  assert(tightened);
7305  ++(*nfixedvars);
7306  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7307  }
7308  }
7309  if( *cutoff )
7310  break;
7311 
7312  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7313  localminweightsum = 0;
7314  /* we can jump to the end of this clique */
7315  i = cliquestartposs[c] - 1;
7316  }
7317  }
7318  ++i;
7319  }
7320  /* add last clique minweightsum */
7321  minweightsum += localminweightsum;
7322 
7323  SCIPdebugMessage("knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7324  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7325 
7326  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7327  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7328  {
7329  SCIP_Longint maxweight;
7330 
7331  c = 0;
7332  maxweight = -1;
7333 
7334  /* check for each negated clique if we can conclude a fixing of a variable to one */
7335  for( i = 0; i < nvars; ++i )
7336  {
7337  /* if there are only one variable negated cliques left we can stop */
7338  if( nnegcliques - c == nvars - i )
7339  break;
7340 
7341  /* we cannot fix the biggest weight */
7342  if( cliquestartposs[c] == i )
7343  {
7344  maxweight = myweights[i];
7345  ++c;
7346  continue;
7347  }
7348 
7349  /* only check variables of negated cliques for which no variable is locally fixed */
7350  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 && SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7351  {
7352  assert(maxweight >= myweights[i]);
7353 
7354  /* if for i \in C (a negated clique) minweightsum - wi + W(C) > capacity => xi = 1
7355  * since replacing i with the element of maximal weight leads to infeasibility */
7356  if( consdata->onesweightsum + minweightsum - myweights[i] + maxweight > consdata->capacity )
7357  {
7358  SCIPdebugMessage(" -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7359  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7360  assert(!infeasible);
7361  assert(tightened);
7362  ++(*nfixedvars);
7363  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7364 
7365  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7366  * consdata->onesweightsum
7367  */
7368  minweightsum -= myweights[i];
7369  assert(minweightsum >= 0);
7370  }
7371  }
7372  }
7373  }
7374 
7375  if( *cutoff )
7376  {
7377  SCIPfreeBufferArray(scip, &secondmaxweights);
7378  SCIPfreeBufferArray(scip, &cliquestartposs);
7379  SCIPfreeBufferArray(scip, &myweights);
7380  SCIPfreeBufferArray(scip, &myvars);
7381 
7382  return SCIP_OKAY;
7383  }
7384  }
7385 
7386  /* check, if weights of fixed variables already exceed knapsack capacity */
7387  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7388  {
7389  SCIPdebugMessage(" -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT ", minimum weight sum: %" SCIP_LONGINT_FORMAT " \n",
7390  consdata->onesweightsum, consdata->capacity, minweightsum);
7391 
7392  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7393  *cutoff = TRUE;
7394 
7395  /* analyze the cutoff if conflict analysis is applicable */
7397  {
7398  /* start conflict analysis with the fixed-to-one variables, add only as many as need to exceed the capacity */
7399  SCIP_Longint weight;
7400 
7401  weight = minweightsum;
7402 
7404  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7405  {
7406  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7407  {
7408  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7409  weight += consdata->weights[i];
7410  }
7411  }
7412 
7413  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7414  }
7415 
7416  if( usenegatedclique && nvars > 0 )
7417  {
7418  SCIPfreeBufferArray(scip, &secondmaxweights);
7419  SCIPfreeBufferArray(scip, &cliquestartposs);
7420  SCIPfreeBufferArray(scip, &myweights);
7421  SCIPfreeBufferArray(scip, &myvars);
7422  }
7423  return SCIP_OKAY;
7424  }
7425 
7426  assert(consdata->negcliquepartitioned || minweightsum == 0);
7427 
7428  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7429  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this cliques
7430  * exceeds the capacity the variables have to be fixed to zero (these variables should only be variables in the
7431  * cliques which have maxweights)
7432  */
7433  if( usenegatedclique && nvars > 0 )
7434  {
7435  SCIP_VAR* var;
7436 
7437  assert(nnegcliques == consdata->nnegcliques);
7438  assert(myvars != NULL);
7439  assert(myweights != NULL);
7440  assert(secondmaxweights != NULL);
7441  assert(cliquestartposs != NULL);
7442 
7443  for( c = 0; c < nnegcliques; ++c )
7444  {
7445  if( consdata->onesweightsum + minweightsum + myweights[cliquestartposs[c]] - secondmaxweights[c] > consdata->capacity )
7446  {
7447  assert(myweights[cliquestartposs[c]] >= secondmaxweights[c]);
7448 
7449  var = myvars[cliquestartposs[c]];
7450  if( SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5 )
7451  {
7452  SCIPdebugMessage(" -> fixing variable <%s> to 0\n", SCIPvarGetName(var));
7453  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7454  SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7455  assert(!infeasible);
7456  assert(tightened);
7457  (*nfixedvars)++;
7458  }
7459  }
7460  }
7461 
7462  SCIPfreeBufferArray(scip, &secondmaxweights);
7463  SCIPfreeBufferArray(scip, &cliquestartposs);
7464  SCIPfreeBufferArray(scip, &myweights);
7465  SCIPfreeBufferArray(scip, &myvars);
7466  }
7467  }
7468  while( FALSE );
7469 
7470  /* check, if weights of fixed variables already exceed knapsack capacity, this can only happen if 'usenegatedclique'
7471  * is FALSE, or 'nnegcliques == nvars', otherwise the stronger condition above should have led to a cutoff
7472  */
7473  if( consdata->capacity < consdata->onesweightsum )
7474  {
7475  SCIPdebugMessage(" -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7476  consdata->onesweightsum, consdata->capacity);
7477 
7478  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7479  *cutoff = TRUE;
7480 
7481  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7483  {
7484  /* start conflict analysis with the fixed-to-one variables, add only as many as need to exceed the capacity */
7485  SCIP_Longint weight;
7486 
7487  weight = 0;
7488 
7490  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7491  {
7492  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7493  {
7494  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7495  weight += consdata->weights[i];
7496  }
7497  }
7498 
7499  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7500  }
7501 
7502  return SCIP_OKAY;
7503  }
7504 
7505  /* fix all variables to zero, that don't fit into the knapsack anymore */
7506  for( i = 0; i < nvars; ++i )
7507  {
7508  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7509  * to zero
7510  */
7511  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7512  {
7513  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7514  {
7515  if( consdata->onesweightsum + consdata->weights[i] > consdata->capacity )
7516  {
7517  SCIPdebugMessage(" -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7518  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7519  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7520  assert(!infeasible);
7521  assert(tightened);
7522  (*nfixedvars)++;
7523  zerosweightsum += consdata->weights[i];
7524  }
7525  }
7526  else
7527  zerosweightsum += consdata->weights[i];
7528  }
7529  }
7530 
7531  assert(consdata->onesweightsum + zerosweightsum <= consdata->weightsum);
7532 
7533  /* if the remaining (potentially unfixed) variables would fit all into the knapsack, the knapsack is now redundant */
7534  if( !SCIPconsIsModifiable(cons) && consdata->weightsum - zerosweightsum <= consdata->capacity )
7535  {
7536  SCIPdebugMessage(" -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", zerosweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7537  SCIPconsGetName(cons), consdata->weightsum, zerosweightsum, consdata->capacity);
7538  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7539  *redundant = TRUE;
7540  }
7541 
7542  /* mark the constraint propagated */
7543  consdata->propagated = TRUE;
7544  return SCIP_OKAY;
7545 }
7546 
7547 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7548  * containing all negated variables of this knapsack constraint
7549  */
7550 static
7552  SCIP* scip, /**< SCIP data structure */
7553  SCIP_CONS* cons, /**< knapsack constraint */
7554  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7555  int* naddconss /**< pointer to count number of added constraints */
7556  )
7557 {
7558  SCIP_CONS* newcons;
7559  SCIP_CONSDATA* consdata;
7560 
7561  assert(scip != NULL);
7562  assert(cons != NULL);
7563  assert(ndelconss != NULL);
7564  assert(naddconss != NULL);
7565 
7566  consdata = SCIPconsGetData(cons);
7567  assert(consdata != NULL);
7568  assert(consdata->nvars > 1);
7569 
7570  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7571  if( consdata->nvars == 2 )
7572  {
7573  SCIPdebugMessage("upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7574 
7575  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7579  SCIPconsIsStickingAtNode(cons)) );
7580  }
7581  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7582  * containing all negated variables of the knapsack
7583  */
7584  else
7585  {
7586  SCIP_VAR** consvars;
7587 
7588  SCIPdebugMessage("upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7589 
7590  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7591  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7592 
7593  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7597  SCIPconsIsStickingAtNode(cons)) );
7598 
7599  SCIPfreeBufferArray(scip, &consvars);
7600  }
7601 
7602  SCIP_CALL( SCIPaddCons(scip, newcons) );
7603  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7604  ++(*naddconss);
7605 
7606  SCIP_CALL( SCIPdelCons(scip, cons) );
7607  ++(*ndelconss);
7608 
7609  return SCIP_OKAY;
7610 }
7611 
7612 /** delete redundant variables
7613  *
7614  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7615  *
7616  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7617  * => x4, x5 always fits into the knapsack, so we can delete them
7618  *
7619  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7620  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7621  */
7622 static
7624  SCIP* scip, /**< SCIP data structure */
7625  SCIP_CONS* cons, /**< knapsack constraint */
7626  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7627  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7628  * first which did not fit */
7629  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7630  int* nchgsides, /**< pointer to store the amount of changed sides */
7631  int* naddconss /**< pointer to count number of added constraints */
7632  )
7633 {
7634  SCIP_CONSHDLRDATA* conshdlrdata;
7635  SCIP_CONSDATA* consdata;
7636  SCIP_VAR** vars;
7637  SCIP_Longint* weights;
7638  SCIP_Longint capacity;
7639  SCIP_Longint gcd;
7640  int nvars;
7641  int w;
7642 
7643  assert(scip != NULL);
7644  assert(cons != NULL);
7645  assert(nchgcoefs != NULL);
7646  assert(nchgsides != NULL);
7647  assert(naddconss != NULL);
7648 
7649  consdata = SCIPconsGetData(cons);
7650  assert(consdata != NULL);
7651  assert(0 < frontsum && frontsum < consdata->weightsum);
7652  assert(0 < splitpos && splitpos < consdata->nvars);
7653 
7654  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7655  assert(conshdlrdata != NULL);
7656 
7657  vars = consdata->vars;
7658  weights = consdata->weights;
7659  nvars = consdata->nvars;
7660  capacity = consdata->capacity;
7661 
7662  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7663  * weight must not be sorted by their index
7664  */
7665 #ifndef NDEBUG
7666  for( w = nvars - 1; w > 0; --w )
7667  assert(weights[w] <= weights[w-1]);
7668 #endif
7669 
7670  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7671  if( consdata->nvars - 1 == splitpos )
7672  return SCIP_OKAY;
7673 
7674  assert(frontsum + weights[splitpos] > capacity);
7675 
7676  /* detect redundant variables */
7677  if( consdata->weightsum - weights[splitpos] <= capacity )
7678  {
7679  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7680  * fit
7681  */
7682  SCIPdebugMessage("Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7683 
7684  /* delete items and update capacity */
7685  for( w = nvars - 1; w > splitpos; --w )
7686  {
7687  consdata->capacity -= weights[w];
7688  SCIP_CALL( delCoefPos(scip, cons, w) );
7689  }
7690  assert(w == splitpos);
7691 
7692  ++(*nchgsides);
7693  *nchgcoefs += (nvars - splitpos);
7694 
7695  /* division by greatest common divisor */
7696  gcd = weights[w];
7697  for( ; w >= 0 && gcd > 1; --w )
7698  {
7699  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7700  }
7701 
7702  /* normalize if possible */
7703  if( gcd > 1 )
7704  {
7705  for( w = splitpos; w >= 0; --w )
7706  {
7707  consdataChgWeight(consdata, w, weights[w]/gcd);
7708  }
7709  (*nchgcoefs) += nvars;
7710 
7711  consdata->capacity /= gcd;
7712  ++(*nchgsides);
7713  }
7714 
7715  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7716  * weight must not be sorted by their index
7717  */
7718 #ifndef NDEBUG
7719  for( w = consdata->nvars - 1; w > 0; --w )
7720  assert(weights[w] <= weights[w - 1]);
7721 #endif
7722  }
7723  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7724  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7725  * splitpos and needs to fit into the knapsack
7726  */
7727  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7728  {
7729  int* clqpart;
7730  int nclq;
7731  int len;
7732 
7733  len = nvars - (splitpos + 1);
7734  /* allocate temporary memory */
7735  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7736 
7737  /* calculate clique partition */
7738  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7739 
7740  /* check if we found at least one clique */
7741  if( nclq < len )
7742  {
7743  SCIP_Longint maxactduetoclq;
7744  int cliquenum;
7745 
7746  maxactduetoclq = 0;
7747  cliquenum = 0;
7748 
7749  /* calculate maximum activity due to cliques */
7750  for( w = 0; w < len; ++w )
7751  {
7752  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7753  if( clqpart[w] == cliquenum )
7754  {
7755  maxactduetoclq += weights[w + splitpos + 1];
7756  ++cliquenum;
7757  }
7758  }
7759 
7760  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
7761  * so delete them and create for all clique the corresponding clique constraints and update the capacity
7762  */
7763  if( frontsum + maxactduetoclq <= capacity )
7764  {
7765  SCIP_VAR** clqvars;
7766  int nclqvars;
7767  int c;
7768 
7769  assert(maxactduetoclq < weights[splitpos]);
7770 
7771  SCIPdebugMessage("Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
7772 
7773  /* allocate temporary memory */
7774  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
7775 
7776  for( c = 0; c < nclq; ++c )
7777  {
7778  nclqvars = 0;
7779  for( w = 0; w < len; ++w )
7780  {
7781  if( clqpart[w] == c )
7782  {
7783  clqvars[nclqvars] = vars[w + splitpos + 1];
7784  ++nclqvars;
7785  }
7786  }
7787 
7788  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
7789  if( nclqvars > 1 )
7790  {
7791  SCIP_CONS* cliquecons;
7792  char name[SCIP_MAXSTRLEN];
7793 
7794  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
7795  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
7799  SCIPconsIsStickingAtNode(cons)) );
7800  SCIPdebugMessage(" -> adding clique constraint: ");
7801  SCIPdebugPrintCons(scip, cliquecons, NULL);
7802  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
7803  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
7804  ++(*naddconss);
7805  }
7806  }
7807 
7808  /* delete items and update capacity */
7809  for( w = nvars - 1; w > splitpos; --w )
7810  {
7811  SCIP_CALL( delCoefPos(scip, cons, w) );
7812  ++(*nchgcoefs);
7813  }
7814  consdata->capacity -= maxactduetoclq;
7815  assert(frontsum <= consdata->capacity);
7816  ++(*nchgsides);
7817 
7818  assert(w == splitpos);
7819 
7820  /* renew weights pointer */
7821  weights = consdata->weights;
7822 
7823  /* division by greatest common divisor */
7824  gcd = weights[w];
7825  for( ; w >= 0 && gcd > 1; --w )
7826  {
7827  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7828  }
7829 
7830  /* normalize if possible */
7831  if( gcd > 1 )
7832  {
7833  for( w = splitpos; w >= 0; --w )
7834  {
7835  consdataChgWeight(consdata, w, weights[w]/gcd);
7836  }
7837  (*nchgcoefs) += nvars;
7838 
7839  consdata->capacity /= gcd;
7840  ++(*nchgsides);
7841  }
7842 
7843  /* free temporary memory */
7844  SCIPfreeBufferArray(scip, &clqvars);
7845 
7846  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7847  * weight must not be sorted by their index
7848  */
7849 #ifndef NDEBUG
7850  for( w = consdata->nvars - 1; w > 0; --w )
7851  assert(weights[w] <= weights[w - 1]);
7852 #endif
7853  }
7854  }
7855 
7856  /* free temporary memory */
7857  SCIPfreeBufferArray(scip, &clqpart);
7858  }
7859 
7860  return SCIP_OKAY;
7861 }
7862 
7863 /* detect redundant variables which always fits into the knapsack
7864  *
7865  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7866  *
7867  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7868  * => x4, x5 always fits into the knapsack, so we can delete them
7869  *
7870  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7871  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7872  */
7873 static
7875  SCIP* scip, /**< SCIP data structure */
7876  SCIP_CONS* cons, /**< knapsack constraint */
7877  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7878  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7879  int* nchgsides, /**< pointer to store the amount of changed sides */
7880  int* naddconss /**< pointer to count number of added constraints */
7881  )
7882 {
7883  SCIP_CONSDATA* consdata;
7884  SCIP_VAR** vars;
7885  SCIP_Longint* weights;
7886  SCIP_Longint capacity;
7887  SCIP_Longint sum;
7888  int noldchgcoefs;
7889  int nvars;
7890  int v;
7891  int w;
7892 
7893  assert(scip != NULL);
7894  assert(cons != NULL);
7895  assert(ndelconss != NULL);
7896  assert(nchgcoefs != NULL);
7897  assert(nchgsides != NULL);
7898  assert(naddconss != NULL);
7899 
7900  consdata = SCIPconsGetData(cons);
7901  assert(consdata != NULL);
7902  assert(consdata->nvars >= 2);
7903  assert(consdata->weightsum > consdata->capacity);
7904 
7905  noldchgcoefs = *nchgcoefs;
7906  vars = consdata->vars;
7907  weights = consdata->weights;
7908  nvars = consdata->nvars;
7909  capacity = consdata->capacity;
7910  sum = 0;
7911 
7912  /* search for maximal fitting items */
7913  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
7914  sum += weights[v];
7915 
7916  assert(v < nvars);
7917 
7918  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
7919  if( v == nvars - 1 )
7920  {
7921  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
7922  assert(SCIPconsIsDeleted(cons));
7923 
7924  return SCIP_OKAY;
7925  }
7926 
7927  if( v < nvars - 1 )
7928  {
7929  /* try to delete variables */
7930  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
7931  assert(consdata->nvars > 1);
7932 
7933  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
7934  if( v == consdata->nvars - 1 )
7935  {
7936  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
7937  assert(SCIPconsIsDeleted(cons));
7938  }
7939 
7940  return SCIP_OKAY;
7941  }
7942 
7943  /* if we already found some redundant variables, stop here */
7944  if( *nchgcoefs > noldchgcoefs )
7945  return SCIP_OKAY;
7946 
7947  assert(vars == consdata->vars);
7948  assert(weights == consdata->weights);
7949  assert(nvars == consdata->nvars);
7950  assert(capacity == consdata->capacity);
7951 
7952  /* calculate clique partition */
7953  SCIP_CALL( calcCliquepartition(scip, consdata, TRUE, FALSE) );
7954 
7955  /* check for real existing cliques */
7956  if( consdata->cliquepartition[v] < v )
7957  {
7958  SCIP_CONSHDLRDATA* conshdlrdata;
7959  SCIP_Longint sumfront;
7960  SCIP_Longint maxactduetoclqfront;
7961  int* clqpart;
7962  int cliquenum;
7963 
7964  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7965  assert(conshdlrdata != NULL);
7966 
7967  sumfront = 0;
7968  maxactduetoclqfront = 0;
7969 
7970  clqpart = consdata->cliquepartition;
7971  cliquenum = 0;
7972 
7973  /* calculate maximal activity due to cliques */
7974  for( w = 0; w < nvars; ++w )
7975  {
7976  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7977  if( clqpart[w] == cliquenum )
7978  {
7979  if( maxactduetoclqfront + weights[w] <= capacity )
7980  {
7981  maxactduetoclqfront += weights[w];
7982  ++cliquenum;
7983  }
7984  else
7985  break;
7986  }
7987  sumfront += weights[w];
7988  }
7989  assert(w >= v);
7990 
7991  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
7992  * information
7993  */
7994  if( conshdlrdata->disaggregation && w == nvars )
7995  {
7996  SCIP_VAR** clqvars;
7997  int nclqvars;
7998  int c;
7999  int ncliques;
8000 
8001  assert(maxactduetoclqfront <= capacity);
8002 
8003  SCIPdebugMessage("Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8004 
8005  ncliques = consdata->ncliques;
8006 
8007  /* allocate temporary memory */
8008  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8009 
8010  for( c = 0; c < ncliques; ++c )
8011  {
8012  nclqvars = 0;
8013  for( w = 0; w < nvars; ++w )
8014  {
8015  if( clqpart[w] == c )
8016  {
8017  clqvars[nclqvars] = vars[w];
8018  ++nclqvars;
8019  }
8020  }
8021 
8022  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8023  if( nclqvars > 1 )
8024  {
8025  SCIP_CONS* cliquecons;
8026  char name[SCIP_MAXSTRLEN];
8027 
8028  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8029  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8033  SCIPconsIsStickingAtNode(cons)) );
8034  SCIPdebugMessage(" -> adding clique constraint: ");
8035  SCIPdebugPrintCons(scip, cliquecons, NULL);
8036  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8037  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8038  ++(*naddconss);
8039  }
8040  }
8041 
8042  /* delete old constraint */
8043  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8044  ++(*ndelconss);
8045 
8046  SCIPfreeBufferArray(scip, &clqvars);
8047 
8048  return SCIP_OKAY;
8049  }
8050 
8051  if( w > v && w < nvars - 1 )
8052  {
8053  /* try to delete variables */
8054  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8055  }
8056  }
8057 
8058  return SCIP_OKAY;
8059 }
8060 
8061 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8062 static
8063 void normalizeWeights(
8064  SCIP_CONS* cons, /**< knapsack constraint */
8065  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8066  int* nchgsides /**< pointer to count number of side changes */
8067  )
8068 {
8069  SCIP_CONSDATA* consdata;
8071  int i;
8072 
8073  assert(nchgcoefs != NULL);
8074  assert(nchgsides != NULL);
8075  assert(!SCIPconsIsModifiable(cons));
8076 
8077  consdata = SCIPconsGetData(cons);
8078  assert(consdata != NULL);
8079  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8080  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8081  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8082  assert(consdata->nvars >= 1);
8083 
8084  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8085  sortItems(consdata);
8086 
8087  gcd = consdata->weights[consdata->nvars-1];
8088  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8089  {
8090  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8091  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8092 
8093  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8094  }
8095 
8096  if( gcd >= 2 )
8097  {
8098  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8099 
8100  for( i = 0; i < consdata->nvars; ++i )
8101  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8102  consdata->capacity /= gcd;
8103  (*nchgcoefs) += consdata->nvars;
8104  (*nchgsides)++;
8105 
8106  /* weight should still be sorted, because the reduction preserves this */
8107 #ifndef NDEBUG
8108  for( i = consdata->nvars - 1; i > 0; --i )
8109  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8110 #endif
8111  consdata->sorted = TRUE;
8112  }
8113 }
8114 
8115 /** dual weights tightening for knapsack constraints
8116  *
8117  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8118  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8119  * constraint
8120  *
8121  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8122  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8123  *
8124  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8125  *
8126  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8127  *
8128  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8129  *
8130  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8131  *
8132  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8133  */
8134 static
8136  SCIP* scip, /**< SCIP data structure */
8137  SCIP_CONS* cons, /**< knapsack constraint */
8138  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8139  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8140  int* nchgsides, /**< pointer to store the amount of changed sides */
8141  int* naddconss /**< pointer to count number of added constraints */
8142  )
8143 {
8144  SCIP_CONSDATA* consdata;
8145  SCIP_Longint* weights;
8146  SCIP_Longint dualcapacity;
8147  SCIP_Longint reductionsum;
8148  SCIP_Longint capacity;
8149  SCIP_Longint exceedsum;
8150  int oldnchgcoefs;
8151  int nvars;
8152  int vbig;
8153  int v;
8154  int w;
8155 #ifndef NDEBUG
8156  int oldnchgsides = *nchgsides;
8157 #endif
8158 
8159  assert(scip != NULL);
8160  assert(cons != NULL);
8161  assert(ndelconss != NULL);
8162  assert(nchgcoefs != NULL);
8163  assert(nchgsides != NULL);
8164  assert(naddconss != NULL);
8165 
8166  consdata = SCIPconsGetData(cons);
8167  assert(consdata != NULL);
8168  assert(consdata->weightsum > consdata->capacity);
8169  assert(consdata->nvars >= 2);
8170  assert(consdata->sorted);
8171 
8172  /* constraint should be merged */
8173  assert(consdata->merged);
8174 
8175  nvars = consdata->nvars;
8176  weights = consdata->weights;
8177  capacity = consdata->capacity;
8178 
8179  oldnchgcoefs = *nchgcoefs;
8180 
8181  /* case 1. */
8182  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8183  {
8184  SCIP_CONS* newcons;
8185 
8186  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8187  *
8188  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8189  */
8190  SCIPdebugMessage("upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8191 
8192  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8196  SCIPconsIsStickingAtNode(cons)) );
8197 
8198  SCIP_CALL( SCIPaddCons(scip, newcons) );
8199  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8200  ++(*naddconss);
8201 
8202  SCIP_CALL( SCIPdelCons(scip, cons) );
8203  ++(*ndelconss);
8204 
8205  return SCIP_OKAY;
8206  }
8207 
8208  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8209  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8210  {
8211  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8212  assert(SCIPconsIsDeleted(cons));
8213 
8214  return SCIP_OKAY;
8215  }
8216 
8217  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8218  /* @todo might be changed/removed when improving the coeffcients tightening */
8219  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8220  return SCIP_OKAY;
8221 
8222  /* case 2. */
8223 
8224  v = 0;
8225 
8226  /* @todo generalize the following algorithm for several parts of the knapsack
8227  *
8228  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8229  * variables each combination is a minimal cover, some examples
8230  *
8231  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8232  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8233  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8234  *
8235  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8236  *
8237  */
8238 
8239  /* determine big weights that fit only by itself */
8240  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8241  ++v;
8242 
8243  vbig = v;
8244  assert(vbig < nvars - 1);
8245  exceedsum = 0;
8246 
8247  /* determine the amount needed to exceed the capacity */
8248  while( v < nvars && exceedsum <= capacity )
8249  {
8250  exceedsum += weights[v];
8251  ++v;
8252  }
8253 
8254  /* if we exceeded the capacity we might reduce the weights */
8255  if( exceedsum > capacity )
8256  {
8257  assert(vbig > 0 || v < nvars);
8258 
8259  /* all small weights were needed to exceed the capacity */
8260  if( v == nvars )
8261  {
8262  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8263  assert(newweight > 0);
8264 
8265  /* reduce big weights */
8266  for( v = 0; v < vbig; ++v )
8267  {
8268  if( weights[v] > newweight )
8269  {
8270  consdataChgWeight(consdata, v, newweight);
8271  ++(*nchgcoefs);
8272  }
8273  }
8274 
8275  /* reduce small weights */
8276  for( ; v < nvars; ++v )
8277  {
8278  if( weights[v] > 1 )
8279  {
8280  consdataChgWeight(consdata, v, 1LL);
8281  ++(*nchgcoefs);
8282  }
8283  }
8284 
8285  consdata->capacity = newweight;
8286 
8287  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8288  * weight must not be sorted by their index
8289  */
8290 #ifndef NDEBUG
8291  for( v = nvars - 1; v > 0; --v )
8292  assert(weights[v] <= weights[v-1]);
8293 #endif
8294 
8295  return SCIP_OKAY;
8296  }
8297  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8298  * small weights
8299  */
8300  else
8301  {
8302  SCIP_Longint exceedsumback = 0;
8303  int nexceed = v - vbig;
8304 
8305  assert(nexceed > 1);
8306 
8307  /* determine weightsum of the same amount as before but of the smallest weight */
8308  for( w = nvars - 1; w >= nvars - nexceed; --w )
8309  exceedsumback += weights[w];
8310 
8311  assert(w >= 0);
8312 
8313  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8314  * combinations of all small weights
8315  */
8316  if( exceedsumback > capacity )
8317  {
8318  SCIP_Longint newweight = nexceed - 1;
8319 
8320  /* taking out the smallest element needs to fit */
8321  assert(exceedsumback - weights[nvars - 1] <= capacity);
8322 
8323  /* reduce big weights */
8324  for( v = 0; v < vbig; ++v )
8325  {
8326  if( weights[v] > newweight )
8327  {
8328  consdataChgWeight(consdata, v, newweight);
8329  ++(*nchgcoefs);
8330  }
8331  }
8332 
8333  /* reduce small weights */
8334  for( ; v < nvars; ++v )
8335  {
8336  if( weights[v] > 1 )
8337  {
8338  consdataChgWeight(consdata, v, 1LL);
8339  ++(*nchgcoefs);
8340  }
8341  }
8342 
8343  consdata->capacity = newweight;
8344 
8345  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8346  * weight must not be sorted by their index
8347  */
8348 #ifndef NDEBUG
8349  for( v = nvars - 1; v > 0; --v )
8350  assert(weights[v] <= weights[v-1]);
8351 #endif
8352  return SCIP_OKAY;
8353  }
8354  }
8355  }
8356  else
8357  {
8358  /* if the follwoing assert fails we have either a redundant constraint or a set-packing constraint, this should
8359  * not happen here
8360  */
8361  assert(vbig > 0 && vbig < nvars);
8362 
8363  /* either choose a big coefficients or all other variables
8364  *
8365  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8366  *
8367  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8368  * constraint to
8369  *
8370  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8371  */
8372 
8373  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8374  {
8375  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8376 #ifndef NDEBUG
8377  SCIP_Longint resweightsum = consdata->weightsum;
8378 
8379  for( v = 0; v < vbig; ++v )
8380  resweightsum -= weights[v];
8381 
8382  assert(exceedsum == resweightsum);
8383 #endif
8384  assert(newweight > 0);
8385 
8386  /* reduce big weights */
8387  for( v = 0; v < vbig; ++v )
8388  {
8389  if( weights[v] > newweight )
8390  {
8391  consdataChgWeight(consdata, v, newweight);
8392  ++(*nchgcoefs);
8393  }
8394  }
8395 
8396  /* reduce small weights */
8397  for( ; v < nvars; ++v )
8398  {
8399  if( weights[v] > 1 )
8400  {
8401  consdataChgWeight(consdata, v, 1LL);
8402  ++(*nchgcoefs);
8403  }
8404  }
8405 
8406  consdata->capacity = newweight;
8407 
8408  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8409  * weight must not be sorted by their index
8410  */
8411 #ifndef NDEBUG
8412  for( v = nvars - 1; v > 0; --v )
8413  assert(weights[v] <= weights[v-1]);
8414 #endif
8415  return SCIP_OKAY;
8416  }
8417  }
8418 
8419  /* case 3. */
8420 
8421  dualcapacity = consdata->weightsum - capacity;
8422  reductionsum = 0;
8423  v = 0;
8424 
8425  /* reduce big weights
8426  *
8427  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8428  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8429  * <=> x0 + x1 + x2 + x3 <= 3
8430  */
8431  while( weights[v] > dualcapacity )
8432  {
8433  reductionsum += (weights[v] - dualcapacity);
8434  consdataChgWeight(consdata, v, dualcapacity);
8435  ++v;
8436  assert(v < nvars);
8437  }
8438  (*nchgcoefs) += v;
8439 
8440  /* skip weights equal to the dualcapacity, because we cannot change them */
8441  while( v < nvars && weights[v] == dualcapacity )
8442  ++v;
8443 
8444  /* one negated variable is enough to fulfill the constraint, so we can update it to a logicor
8445  *
8446  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8447  */
8448  if( v == nvars )
8449  {
8450  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8451  assert(SCIPconsIsDeleted(cons));
8452 
8453  return SCIP_OKAY;
8454  }
8455  else if( v < nvars - 1 )
8456  {
8457  /* @todo generalize the following algorithm for more than two variables */
8458 
8459  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8460  {
8461  /* we have a dual-knapsack constraint were we either need to choose one variable out of a subset (big
8462  * coefficients) of all or two variables of the rest
8463  *
8464  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8465  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8466  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8467  *
8468  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8469  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8470  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8471  *
8472  */
8473  if( v > 0 && weights[nvars - 2] > 1 )
8474  {
8475  int ncoefchg = 0;
8476 
8477  /* reduce all bigger weights */
8478  for( w = 0; w < v; ++w )
8479  {
8480  if( weights[w] > 2 )
8481  {
8482  consdataChgWeight(consdata, w, 2LL);
8483  ++ncoefchg;
8484  }
8485  else
8486  {
8487  assert(weights[0] == 2);
8488  assert(weights[v - 1] == 2);
8489  break;
8490  }
8491  }
8492 
8493  /* reduce all smaller weights */
8494  for( w = v; w < nvars; ++w )
8495  {
8496  if( weights[w] > 1 )
8497  {
8498  consdataChgWeight(consdata, w, 1LL);
8499  ++ncoefchg;
8500  }
8501  }
8502  assert(ncoefchg > 0);
8503 
8504  (*nchgcoefs) += ncoefchg;
8505 
8506  /* correct the capacity */
8507  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8508  assert(consdata->capacity > 0);
8509  assert(weights[0] <= consdata->capacity);
8510  assert(consdata->weightsum > consdata->capacity);
8511  /* reset the reductionsum */
8512  reductionsum = 0;
8513  }
8514  else if( v == 0 )
8515  {
8516  assert(weights[nvars - 2] == 1);
8517  }
8518  }
8519  else
8520  {
8521  SCIP_Longint minweight = weights[nvars - 1];
8522  SCIP_Longint newweight = dualcapacity - minweight;
8523  SCIP_Longint restsumweights = 0;
8524  SCIP_Longint sumcoef;
8525  SCIP_Bool sumcoefcase = FALSE;
8526  int startv = v;
8527  int end;
8528  int k;
8529 
8530  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8531 
8532  /* reduce big weights of pairs that exceed the dualcapacity
8533  *
8534  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8535  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8536  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8537  */
8538  while( weights[v] > newweight )
8539  {
8540  reductionsum += (weights[v] - newweight);
8541  consdataChgWeight(consdata, v, newweight);
8542  ++v;
8543  assert(v < nvars);
8544  }
8545  (*nchgcoefs) += (v - startv);
8546 
8547  /* skip equal weights */
8548  while( weights[v] == newweight )
8549  ++v;
8550 
8551  if( v > 0 )
8552  {
8553  for( w = v; w < nvars; ++w )
8554  restsumweights += weights[w];
8555  }
8556  else
8557  restsumweights = consdata->weightsum;
8558 
8559  if( restsumweights < dualcapacity )
8560  {
8561  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8562  *
8563  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8564  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8565  */
8566  if( startv == v )
8567  {
8568  /* remove redundant variables */
8569  for( w = nvars - 1; w >= v; --w )
8570  {
8571  SCIP_CALL( delCoefPos(scip, cons, v) );
8572  ++(*nchgcoefs);
8573  }
8574 
8575 #ifndef NDEBUG
8576  /* each coefficients should exceed the dualcapacity by itself */
8577  for( ; w >= 0; --w )
8578  assert(weights[w] == dualcapacity);
8579 #endif
8580  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8581  * upgrade this constraint
8582  */
8583  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8584  assert(SCIPconsIsDeleted(cons));
8585 
8586  return SCIP_OKAY;
8587  }
8588 
8589  /* special case where we have three different coefficient types
8590  *
8591  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8592  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8593  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8594  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8595  */
8596  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8597  {
8598  SCIP_Longint newcap;
8599 
8600  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8601  for( w = nvars - 1; w >= v; --w )
8602  {
8603  if( weights[w] > 1 )
8604  {
8605  consdataChgWeight(consdata, w, 1LL);
8606  ++(*nchgcoefs);
8607  }
8608  }
8609 
8610  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8611  * dualcapacity
8612  */
8613  newweight = (SCIP_Longint)nvars - v;
8614  assert(newweight > 1);
8615  for( ; w >= startv; --w )
8616  {
8617  if( weights[w] > newweight )
8618  {
8619  consdataChgWeight(consdata, w, newweight);
8620  ++(*nchgcoefs);
8621  }
8622  else
8623  assert(weights[w] == newweight);
8624  }
8625 
8626  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8627  ++newweight;
8628  assert(newweight > 2);
8629  for( ; w >= 0; --w )
8630  {
8631  if( weights[w] > newweight )
8632  {
8633  consdataChgWeight(consdata, w, newweight);
8634  ++(*nchgcoefs);
8635  }
8636  else
8637  assert(weights[w] == newweight);
8638  }
8639 
8640  /* update the capacity */
8641  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8642  if( consdata->capacity > newcap )
8643  {
8644  consdata->capacity = newcap;
8645  ++(*nchgsides);
8646  }
8647  else
8648  assert(consdata->capacity == newcap);
8649  }
8650  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8651 
8652  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8653  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8654 
8655  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8656  * weight must not be sorted by their index
8657  */
8658 #ifndef NDEBUG
8659  for( w = nvars - 1; w > 0; --w )
8660  assert(weights[w] <= weights[w - 1]);
8661 #endif
8662  return SCIP_OKAY;
8663  }
8664 
8665  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8666  end = nvars - 2;
8667  while( end >= 0 && weights[end] == weights[end + 1] )
8668  {
8669  assert(end >= v);
8670  --end;
8671  }
8672 
8673  if( v >= end )
8674  goto TERMINATE;
8675 
8676  end = nvars - 2;
8677 
8678  /* can we stop early, another special reduction case might exist */
8679  if( 2 * weights[end] > dualcapacity )
8680  {
8681  restsumweights = 0;
8682 
8683  /* determine capacity of the small items */
8684  for( w = end + 1; w < nvars; ++w )
8685  restsumweights += weights[w];
8686 
8687  if( restsumweights * 2 <= dualcapacity )
8688  {
8689  /* check for further posssible reductions in the middle */
8690  while( v < end && restsumweights + weights[v] >= dualcapacity )
8691  ++v;
8692 
8693  if( v >= end )
8694  goto TERMINATE;
8695 
8696  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8697  if( (dualcapacity & 1) == 0 )
8698  {
8699  newweight = dualcapacity / 2;
8700  startv = v;
8701 
8702  /* set all middle coefficients */
8703  for( ; v <= end; ++v )
8704  {
8705  if( weights[v] > newweight )
8706  {
8707  reductionsum += (weights[v] - newweight);
8708  consdataChgWeight(consdata, v, newweight);
8709  ++(*nchgcoefs);
8710  }
8711  }
8712  }
8713  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8714  * other coefficients by 2
8715  */
8716  else
8717  {
8718  /* correct the reductionsum */
8719  reductionsum *= 2;
8720 
8721  /* multiply big coefficients by 2 */
8722  for( w = 0; w < v; ++w )
8723  {
8724  consdataChgWeight(consdata, w, weights[w] * 2);
8725  }
8726 
8727  newweight = dualcapacity;
8728  /* set all middle coefficients */
8729  for( ; v <= end; ++v )
8730  {
8731  reductionsum += (2 * weights[v] - newweight);
8732  consdataChgWeight(consdata, v, newweight);
8733  }
8734 
8735  /* multiply small coefficients by 2 */
8736  for( w = end + 1; w < nvars; ++w )
8737  {
8738  consdataChgWeight(consdata, w, weights[w] * 2);
8739  }
8740  (*nchgcoefs) += nvars;
8741 
8742  dualcapacity *= 2;
8743  consdata->capacity *= 2;
8744  ++(*nchgsides);
8745  }
8746  }
8747 
8748  goto TERMINATE;
8749  }
8750 
8751  /* further reductions using the next possible coefficient sum
8752  *
8753  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
8754  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
8755  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
8756  */
8757  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
8758  for( k = 0; k < 4; ++k )
8759  {
8760  /* determine next minimal coefficient sum */
8761  switch( k )
8762  {
8763  case 0:
8764  sumcoef = weights[nvars - 1] + weights[nvars - 2];
8765  break;
8766  case 1:
8767  assert(nvars >= 3);
8768  sumcoef = weights[nvars - 1] + weights[nvars - 3];
8769  break;
8770  case 2:
8771  assert(nvars >= 4);
8772  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
8773  {
8774  sumcoefcase = TRUE;
8775  sumcoef = weights[nvars - 1] + weights[nvars - 4];
8776  }
8777  else
8778  {
8779  sumcoefcase = FALSE;
8780  sumcoef = weights[nvars - 2] + weights[nvars - 3];
8781  }
8782  break;
8783  case 3:
8784  assert(nvars >= 5);
8785  if( sumcoefcase )
8786  {
8787  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
8788  }
8789  else
8790  {
8791  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
8792  }
8793  break;
8794  default:
8795  return SCIP_ERROR;
8796  }
8797 
8798  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
8799  minweight = weights[end];
8800  while( minweight <= sumcoef )
8801  {
8802  newweight = dualcapacity - minweight;
8803  startv = v;
8804  assert(v < nvars);
8805 
8806  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
8807  /* shrink big coefficients */
8808  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
8809  {
8810  reductionsum += (weights[v] - newweight);
8811  consdataChgWeight(consdata, v, newweight);
8812  ++v;
8813  assert(v < nvars);
8814  }
8815  (*nchgcoefs) += (v - startv);
8816 
8817  /* skip unchangable weights */
8818  while( weights[v] + minweight == dualcapacity )
8819  {
8820  assert(v < nvars);
8821  ++v;
8822  }
8823 
8824  --end;
8825  /* skip same end weights */
8826  while( end >= 0 && weights[end] == weights[end + 1] )
8827  --end;
8828 
8829  if( v >= end )
8830  goto TERMINATE;
8831 
8832  minweight = weights[end];
8833  }
8834 
8835  if( v >= end )
8836  goto TERMINATE;
8837 
8838  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
8839  if( sumcoef < minweight )
8840  {
8841  minweight = sumcoef;
8842  newweight = dualcapacity - minweight;
8843  startv = v;
8844  assert(v < nvars);
8845 
8846  /* shrink big coefficients */
8847  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
8848  {
8849  reductionsum += (weights[v] - newweight);
8850  consdataChgWeight(consdata, v, newweight);
8851  ++v;
8852  assert(v < nvars);
8853  }
8854  (*nchgcoefs) += (v - startv);
8855 
8856  /* skip unchangable weights */
8857  while( weights[v] + minweight == dualcapacity )
8858  {
8859  assert(v < nvars);
8860  ++v;
8861  }
8862  }
8863 
8864  if( v >= end )
8865  goto TERMINATE;
8866 
8867  /* can we stop early, another special reduction case might exist */
8868  if( 2 * weights[end] > dualcapacity )
8869  {
8870  restsumweights = 0;
8871 
8872  /* determine capacity of the small items */
8873  for( w = end + 1; w < nvars; ++w )
8874  restsumweights += weights[w];
8875 
8876  if( restsumweights * 2 <= dualcapacity )
8877  {
8878  /* check for further posssible reductions in the middle */
8879  while( v < end && restsumweights + weights[v] >= dualcapacity )
8880  ++v;
8881 
8882  if( v >= end )
8883  goto TERMINATE;
8884 
8885  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8886  if( (dualcapacity & 1) == 0 )
8887  {
8888  newweight = dualcapacity / 2;
8889  startv = v;
8890 
8891  /* set all middle coefficients */
8892  for( ; v <= end; ++v )
8893  {
8894  if( weights[v] > newweight )
8895  {
8896  reductionsum += (weights[v] - newweight);
8897  consdataChgWeight(consdata, v, newweight);
8898  ++(*nchgcoefs);
8899  }
8900  }
8901  }
8902  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8903  * other coefficients by 2
8904  */
8905  else
8906  {
8907  /* correct the reductionsum */
8908  reductionsum *= 2;
8909 
8910  /* multiply big coefficients by 2 */
8911  for( w = 0; w < v; ++w )
8912  {
8913  consdataChgWeight(consdata, w, weights[w] * 2);
8914  }
8915 
8916  newweight = dualcapacity;
8917  /* set all middle coefficients */
8918  for( ; v <= end; ++v )
8919  {
8920  reductionsum += (2 * weights[v] - newweight);
8921  consdataChgWeight(consdata, v, newweight);
8922  }
8923 
8924  /* multiply small coefficients by 2 */
8925  for( w = end + 1; w < nvars; ++w )
8926  {
8927  consdataChgWeight(consdata, w, weights[w] * 2);
8928  }
8929  (*nchgcoefs) += nvars;
8930 
8931  dualcapacity *= 2;
8932  consdata->capacity *= 2;
8933  ++(*nchgsides);
8934  }
8935  }
8936 
8937  goto TERMINATE;
8938  }
8939 
8940  /* cannot tighten any further */
8941  if( 2 * sumcoef > dualcapacity )
8942  goto TERMINATE;
8943  }
8944  }
8945  }
8946 
8947 
8948  TERMINATE:
8949  /* correct capacity */
8950  if( reductionsum > 0 )
8951  {
8952  assert(v > 0);
8953 
8954  consdata->capacity -= reductionsum;
8955  ++(*nchgsides);
8956 
8957  assert(consdata->weightsum - dualcapacity == consdata->capacity);
8958  }
8959  assert(weights[0] <= consdata->capacity);
8960 
8961  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8962  * weight must not be sorted by their index
8963  */
8964 #ifndef NDEBUG
8965  for( w = nvars - 1; w > 0; --w )
8966  assert(weights[w] <= weights[w - 1]);
8967 #endif
8968 
8969  if( oldnchgcoefs < *nchgcoefs )
8970  {
8971  assert(!SCIPconsIsDeleted(cons));
8972 
8973  /* it might be that we can divide the weights by their greatest common divisor */
8974  normalizeWeights(cons, nchgcoefs, nchgsides);
8975  }
8976  else
8977  {
8978  assert(oldnchgcoefs == *nchgcoefs);
8979  assert(oldnchgsides == *nchgsides);
8980  }
8981 
8982  return SCIP_OKAY;
8983 }
8984 
8985 
8986 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
8987 static
8989  SCIP* scip, /**< SCIP data structure */
8990  SCIP_CONS* cons, /**< knapsack constraint */
8991  int* nfixedvars, /**< pointer to store the amount of fixed variables */
8992  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8993  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
8994  )
8996  SCIP_VAR** vars;
8997  SCIP_CONSDATA* consdata;
8998  SCIP_Longint* weights;
8999  SCIP_Longint capacity;
9000  SCIP_Bool infeasible;
9001  SCIP_Bool fixed;
9002  int nvars;
9003  int v;
9004 
9005  assert(scip != NULL);
9006  assert(cons != NULL);
9007  assert(nfixedvars != NULL);
9008  assert(ndelconss != NULL);
9009  assert(nchgcoefs != NULL);
9010 
9011  consdata = SCIPconsGetData(cons);
9012  assert(consdata != NULL);
9013 
9014  nvars = consdata->nvars;
9015 
9016  /* no variables left, then delete constraint */
9017  if( nvars == 0 )
9018  {
9019  assert(consdata->capacity >= 0);
9020 
9021  SCIP_CALL( SCIPdelCons(scip, cons) );
9022  ++(*ndelconss);
9023 
9024  return SCIP_OKAY;
9025  }
9026 
9027  /* sort items */
9028  sortItems(consdata);
9029 
9030  vars = consdata->vars;
9031  weights = consdata->weights;
9032  capacity = consdata->capacity;
9033  v = 0;
9034 
9035  /* check for weights bigger than the capacity */
9036  while( weights[v] > capacity )
9037  {
9038  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9039  assert(!infeasible);
9040 
9041  if( fixed )
9042  ++(*nfixedvars);
9043 
9044  ++v;
9045  }
9046 
9047  /* if we fixed at least one variable we need to delete them from the constraint */
9048  if( v > 0 )
9049  {
9050  if( v == nvars )
9051  {
9052  SCIP_CALL( SCIPdelCons(scip, cons) );
9053  ++(*ndelconss);
9054 
9055  return SCIP_OKAY;
9056  }
9057 
9058  /* delete all position from back to front */
9059  for( --v; v >= 0; --v )
9060  {
9061  SCIP_CALL( delCoefPos(scip, cons, v) );
9062  ++(*nchgcoefs);
9063  }
9064 
9065  /* sort items again because of deletion */
9066  sortItems(consdata);
9067  assert(vars == consdata->vars);
9068  assert(weights == consdata->weights);
9069  }
9070  assert(consdata->sorted);
9071  assert(weights[0] <= capacity);
9072 
9073  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9074  {
9075  SCIP_CALL( SCIPdelCons(scip, cons) );
9076  ++(*ndelconss);
9077  }
9078 
9079  return SCIP_OKAY;
9080 }
9081 
9082 
9083 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9084  *
9085  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9086  *
9087  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9088  *
9089  * the above constraint can be changed to
9090  *
9091  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9092  *
9093  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delte them, e.g.
9094  *
9095  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9096  *
9097  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9098  * constraint further, e.g.
9099  *
9100  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9101  * => 2x1 + x2 + x3 + x4 <= 2
9102  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9103  */
9104 static
9106  SCIP* scip, /**< SCIP data structure */
9107  SCIP_CONS* cons, /**< knapsack constraint */
9108  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9109  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9110  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9111  int* nchgsides, /**< pointer to store the amount of changed sides */
9112  int* naddconss, /**< pointer to count number of added constraints */
9113  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9114  )
9115 {
9116  SCIP_VAR** vars;
9117  SCIP_CONSDATA* consdata;
9118  SCIP_Longint* weights;
9119  SCIP_Longint restweight;
9120  SCIP_Longint newweight;
9121  SCIP_Longint weight;
9122  SCIP_Longint oldgcd;
9123  SCIP_Longint rest;
9124  SCIP_Longint gcd;
9125  int oldnchgcoefs;
9126  int oldnchgsides;
9127  int candpos;
9128  int candpos2;
9129  int offsetv;
9130  int nvars;
9131  int v;
9132 
9133  assert(scip != NULL);
9134  assert(cons != NULL);
9135  assert(nfixedvars != NULL);
9136  assert(ndelconss != NULL);
9137  assert(nchgcoefs != NULL);
9138  assert(nchgsides != NULL);
9139  assert(naddconss != NULL);
9140  assert(cutoff != NULL);
9141  assert(!SCIPconsIsModifiable(cons));
9142 
9143  consdata = SCIPconsGetData(cons);
9144  assert( consdata != NULL );
9145 
9146  *cutoff = FALSE;
9147 
9148  /* remove double enties and also combinations of active and negated variables */
9149  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9150  assert(consdata->merged);
9151  if( *cutoff )
9152  return SCIP_OKAY;
9153 
9154  assert(consdata->capacity >= 0);
9155 
9156  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9157  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9158 
9159  if( SCIPconsIsDeleted(cons) )
9160  return SCIP_OKAY;
9161 
9162  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9163  {
9164  /* 1. dual weights tightening */
9165  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9166 
9167  if( SCIPconsIsDeleted(cons) )
9168  return SCIP_OKAY;
9169  /* 2. delete redundant variables */
9170  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9171 
9172  if( SCIPconsIsDeleted(cons) )
9173  return SCIP_OKAY;
9174  }
9175 
9176  vars = consdata->vars;
9177  weights = consdata->weights;
9178  nvars = consdata->nvars;
9179 
9180 #ifndef NDEBUG
9181  /* constraint might not be sorted, but the weights are already sorted */
9182  for( v = nvars - 1; v > 0; --v )
9183  assert(weights[v] <= weights[v-1]);
9184 #endif
9185 
9186  /* determine greatest common divisor */
9187  gcd = weights[nvars - 1];
9188  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9189  {
9190  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9191  }
9192 
9193  /* divide the constraint by their greatest common divisor */
9194  if( gcd >= 2 )
9195  {
9196  for( v = nvars - 1; v >= 0; --v )
9197  {
9198  consdataChgWeight(consdata, v, weights[v]/gcd);
9199  }
9200  (*nchgcoefs) += nvars;
9201 
9202  consdata->capacity /= gcd;
9203  (*nchgsides)++;
9204  }
9205  assert(consdata->nvars == nvars);
9206 
9207  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9208  * must not be sorted by their index
9209  */
9210 #ifndef NDEBUG
9211  for( v = nvars - 1; v > 0; --v )
9212  assert(weights[v] <= weights[v-1]);
9213 #endif
9214 
9215  /* 3. start gcd procedure for all variables */
9216  do
9217  {
9218  oldnchgcoefs = *nchgcoefs;
9219  oldnchgsides = *nchgsides;
9220 
9221  vars = consdata->vars;
9222  weights = consdata->weights;
9223  nvars = consdata->nvars;
9224 
9225  /* stop if we have two coefficients which are one in absolute value */
9226  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9227  return SCIP_OKAY;
9228 
9229  v = 0;
9230  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9231  * gcd
9232  */
9233  while( weights[v] == consdata->capacity )
9234  {
9235  ++v;
9236  assert(v < nvars);
9237  }
9238 
9239  /* all but one variable are as big as the capacity, this is handled elsewhere */
9240  if( v == nvars - 1 )
9241  return SCIP_OKAY;
9242 
9243  offsetv = v;
9244 
9245  gcd = -1;
9246  candpos = -1;
9247  candpos2 = -1;
9248 
9249  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9250  * change the coefficient
9251  */
9252  for( v = nvars - 1; v >= offsetv; --v )
9253  {
9254  weight = weights[v];
9255  assert(weight >= 1);
9256 
9257  oldgcd = gcd;
9258 
9259  if( gcd == -1 )
9260  {
9261  gcd = weights[v];
9262  assert(gcd >= 1);
9263  }
9264  else
9265  {
9266  /* calculate greatest common divisor for all variables */
9267  gcd = SCIPcalcGreComDiv(gcd, weight);
9268  }
9269 
9270  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9271  * can terminate
9272  */
9273  if( gcd == 1 )
9274  {
9275  /* found candidate */
9276  if( candpos == -1 )
9277  {
9278  gcd = oldgcd;
9279  candpos = v;
9280 
9281  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9282  if( v == nvars - 2 )
9283  candpos2 = v + 1;
9284  }
9285  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9286  else
9287  {
9288  if( candpos == v + 1 && candpos2 == v + 2 )
9289  {
9290  assert(candpos2 == nvars - 1);
9291 
9292  /* take new candidates */
9293  candpos = candpos2;
9294 
9295  /* recalculate gcd from scratch */
9296  gcd = weights[v+1];
9297  assert(gcd >= 1);
9298 
9299  /* calculate greatest common divisor for variables */
9300  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9301  if( gcd == 1 )
9302  return SCIP_OKAY;
9303  }
9304  else
9305  /* cannot determine a possible coefficient for reduction */
9306  return SCIP_OKAY;
9307  }
9308  }
9309  }
9310  assert(gcd >= 2);
9311 
9312  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9313  * further
9314  */
9315  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9316 
9317  /* determine the remainder of the capacity and the gcd */
9318  rest = consdata->capacity % gcd;
9319  assert(rest >= 0);
9320  assert(rest < gcd);
9321 
9322  if( candpos == -1 )
9323  {
9324  /* we assume that the constraint was normalized */
9325  assert(rest > 0);
9326 
9327  /* replace old with new capacity */
9328  consdata->capacity -= rest;
9329  ++(*nchgsides);
9330 
9331  /* replace old big coefficients with new capacity */
9332  for( v = 0; v < offsetv; ++v )
9333  consdataChgWeight(consdata, v, consdata->capacity);
9334 
9335  *nchgcoefs += offsetv;
9336  goto CONTINUE;
9337  }
9338 
9339  /* determine the remainder of the coefficient candidate and the gcd */
9340  restweight = weights[candpos] % gcd;
9341  assert(restweight >= 1);
9342  assert(restweight < gcd);
9343 
9344  /* calculate new coefficient */
9345  if( restweight > rest )
9346  newweight = weights[candpos] - restweight + gcd;
9347  else
9348  newweight = weights[candpos] - restweight;
9349 
9350  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9351 
9352  SCIPdebugMessage("gcd = %" SCIP_LONGINT_FORMAT ", rest = %" SCIP_LONGINT_FORMAT ", restweight = %" SCIP_LONGINT_FORMAT "; possible new weight of variable <%s> %" SCIP_LONGINT_FORMAT ", possible new capacity %" SCIP_LONGINT_FORMAT ", offset of coefficients as big as capacity %d\n", gcd, rest, restweight, SCIPvarGetName(vars[candpos]), newweight, consdata->capacity - rest, offsetv);
9353 
9354  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9355  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9356  */
9357  if( newweight == 0 && offsetv > 0 )
9358  return SCIP_OKAY;
9359 
9360  if( rest > 0 )
9361  {
9362  /* replace old with new capacity */
9363  consdata->capacity -= rest;
9364  ++(*nchgsides);
9365 
9366  /* replace old big coefficients with new capacity */
9367  for( v = 0; v < offsetv; ++v )
9368  consdataChgWeight(consdata, v, consdata->capacity);
9369 
9370  *nchgcoefs += offsetv;
9371  }
9372 
9373  if( newweight == 0 )
9374  {
9375  /* delete redundant coefficient */
9376  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9377  assert(consdata->nvars == nvars - 1);
9378  --nvars;
9379  }
9380  else
9381  {
9382  /* replace old with new coefficient */
9383  consdataChgWeight(consdata, candpos, newweight);
9384  }
9385  ++(*nchgcoefs);
9386 
9387  assert(consdata->vars == vars);
9388  assert(consdata->nvars == nvars);
9389  assert(consdata->weights == weights);
9390 
9391  CONTINUE:
9392  /* now constraint can be normalized, dividing it by the gcd */
9393  for( v = nvars - 1; v >= 0; --v )
9394  {
9395  consdataChgWeight(consdata, v, weights[v]/gcd);
9396  }
9397  (*nchgcoefs) += nvars;
9398 
9399  consdata->capacity /= gcd;
9400  ++(*nchgsides);
9401 
9402  SCIPdebugPrintCons(scip, cons, NULL);
9403 
9404  SCIPdebugMessage("we did %d coefficient changes and %d side changes on constraint %s when applying one round of the gcd algorithm\n", *nchgcoefs - oldnchgcoefs, *nchgsides - oldnchgsides, SCIPconsGetName(cons));
9405  }
9406  while( nvars >= 2 );
9407 
9408  return SCIP_OKAY;
9409 }
9410 
9411 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
9412 static
9414  SCIP* scip, /**< SCIP data structure */
9415  SCIP_CONS* cons, /**< knapsack constraint */
9416  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
9417  * information is not needed; in this case, we apply all fixings
9418  * instead of stopping after the first infeasible one */
9419  )
9421  SCIP_CONSDATA* consdata;
9422  int v;
9423 
9424  assert(scip != NULL);
9425  assert(cons != NULL);
9426 
9427  consdata = SCIPconsGetData(cons);
9428  assert(consdata != NULL);
9429  assert(consdata->nvars == 0 || consdata->vars != NULL);
9430 
9431  if( cutoff != NULL )
9432  *cutoff = FALSE;
9433 
9434  SCIPdebugMessage("apply fixings:\n");
9435  SCIPdebugPrintCons(scip, cons, NULL);
9436 
9437  /* check infeasibility */
9438  if ( consdata->onesweightsum > consdata->capacity )
9439  {
9440  SCIPdebugMessage("apply fixings detected cutoff.\n");
9441 
9442  if( cutoff != NULL )
9443  *cutoff = TRUE;
9444 
9445  return SCIP_OKAY;
9446  }
9447 
9448  /* all multi-aggregations should be resolved */
9449  consdata->existmultaggr = FALSE;
9450 
9451  v = 0;
9452  while( v < consdata->nvars )
9453  {
9454  SCIP_VAR* var;
9455 
9456  var = consdata->vars[v];
9457  assert(SCIPvarIsBinary(var));
9458 
9459  if( SCIPvarGetLbGlobal(var) > 0.5 )
9460  {
9461  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
9462  consdata->capacity -= consdata->weights[v];
9463  SCIP_CALL( delCoefPos(scip, cons, v) );
9464  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
9465  }
9466  else if( SCIPvarGetUbGlobal(var) < 0.5 )
9467  {
9468  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
9469  SCIP_CALL( delCoefPos(scip, cons, v) );
9470  }
9471  else
9472  {
9473  SCIP_VAR* repvar;
9474  SCIP_VAR* negvar;
9475  SCIP_VAR* workvar;
9476  SCIP_Longint weight;
9477  SCIP_Bool negated;
9478 
9479  weight = consdata->weights[v];
9480 
9481  /* get binary representative of variable */
9482  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
9483  assert(repvar != NULL);
9484 
9485  /* check for multi-aggregation */
9486  if( SCIPvarIsNegated(repvar) )
9487  {
9488  workvar = SCIPvarGetNegatedVar(repvar);
9489  assert(workvar != NULL);
9490  negated = TRUE;
9491  }
9492  else
9493  {
9494  workvar = repvar;
9495  negated = FALSE;
9496  }
9497 
9498  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
9499  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
9500  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
9501  *
9502  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
9503  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
9504  *
9505  * The explanation for the following block:
9506  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
9507  * weight * (a_1*y_1 + ... + a_n*y_n + c).
9508  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
9509  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
9510  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
9511  * 2) For all replacement variable we check:
9512  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
9513  * capacity -= weight * a_i caused by the negation of y_i.
9514  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
9515  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
9516  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
9517  * weight in this case.
9518  */
9519  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
9520  {
9521  SCIP_VAR** aggrvars;
9522  SCIP_Real* aggrscalars;
9523  SCIP_Real aggrconst;
9524  int naggrvars;
9525  int i;
9526 
9527  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
9528  naggrvars = SCIPvarGetMultaggrNVars(workvar);
9529  aggrvars = SCIPvarGetMultaggrVars(workvar);
9530  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
9531  aggrconst = SCIPvarGetMultaggrConstant(workvar);
9532  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
9533 
9534  if( !SCIPisIntegral(scip, weight * aggrconst) )
9535  {
9536  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
9537  return SCIP_ERROR;
9538  }
9539 
9540  /* if workvar was negated, we have to flip the weight */
9541  if( negated )
9542  weight *= -1;
9543 
9544  for( i = naggrvars - 1; i >= 0; --i )
9545  {
9546  assert(aggrvars != NULL);
9547  assert(aggrscalars != NULL);
9548 
9549  if( !SCIPvarIsBinary(aggrvars[i]) )
9550  {
9551  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary variable <%s>\n", aggrvars[i]);
9552  return SCIP_ERROR;
9553  }
9554  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
9555  {
9556  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
9557  return SCIP_ERROR;
9558  }
9559  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
9560  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
9561  {
9562  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
9563  assert(negvar != NULL);
9564  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
9565  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
9566  }
9567  else
9568  {
9569  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
9570  }
9571  }
9572  /* delete old coefficient */
9573  SCIP_CALL( delCoefPos(scip, cons, v) );
9574 
9575  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
9576  if( negated )
9577  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
9578  else
9579  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
9580 
9581  if( consdata->capacity < 0 )
9582  {
9583  if( cutoff != NULL )
9584  {
9585  *cutoff = TRUE;
9586  break;
9587  }
9588  }
9589  }
9590  /* check, if the variable should be replaced with the representative */
9591  else if( repvar != var )
9592  {
9593  /* delete old (aggregated) variable */
9594  SCIP_CALL( delCoefPos(scip, cons, v) );
9595 
9596  /* add representative instead */
9597  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
9598  }
9599  else
9600  ++v;
9601  }
9602  }
9603  assert(consdata->onesweightsum == 0);
9604 
9605  SCIPdebugMessage("after applyFixings, before merging:\n");
9606  SCIPdebugPrintCons(scip, cons, NULL);
9607 
9608  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
9609  * clean up the constraint
9610  */
9611  if( cutoff != NULL && !(*cutoff) )
9612  {
9613  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9614  SCIPdebugMessage("after applyFixings and merging:\n");
9615  SCIPdebugPrintCons(scip, cons, NULL);
9616  }
9617 
9618  return SCIP_OKAY;
9619 }
9620 
9621 /** inserts an element into the list of binary zero implications */
9622 static
9624  SCIP* scip, /**< SCIP data structure */
9625  int** liftcands, /**< array of the lifting candidates */
9626  int* nliftcands, /**< number of lifting candidates */
9627  int** firstidxs, /**< array of first zeroitems indices */
9628  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9629  int** zeroitems, /**< pointer to zero items array */
9630  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9631  int* zeroitemssize, /**< pointer to size of zero items array */
9632  int* nzeroitems, /**< pointer to length of zero items array */
9633  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9634  SCIP_Bool value, /**< value v of variable y in implication */
9635  int knapsackidx, /**< index of variable x in knapsack */
9636  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9637  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9638  )
9639 {
9640  int nzeros;
9641 
9642  assert(liftcands != NULL);
9643  assert(liftcands[value] != NULL);
9644  assert(nliftcands != NULL);
9645  assert(firstidxs != NULL);
9646  assert(firstidxs[value] != NULL);
9647  assert(zeroweightsums != NULL);
9648  assert(zeroweightsums[value] != NULL);
9649  assert(zeroitems != NULL);
9650  assert(nextidxs != NULL);
9651  assert(zeroitemssize != NULL);
9652  assert(nzeroitems != NULL);
9653  assert(*nzeroitems <= *zeroitemssize);
9654  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9655  assert(memlimitreached != NULL);
9656 
9657  nzeros = *nzeroitems;
9658 
9659  /* allocate enough memory */
9660  if( nzeros == *zeroitemssize )
9661  {
9662  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9663  * this can be too huge - abort on memory limit
9664  */
9665  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9666  {
9667  SCIPdebugMessage("memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9668  *zeroitemssize);
9669  *memlimitreached = TRUE;
9670  return SCIP_OKAY;
9671  }
9672  *zeroitemssize *= 2;
9673  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9674  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9675  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9676  }
9677  assert(nzeros < *zeroitemssize);
9678 
9679  if( *memlimitreached )
9680  *memlimitreached = FALSE;
9681 
9682  /* insert element */
9683  (*zeroitems)[nzeros] = knapsackidx;
9684  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9685  if( firstidxs[value][probindex] == 0 )
9686  {
9687  liftcands[value][nliftcands[value]] = probindex;
9688  ++nliftcands[value];
9689  }
9690  firstidxs[value][probindex] = nzeros;
9691  ++(*nzeroitems);
9692  zeroweightsums[value][probindex] += knapsackweight;
9693 
9694  return SCIP_OKAY;
9695 }
9696 
9697 #define MAX_CLIQUELENGTH 50
9698 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9699  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9700  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9701  * if cliqueweightsum(xi == v) < capacity:
9702  * - fixing variable xi to v would make the knapsack constraint redundant
9703  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9704  * redundancy effect:
9705  * wi' := capacity - cliqueweightsum(xi == v)
9706  * this rule can also be applied to binary variables not in the knapsack!
9707  */
9708 static
9710  SCIP* scip, /**< SCIP data structure */
9711  SCIP_CONS* cons, /**< knapsack constraint */
9712  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9713  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9714  )
9715 {
9716  SCIP_CONSDATA* consdata;
9717  SCIP_VAR** binvars;
9718  int nbinvars;
9719  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9720  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9721  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9722  int* zeroitems; /* item number in knapsack that is implied to zero */
9723  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9724  int zeroitemssize;
9725  int nzeroitems;
9726  SCIP_Bool* zeroiteminserted[2];
9727  SCIP_Bool memlimitreached;
9728  int nliftcands[2];
9729  SCIP_Bool* cliqueused;
9730  SCIP_Bool* itemremoved;
9731  SCIP_Longint maxcliqueweightsum;
9732  SCIP_VAR** addvars;
9733  SCIP_Longint* addweights;
9734  SCIP_Longint addweightsum;
9735  int nvars;
9736  int cliquenum;
9737  int naddvars;
9738  int val;
9739  int i;
9740 
9741  int* tmpindices;
9742  SCIP_Bool* tmpboolindices;
9743  int* tmpindices2;
9744  SCIP_Bool* tmpboolindices2;
9745  int* tmpindices3;
9746  SCIP_Bool* tmpboolindices3;
9747  int tmp;
9748  int tmp2;
9749  int tmp3;
9750  SCIP_CONSHDLR* conshdlr;
9751  SCIP_CONSHDLRDATA* conshdlrdata;
9752 
9753  assert(nchgcoefs != NULL);
9754  assert(!SCIPconsIsModifiable(cons));
9755 
9756  consdata = SCIPconsGetData(cons);
9757  assert(consdata != NULL);
9758  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9759  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9760  assert(consdata->nvars > 0);
9761  assert(consdata->merged);
9762 
9763  nvars = consdata->nvars;
9764 
9765  /* check if the knapsack has too many items/cliques for applying this costly method */
9766  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9767  return SCIP_OKAY;
9768 
9769  /* sort items, s.t. the heaviest one is in the first position */
9770  sortItems(consdata);
9771 
9772  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9773  return SCIP_OKAY;
9774 
9775  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9776  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9777  assert(nbinvars > 0);
9778  binvars = SCIPgetVars(scip);
9779 
9780  /* get conshdlrdata to use cleared memory */
9781  conshdlr = SCIPconsGetHdlr(cons);
9782  assert(conshdlr != NULL);
9783  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9784  assert(conshdlrdata != NULL);
9785 
9786  /* allocate temporary memory for the list of implied to zero variables */
9787  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9788  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9789  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9790 
9791  assert(conshdlrdata->ints1size > 0);
9792  assert(conshdlrdata->ints2size > 0);
9793  assert(conshdlrdata->longints1size > 0);
9794  assert(conshdlrdata->longints2size > 0);
9795 
9796  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9797  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9798  * transform all integers into their binary representation then it maybe happens
9799  */
9800  if( conshdlrdata->ints1size < nbinvars )
9801  {
9802  int oldsize;
9803  oldsize = conshdlrdata->ints1size;
9804 
9805  while( conshdlrdata->ints1size < nbinvars )
9806  conshdlrdata->ints1size *= 2;
9807  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->ints1, conshdlrdata->ints1size) );
9808  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9809  }
9810  if( conshdlrdata->ints2size < nbinvars )
9811  {
9812  int oldsize;
9813  oldsize = conshdlrdata->ints2size;
9814 
9815  while( conshdlrdata->ints2size < nbinvars )
9816  conshdlrdata->ints2size *= 2;
9817  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->ints2, conshdlrdata->ints2size) );
9818  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9819  }
9820  if( conshdlrdata->longints1size < nbinvars )
9821  {
9822  int oldsize;
9823  oldsize = conshdlrdata->longints1size;
9824 
9825  while( conshdlrdata->longints1size < nbinvars )
9826  conshdlrdata->longints1size *= 2;
9827  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->longints1, conshdlrdata->longints1size) );
9828  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9829  }
9830  if( conshdlrdata->longints2size < nbinvars )
9831  {
9832  int oldsize;
9833  oldsize = conshdlrdata->longints2size;
9834 
9835  while( conshdlrdata->longints2size < nbinvars )
9836  conshdlrdata->longints2size *= 2;
9837  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->longints2, conshdlrdata->longints2size) );
9838  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9839  }
9840 
9841  firstidxs[0] = conshdlrdata->ints1;
9842  firstidxs[1] = conshdlrdata->ints2;
9843  zeroweightsums[0] = conshdlrdata->longints1;
9844  zeroweightsums[1] = conshdlrdata->longints2;
9845 
9846  /* check for cleared arrays, all entries are zero */
9847 #ifndef NDEBUG
9848  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9849  {
9850  assert(firstidxs[0][tmp] == 0);
9851  assert(firstidxs[1][tmp] == 0);
9852  assert(zeroweightsums[0][tmp] == 0);
9853  assert(zeroweightsums[1][tmp] == 0);
9854  }
9855 #endif
9856 
9857  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9858  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9859 
9860  zeroitems[0] = -1; /* dummy element */
9861  nextidxs[0] = -1;
9862  nzeroitems = 1;
9863  nliftcands[0] = 0;
9864  nliftcands[1] = 0;
9865 
9866  assert(conshdlrdata->bools1size > 0);
9867  assert(conshdlrdata->bools2size > 0);
9868 
9869  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9870  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9871  * transform all integers into their binary representation then it maybe happens
9872  */
9873  if( conshdlrdata->bools1size < nbinvars )
9874  {
9875  int oldsize;
9876  oldsize = conshdlrdata->bools1size;
9877 
9878  while( conshdlrdata->bools1size < nbinvars )
9879  conshdlrdata->bools1size *= 2;
9880  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->bools1, conshdlrdata->bools1size) );
9881  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9882  }
9883  if( conshdlrdata->bools2size < nbinvars )
9884  {
9885  int oldsize;
9886  oldsize = conshdlrdata->bools2size;
9887 
9888  while( conshdlrdata->bools2size < nbinvars )
9889  conshdlrdata->bools2size *= 2;
9890  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->bools2, conshdlrdata->bools2size) );
9891  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9892  }
9893 
9894  zeroiteminserted[0] = conshdlrdata->bools1;
9895  zeroiteminserted[1] = conshdlrdata->bools2;
9896 
9897  /* check for cleared arrays, all entries are zero */
9898 #ifndef NDEBUG
9899  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9900  {
9901  assert(zeroiteminserted[0][tmp] == 0);
9902  assert(zeroiteminserted[1][tmp] == 0);
9903  }
9904 #endif
9905 
9906  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9907  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9908  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9909  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9910  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9911  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9912  tmp2 = 0;
9913  tmp3 = 0;
9914 
9915  memlimitreached = FALSE;
9916  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9917  {
9918  SCIP_CLIQUE** cliques;
9919  SCIP_VAR* var;
9920  SCIP_Longint weight;
9921  SCIP_Bool value;
9922  int varprobindex;
9923  int ncliques;
9924  int j;
9925 
9926  tmp = 0;
9927 
9928  /* get corresponding active problem variable */
9929  var = consdata->vars[i];
9930  weight = consdata->weights[i];
9931  value = TRUE;
9932  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9933  varprobindex = SCIPvarGetProbindex(var);
9934  assert(0 <= varprobindex && varprobindex < nbinvars);
9935 
9936  /* update the zeroweightsum */
9937  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9938  tmpboolindices3[tmp3] = !value;
9939  tmpindices3[tmp3] = varprobindex;
9940  ++tmp3;
9941 
9942  /* initialize the arrays of inserted zero items */
9943  /* first add the implications (~x == 1 -> x == 0) */
9944  {
9945  SCIP_Bool implvalue;
9946  int probindex;
9947 
9948  probindex = SCIPvarGetProbindex(var);
9949  assert(0 <= probindex && probindex < nbinvars);
9950 
9951  implvalue = !value;
9952 
9953  /* insert the item into the list of the implied variable/value */
9954  assert( !zeroiteminserted[implvalue][probindex] );
9955 
9956  if( firstidxs[implvalue][probindex] == 0 )
9957  {
9958  tmpboolindices2[tmp2] = implvalue;
9959  tmpindices2[tmp2] = probindex;
9960  ++tmp2;
9961  }
9962  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
9963  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
9964  &memlimitreached) );
9965  zeroiteminserted[implvalue][probindex] = TRUE;
9966  tmpboolindices[tmp] = implvalue;
9967  tmpindices[tmp] = probindex;
9968  ++tmp;
9969  }
9970 
9971  /* get the cliques where the knapsack item is member of with value 1 */
9972  ncliques = SCIPvarGetNCliques(var, value);
9973  cliques = SCIPvarGetCliques(var, value);
9974  for( j = 0; j < ncliques && !memlimitreached; ++j )
9975  {
9976  SCIP_VAR** cliquevars;
9977  SCIP_Bool* cliquevalues;
9978  int ncliquevars;
9979  int k;
9980 
9981  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
9982 
9983  /* discard big cliques */
9984  if( ncliquevars > MAX_CLIQUELENGTH )
9985  continue;
9986 
9987  cliquevars = SCIPcliqueGetVars(cliques[j]);
9988  cliquevalues = SCIPcliqueGetValues(cliques[j]);
9989 
9990  for( k = ncliquevars - 1; k >= 0; --k )
9991  {
9992  SCIP_Bool implvalue;
9993  int probindex;
9994 
9995  if( var == cliquevars[k] )
9996  continue;
9997 
9998  probindex = SCIPvarGetProbindex(cliquevars[k]);
9999  if( probindex == -1 )
10000  continue;
10001 
10002  assert(0 <= probindex && probindex < nbinvars);
10003  implvalue = cliquevalues[k];
10004 
10005  /* insert the item into the list of the clique variable/value */
10006  if( !zeroiteminserted[implvalue][probindex] )
10007  {
10008  if( firstidxs[implvalue][probindex] == 0 )
10009  {
10010  tmpboolindices2[tmp2] = implvalue;
10011  tmpindices2[tmp2] = probindex;
10012  ++tmp2;
10013  }
10014 
10015  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10016  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10017  &memlimitreached) );
10018  zeroiteminserted[implvalue][probindex] = TRUE;
10019  tmpboolindices[tmp] = implvalue;
10020  tmpindices[tmp] = probindex;
10021  ++tmp;
10022 
10023  if( memlimitreached )
10024  break;
10025  }
10026  }
10027  }
10028  /* clear zeroiteminserted */
10029  for( --tmp; tmp >= 0; --tmp)
10030  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10031  }
10032  SCIPfreeBufferArray(scip, &tmpboolindices);
10033 
10034  /* calculate the clique partition and the maximal sum of weights using the clique information */
10035  assert(consdata->sorted);
10036  SCIP_CALL( calcCliquepartition(scip, consdata, TRUE, FALSE) );
10037 
10038  assert(conshdlrdata->bools3size > 0);
10039 
10040  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10041  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10042  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10043  */
10044  if( conshdlrdata->bools3size < consdata->nvars )
10045  {
10046  int oldsize;
10047  oldsize = conshdlrdata->bools3size;
10048 
10049  while( conshdlrdata->bools3size < consdata->nvars )
10050  conshdlrdata->bools3size *= 2;
10051  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->bools3, conshdlrdata->bools3size) );
10052  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10053  }
10054 
10055  cliqueused = conshdlrdata->bools3;
10056 
10057  /* check for cleared array, all entries are zero */
10058 #ifndef NDEBUG
10059  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10060  assert(cliqueused[tmp] == 0);
10061 #endif
10062 
10063  maxcliqueweightsum = 0;
10064  tmp = 0;
10065 
10066  /* calculates maximal weight of cliques */
10067  for( i = 0; i < consdata->nvars; ++i )
10068  {
10069  cliquenum = consdata->cliquepartition[i];
10070  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10071 
10072  if( !cliqueused[cliquenum] )
10073  {
10074  maxcliqueweightsum += consdata->weights[i];
10075  cliqueused[cliquenum] = TRUE;
10076  tmpindices[tmp] = cliquenum;
10077  ++tmp;
10078  }
10079  }
10080  /* clear cliqueused */
10081  for( --tmp; tmp >= 0; --tmp)
10082  cliqueused[tmp] = FALSE;
10083 
10084  assert(conshdlrdata->bools4size > 0);
10085 
10086  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10087  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10088  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10089  */
10090  if( conshdlrdata->bools4size < consdata->nvars )
10091  {
10092  int oldsize;
10093  oldsize = conshdlrdata->bools4size;
10094 
10095  while( conshdlrdata->bools4size < consdata->nvars )
10096  conshdlrdata->bools4size *= 2;
10097  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->bools4, conshdlrdata->bools4size) );
10098  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10099  }
10100 
10101  itemremoved = conshdlrdata->bools4;
10102 
10103  /* check for cleared array, all entries are zero */
10104 #ifndef NDEBUG
10105  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10106  assert(itemremoved[tmp] == 0);
10107 #endif
10108 
10109  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10110  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10111  * included in subsequent cliqueweightsum calculations)
10112  */
10113  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10114  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10115  naddvars = 0;
10116  addweightsum = 0;
10117  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10118  {
10119  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10120  {
10121  SCIP_Longint cliqueweightsum;
10122  int probindex;
10123  int idx;
10124  int j;
10125 
10126  tmp = 0;
10127 
10128  probindex = liftcands[val][i];
10129  assert(0 <= probindex && probindex < nbinvars);
10130 
10131  /* ignore empty zero lists and variables that cannot be lifted anyways */
10132  if( firstidxs[val][probindex] == 0
10133  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10134  continue;
10135 
10136  /* mark the items that are implied to zero by setting the current variable to the current value */
10137  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10138  {
10139  assert(0 < idx && idx < nzeroitems);
10140  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10141  itemremoved[zeroitems[idx]] = TRUE;
10142  }
10143 
10144  /* calculate the residual cliqueweight sum */
10145  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10146  for( j = 0; j < consdata->nvars; ++j )
10147  {
10148  cliquenum = consdata->cliquepartition[j];
10149  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10150  if( !itemremoved[j] )
10151  {
10152  if( !cliqueused[cliquenum] )
10153  {
10154  cliqueweightsum += consdata->weights[j];
10155  cliqueused[cliquenum] = TRUE;
10156  tmpindices[tmp] = cliquenum;
10157  ++tmp;
10158  }
10159 
10160  if( cliqueweightsum >= consdata->capacity )
10161  break;
10162  }
10163  }
10164 
10165  /* check if the weight of the variable/value can be increased */
10166  if( cliqueweightsum < consdata->capacity )
10167  {
10168  SCIP_VAR* var;
10169  SCIP_Longint weight;
10170 
10171  /* insert the variable (with value TRUE) in the list of additional items */
10172  assert(naddvars < 2*nbinvars);
10173  var = binvars[probindex];
10174  if( val == FALSE )
10175  {
10176  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10177  }
10178  weight = consdata->capacity - cliqueweightsum;
10179  addvars[naddvars] = var;
10180  addweights[naddvars] = weight;
10181  addweightsum += weight;
10182  naddvars++;
10183 
10184  SCIPdebugMessage("knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10185  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10186  }
10187 
10188  /* clear itemremoved */
10189  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10190  {
10191  assert(0 < idx && idx < nzeroitems);
10192  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10193  itemremoved[zeroitems[idx]] = FALSE;
10194  }
10195  /* clear cliqueused */
10196  for( --tmp; tmp >= 0; --tmp)
10197  cliqueused[tmpindices[tmp]] = FALSE;
10198  }
10199  }
10200  SCIPfreeBufferArray(scip, &tmpindices);
10201 
10202  /* clear part of zeroweightsums */
10203  for( --tmp3; tmp3 >= 0; --tmp3)
10204  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10205 
10206  /* clear rest of zeroweightsums and firstidxs */
10207  for( --tmp2; tmp2 >= 0; --tmp2)
10208  {
10209  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10210  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10211  }
10212 
10213  SCIPfreeBufferArray(scip, &tmpindices2);
10214  SCIPfreeBufferArray(scip, &tmpindices3);
10215  SCIPfreeBufferArray(scip, &tmpboolindices2);
10216  SCIPfreeBufferArray(scip, &tmpboolindices3);
10217 
10218  /* add all additional item weights */
10219  for( i = 0; i < naddvars; ++i )
10220  {
10221  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10222  }
10223  *nchgcoefs += naddvars;
10224 
10225  if( naddvars > 0 )
10226  {
10227  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10228  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10229  }
10230 
10231  /* free temporary memory */
10232  SCIPfreeBufferArray(scip, &addweights);
10233  SCIPfreeBufferArray(scip, &addvars);
10234  SCIPfreeBufferArray(scip, &nextidxs);
10235  SCIPfreeBufferArray(scip, &zeroitems);
10236  SCIPfreeBufferArray(scip, &liftcands[1]);
10237  SCIPfreeBufferArray(scip, &liftcands[0]);
10238 
10239  return SCIP_OKAY;
10240 }
10241 
10242 /** tightens item weights and capacity in presolving:
10243  * given a knapsack sum(wi*xi) <= capacity
10244  * (1) let weightsum := sum(wi)
10245  * if weightsum - wi < capacity:
10246  * - not using item i would make the knapsack constraint redundant
10247  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10248  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10249  * - change coefficients:
10250  * wi' := weightsum - capacity
10251  * capacity' := capacity - (wi - wi')
10252  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10253  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10254  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10255  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10256  * can be multiple times the same weight, this can be improved
10257  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10258  * weight, to capacity - lastmininmalweightsum, e.g. :
10259  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10260  * -> minimal weightsums: 5, 5, 10, 10
10261  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10262  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10263  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10264  * (3) let W(C) be the maximal weight of clique C,
10265  * cliqueweightsum := sum(W(C))
10266  * if cliqueweightsum - W(C) < capacity:
10267  * - not using any item of C would make the knapsack constraint redundant
10268  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10269  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10270  * - change coefficients:
10271  * delta := capacity - (cliqueweightsum - W(C))
10272  * wi' := max(wi - delta, 0)
10273  * capacity' := capacity - delta
10274  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10275  * introduce infeasible solutions.
10276  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10277  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10278  * if cliqueweightsum(xi == v) < capacity:
10279  * - fixing variable xi to v would make the knapsack constraint redundant
10280  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10281  * redundancy effect:
10282  * wi' := capacity - cliqueweightsum(xi == v)
10283  * This rule can also be applied to binary variables not in the knapsack!
10284  * (5) if min{w} + wi > capacity:
10285  * - using item i would force to fix other items to zero
10286  * - wi can be increased to the capacity
10287  */
10288 static
10290  SCIP* scip, /**< SCIP data structure */
10291  SCIP_CONS* cons, /**< knapsack constraint */
10292  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10293  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10294  int* nchgsides, /**< pointer to count number of side changes */
10295  int* naddconss, /**< pointer to count number of added constraints */
10296  int* ndelconss, /**< pointer to count number of deleted constraints */
10297  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10298  )
10299 {
10300  SCIP_CONSHDLRDATA* conshdlrdata;
10301  SCIP_CONSDATA* consdata;
10302  SCIP_Longint* weights;
10303  SCIP_Longint sumcoef;
10304  SCIP_Longint capacity;
10305  SCIP_Longint newweight;
10306  SCIP_Longint maxweight;
10307  SCIP_Longint minweight;
10308  SCIP_Bool sumcoefcase = FALSE;
10309  int startpos;
10310  int backpos;
10311  int nvars;
10312  int pos;
10313  int k;
10314  int i;
10315 
10316  assert(nchgcoefs != NULL);
10317  assert(nchgsides != NULL);
10318  assert(!SCIPconsIsModifiable(cons));
10319 
10320  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10321  assert(conshdlrdata != NULL);
10322 
10323  consdata = SCIPconsGetData(cons);
10324  assert(consdata != NULL);
10325  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10326  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10327  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10328  assert(consdata->nvars > 0);
10329 
10330  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10331  if( *cutoff )
10332  return SCIP_OKAY;
10333 
10334  /* apply rule (1) */
10335  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10336  {
10337  do
10338  {
10339  assert(consdata->merged);
10340 
10341  /* sort items, s.t. the heaviest one is in the first position */
10342  sortItems(consdata);
10343 
10344  for( i = 0; i < consdata->nvars; ++i )
10345  {
10346  SCIP_Longint weight;
10347 
10348  weight = consdata->weights[i];
10349  if( consdata->weightsum - weight < consdata->capacity )
10350  {
10351  newweight = consdata->weightsum - consdata->capacity;
10352  consdataChgWeight(consdata, i, newweight);
10353  consdata->capacity -= (weight - newweight);
10354  (*nchgcoefs)++;
10355  (*nchgsides)++;
10356  assert(!consdata->sorted);
10357  SCIPdebugMessage("knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT ", capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10358  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10359  consdata->capacity + (weight-newweight), consdata->capacity);
10360  }
10361  else
10362  break;
10363  }
10364  }
10365  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10366  }
10367 
10368  /* check for redundancy */
10369  if( consdata->weightsum <= consdata->capacity )
10370  return SCIP_OKAY;
10371 
10372  pos = 0;
10373  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10374  ++pos;
10375 
10376  sumcoef = 0;
10377  weights = consdata->weights;
10378  nvars = consdata->nvars;
10379  capacity = consdata->capacity;
10380 
10381  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10382  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10383  {
10384  /* further reductions using the next possible coefficient sum
10385  *
10386  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10387  */
10388  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10389  for( k = 0; k < 4; ++k )
10390  {
10391  newweight = capacity - sumcoef;
10392 
10393  /* determine next minimal coefficient sum */
10394  switch( k )
10395  {
10396  case 0:
10397  sumcoef = weights[nvars - 1];
10398  backpos = nvars - 1;
10399  break;
10400  case 1:
10401  sumcoef = weights[nvars - 2];
10402  backpos = nvars - 2;
10403  break;
10404  case 2:
10405  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10406  {
10407  sumcoefcase = TRUE;
10408  sumcoef = weights[nvars - 3];
10409  backpos = nvars - 3;
10410  }
10411  else
10412  {
10413  sumcoefcase = FALSE;
10414  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10415  backpos = nvars - 2;
10416  }
10417  break;
10418  case 3:
10419  if( sumcoefcase )
10420  {
10421  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10422  {
10423  sumcoef = weights[nvars - 4];
10424  backpos = nvars - 4;
10425  }
10426  else
10427  {
10428  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10429  backpos = nvars - 2;
10430  }
10431  }
10432  else
10433  {
10434  sumcoef = weights[nvars - 3];
10435  backpos = nvars - 3;
10436  }
10437  break;
10438  default:
10439  return SCIP_ERROR;
10440  }
10441 
10442  if( backpos <= pos )
10443  break;
10444 
10445  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10446  maxweight = weights[pos];
10447  startpos = pos;
10448  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10449  {
10450  assert(newweight > weights[pos]);
10451 
10452  SCIPdebugMessage("in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10453  SCIPconsGetName(cons), maxweight, newweight);
10454 
10455  consdataChgWeight(consdata, pos, newweight);
10456 
10457  ++pos;
10458  assert(pos < nvars);
10459 
10460  maxweight = weights[pos];
10461 
10462  if( backpos <= pos )
10463  break;
10464  }
10465  (*nchgcoefs) += (pos - startpos);
10466 
10467  /* skip unchangable weights */
10468  while( pos < nvars && weights[pos] + sumcoef == capacity )
10469  ++pos;
10470 
10471  /* check special case were there is only one weight left to tighten
10472  *
10473  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10474  *
10475  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10476  *
10477  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10478  */
10479  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10480  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10481  {
10482  newweight = capacity - sumcoef;
10483  assert(newweight > weights[pos]);
10484 
10485  SCIPdebugMessage("in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10486  SCIPconsGetName(cons), maxweight, newweight);
10487 
10488  consdataChgWeight(consdata, pos, newweight);
10489 
10490  break;
10491  }
10492 
10493  if( backpos <= pos )
10494  break;
10495  }
10496  }
10497 
10498  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10499  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10500  {
10501  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10502  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10503  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10504  {
10505  SCIP_VAR** clqvars;
10506  SCIP_CONS* cliquecons;
10507  char name[SCIP_MAXSTRLEN];
10508  int* clqpart;
10509  int nclqvars;
10510  int nclq;
10511  int len;
10512  int c;
10513  int w;
10514 
10515  assert(!SCIPconsIsDeleted(cons));
10516 
10517  if( pos == consdata->nvars )
10518  {
10519  SCIPdebugMessage("upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10520 
10521  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10525  SCIPconsIsStickingAtNode(cons)) );
10526 
10527  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10528  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10529  ++(*naddconss);
10530 
10531  /* delete old constraint */
10532  SCIP_CALL( SCIPdelCons(scip, cons) );
10533  ++(*ndelconss);
10534 
10535  return SCIP_OKAY;
10536  }
10537 
10538  len = consdata->nvars - pos;
10539 
10540  /* allocate temporary memory */
10541  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10542 
10543  /* calculate clique partition */
10544  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10545  assert(nclq <= len);
10546 
10547 #ifndef NDEBUG
10548  /* clique numbers must be at least as high as the index */
10549  for( w = 0; w < nclq; ++w )
10550  assert(clqpart[w] <= w);
10551 #endif
10552 
10553  SCIPdebugMessage("Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10554 
10555  /* allocate temporary memory */
10556  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10557 
10558  /* copy corresponding variables with big coefficients */
10559  for( w = pos - 1; w >= 0; --w )
10560  clqvars[w] = consdata->vars[w];
10561 
10562  /* create for each clique a set-packing constraint */
10563  for( c = 0; c < nclq; ++c )
10564  {
10565  nclqvars = pos;
10566 
10567  for( w = c; w < len; ++w )
10568  {
10569  if( clqpart[w] == c )
10570  {
10571  assert(nclqvars < pos + len - nclq + 1);
10572  clqvars[nclqvars] = consdata->vars[w + pos];
10573  ++nclqvars;
10574  }
10575  }
10576 
10577  assert(nclqvars > 1);
10578 
10579  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10580  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10584  SCIPconsIsStickingAtNode(cons)) );
10585  SCIPdebugMessage(" -> adding clique constraint: ");
10586  SCIPdebugPrintCons(scip, cliquecons, NULL);
10587  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10588  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10589  ++(*naddconss);
10590  }
10591 
10592  /* delete old constraint */
10593  SCIP_CALL( SCIPdelCons(scip, cons) );
10594  ++(*ndelconss);
10595 
10596  SCIPfreeBufferArray(scip, &clqvars);
10597  SCIPfreeBufferArray(scip, &clqpart);
10598 
10599  return SCIP_OKAY;
10600  }
10601  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10602  {
10603  SCIP_Longint* maxcliqueweights;
10604  SCIP_Longint* newweightvals;
10605  int* newweightidxs;
10606  SCIP_Longint cliqueweightsum;
10607 
10608  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10609  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10610  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10611 
10612  /* repeat as long as changes have been applied */
10613  do
10614  {
10615  int ncliques;
10616  int cliquenum;
10617  SCIP_Bool zeroweights;
10618 
10619  assert(consdata->merged);
10620 
10621  /* sort items, s.t. the heaviest one is in the first position */
10622  sortItems(consdata);
10623 
10624  /* calculate a clique partition */
10625  SCIP_CALL( calcCliquepartition(scip, consdata, TRUE, FALSE) );
10626 
10627  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10628  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10629  break;
10630 
10631  /* calculate the maximal weight of the cliques and store the clique type */
10632  cliqueweightsum = 0;
10633  ncliques = 0;
10634 
10635  for( i = 0; i < consdata->nvars; ++i )
10636  {
10637  SCIP_Longint weight;
10638 
10639  cliquenum = consdata->cliquepartition[i];
10640  assert(0 <= cliquenum && cliquenum <= ncliques);
10641 
10642  weight = consdata->weights[i];
10643  assert(weight > 0);
10644 
10645  if( cliquenum == ncliques )
10646  {
10647  maxcliqueweights[ncliques] = weight;
10648  cliqueweightsum += weight;
10649  ++ncliques;
10650  }
10651 
10652  assert(maxcliqueweights[cliquenum] >= weight);
10653  }
10654 
10655  /* apply rule on every clique */
10656  zeroweights = FALSE;
10657  for( i = 0; i < ncliques; ++i )
10658  {
10659  SCIP_Longint delta;
10660 
10661  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10662  if( delta > 0 )
10663  {
10664  SCIP_Longint newcapacity;
10665 #ifndef NDEBUG
10666  SCIP_Longint newmincliqueweight;
10667 #endif
10668  SCIP_Longint newminweightsuminclique;
10669  SCIP_Bool forceclique;
10670  int nnewweights;
10671  int j;
10672 
10673  SCIPdebugMessage("knapsack constraint <%s>: weights of clique %d (maxweight: %" SCIP_LONGINT_FORMAT ") can be tightened: cliqueweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT " -> delta: %" SCIP_LONGINT_FORMAT "\n",
10674  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10675  newcapacity = consdata->capacity - delta;
10676  forceclique = FALSE;
10677  nnewweights = 0;
10678 #ifndef NDEBUG
10679  newmincliqueweight = newcapacity + 1;
10680  for( j = 0; j < i; ++j )
10681  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10682 #endif
10683  for( j = i; j < consdata->nvars; ++j )
10684  {
10685  if( consdata->cliquepartition[j] == i )
10686  {
10687  newweight = consdata->weights[j] - delta;
10688  newweight = MAX(newweight, 0);
10689 
10690  /* cache the new weight */
10691  assert(nnewweights < consdata->nvars);
10692  newweightvals[nnewweights] = newweight;
10693  newweightidxs[nnewweights] = j;
10694  nnewweights++;
10695 
10696 #ifndef NDEBUG
10697  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10698  newmincliqueweight = newweight;
10699 #endif
10700  }
10701  }
10702 
10703  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10704  if( nnewweights > 1 )
10705  {
10706 #ifndef NDEBUG
10707  j = newweightidxs[nnewweights - 2];
10708  assert(0 <= j && j < consdata->nvars);
10709  assert(consdata->cliquepartition[j] == i);
10710  j = newweightidxs[nnewweights - 1];
10711  assert(0 <= j && j < consdata->nvars);
10712  assert(consdata->cliquepartition[j] == i);
10713 #endif
10714 
10715  newminweightsuminclique = newweightvals[nnewweights - 2];
10716  newminweightsuminclique += newweightvals[nnewweights - 1];
10717 
10718  /* check if these new two minimal weights both fit into the knapsack;
10719  * if this is true, we have to add a clique constraint in order to enforce the clique
10720  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10721  * reduction might be infeasible, i.e., allows additional solutions)
10722  */
10723  if( newminweightsuminclique <= newcapacity )
10724  forceclique = TRUE;
10725  }
10726 
10727  /* check if we really want to apply the change */
10728  if( conshdlrdata->disaggregation || !forceclique )
10729  {
10730  SCIPdebugMessage(" -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10731  consdata->capacity, newcapacity, forceclique);
10732  consdata->capacity = newcapacity;
10733  (*nchgsides)++;
10734 
10735  for( k = 0; k < nnewweights; ++k )
10736  {
10737  j = newweightidxs[k];
10738  assert(0 <= j && j < consdata->nvars);
10739  assert(consdata->cliquepartition[j] == i);
10740 
10741  /* apply the weight change */
10742  SCIPdebugMessage(" -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10743  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10744  consdataChgWeight(consdata, j, newweightvals[k]);
10745  (*nchgcoefs)++;
10746  assert(!consdata->sorted);
10747  zeroweights = zeroweights || (newweightvals[k] == 0);
10748  }
10749  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10750  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10751  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10752  * knapsack constraint
10753  */
10754  if( forceclique )
10755  {
10756  SCIP_CONS* cliquecons;
10757  char name[SCIP_MAXSTRLEN];
10758  SCIP_VAR** cliquevars;
10759 
10760  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10761  for( k = 0; k < nnewweights; ++k )
10762  cliquevars[k] = consdata->vars[newweightidxs[k]];
10763 
10764  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10765  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10769  SCIPconsIsStickingAtNode(cons)) );
10770  SCIPdebugMessage(" -> adding clique constraint: ");
10771  SCIPdebugPrintCons(scip, cliquecons, NULL);
10772  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10773  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10774  SCIPfreeBufferArray(scip, &cliquevars);
10775  (*naddconss)++;
10776  }
10777  }
10778  }
10779  }
10780  if( zeroweights )
10781  {
10782  SCIP_CALL( removeZeroWeights(scip, cons) );
10783  }
10784  }
10785  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10786 
10787  /* free temporary memory */
10788  SCIPfreeBufferArray(scip, &newweightidxs);
10789  SCIPfreeBufferArray(scip, &newweightvals);
10790  SCIPfreeBufferArray(scip, &maxcliqueweights);
10791 
10792  /* check for redundancy */
10793  if( consdata->weightsum <= consdata->capacity )
10794  return SCIP_OKAY;
10795  }
10796  }
10797 
10798  /* apply rule (3) */
10799  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10800  {
10801  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10802  }
10803 
10804  /* check for redundancy */
10805  if( consdata->weightsum <= consdata->capacity )
10806  return SCIP_OKAY;
10807 
10808  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10809  {
10810  /* apply rule (4) (all but smallest weight) */
10811  assert(consdata->merged);
10812  sortItems(consdata);
10813  minweight = consdata->weights[consdata->nvars-1];
10814  for( i = 0; i < consdata->nvars-1; ++i )
10815  {
10816  SCIP_Longint weight;
10817 
10818  weight = consdata->weights[i];
10819  assert(weight >= minweight);
10820  if( minweight + weight > consdata->capacity )
10821  {
10822  if( weight < consdata->capacity )
10823  {
10824  SCIPdebugMessage("knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10825  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10826  assert(consdata->sorted);
10827  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10828  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10829  consdata->sorted = TRUE;
10830  (*nchgcoefs)++;
10831  }
10832  }
10833  else
10834  break;
10835  }
10836 
10837  /* apply rule (5) (smallest weight) */
10838  if( consdata->nvars >= 2 )
10839  {
10840  SCIP_Longint weight;
10841 
10842  minweight = consdata->weights[consdata->nvars-2];
10843  weight = consdata->weights[consdata->nvars-1];
10844  assert(minweight >= weight);
10845  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10846  {
10847  SCIPdebugMessage("knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10848  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10849  assert(consdata->sorted);
10850  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10851  assert(minweight >= consdata->weights[consdata->nvars-1]);
10852  consdata->sorted = TRUE;
10853  (*nchgcoefs)++;
10854  }
10855  }
10856  }
10857 
10858  return SCIP_OKAY;
10859 }
10860 
10861 /** adds negated cliques of the knapsack constraint to the global clique table */
10862 static
10864  SCIP*const scip, /**< SCIP data structure */
10865  SCIP_CONS*const cons, /**< knapsack constraint */
10866  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10867  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10868  )
10869 {
10870  SCIP_CONSDATA* consdata;
10871  SCIP_VAR** poscliquevars;
10872  SCIP_VAR** cliquevars;
10873  SCIP_Longint* maxweights;
10874  SCIP_Longint* gainweights;
10875  int* gaincliquepartition;
10876  SCIP_Bool* cliqueused;
10877  SCIP_Longint minactduetonegcliques;
10878  SCIP_Longint freecapacity;
10879  SCIP_Longint lastweight;
10880  SCIP_Longint beforelastweight;
10881  int nposcliquevars;
10882  int ncliquevars;
10883  int nvars;
10884  int nnegcliques;
10885  int lastcliqueused;
10886  int thisnbdchgs;
10887  int v;
10888  int w;
10889 
10890  assert(scip != NULL);
10891  assert(cons != NULL);
10892  assert(cutoff != NULL);
10893  assert(nbdchgs != NULL);
10894 
10895  *cutoff = FALSE;
10896 
10897  consdata = SCIPconsGetData(cons);
10898  assert(consdata != NULL);
10899 
10900  nvars = consdata->nvars;
10901 
10902  /* check whether the cliques have already been added */
10903  if( consdata->cliquesadded || nvars == 0 )
10904  return SCIP_OKAY;
10905 
10906  /* make sure, the items are merged */
10907  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10908  if( *cutoff )
10909  return SCIP_OKAY;
10910 
10911  /* make sure, items are sorted by non-increasing weight */
10912  sortItems(consdata);
10913 
10914  assert(consdata->merged);
10915 
10916  /* calculate a clique partition */
10917  SCIP_CALL( calcCliquepartition(scip, consdata, FALSE, TRUE) );
10918  nnegcliques = consdata->nnegcliques;
10919 
10920  /* if we have no negated cliques, stop */
10921  if( nnegcliques == nvars )
10922  return SCIP_OKAY;
10923 
10924  /* get temporary memory */
10925  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10926  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10927  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
10928  BMSclearMemoryArray(gainweights, nvars);
10929  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10930  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10931  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueused, nnegcliques) );
10932  BMSclearMemoryArray(cliqueused, nnegcliques);
10933 
10934  nnegcliques = 0;
10935  minactduetonegcliques = 0;
10936 
10937  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10938  for( v = 0; v < nvars; ++v )
10939  {
10940  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10941  assert(consdata->weights[v] > 0);
10942 
10943  if( consdata->negcliquepartition[v] == nnegcliques )
10944  {
10945  nnegcliques++;
10946  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
10947  }
10948  else
10949  minactduetonegcliques += consdata->weights[v];
10950  }
10951 
10952  nposcliquevars = 0;
10953 
10954  /* add cliques, using negated cliques information */
10955  if( minactduetonegcliques > 0 )
10956  {
10957  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
10958  freecapacity = consdata->capacity - minactduetonegcliques;
10959 
10960  SCIPdebugPrintCons(scip, cons, NULL);
10961  SCIPdebugMessage("Try to add negated cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
10962  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
10963 
10964  /* calculate possible gain by switching chosen items in negated cliques */
10965  for( v = 0; v < nvars; ++v )
10966  {
10967  if( !cliqueused[consdata->negcliquepartition[v]] )
10968  {
10969  cliqueused[consdata->negcliquepartition[v]] = TRUE;
10970  for( w = v + 1; w < nvars; ++w )
10971  {
10972  /* if we would take the biggest weight instead of another what would we gain, take weight[i] instead of
10973  * weight[j] (which are both in a negated clique) */
10974  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
10975  && consdata->weights[v] > consdata->weights[w] )
10976  {
10977  poscliquevars[nposcliquevars] = consdata->vars[w];
10978  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
10979  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
10980  ++nposcliquevars;
10981  }
10982  }
10983  }
10984  }
10985 
10986  /* try to create negated cliques */
10987  if( nposcliquevars > 0 )
10988  {
10989  /* sort possible gain per substitution of the clique members */
10990  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
10991 
10992  for( v = 0; v < nposcliquevars; ++v )
10993  {
10994  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
10995  ncliquevars = 1;
10996  lastweight = gainweights[v];
10997  beforelastweight = -1;
10998  lastcliqueused = gaincliquepartition[v];
10999  /* clear cliqueused to get an unused array */
11000  BMSclearMemoryArray(cliqueused, nnegcliques);
11001  cliqueused[gaincliquepartition[v]] = TRUE;
11002 
11003  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11004  * in the same negated clique and by taking two of them would exceed the free capacity */
11005  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11006  {
11007  beforelastweight = lastweight;
11008  lastweight = gainweights[w];
11009  lastcliqueused = gaincliquepartition[w];
11010  cliqueused[gaincliquepartition[w]] = TRUE;
11011  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11012  ++ncliquevars;
11013  }
11014 
11015  if( ncliquevars > 1 )
11016  {
11017 #ifdef SCIP_DEBUG
11018  int b;
11019  SCIPdebugMessage("adding new Clique: ");
11020  for( b = 0; b < ncliquevars; ++b )
11021  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
11022  SCIPdebugPrintf("\n");
11023 #endif
11024 
11025  assert(beforelastweight > 0);
11026  /* add the clique to the clique table */
11027  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11028  if( *cutoff )
11029  goto TERMINATE;
11030  *nbdchgs += thisnbdchgs;
11031 
11032  /* reset last used clique to get slightly different cliques */
11033  cliqueused[lastcliqueused] = FALSE;
11034 
11035  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11036  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11037  {
11038  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11039 #ifdef SCIP_DEBUG
11040  {
11041  SCIPdebugMessage("adding new Clique: ");
11042  for( b = 0; b < ncliquevars; ++b )
11043  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
11044  SCIPdebugPrintf("\n");
11045  }
11046 #endif
11047  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11048  if( *cutoff )
11049  goto TERMINATE;
11050  *nbdchgs += thisnbdchgs;
11051  }
11052  }
11053  }
11054  }
11055  }
11056 
11057  TERMINATE:
11058  /* free temporary memory */
11059  SCIPfreeBufferArray(scip, &cliqueused);
11060  SCIPfreeBufferArray(scip, &gaincliquepartition);
11061  SCIPfreeBufferArray(scip, &maxweights);
11062  SCIPfreeBufferArray(scip, &gainweights);
11063  SCIPfreeBufferArray(scip, &cliquevars);
11064  SCIPfreeBufferArray(scip, &poscliquevars);
11065 
11066  return SCIP_OKAY;
11067 }
11068 
11069 /** adds cliques of the knapsack constraint to the global clique table */
11070 static
11072  SCIP*const scip, /**< SCIP data structure */
11073  SCIP_CONS*const cons, /**< knapsack constraint */
11074  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11075  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11076  )
11077 {
11078  SCIP_CONSDATA* consdata;
11079  SCIP_VAR** cliquevars;
11080  int ncliquevars;
11081  int i;
11082  SCIP_Longint minactduetonegcliques;
11083  SCIP_Longint freecapacity;
11084  SCIP_Longint lastweight;
11085  SCIP_Longint beforelastweight;
11086  int nnegcliques;
11087  int cliquenum;
11088  int thisnbdchgs;
11089  SCIP_VAR** poscliquevars;
11090  SCIP_Longint* gainweights;
11091  int nposcliquevars;
11092  SCIP_Longint* secondmaxweights;
11093  int nvars;
11094 
11095  assert(scip != NULL);
11096  assert(cons != NULL);
11097  assert(cutoff != NULL);
11098  assert(nbdchgs != NULL);
11099 
11100  *cutoff = FALSE;
11101 
11102  consdata = SCIPconsGetData(cons);
11103  assert(consdata != NULL);
11104 
11105  nvars = consdata->nvars;
11106 
11107  /* check whether the cliques have already been added */
11108  if( consdata->cliquesadded || nvars == 0 )
11109  return SCIP_OKAY;
11110 
11111  /* make sure, the items are merged */
11112  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11113  if( *cutoff )
11114  return SCIP_OKAY;
11115 
11116  /* make sure, the items are sorted by non-increasing weight */
11117  sortItems(consdata);
11118 
11119  assert(consdata->merged);
11120 
11121  /* calculate a clique partition */
11122  SCIP_CALL( calcCliquepartition(scip, consdata, FALSE, TRUE) );
11123  nnegcliques = consdata->nnegcliques;
11124  assert(nnegcliques <= nvars);
11125 
11126  /* get temporary memory */
11127  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11128  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11129  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11130  BMSclearMemoryArray(gainweights, nvars);
11131  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11132  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11133 
11134  minactduetonegcliques = 0;
11135 
11136  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11137  if( nnegcliques < nvars )
11138  {
11139  nnegcliques = 0;
11140 
11141  for( i = 0; i < nvars; ++i )
11142  {
11143  SCIP_Longint weight;
11144 
11145  cliquenum = consdata->negcliquepartition[i];
11146  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11147 
11148  weight = consdata->weights[i];
11149  assert(weight > 0);
11150 
11151  if( cliquenum == nnegcliques )
11152  nnegcliques++;
11153  else
11154  {
11155  minactduetonegcliques += weight;
11156  if( secondmaxweights[cliquenum] == 0 )
11157  secondmaxweights[cliquenum] = weight;
11158  }
11159  }
11160  }
11161 
11162  /* add cliques, using negated cliques information */
11163  if( minactduetonegcliques > 0 )
11164  {
11165  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11166  freecapacity = consdata->capacity - minactduetonegcliques;
11167 
11168  SCIPdebugPrintCons(scip, cons, NULL);
11169  SCIPdebugMessage("Try to add cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
11170  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11171 
11172  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11173  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11174 
11175  nposcliquevars = 0;
11176 
11177  for( i = nvars - 1; i >= 0; --i )
11178  {
11179  /* if we would take the biggest weight instead of the second biggest */
11180  cliquenum = consdata->negcliquepartition[i];
11181  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11182  {
11183  poscliquevars[nposcliquevars] = consdata->vars[i];
11184  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11185  ++nposcliquevars;
11186  }
11187  }
11188 
11189  if( nposcliquevars > 0 )
11190  {
11191  /* sort possible gain per substitution of the clique members */
11192  SCIPsortDownLongPtr(gainweights,(void**) poscliquevars, nposcliquevars);
11193 
11194  cliquevars[0] = poscliquevars[0];
11195  ncliquevars = 1;
11196  lastweight = gainweights[0];
11197  beforelastweight = 0;
11198 
11199  /* taking bigger weights make the knapsack redundant so we will create cliques */
11200  for( i = 1; i < nposcliquevars && gainweights[i] + lastweight > freecapacity; ++i )
11201  {
11202  beforelastweight = lastweight;
11203  lastweight = gainweights[i];
11204  cliquevars[ncliquevars] = poscliquevars[i];
11205  ++ncliquevars;
11206  }
11207 
11208  if( ncliquevars > 1 )
11209  {
11210 #ifdef SCIP_DEBUG
11211  int b;
11212  SCIPdebugMessage("adding new Clique: ");
11213  for( b = 0; b < ncliquevars; ++b )
11214  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
11215  SCIPdebugPrintf("\n");
11216 #endif
11217 
11218  assert(beforelastweight > 0);
11219  /* add the clique to the clique table */
11220  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11221  if( *cutoff )
11222  goto TERMINATE;
11223  *nbdchgs += thisnbdchgs;
11224 
11225  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11226  for( ++i; i < nposcliquevars && beforelastweight + gainweights[i] > freecapacity; ++i )
11227  {
11228  cliquevars[ncliquevars - 1] = poscliquevars[i];
11229 #ifdef SCIP_DEBUG
11230  {
11231  SCIPdebugMessage("adding new Clique: ");
11232  for( b = 0; b < ncliquevars; ++b )
11233  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
11234  SCIPdebugPrintf("\n");
11235  }
11236 #endif
11237  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11238  if( *cutoff )
11239  goto TERMINATE;
11240  *nbdchgs += thisnbdchgs;
11241  }
11242  }
11243  }
11244  }
11245 
11246  /* build a largest clique by using the items with the maximal weights */
11247  cliquevars[0] = consdata->vars[0];
11248  for( i = 1; i < nvars && consdata->weights[i-1] + consdata->weights[i] > consdata->capacity; ++i )
11249  cliquevars[i] = consdata->vars[i];
11250 
11251  ncliquevars = i;
11252 
11253  if( ncliquevars >= 2 )
11254  {
11255  SCIP_Longint cliqueminweight;
11256 #ifdef SCIP_DEBUG
11257  int b;
11258  SCIPdebugMessage("adding new Clique: ");
11259  for( b = 0; b < ncliquevars; ++b )
11260  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
11261  SCIPdebugPrintf("\n");
11262 #endif
11263 
11264  /* add the clique to the clique table */
11265  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11266  if( *cutoff )
11267  goto TERMINATE;
11268  *nbdchgs += thisnbdchgs;
11269 
11270  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11271  cliqueminweight = consdata->weights[ncliquevars-2];
11272  for( i = ncliquevars; i < nvars && cliqueminweight + consdata->weights[i] > consdata->capacity; ++i )
11273  {
11274  cliquevars[ncliquevars - 1] = consdata->vars[i];
11275 #ifdef SCIP_DEBUG
11276  {
11277  SCIPdebugMessage("adding new Clique: ");
11278  for( b = 0; b < ncliquevars; ++b )
11279  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
11280  SCIPdebugPrintf("\n");
11281  }
11282 #endif
11283  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11284  if( *cutoff )
11285  goto TERMINATE;
11286  *nbdchgs += thisnbdchgs;
11287  }
11288  }
11289 
11290  TERMINATE:
11291  /* free temporary memory and mark the constraint */
11292  SCIPfreeBufferArray(scip, &secondmaxweights);
11293  SCIPfreeBufferArray(scip, &gainweights);
11294  SCIPfreeBufferArray(scip, &cliquevars);
11295  SCIPfreeBufferArray(scip, &poscliquevars);
11296  consdata->cliquesadded = TRUE;
11297 
11298  return SCIP_OKAY;
11299 }
11300 
11301 
11302 /** gets the key of the given element */
11303 static
11304 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11305 { /*lint --e{715}*/
11306  /* the key is the element itself */
11307  return elem;
11308 }
11309 
11310 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11311  * same coefficients
11312  */
11313 static
11314 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11315 {
11316 #ifndef NDEBUG
11317  SCIP* scip;
11318 #endif
11319  SCIP_CONSDATA* consdata1;
11320  SCIP_CONSDATA* consdata2;
11321  int i;
11322 
11323  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11324  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11325  assert(consdata1->sorted);
11326  assert(consdata2->sorted);
11327 #ifndef NDEBUG
11328  scip = (SCIP*)userptr;
11329  assert(scip != NULL);
11330 #endif
11331 
11332  /* checks trivial case */
11333  if( consdata1->nvars != consdata2->nvars )
11334  return FALSE;
11335 
11336  for( i = consdata1->nvars - 1; i >= 0; --i )
11337  {
11338  /* tests if variables are equal */
11339  if( consdata1->vars[i] != consdata2->vars[i] )
11340  {
11341  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11342  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11343  return FALSE;
11344  }
11345  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11346 
11347  /* tests if weights are equal too */
11348  if( consdata1->weights[i] != consdata2->weights[i] )
11349  return FALSE;
11350  }
11351 
11352  return TRUE;
11353 }
11354 
11355 /** returns the hash value of the key */
11356 static
11357 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11358 {
11359 #ifndef NDEBUG
11360  SCIP* scip;
11361 #endif
11362  SCIP_CONSDATA* consdata;
11363  unsigned int hashval;
11364  int minidx;
11365  int mididx;
11366  int maxidx;
11367  int maxabsval;
11368 
11369  consdata = SCIPconsGetData((SCIP_CONS*)key);
11370  assert(consdata != NULL);
11371  assert(consdata->nvars > 0);
11372 
11373 #ifndef NDEBUG
11374  scip = (SCIP*)userptr;
11375  assert(scip != NULL);
11376 #endif
11377 
11378  /* sorts the constraints */
11379  sortItems(consdata);
11380 
11381  minidx = SCIPvarGetIndex(consdata->vars[0]);
11382  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11383  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11384  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11385 
11386  if( consdata->weights[0] > INT_MAX )
11387  maxabsval = 0;
11388  else
11389  maxabsval = (int) consdata->weights[0];
11390 
11391  /* hash value depends on vectors of variable indices */
11392  hashval = (consdata->nvars << 29) + (minidx << 22) + (mididx << 11) + maxidx + maxabsval; /*lint !e701*/
11393 
11394  return hashval;
11395 }
11396 
11397 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11398  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11399  */
11400 static
11402  SCIP* scip, /**< SCIP data structure */
11403  BMS_BLKMEM* blkmem, /**< block memory */
11404  SCIP_CONS** conss, /**< constraint set */
11405  int nconss, /**< number of constraints in constraint set */
11406  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11407  int* ndelconss /**< pointer to count number of deleted constraints */
11408  )
11409 {
11410  SCIP_HASHTABLE* hashtable;
11411  int hashtablesize;
11412  int c;
11413 
11414  assert(scip != NULL);
11415  assert(blkmem != NULL);
11416  assert(conss != NULL);
11417  assert(ndelconss != NULL);
11418 
11419  /* create a hash table for the constraint set */
11420  hashtablesize = SCIPcalcHashtableSize(10*nconss);
11421  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11422  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11423  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11424 
11425  /* check all constraints in the given set for redundancy */
11426  for( c = nconss - 1; c >= 0; --c )
11427  {
11428  SCIP_CONS* cons0;
11429  SCIP_CONS* cons1;
11430  SCIP_CONSDATA* consdata0;
11431 
11432  cons0 = conss[c];
11433 
11434  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11435  continue;
11436 
11437  consdata0 = SCIPconsGetData(cons0);
11438  assert(consdata0 != NULL);
11439  if( consdata0->nvars == 0 )
11440  {
11441  if( consdata0->capacity < 0 )
11442  {
11443  *cutoff = TRUE;
11444  goto TERMINATE;
11445  }
11446  else
11447  {
11448  SCIP_CALL( SCIPdelCons(scip, cons0) );
11449  ++(*ndelconss);
11450  continue;
11451  }
11452  }
11453 
11454  /* get constraint from current hash table with same variables and same weights as cons0 */
11455  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11456 
11457  if( cons1 != NULL )
11458  {
11459  SCIP_CONS* consstay;
11460  SCIP_CONS* consdel;
11461  SCIP_CONSDATA* consdata1;
11462 
11463  assert(SCIPconsIsActive(cons1));
11464  assert(!SCIPconsIsModifiable(cons1));
11465 
11466  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11467  * delete old constraints afterwards
11468  */
11469  consdata1 = SCIPconsGetData(cons1);
11470 
11471  assert(consdata1 != NULL);
11472  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11473 
11474  assert(consdata0->sorted && consdata1->sorted);
11475  assert(consdata0->vars[0] == consdata1->vars[0]);
11476  assert(consdata0->weights[0] == consdata1->weights[0]);
11477 
11478  SCIPdebugMessage("knapsack constraints <%s> and <%s> with equal coefficients\n",
11479  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11480 
11481  /* check which constraint has to stay; */
11482  if( consdata0->capacity < consdata1->capacity )
11483  {
11484  consstay = cons0;
11485  consdel = cons1;
11486 
11487  /* exchange consdel with consstay in hashtable */
11488  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11489  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11490  }
11491  else
11492  {
11493  consstay = cons1;
11494  consdel = cons0;
11495  }
11496 
11497  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11498  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11499 
11500  /* delete consdel */
11501  SCIP_CALL( SCIPdelCons(scip, consdel) );
11502  ++(*ndelconss);
11503 
11504  assert(SCIPconsIsActive(consstay));
11505  }
11506  else
11507  {
11508  /* no such constraint in current hash table: insert cons0 into hash table */
11509  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11510  }
11511  }
11512 
11513  TERMINATE:
11514  /* free hash table */
11515  SCIPhashtableFree(&hashtable);
11516 
11517  return SCIP_OKAY;
11518 }
11519 
11520 
11521 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11522  * and removes or changes constraint accordingly
11523  */
11524 static
11526  SCIP* scip, /**< SCIP data structure */
11527  SCIP_CONS** conss, /**< constraint set */
11528  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11529  int chkind, /**< index of constraint to check against all prior indices upto startind */
11530  int* ndelconss /**< pointer to count number of deleted constraints */
11531  )
11533  SCIP_CONS* cons0;
11534  SCIP_CONSDATA* consdata0;
11535  int c;
11536 
11537  assert(scip != NULL);
11538  assert(conss != NULL);
11539  assert(firstchange <= chkind);
11540  assert(ndelconss != NULL);
11541 
11542  /* get the constraint to be checked against all prior constraints */
11543  cons0 = conss[chkind];
11544  assert(cons0 != NULL);
11545  assert(SCIPconsIsActive(cons0));
11546  assert(!SCIPconsIsModifiable(cons0));
11547 
11548  consdata0 = SCIPconsGetData(cons0);
11549  assert(consdata0 != NULL);
11550  assert(consdata0->nvars >= 1);
11551  assert(consdata0->merged);
11552 
11553  /* sort the constraint */
11554  sortItems(consdata0);
11555 
11556  /* check constraint against all prior constraints */
11557  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11558  {
11559  SCIP_CONS* cons1;
11560  SCIP_CONSDATA* consdata1;
11561  SCIP_Bool iscons0incons1contained;
11562  SCIP_Bool iscons1incons0contained;
11563  SCIP_Real quotient;
11564  int v;
11565  int v0;
11566  int v1;
11567 
11568  cons1 = conss[c];
11569  assert(cons1 != NULL);
11570  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11571  continue;
11572 
11573  consdata1 = SCIPconsGetData(cons1);
11574  assert(consdata1 != NULL);
11575 
11576  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11577  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11578  continue;
11579 
11580  assert(consdata1->nvars >= 1);
11581  assert(consdata1->merged);
11582 
11583  /* sort the constraint */
11584  sortItems(consdata1);
11585 
11586  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11587 
11588  if( consdata0->nvars > consdata1->nvars )
11589  {
11590  iscons0incons1contained = FALSE;
11591  iscons1incons0contained = TRUE;
11592  v = consdata1->nvars - 1;
11593  }
11594  else if( consdata0->nvars < consdata1->nvars )
11595  {
11596  iscons0incons1contained = TRUE;
11597  iscons1incons0contained = FALSE;
11598  v = consdata0->nvars - 1;
11599  }
11600  else
11601  {
11602  iscons0incons1contained = TRUE;
11603  iscons1incons0contained = TRUE;
11604  v = consdata0->nvars - 1;
11605  }
11606 
11607  SCIPdebugMessage("preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11608 
11609  /* check consdata0 against consdata1:
11610  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11611  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11612  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11613  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11614  */
11615  v0 = consdata0->nvars - 1;
11616  v1 = consdata1->nvars - 1;
11617 
11618  while( v >= 0 )
11619  {
11620  assert(iscons0incons1contained || iscons1incons0contained);
11621 
11622  /* now there are more variables in cons1 left */
11623  if( v1 > v0 )
11624  {
11625  iscons1incons0contained = FALSE;
11626  if( !iscons0incons1contained )
11627  break;
11628  }
11629  /* now there are more variables in cons0 left */
11630  else if( v1 < v0 )
11631  {
11632  iscons0incons1contained = FALSE;
11633  if( !iscons1incons0contained )
11634  break;
11635  }
11636 
11637  assert(v == v0 || v == v1);
11638  assert(v0 >= 0);
11639  assert(v1 >= 0);
11640 
11641  /* both variables are the same */
11642  if( consdata0->vars[v0] == consdata1->vars[v1] )
11643  {
11644  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11645  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11646  {
11647  iscons1incons0contained = FALSE;
11648  if( !iscons0incons1contained )
11649  break;
11650  }
11651  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11652  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11653  {
11654  iscons0incons1contained = FALSE;
11655  if( !iscons1incons0contained )
11656  break;
11657  }
11658  --v0;
11659  --v1;
11660  --v;
11661  }
11662  else
11663  {
11664  /* both constraints have a variables which is not part of the other constraint, so stop */
11665  if( iscons0incons1contained && iscons1incons0contained )
11666  {
11667  iscons0incons1contained = FALSE;
11668  iscons1incons0contained = FALSE;
11669  break;
11670  }
11671  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11672  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11673  /* continue to the next variable */
11674  if( iscons0incons1contained )
11675  --v1;
11676  else
11677  --v0;
11678  }
11679  }
11680  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11681  * other
11682  */
11683  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11684 
11685  if( iscons1incons0contained )
11686  {
11687  SCIPdebugMessage("knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11688  SCIPdebugPrintCons(scip, cons1, NULL);
11689 
11690  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11691  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11692 
11693  SCIP_CALL( SCIPdelCons(scip, cons1) );
11694  ++(*ndelconss);
11695  }
11696  else if( iscons0incons1contained )
11697  {
11698  SCIPdebugMessage("knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11699  SCIPdebugPrintCons(scip, cons0, NULL);
11700 
11701  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11702  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11703 
11704  SCIP_CALL( SCIPdelCons(scip, cons0) );
11705  ++(*ndelconss);
11706  break;
11707  }
11708  }
11709 
11710  return SCIP_OKAY;
11711 }
11712 
11713 /*
11714  * Linear constraint upgrading
11715  */
11716 
11717 /** creates and captures a knapsack constraint out of a linear inequality */
11718 static
11720  SCIP* scip, /**< SCIP data structure */
11721  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11722  const char* name, /**< name of constraint */
11723  int nvars, /**< number of variables in the constraint */
11724  SCIP_VAR** vars, /**< array with variables of constraint entries */
11725  SCIP_Real* vals, /**< array with inequality coefficients */
11726  SCIP_Real lhs, /**< left hand side of inequality */
11727  SCIP_Real rhs, /**< right hand side of inequality */
11728  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11729  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11730  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11731  * Usually set to TRUE. */
11732  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11733  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11734  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11735  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11736  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11737  * Usually set to TRUE. */
11738  SCIP_Bool local, /**< is constraint only valid locally?
11739  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11740  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11741  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11742  * adds coefficients to this constraint. */
11743  SCIP_Bool dynamic, /**< is constraint subject to aging?
11744  * Usually set to FALSE. Set to TRUE for own cuts which
11745  * are separated as constraints. */
11746  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11747  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11748  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11749  * if it may be moved to a more global node?
11750  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11751  )
11752 {
11753  SCIP_VAR** transvars;
11754  SCIP_Longint* weights;
11755  SCIP_Longint capacity;
11756  SCIP_Longint weight;
11757  int mult;
11758  int v;
11759 
11760  assert(nvars == 0 || vars != NULL);
11761  assert(nvars == 0 || vals != NULL);
11762  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11763 
11764  /* get temporary memory */
11765  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11766  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11767 
11768  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11769  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11770  */
11771  if( SCIPisInfinity(scip, rhs) )
11772  {
11773  mult = -1;
11774  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11775  }
11776  else
11777  {
11778  mult = +1;
11779  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11780  }
11781 
11782  /* negate positive or negative variables */
11783  for( v = 0; v < nvars; ++v )
11784  {
11785  assert(SCIPisFeasIntegral(scip, vals[v]));
11786  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11787  if( weight > 0 )
11788  {
11789  transvars[v] = vars[v];
11790  weights[v] = weight;
11791  }
11792  else
11793  {
11794  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11795  weights[v] = -weight;
11796  capacity -= weight;
11797  }
11798  assert(transvars[v] != NULL);
11799  }
11800 
11801  /* create the constraint */
11802  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11803  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11804 
11805  /* free temporary memory */
11806  SCIPfreeBufferArray(scip, &weights);
11807  SCIPfreeBufferArray(scip, &transvars);
11808 
11809  return SCIP_OKAY;
11810 }
11811 
11812 /** tries to upgrade a linear constraint into a knapsack constraint */
11813 static
11814 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11815 { /*lint --e{715}*/
11816  SCIP_Bool upgrade;
11817 
11818  assert(upgdcons != NULL);
11819 
11820  /* check, if linear constraint can be upgraded to a knapsack constraint
11821  * - all variables must be binary
11822  * - all coefficients must be integral
11823  * - exactly one of the sides must be infinite
11824  */
11825  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11826  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11827  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11828 
11829  if( upgrade )
11830  {
11831  SCIPdebugMessage("upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11832 
11833  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11834  assert(!SCIPconsIsModifiable(cons));
11835  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11840  }
11841 
11842  return SCIP_OKAY;
11843 }
11844 
11845 
11846 /*
11847  * Callback methods of constraint handler
11848  */
11849 
11850 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11851 static
11852 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11853 { /*lint --e{715}*/
11854  assert(scip != NULL);
11855  assert(conshdlr != NULL);
11856  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11857 
11858  /* call inclusion method of constraint handler */
11860 
11861  *valid = TRUE;
11862 
11863  return SCIP_OKAY;
11864 }
11865 
11866 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11867 static
11868 SCIP_DECL_CONSFREE(consFreeKnapsack)
11869 { /*lint --e{715}*/
11870  SCIP_CONSHDLRDATA* conshdlrdata;
11871 
11872  /* free constraint handler data */
11873  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11874  assert(conshdlrdata != NULL);
11876  SCIPfreeMemory(scip, &conshdlrdata);
11877 
11878  SCIPconshdlrSetData(conshdlr, NULL);
11879 
11880  return SCIP_OKAY;
11881 }
11882 
11883 
11884 /** initialization method of constraint handler (called after problem was transformed) */
11885 static
11886 SCIP_DECL_CONSINIT(consInitKnapsack)
11887 { /*lint --e{715}*/
11888  SCIP_CONSHDLRDATA* conshdlrdata;
11889  int nvars;
11890 
11891  assert( scip != NULL );
11892  assert( conshdlr != NULL );
11894  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11895  assert(conshdlrdata != NULL);
11896 
11897  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
11898  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
11899 
11900  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->reals1, nvars) );
11901  BMSclearMemoryArray(conshdlrdata->reals1, nvars);
11902  conshdlrdata->reals1size = nvars;
11903 
11904  return SCIP_OKAY;
11905 }
11906 
11907 /** deinitialization method of constraint handler (called before transformed problem is freed) */
11908 static
11909 SCIP_DECL_CONSEXIT(consExitKnapsack)
11910 { /*lint --e{715}*/
11911  SCIP_CONSHDLRDATA* conshdlrdata;
11912 
11913  assert( scip != NULL );
11914  assert( conshdlr != NULL );
11915 
11916  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11917  assert(conshdlrdata != NULL);
11918 
11919  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->reals1);
11920  conshdlrdata->reals1size = 0;
11921 
11922  return SCIP_OKAY;
11923 }
11924 
11925 
11926 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
11927 static
11928 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
11929 { /*lint --e{715}*/
11930  SCIP_CONSHDLRDATA* conshdlrdata;
11931  int nvars;
11932 
11933  assert(scip != NULL);
11934  assert(conshdlr != NULL);
11935  assert(nconss == 0 || conss != NULL);
11936 
11937  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11938  assert(conshdlrdata != NULL);
11939 
11940  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
11941  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
11942 
11943  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->ints1, nvars) );
11944  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->ints2, nvars) );
11945  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->longints1, nvars) );
11946  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->longints2, nvars) );
11947  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->bools1, nvars) );
11948  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->bools2, nvars) );
11949  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->bools3, nvars) );
11950  SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrdata->bools4, nvars) );
11951 
11952  BMSclearMemoryArray(conshdlrdata->ints1, nvars);
11953  BMSclearMemoryArray(conshdlrdata->ints2, nvars);
11954  BMSclearMemoryArray(conshdlrdata->longints1, nvars);
11955  BMSclearMemoryArray(conshdlrdata->longints2, nvars);
11956  BMSclearMemoryArray(conshdlrdata->bools1, nvars);
11957  BMSclearMemoryArray(conshdlrdata->bools2, nvars);
11958  BMSclearMemoryArray(conshdlrdata->bools3, nvars);
11959  BMSclearMemoryArray(conshdlrdata->bools4, nvars);
11960 
11961  conshdlrdata->ints1size = nvars;
11962  conshdlrdata->ints2size = nvars;
11963  conshdlrdata->longints1size = nvars;
11964  conshdlrdata->longints2size = nvars;
11965  conshdlrdata->bools1size = nvars;
11966  conshdlrdata->bools2size = nvars;
11967  conshdlrdata->bools3size = nvars;
11968  conshdlrdata->bools4size = nvars;
11969 
11970  return SCIP_OKAY;
11971 }
11972 
11973 
11974 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11975 static
11976 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
11977 { /*lint --e{715}*/
11978  SCIP_CONSHDLRDATA* conshdlrdata;
11979  int c;
11980 
11981  assert(scip != NULL);
11982  assert(conshdlr != NULL);
11984  for( c = 0; c < nconss; ++c )
11985  {
11986  if( !SCIPconsIsDeleted(conss[c]) )
11987  {
11988  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
11989  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
11990  }
11991  }
11992 
11993  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11994  assert(conshdlrdata != NULL);
11995 
11996  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->ints1);
11997  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->ints2);
11998  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->longints1);
11999  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->longints2);
12000  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->bools1);
12001  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->bools2);
12002  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->bools3);
12003  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->bools4);
12004 
12005  conshdlrdata->ints1size = 0;
12006  conshdlrdata->ints2size = 0;
12007  conshdlrdata->longints1size = 0;
12008  conshdlrdata->longints2size = 0;
12009  conshdlrdata->bools1size = 0;
12010  conshdlrdata->bools2size = 0;
12011  conshdlrdata->bools3size = 0;
12012  conshdlrdata->bools4size = 0;
12013 
12014  return SCIP_OKAY;
12015 }
12016 
12017 
12018 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12019 static
12020 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12021 { /*lint --e{715}*/
12022  SCIP_CONSDATA* consdata;
12023  int c;
12024 
12025  assert( scip != NULL );
12026 
12027  /* release the rows of all constraints */
12028  for( c = 0; c < nconss; ++c )
12029  {
12030  consdata = SCIPconsGetData(conss[c]);
12031  assert(consdata != NULL);
12032 
12033  if( consdata->row != NULL )
12034  {
12035  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12036  }
12037  }
12038 
12039  return SCIP_OKAY;
12040 }
12041 
12042 /** frees specific constraint data */
12043 static
12044 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12045 { /*lint --e{715}*/
12046  SCIP_CONSHDLRDATA* conshdlrdata;
12047 
12048  assert(conshdlr != NULL);
12049  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12050 
12051  /* get event handler */
12052  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12053  assert(conshdlrdata != NULL);
12054  assert(conshdlrdata->eventhdlr != NULL);
12055 
12056  /* free knapsack constraint */
12057  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12058 
12059  return SCIP_OKAY;
12060 }
12061 
12062 /** transforms constraint data into data belonging to the transformed problem */
12063 static
12064 SCIP_DECL_CONSTRANS(consTransKnapsack)
12065 { /*lint --e{715}*/
12066  SCIP_CONSHDLRDATA* conshdlrdata;
12067  SCIP_CONSDATA* sourcedata;
12068  SCIP_CONSDATA* targetdata;
12069 
12070  assert(conshdlr != NULL);
12071  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12072  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12073  assert(sourcecons != NULL);
12074  assert(targetcons != NULL);
12075 
12076  sourcedata = SCIPconsGetData(sourcecons);
12077  assert(sourcedata != NULL);
12078  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12079 
12080  /* get event handler */
12081  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12082  assert(conshdlrdata != NULL);
12083  assert(conshdlrdata->eventhdlr != NULL);
12084 
12085  /* create target constraint data */
12086  SCIP_CALL( consdataCreate(scip, &targetdata, conshdlrdata->eventhdlr,
12087  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12088 
12089  /* create target constraint */
12090  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12091  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12092  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12093  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12094  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12095 
12096  return SCIP_OKAY;
12097 }
12098 
12099 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12100 static
12101 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12102 { /*lint --e{715}*/
12103  SCIP_Bool cutoff;
12104  int i;
12105 
12106  for( i = 0; i < nconss; i++ )
12107  {
12108  assert(SCIPconsIsInitial(conss[i]));
12109  SCIP_CALL( addRelaxation(scip, conss[i], NULL, &cutoff) );
12110  /* ignore cutoff: cannot return status */
12111  }
12112 
12113  return SCIP_OKAY;
12114 }
12115 
12116 /** separation method of constraint handler for LP solutions */
12117 static
12118 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12119 { /*lint --e{715}*/
12120  SCIP_CONSHDLRDATA* conshdlrdata;
12121  SCIP_Bool sepacardinality;
12122  SCIP_Bool cutoff;
12123 
12124  SCIP_Real loclowerbound;
12125  SCIP_Real glblowerbound;
12126  SCIP_Real cutoffbound;
12127  SCIP_Real maxbound;
12128 
12129  int depth;
12130  int nrounds;
12131  int sepafreq;
12132  int sepacardfreq;
12133  int ncuts;
12134  int maxsepacuts;
12135  int i;
12136 
12137  *result = SCIP_DIDNOTRUN;
12138 
12139  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12140  assert(conshdlrdata != NULL);
12141 
12142  depth = SCIPgetDepth(scip);
12143  nrounds = SCIPgetNSepaRounds(scip);
12144 
12145  SCIPdebugMessage("knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12146  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12147 
12148  /* only call the separator a given number of times at each node */
12149  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12150  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12151  return SCIP_OKAY;
12152 
12153  /* check, if we should additionally separate knapsack cuts */
12154  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12155  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12156  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12157  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12158 
12159  /* check dual bound to see if we want to produce knapsack cuts at this node */
12160  loclowerbound = SCIPgetLocalLowerbound(scip);
12161  glblowerbound = SCIPgetLowerbound(scip);
12162  cutoffbound = SCIPgetCutoffbound(scip);
12163  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12164  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12165  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12166 
12167  /* get the maximal number of cuts allowed in a separation round */
12168  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12169 
12170  *result = SCIP_DIDNOTFIND;
12171  ncuts = 0;
12172  cutoff = FALSE;
12173 
12174  /* separate useful constraints */
12175  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12176  {
12177  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12178  }
12179 
12180  /* adjust return value */
12181  if ( cutoff )
12182  *result = SCIP_CUTOFF;
12183  else if ( ncuts > 0 )
12184  *result = SCIP_SEPARATED;
12185 
12186  return SCIP_OKAY;
12187 }
12188 
12189 
12190 /** separation method of constraint handler for arbitrary primal solutions */
12191 static
12192 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12193 { /*lint --e{715}*/
12194  SCIP_CONSHDLRDATA* conshdlrdata;
12195  SCIP_Bool sepacardinality;
12196  SCIP_Bool cutoff;
12197 
12198  int depth;
12199  int nrounds;
12200  int sepafreq;
12201  int sepacardfreq;
12202  int ncuts;
12203  int maxsepacuts;
12204  int i;
12205 
12206  *result = SCIP_DIDNOTRUN;
12207 
12208  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12209  assert(conshdlrdata != NULL);
12210 
12211  depth = SCIPgetDepth(scip);
12212  nrounds = SCIPgetNSepaRounds(scip);
12213 
12214  SCIPdebugMessage("knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12215  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12216 
12217  /* only call the separator a given number of times at each node */
12218  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12219  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12220  return SCIP_OKAY;
12221 
12222  /* check, if we should additionally separate knapsack cuts */
12223  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12224  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12225  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12226  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12227 
12228  /* get the maximal number of cuts allowed in a separation round */
12229  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12230 
12231  *result = SCIP_DIDNOTFIND;
12232  ncuts = 0;
12233  cutoff = FALSE;
12234 
12235  /* separate useful constraints */
12236  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12237  {
12238  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12239  }
12240 
12241  /* adjust return value */
12242  if ( cutoff )
12243  *result = SCIP_CUTOFF;
12244  else if( ncuts > 0 )
12245  *result = SCIP_SEPARATED;
12246 
12247  return SCIP_OKAY;
12248 }
12249 
12250 
12251 /** constraint enforcing method of constraint handler for LP solutions */
12252 static
12253 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12254 { /*lint --e{715}*/
12255  SCIP_CONSHDLRDATA* conshdlrdata;
12256  SCIP_Bool violated;
12257  SCIP_Bool cutoff = FALSE;
12258  int maxncuts;
12259  int ncuts = 0;
12260  int i;
12261 
12262  *result = SCIP_FEASIBLE;
12263 
12264  SCIPdebugMessage("knapsack enforcement of %d/%d constraints\n", nusefulconss, nconss);
12265 
12266  /* get maximal number of cuts per round */
12267  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12268  assert(conshdlrdata != NULL);
12269  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12270 
12271  /* search for violated useful knapsack constraints */
12272  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
12273  {
12274  SCIP_CALL( checkCons(scip, conss[i], NULL, FALSE, FALSE, &violated) );
12275  if( violated )
12276  {
12277  /* add knapsack constraint as LP row to the LP */
12278  SCIP_CALL( addRelaxation(scip, conss[i], NULL, &cutoff) );
12279  ncuts++;
12280  }
12281  }
12282 
12283  /* as long as no violations were found, search for violated obsolete knapsack constraints */
12284  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
12285  {
12286  SCIP_CALL( checkCons(scip, conss[i], NULL, FALSE, FALSE, &violated) );
12287  if( violated )
12288  {
12289  /* add knapsack constraint as LP row to the LP */
12290  SCIP_CALL( addRelaxation(scip, conss[i], NULL, &cutoff) );
12291  ncuts++;
12292  }
12293  }
12294 
12295  /* adjust the result code */
12296  if ( cutoff )
12297  *result = SCIP_CUTOFF;
12298  else if ( ncuts > 0 )
12299  *result = SCIP_SEPARATED;
12300 
12301  return SCIP_OKAY;
12302 }
12303 
12304 /** constraint enforcing method of constraint handler for pseudo solutions */
12305 static
12306 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12307 { /*lint --e{715}*/
12308  SCIP_Bool violated;
12309  int i;
12310 
12311  for( i = 0; i < nconss; i++ )
12312  {
12313  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12314  if( violated )
12315  {
12316  *result = SCIP_INFEASIBLE;
12317  return SCIP_OKAY;
12318  }
12319  }
12320  *result = SCIP_FEASIBLE;
12321 
12322  return SCIP_OKAY;
12323 }
12324 
12325 /** feasibility check method of constraint handler for integral solutions */
12326 static
12327 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12328 { /*lint --e{715}*/
12329  SCIP_Bool violated;
12330  int i;
12331 
12332  for( i = 0; i < nconss; i++ )
12333  {
12334  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12335  if( violated )
12336  {
12337  *result = SCIP_INFEASIBLE;
12338  return SCIP_OKAY;
12339  }
12340  }
12341  *result = SCIP_FEASIBLE;
12342 
12343  return SCIP_OKAY;
12344 }
12345 
12346 /** domain propagation method of constraint handler */
12347 static
12348 SCIP_DECL_CONSPROP(consPropKnapsack)
12349 { /*lint --e{715}*/
12350  SCIP_CONSHDLRDATA* conshdlrdata;
12351  SCIP_Bool cutoff;
12352  SCIP_Bool redundant;
12353  SCIP_Bool inpresolve;
12354  int nfixedvars;
12355  int i;
12356 
12357  cutoff = FALSE;
12358  nfixedvars = 0;
12359 
12360  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12361  assert(conshdlrdata != NULL);
12362 
12363  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12364 
12365  /* process useful constraints */
12366  for( i = 0; i < nusefulconss && !cutoff; i++ )
12367  {
12368  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12369  * otherwise the multi-aggregation should be resolved
12370  */
12371  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12372  continue;
12373 #ifndef NDEBUG
12374  else if( !inpresolve )
12375  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12376 #endif
12377 
12378  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12379  }
12380 
12381  /* adjust result code */
12382  if( cutoff )
12383  *result = SCIP_CUTOFF;
12384  else if( nfixedvars > 0 )
12385  *result = SCIP_REDUCEDDOM;
12386  else
12387  *result = SCIP_DIDNOTFIND;
12388 
12389  return SCIP_OKAY;
12390 }
12391 
12392 /** presolving method of constraint handler */
12393 static
12394 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12395 { /*lint --e{574,715}*/
12396  SCIP_CONSHDLRDATA* conshdlrdata;
12397  SCIP_CONSDATA* consdata;
12398  SCIP_CONS* cons;
12399  SCIP_Bool cutoff;
12400  SCIP_Bool redundant;
12401  SCIP_Bool success;
12402  int oldnfixedvars;
12403  int oldnchgbds;
12404  int oldndelconss;
12405  int oldnaddconss;
12406  int oldnchgcoefs;
12407  int oldnchgsides;
12408  int firstchange;
12409  int c;
12410  SCIP_Bool newchanges;
12411 
12412  /* remember old preprocessing counters */
12413  cutoff = FALSE;
12414  oldnfixedvars = *nfixedvars;
12415  oldnchgbds = *nchgbds;
12416  oldndelconss = *ndelconss;
12417  oldnaddconss = *naddconss;
12418  oldnchgcoefs = *nchgcoefs;
12419  oldnchgsides = *nchgsides;
12420  firstchange = INT_MAX;
12421 
12422  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12423 
12424  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12425  assert(conshdlrdata != NULL);
12426 
12427  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12428  {
12429  int thisnfixedvars;
12430  int thisnchgbds;
12431 
12432  cons = conss[c];
12433  consdata = SCIPconsGetData(cons);
12434  assert(consdata != NULL);
12435 
12436  /* update data structures */
12437  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12438  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12439  {
12440  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12441  if( cutoff )
12442  break;
12443  }
12444 
12445  /* force presolving the constraint in the initial round */
12446  if( nrounds == 0 )
12447  consdata->presolvedtiming = 0;
12448  else if( consdata->presolvedtiming >= presoltiming )
12449  continue;
12450 
12451  SCIPdebugMessage("presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12452  SCIPdebugPrintCons(scip, cons, NULL);
12453  consdata->presolvedtiming = presoltiming;
12454 
12455  thisnfixedvars = *nfixedvars;
12456  thisnchgbds = *nchgbds;
12457 
12458  /* merge constraint, so propagation works better */
12459  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12460  if( cutoff )
12461  break;
12462 
12463  /* add cliques in the knapsack to the clique table */
12464  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12465  {
12466  SCIP_CALL( addCliques(scip, cons, &cutoff, nchgbds) );
12467  if( cutoff )
12468  break;
12469  }
12470 
12471  /* propagate constraint */
12472  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12473  if( cutoff )
12474  break;
12475  if( redundant )
12476  {
12477  (*ndelconss)++;
12478  continue;
12479  }
12480 
12481  /* remove again all fixed variables, if further fixings were found */
12482  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12483  {
12484  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12485  if( cutoff )
12486  break;
12487 
12488  thisnfixedvars = *nfixedvars;
12489  }
12490 
12491  if( !SCIPconsIsModifiable(cons) )
12492  {
12493  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12494  if( consdata->weightsum <= consdata->capacity )
12495  {
12496  SCIPdebugMessage(" -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12497  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12498  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12499  continue;
12500  }
12501 
12502  /* divide weights by their greatest common divisor */
12503  normalizeWeights(cons, nchgcoefs, nchgsides);
12504 
12505  /* try to simplify inequalities */
12506  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12507  {
12508  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12509  if( cutoff )
12510  break;
12511 
12512  if( SCIPconsIsDeleted(cons) )
12513  continue;
12514 
12515  /* remove again all fixed variables, if further fixings were found */
12516  if( *nfixedvars > thisnfixedvars )
12517  {
12518  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12519  if( cutoff )
12520  break;
12521  }
12522  }
12523 
12524  /* tighten capacity and weights */
12525  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12526  if( cutoff )
12527  break;
12528 
12529  if( SCIPconsIsActive(cons) )
12530  {
12531  if( conshdlrdata->dualpresolving && SCIPallowDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12532  {
12533  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12534  * dual reduction
12535  */
12536  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12537  if( redundant )
12538  continue;
12539  }
12540 
12541  /* check if knapsack constraint is parallel to objective function */
12542  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12543  }
12544  }
12545  /* remember the first changed constraint to begin the next aggregation round with */
12546  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12547  firstchange = c;
12548  }
12549 
12550  /* preprocess pairs of knapsack constraints */
12551  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12552  {
12553  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12554  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12555  }
12556 
12557  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12558  success = TRUE;
12559  else
12560  success = FALSE;
12561 
12562  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12563  {
12564  SCIP_Longint npaircomparisons;
12565 
12566  npaircomparisons = 0;
12567  oldndelconss = *ndelconss;
12568  oldnchgsides = *nchgsides;
12569  oldnchgcoefs = *nchgcoefs;
12570 
12571  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12572  {
12573  cons = conss[c];
12574  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12575  continue;
12576 
12577  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12578 
12579  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12580 
12581  if( npaircomparisons > NMINCOMPARISONS )
12582  {
12583  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12584  success = TRUE;
12585  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12586  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12587  break;
12588  oldndelconss = *ndelconss;
12589  oldnchgsides = *nchgsides;
12590  oldnchgcoefs = *nchgcoefs;
12591  npaircomparisons = 0;
12592  }
12593  }
12594  }
12595 
12596  if( cutoff )
12597  *result = SCIP_CUTOFF;
12598  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12599  *result = SCIP_SUCCESS;
12600  else
12601  *result = SCIP_DIDNOTFIND;
12602 
12603  return SCIP_OKAY;
12604 }
12605 
12606 /** propagation conflict resolving method of constraint handler */
12607 static
12608 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12609 { /*lint --e{715}*/
12610  SCIP_CONSDATA* consdata;
12611  SCIP_Longint capsum;
12612  int i;
12613 
12614  assert(result != NULL);
12616  consdata = SCIPconsGetData(cons);
12617  assert(consdata != NULL);
12618 
12619  /* check if we fixed a binary variable to one (due to negated clique) */
12620  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12621  {
12622  for( i = 0; i < consdata->nvars; ++i )
12623  {
12624  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12625  {
12626  assert( SCIPvarGetUbAtIndex(consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12627  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12628  break;
12629  }
12630  }
12631  assert(i < consdata->nvars);
12632  }
12633  else
12634  {
12635  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12636  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12637  * knapsack constraint, see one above call of SCIPinferBinvarCons
12638  */
12639  if( inferinfo < 0 )
12640  capsum = 0;
12641  else
12642  {
12643  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12644  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12645  */
12646  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12647  capsum = consdata->weights[inferinfo];
12648  else
12649  {
12650  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12651  {}
12652  assert(i < consdata->nvars);
12653  capsum = consdata->weights[i];
12654  }
12655  }
12656 
12657  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12658  * the capacity
12659  */
12660  if( capsum <= consdata->capacity )
12661  {
12662  for( i = 0; i < consdata->nvars; i++ )
12663  {
12664  if( SCIPvarGetLbAtIndex(consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12665  {
12666  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12667  capsum += consdata->weights[i];
12668  if( capsum > consdata->capacity )
12669  break;
12670  }
12671  }
12672  }
12673  }
12674 
12675  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12676  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12677  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12678  * used to fix variables to zero.
12679  *
12680  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12681  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12682  * one.
12683  */
12684  *result = SCIP_SUCCESS;
12685 
12686  return SCIP_OKAY;
12687 }
12688 
12689 /** variable rounding lock method of constraint handler */
12690 static
12691 SCIP_DECL_CONSLOCK(consLockKnapsack)
12692 { /*lint --e{715}*/
12693  SCIP_CONSDATA* consdata;
12694  int i;
12695 
12696  consdata = SCIPconsGetData(cons);
12697  assert(consdata != NULL);
12699  for( i = 0; i < consdata->nvars; i++)
12700  {
12701  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[i], nlocksneg, nlockspos) );
12702  }
12703 
12704  return SCIP_OKAY;
12705 }
12706 
12707 
12708 /** variable deletion method of constraint handler */
12709 static
12710 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
12711 {
12712  assert(scip != NULL);
12713  assert(conshdlr != NULL);
12714  assert(conss != NULL || nconss == 0);
12715 
12716  if( nconss > 0 )
12717  {
12718  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
12719  }
12720 
12721  return SCIP_OKAY;
12722 }
12723 
12724 /** constraint display method of constraint handler */
12725 static
12726 SCIP_DECL_CONSPRINT(consPrintKnapsack)
12727 { /*lint --e{715}*/
12728  SCIP_CONSDATA* consdata;
12729  int i;
12730 
12731  assert( scip != NULL );
12732  assert( conshdlr != NULL );
12733  assert( cons != NULL );
12734 
12735  consdata = SCIPconsGetData(cons);
12736  assert(consdata != NULL);
12737 
12738  for( i = 0; i < consdata->nvars; ++i )
12739  {
12740  if( i > 0 )
12741  SCIPinfoMessage(scip, file, " ");
12742  SCIPinfoMessage(scip, file, "%+"SCIP_LONGINT_FORMAT, consdata->weights[i]);
12743  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
12744  }
12745  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
12746 
12747  return SCIP_OKAY;
12748 }
12749 
12750 /** constraint copying method of constraint handler */
12751 static
12752 SCIP_DECL_CONSCOPY(consCopyKnapsack)
12753 { /*lint --e{715}*/
12754  SCIP_VAR** sourcevars;
12755  SCIP_Longint* weights;
12756  SCIP_Real* coefs;
12757  const char* consname;
12758  int nvars;
12759  int v;
12760 
12761  /* get variables and coefficients of the source constraint */
12762  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
12763  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
12764  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
12765 
12766  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
12767  for( v = 0; v < nvars; ++v )
12768  coefs[v] = (SCIP_Real) weights[v];
12769 
12770  if( name != NULL )
12771  consname = name;
12772  else
12773  consname = SCIPconsGetName(sourcecons);
12774 
12775  /* copy the logic using the linear constraint copy method */
12776  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
12777  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
12778  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
12779  assert(cons != NULL);
12780 
12781  SCIPfreeBufferArray(scip, &coefs);
12782 
12783  return SCIP_OKAY;
12784 }
12785 
12786 /** constraint parsing method of constraint handler */
12787 static
12788 SCIP_DECL_CONSPARSE(consParseKnapsack)
12789 { /*lint --e{715}*/
12790  SCIP_VAR* var;
12791  SCIP_Longint weight;
12792  SCIP_VAR** vars;
12793  SCIP_Longint* weights;
12794  SCIP_Longint capacity;
12795  char* endptr;
12796  int nread;
12797  int nvars;
12798  int varssize;
12799 
12800  assert(scip != NULL);
12801  assert(success != NULL);
12802  assert(str != NULL);
12803  assert(name != NULL);
12804  assert(cons != NULL);
12805 
12806  *success = TRUE;
12807 
12808  nvars = 0;
12809  varssize = 5;
12810  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
12811  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
12812 
12813  while( *str != '\0' )
12814  {
12815  /* try to parse coefficient, and stop if not successful (probably reached <=) */
12816  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
12817  break;
12818 
12819  str += nread;
12820 
12821  /* skip whitespace */
12822  while( isspace((int)*str) )
12823  ++str;
12824 
12825  /* parse variable name */
12826  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
12827  if( var == NULL )
12828  {
12829  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
12830  *success = FALSE;
12831  break;
12832  }
12833 
12834  str = endptr;
12835 
12836  /* store weight and variable */
12837  if( varssize <= nvars )
12838  {
12839  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
12840  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
12841  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
12842  }
12843 
12844  vars[nvars] = var;
12845  weights[nvars] = weight;
12846  ++nvars;
12847 
12848  /* skip whitespace */
12849  while( isspace((int)*str) )
12850  ++str;
12851  }
12852 
12853  if( *success )
12854  {
12855  if( strncmp(str, "<= ", 3) != 0 )
12856  {
12857  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
12858  *success = FALSE;
12859  }
12860  else
12861  {
12862  str += 3;
12863  }
12864  }
12865 
12866  if( *success )
12867  {
12868  if( sscanf(str, "%"SCIP_LONGINT_FORMAT, &capacity) != 1 )
12869  {
12870  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
12871  *success = FALSE;
12872  }
12873  else
12874  {
12875  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
12876  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
12877  }
12878  }
12879 
12880  SCIPfreeBufferArray(scip, &vars);
12881  SCIPfreeBufferArray(scip, &weights);
12882 
12883  return SCIP_OKAY;
12884 }
12885 
12886 /** constraint method of constraint handler which returns the variables (if possible) */
12887 static
12888 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
12889 { /*lint --e{715}*/
12890  SCIP_CONSDATA* consdata;
12891 
12892  consdata = SCIPconsGetData(cons);
12893  assert(consdata != NULL);
12894 
12895  if( varssize < consdata->nvars )
12896  (*success) = FALSE;
12897  else
12898  {
12899  assert(vars != NULL);
12900 
12901  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
12902  (*success) = TRUE;
12903  }
12904 
12905  return SCIP_OKAY;
12906 }
12907 
12908 /** constraint method of constraint handler which returns the number of variables (if possible) */
12909 static
12910 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
12911 { /*lint --e{715}*/
12912  SCIP_CONSDATA* consdata;
12913 
12914  consdata = SCIPconsGetData(cons);
12915  assert(consdata != NULL);
12916 
12917  (*nvars) = consdata->nvars;
12918  (*success) = TRUE;
12919 
12920  return SCIP_OKAY;
12921 }
12922 
12923 /*
12924  * Event handler
12925  */
12926 
12927 /** execution method of bound change event handler */
12928 static
12929 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
12930 { /*lint --e{715}*/
12931  assert(eventdata != NULL);
12932  assert(eventdata->consdata != NULL);
12933 
12934  switch( SCIPeventGetType(event) )
12935  {
12936  SCIP_CONSHDLR* conshdlr;
12937  SCIP_CONSHDLRDATA* conshdlrdata;
12938 
12940  eventdata->consdata->onesweightsum += eventdata->weight;
12941  eventdata->consdata->propagated = FALSE;
12942  eventdata->consdata->presolvedtiming = 0;
12943  break;
12945  eventdata->consdata->onesweightsum -= eventdata->weight;
12946 
12947  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12948  assert(conshdlr != NULL);
12949  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12950  assert(conshdlrdata != NULL);
12951 
12952  if( conshdlrdata->negatedclique )
12953  {
12954  /* if a variable fixed to 1 is unfixed, it is possible, that it can be fixed to 1 again */
12955  eventdata->consdata->propagated = FALSE;
12956  }
12957 
12958  break;
12960  /* if a variable fixed to 0 is unfixed, it is possible, that it can be fixed to 0 again */
12961  eventdata->consdata->propagated = FALSE;
12962  break;
12963  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
12964  if( !eventdata->consdata->existmultaggr )
12965  {
12966  SCIP_VAR* var = SCIPeventGetVar(event);
12967  assert(var != NULL);
12968 
12970  eventdata->consdata->existmultaggr = TRUE;
12971  }
12972  /*lint -fallthrough*/
12973  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
12974  eventdata->consdata->presolvedtiming = 0;
12975  break;
12977  eventdata->consdata->varsdeleted = TRUE;
12978  break;
12979  default:
12980  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
12981  return SCIP_INVALIDDATA;
12982  }
12983 
12984  return SCIP_OKAY;
12985 }
12986 
12987 
12988 /*
12989  * constraint specific interface methods
12990  */
12991 
12992 /** creates the handler for knapsack constraints and includes it in SCIP */
12994  SCIP* scip /**< SCIP data structure */
12995  )
12996 {
12997  SCIP_EVENTHDLRDATA* eventhdlrdata;
12998  SCIP_CONSHDLRDATA* conshdlrdata;
12999  SCIP_CONSHDLR* conshdlr;
13001  /* create knapsack constraint handler data */
13002  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
13003 
13004  /* include event handler for bound change events */
13005  eventhdlrdata = NULL;
13006  conshdlrdata->eventhdlr = NULL;
13007  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13008  eventExecKnapsack, eventhdlrdata) );
13009 
13010  /* get event handler for bound change events */
13011  if( conshdlrdata->eventhdlr == NULL )
13012  {
13013  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13014  return SCIP_PLUGINNOTFOUND;
13015  }
13016 
13017  /* include constraint handler */
13020  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13021  conshdlrdata) );
13022 
13023  assert(conshdlr != NULL);
13024 
13025  /* set non-fundamental callbacks via specific setter functions */
13026  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13027  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13028  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13029  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13030  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13031  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13032  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13033  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13034  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13035  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13036  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13037  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13038  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13039  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13040  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13041  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13043  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13044  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13046  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13047 
13048  if( SCIPfindConshdlr(scip,"linear") != NULL )
13049  {
13050  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13052  }
13053 
13054  /* add knapsack constraint handler parameters */
13055  SCIP_CALL( SCIPaddIntParam(scip,
13056  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13057  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13058  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, INT_MAX, NULL, NULL) );
13060  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13061  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13062  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13063  SCIP_CALL( SCIPaddIntParam(scip,
13064  "constraints/" CONSHDLR_NAME "/maxrounds",
13065  "maximal number of separation rounds per node (-1: unlimited)",
13066  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13067  SCIP_CALL( SCIPaddIntParam(scip,
13068  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13069  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13070  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13071  SCIP_CALL( SCIPaddIntParam(scip,
13072  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13073  "maximal number of cuts separated per separation round",
13074  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13075  SCIP_CALL( SCIPaddIntParam(scip,
13076  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13077  "maximal number of cuts separated per separation round in the root node",
13078  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13080  "constraints/" CONSHDLR_NAME "/disaggregation",
13081  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13082  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13084  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13085  "should presolving try to simplify knapsacks",
13086  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13088  "constraints/" CONSHDLR_NAME "/negatedclique",
13089  "should negated clique information be used in solving process",
13090  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13092  "constraints/" CONSHDLR_NAME "/presolpairwise",
13093  "should pairwise constraint comparison be performed in presolving?",
13094  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13096  "constraints/" CONSHDLR_NAME "/presolusehashing",
13097  "should hash table be used for detecting redundant constraints in advance",
13098  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13100  "constraints/" CONSHDLR_NAME "/dualpresolving",
13101  "should dual presolving steps be performed?",
13102  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13104  "constraints/" CONSHDLR_NAME "/usegubs",
13105  "should GUB information be used for separation?",
13106  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13108  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13109  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13110  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13112  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13113  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13114  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13115 
13116  return SCIP_OKAY;
13117 }
13118 
13119 /** creates and captures a knapsack constraint
13120  *
13121  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13122  */
13124  SCIP* scip, /**< SCIP data structure */
13125  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13126  const char* name, /**< name of constraint */
13127  int nvars, /**< number of items in the knapsack */
13128  SCIP_VAR** vars, /**< array with item variables */
13129  SCIP_Longint* weights, /**< array with item weights */
13130  SCIP_Longint capacity, /**< capacity of knapsack */
13131  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13132  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13133  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13134  * Usually set to TRUE. */
13135  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13136  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13137  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13138  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13139  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13140  * Usually set to TRUE. */
13141  SCIP_Bool local, /**< is constraint only valid locally?
13142  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13143  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13144  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13145  * adds coefficients to this constraint. */
13146  SCIP_Bool dynamic, /**< is constraint subject to aging?
13147  * Usually set to FALSE. Set to TRUE for own cuts which
13148  * are separated as constraints. */
13149  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13150  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13151  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13152  * if it may be moved to a more global node?
13153  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13154  )
13155 {
13156  SCIP_CONSHDLRDATA* conshdlrdata;
13157  SCIP_CONSHDLR* conshdlr;
13158  SCIP_CONSDATA* consdata;
13159 
13160  /* find the knapsack constraint handler */
13161  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13162  if( conshdlr == NULL )
13163  {
13164  SCIPerrorMessage("knapsack constraint handler not found\n");
13165  return SCIP_PLUGINNOTFOUND;
13166  }
13167 
13168  /* get event handler */
13169  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13170  assert(conshdlrdata != NULL);
13171  assert(conshdlrdata->eventhdlr != NULL);
13172 
13173  /* create constraint data */
13174  SCIP_CALL( consdataCreate(scip, &consdata, conshdlrdata->eventhdlr, nvars, vars, weights, capacity) );
13175 
13176  /* create constraint */
13177  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13178  local, modifiable, dynamic, removable, stickingatnode) );
13179 
13180  return SCIP_OKAY;
13181 }
13182 
13183 /** creates and captures a knapsack constraint
13184  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13185  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13186  *
13187  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13188  *
13189  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13190  */
13192  SCIP* scip, /**< SCIP data structure */
13193  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13194  const char* name, /**< name of constraint */
13195  int nvars, /**< number of items in the knapsack */
13196  SCIP_VAR** vars, /**< array with item variables */
13197  SCIP_Longint* weights, /**< array with item weights */
13198  SCIP_Longint capacity /**< capacity of knapsack */
13199  )
13200 {
13201  assert(scip != NULL);
13202 
13203  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13204  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13205 
13206  return SCIP_OKAY;
13207 }
13208 
13209 /** adds new item to knapsack constraint */
13211  SCIP* scip, /**< SCIP data structure */
13212  SCIP_CONS* cons, /**< constraint data */
13213  SCIP_VAR* var, /**< item variable */
13214  SCIP_Longint weight /**< item weight */
13215  )
13216 {
13217  assert(var != NULL);
13218 
13219  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13220  {
13221  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13222  return SCIP_INVALIDDATA;
13223  }
13224 
13225  SCIP_CALL( addCoef(scip, cons, var, weight) );
13226 
13227  return SCIP_OKAY;
13228 }
13229 
13230 /** gets the capacity of the knapsack constraint */
13232  SCIP* scip, /**< SCIP data structure */
13233  SCIP_CONS* cons /**< constraint data */
13234  )
13235 {
13236  SCIP_CONSDATA* consdata;
13237 
13239  {
13240  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13241  SCIPABORT();
13242  return 0; /*lint !e527*/
13243  }
13244 
13245  consdata = SCIPconsGetData(cons);
13246  assert(consdata != NULL);
13247 
13248  return consdata->capacity;
13249 }
13250 
13251 /** changes capacity of the knapsack constraint
13252  *
13253  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13254  */
13256  SCIP* scip, /**< SCIP data structure */
13257  SCIP_CONS* cons, /**< constraint data */
13258  SCIP_Longint capacity /**< new capacity of knapsack */
13259  )
13260 {
13261  SCIP_CONSDATA* consdata;
13263  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13264  {
13265  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13266  return SCIP_INVALIDDATA;
13267  }
13268 
13269  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13270  {
13271  SCIPerrorMessage("method can only be called during problem creation stage\n");
13272  return SCIP_INVALIDDATA;
13273  }
13274 
13275  consdata = SCIPconsGetData(cons);
13276  assert(consdata != NULL);
13277 
13278  consdata->capacity = capacity;
13279 
13280  return SCIP_OKAY;
13281 }
13282 
13283 /** gets the number of items in the knapsack constraint */
13285  SCIP* scip, /**< SCIP data structure */
13286  SCIP_CONS* cons /**< constraint data */
13287  )
13288 {
13289  SCIP_CONSDATA* consdata;
13290 
13292  {
13293  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13294  SCIPABORT();
13295  return -1; /*lint !e527*/
13296  }
13297 
13298  consdata = SCIPconsGetData(cons);
13299  assert(consdata != NULL);
13300 
13301  return consdata->nvars;
13302 }
13303 
13304 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13306  SCIP* scip, /**< SCIP data structure */
13307  SCIP_CONS* cons /**< constraint data */
13308  )
13309 {
13310  SCIP_CONSDATA* consdata;
13311 
13313  {
13314  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13315  SCIPABORT();
13316  return NULL; /*lint !e527*/
13317  }
13318 
13319  consdata = SCIPconsGetData(cons);
13320  assert(consdata != NULL);
13321 
13322  return consdata->vars;
13323 }
13324 
13325 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13327  SCIP* scip, /**< SCIP data structure */
13328  SCIP_CONS* cons /**< constraint data */
13329  )
13330 {
13331  SCIP_CONSDATA* consdata;
13332 
13334  {
13335  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13336  SCIPABORT();
13337  return NULL; /*lint !e527*/
13338  }
13339 
13340  consdata = SCIPconsGetData(cons);
13341  assert(consdata != NULL);
13342 
13343  return consdata->weights;
13344 }
13345 
13346 /** gets the dual solution of the knapsack constraint in the current LP */
13348  SCIP* scip, /**< SCIP data structure */
13349  SCIP_CONS* cons /**< constraint data */
13350  )
13351 {
13352  SCIP_CONSDATA* consdata;
13353 
13355  {
13356  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13357  SCIPABORT();
13358  return SCIP_INVALID; /*lint !e527*/
13359  }
13360 
13361  consdata = SCIPconsGetData(cons);
13362  assert(consdata != NULL);
13363 
13364  if( consdata->row != NULL )
13365  return SCIProwGetDualsol(consdata->row);
13366  else
13367  return 0.0;
13368 }
13369 
13370 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13372  SCIP* scip, /**< SCIP data structure */
13373  SCIP_CONS* cons /**< constraint data */
13374  )
13375 {
13376  SCIP_CONSDATA* consdata;
13377 
13379  {
13380  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13381  SCIPABORT();
13382  return SCIP_INVALID; /*lint !e527*/
13383  }
13384 
13385  consdata = SCIPconsGetData(cons);
13386  assert(consdata != NULL);
13387 
13388  if( consdata->row != NULL )
13389  return SCIProwGetDualfarkas(consdata->row);
13390  else
13391  return 0.0;
13392 }
13393 
13394 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13395  * the user must not modify the row!
13396  */
13398  SCIP* scip, /**< SCIP data structure */
13399  SCIP_CONS* cons /**< constraint data */
13400  )
13401 {
13402  SCIP_CONSDATA* consdata;
13403 
13405  {
13406  SCIPerrorMessage("constraint is not a knapsack\n");
13407  SCIPABORT();
13408  return NULL; /*lint !e527*/
13409  }
13410 
13411  consdata = SCIPconsGetData(cons);
13412  assert(consdata != NULL);
13413 
13414  return consdata->row;
13415 }
13416 
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip.c:33158
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:22777
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define KNAPSACKRELAX_MAXSCALE
Definition: cons_knapsack.c:71
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41572
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int * gubconssidx
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16861
#define DEFAULT_DETECTCUTOFFBOUND
Definition: cons_knapsack.c:97
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip.c:15853
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41685
static SCIP_RETCODE GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10698
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5878
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20526
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5588
GUBVarstatus
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:25588
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3111
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16443
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
#define CONSHDLR_DESC
Definition: cons_knapsack.c:40
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:55
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:48
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20589
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41648
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1567
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20573
static SCIP_DECL_CONSINIT(consInitKnapsack)
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11540
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16623
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41920
GUBCONSSTATUS * gubconsstatus
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10653
#define SCIP_MAXSTRLEN
Definition: def.h:201
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17420
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:5634
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip.c:30877
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5246
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:42
#define NULL
Definition: lpi_spx.cpp:130
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17113
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1125
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:42032
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17323
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7849
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17261
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
#define LINCONSUPGD_PRIORITY
Definition: cons_knapsack.c:60
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7681
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5334
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
Definition: scip.c:41202
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
Definition: scip.c:38589
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17067
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip.c:30859
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip.c:12302
SCIP_GUBCONS ** gubconss
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip.c:17196
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:129
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17291
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:24320
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip.h:20544
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
GUBConsstatus
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5818
#define CONSHDLR_SEPAFREQ
Definition: cons_knapsack.c:44
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:8948
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip.h:20528
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7909
#define FALSE
Definition: def.h:56
#define MAX_CLIQUELENGTH
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:49
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7778
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:8174
#define TRUE
Definition: def.h:55
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7640
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:46
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5795
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
#define SCIP_CALL(x)
Definition: def.h:266
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip.c:23083
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:42008
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:38561
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20556
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15737
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:57
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:34983
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16905
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
#define SCIP_LONGINT_MAX
Definition: def.h:113
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:10878
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip.c:25147
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7839
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7779
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:26237
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:30967
Constraint handler for the set partitioning / packing / covering constraints .
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:24949
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:633
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:20554
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:54
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11206
#define DEFAULT_PRESOLUSEHASHING
Definition: cons_knapsack.c:88
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:5359
SCIP_Real SCIPgetLowerbound(SCIP *scip)
Definition: scip.c:38393
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7769
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:1480
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition: scip.c:24720
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:95
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:5383
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3547
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:27658
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16562
#define DEFAULT_SEPACARDFREQ
Definition: cons_knapsack.c:73
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3573
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:16156
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:56
static SCIP_RETCODE GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3917
static SCIP_DECL_CONSPARSE(consParseKnapsack)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
#define DEFAULT_MAXROUNDS
Definition: cons_knapsack.c:74
#define DEFAULT_DISAGGREGATION
Definition: cons_knapsack.c:81
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36622
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip.c:17233
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define CONSHDLR_SEPAPRIORITY
Definition: cons_knapsack.c:41
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Constraint handler for knapsack constraints of the form , x binary and .
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20542
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip)
Definition: scip.c:24342
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41585
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16585
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:25560
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11541
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41984
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17303
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41709
enum GUBVarstatus GUBVARSTATUS
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7879
int SCIPgetNSepaRounds(SCIP *scip)
Definition: scip.c:37979
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:45
#define SCIPdebugPrintf
Definition: pub_message.h:80
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19526
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip.c:25300
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
#define DEFAULT_PRESOLPAIRWISE
Definition: cons_knapsack.c:91
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3897
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1157
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15859
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:41118
SCIPInterval sqrt(const SCIPInterval &x)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41598
#define DEFAULT_DUALPRESOLVING
Definition: cons_knapsack.c:96
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip.c:17163
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:5527
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:41353
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7620
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41907
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:16598
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:19126
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:63
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:41758
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:16664
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20669
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:5503
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:20562
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:11573
#define DEFAULT_NEGATEDCLIQUE
Definition: cons_knapsack.c:83
#define SCIP_EVENTTYPE_UBRELAXED
Definition: type_event.h:58
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16837
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3204
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:35020
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:41637
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5292
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:55
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:50
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5192
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:10742
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1719
GUBVARSTATUS * gubvarsstatus
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *cutoff)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:32131
#define KNAPSACKRELAX_MAXDNOM
Definition: cons_knapsack.c:70
#define DEFAULT_MAXSEPACUTSROOT
Definition: cons_knapsack.c:77
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:27629
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41946
static SCIP_DECL_CONSFREE(consFreeKnapsack)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7650
static SCIP_Bool checkSolveKnapsack(SCIP *scip, int nitems, SCIP_Longint *transweights, SCIP_Real *transprofits, int *items, SCIP_Longint *weights, SCIP_Real *solvals, SCIP_Bool modtransused)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:16884
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:41660
static SCIP_DECL_CONSEXIT(consExitKnapsack)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12080
void SCIPsortDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, int len)
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:17116
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41611
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:16873
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4751
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip.c:5749
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20193
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:16850
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17123
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:997
public data structures and miscellaneous methods
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip.c:5479
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:24772
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip.c:21810
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:25097
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16740
#define SCIP_Bool
Definition: def.h:53
#define MINGAINPERNMINCOMPARISONS
Definition: cons_knapsack.c:93
static SCIP_DECL_CONSPROP(consPropKnapsack)
#define MAXABSVBCOEF
Definition: cons_knapsack.c:85
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip.c:21859
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:50
#define DEFAULT_MAXSEPACUTS
Definition: cons_knapsack.c:76
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17313
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7859
#define DEFAULT_MAXCARDBOUNDDIST
Definition: cons_knapsack.c:78
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:27811
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip.c:12191
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:17329
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17281
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3123
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7869
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
#define DEFAULT_USEGUBS
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:7739
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
#define KNAPSACKRELAX_MAXDELTA
Definition: cons_knapsack.c:69
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:67
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:58
#define CONSHDLR_NAME
Definition: cons_knapsack.c:39
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16825
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5611
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip.h:20534
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17249
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:51
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16849
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
Constraint handler for linear constraints in their most general form, .
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:1627
int * gubvarsidx
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:38140
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1298
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41624
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1510
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36668
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5565
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11477
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17271
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20585
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17057
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:5772
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:18935
static SCIP_DECL_CONSLOCK(consLockKnapsack)
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:27834
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip.c:25072
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1281
#define REALABS(x)
Definition: def.h:151
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip.h:20545
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4521
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:41721
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:20593
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5455
#define DEFAULT_DETECTLOWERBOUND
#define HASHSIZE_KNAPSACKCONS
Definition: cons_knapsack.c:89
enum GUBConsstatus GUBCONSSTATUS
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:66
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41933
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19453
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16750
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:127
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7799
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:25047
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20299
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17409
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
#define MIN(x, y)
Definition: memory.c:67
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:27600
#define GUBCONSGROWVALUE
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28334
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41959
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:20568
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip.c:22008
#define SCIP_INVALID
Definition: def.h:147
#define SCIPfreeBuffer(scip, ptr)
Definition: scip.h:20595
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
Definition: cons_knapsack.c:75
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:27738
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:45
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:52
#define SCIP_Longint
Definition: def.h:112
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:7375
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:20571
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:5407
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:19399
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20597
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16730
int SCIPgetNObjVars(SCIP *scip)
Definition: scip.c:10926
#define SCIPdebug(x)
Definition: pub_message.h:74
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3101
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:24573
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONSDATA *consdata, SCIP_Longint weight)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:41422
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
#define USESUPADDLIFT
Definition: cons_knapsack.c:86
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
#define NMINCOMPARISONS
Definition: cons_knapsack.c:92
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:18948
static SCIP_DECL_CONSTRANS(consTransKnapsack)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41697
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:780
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3629
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5841
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11481
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:27864
#define SCIPABORT()
Definition: def.h:238
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
#define MAXCOVERSIZEITERLEWI
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7789
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7083
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:7819
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:3927
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3149
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:43
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:36834
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:47
#define DEFAULT_SIMPLIFYINEQUALITIES
Definition: cons_knapsack.c:82
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
#define SCIPallocBuffer(scip, ptr)
Definition: scip.h:20583
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)