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-2017 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 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
59  | SCIP_EVENTTYPE_UBTIGHTENED \
60  | SCIP_EVENTTYPE_VARFIXED \
61  | SCIP_EVENTTYPE_VARDELETED \
62  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
63 
64 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
65 
66 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
67 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
68 
69 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
70 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
71 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
72 
73 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
74 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
75 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
76 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
77 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
78 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
79  * to best node's dual bound for separating knapsack cuts */
80 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
81 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
82 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
83 
84 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
85 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
86 
87 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
88 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
89 
90 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
91 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
92 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
93  * comparison round */
94 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
95 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
96  * function defining an upper bound and prevent these constraints from
97  * entering the LP */
98 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
99  * function defining a lower bound and prevent these constraints from
100  * entering the LP */
101 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
102 
103 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
104 
105 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
106 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
107 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
108 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
109  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
110 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
111 
112 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
114 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
116 /*
117  * Data structures
118  */
119 
120 /** constraint handler data */
121 struct SCIP_ConshdlrData
122 {
123  int* ints1; /**< 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  int* ints2; /**< 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_Longint* longints1; /**< 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_Longint* longints2; /**< 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* bools1; /**< 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_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
134  * you have to clear it at the end, exists only in presolving stage */
135  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
136  * you have to clear it at the end, exists only in presolving stage */
137  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
138  * you have to clear it at the end, exists only in presolving stage */
139  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
140  * you have to clear it at the end */
141  int ints1size; /**< size of ints1 array */
142  int ints2size; /**< size of ints2 array */
143  int longints1size; /**< size of longints1 array */
144  int longints2size; /**< size of longints2 array */
145  int bools1size; /**< size of bools1 array */
146  int bools2size; /**< size of bools2 array */
147  int bools3size; /**< size of bools3 array */
148  int bools4size; /**< size of bools4 array */
149  int reals1size; /**< size of reals1 array */
150  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
151  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
152  * to best node's dual bound for separating knapsack cuts */
153  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
154  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
155  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
156  int maxsepacuts; /**< maximal number of cuts separated per separation round */
157  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
158  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
159  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
160  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
161  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
162  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
163  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
164  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
165  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
166  * function defining an upper bound and prevent these constraints from
167  * entering the LP */
168  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
169  * function defining a lower bound and prevent these constraints from
170  * entering the LP */
171  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
172  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
173  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
174  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
175 };
176 
177 
178 /** constraint data for knapsack constraints */
179 struct SCIP_ConsData
180 {
181  SCIP_VAR** vars; /**< variables in knapsack constraint */
182  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
183  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
184  int* cliquepartition; /**< clique indices of the clique partition */
185  int* negcliquepartition; /**< clique indices of the negated clique partition */
186  SCIP_ROW* row; /**< corresponding LP row */
187  int nvars; /**< number of variables in knapsack constraint */
188  int varssize; /**< size of vars, weights, and eventdata arrays */
189  int ncliques; /**< number of cliques in the clique partition */
190  int nnegcliques; /**< number of cliques in the negated clique partition */
191  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
192  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
193  SCIP_Longint capacity; /**< capacity of knapsack */
194  SCIP_Longint weightsum; /**< sum of all weights */
195  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
196  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
197  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
198  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
199  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
200  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
201  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
202  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
203  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
204 };
205 
206 /** event data for bound changes events */
207 struct SCIP_EventData
208 {
209  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
210  SCIP_Longint weight; /**< weight of variable */
211  int filterpos; /**< position of event in variable's event filter */
212 };
213 
214 
215 /** data structure to combine two sorting key values */
216 struct sortkeypair
217 {
218  SCIP_Real key1; /**< first sort key value */
219  SCIP_Real key2; /**< second sort key value */
220 };
221 typedef struct sortkeypair SORTKEYPAIR;
222 
223 /** status of GUB constraint */
224 enum GUBVarstatus
225 {
226  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
227  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
228  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
229  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
230  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
231  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
232 };
233 typedef enum GUBVarstatus GUBVARSTATUS;
235 /** status of variable in GUB constraint */
237 {
238  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
239  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
240  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
241  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
242  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
243  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
244 };
245 typedef enum GUBConsstatus GUBCONSSTATUS;
247 /** data structure of GUB constraints */
249 {
250  int* gubvars; /**< indices of GUB variables in knapsack constraint */
251  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
252  int ngubvars; /**< number of GUB variables */
253  int gubvarssize; /**< size of gubvars array */
254 };
255 typedef struct SCIP_GUBCons SCIP_GUBCONS;
257 /** data structure of a set of GUB constraints */
259 {
260  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
261  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
262  int ngubconss; /**< number of GUB constraints */
263  int nvars; /**< number of variables in knapsack constraint */
264  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
265  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
266 };
267 typedef struct SCIP_GUBSet SCIP_GUBSET;
269 /*
270  * Local methods
271  */
273 /** comparison method for two sorting key pairs */
274 static
275 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
276 {
277  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
278  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
279 
280  if( sortkeypair1->key1 < sortkeypair2->key1 )
281  return -1;
282  else if( sortkeypair1->key1 > sortkeypair2->key1 )
283  return +1;
284  else if( sortkeypair1->key2 < sortkeypair2->key2 )
285  return -1;
286  else if( sortkeypair1->key2 > sortkeypair2->key2 )
287  return +1;
288  else
289  return 0;
290 }
291 
292 /** creates event data */
293 static
295  SCIP* scip, /**< SCIP data structure */
296  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
297  SCIP_CONS* cons, /**< constraint */
298  SCIP_Longint weight /**< weight of variable */
299  )
300 {
301  assert(eventdata != NULL);
303  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
304  (*eventdata)->cons = cons;
305  (*eventdata)->weight = weight;
306 
307  return SCIP_OKAY;
308 }
309 
310 /** frees event data */
311 static
313  SCIP* scip, /**< SCIP data structure */
314  SCIP_EVENTDATA** eventdata /**< pointer to event data */
315  )
316 {
317  assert(eventdata != NULL);
318 
319  SCIPfreeBlockMemory(scip, eventdata);
321  return SCIP_OKAY;
322 }
323 
324 /** sorts items in knapsack with nonincreasing weights */
325 static
326 void sortItems(
327  SCIP_CONSDATA* consdata /**< constraint data */
328  )
329 {
330  assert(consdata != NULL);
331  assert(consdata->nvars == 0 || consdata->vars != NULL);
332  assert(consdata->nvars == 0 || consdata->weights != NULL);
333  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
334  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
335 
336  if( !consdata->sorted )
337  {
338  int pos;
339  int lastcliquenum;
340  int v;
341 
342  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
343  * sorted by first array in non-increasing order via sort template */
345  consdata->weights,
346  (void**)consdata->vars,
347  (void**)consdata->eventdata,
348  consdata->cliquepartition,
349  consdata->negcliquepartition,
350  consdata->nvars);
351 
352  v = consdata->nvars - 1;
353  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
354  while( v >= 0 )
355  {
356  int w = v - 1;
357 
358  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
359  --w;
360 
361  if( v - w > 1 )
362  {
363  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
365  (void**)(&(consdata->vars[w+1])),
366  (void**)(&(consdata->eventdata[w+1])),
367  &(consdata->cliquepartition[w+1]),
368  &(consdata->negcliquepartition[w+1]),
369  SCIPvarComp,
370  v - w);
371  }
372  v = w;
373  }
374 
375  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
376  if( consdata->cliquepartitioned )
377  {
378  lastcliquenum = 0;
379 
380  for( pos = 0; pos < consdata->nvars; ++pos )
381  {
382  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
383  * partition is invalid */
384  if( consdata->cliquepartition[pos] > lastcliquenum )
385  {
386  consdata->cliquepartitioned = FALSE;
387  break;
388  }
389  else if( consdata->cliquepartition[pos] == lastcliquenum )
390  ++lastcliquenum;
391  }
392  }
393  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
394  if( consdata->negcliquepartitioned )
395  {
396  lastcliquenum = 0;
397 
398  for( pos = 0; pos < consdata->nvars; ++pos )
399  {
400  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
401  * partition is invalid */
402  if( consdata->negcliquepartition[pos] > lastcliquenum )
403  {
404  consdata->negcliquepartitioned = FALSE;
405  break;
406  }
407  else if( consdata->negcliquepartition[pos] == lastcliquenum )
408  ++lastcliquenum;
409  }
410  }
411 
412  consdata->sorted = TRUE;
413  }
414 #ifndef NDEBUG
415  {
416  /* check if the weight array is sorted in a non-increasing way */
417  int i;
418  for( i = 0; i < consdata->nvars-1; ++i )
419  assert(consdata->weights[i] >= consdata->weights[i+1]);
420  }
421 #endif
422 }
423 
424 /** calculates a partition of the variables into cliques */
425 static
427  SCIP* scip, /**< SCIP data structure */
428  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
429  SCIP_CONSDATA* consdata, /**< constraint data */
430  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
431  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
432  )
433 {
434  SCIP_Bool ispartitionoutdated;
435  SCIP_Bool isnegpartitionoutdated;
436  assert(consdata != NULL);
437  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
438 
439  /* rerun eventually if number of global cliques increased considerably since last partition */
440  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
441  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
442 
443  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
444  {
445  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
446  consdata->cliquepartitioned = TRUE;
447  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
448  }
449 
450  /* rerun eventually if number of global cliques increased considerably since last negated partition */
451  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
452  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
453 
454  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
455  {
456  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
457  consdata->negcliquepartitioned = TRUE;
458  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
459  }
460  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
461  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
462 
463  return SCIP_OKAY;
464 }
465 
466 /** installs rounding locks for the given variable in the given knapsack constraint */
467 static
469  SCIP* scip, /**< SCIP data structure */
470  SCIP_CONS* cons, /**< knapsack constraint */
471  SCIP_VAR* var /**< variable of constraint entry */
472  )
473 {
474  /* rounding up may violate the constraint */
475  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
477  return SCIP_OKAY;
478 }
479 
480 /** removes rounding locks for the given variable in the given knapsack constraint */
481 static
483  SCIP* scip, /**< SCIP data structure */
484  SCIP_CONS* cons, /**< knapsack constraint */
485  SCIP_VAR* var /**< variable of constraint entry */
486  )
487 {
488  /* rounding up may violate the constraint */
489  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
491  return SCIP_OKAY;
492 }
493 
494 /** catches bound change events for variables in knapsack */
495 static
497  SCIP* scip, /**< SCIP data structure */
498  SCIP_CONS* cons, /**< constraint */
499  SCIP_CONSDATA* consdata, /**< constraint data */
500  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
501  )
502 {
503  int i;
505  assert(cons != NULL);
506  assert(consdata != NULL);
507  assert(consdata->nvars == 0 || consdata->vars != NULL);
508  assert(consdata->nvars == 0 || consdata->weights != NULL);
509  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
510 
511  for( i = 0; i < consdata->nvars; i++)
512  {
513  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
514  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
515  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
516  }
517 
518  return SCIP_OKAY;
519 }
520 
521 /** drops bound change events for variables in knapsack */
522 static
524  SCIP* scip, /**< SCIP data structure */
525  SCIP_CONSDATA* consdata, /**< constraint data */
526  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
527  )
528 {
529  int i;
530 
531  assert(consdata != NULL);
532  assert(consdata->nvars == 0 || consdata->vars != NULL);
533  assert(consdata->nvars == 0 || consdata->weights != NULL);
534  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
535 
536  for( i = 0; i < consdata->nvars; i++)
537  {
538  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
539  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
540  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
541  }
542 
543  return SCIP_OKAY;
544 }
545 
546 /** ensures, that vars and vals arrays can store at least num entries */
547 static
549  SCIP* scip, /**< SCIP data structure */
550  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
551  int num, /**< minimum number of entries to store */
552  SCIP_Bool transformed /**< is constraint from transformed problem? */
553  )
554 {
555  assert(consdata != NULL);
556  assert(consdata->nvars <= consdata->varssize);
557 
558  if( num > consdata->varssize )
559  {
560  int newsize;
561 
562  newsize = SCIPcalcMemGrowSize(scip, num);
563  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
564  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
565  if( transformed )
566  {
567  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
568  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
569  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
570  }
571  else
572  {
573  assert(consdata->eventdata == NULL);
574  assert(consdata->cliquepartition == NULL);
575  assert(consdata->negcliquepartition == NULL);
576  }
577  consdata->varssize = newsize;
578  }
579  assert(num <= consdata->varssize);
580 
581  return SCIP_OKAY;
582 }
583 
584 /** updates all weight sums for fixed and unfixed variables */
585 static
586 void updateWeightSums(
587  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
588  SCIP_VAR* var, /**< variable for this weight */
589  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
590  )
591 {
592  assert(consdata != NULL);
593  assert(var != NULL);
595  consdata->weightsum += weightdelta;
596 
597  if( SCIPvarGetLbLocal(var) > 0.5 )
598  consdata->onesweightsum += weightdelta;
599 
600  assert(consdata->weightsum >= 0);
601  assert(consdata->onesweightsum >= 0);
602 }
603 
604 /** creates knapsack constraint data */
605 static
607  SCIP* scip, /**< SCIP data structure */
608  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
609  int nvars, /**< number of variables in knapsack */
610  SCIP_VAR** vars, /**< variables of knapsack */
611  SCIP_Longint* weights, /**< weights of knapsack items */
612  SCIP_Longint capacity /**< capacity of knapsack */
613  )
614 {
615  int v;
616  SCIP_Longint constant;
617 
618  assert(consdata != NULL);
619 
620  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
621 
622  constant = 0L;
623  (*consdata)->vars = NULL;
624  (*consdata)->weights = NULL;
625  (*consdata)->nvars = 0;
626  if( nvars > 0 )
627  {
628  SCIP_VAR** varsbuffer;
629  SCIP_Longint* weightsbuffer;
630  int k;
631 
632  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
633  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
634 
635  k = 0;
636  for( v = 0; v < nvars; ++v )
637  {
638  assert(vars[v] != NULL);
639  assert(SCIPvarIsBinary(vars[v]));
640 
641  /* all weight have to be non negative */
642  assert( weights[v] >= 0 );
643 
644  if( weights[v] > 0 )
645  {
646  /* treat fixed variables as constants if problem compression is enabled */
647  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
648  {
649  /* only if the variable is fixed to 1, we add its weight to the constant */
650  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
651  constant += weights[v];
652  }
653  else
654  {
655  varsbuffer[k] = vars[v];
656  weightsbuffer[k] = weights[v];
657  ++k;
658  }
659  }
660  }
661  assert(k >= 0);
662 
663  (*consdata)->nvars = k;
664 
665  /* copy the active variables and weights into the constraint data structure */
666  if( k > 0 )
667  {
668  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
669  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
670  }
671 
672  /* free buffer storage */
673  SCIPfreeBufferArray(scip, &weightsbuffer);
674  SCIPfreeBufferArray(scip, &varsbuffer);
675  }
676 
677  /* capacity has to be greater or equal to zero */
678  assert(capacity >= 0);
679  assert(constant >= 0);
680 
681  (*consdata)->varssize = (*consdata)->nvars;
682  (*consdata)->capacity = capacity - constant;
683  (*consdata)->eventdata = NULL;
684  (*consdata)->cliquepartition = NULL;
685  (*consdata)->negcliquepartition = NULL;
686  (*consdata)->row = NULL;
687  (*consdata)->weightsum = 0;
688  (*consdata)->onesweightsum = 0;
689  (*consdata)->ncliques = 0;
690  (*consdata)->nnegcliques = 0;
691  (*consdata)->presolvedtiming = 0;
692  (*consdata)->sorted = FALSE;
693  (*consdata)->cliquepartitioned = FALSE;
694  (*consdata)->negcliquepartitioned = FALSE;
695  (*consdata)->ncliqueslastpart = -1;
696  (*consdata)->ncliqueslastnegpart = -1;
697  (*consdata)->merged = FALSE;
698  (*consdata)->cliquesadded = FALSE;
699  (*consdata)->varsdeleted = FALSE;
700  (*consdata)->existmultaggr = FALSE;
701 
702  /* get transformed variables, if we are in the transformed problem */
703  if( SCIPisTransformed(scip) )
704  {
705  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
706 
707  for( v = 0; v < (*consdata)->nvars; v++ )
708  {
709  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
710  assert(var != NULL);
711  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
712  }
713 
714  /* allocate memory for additional data structures */
715  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
716  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
717  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
718  }
719 
720  /* calculate sum of weights and capture variables */
721  for( v = 0; v < (*consdata)->nvars; ++v )
722  {
723  /* calculate sum of weights */
724  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
725 
726  /* capture variables */
727  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
728  }
729  return SCIP_OKAY;
730 }
731 
732 /** frees knapsack constraint data */
733 static
735  SCIP* scip, /**< SCIP data structure */
736  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
737  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
738  )
739 {
740  assert(consdata != NULL);
741  assert(*consdata != NULL);
743  if( (*consdata)->row != NULL )
744  {
745  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
746  }
747  if( (*consdata)->eventdata != NULL )
748  {
749  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
750  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
751  }
752  if( (*consdata)->negcliquepartition != NULL )
753  {
754  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
755  }
756  if( (*consdata)->cliquepartition != NULL )
757  {
758  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
759  }
760  if( (*consdata)->vars != NULL )
761  {
762  int v;
763 
764  /* release variables */
765  for( v = 0; v < (*consdata)->nvars; v++ )
766  {
767  assert((*consdata)->vars[v] != NULL);
768  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
769  }
770 
771  assert( (*consdata)->weights != NULL );
772  assert( (*consdata)->varssize > 0 );
773  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
774  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
775  }
776 
777  SCIPfreeBlockMemory(scip, consdata);
778 
779  return SCIP_OKAY;
780 }
781 
782 /** changes a single weight in knapsack constraint data */
783 static
784 void consdataChgWeight(
785  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
786  int item, /**< item number */
787  SCIP_Longint newweight /**< new weight of item */
788  )
789 {
790  SCIP_Longint oldweight;
791  SCIP_Longint weightdiff;
793  assert(consdata != NULL);
794  assert(0 <= item && item < consdata->nvars);
795 
796  oldweight = consdata->weights[item];
797  weightdiff = newweight - oldweight;
798  consdata->weights[item] = newweight;
799 
800 
801  /* update weight sums for all and fixed variables */
802  updateWeightSums(consdata, consdata->vars[item], weightdiff);
803 
804  if( consdata->eventdata != NULL )
805  {
806  assert(consdata->eventdata[item] != NULL);
807  assert(consdata->eventdata[item]->weight == oldweight);
808  consdata->eventdata[item]->weight = newweight;
809  }
810 
811  consdata->presolvedtiming = 0;
812  consdata->sorted = FALSE;
813 
814  /* recalculate cliques extraction after a weight was increased */
815  if( oldweight < newweight )
816  {
817  consdata->cliquesadded = FALSE;
818  }
819 }
820 
821 /** creates LP row corresponding to knapsack constraint */
822 static
824  SCIP* scip, /**< SCIP data structure */
825  SCIP_CONS* cons /**< knapsack constraint */
826  )
827 {
828  SCIP_CONSDATA* consdata;
829  int i;
830 
831  consdata = SCIPconsGetData(cons);
832  assert(consdata != NULL);
833  assert(consdata->row == NULL);
834 
835  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, SCIPconsGetHdlr(cons), SCIPconsGetName(cons),
836  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
838 
839  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
840  for( i = 0; i < consdata->nvars; ++i )
841  {
842  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
843  }
844  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
845 
846  return SCIP_OKAY;
847 }
848 
849 /** adds linear relaxation of knapsack constraint to the LP */
850 static
852  SCIP* scip, /**< SCIP data structure */
853  SCIP_CONS* cons, /**< knapsack constraint */
854  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
855  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
856  )
857 {
858  SCIP_CONSDATA* consdata;
860  assert( cutoff != NULL );
861  *cutoff = FALSE;
862 
863  consdata = SCIPconsGetData(cons);
864  assert(consdata != NULL);
865 
866  if( consdata->row == NULL )
867  {
868  SCIP_CALL( createRelaxation(scip, cons) );
869  }
870  assert(consdata->row != NULL);
871 
872  /* insert LP row as cut */
873  if( !SCIProwIsInLP(consdata->row) )
874  {
875  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
876  SCIPconsGetName(cons), consdata->capacity);
877  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
878  SCIP_CALL( SCIPaddCut(scip, sol, consdata->row, FALSE, cutoff) );
879  }
880 
881  return SCIP_OKAY;
882 }
883 
884 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
885 static
887  SCIP* scip, /**< SCIP data structure */
888  SCIP_CONS* cons, /**< constraint to check */
889  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
890  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
891  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
892  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
893  )
894 {
895  SCIP_CONSDATA* consdata;
896 
897  assert(violated != NULL);
898 
899  consdata = SCIPconsGetData(cons);
900  assert(consdata != NULL);
901 
902  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
903  SCIPconsGetName(cons), (void*)sol, checklprows);
904 
905  *violated = FALSE;
906 
907  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
908  {
909  SCIP_Real sum;
910  SCIP_Longint integralsum;
911  SCIP_Bool ishuge;
912  int v;
913 
914  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
915  * enforcement
916  */
917  if( sol == NULL )
918  {
919  SCIP_CALL( SCIPincConsAge(scip, cons) );
920  }
921 
922  sum = 0.0;
923  integralsum = 0;
924  /* we perform an more exact comparison if the capacity does not exceed the huge value */
925  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
926  {
927  ishuge = TRUE;
928 
929  /* sum over all weight times the corresponding solution value */
930  for( v = consdata->nvars - 1; v >= 0; --v )
931  {
932  assert(SCIPvarIsBinary(consdata->vars[v]));
933  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
934  }
935  }
936  else
937  {
938  ishuge = FALSE;
939 
940  /* sum over all weight for which the variable has a solution value of 1 in feastol */
941  for( v = consdata->nvars - 1; v >= 0; --v )
942  {
943  assert(SCIPvarIsBinary(consdata->vars[v]));
944 
945  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
946  integralsum += consdata->weights[v];
947  }
948  }
949 
950  if( (!ishuge && integralsum > consdata->capacity) || (ishuge && SCIPisFeasGT(scip, sum, (SCIP_Real)consdata->capacity)) )
951  {
952  *violated = TRUE;
953 
954  /* only reset constraint age if we are in enforcement */
955  if( sol == NULL )
956  {
957  SCIP_CALL( SCIPresetConsAge(scip, cons) );
958  }
959 
960  if( printreason )
961  {
962  SCIP_Real viol = ishuge ? sum : (SCIP_Real)integralsum;
963 
964  viol -= consdata->capacity;
965  assert(viol > 0);
966 
967  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
968 
969  SCIPinfoMessage(scip, NULL, ";\n");
970  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", viol);
971  }
972  }
973  }
974 
975  return SCIP_OKAY;
976 }
977 
978 /* IDX computes the integer index for the optimal solution array */
979 #define IDX(j,d) ((j)*(intcap)+(d))
980 
981 /** solves knapsack problem in maximization form exactly using dynamic programming;
982  * if needed, one can provide arrays to store all selected items and all not selected items
983  *
984  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part as well
985  */
987  SCIP* scip, /**< SCIP data structure */
988  int nitems, /**< number of available items */
989  SCIP_Longint* weights, /**< item weights */
990  SCIP_Real* profits, /**< item profits */
991  SCIP_Longint capacity, /**< capacity of knapsack */
992  int* items, /**< item numbers */
993  int* solitems, /**< array to store items in solution, or NULL */
994  int* nonsolitems, /**< array to store items not in solution, or NULL */
995  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
996  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
997  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
998  SCIP_Bool* success /**< pointer to store if an error occured during solving
999  * (normally a memory problem) */
1000  )
1001 {
1002  SCIP_RETCODE retcode;
1003  SCIP_Real* tempsort;
1004  SCIP_Real* optvalues;
1005  int intcap;
1006  int d;
1007  int j;
1008  SCIP_Longint weightsum;
1009  int* myitems;
1010  SCIP_Longint* myweights;
1011  int* allcurrminweight;
1012  SCIP_Real* myprofits;
1013  int nmyitems;
1014  SCIP_Longint gcd;
1015  SCIP_Longint minweight;
1016  SCIP_Longint maxweight;
1017  int currminweight;
1018  SCIP_Longint greedycap;
1019  SCIP_Longint greedysolweight;
1020  SCIP_Real greedysolvalue;
1021  SCIP_Bool eqweights;
1022  SCIP_Bool isoptimal;
1023  const size_t maxsize_t = (size_t)(-1);
1024 
1025  assert(weights != NULL);
1026  assert(profits != NULL);
1027  assert(capacity >= 0);
1028  assert(items != NULL);
1029  assert(nitems >= 0);
1030  assert(success != NULL);
1031 
1032  *success = TRUE;
1033 
1034 #ifndef NDEBUG
1035  for( j = nitems - 1; j >= 0; --j )
1036  assert(weights[j] >= 0);
1037 #endif
1038 
1039  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1040 
1041  /* initializing solution value */
1042  if( solval != NULL )
1043  *solval = 0.0;
1044 
1045  /* produces optimal solution by following the table */
1046  if( solitems != NULL)
1047  {
1048  assert(items != NULL);
1049  assert(nsolitems != NULL);
1050  assert(nonsolitems != NULL);
1051  assert(nnonsolitems != NULL);
1052 
1053  *nnonsolitems = 0;
1054  *nsolitems = 0;
1055  }
1056 
1057  /* allocate temporary memory */
1058  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1059  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1060  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1061  nmyitems = 0;
1062  weightsum = 0;
1063  minweight = SCIP_LONGINT_MAX;
1064  maxweight = 0;
1065 
1066  /* remove unnecessary items */
1067  for( j = 0; j < nitems; ++j )
1068  {
1069  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1070  /* items does not fit */
1071  if( weights[j] > capacity )
1072  {
1073  if( solitems != NULL)
1074  {
1075  nonsolitems[*nnonsolitems] = items[j];
1076  ++(*nnonsolitems);
1077  }
1078  }
1079  /* items we does not want */
1080  else if( profits[j] <= 0.0 )
1081  {
1082  if( solitems != NULL)
1083  {
1084  nonsolitems[*nnonsolitems] = items[j];
1085  ++(*nnonsolitems);
1086  }
1087  }
1088  /* items which always fit */
1089  else if( weights[j] == 0 )
1090  {
1091  if( solitems != NULL)
1092  {
1093  solitems[*nsolitems] = items[j];
1094  ++(*nsolitems);
1095  }
1096  if( solval != NULL )
1097  *solval += profits[j];
1098  }
1099  /* all important items */
1100  else
1101  {
1102  myweights[nmyitems] = weights[j];
1103  myprofits[nmyitems] = profits[j];
1104  myitems[nmyitems] = items[j];
1105 
1106  /* remember smallest item */
1107  if( myweights[nmyitems] < minweight )
1108  minweight = myweights[nmyitems];
1109 
1110  /* remember bigest item */
1111  if( myweights[nmyitems] > maxweight )
1112  maxweight = myweights[nmyitems];
1113 
1114  weightsum += myweights[nmyitems];
1115  ++nmyitems;
1116  }
1117  }
1118 
1119  /* no item is left then goto end */
1120  if( nmyitems == 0 )
1121  {
1122  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1123 
1124  goto TERMINATE;
1125  }
1126  /* if all items fit, we also do not need to do the expensive stuff later on */
1127  else if( weightsum > 0 && weightsum <= capacity )
1128  {
1129  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1130 
1131  for( j = nmyitems - 1; j >= 0; --j )
1132  {
1133  if( solitems != NULL )
1134  {
1135  solitems[*nsolitems] = myitems[j];
1136  ++(*nsolitems);
1137  }
1138  if( solval != NULL )
1139  *solval += myprofits[j];
1140  }
1141 
1142  goto TERMINATE;
1143  }
1144 
1145  assert(minweight > 0);
1146  assert(maxweight > 0);
1147 
1148  if( maxweight > 1 )
1149  {
1150  /* determine greatest common divisor */
1151  gcd = myweights[nmyitems - 1];
1152  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1153  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1154 
1155  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1156 
1157  /* divide by greatest common divisor */
1158  if( gcd > 1 )
1159  {
1160  eqweights = TRUE;
1161  for( j = nmyitems - 1; j >= 0; --j )
1162  {
1163  myweights[j] /= gcd;
1164  eqweights = eqweights && (myweights[j] == 1);
1165  }
1166  capacity /= gcd;
1167  minweight /= gcd;
1168  }
1169  else
1170  eqweights = FALSE;
1171  }
1172  else
1173  {
1174  assert(maxweight == 1);
1175  eqweights = TRUE;
1176  }
1177 
1178  assert(minweight <= capacity);
1179 
1180  /* only one item fits, than take the best */
1181  if( minweight > capacity / 2 )
1182  {
1183  int p;
1184 
1185  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1186 
1187  p = nmyitems - 1;
1188 
1189  /* find best item */
1190  for( j = nmyitems - 2; j >= 0; --j )
1191  if( myprofits[j] > myprofits[p] )
1192  p = j;
1193 
1194  /* update solution information */
1195  if( solitems != NULL)
1196  {
1197  solitems[*nsolitems] = myitems[p];
1198  ++(*nsolitems);
1199  for( j = nmyitems - 1; j >= 0; --j )
1200  if( j != p )
1201  {
1202  nonsolitems[*nnonsolitems] = myitems[j];
1203  ++(*nnonsolitems);
1204  }
1205  }
1206  /* update solution value */
1207  if( solval != NULL )
1208  *solval += myprofits[p];
1209 
1210  goto TERMINATE;
1211  }
1212 
1213  /* all items have the same weight, than take the best */
1214  if( eqweights )
1215  {
1216  SCIP_Real addval;
1217 
1218  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1219 
1220  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1221 
1222  addval = 0.0;
1223  /* update solution information */
1224  if( solitems != NULL || solval != NULL )
1225  {
1226  SCIP_Longint i;
1227 
1228  /* if all items would fit we had handled this case before */
1229  assert((SCIP_Longint) nmyitems > capacity);
1230 
1231  /* take the first best items into the solution */
1232  for( i = capacity - 1; i >= 0; --i )
1233  {
1234  if( solitems != NULL)
1235  {
1236  assert(nonsolitems != NULL);
1237  solitems[*nsolitems] = myitems[i];
1238  ++(*nsolitems);
1239  }
1240  addval += myprofits[i];
1241  }
1242 
1243  if( solitems != NULL)
1244  {
1245  assert(nonsolitems != NULL);
1246 
1247  /* the rest are not in the solution */
1248  for( i = nmyitems - 1; i >= capacity; --i )
1249  {
1250  nonsolitems[*nnonsolitems] = myitems[i];
1251  ++(*nnonsolitems);
1252  }
1253  }
1254  }
1255  /* update solution value */
1256  if( solval != NULL )
1257  {
1258  assert(addval > 0.0);
1259  *solval += addval;
1260  }
1261 
1262  goto TERMINATE;
1263  }
1264 
1265  /* in the following table we do not need the first minweight columns */
1266  capacity -= (minweight - 1);
1267 
1268  /* we can only handle integers */
1269  if( capacity >= INT_MAX )
1270  {
1271  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1272 
1273  *success = FALSE;
1274  goto TERMINATE;
1275  }
1276  assert(capacity < INT_MAX);
1277 
1278  intcap = (int)capacity;
1279  assert(intcap >= 0);
1280  assert(nmyitems > 0);
1281  assert(sizeof(size_t) >= sizeof(int)); /* no following conversion should be messed up */
1282 
1283  /* this condition checks if we will try to allocate a correct number of bytes and do not have an overflow, while
1284  * computing the size for the allocation
1285  */
1286  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*/
1287  {
1288  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1289 
1290  *success = FALSE;
1291  goto TERMINATE;
1292  }
1293 
1294  /* allocate temporary memory and check for memory exceeding */
1295  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1296  if( retcode == SCIP_NOMEMORY )
1297  {
1298  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1299 
1300  *success = FALSE;
1301  goto TERMINATE;
1302  }
1303  else
1304  {
1305  SCIP_CALL( retcode );
1306  }
1307 
1308  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1309  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only use for greedy solution
1310  */
1311  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1312  for( j = nmyitems - 1; j >= 0; --j )
1313  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1314 
1315  SCIPsortDownRealLongRealInt(tempsort, myweights, myprofits, myitems, nmyitems);
1316 
1317  /* initialize values for greedy solution information */
1318  greedysolweight = 0;
1319  greedysolvalue = 0.0;
1320  isoptimal = TRUE;
1321  greedycap = capacity + (minweight - 1);
1322 
1323  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1324 
1325  /* determine greedy solution */
1326  for( j = 0; j < nmyitems; ++j )
1327  {
1328  assert(myweights[j] <= greedycap);
1329 
1330  /* take all fitting items */
1331  if( myweights[j] + greedysolweight <= greedycap )
1332  {
1333  /* update greedy solution weight and value */
1334  greedysolweight += myweights[j];
1335  greedysolvalue += myprofits[j];
1336  continue;
1337  }
1338  else if( greedysolweight < greedycap )
1339  isoptimal = FALSE;
1340  break;
1341  }
1342  assert(greedysolweight > 0);
1343  assert(greedysolvalue > 0.0);
1344 
1345  /* greedy solution is optimal */
1346  if( isoptimal )
1347  {
1348  assert(greedysolweight == greedycap);
1349 
1350  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1351 
1352  greedysolweight = 0;
1353 
1354  /* update solution information */
1355  if( solitems != NULL)
1356  {
1357  /* take the first best items into the solution */
1358  for( j = 0; j < nmyitems; ++j )
1359  {
1360  /* take all fitting items */
1361  if( myweights[j] + greedysolweight <= greedycap )
1362  {
1363  solitems[*nsolitems] = myitems[j];
1364  ++(*nsolitems);
1365  greedysolweight += myweights[j];
1366  }
1367  else
1368  {
1369  nonsolitems[*nnonsolitems] = myitems[j];
1370  ++(*nnonsolitems);
1371  }
1372  }
1373  }
1374  /* update solution value */
1375  if( solval != NULL )
1376  {
1377  assert(greedysolvalue > 0.0);
1378  *solval += greedysolvalue;
1379  }
1380 
1381  SCIPfreeBufferArray(scip, &tempsort);
1382  SCIPfreeBufferArray(scip, &optvalues);
1383 
1384  goto TERMINATE;
1385  }
1386 
1387  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1388 
1389  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1390  * all values entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1391  * invalid, a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1392  * 'nmyitem' values
1393  */
1394  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1395  assert(myweights[0] - minweight < INT_MAX);
1396  currminweight = (int) (myweights[0] - minweight);
1397  allcurrminweight[0] = currminweight;
1398 
1399  /* fills first row of dynamic programming table with optimal values */
1400  for( d = currminweight; d < intcap; ++d )
1401  optvalues[d] = myprofits[0];
1402  /* fills dynamic programming table with optimal values */
1403  for( j = 1; j < nmyitems; ++j )
1404  {
1405  int intweight;
1406 
1407  /* compute important part of weight, which will be represented in the table */
1408  intweight = (int)(myweights[j] - minweight);
1409  assert(0 <= intweight && intweight < intcap);
1410 
1411  /* copy all nonzeros from row above */
1412  for( d = currminweight; d < intweight && d < intcap; ++d )
1413  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1414 
1415  /* update corresponding row */
1416  for( d = intweight; d < intcap; ++d )
1417  {
1418  /* if index d is smaller the the current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should
1419  * be 0
1420  */
1421  if( d < currminweight )
1422  {
1423  optvalues[IDX(j,d)] = myprofits[j];
1424  }
1425  else
1426  {
1427  SCIP_Real sumprofit;
1428 
1429  if( d - myweights[j] < currminweight )
1430  sumprofit = myprofits[j];
1431  else
1432  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1433 
1434  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1435  }
1436  }
1437  /* update currminweight */
1438  if( intweight < currminweight )
1439  currminweight = intweight;
1440 
1441  allcurrminweight[j] = currminweight;
1442  }
1443 
1444  /* update optimal solution by following the table */
1445  if( solitems != NULL)
1446  {
1447  d = intcap - 1;
1448 
1449  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1450 
1451  /* insert all items in (non-) solution vector */
1452  for( j = nmyitems - 1; j > 0; --j )
1453  {
1454  /* if we cannot find any item anymore which is in our solution stop, if the following condition holds this
1455  * means all remaining items does not fit anymore
1456  */
1457  if( d < allcurrminweight[j] )
1458  {
1459  /* we cannot have exceeded our capacity */
1460  assert((SCIP_Longint) d >= -minweight);
1461  break;
1462  }
1463  /* collect solution items, first condition means that no next item can fit anymore, but this does */
1464  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1465  {
1466  solitems[*nsolitems] = myitems[j];
1467  ++(*nsolitems);
1468 
1469  /* check that we do not have an underflow */
1470  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1471  d = (int)(d - myweights[j]);
1472  }
1473  /* collect non-solution items */
1474  else
1475  {
1476  nonsolitems[*nnonsolitems] = myitems[j];
1477  ++(*nnonsolitems);
1478  }
1479  }
1480 
1481  /* insert remaining items */
1482  if( d >= allcurrminweight[j] )
1483  {
1484  assert(j == 0);
1485  solitems[*nsolitems] = myitems[j];
1486  ++(*nsolitems);
1487  }
1488  else
1489  {
1490  assert(j >= 0);
1491  assert(d < allcurrminweight[j]);
1492 
1493  for( ; j >= 0; --j )
1494  {
1495  nonsolitems[*nnonsolitems] = myitems[j];
1496  ++(*nnonsolitems);
1497  }
1498  }
1499 
1500  assert(*nsolitems + *nnonsolitems == nitems);
1501  }
1502 
1503  /* update solution value */
1504  if( solval != NULL )
1505  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1506 
1507  SCIPfreeBufferArray(scip, &allcurrminweight);
1508 
1509  /* free all temporary memory */
1510  SCIPfreeBufferArray(scip, &tempsort);
1511  SCIPfreeBufferArray(scip, &optvalues);
1512 
1513  TERMINATE:
1514  SCIPfreeBufferArray(scip, &myitems);
1515  SCIPfreeBufferArray(scip, &myprofits);
1516  SCIPfreeBufferArray(scip, &myweights);
1517 
1518  return SCIP_OKAY;
1519 }
1520 
1521 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1522  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1523  * selected items
1524  */
1526  SCIP* scip, /**< SCIP data structure */
1527  int nitems, /**< number of available items */
1528  SCIP_Longint* weights, /**< item weights */
1529  SCIP_Real* profits, /**< item profits */
1530  SCIP_Longint capacity, /**< capacity of knapsack */
1531  int* items, /**< item numbers */
1532  int* solitems, /**< array to store items in solution, or NULL */
1533  int* nonsolitems, /**< array to store items not in solution, or NULL */
1534  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1535  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1536  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1537  )
1538 {
1539  SCIP_Real* tempsort;
1540  SCIP_Longint solitemsweight;
1541  SCIP_Real* realweights;
1542  int j;
1543  int criticalindex;
1544 
1545  assert(weights != NULL);
1546  assert(profits != NULL);
1547  assert(capacity >= 0);
1548  assert(items != NULL);
1549  assert(nitems >= 0);
1550 
1551  if( solitems != NULL )
1552  {
1553  *nsolitems = 0;
1554  *nnonsolitems = 0;
1555  }
1556  if( solval != NULL )
1557  *solval = 0.0;
1558 
1559  /* initialize data for median search */
1560  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1561  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1562  for( j = nitems - 1; j >= 0; --j )
1563  {
1564  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1565  realweights[j] = (SCIP_Real)weights[j];
1566 
1567  }
1568 
1569  /* partially sort indices such that all elements that are larger than the break item appear first */
1570  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1571 
1572  /* selects items as long as they fit into the knapsack */
1573  solitemsweight = 0;
1574  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1575  {
1576  if( solitems != NULL )
1577  {
1578  solitems[*nsolitems] = items[j];
1579  (*nsolitems)++;
1580  }
1581  if( solval != NULL )
1582  (*solval) += profits[j];
1583  solitemsweight += weights[j];
1584  }
1585  for( ; j < nitems && solitems != NULL; j++ )
1586  {
1587  nonsolitems[*nnonsolitems] = items[j];
1588  (*nnonsolitems)++;
1589  }
1590 
1591  SCIPfreeBufferArray(scip, &realweights);
1592  SCIPfreeBufferArray(scip, &tempsort);
1593 
1594  return SCIP_OKAY;
1595 }
1596 
1597 #ifdef SCIP_DEBUG
1598 /** prints all nontrivial GUB constraints and their LP solution values */
1599 static
1600 void GUBsetPrint(
1601  SCIP* scip, /**< SCIP data structure */
1602  SCIP_GUBSET* gubset, /**< GUB set data structure */
1603  SCIP_VAR** vars, /**< variables in knapsack constraint */
1604  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1605  )
1606 {
1607  int nnontrivialgubconss;
1608  int c;
1609 
1610  nnontrivialgubconss = 0;
1611 
1612  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1613 
1614  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1615  for( c = 0; c < gubset->ngubconss; c++ )
1616  {
1617  SCIP_Real gubsolval;
1618 
1619  assert(gubset->gubconss[c]->ngubvars >= 0);
1620 
1621  /* nontrivial GUB */
1622  if( gubset->gubconss[c]->ngubvars > 1 )
1623  {
1624  int v;
1625 
1626  gubsolval = 0.0;
1627  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1628 
1629  /* print GUB var */
1630  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1631  {
1632  int currentvar;
1633 
1634  currentvar = gubset->gubconss[c]->gubvars[v];
1635  if( solvals != NULL )
1636  {
1637  gubsolval += solvals[currentvar];
1638  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1639  }
1640  else
1641  {
1642  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1643  }
1644  }
1645 
1646  /* check whether LP solution satisfies the GUB constraint */
1647  if( solvals != NULL )
1648  {
1649  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1650  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1651  }
1652  else
1653  {
1654  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1655  }
1656  nnontrivialgubconss++;
1657  }
1658  }
1659 
1660  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1661 }
1662 #endif
1663 
1664 /** creates an empty GUB constraint */
1665 static
1667  SCIP* scip, /**< SCIP data structure */
1668  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1669  )
1670 {
1671  assert(scip != NULL);
1672  assert(gubcons != NULL);
1673 
1674  /* allocate memory for GUB constraint data structures */
1675  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1676  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1677  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1678  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1679 
1680  (*gubcons)->ngubvars = 0;
1681 
1682  return SCIP_OKAY;
1683 }
1684 
1685 /** frees GUB constraint */
1686 static
1688  SCIP* scip, /**< SCIP data structure */
1689  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1690  )
1691 {
1692  assert(scip != NULL);
1693  assert(gubcons != NULL);
1694  assert((*gubcons)->gubvars != NULL);
1695  assert((*gubcons)->gubvarsstatus != NULL);
1696 
1697  /* free allocated memory */
1698  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1699  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1700  SCIPfreeBuffer(scip, gubcons);
1701 
1702  return SCIP_OKAY;
1703 }
1704 
1705 /** adds variable to given GUB constraint */
1706 static
1708  SCIP* scip, /**< SCIP data structure */
1709  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1710  int var /**< index of given variable in knapsack constraint */
1711  )
1712 {
1713  assert(scip != NULL);
1714  assert(gubcons != NULL);
1715  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1716  assert(gubcons->gubvars != NULL);
1717  assert(gubcons->gubvarsstatus != NULL);
1718  assert(var >= 0);
1719 
1720  /* add variable to GUB constraint */
1721  gubcons->gubvars[gubcons->ngubvars] = var;
1722  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1723  gubcons->ngubvars++;
1724 
1725  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1726  if( gubcons->ngubvars == gubcons->gubvarssize )
1727  {
1728  int newlen;
1729 
1730  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1731  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1732  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1733 
1734  gubcons->gubvarssize = newlen;
1735  }
1736 
1737  return SCIP_OKAY;
1738 }
1739 
1740 /** deletes variable from its current GUB constraint */
1741 static
1743  SCIP* scip, /**< SCIP data structure */
1744  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1745  int var, /**< index of given variable in knapsack constraint */
1746  int gubvarsidx /**< index of the variable in its current GUB constraint */
1747  )
1748 {
1749  assert(scip != NULL);
1750  assert(gubcons != NULL);
1751  assert(var >= 0);
1752  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1753  assert(gubcons->ngubvars >= gubvarsidx+1);
1754  assert(gubcons->gubvars[gubvarsidx] == var);
1755 
1756  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1757  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1758  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1759  gubcons->ngubvars--;
1760 
1761  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1762  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1763  {
1764  int newlen;
1765 
1766  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1767 
1768  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1769  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1770 
1771  gubcons->gubvarssize = newlen;
1772  }
1773 
1774  return SCIP_OKAY;
1775 }
1776 
1777 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1778 static
1780  SCIP* scip, /**< SCIP data structure */
1781  SCIP_GUBSET* gubset, /**< GUB set data structure */
1782  SCIP_VAR** vars, /**< variables in knapsack constraint */
1783  int var, /**< index of given variable in knapsack constraint */
1784  int oldgubcons, /**< index of old GUB constraint of given variable */
1785  int newgubcons /**< index of new GUB constraint of given variable */
1786  )
1788  int oldgubvaridx;
1789  int replacevar;
1790  int j;
1791 
1792  assert(scip != NULL);
1793  assert(gubset != NULL);
1794  assert(var >= 0);
1795  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1796  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1797  assert(oldgubcons != newgubcons);
1798  assert(gubset->gubconssidx[var] == oldgubcons);
1799  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1800  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1801 
1802  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1803 
1804  oldgubvaridx = gubset->gubvarsidx[var];
1805 
1806  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1807  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1808 
1809  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1810  * replacement variable is given by old position of the deleted variable
1811  */
1812  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1813  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1814  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1815 
1816  /* add variable to the end of new GUB constraint */
1817  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1818  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1819 
1820  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1821  gubset->gubconssidx[var] = newgubcons;
1822  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1823 
1824  /* delete old GUB constraint if it became empty */
1825  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1826  {
1827  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1828 #ifdef SCIP_DEBUG
1829  GUBsetPrint(scip, gubset, vars, NULL);
1830 #endif
1831 
1832  /* free old GUB constraint */
1833  SCIP_CALL( GUBconsFree(scip, &gubset->gubconss[oldgubcons]) );
1834 
1835  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1836  if( oldgubcons != gubset->ngubconss-1 )
1837  {
1838  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1839  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1840 
1841  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1842  * replacement GUB is given by old position of the deleted GUB
1843  */
1844  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1845  {
1846  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1847  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1848  }
1849  }
1850 
1851  /* update number of GUB constraints */
1852  gubset->ngubconss--;
1853 
1854  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1855  * (because it was at the end of the GUB constraint array)
1856  */
1857  assert(gubset->gubconssidx[var] == newgubcons
1858  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1859  }
1860 #ifndef NDEBUG
1861  else
1862  assert(gubset->gubconssidx[var] == newgubcons);
1863 #endif
1864 
1865  return SCIP_OKAY;
1866 }
1867 
1868 /** swaps two variables in the same GUB constraint */
1869 static
1870 void GUBsetSwapVars(
1871  SCIP* scip, /**< SCIP data structure */
1872  SCIP_GUBSET* gubset, /**< GUB set data structure */
1873  int var1, /**< first variable to be swapped */
1874  int var2 /**< second variable to be swapped */
1875  )
1876 {
1877  int gubcons;
1878  int var1idx;
1879  GUBVARSTATUS var1status;
1880  int var2idx;
1881  GUBVARSTATUS var2status;
1882 
1883  assert(scip != NULL);
1884  assert(gubset != NULL);
1885 
1886  gubcons = gubset->gubconssidx[var1];
1887  assert(gubcons == gubset->gubconssidx[var2]);
1888 
1889  /* nothing to be done if both variables are the same */
1890  if( var1 == var2 )
1891  return;
1892 
1893  /* swap index and status of variables in GUB constraint */
1894  var1idx = gubset->gubvarsidx[var1];
1895  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1896  var2idx = gubset->gubvarsidx[var2];
1897  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1898 
1899  gubset->gubvarsidx[var1] = var2idx;
1900  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1901  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1902 
1903  gubset->gubvarsidx[var2] = var1idx;
1904  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1905  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1906 }
1907 
1908 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1909 static
1911  SCIP* scip, /**< SCIP data structure */
1912  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1913  int nvars, /**< number of variables in the knapsack constraint */
1914  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1915  SCIP_Longint capacity /**< capacity of knapsack */
1916  )
1917 {
1918  int i;
1919 
1920  assert(scip != NULL);
1921  assert(gubset != NULL);
1922  assert(nvars > 0);
1923  assert(weights != NULL);
1924  assert(capacity >= 0);
1925 
1926  /* allocate memory for GUB set data structures */
1927  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1928  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1929  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1930  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1931  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1932  (*gubset)->ngubconss = nvars;
1933  (*gubset)->nvars = nvars;
1934 
1935  /* initialize the set of GUB constraints */
1936  for( i = 0; i < nvars; i++ )
1937  {
1938  /* assign each variable to a new (trivial) GUB constraint */
1939  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1940  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1941 
1942  /* set status of GUB constraint to initial */
1943  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1944 
1945  (*gubset)->gubconssidx[i] = i;
1946  (*gubset)->gubvarsidx[i] = 0;
1947  assert((*gubset)->gubconss[i]->ngubvars == 1);
1948 
1949  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1950  if( weights[i] > capacity )
1951  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1952 
1953  }
1954 
1955  return SCIP_OKAY;
1956 }
1957 
1958 /** frees GUB set data structure */
1959 static
1961  SCIP* scip, /**< SCIP data structure */
1962  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1963  )
1964 {
1965  int i;
1966 
1967  assert(scip != NULL);
1968  assert(gubset != NULL);
1969  assert((*gubset)->gubconss != NULL);
1970  assert((*gubset)->gubconsstatus != NULL);
1971  assert((*gubset)->gubconssidx != NULL);
1972  assert((*gubset)->gubvarsidx != NULL);
1973 
1974  /* free all GUB constraints */
1975  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1976  {
1977  assert((*gubset)->gubconss[i] != NULL);
1978  SCIP_CALL( GUBconsFree(scip, &(*gubset)->gubconss[i]) );
1979  }
1980 
1981  /* free allocated memory */
1982  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1983  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1984  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1985  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
1986  SCIPfreeBuffer(scip, gubset);
1987 
1988  return SCIP_OKAY;
1989 }
1990 
1991 #ifndef NDEBUG
1992 /** checks whether GUB set data structure is consistent */
1993 static
1995  SCIP* scip, /**< SCIP data structure */
1996  SCIP_GUBSET* gubset, /**< GUB set data structure */
1997  SCIP_VAR** vars /**< variables in the knapsack constraint */
1998  )
1999 {
2000  int i;
2001  int gubconsidx;
2002  int gubvaridx;
2003  SCIP_VAR* var1;
2004  SCIP_VAR* var2;
2005  SCIP_Bool var1negated;
2006  SCIP_Bool var2negated;
2007 
2008  assert(scip != NULL);
2009  assert(gubset != NULL);
2010 
2011  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2012 
2013  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2014  for( i = 0; i < gubset->nvars; i++ )
2015  {
2016  gubconsidx = gubset->gubconssidx[i];
2017  gubvaridx = gubset->gubvarsidx[i];
2018 
2019  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2020  {
2021  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2022  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2023  }
2024  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2025  }
2026 
2027  /* checks for each GUB whether all pairs of its variables have a common clique */
2028  for( i = 0; i < gubset->ngubconss; i++ )
2029  {
2030  int j;
2031 
2032  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2033  {
2034  int k;
2035 
2036  /* get corresponding active problem variable */
2037  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2038  var1negated = FALSE;
2039  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2040 
2041  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2042  {
2043  /* get corresponding active problem variable */
2044  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2045  var2negated = FALSE;
2046  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2047 
2048  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2049  {
2050  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2051  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2052  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2053  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2054  SCIPvarGetName(var1), k,
2055  SCIPvarGetName(var2));
2056  }
2057 
2058  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2059  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2060  }
2061  }
2062  }
2063  SCIPdebugMsg(scip, " --> successful\n");
2064 
2065  return SCIP_OKAY;
2066 }
2067 #endif
2068 
2069 /** calculates a partition of the given set of binary variables into cliques;
2070  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2071  * were assigned to the same clique;
2072  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2073  * the preceding variables was assigned to clique i-1;
2074  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2075  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2076  */
2077 
2078 static
2080  SCIP*const scip, /**< SCIP data structure */
2081  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2082  int const nvars, /**< number of variables in the clique */
2083  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2084  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2085  SCIP_Real* solvals /**< solution values of all given binary variables */
2086  )
2088  SCIP_VAR** tmpvars;
2089  SCIP_VAR** cliquevars;
2090  SCIP_Bool* cliquevalues;
2091  SCIP_Bool* tmpvalues;
2092  int* varseq;
2093  int* sortkeys;
2094  int ncliquevars;
2095  int maxncliquevarscomp;
2096  int nignorevars;
2097  int nvarsused;
2098  int i;
2099 
2100  assert(scip != NULL);
2101  assert(nvars == 0 || vars != NULL);
2102  assert(nvars == 0 || cliquepartition != NULL);
2103  assert(ncliques != NULL);
2104 
2105  if( nvars == 0 )
2106  {
2107  *ncliques = 0;
2108  return SCIP_OKAY;
2109  }
2110 
2111  /* allocate temporary memory for storing the variables of the current clique */
2112  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2113  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2114  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2115  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2116  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2117  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2118 
2119  /* initialize the cliquepartition array with -1 */
2120  /* initialize the tmpvalues array */
2121  for( i = nvars - 1; i >= 0; --i )
2122  {
2123  tmpvalues[i] = TRUE;
2124  cliquepartition[i] = -1;
2125  }
2126 
2127  /* get corresponding active problem variables */
2128  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2129 
2130  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2131  * by nondecreasing number of cliques the variables are in
2132  */
2133  nignorevars = 0;
2134  nvarsused = 0;
2135  for( i = 0; i < nvars; i++ )
2136  {
2137  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2138  {
2139  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2140  varseq[nvars-1-nignorevars] = i;
2141  nignorevars++;
2142  }
2143  else
2144  {
2145  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2146  varseq[nvarsused] = i;
2147  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2148  nvarsused++;
2149  }
2150  }
2151  assert(nvarsused + nignorevars == nvars);
2152 
2153  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2154  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2155 
2156  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2157 
2158  /* calculate the clique partition */
2159  *ncliques = 0;
2160  for( i = 0; i < nvars; ++i )
2161  {
2162  if( cliquepartition[varseq[i]] == -1 )
2163  {
2164  int j;
2165 
2166  /* variable starts a new clique */
2167  cliquepartition[varseq[i]] = *ncliques;
2168  cliquevars[0] = tmpvars[varseq[i]];
2169  cliquevalues[0] = tmpvalues[varseq[i]];
2170  ncliquevars = 1;
2171 
2172  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2173  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2174  */
2175  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2176  {
2177  /* greedily fill up the clique */
2178  for( j = i + 1; j < nvarsused; ++j )
2179  {
2180  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2181  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2182  {
2183  int k;
2184 
2185  /* check if every variable in the actual clique is in clique with the new variable */
2186  for( k = ncliquevars - 1; k >= 0; --k )
2187  {
2188  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2189  cliquevalues[k], TRUE) )
2190  break;
2191  }
2192 
2193  if( k == -1 )
2194  {
2195  /* put the variable into the same clique */
2196  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2197  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2198  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2199  ++ncliquevars;
2200  }
2201  }
2202  }
2203  }
2204 
2205  /* this clique is finished */
2206  ++(*ncliques);
2207  }
2208  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2209 
2210  /* break if we reached the maximal number of comparisons */
2211  if( i * nvars > maxncliquevarscomp )
2212  break;
2213  }
2214  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2215  for( ; i < nvars; ++i )
2216  {
2217  if( cliquepartition[varseq[i]] == -1 )
2218  {
2219  cliquepartition[varseq[i]] = *ncliques;
2220  ++(*ncliques);
2221  }
2222  }
2223 
2224  /* free temporary memory */
2225  SCIPfreeBufferArray(scip, &sortkeys);
2226  SCIPfreeBufferArray(scip, &varseq);
2227  SCIPfreeBufferArray(scip, &tmpvars);
2228  SCIPfreeBufferArray(scip, &tmpvalues);
2229  SCIPfreeBufferArray(scip, &cliquevalues);
2230  SCIPfreeBufferArray(scip, &cliquevars);
2231 
2232  return SCIP_OKAY;
2233 }
2234 
2235 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2236 static
2238  SCIP* scip, /**< SCIP data structure */
2239  SCIP_GUBSET* gubset, /**< GUB set data structure */
2240  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2241  SCIP_Real* solvals /**< solution values of all knapsack variables */
2242  )
2243 {
2244  int* cliquepartition;
2245  int* gubfirstvar;
2246  int ncliques;
2247  int currentgubconsidx;
2248  int newgubconsidx;
2249  int cliqueidx;
2250  int nvars;
2251  int i;
2252 
2253  assert(scip != NULL);
2254  assert(gubset != NULL);
2255  assert(vars != NULL);
2256 
2257  nvars = gubset->nvars;
2258  assert(nvars >= 0);
2259 
2260  /* allocate temporary memory for clique partition */
2261  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2262 
2263  /* compute sophisticated clique partition */
2264  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2265 
2266  /* allocate temporary memory for GUB set data structure */
2267  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2268 
2269  /* translate GUB partition into GUB set data structure */
2270  for( i = 0; i < ncliques; i++ )
2271  {
2272  /* initialize first variable for every GUB */
2273  gubfirstvar[i] = -1;
2274  }
2275  /* move every knapsack variable into GUB defined by clique partition */
2276  for( i = 0; i < nvars; i++ )
2277  {
2278  assert(cliquepartition[i] >= 0);
2279 
2280  cliqueidx = cliquepartition[i];
2281  currentgubconsidx = gubset->gubconssidx[i];
2282  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2283 
2284  /* variable is first element in GUB constraint defined by clique partition */
2285  if( gubfirstvar[cliqueidx] == -1 )
2286  {
2287  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2288  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2289  */
2290  assert(gubset->gubvarsidx[i] == 0);
2291  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2292 
2293  /* remember the first variable found for the current GUB */
2294  gubfirstvar[cliqueidx] = i;
2295  }
2296  /* variable is additional element of GUB constraint defined by clique partition */
2297  else
2298  {
2299  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2300 
2301  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2302  * first variable of this GUB constraint
2303  */
2304  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2305  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2306  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2307 
2308  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2309  }
2310  }
2311 
2312 #ifdef SCIP_DEBUG
2313  /* prints GUB set data structure */
2314  GUBsetPrint(scip, gubset, vars, solvals);
2315 #endif
2316 
2317 #ifndef NDEBUG
2318  /* checks consistency of GUB set data structure */
2319  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2320 #endif
2321 
2322  /* free temporary memory */
2323  SCIPfreeBufferArray(scip, &gubfirstvar);
2324  SCIPfreeBufferArray(scip, &cliquepartition);
2325 
2326  return SCIP_OKAY;
2327 }
2328 
2329 /** 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$
2330  * 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
2331  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2332  */
2333 static
2335  SCIP* scip, /**< SCIP data structure */
2336  SCIP_VAR** vars, /**< variables in knapsack constraint */
2337  int nvars, /**< number of variables in knapsack constraint */
2338  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2339  SCIP_Longint capacity, /**< capacity of knapsack */
2340  SCIP_Real* solvals, /**< solution values of all problem variables */
2341  int* covervars, /**< pointer to store cover variables */
2342  int* noncovervars, /**< pointer to store noncover variables */
2343  int* ncovervars, /**< pointer to store number of cover variables */
2344  int* nnoncovervars, /**< pointer to store number of noncover variables */
2345  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2346  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2347  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2348  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2349  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2350  )
2351 {
2352  SCIP_Longint* transweights;
2353  SCIP_Real* transprofits;
2354  SCIP_Longint transcapacity;
2355  SCIP_Longint fixedonesweight;
2356  SCIP_Longint itemsweight;
2357  SCIP_Bool infeasible;
2358  int* fixedones;
2359  int* fixedzeros;
2360  int* items;
2361  int nfixedones;
2362  int nfixedzeros;
2363  int nitems;
2364  int j;
2365 
2366  assert(scip != NULL);
2367  assert(vars != NULL);
2368  assert(nvars > 0);
2369  assert(weights != NULL);
2370  assert(capacity >= 0);
2371  assert(solvals != NULL);
2372  assert(covervars != NULL);
2373  assert(noncovervars != NULL);
2374  assert(ncovervars != NULL);
2375  assert(nnoncovervars != NULL);
2376  assert(coverweight != NULL);
2377  assert(found != NULL);
2378  assert(ntightened != NULL);
2379  assert(fractional != NULL);
2380 
2381  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2382 
2383  /* allocates temporary memory */
2384  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2385  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2386  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2387  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2388  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2389 
2390  *found = FALSE;
2391  *ncovervars = 0;
2392  *nnoncovervars = 0;
2393  *coverweight = 0;
2394  *fractional = TRUE;
2395 
2396  /* gets the following sets
2397  * N_1 = {j in N : x*_j = 1} (fixedones),
2398  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2399  * N\(N_0 & N_1) (items),
2400  * where x*_j is the solution value of variable x_j
2401  */
2402  nfixedones = 0;
2403  nfixedzeros = 0;
2404  nitems = 0;
2405  fixedonesweight = 0;
2406  itemsweight = 0;
2407  *ntightened = 0;
2408  for( j = 0; j < nvars; j++ )
2409  {
2410  assert(SCIPvarIsBinary(vars[j]));
2411 
2412  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2413  if( weights[j] > capacity )
2414  {
2415  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2416  assert(!infeasible);
2417  (*ntightened)++;
2418  continue;
2419  }
2420 
2421  /* variable x_j has solution value one */
2422  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2423  {
2424  fixedones[nfixedones] = j;
2425  nfixedones++;
2426  fixedonesweight += weights[j];
2427  }
2428  /* variable x_j has solution value zero */
2429  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2430  {
2431  fixedzeros[nfixedzeros] = j;
2432  nfixedzeros++;
2433  }
2434  /* variable x_j has fractional solution value */
2435  else
2436  {
2437  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2438  items[nitems] = j;
2439  nitems++;
2440  itemsweight += weights[j];
2441  }
2442  }
2443  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2444 
2445  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2446  * the separation routine
2447  */
2448  assert(nitems >= 0);
2449  if( nitems == 0 )
2450  {
2451  *fractional = FALSE;
2452  goto TERMINATE;
2453  }
2454  assert(*fractional);
2455 
2456  /* transforms the traditional separation problem (under consideration of the following fixing:
2457  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2458  *
2459  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2460  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2461  * z_j in {0,1}, j in N\(N_0 & N_1)
2462  *
2463  * to a knapsack problem in maximization form by complementing the variables
2464  *
2465  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2466  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2467  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2468  * z_j in {0,1}, j in N\(N_0 & N_1)
2469  */
2470 
2471  /* gets weight and profit of variables in transformed knapsack problem */
2472  for( j = 0; j < nitems; j++ )
2473  {
2474  transweights[j] = weights[items[j]];
2475  transprofits[j] = 1.0 - solvals[items[j]];
2476  }
2477  /* gets capacity of transformed knapsack problem */
2478  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2479 
2480  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2481  * (when variables fixed to zero are not used)
2482  */
2483  if( transcapacity < 0 )
2484  {
2485  assert(!(*found));
2486  goto TERMINATE;
2487  }
2488 
2489  if( modtransused )
2490  {
2491  /* transforms the modified separation problem (under consideration of the following fixing:
2492  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2493  *
2494  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2495  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2496  * z_j in {0,1}, j in N\(N_0 & N_1)
2497  *
2498  * to a knapsack problem in maximization form by complementing the variables
2499  *
2500  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2501  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2502  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2503  * z_j in {0,1}, j in N\(N_0 & N_1)
2504  */
2505 
2506  /* gets weight and profit of variables in modified transformed knapsack problem */
2507  for( j = 0; j < nitems; j++ )
2508  {
2509  transprofits[j] *= weights[items[j]];
2510  assert(SCIPisFeasPositive(scip, transprofits[j]));
2511  }
2512  }
2513 
2514  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2515  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2516  * let z* be the solution, then
2517  * j in C, if z*_j = 0 and
2518  * i in N\C, if z*_j = 1.
2519  */
2520  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2521  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2522  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2523 
2524  /* constructs cover C (sum_{j in C} a_j > a_0) */
2525  for( j = 0; j < *ncovervars; j++ )
2526  {
2527  (*coverweight) += weights[covervars[j]];
2528  }
2529 
2530  /* adds all variables from N_1 to C */
2531  for( j = 0; j < nfixedones; j++ )
2532  {
2533  covervars[*ncovervars] = fixedones[j];
2534  (*ncovervars)++;
2535  (*coverweight) += weights[fixedones[j]];
2536  }
2537 
2538  /* adds all variables from N_0 to N\C */
2539  for( j = 0; j < nfixedzeros; j++ )
2540  {
2541  noncovervars[*nnoncovervars] = fixedzeros[j];
2542  (*nnoncovervars)++;
2543  }
2544  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2545  assert((*coverweight) > capacity);
2546  *found = TRUE;
2547 
2548  TERMINATE:
2549  /* frees temporary memory */
2550  SCIPfreeBufferArray(scip, &items);
2551  SCIPfreeBufferArray(scip, &fixedzeros);
2552  SCIPfreeBufferArray(scip, &fixedones);
2553  SCIPfreeBufferArray(scip, &transprofits);
2554  SCIPfreeBufferArray(scip, &transweights);
2555 
2556  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2557 
2558  return SCIP_OKAY;
2559 }
2560 
2561 #ifndef NDEBUG
2562 /** checks if minweightidx is set correctly
2563  */
2564 static
2566  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2567  SCIP_Longint capacity, /**< capacity of knapsack */
2568  int* covervars, /**< pointer to store cover variables */
2569  int ncovervars, /**< pointer to store number of cover variables */
2570  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2571  int minweightidx, /**< index of variable in cover variables with minimum weight */
2572  int j /**< current index in cover variables */
2573  )
2574 {
2575  SCIP_Longint minweight;
2576  int i;
2577 
2578  assert(weights != NULL);
2579  assert(covervars != NULL);
2580  assert(ncovervars > 0);
2581 
2582  minweight = weights[covervars[minweightidx]];
2583 
2584  /* checks if all cover variables before index j have weight greater than minweight */
2585  for( i = 0; i < j; i++ )
2586  {
2587  assert(weights[covervars[i]] > minweight);
2588  if( weights[covervars[i]] <= minweight )
2589  return FALSE;
2590  }
2591 
2592  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2593  for( i = 0; i < j; i++ )
2594  {
2595  assert(coverweight - weights[covervars[i]] <= capacity);
2596  if( coverweight - weights[covervars[i]] > capacity )
2597  return FALSE;
2598  }
2599  return TRUE;
2600 }
2601 #endif
2602 
2603 
2604 /** 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$,
2605  * 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$
2606  */
2607 static
2609  SCIP* scip, /**< SCIP data structure */
2610  SCIP_Real* solvals, /**< solution values of all problem variables */
2611  int* covervars, /**< cover variables */
2612  int ncovervars, /**< number of cover variables */
2613  int* varsC1, /**< pointer to store variables in C1 */
2614  int* varsC2, /**< pointer to store variables in C2 */
2615  int* nvarsC1, /**< pointer to store number of variables in C1 */
2616  int* nvarsC2 /**< pointer to store number of variables in C2 */
2617  )
2618 {
2619  int j;
2620 
2621  assert(scip != NULL);
2622  assert(ncovervars >= 0);
2623  assert(solvals != NULL);
2624  assert(covervars != NULL);
2625  assert(varsC1 != NULL);
2626  assert(varsC2 != NULL);
2627  assert(nvarsC1 != NULL);
2628  assert(nvarsC2 != NULL);
2629 
2630  *nvarsC1 = 0;
2631  *nvarsC2 = 0;
2632  for( j = 0; j < ncovervars; j++ )
2633  {
2634  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2635 
2636  /* variable has solution value one */
2637  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2638  {
2639  varsC2[*nvarsC2] = covervars[j];
2640  (*nvarsC2)++;
2641  }
2642  /* variable has solution value less than one */
2643  else
2644  {
2645  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2646  varsC1[*nvarsC1] = covervars[j];
2647  (*nvarsC1)++;
2648  }
2649  }
2650  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2651 }
2652 
2653 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2654  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2655  */
2656 static
2658  SCIP* scip, /**< SCIP data structure */
2659  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2660  int* varsC1, /**< pointer to store variables in C1 */
2661  int* varsC2, /**< pointer to store variables in C2 */
2662  int* nvarsC1, /**< pointer to store number of variables in C1 */
2663  int* nvarsC2 /**< pointer to store number of variables in C2 */
2664  )
2666  SCIP_Real* sortkeysC2;
2667  int j;
2668 
2669  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2670  assert(*nvarsC2 > 0);
2671 
2672  /* allocates temporary memory */
2673  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2674 
2675  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2676  for( j = 0; j < *nvarsC2; j++ )
2677  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2678  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2679 
2680  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2681  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2682  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2683  {
2684  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2685  (*nvarsC1)++;
2686  (*nvarsC2)--;
2687  }
2688 
2689  /* frees temporary memory */
2690  SCIPfreeBufferArray(scip, &sortkeysC2);
2691 
2692  return SCIP_OKAY;
2693 }
2694 
2695 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2696 static
2698  SCIP* scip, /**< SCIP data structure */
2699  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2700  int* varsC1, /**< pointer to store variables in C1 */
2701  int* varsC2, /**< pointer to store variables in C2 */
2702  int* nvarsC1, /**< pointer to store number of variables in C1 */
2703  int* nvarsC2 /**< pointer to store number of variables in C2 */
2704  )
2706  SCIP_Real* sortkeysC2;
2707  int j;
2708 
2709  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2710  assert(*nvarsC2 > 0);
2711 
2712  /* allocates temporary memory */
2713  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2714 
2715  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2716  for( j = 0; j < *nvarsC2; j++ )
2717  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2718  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2719 
2720  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2721  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2722  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2723  (*nvarsC1)++;
2724  (*nvarsC2)--;
2725 
2726  /* frees temporary memory */
2727  SCIPfreeBufferArray(scip, &sortkeysC2);
2728 
2729  return SCIP_OKAY;
2730 }
2731 
2732 
2733 /** 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$
2734  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2735  * \f$F = (N \setminus C) \setminus F\f$
2736  */
2737 static
2739  SCIP* scip, /**< SCIP data structure */
2740  SCIP_Real* solvals, /**< solution values of all problem variables */
2741  int* noncovervars, /**< noncover variables */
2742  int nnoncovervars, /**< number of noncover variables */
2743  int* varsF, /**< pointer to store variables in F */
2744  int* varsR, /**< pointer to store variables in R */
2745  int* nvarsF, /**< pointer to store number of variables in F */
2746  int* nvarsR /**< pointer to store number of variables in R */
2747  )
2748 {
2749  int j;
2750 
2751  assert(scip != NULL);
2752  assert(nnoncovervars >= 0);
2753  assert(solvals != NULL);
2754  assert(noncovervars != NULL);
2755  assert(varsF != NULL);
2756  assert(varsR != NULL);
2757  assert(nvarsF != NULL);
2758  assert(nvarsR != NULL);
2759 
2760  *nvarsF = 0;
2761  *nvarsR = 0;
2762 
2763  for( j = 0; j < nnoncovervars; j++ )
2764  {
2765  /* variable has solution value zero */
2766  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2767  {
2768  varsR[*nvarsR] = noncovervars[j];
2769  (*nvarsR)++;
2770  }
2771  /* variable has solution value greater than zero */
2772  else
2773  {
2774  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2775  varsF[*nvarsF] = noncovervars[j];
2776  (*nvarsF)++;
2777  }
2778  }
2779  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2780 }
2781 
2782 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2783  * lifting procedure
2784  */
2785 static
2787  SCIP* scip, /**< SCIP data structure */
2788  SCIP_Real* solvals, /**< solution values of all problem variables */
2789  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2790  int* varsF, /**< pointer to store variables in F */
2791  int* varsC2, /**< pointer to store variables in C2 */
2792  int* varsR, /**< pointer to store variables in R */
2793  int nvarsF, /**< number of variables in F */
2794  int nvarsC2, /**< number of variables in C2 */
2795  int nvarsR /**< number of variables in R */
2796  )
2797 {
2798  SORTKEYPAIR** sortkeypairsF;
2799  SORTKEYPAIR* sortkeypairsFstore;
2800  SCIP_Real* sortkeysC2;
2801  SCIP_Real* sortkeysR;
2802  int j;
2803 
2804  assert(scip != NULL);
2805  assert(solvals != NULL);
2806  assert(weights != NULL);
2807  assert(varsF != NULL);
2808  assert(varsC2 != NULL);
2809  assert(varsR != NULL);
2810  assert(nvarsF >= 0);
2811  assert(nvarsC2 >= 0);
2812  assert(nvarsR >= 0);
2813 
2814  /* allocates temporary memory */
2815  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2816  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2817  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2818  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2819 
2820  /* gets sorting key for variables in F corresponding to the following lifting sequence
2821  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2822  * x*_1 >= x*_2 >= ... >= x*_|F|
2823  * in case of equality uses
2824  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2825  */
2826  for( j = 0; j < nvarsF; j++ )
2827  {
2828  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2829  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2830  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2831  }
2832 
2833  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2834  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2835  */
2836  for( j = 0; j < nvarsC2; j++ )
2837  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2838 
2839  /* gets sorting key for variables in R corresponding to the following lifting sequence
2840  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2841  */
2842  for( j = 0; j < nvarsR; j++ )
2843  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2844 
2845  /* sorts F, C2 and R */
2846  if( nvarsF > 0 )
2847  {
2848  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2849  }
2850  if( nvarsC2 > 0 )
2851  {
2852  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2853  }
2854  if( nvarsR > 0)
2855  {
2856  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2857  }
2858 
2859  /* frees temporary memory */
2860  SCIPfreeBufferArray(scip, &sortkeysR);
2861  SCIPfreeBufferArray(scip, &sortkeysC2);
2862  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2863  SCIPfreeBufferArray(scip, &sortkeypairsF);
2864 
2865  return SCIP_OKAY;
2866 }
2867 
2868 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2869  * for the sequential GUB wise lifting procedure
2870  */
2871 static
2873  SCIP* scip, /**< SCIP data structure */
2874  SCIP_GUBSET* gubset, /**< GUB set data structure */
2875  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2876  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2877  int* varsC1, /**< variables in C1 */
2878  int* varsC2, /**< variables in C2 */
2879  int* varsF, /**< variables in F */
2880  int* varsR, /**< variables in R */
2881  int nvarsC1, /**< number of variables in C1 */
2882  int nvarsC2, /**< number of variables in C2 */
2883  int nvarsF, /**< number of variables in F */
2884  int nvarsR, /**< number of variables in R */
2885  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2886  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2887  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2888  int* gubconsGR, /**< pointer to store GUBs in GR */
2889  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2890  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2891  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2892  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2893  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2894  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2895  )
2896 {
2897 #if 0 /* not required */
2898  SORTKEYPAIR** sortkeypairsF;
2899 #endif
2900  SORTKEYPAIR** sortkeypairsGFC1;
2901  SORTKEYPAIR* sortkeypairsGFC1store;
2902  SCIP_Real* sortkeysC1;
2903  SCIP_Real* sortkeysC2;
2904  SCIP_Real* sortkeysR;
2905  int* nC1varsingubcons;
2906  int var;
2907  int gubconsidx;
2908  int varidx;
2909  int ngubconss;
2910  int ngubconsGOC1;
2911  int targetvar;
2912  int nvarsprocessed;
2913  int i;
2914  int j;
2915 
2916 #if GUBSPLITGNC1GUBS
2917  SCIP_Bool gubconswithF;
2918  int origngubconss;
2919  origngubconss = gubset->ngubconss;
2920 #endif
2921 
2922  assert(scip != NULL);
2923  assert(gubset != NULL);
2924  assert(solvals != NULL);
2925  assert(weights != NULL);
2926  assert(varsC1 != NULL);
2927  assert(varsC2 != NULL);
2928  assert(varsF != NULL);
2929  assert(varsR != NULL);
2930  assert(nvarsC1 > 0);
2931  assert(nvarsC2 >= 0);
2932  assert(nvarsF >= 0);
2933  assert(nvarsR >= 0);
2934  assert(gubconsGC1 != NULL);
2935  assert(gubconsGC2 != NULL);
2936  assert(gubconsGFC1 != NULL);
2937  assert(gubconsGR != NULL);
2938  assert(ngubconsGC1 != NULL);
2939  assert(ngubconsGC2 != NULL);
2940  assert(ngubconsGFC1 != NULL);
2941  assert(ngubconsGR != NULL);
2942  assert(maxgubvarssize != NULL);
2943 
2944  ngubconss = gubset->ngubconss;
2945  nvarsprocessed = 0;
2946  ngubconsGOC1 = 0;
2947 
2948  /* GUBs are categorized into different types according to the variables in volved
2949  * - GOC1: involves variables in C1 only -- no C2, R, F
2950  * - GNC1: involves variables in C1 and F (and R) -- no C2
2951  * - GF: involves variables in F (and R) only -- no C1, C2
2952  * - GC2: involves variables in C2 only -- no C1, R, F
2953  * - GR: involves variables in R only -- no C1, C2, F
2954  * which requires splitting GUBs in case they include variable in F and R.
2955  *
2956  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2957  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2958  * - second ordering level is
2959  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2960  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2961  * GR: non-increasing max{ a_k : k in GR_j}
2962  *
2963  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2964  * - GC1: GUBs of category GOC1 and GNC1
2965  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2966  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2967  */
2968 
2969  /* allocates temporary memory */
2970  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2971 #if 0 /* not required */
2972  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2973 #endif
2974  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2975  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2976 
2977 
2978  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2979  * - F: non-increasing x*_j and non-increasing a_j in case of equality
2980  * - C2: non-increasing a_j
2981  * - R: non-increasing a_j
2982  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2983  */
2984 
2985  /* gets sorting key for variables in C1 corresponding to the following ordering
2986  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
2987  */
2988  for( j = 0; j < nvarsC1; j++ )
2989  {
2990  /* gets sortkeys */
2991  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
2992 
2993  /* update status of variable in its gub constraint */
2994  gubconsidx = gubset->gubconssidx[varsC1[j]];
2995  varidx = gubset->gubvarsidx[varsC1[j]];
2996  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
2997  }
2998 
2999  /* gets sorting key for variables in F corresponding to the following ordering
3000  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3001  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3002  * and updates status of each variable in F in GUB set data structure
3003  */
3004  for( j = 0; j < nvarsF; j++ )
3005  {
3006 #if 0 /* not required */
3007  /* gets sortkeys */
3008  SCIP_CALL( SCIPallocBuffer(scip, &sortkeypairsF[j]) );
3009  sortkeypairsF[j]->key1 = solvals[varsF[j]];
3010  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
3011 #endif
3012 
3013  /* update status of variable in its gub constraint */
3014  gubconsidx = gubset->gubconssidx[varsF[j]];
3015  varidx = gubset->gubvarsidx[varsF[j]];
3016  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3017  }
3018 
3019  /* gets sorting key for variables in C2 corresponding to the following ordering
3020  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3021  * and updates status of each variable in F in GUB set data structure
3022  */
3023  for( j = 0; j < nvarsC2; j++ )
3024  {
3025  /* gets sortkeys */
3026  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3027 
3028  /* update status of variable in its gub constraint */
3029  gubconsidx = gubset->gubconssidx[varsC2[j]];
3030  varidx = gubset->gubvarsidx[varsC2[j]];
3031  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3032  }
3033 
3034  /* gets sorting key for variables in R corresponding to the following ordering
3035  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3036  * and updates status of each variable in F in GUB set data structure
3037  */
3038  for( j = 0; j < nvarsR; j++ )
3039  {
3040  /* gets sortkeys */
3041  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3042 
3043  /* update status of variable in its gub constraint */
3044  gubconsidx = gubset->gubconssidx[varsR[j]];
3045  varidx = gubset->gubvarsidx[varsR[j]];
3046  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3047  }
3048 
3049  /* sorts C1, F, C2 and R */
3050  if( nvarsC1 > 0 )
3051  {
3052  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3053  }
3054 #if 0 /* not required */
3055  if( nvarsF > 0 )
3056  {
3057  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
3058  }
3059 #endif
3060  if( nvarsC2 > 0 )
3061  {
3062  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3063  }
3064  if( nvarsR > 0)
3065  {
3066  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3067  }
3068 
3069  /* frees temporary memory */
3070  SCIPfreeBufferArray(scip, &sortkeysR);
3071  SCIPfreeBufferArray(scip, &sortkeysC2);
3072 #if 0 /* not required */
3073  for( j = nvarsF-1; j >= 0; j-- )
3074  SCIPfreeBuffer(scip, &sortkeypairsF[j]);
3075  SCIPfreeBufferArray(scip, &sortkeypairsF);
3076 #endif
3077  SCIPfreeBufferArray(scip, &sortkeysC1);
3078 
3079  /* allocate and initialize temporary memory for sorting GUB constraints */
3080  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3081  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3082  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3083  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3084  for( i = 0; i < ngubconss; i++)
3085  {
3086  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3087  sortkeypairsGFC1[i]->key1 = 0.0;
3088  sortkeypairsGFC1[i]->key2 = 0.0;
3089  }
3090  *ngubconsGC1 = 0;
3091  *ngubconsGC2 = 0;
3092  *ngubconsGFC1 = 0;
3093  *ngubconsGR = 0;
3094  *ngubconscapexceed = 0;
3095  *maxgubvarssize = 0;
3096 
3097 #ifndef NDEBUG
3098  for( i = 0; i < gubset->ngubconss; i++ )
3099  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3100 #endif
3101 
3102  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3103  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3104  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3105  * non-increasing number of variables in F, and
3106  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3107  */
3108  for( i = 0; i < nvarsC1; i++ )
3109  {
3110  int nvarsC1capexceed;
3111 
3112  nvarsC1capexceed = 0;
3113 
3114  var = varsC1[i];
3115  gubconsidx = gubset->gubconssidx[var];
3116  varidx = gubset->gubvarsidx[var];
3117 
3118  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3119  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3120 
3121  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3122  * note that variables in C1 are already sorted by non-decreasing weigth
3123  */
3124  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3125  GUBsetSwapVars(scip, gubset, var, targetvar);
3126  nC1varsingubcons[gubconsidx]++;
3127 
3128  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3129  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3130  {
3131  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3132  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3133  continue;
3134  }
3135 
3136  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3137  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3138  */
3139 #if GUBSPLITGNC1GUBS
3140  gubconswithF = FALSE;
3141 #endif
3142  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3143  {
3144  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3145 
3146  /* C1-variable: update number of C1/capacity exceeding variables */
3147  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3148  {
3149  nvarsC1capexceed++;
3150  nvarsprocessed++;
3151  }
3152  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3153  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3154  {
3155 #if GUBSPLITGNC1GUBS
3156  gubconswithF = TRUE;
3157 #endif
3158  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3159 
3160  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3161  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3162  }
3163  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3164  {
3165  nvarsC1capexceed++;
3166  }
3167  else
3168  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3169  }
3170 
3171  /* update set of GC1 GUBs */
3172  gubconsGC1[*ngubconsGC1] = gubconsidx;
3173  (*ngubconsGC1)++;
3174 
3175  /* update maximum size of all GUB constraints */
3176  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3177  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3178 
3179  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3180  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3181  {
3182  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3183  ngubconsGOC1++;
3184  }
3185  else
3186  {
3187 #if GUBSPLITGNC1GUBS
3188  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3189  if( !gubconswithF )
3190  {
3191  GUBVARSTATUS movevarstatus;
3192 
3193  assert(gubset->ngubconss < gubset->nvars);
3194 
3195  /* create a new GUB for GR part of splitting */
3196  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3197  gubset->ngubconss++;
3198  ngubconss = gubset->ngubconss;
3199 
3200  /* fill GR with R variables in current GUB */
3201  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3202  {
3203  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3204  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3205  {
3206  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3207  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3208  gubconsidx, ngubconss-1) );
3209  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3210  movevarstatus;
3211  }
3212  }
3213 
3214  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3215  ngubconsGOC1++;
3216 
3217  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3218  gubconsGR[*ngubconsGR] = ngubconss-1;
3219  (*ngubconsGR)++;
3220  }
3221  /* variables in C1, F, and maybe R: GNC1 GUB */
3222  else
3223  {
3224  assert(gubconswithF);
3225 
3226  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3227  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3228  (*ngubconsGFC1)++;
3229  }
3230 #else
3231  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3232  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3233  (*ngubconsGFC1)++;
3234 #endif
3235  }
3236  }
3237 
3238  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3239  * are already sorted correctly
3240  */
3241  for( i = 0; i < nvarsC2; i++ )
3242  {
3243  var = varsC2[i];
3244  gubconsidx = gubset->gubconssidx[var];
3245  varidx = gubset->gubvarsidx[var];
3246 
3247  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3248  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3249  assert(varidx == 0);
3250  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3251  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3252 
3253  /* set status of GC2 GUB */
3254  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3255 
3256  /* update group of GC2 GUBs */
3257  gubconsGC2[*ngubconsGC2] = gubconsidx;
3258  (*ngubconsGC2)++;
3259 
3260  /* update maximum size of all GUB constraints */
3261  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3262  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3263 
3264  nvarsprocessed++;
3265  }
3266 
3267  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3268  * non-increasing number of variables in F, and
3269  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3270  */
3271  for( i = 0; i < nvarsF; i++ )
3272  {
3273  var = varsF[i];
3274  gubconsidx = gubset->gubconssidx[var];
3275  varidx = gubset->gubvarsidx[var];
3276 
3277  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3278  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3279 
3280  nvarsprocessed++;
3281 
3282  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3283  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3284  {
3285  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3286  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3287  continue;
3288  }
3289 
3290  /* set status of GF GUB */
3291  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3292 
3293  /* update sorting key of corresponding GFC1 GUB */
3294  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3295  {
3296  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3297  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3298 
3299  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3300  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3301  {
3302  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3303 
3304  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3305  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3306  }
3307  }
3308 
3309  /* update set of GFC1 GUBs */
3310  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3311  (*ngubconsGFC1)++;
3312 
3313  /* update maximum size of all GUB constraints */
3314  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3315  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3316  }
3317 
3318  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3319  * correctly
3320  */
3321  for( i = 0; i < nvarsR; i++ )
3322  {
3323  var = varsR[i];
3324  gubconsidx = gubset->gubconssidx[var];
3325  varidx = gubset->gubvarsidx[var];
3326 
3327  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3328  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3329 
3330  nvarsprocessed++;
3331 
3332  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3333  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3334  {
3335  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3336  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3337  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3338  continue;
3339  }
3340 
3341  /* set status of GR GUB */
3342  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3343 
3344  /* update set of GR GUBs */
3345  gubconsGR[*ngubconsGR] = gubconsidx;
3346  (*ngubconsGR)++;
3347 
3348  /* update maximum size of all GUB constraints */
3349  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3350  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3351  }
3352  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3353 
3354  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3355  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3356  assert(*ngubconscapexceed >= 0);
3357 #ifndef NDEBUG
3358  {
3359  int check;
3360 
3361  check = 0;
3362 
3363  /* remaining not handled GUBs should only contain capacity exceeding variables */
3364  for( i = 0; i < ngubconss; i++ )
3365  {
3366  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3367  check++;
3368  }
3369  assert(check == *ngubconscapexceed);
3370  }
3371 #endif
3372 
3373  /* sort GFCI GUBs according to computed sorting keys */
3374  if( (*ngubconsGFC1) > 0 )
3375  {
3376  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3377  }
3378 
3379  /* free temporary memory */
3380 #if GUBSPLITGNC1GUBS
3381  ngubconss = origngubconss;
3382 #endif
3383  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3384  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3385  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3386 
3387  return SCIP_OKAY;
3388 }
3389 
3390 /** enlarges minweight table to at least the given length */
3391 static
3393  SCIP* scip, /**< SCIP data structure */
3394  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3395  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3396  int* minweightssize, /**< pointer to current size of minweights table */
3397  int newlen /**< new length of minweights table */
3398  )
3399 {
3400  int j;
3401 
3402  assert(minweightsptr != NULL);
3403  assert(*minweightsptr != NULL);
3404  assert(minweightslen != NULL);
3405  assert(*minweightslen >= 0);
3406  assert(minweightssize != NULL);
3407  assert(*minweightssize >= 0);
3408 
3409  if( newlen > *minweightssize )
3410  {
3411  int newsize;
3412 
3413  /* reallocate table memory */
3414  newsize = SCIPcalcMemGrowSize(scip, newlen);
3415  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3416  *minweightssize = newsize;
3417  }
3418  assert(newlen <= *minweightssize);
3419 
3420  /* initialize new elements */
3421  for( j = *minweightslen; j < newlen; ++j )
3422  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3423  *minweightslen = newlen;
3424 
3425  return SCIP_OKAY;
3426 }
3427 
3428 /** lifts given inequality
3429  * sum_{j in M_1} x_j <= alpha_0
3430  * valid for
3431  * 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 }
3432  * to a valid inequality
3433  * 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
3434  * <= alpha_0 + sum_{j in M_2} alpha_j
3435  * for
3436  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3437  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3438  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3439  * extended weight inequalities.
3440  */
3441 static
3443  SCIP* scip, /**< SCIP data structure */
3444  SCIP_VAR** vars, /**< variables in knapsack constraint */
3445  int nvars, /**< number of variables in knapsack constraint */
3446  int ntightened, /**< number of variables with tightened upper bound */
3447  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3448  SCIP_Longint capacity, /**< capacity of knapsack */
3449  SCIP_Real* solvals, /**< solution values of all problem variables */
3450  int* varsM1, /**< variables in M_1 */
3451  int* varsM2, /**< variables in M_2 */
3452  int* varsF, /**< variables in F */
3453  int* varsR, /**< variables in R */
3454  int nvarsM1, /**< number of variables in M_1 */
3455  int nvarsM2, /**< number of variables in M_2 */
3456  int nvarsF, /**< number of variables in F */
3457  int nvarsR, /**< number of variables in R */
3458  int alpha0, /**< rights hand side of given valid inequality */
3459  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3460  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3461  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3462  )
3463 {
3464  SCIP_Longint* minweights;
3465  SCIP_Real* sortkeys;
3466  SCIP_Longint fixedonesweight;
3467  int minweightssize;
3468  int minweightslen;
3469  int j;
3470  int w;
3471 
3472  assert(scip != NULL);
3473  assert(vars != NULL);
3474  assert(nvars >= 0);
3475  assert(weights != NULL);
3476  assert(capacity >= 0);
3477  assert(solvals != NULL);
3478  assert(varsM1 != NULL);
3479  assert(varsM2 != NULL);
3480  assert(varsF != NULL);
3481  assert(varsR != NULL);
3482  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3483  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3484  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3485  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3486  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3487  assert(alpha0 >= 0);
3488  assert(liftcoefs != NULL);
3489  assert(cutact != NULL);
3490  assert(liftrhs != NULL);
3491 
3492  /* allocates temporary memory */
3493  minweightssize = nvarsM1 + 1;
3494  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3495  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3496 
3497  /* initializes data structures */
3498  BMSclearMemoryArray(liftcoefs, nvars);
3499  *cutact = 0.0;
3500 
3501  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3502  * and calculates activity of the current valid inequality
3503  */
3504  for( j = 0; j < nvarsM1; j++ )
3505  {
3506  assert(liftcoefs[varsM1[j]] == 0);
3507  liftcoefs[varsM1[j]] = 1;
3508  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3509  (*cutact) += solvals[varsM1[j]];
3510  }
3511 
3512  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3513 
3514  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3515  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3516  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3517  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3518  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3519  */
3520  minweights[0] = 0;
3521  for( w = 1; w <= nvarsM1; w++ )
3522  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3523  minweightslen = nvarsM1 + 1;
3524 
3525  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3526  fixedonesweight = 0;
3527  for( j = 0; j < nvarsM2; j++ )
3528  fixedonesweight += weights[varsM2[j]];
3529  assert(fixedonesweight >= 0);
3530 
3531  /* initializes right hand side of lifted valid inequality */
3532  *liftrhs = alpha0;
3533 
3534  /* sequentially up-lifts all variables in F: */
3535  for( j = 0; j < nvarsF; j++ )
3536  {
3537  SCIP_Longint weight;
3538  int liftvar;
3539  int liftcoef;
3540  int z;
3541 
3542  liftvar = varsF[j];
3543  weight = weights[liftvar];
3544  assert(liftvar >= 0 && liftvar < nvars);
3545  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3546  assert(weight > 0);
3547 
3548  /* knapsack problem is infeasible:
3549  * sets z = 0
3550  */
3551  if( capacity - fixedonesweight - weight < 0 )
3552  {
3553  z = 0;
3554  }
3555  /* knapsack problem is feasible:
3556  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3557  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3558  */
3559  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3560  {
3561  z = *liftrhs;
3562  }
3563  /* knapsack problem is feasible:
3564  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3565  */
3566  else
3567  {
3568  int left;
3569  int right;
3570  int middle;
3571 
3572  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3573  left = 0;
3574  right = (*liftrhs) + 1;
3575  while( left < right - 1 )
3576  {
3577  middle = (left + right) / 2;
3578  assert(0 <= middle && middle < minweightslen);
3579  if( minweights[middle] <= capacity - fixedonesweight - weight )
3580  left = middle;
3581  else
3582  right = middle;
3583  }
3584  assert(left == right - 1);
3585  assert(0 <= left && left < minweightslen);
3586  assert(minweights[left] <= capacity - fixedonesweight - weight );
3587  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3588 
3589  /* now z = left */
3590  z = left;
3591  assert(z <= *liftrhs);
3592  }
3593 
3594  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3595  liftcoef = (*liftrhs) - z;
3596  liftcoefs[liftvar] = liftcoef;
3597  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3598 
3599  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3600  if( liftcoef == 0 )
3601  continue;
3602 
3603  /* updates activity of current valid inequality */
3604  (*cutact) += liftcoef * solvals[liftvar];
3605 
3606  /* enlarges current minweight table:
3607  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3608  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3609  * and sets minweights_i[w] = infinity for
3610  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3611  */
3612  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3613 
3614  /* updates minweight table: minweight_i+1[w] =
3615  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3616  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3617  */
3618  for( w = minweightslen - 1; w >= 0; w-- )
3619  {
3620  SCIP_Longint min;
3621  if( w < liftcoef )
3622  {
3623  min = MIN(minweights[w], weight);
3624  minweights[w] = min;
3625  }
3626  else
3627  {
3628  assert(w >= liftcoef);
3629  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3630  minweights[w] = min;
3631  }
3632  }
3633  }
3634  assert(minweights[0] == 0);
3635 
3636  /* sequentially down-lifts all variables in M_2: */
3637  for( j = 0; j < nvarsM2; j++ )
3638  {
3639  SCIP_Longint weight;
3640  int liftvar;
3641  int liftcoef;
3642  int left;
3643  int right;
3644  int middle;
3645  int z;
3646 
3647  liftvar = varsM2[j];
3648  weight = weights[liftvar];
3649  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3650  assert(liftvar >= 0 && liftvar < nvars);
3651  assert(weight > 0);
3652 
3653  /* uses binary search to find
3654  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3655  */
3656  left = 0;
3657  right = minweightslen;
3658  while( left < right - 1 )
3659  {
3660  middle = (left + right) / 2;
3661  assert(0 <= middle && middle < minweightslen);
3662  if( minweights[middle] <= capacity - fixedonesweight + weight )
3663  left = middle;
3664  else
3665  right = middle;
3666  }
3667  assert(left == right - 1);
3668  assert(0 <= left && left < minweightslen);
3669  assert(minweights[left] <= capacity - fixedonesweight + weight );
3670  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3671 
3672  /* now z = left */
3673  z = left;
3674  assert(z >= *liftrhs);
3675 
3676  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3677  liftcoef = z - (*liftrhs);
3678  liftcoefs[liftvar] = liftcoef;
3679  assert(liftcoef >= 0);
3680 
3681  /* updates sum of weights of variables fixed to one */
3682  fixedonesweight -= weight;
3683 
3684  /* updates right-hand side of current valid inequality */
3685  (*liftrhs) += liftcoef;
3686  assert(*liftrhs >= alpha0);
3687 
3688  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3689  if( liftcoef == 0 )
3690  continue;
3691 
3692  /* updates activity of current valid inequality */
3693  (*cutact) += liftcoef * solvals[liftvar];
3694 
3695  /* enlarges current minweight table:
3696  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3697  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3698  * and sets minweights_i[w] = infinity for
3699  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3700  */
3701  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3702 
3703  /* updates minweight table: minweight_i+1[w] =
3704  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3705  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3706  */
3707  for( w = minweightslen - 1; w >= 0; w-- )
3708  {
3709  SCIP_Longint min;
3710  if( w < liftcoef )
3711  {
3712  min = MIN(minweights[w], weight);
3713  minweights[w] = min;
3714  }
3715  else
3716  {
3717  assert(w >= liftcoef);
3718  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3719  minweights[w] = min;
3720  }
3721  }
3722  }
3723  assert(fixedonesweight == 0);
3724  assert(*liftrhs >= alpha0);
3725 
3726  /* sequentially up-lifts all variables in R: */
3727  for( j = 0; j < nvarsR; j++ )
3728  {
3729  SCIP_Longint weight;
3730  int liftvar;
3731  int liftcoef;
3732  int z;
3733 
3734  liftvar = varsR[j];
3735  weight = weights[liftvar];
3736  assert(liftvar >= 0 && liftvar < nvars);
3737  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3738  assert(weight > 0);
3739  assert(capacity - weight >= 0);
3740  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3741 
3742  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3743  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3744  */
3745  if( minweights[*liftrhs] <= capacity - weight )
3746  {
3747  z = *liftrhs;
3748  }
3749  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3750  */
3751  else
3752  {
3753  int left;
3754  int right;
3755  int middle;
3756 
3757  left = 0;
3758  right = (*liftrhs) + 1;
3759  while( left < right - 1)
3760  {
3761  middle = (left + right) / 2;
3762  assert(0 <= middle && middle < minweightslen);
3763  if( minweights[middle] <= capacity - weight )
3764  left = middle;
3765  else
3766  right = middle;
3767  }
3768  assert(left == right - 1);
3769  assert(0 <= left && left < minweightslen);
3770  assert(minweights[left] <= capacity - weight );
3771  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3772 
3773  /* now z = left */
3774  z = left;
3775  assert(z <= *liftrhs);
3776  }
3777 
3778  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3779  liftcoef = (*liftrhs) - z;
3780  liftcoefs[liftvar] = liftcoef;
3781  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3782 
3783  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3784  if( liftcoef == 0 )
3785  continue;
3786 
3787  /* updates activity of current valid inequality */
3788  (*cutact) += liftcoef * solvals[liftvar];
3789 
3790  /* updates minweight table: minweight_i+1[w] =
3791  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3792  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3793  */
3794  for( w = *liftrhs; w >= 0; w-- )
3795  {
3796  SCIP_Longint min;
3797  if( w < liftcoef )
3798  {
3799  min = MIN(minweights[w], weight);
3800  minweights[w] = min;
3801  }
3802  else
3803  {
3804  assert(w >= liftcoef);
3805  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3806  minweights[w] = min;
3807  }
3808  }
3809  }
3810 
3811  /* frees temporary memory */
3812  SCIPfreeBufferArray(scip, &sortkeys);
3813  SCIPfreeBufferArray(scip, &minweights);
3814 
3815  return SCIP_OKAY;
3816 }
3817 
3818 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3819 static
3821  SCIP_Longint val1, /**< first value to add */
3822  SCIP_Longint val2 /**< second value to add */
3823  )
3824 {
3825  assert(val1 >= 0);
3826  assert(val2 >= 0);
3827 
3828  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3829  return SCIP_LONGINT_MAX;
3830  else
3831  {
3832  assert(val1 <= SCIP_LONGINT_MAX - val2);
3833  return (val1 + val2);
3834  }
3835 }
3836 
3837 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3838 static
3840  SCIP_Longint* minweights, /**< minweight table to compute */
3841  SCIP_Longint* finished, /**< given finished table */
3842  SCIP_Longint* unfinished, /**< given unfinished table */
3843  int minweightslen /**< length of minweight, finished, and unfinished tables */
3844  )
3845 {
3846  int w1;
3847  int w2;
3848 
3849  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3850  * note that finished and unfished arrays sorted by non-decreasing weight
3851  */
3852 
3853  /* initialize minweight with w2 = 0 */
3854  w2 = 0;
3855  assert(unfinished[w2] == 0);
3856  for( w1 = 0; w1 < minweightslen; w1++ )
3857  minweights[w1] = finished[w1];
3858 
3859  /* consider w2 = 1, ..., minweightslen-1 */
3860  for( w2 = 1; w2 < minweightslen; w2++ )
3861  {
3862  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3863  break;
3864 
3865  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3866  {
3867  SCIP_Longint temp;
3868 
3869  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3870  if( temp <= minweights[w1+w2] )
3871  minweights[w1+w2] = temp;
3872  }
3873  }
3874 }
3875 
3876 /** lifts given inequality
3877  * sum_{j in C_1} x_j <= alpha_0
3878  * valid for
3879  * 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;
3880  * sum_{j in Q_i} x_j <= 1, forall i in I }
3881  * to a valid inequality
3882  * 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
3883  * <= alpha_0 + sum_{j in C_2} alpha_j
3884  * for
3885  * 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 };
3886  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3887  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3888  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3889  */
3890 static
3892  SCIP* scip, /**< SCIP data structure */
3893  SCIP_GUBSET* gubset, /**< GUB set data structure */
3894  SCIP_VAR** vars, /**< variables in knapsack constraint */
3895  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3896  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3897  SCIP_Longint capacity, /**< capacity of knapsack */
3898  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3899  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3900  int* gubconsGC2, /**< GUBs in GC2 */
3901  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3902  int* gubconsGR, /**< GUBs in GR */
3903  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3904  int ngubconsGC2, /**< number of GUBs in GC2 */
3905  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3906  int ngubconsGR, /**< number of GUBs in GR */
3907  int alpha0, /**< rights hand side of given valid inequality */
3908  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3909  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3910  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3911  int maxgubvarssize /**< maximal size of GUB constraints */
3912  )
3913 {
3914  SCIP_Longint* minweights;
3915  SCIP_Longint* finished;
3916  SCIP_Longint* unfinished;
3917  int* gubconsGOC1;
3918  int* gubconsGNC1;
3919  int* liftgubvars;
3920  SCIP_Longint fixedonesweight;
3921  SCIP_Longint weight;
3922  SCIP_Longint weightdiff1;
3923  SCIP_Longint weightdiff2;
3924  SCIP_Longint min;
3925  int minweightssize;
3926  int minweightslen;
3927  int nvars;
3928  int varidx;
3929  int liftgubconsidx;
3930  int liftvar;
3931  int sumliftcoef;
3932  int liftcoef;
3933  int ngubconsGOC1;
3934  int ngubconsGNC1;
3935  int left;
3936  int right;
3937  int middle;
3938  int nliftgubvars;
3939  int tmplen;
3940  int tmpsize;
3941  int j;
3942  int k;
3943  int w;
3944  int z;
3945 #ifndef NDEBUG
3946  int ngubconss;
3947  int nliftgubC1;
3948 
3949  assert(gubset != NULL);
3950  ngubconss = gubset->ngubconss;
3951 #else
3952  assert(gubset != NULL);
3953 #endif
3954 
3955  nvars = gubset->nvars;
3956 
3957  assert(scip != NULL);
3958  assert(vars != NULL);
3959  assert(nvars >= 0);
3960  assert(weights != NULL);
3961  assert(capacity >= 0);
3962  assert(solvals != NULL);
3963  assert(gubconsGC1 != NULL);
3964  assert(gubconsGC2 != NULL);
3965  assert(gubconsGFC1 != NULL);
3966  assert(gubconsGR != NULL);
3967  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3968  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3969  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3970  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3971  assert(alpha0 >= 0);
3972  assert(liftcoefs != NULL);
3973  assert(cutact != NULL);
3974  assert(liftrhs != NULL);
3975 
3976  minweightssize = ngubconsGC1+1;
3977 
3978  /* allocates temporary memory */
3979  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3980  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3981  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3982  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3983  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3984  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3985 
3986  /* initializes data structures */
3987  BMSclearMemoryArray(liftcoefs, nvars);
3988  *cutact = 0.0;
3989 
3990  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
3991  * valid inequality
3992  */
3993  ngubconsGOC1 = 0;
3994  ngubconsGNC1 = 0;
3995  for( j = 0; j < ngubconsGC1; j++ )
3996  {
3997  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
3998  {
3999  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4000  ngubconsGOC1++;
4001  }
4002  else
4003  {
4004  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4005  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4006  ngubconsGNC1++;
4007  }
4008  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4009  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4010  {
4011  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4012  assert(varidx >= 0 && varidx < nvars);
4013  assert(liftcoefs[varidx] == 0);
4014 
4015  liftcoefs[varidx] = 1;
4016  (*cutact) += solvals[varidx];
4017  }
4018  assert(k >= 1);
4019  }
4020  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4021  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4022 
4023  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4024  * - finished_i[w] =
4025  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4026  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4027  * sum_{j in Q_k} x_j <= 1
4028  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4029  * - unfinished_i[w] =
4030  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4031  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4032  * sum_{j in Q_k} x_j <= 1
4033  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4034  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4035  */
4036 
4037  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4038  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4039  * 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
4040  * comes from the first variable in the GUB
4041  */
4042  assert(ngubconsGOC1 <= ngubconsGC1);
4043  finished[0] = 0;
4044  for( w = 1; w <= ngubconsGOC1; w++ )
4045  {
4046  liftgubconsidx = gubconsGOC1[w-1];
4047 
4048  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4049  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4050 
4051  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4052 
4053  assert(varidx >= 0 && varidx < nvars);
4054  assert(liftcoefs[varidx] == 1);
4055 
4056  min = weights[varidx];
4057  finished[w] = finished[w-1] + min;
4058 
4059 #ifndef NDEBUG
4060  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4061  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4062  {
4063  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4064  assert(varidx >= 0 && varidx < nvars);
4065  assert(liftcoefs[varidx] == 1);
4066  assert(weights[varidx] >= min);
4067  }
4068 #endif
4069  }
4070  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4071  finished[w] = SCIP_LONGINT_MAX;
4072 
4073  /* initialize unfinished table; note that variables in GNC1 GUBs
4074  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4075  * 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
4076  * comes from the first variable in the GUB
4077  */
4078  assert(ngubconsGNC1 <= ngubconsGC1);
4079  unfinished[0] = 0;
4080  for( w = 1; w <= ngubconsGNC1; w++ )
4081  {
4082  liftgubconsidx = gubconsGNC1[w-1];
4083 
4084  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4085  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4086 
4087  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4088 
4089  assert(varidx >= 0 && varidx < nvars);
4090  assert(liftcoefs[varidx] == 1);
4091 
4092  min = weights[varidx];
4093  unfinished[w] = unfinished[w-1] + min;
4094 
4095 #ifndef NDEBUG
4096  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4097  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4098  {
4099  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4100  assert(varidx >= 0 && varidx < nvars);
4101  assert(liftcoefs[varidx] == 1);
4102  assert(weights[varidx] >= min );
4103  }
4104 #endif
4105  }
4106  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4107  unfinished[w] = SCIP_LONGINT_MAX;
4108 
4109  /* initialize minweights table; note that variables in GC1 GUBs
4110  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4111  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4112  * consuming) because is it has to be build using weights from C1 only.
4113  */
4114  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4115  minweights[0] = 0;
4116  for( w = 1; w <= ngubconsGC1; w++ )
4117  {
4118  liftgubconsidx = gubconsGC1[w-1];
4119 
4120  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4121  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4122  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4123 
4124  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4125 
4126  assert(varidx >= 0 && varidx < nvars);
4127  assert(liftcoefs[varidx] == 1);
4128 
4129  min = weights[varidx];
4130  minweights[w] = minweights[w-1] + min;
4131 
4132 #ifndef NDEBUG
4133  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4134  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4135  {
4136  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4137  assert(varidx >= 0 && varidx < nvars);
4138  assert(liftcoefs[varidx] == 1);
4139  assert(weights[varidx] >= min);
4140  }
4141 #endif
4142  }
4143  minweightslen = ngubconsGC1 + 1;
4144 
4145  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4146  fixedonesweight = 0;
4147  for( j = 0; j < ngubconsGC2; j++ )
4148  {
4149  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4150 
4151  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4152  assert(varidx >= 0 && varidx < nvars);
4153  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4154 
4155  fixedonesweight += weights[varidx];
4156  }
4157  assert(fixedonesweight >= 0);
4158 
4159  /* initializes right hand side of lifted valid inequality */
4160  *liftrhs = alpha0;
4161 
4162  /* sequentially up-lifts all variables in GFC1 GUBs */
4163  for( j = 0; j < ngubconsGFC1; j++ )
4164  {
4165  liftgubconsidx = gubconsGFC1[j];
4166  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4167 
4168  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4169  * compute minweight table via updated unfinished table and aleady upto date finished table;
4170  */
4171  k = 0;
4172  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4173  {
4174  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4175  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4176  assert(ngubconsGNC1 > 0);
4177 
4178  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4179  * are considered for the lifting, i.e., not capacity exceeding
4180  */
4181  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4182  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4183  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4184  assert(k >= 1);
4185 
4186  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4187  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4188  */
4189  weight = weights[liftgubvars[0]];
4190 
4191  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4192  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4193  for( w = ngubconsGNC1-1; w >= 1; w-- )
4194  {
4195  weightdiff1 = weightdiff2;
4196  weightdiff2 = unfinished[w] - weight;
4197 
4198  if( unfinished[w] < weightdiff1 )
4199  unfinished[w] = weightdiff1;
4200  else
4201  break;
4202  }
4203  ngubconsGNC1--;
4204 
4205  /* computes minweights table by combining unfished and fished tables */
4206  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4207  assert(minweights[0] == 0);
4208  }
4209  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4210  * are therefore not in the unfinished table
4211  */
4212  else
4213  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4214 
4215 #ifndef NDEBUG
4216  nliftgubC1 = k;
4217 #endif
4218  nliftgubvars = k;
4219  sumliftcoef = 0;
4220 
4221  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4222  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4223  {
4224  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4225  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4226  {
4227  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4228  weight = weights[liftvar];
4229  assert(weight > 0);
4230  assert(liftvar >= 0 && liftvar < nvars);
4231  assert(capacity - weight >= 0);
4232 
4233  /* put variable into array of variables in GUB that are considered for the lifting,
4234  * i.e., not capacity exceeding
4235  */
4236  liftgubvars[nliftgubvars] = liftvar;
4237  nliftgubvars++;
4238 
4239  /* knapsack problem is infeasible:
4240  * sets z = 0
4241  */
4242  if( capacity - fixedonesweight - weight < 0 )
4243  {
4244  z = 0;
4245  }
4246  /* knapsack problem is feasible:
4247  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4248  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4249  */
4250  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4251  {
4252  z = *liftrhs;
4253  }
4254  /* knapsack problem is feasible:
4255  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4256  */
4257  else
4258  {
4259  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4260  left = 0;
4261  right = (*liftrhs) + 1;
4262  while( left < right - 1 )
4263  {
4264  middle = (left + right) / 2;
4265  assert(0 <= middle && middle < minweightslen);
4266  if( minweights[middle] <= capacity - fixedonesweight - weight )
4267  left = middle;
4268  else
4269  right = middle;
4270  }
4271  assert(left == right - 1);
4272  assert(0 <= left && left < minweightslen);
4273  assert(minweights[left] <= capacity - fixedonesweight - weight);
4274  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4275 
4276  /* now z = left */
4277  z = left;
4278  assert(z <= *liftrhs);
4279  }
4280 
4281  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4282  liftcoef = (*liftrhs) - z;
4283  liftcoefs[liftvar] = liftcoef;
4284  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4285 
4286  /* updates activity of current valid inequality */
4287  (*cutact) += liftcoef * solvals[liftvar];
4288 
4289  /* updates sum of all lifting coefficients in GUB */
4290  sumliftcoef += liftcoefs[liftvar];
4291  }
4292  else
4293  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4294  }
4295  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4296  assert(nliftgubvars > nliftgubC1);
4297 
4298  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4299  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4300  * not needed for GF GUBs
4301  */
4302  if( sumliftcoef == 0 )
4303  {
4304  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4305  {
4306  weight = weights[liftgubvars[0]];
4307  /* update finished table and minweights table by applying special case of
4308  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4309  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4310  */
4311  for( w = minweightslen-1; w >= 1; w-- )
4312  {
4313  SCIP_Longint tmpval;
4314 
4315  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4316  finished[w] = MIN(finished[w], tmpval);
4317 
4318  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4319  minweights[w] = MIN(minweights[w], tmpval);
4320  }
4321  }
4322  else
4323  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4324 
4325  continue;
4326  }
4327 
4328  /* enlarges current minweights tables(finished, unfinished, minweights):
4329  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4330  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4331  * and sets minweights_i[w] = infinity for
4332  * 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
4333  */
4334  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4335  tmpsize = minweightssize;
4336  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4337  tmplen = minweightslen;
4338  tmpsize = minweightssize;
4339  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4340  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4341 
4342  /* update finished table and minweight table;
4343  * note that instead of computing minweight table from updated finished and updated unfinished table again
4344  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4345  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4346  * not needed because only finished table changed at this point and the change was "adding" one weight)
4347  *
4348  * update formular for minweight table is: minweight_i+1[w] =
4349  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4350  * formular for finished table has the same pattern.
4351  */
4352  for( w = minweightslen-1; w >= 0; w-- )
4353  {
4354  SCIP_Longint minminweight;
4355  SCIP_Longint minfinished;
4356 
4357  for( k = 0; k < nliftgubvars; k++ )
4358  {
4359  liftcoef = liftcoefs[liftgubvars[k]];
4360  weight = weights[liftgubvars[k]];
4361 
4362  if( w < liftcoef )
4363  {
4364  minfinished = MIN(finished[w], weight);
4365  minminweight = MIN(minweights[w], weight);
4366 
4367  finished[w] = minfinished;
4368  minweights[w] = minminweight;
4369  }
4370  else
4371  {
4372  SCIP_Longint tmpval;
4373 
4374  assert(w >= liftcoef);
4375 
4376  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4377  minfinished = MIN(finished[w], tmpval);
4378 
4379  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4380  minminweight = MIN(minweights[w], tmpval);
4381 
4382  finished[w] = minfinished;
4383  minweights[w] = minminweight;
4384  }
4385  }
4386  }
4387  assert(minweights[0] == 0);
4388  }
4389  assert(ngubconsGNC1 == 0);
4390 
4391  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4392  * therefore, only work with minweight table from here on
4393  */
4394 
4395  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4396  for( j = 0; j < ngubconsGC2; j++ )
4397  {
4398  liftgubconsidx = gubconsGC2[j];
4399 
4400  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4401  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4402  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4403  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4404 
4405  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4406  weight = weights[liftvar];
4407 
4408  assert(liftvar >= 0 && liftvar < nvars);
4409  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4410  assert(weight > 0);
4411 
4412  /* uses binary search to find
4413  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4414  */
4415  left = 0;
4416  right = minweightslen;
4417  while( left < right - 1 )
4418  {
4419  middle = (left + right) / 2;
4420  assert(0 <= middle && middle < minweightslen);
4421  if( minweights[middle] <= capacity - fixedonesweight + weight )
4422  left = middle;
4423  else
4424  right = middle;
4425  }
4426  assert(left == right - 1);
4427  assert(0 <= left && left < minweightslen);
4428  assert(minweights[left] <= capacity - fixedonesweight + weight);
4429  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4430 
4431  /* now z = left */
4432  z = left;
4433  assert(z >= *liftrhs);
4434 
4435  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4436  liftcoef = z - (*liftrhs);
4437  liftcoefs[liftvar] = liftcoef;
4438  assert(liftcoef >= 0);
4439 
4440  /* updates sum of weights of variables fixed to one */
4441  fixedonesweight -= weight;
4442 
4443  /* updates right-hand side of current valid inequality */
4444  (*liftrhs) += liftcoef;
4445  assert(*liftrhs >= alpha0);
4446 
4447  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4448  if( liftcoef == 0 )
4449  continue;
4450 
4451  /* updates activity of current valid inequality */
4452  (*cutact) += liftcoef * solvals[liftvar];
4453 
4454  /* enlarges current minweight table:
4455  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4456  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4457  * and sets minweights_i[w] = infinity for
4458  * 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
4459  */
4460  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4461 
4462  /* updates minweight table: minweight_i+1[w] =
4463  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4464  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4465  */
4466  for( w = minweightslen - 1; w >= 0; w-- )
4467  {
4468  if( w < liftcoef )
4469  {
4470  min = MIN(minweights[w], weight);
4471  minweights[w] = min;
4472  }
4473  else
4474  {
4475  SCIP_Longint tmpval;
4476 
4477  assert(w >= liftcoef);
4478 
4479  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4480  min = MIN(minweights[w], tmpval);
4481  minweights[w] = min;
4482  }
4483  }
4484  }
4485  assert(fixedonesweight == 0);
4486  assert(*liftrhs >= alpha0);
4487 
4488  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4489  for( j = 0; j < ngubconsGR; j++ )
4490  {
4491  liftgubconsidx = gubconsGR[j];
4492 
4493  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4494  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4495 
4496  sumliftcoef = 0;
4497  nliftgubvars = 0;
4498  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4499  {
4500  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4501  {
4502  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4503  weight = weights[liftvar];
4504  assert(weight > 0);
4505  assert(liftvar >= 0 && liftvar < nvars);
4506  assert(capacity - weight >= 0);
4507  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4508 
4509  /* put variable into array of variables in GUB that are considered for the lifting,
4510  * i.e., not capacity exceeding
4511  */
4512  liftgubvars[nliftgubvars] = liftvar;
4513  nliftgubvars++;
4514 
4515  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4516  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4517  */
4518  if( minweights[*liftrhs] <= capacity - weight )
4519  {
4520  z = *liftrhs;
4521  }
4522  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4523  */
4524  else
4525  {
4526  left = 0;
4527  right = (*liftrhs) + 1;
4528  while( left < right - 1 )
4529  {
4530  middle = (left + right) / 2;
4531  assert(0 <= middle && middle < minweightslen);
4532  if( minweights[middle] <= capacity - weight )
4533  left = middle;
4534  else
4535  right = middle;
4536  }
4537  assert(left == right - 1);
4538  assert(0 <= left && left < minweightslen);
4539  assert(minweights[left] <= capacity - weight);
4540  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4541 
4542  /* now z = left */
4543  z = left;
4544  assert(z <= *liftrhs);
4545  }
4546  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4547  liftcoef = (*liftrhs) - z;
4548  liftcoefs[liftvar] = liftcoef;
4549  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4550 
4551  /* updates activity of current valid inequality */
4552  (*cutact) += liftcoef * solvals[liftvar];
4553 
4554  /* updates sum of all lifting coefficients in GUB */
4555  sumliftcoef += liftcoefs[liftvar];
4556  }
4557  else
4558  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4559  }
4560  assert(nliftgubvars >= 1); /* at least one variable is in R */
4561 
4562  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4563  if( sumliftcoef == 0 )
4564  continue;
4565 
4566  /* updates minweight table: minweight_i+1[w] =
4567  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4568  */
4569  for( w = *liftrhs; w >= 0; w-- )
4570  {
4571  for( k = 0; k < nliftgubvars; k++ )
4572  {
4573  liftcoef = liftcoefs[liftgubvars[k]];
4574  weight = weights[liftgubvars[k]];
4575 
4576  if( w < liftcoef )
4577  {
4578  min = MIN(minweights[w], weight);
4579  minweights[w] = min;
4580  }
4581  else
4582  {
4583  SCIP_Longint tmpval;
4584 
4585  assert(w >= liftcoef);
4586 
4587  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4588  min = MIN(minweights[w], tmpval);
4589  minweights[w] = min;
4590  }
4591  }
4592  }
4593  assert(minweights[0] == 0);
4594  }
4595 
4596  /* frees temporary memory */
4597  SCIPfreeBufferArray(scip, &minweights);
4598  SCIPfreeBufferArray(scip, &finished);
4599  SCIPfreeBufferArray(scip, &unfinished);
4600  SCIPfreeBufferArray(scip, &liftgubvars);
4601  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4602  SCIPfreeBufferArray(scip, &gubconsGNC1);
4603 
4604  return SCIP_OKAY;
4605 }
4606 
4607 /** lifts given minimal cover inequality
4608  * \f[
4609  * \sum_{j \in C} x_j \leq |C| - 1
4610  * \f]
4611  * valid for
4612  * \f[
4613  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4614  * \f]
4615  * to a valid inequality
4616  * \f[
4617  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4618  * \f]
4619  * for
4620  * \f[
4621  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4622  * \f]
4623  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4624  */
4625 static
4627  SCIP* scip, /**< SCIP data structure */
4628  SCIP_VAR** vars, /**< variables in knapsack constraint */
4629  int nvars, /**< number of variables in knapsack constraint */
4630  int ntightened, /**< number of variables with tightened upper bound */
4631  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4632  SCIP_Longint capacity, /**< capacity of knapsack */
4633  SCIP_Real* solvals, /**< solution values of all problem variables */
4634  int* covervars, /**< cover variables */
4635  int* noncovervars, /**< noncover variables */
4636  int ncovervars, /**< number of cover variables */
4637  int nnoncovervars, /**< number of noncover variables */
4638  SCIP_Longint coverweight, /**< weight of cover */
4639  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4640  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4641  )
4642 {
4643  SCIP_Longint* maxweightsums;
4644  SCIP_Longint* intervalends;
4645  SCIP_Longint* rhos;
4646  SCIP_Real* sortkeys;
4647  SCIP_Longint lambda;
4648  int j;
4649  int h;
4650 
4651  assert(scip != NULL);
4652  assert(vars != NULL);
4653  assert(nvars >= 0);
4654  assert(weights != NULL);
4655  assert(capacity >= 0);
4656  assert(solvals != NULL);
4657  assert(covervars != NULL);
4658  assert(noncovervars != NULL);
4659  assert(ncovervars > 0 && ncovervars <= nvars);
4660  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4661  assert(ncovervars + nnoncovervars == nvars - ntightened);
4662  assert(liftcoefs != NULL);
4663  assert(cutact != NULL);
4664 
4665  /* allocates temporary memory */
4666  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4667  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4668  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4669  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4670 
4671  /* initializes data structures */
4672  BMSclearMemoryArray(liftcoefs, nvars);
4673  *cutact = 0.0;
4674 
4675  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4676  * and calculates activity of current valid inequality
4677  */
4678  for( j = 0; j < ncovervars; j++ )
4679  {
4680  assert(liftcoefs[covervars[j]] == 0.0);
4681  liftcoefs[covervars[j]] = 1.0;
4682  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4683  (*cutact) += solvals[covervars[j]];
4684  }
4685  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4686 
4687  /* calculates weight excess of cover C */
4688  lambda = coverweight - capacity;
4689  assert(lambda > 0);
4690 
4691  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4692  maxweightsums[0] = 0;
4693  for( h = 1; h <= ncovervars; h++ )
4694  {
4695  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4696  intervalends[h-1] = maxweightsums[h] - lambda;
4697  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4698  }
4699 
4700  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4701  for( j = 0; j < nnoncovervars; j++ )
4702  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4703  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4704 
4705  /* calculates lifting coefficient for all variables in N\C */
4706  h = 0;
4707  for( j = 0; j < nnoncovervars; j++ )
4708  {
4709  int liftvar;
4710  SCIP_Longint weight;
4711  SCIP_Real liftcoef;
4712 
4713  liftvar = noncovervars[j];
4714  weight = weights[liftvar];
4715 
4716  while( intervalends[h] < weight )
4717  h++;
4718 
4719  if( h == 0 )
4720  liftcoef = h;
4721  else
4722  {
4723  if( weight <= intervalends[h-1] + rhos[h] )
4724  {
4725  SCIP_Real tmp1;
4726  SCIP_Real tmp2;
4727  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4728  tmp2 = (SCIP_Real) rhos[1];
4729  liftcoef = h - ( tmp1 / tmp2 );
4730  }
4731  else
4732  liftcoef = h;
4733  }
4734 
4735  /* sets lifting coefficient */
4736  assert(liftcoefs[liftvar] == 0.0);
4737  liftcoefs[liftvar] = liftcoef;
4738 
4739  /* updates activity of current valid inequality */
4740  (*cutact) += liftcoef * solvals[liftvar];
4741  }
4742 
4743  /* frees temporary memory */
4744  SCIPfreeBufferArray(scip, &rhos);
4745  SCIPfreeBufferArray(scip, &intervalends);
4746  SCIPfreeBufferArray(scip, &maxweightsums);
4747  SCIPfreeBufferArray(scip, &sortkeys);
4748 
4749  return SCIP_OKAY;
4750 }
4751 
4752 
4753 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4754  * given knapsack problem
4755 */
4756 static
4758  SCIP* scip, /**< SCIP data structure */
4759  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4760  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4761  SCIP_VAR** vars, /**< variables in knapsack constraint */
4762  int nvars, /**< number of variables in knapsack constraint */
4763  int ntightened, /**< number of variables with tightened upper bound */
4764  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4765  SCIP_Longint capacity, /**< capacity of knapsack */
4766  SCIP_Real* solvals, /**< solution values of all problem variables */
4767  int* mincovervars, /**< mincover variables */
4768  int* nonmincovervars, /**< nonmincover variables */
4769  int nmincovervars, /**< number of mincover variables */
4770  int nnonmincovervars, /**< number of nonmincover variables */
4771  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4772  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4773  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4774  int* ncuts /**< pointer to add up the number of found cuts */
4775  )
4776 {
4777  int* varsC1;
4778  int* varsC2;
4779  int* varsF;
4780  int* varsR;
4781  int nvarsC1;
4782  int nvarsC2;
4783  int nvarsF;
4784  int nvarsR;
4785  SCIP_Real cutact;
4786  int* liftcoefs;
4787  int liftrhs;
4788 
4789  assert( cutoff != NULL );
4790  *cutoff = FALSE;
4791 
4792  /* allocates temporary memory */
4793  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4794  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4795  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4796  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4797  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4798 
4799  /* 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
4800  * as follows
4801  * C_2 = { j in C : x*_j = 1 } and
4802  * C_1 = C\C_2
4803  */
4804  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4805  assert(nvarsC1 + nvarsC2 == nmincovervars);
4806  assert(nmincovervars > 0);
4807  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4808 
4809  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4810  if( nvarsC1 < 2 && nvarsC2 > 0)
4811  {
4812  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4813  assert(nvarsC1 >= 1);
4814  }
4815  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4816 
4817  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4818  * R = { j in N\C : x*_j = 0 } and
4819  * F = (N\C)\F
4820  */
4821  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4822  assert(nvarsF + nvarsR == nnonmincovervars);
4823  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4824 
4825  /* lift cuts without GUB information */
4826  if( gubset == NULL )
4827  {
4828  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4829  * lifting procedure
4830  */
4831  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4832 
4833  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4834  *
4835  * 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 }
4836  *
4837  * 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
4838  *
4839  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4840  *
4841  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4842  * up-lifting for the variables in R according to the second level lifting sequence
4843  */
4844  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4845  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4846  }
4847  /* lift cuts with GUB information */
4848  else
4849  {
4850  int* gubconsGC1;
4851  int* gubconsGC2;
4852  int* gubconsGFC1;
4853  int* gubconsGR;
4854  int ngubconsGC1;
4855  int ngubconsGC2;
4856  int ngubconsGFC1;
4857  int ngubconsGR;
4858  int ngubconss;
4859  int nconstightened;
4860  int maxgubvarssize;
4861 
4862  assert(nvars == gubset->nvars);
4863 
4864  ngubconsGC1 = 0;
4865  ngubconsGC2 = 0;
4866  ngubconsGFC1 = 0;
4867  ngubconsGR = 0;
4868  ngubconss = gubset->ngubconss;
4869  nconstightened = 0;
4870  maxgubvarssize = 0;
4871 
4872  /* allocates temporary memory */
4873  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4874  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4875  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4876  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4877 
4878  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4879  * the GUBs for the sequential GUB wise lifting procedure
4880  */
4881  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4882  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4883  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4884 
4885  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4886  *
4887  * 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,
4888  * sum_{j in Q_i} x_j <= 1, forall i in I }
4889  *
4890  * 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
4891  *
4892  * 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 },
4893  *
4894  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4895  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4896  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4897  */
4898  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4899  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4900  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4901 
4902  /* frees temporary memory */
4903  SCIPfreeBufferArray(scip, &gubconsGR);
4904  SCIPfreeBufferArray(scip, &gubconsGFC1);
4905  SCIPfreeBufferArray(scip, &gubconsGC2);
4906  SCIPfreeBufferArray(scip, &gubconsGC1);
4907  }
4908 
4909  /* checks, if lifting yielded a violated cut */
4910  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4911  {
4912  SCIP_ROW* row;
4913  char name[SCIP_MAXSTRLEN];
4914  int j;
4915 
4916  /* creates LP row */
4917  assert( cons == NULL || sepa == NULL );
4918  if ( cons != NULL )
4919  {
4920  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4921  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4922  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4923  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4924  }
4925  else if ( sepa != NULL )
4926  {
4927  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4928  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4929  }
4930  else
4931  {
4932  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
4933  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4934  }
4935 
4936  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4937  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4938  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4939  for( j = 0; j < nvarsC1; j++ )
4940  {
4941  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4942  }
4943  for( j = 0; j < nvarsC2; j++ )
4944  {
4945  if( liftcoefs[varsC2[j]] > 0 )
4946  {
4947  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4948  }
4949  }
4950  for( j = 0; j < nvarsF; j++ )
4951  {
4952  if( liftcoefs[varsF[j]] > 0 )
4953  {
4954  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4955  }
4956  }
4957  for( j = 0; j < nvarsR; j++ )
4958  {
4959  if( liftcoefs[varsR[j]] > 0 )
4960  {
4961  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4962  }
4963  }
4964  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4965 
4966  /* checks, if cut is violated enough */
4967  if( SCIPisCutEfficacious(scip, sol, row) )
4968  {
4969  if( cons != NULL )
4970  {
4971  SCIP_CALL( SCIPresetConsAge(scip, cons) );
4972  }
4973  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
4974  (*ncuts)++;
4975  }
4976  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4977  }
4978 
4979  /* frees temporary memory */
4980  SCIPfreeBufferArray(scip, &liftcoefs);
4981  SCIPfreeBufferArray(scip, &varsR);
4982  SCIPfreeBufferArray(scip, &varsF);
4983  SCIPfreeBufferArray(scip, &varsC2);
4984  SCIPfreeBufferArray(scip, &varsC1);
4985 
4986  return SCIP_OKAY;
4987 }
4988 
4989 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
4990 static
4992  SCIP* scip, /**< SCIP data structure */
4993  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
4994  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4995  SCIP_VAR** vars, /**< variables in knapsack constraint */
4996  int nvars, /**< number of variables in knapsack constraint */
4997  int ntightened, /**< number of variables with tightened upper bound */
4998  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4999  SCIP_Longint capacity, /**< capacity of knapsack */
5000  SCIP_Real* solvals, /**< solution values of all problem variables */
5001  int* feassetvars, /**< variables in feasible set */
5002  int* nonfeassetvars, /**< variables not in feasible set */
5003  int nfeassetvars, /**< number of variables in feasible set */
5004  int nnonfeassetvars, /**< number of variables not in feasible set */
5005  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5006  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5007  int* ncuts /**< pointer to add up the number of found cuts */
5008  )
5009 {
5010  int* varsT1;
5011  int* varsT2;
5012  int* varsF;
5013  int* varsR;
5014  int* liftcoefs;
5015  SCIP_Real cutact;
5016  int nvarsT1;
5017  int nvarsT2;
5018  int nvarsF;
5019  int nvarsR;
5020  int liftrhs;
5021  int j;
5022 
5023  assert( cutoff != NULL );
5024  *cutoff = FALSE;
5025 
5026  /* allocates temporary memory */
5027  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5028  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5029  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5030  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5031  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5032 
5033  /* 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
5034  * as follows
5035  * T_2 = { j in T : x*_j = 1 } and
5036  * T_1 = T\T_2
5037  */
5038  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5039  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5040 
5041  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5042  if( nvarsT1 == 0 && nvarsT2 > 0)
5043  {
5044  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5045  assert(nvarsT1 == 1);
5046  }
5047  assert(nvarsT2 == 0 || nvarsT1 > 0);
5048 
5049  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5050  * R = { j in N\T : x*_j = 0 } and
5051  * F = (N\T)\F
5052  */
5053  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5054  assert(nvarsF + nvarsR == nnonfeassetvars);
5055  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5056 
5057  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5058  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5059  * is included in the sorting routine)
5060  */
5061  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5062 
5063  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5064  *
5065  * 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 }
5066  *
5067  * 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
5068  *
5069  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5070  *
5071  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5072  * up-lifting for the variabels in R according to the second level lifting sequence
5073  */
5074  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5075  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5076 
5077  /* checks, if lifting yielded a violated cut */
5078  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5079  {
5080  SCIP_ROW* row;
5081  char name[SCIP_MAXSTRLEN];
5082 
5083  /* creates LP row */
5084  assert( cons == NULL || sepa == NULL );
5085  if( cons != NULL )
5086  {
5087  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5088  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5089  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5090  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5091  }
5092  else if ( sepa != NULL )
5093  {
5094  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5095  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5096  }
5097  else
5098  {
5099  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
5100  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5101  }
5102 
5103  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5104  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5105  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5106  for( j = 0; j < nvarsT1; j++ )
5107  {
5108  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5109  }
5110  for( j = 0; j < nvarsT2; j++ )
5111  {
5112  if( liftcoefs[varsT2[j]] > 0 )
5113  {
5114  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5115  }
5116  }
5117  for( j = 0; j < nvarsF; j++ )
5118  {
5119  if( liftcoefs[varsF[j]] > 0 )
5120  {
5121  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5122  }
5123  }
5124  for( j = 0; j < nvarsR; j++ )
5125  {
5126  if( liftcoefs[varsR[j]] > 0 )
5127  {
5128  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5129  }
5130  }
5131  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5132 
5133  /* checks, if cut is violated enough */
5134  if( SCIPisCutEfficacious(scip, sol, row) )
5135  {
5136  if( cons != NULL )
5137  {
5138  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5139  }
5140  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
5141  (*ncuts)++;
5142  }
5143  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5144  }
5145 
5146  /* frees temporary memory */
5147  SCIPfreeBufferArray(scip, &liftcoefs);
5148  SCIPfreeBufferArray(scip, &varsR);
5149  SCIPfreeBufferArray(scip, &varsF);
5150  SCIPfreeBufferArray(scip, &varsT2);
5151  SCIPfreeBufferArray(scip, &varsT1);
5152 
5153  return SCIP_OKAY;
5154 }
5155 
5156 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5157 static
5159  SCIP* scip, /**< SCIP data structure */
5160  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5161  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5162  SCIP_VAR** vars, /**< variables in knapsack constraint */
5163  int nvars, /**< number of variables in knapsack constraint */
5164  int ntightened, /**< number of variables with tightened upper bound */
5165  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5166  SCIP_Longint capacity, /**< capacity of knapsack */
5167  SCIP_Real* solvals, /**< solution values of all problem variables */
5168  int* mincovervars, /**< mincover variables */
5169  int* nonmincovervars, /**< nonmincover variables */
5170  int nmincovervars, /**< number of mincover variables */
5171  int nnonmincovervars, /**< number of nonmincover variables */
5172  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5173  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5174  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5175  int* ncuts /**< pointer to add up the number of found cuts */
5176  )
5177 {
5178  SCIP_Real* realliftcoefs;
5179  SCIP_Real cutact;
5180  int liftrhs;
5181 
5182  assert( cutoff != NULL );
5183  *cutoff = FALSE;
5184  cutact = 0.0;
5185 
5186  /* allocates temporary memory */
5187  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5188 
5189  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5190  *
5191  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5192  *
5193  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5194  *
5195  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5196  *
5197  * uses superadditive up-lifting for the variables in N\C.
5198  */
5199  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5200  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5201  liftrhs = nmincovervars - 1;
5202 
5203  /* checks, if lifting yielded a violated cut */
5204  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5205  {
5206  SCIP_ROW* row;
5207  char name[SCIP_MAXSTRLEN];
5208  int j;
5209 
5210  /* creates LP row */
5211  assert( cons == NULL || sepa == NULL );
5212  if ( cons != NULL )
5213  {
5214  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5215  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5216  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5217  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5218  }
5219  else if ( sepa != NULL )
5220  {
5221  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5222  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5223  }
5224  else
5225  {
5226  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%" SCIP_LONGINT_FORMAT "", *ncuts);
5227  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5228  }
5229 
5230  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5231  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5232  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5233  for( j = 0; j < nmincovervars; j++ )
5234  {
5235  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5236  }
5237  for( j = 0; j < nnonmincovervars; j++ )
5238  {
5239  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5240  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5241  {
5242  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5243  }
5244  }
5245  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5246 
5247  /* checks, if cut is violated enough */
5248  if( SCIPisCutEfficacious(scip, sol, row) )
5249  {
5250  if( cons != NULL )
5251  {
5252  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5253  }
5254  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
5255  (*ncuts)++;
5256  }
5257  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5258  }
5259 
5260  /* frees temporary memory */
5261  SCIPfreeBufferArray(scip, &realliftcoefs);
5262 
5263  return SCIP_OKAY;
5264 }
5265 
5266 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5267  * 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
5268  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5269  * note that all variables with x*_j = 1 will be removed last
5270  */
5271 static
5273  SCIP* scip, /**< SCIP data structure */
5274  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5275  SCIP_Longint capacity, /**< capacity of knapsack */
5276  SCIP_Real* solvals, /**< solution values of all problem variables */
5277  int* covervars, /**< pointer to store cover variables */
5278  int* noncovervars, /**< pointer to store noncover variables */
5279  int* ncovervars, /**< pointer to store number of cover variables */
5280  int* nnoncovervars, /**< pointer to store number of noncover variables */
5281  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5282  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5283  )
5284 {
5285  SORTKEYPAIR** sortkeypairs;
5286  SCIP_Longint minweight;
5287  int nsortkeypairs;
5288  int minweightidx;
5289  int j;
5290  int k;
5291 
5292  assert(scip != NULL);
5293  assert(covervars != NULL);
5294  assert(noncovervars != NULL);
5295  assert(ncovervars != NULL);
5296  assert(*ncovervars > 0);
5297  assert(nnoncovervars != NULL);
5298  assert(*nnoncovervars >= 0);
5299  assert(coverweight != NULL);
5300  assert(*coverweight > 0);
5301  assert(*coverweight > capacity);
5302 
5303  /* allocates temporary memory */
5304  nsortkeypairs = *ncovervars;
5305  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5306 
5307  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5308  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5309  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5310  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5311  */
5312  assert(*ncovervars == nsortkeypairs);
5313  if( modtransused )
5314  {
5315  for( j = 0; j < *ncovervars; j++ )
5316  {
5317  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5318 
5319  sortkeypairs[j]->key1 = solvals[covervars[j]];
5320  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5321  }
5322  }
5323  else
5324  {
5325  for( j = 0; j < *ncovervars; j++ )
5326  {
5327  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5328 
5329  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5330  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5331  }
5332  }
5333  SCIPsortPtrInt((void**)sortkeypairs, covervars, compSortkeypairs, *ncovervars);
5334 
5335  /* gets j' with a_j' = min{ a_j : j in C } */
5336  minweightidx = 0;
5337  minweight = weights[covervars[minweightidx]];
5338  for( j = 1; j < *ncovervars; j++ )
5339  {
5340  if( weights[covervars[j]] <= minweight )
5341  {
5342  minweightidx = j;
5343  minweight = weights[covervars[minweightidx]];
5344  }
5345  }
5346  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5347  assert(minweight > 0 && minweight <= *coverweight);
5348 
5349  j = 0;
5350  /* removes variables from C until the remaining variables form a minimal cover */
5351  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5352  {
5353  assert(minweightidx >= j);
5354  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5355 
5356  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5357  if( (*coverweight) - weights[covervars[j]] <= capacity )
5358  {
5359  ++j;
5360  continue;
5361  }
5362 
5363  /* adds j to N\C */
5364  noncovervars[*nnoncovervars] = covervars[j];
5365  (*nnoncovervars)++;
5366 
5367  /* removes j from C */
5368  (*coverweight) -= weights[covervars[j]];
5369  for( k = j; k < (*ncovervars) - 1; k++ )
5370  covervars[k] = covervars[k+1];
5371  (*ncovervars)--;
5372 
5373  /* updates j' with a_j' = min{ a_j : j in C } */
5374  if( j == minweightidx )
5375  {
5376  minweightidx = 0;
5377  minweight = weights[covervars[minweightidx]];
5378  for( k = 1; k < *ncovervars; k++ )
5379  {
5380  if( weights[covervars[k]] <= minweight )
5381  {
5382  minweightidx = k;
5383  minweight = weights[covervars[minweightidx]];
5384  }
5385  }
5386  assert(minweight > 0 && minweight <= *coverweight);
5387  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5388  }
5389  else
5390  {
5391  assert(minweightidx > j);
5392  minweightidx--;
5393  }
5394  /* j needs to stay the same */
5395  }
5396  assert((*coverweight) > capacity);
5397  assert((*coverweight) - minweight <= capacity);
5398 
5399  /* frees temporary memory */
5400  for( j = nsortkeypairs-1; j >= 0; j-- )
5401  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5402  SCIPfreeBufferArray(scip, &sortkeypairs);
5403 
5404  return SCIP_OKAY;
5405 }
5406 
5407 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5408  * they were chosen to be in C_init:
5409  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5410  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5411  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5412  * and all subsequent feasible sets.
5413  */
5414 static
5416  SCIP* scip, /**< SCIP data structure */
5417  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5418  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5419  SCIP_VAR** vars, /**< variables in knapsack constraint */
5420  int nvars, /**< number of variables in knapsack constraint */
5421  int ntightened, /**< number of variables with tightened upper bound */
5422  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5423  SCIP_Longint capacity, /**< capacity of knapsack */
5424  SCIP_Real* solvals, /**< solution values of all problem variables */
5425  int* covervars, /**< pointer to store cover variables */
5426  int* noncovervars, /**< pointer to store noncover variables */
5427  int* ncovervars, /**< pointer to store number of cover variables */
5428  int* nnoncovervars, /**< pointer to store number of noncover variables */
5429  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5430  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5431  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5432  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5433  int* ncuts /**< pointer to add up the number of found cuts */
5434  )
5435 {
5436  SCIP_Real* sortkeys;
5437  int j;
5438  int k;
5439 
5440  assert(scip != NULL);
5441  assert(covervars != NULL);
5442  assert(noncovervars != NULL);
5443  assert(ncovervars != NULL);
5444  assert(*ncovervars > 0);
5445  assert(nnoncovervars != NULL);
5446  assert(*nnoncovervars >= 0);
5447  assert(coverweight != NULL);
5448  assert(*coverweight > 0);
5449  assert(*coverweight > capacity);
5450  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5451  assert(cutoff != NULL);
5452 
5453  *cutoff = FALSE;
5454 
5455  /* allocates temporary memory */
5456  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5457 
5458  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5459  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5460  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5461  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5462  */
5463  if( modtransused )
5464  {
5465  for( j = 0; j < *ncovervars; j++ )
5466  {
5467  sortkeys[j] = solvals[covervars[j]];
5468  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5469  }
5470  }
5471  else
5472  {
5473  for( j = 0; j < *ncovervars; j++ )
5474  {
5475  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5476  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5477  }
5478  }
5479  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5480 
5481  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5482  * in addition to an extended weight inequality this gives cardinality inequalities */
5483  while( *ncovervars >= 2 )
5484  {
5485  /* adds first element of C_init to N\C_init */
5486  noncovervars[*nnoncovervars] = covervars[0];
5487  (*nnoncovervars)++;
5488 
5489  /* removes first element from C_init */
5490  (*coverweight) -= weights[covervars[0]];
5491  for( k = 0; k < (*ncovervars) - 1; k++ )
5492  covervars[k] = covervars[k+1];
5493  (*ncovervars)--;
5494 
5495  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5496  if( (*coverweight) <= capacity )
5497  {
5498  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5499  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5500  }
5501 
5502  /* stop if cover is too large */
5503  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5504  break;
5505  }
5506 
5507  /* frees temporary memory */
5508  SCIPfreeBufferArray(scip, &sortkeys);
5509 
5510  return SCIP_OKAY;
5511 }
5512 
5513 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5515  SCIP* scip, /**< SCIP data structure */
5516  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5517  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5518  SCIP_VAR** vars, /**< variables in knapsack constraint */
5519  int nvars, /**< number of variables in knapsack constraint */
5520  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5521  SCIP_Longint capacity, /**< capacity of knapsack */
5522  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5523  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5524  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5525  int* ncuts /**< pointer to add up the number of found cuts */
5526  )
5527 {
5528  SCIP_Real* solvals;
5529  int* covervars;
5530  int* noncovervars;
5531  SCIP_Bool coverfound;
5532  SCIP_Bool fractional;
5533  SCIP_Bool modtransused;
5534  SCIP_Longint coverweight;
5535  int ncovervars;
5536  int nnoncovervars;
5537  int ntightened;
5538 
5539  assert(scip != NULL);
5540  assert(capacity >= 0);
5541  assert(cutoff != NULL);
5542  assert(ncuts != NULL);
5543 
5544  *cutoff = FALSE;
5545 
5546  if( nvars == 0 )
5547  return SCIP_OKAY;
5548 
5549  assert(vars != NULL);
5550  assert(nvars > 0);
5551  assert(weights != NULL);
5552 
5553  /* increase age of constraint (age is reset to zero, if a cut was found) */
5554  if( cons != NULL )
5555  {
5556  SCIP_CALL( SCIPincConsAge(scip, cons) );
5557  }
5558 
5559  /* allocates temporary memory */
5560  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5561  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5562  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5563 
5564  /* gets solution values of all problem variables */
5565  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5566 
5567 #ifdef SCIP_DEBUG
5568  {
5569  int i;
5570 
5571  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5572  cons == NULL ? "-" : SCIPconsGetName(cons));
5573  for( i = 0; i < nvars; ++i )
5574  {
5575  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5576  }
5577  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5578  }
5579 #endif
5580 
5581  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5582  */
5583  if( usegubs )
5584  {
5585  SCIP_GUBSET* gubset;
5586 
5587  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5588 
5589  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5590  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5591 
5592  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5593  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5594  assert(gubset->ngubconss <= nvars);
5595 
5596  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5597  * MODIFIED transformed separation problem and taking into account the following fixing:
5598  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5599  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5600  * if one exists
5601  */
5602  modtransused = TRUE;
5603  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5604  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5605 
5606  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5607 
5608  /* if x* is not fractional we stop the separation routine */
5609  if( !fractional )
5610  {
5611  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5612 
5613  /* frees memory for GUB set data structure */
5614  SCIP_CALL( GUBsetFree(scip, &gubset) );
5615 
5616  goto TERMINATE;
5617  }
5618 
5619  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5620  if( coverfound )
5621  {
5622  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5623  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5624  */
5625  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5626  &nnoncovervars, &coverweight, modtransused) );
5627 
5628  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5629  if( gubset->ngubconss < nvars )
5630  {
5631  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5632  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5633  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5634  }
5635  else
5636  {
5637  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5638  * GUB information
5639  */
5640  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5641  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5642  }
5643  }
5644 
5645  /* frees memory for GUB set data structure */
5646  SCIP_CALL( GUBsetFree(scip, &gubset) );
5647  }
5648  else
5649  {
5650  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5651  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5652  */
5653 
5654  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5655  * MODIFIED transformed separation problem and taking into account the following fixing:
5656  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5657  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5658  * if one exists
5659  */
5660  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5661  modtransused = TRUE;
5662  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5663  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5664  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5665 
5666  /* if x* is not fractional we stop the separation routine */
5667  if( !fractional )
5668  goto TERMINATE;
5669 
5670  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5671  if( coverfound )
5672  {
5673  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5674  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5675  */
5676  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5677  &nnoncovervars, &coverweight, modtransused) );
5678 
5679  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5680  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5681  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5682 
5683  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5684  {
5685  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5686  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5687  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5688  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5689  }
5690  }
5691  }
5692 
5693  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5694  if ( ! (*cutoff) )
5695  {
5696  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5697  * transformed separation problem and taking into account the following fixing:
5698  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5699  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5700  * if one exists
5701  */
5702  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5703  modtransused = FALSE;
5704  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5705  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5706  assert(fractional);
5707  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5708 
5709  /* if no cover was found we stop the separation routine */
5710  if( coverfound )
5711  {
5712  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5713  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5714  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5715  */
5716  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5717  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5718  }
5719  }
5720 
5721  TERMINATE:
5722  /* frees temporary memory */
5723  SCIPfreeBufferArray(scip, &noncovervars);
5724  SCIPfreeBufferArray(scip, &covervars);
5725  SCIPfreeBufferArray(scip, &solvals);
5726 
5727  return SCIP_OKAY;
5728 }
5729 
5730 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5732  SCIP* scip, /**< SCIP data structure */
5733  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5734  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5735  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5736  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5737  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5738  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5739  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5740  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5741  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5742  int* ncuts /**< pointer to add up the number of found cuts */
5743  )
5744 {
5745  SCIP_VAR** binvars;
5746  SCIP_VAR** consvars;
5747  SCIP_Real* binvals;
5748  SCIP_Longint* consvals;
5749  SCIP_Longint minact;
5750  SCIP_Longint maxact;
5751  SCIP_Real intscalar;
5752  SCIP_Bool success;
5753  int nbinvars;
5754  int nconsvars;
5755  int i;
5756 
5757  int* tmpindices;
5758  int tmp;
5759  SCIP_CONSHDLR* conshdlr;
5760  SCIP_CONSHDLRDATA* conshdlrdata;
5761  SCIP_Bool noknapsackconshdlr;
5762  SCIP_Bool usegubs;
5763 
5764  assert(nknapvars > 0);
5765  assert(knapvars != NULL);
5766  assert(cutoff != NULL);
5767 
5768  tmpindices = NULL;
5769 
5770  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5771  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5772 
5773  binvars = SCIPgetVars(scip);
5774 
5775  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5776  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5777 
5778  *cutoff = FALSE;
5779 
5780  if( nbinvars == 0 )
5781  return SCIP_OKAY;
5782 
5783  /* set up data structures */
5784  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5785  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5786 
5787  /* get conshdlrdata to use cleared memory */
5788  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5789  if( conshdlr == NULL )
5790  {
5791  noknapsackconshdlr = TRUE;
5792  usegubs = DEFAULT_USEGUBS;
5793 
5794  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5795  BMSclearMemoryArray(binvals, nbinvars);
5796  }
5797  else
5798  {
5799  noknapsackconshdlr = FALSE;
5800  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5801  assert(conshdlrdata != NULL);
5802  usegubs = conshdlrdata->usegubs;
5803 
5804  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5805 
5806  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5807  * change their types to SCIP_VARTYPE_BINARY during presolving
5808  */
5809  if( conshdlrdata->reals1size == 0 )
5810  {
5811  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5812  conshdlrdata->reals1size = 1;
5813  conshdlrdata->reals1[0] = 0.0;
5814  }
5815 
5816  assert(conshdlrdata->reals1size > 0);
5817 
5818  /* next if condition should normally not be true, because it means that presolving has created more binary
5819  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5820  * transform all integers into their binary representation then it maybe happens
5821  */
5822  if( conshdlrdata->reals1size < nbinvars )
5823  {
5824  int oldsize = conshdlrdata->reals1size;
5825 
5826  conshdlrdata->reals1size = nbinvars;
5827  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5828  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5829  }
5830  binvals = conshdlrdata->reals1;
5831 
5832  /* check for cleared array, all entries have to be zero */
5833 #ifndef NDEBUG
5834  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5835  {
5836  assert(binvals[tmp] == 0);
5837  }
5838 #endif
5839  }
5840 
5841  tmp = 0;
5842 
5843  /* relax continuous knapsack constraint:
5844  * 1. make all variables binary:
5845  * if x_j is continuous or integer variable substitute:
5846  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5847  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5848  * 2. convert coefficients of all variables to positive integers:
5849  * - scale all coefficients a_j to a~_j integral
5850  * - substitute x~_j = 1 - x_j if a~_j < 0
5851  */
5852 
5853  /* replace integer and continuous variables with binary variables */
5854  for( i = 0; i < nknapvars; i++ )
5855  {
5856  SCIP_VAR* var;
5857 
5858  var = knapvars[i];
5859 
5860  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5861  {
5862  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5863  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5864  if( !noknapsackconshdlr )
5865  {
5866  assert(tmpindices != NULL);
5867 
5868  tmpindices[tmp] = SCIPvarGetProbindex(var);
5869  ++tmp;
5870  }
5871  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5872  }
5873  else if( valscale * knapvals[i] > 0.0 )
5874  {
5875  SCIP_VAR** zvlb;
5876  SCIP_Real* bvlb;
5877  SCIP_Real* dvlb;
5878  SCIP_Real bestlbsol;
5879  int bestlbtype;
5880  int nvlb;
5881  int j;
5882 
5883  /* a_j > 0: substitution with lb or vlb */
5884  nvlb = SCIPvarGetNVlbs(var);
5885  zvlb = SCIPvarGetVlbVars(var);
5886  bvlb = SCIPvarGetVlbCoefs(var);
5887  dvlb = SCIPvarGetVlbConstants(var);
5888 
5889  /* search for lb or vlb with maximal bound value */
5890  bestlbsol = SCIPvarGetLbGlobal(var);
5891  bestlbtype = -1;
5892  for( j = 0; j < nvlb; j++ )
5893  {
5894  /* use only numerical stable vlb with binary variable z */
5895  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5896  {
5897  SCIP_Real vlbsol;
5898 
5899  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5900  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5901  {
5902  *cutoff = TRUE;
5903  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5905  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5906  goto TERMINATE;
5907  }
5908 
5909  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5910  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5911  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5912  {
5913  bestlbsol = vlbsol;
5914  bestlbtype = j;
5915  }
5916  }
5917  }
5918 
5919  /* if no lb or vlb with binary variable was found, we have to abort */
5920  if( SCIPisInfinity(scip, -bestlbsol) )
5921  goto TERMINATE;
5922 
5923  if( bestlbtype == -1 )
5924  {
5925  rhs -= valscale * knapvals[i] * bestlbsol;
5926  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5927  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5928  }
5929  else
5930  {
5931  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5932  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5933  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5934 
5935  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5936  goto TERMINATE;
5937 
5938  if( !noknapsackconshdlr )
5939  {
5940  assert(tmpindices != NULL);
5941 
5942  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5943  ++tmp;
5944  }
5945  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5946  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5947  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5948  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5949  }
5950  }
5951  else
5952  {
5953  SCIP_VAR** zvub;
5954  SCIP_Real* bvub;
5955  SCIP_Real* dvub;
5956  SCIP_Real bestubsol;
5957  int bestubtype;
5958  int nvub;
5959  int j;
5960 
5961  assert(valscale * knapvals[i] < 0.0);
5962 
5963  /* a_j < 0: substitution with ub or vub */
5964  nvub = SCIPvarGetNVubs(var);
5965  zvub = SCIPvarGetVubVars(var);
5966  bvub = SCIPvarGetVubCoefs(var);
5967  dvub = SCIPvarGetVubConstants(var);
5968 
5969  /* search for ub or vub with minimal bound value */
5970  bestubsol = SCIPvarGetUbGlobal(var);
5971  bestubtype = -1;
5972  for( j = 0; j < nvub; j++ )
5973  {
5974  /* use only numerical stable vub with active binary variable z */
5975  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
5976  {
5977  SCIP_Real vubsol;
5978 
5979  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
5980  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
5981  {
5982  *cutoff = TRUE;
5983  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
5985  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
5986  goto TERMINATE;
5987  }
5988 
5989  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
5990  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
5991  if( SCIPisLE(scip, vubsol, bestubsol) )
5992  {
5993  bestubsol = vubsol;
5994  bestubtype = j;
5995  }
5996  }
5997  }
5998 
5999  /* if no ub or vub with binary variable was found, we have to abort */
6000  if( SCIPisInfinity(scip, bestubsol) )
6001  goto TERMINATE;
6002 
6003  if( bestubtype == -1 )
6004  {
6005  rhs -= valscale * knapvals[i] * bestubsol;
6006  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6007  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6008  }
6009  else
6010  {
6011  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6012  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6013  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6014 
6015  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6016  goto TERMINATE;
6017 
6018  if( !noknapsackconshdlr )
6019  {
6020  assert(tmpindices != NULL);
6021 
6022  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6023  ++tmp;
6024  }
6025  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6026  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6027  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6028  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6029  }
6030  }
6031  }
6032 
6033  /* convert coefficients of all (now binary) variables to positive integers:
6034  * - make all coefficients integral
6035  * - make all coefficients positive (substitute negated variable)
6036  */
6037  nconsvars = 0;
6038 
6039  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6040  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6041  */
6043  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6044  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6045 
6046  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6047  if( !success )
6048  intscalar = 1.0;
6049 
6050  /* make all coefficients integral and positive:
6051  * - scale a~_j = a_j * intscalar
6052  * - substitute x~_j = 1 - x_j if a~_j < 0
6053  */
6054  rhs = rhs*intscalar;
6055 
6056  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6057  minact = 0;
6058  maxact = 0;
6059  for( i = 0; i < nbinvars; i++ )
6060  {
6061  SCIP_VAR* var;
6062  SCIP_Longint val;
6063 
6064  val = (SCIP_Longint)SCIPfloor(scip, binvals[i]*intscalar);
6065  if( val == 0 )
6066  continue;
6067 
6068  if( val > 0 )
6069  {
6070  var = binvars[i];
6071  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6072  val, SCIPvarGetName(var), binvals[i], rhs);
6073  }
6074  else
6075  {
6076  assert(val < 0);
6077 
6078  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6079  val = -val;
6080  rhs += val;
6081  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6082  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6083  }
6084 
6085  if( SCIPvarGetLbLocal(var) > 0.5 )
6086  minact += val;
6087  if( SCIPvarGetUbLocal(var) > 0.5 )
6088  maxact += val;
6089  consvals[nconsvars] = val;
6090  consvars[nconsvars] = var;
6091  nconsvars++;
6092  }
6093 
6094  if( nconsvars > 0 )
6095  {
6096  SCIP_Longint capacity;
6097 
6098  assert(consvars != NULL);
6099  assert(consvals != NULL);
6100  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6101 
6102 #ifdef SCIP_DEBUG
6103  {
6104  SCIP_Real act;
6105 
6106  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6107  act = 0.0;
6108  for( i = 0; i < nconsvars; ++i )
6109  {
6110  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6111  SCIPgetSolVal(scip, sol, consvars[i]));
6112  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6113  }
6114  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6115  capacity, rhs, act, minact, maxact);
6116  }
6117 #endif
6118 
6119  if( minact > capacity )
6120  {
6121  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6122  *cutoff = TRUE;
6123  goto TERMINATE;
6124  }
6125 
6126  if( maxact > capacity )
6127  {
6128  /* separate lifted cut from relaxed knapsack constraint */
6129  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6130  }
6131  }
6132 
6133  TERMINATE:
6134  /* free data structures */
6135  if( noknapsackconshdlr)
6136  {
6137  SCIPfreeBufferArray(scip, &binvals);
6138  }
6139  else
6140  {
6141  /* clear binvals */
6142  for( --tmp; tmp >= 0; --tmp)
6143  {
6144  assert(tmpindices != NULL);
6145  binvals[tmpindices[tmp]] = 0;
6146  }
6147  SCIPfreeBufferArray(scip, &tmpindices);
6148  }
6149  SCIPfreeBufferArray(scip, &consvals);
6150  SCIPfreeBufferArray(scip, &consvars);
6151 
6152  return SCIP_OKAY;
6153 }
6154 
6155 /** separates given knapsack constraint */
6156 static
6158  SCIP* scip, /**< SCIP data structure */
6159  SCIP_CONS* cons, /**< knapsack constraint */
6160  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6161  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6162  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6163  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6164  int* ncuts /**< pointer to add up the number of found cuts */
6165  )
6166 {
6167  SCIP_CONSDATA* consdata;
6168  SCIP_Bool violated;
6169 
6170  assert(ncuts != NULL);
6171  assert(cutoff != NULL);
6172  *cutoff = FALSE;
6173 
6174  consdata = SCIPconsGetData(cons);
6175  assert(consdata != NULL);
6176 
6177  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6178 
6179  /* check knapsack constraint itself for feasibility */
6180  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6181 
6182  if( violated )
6183  {
6184  /* add knapsack constraint as LP row to the LP */
6185  SCIP_CALL( addRelaxation(scip, cons, sol, cutoff) );
6186  (*ncuts)++;
6187  }
6188  else if( sepacuts )
6189  {
6190  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6191  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6192  }
6193 
6194  return SCIP_OKAY;
6195 }
6196 
6197 /** adds coefficient to constraint data */
6198 static
6200  SCIP* scip, /**< SCIP data structure */
6201  SCIP_CONS* cons, /**< knapsack constraint */
6202  SCIP_VAR* var, /**< variable to add to knapsack */
6203  SCIP_Longint weight /**< weight of variable in knapsack */
6204  )
6205 {
6206  SCIP_CONSDATA* consdata;
6208  consdata = SCIPconsGetData(cons);
6209  assert(consdata != NULL);
6210  assert(SCIPvarIsBinary(var));
6211  assert(weight > 0);
6212 
6213  /* add the new coefficient to the LP row */
6214  if( consdata->row != NULL )
6215  {
6216  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6217  }
6218 
6219  /* check for fixed variable */
6220  if( SCIPvarGetLbGlobal(var) > 0.5 )
6221  {
6222  /* variable is fixed to one: reduce capacity */
6223  consdata->capacity -= weight;
6224  }
6225  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6226  {
6227  SCIP_Bool negated;
6228 
6229  /* get binary representative of variable */
6230  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6231 
6232  /* insert coefficient */
6233  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6234  consdata->vars[consdata->nvars] = var;
6235  consdata->weights[consdata->nvars] = weight;
6236  consdata->nvars++;
6237 
6238  /* capture variable */
6239  SCIP_CALL( SCIPcaptureVar(scip, var) );
6240 
6241  /* install the rounding locks of variable */
6242  SCIP_CALL( lockRounding(scip, cons, var) );
6243 
6244  /* catch events */
6245  if( SCIPconsIsTransformed(cons) )
6246  {
6247  SCIP_CONSHDLRDATA* conshdlrdata;
6248 
6249  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6250  assert(conshdlrdata != NULL);
6251  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6253  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6254  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6255 
6256  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6257  consdata->existmultaggr = TRUE;
6258 
6259  /* mark constraint to be propagated and presolved */
6260  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6261  consdata->presolvedtiming = 0;
6262  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6263  }
6264 
6265  /* update weight sums */
6266  updateWeightSums(consdata, var, weight);
6267 
6268  consdata->sorted = FALSE;
6269  consdata->cliquepartitioned = FALSE;
6270  consdata->negcliquepartitioned = FALSE;
6271  consdata->merged = FALSE;
6272  }
6273 
6274  return SCIP_OKAY;
6275 }
6276 
6277 /** deletes coefficient at given position from constraint data */
6278 static
6280  SCIP* scip, /**< SCIP data structure */
6281  SCIP_CONS* cons, /**< knapsack constraint */
6282  int pos /**< position of coefficient to delete */
6283  )
6284 {
6285  SCIP_CONSDATA* consdata;
6286  SCIP_VAR* var;
6288  consdata = SCIPconsGetData(cons);
6289  assert(consdata != NULL);
6290  assert(0 <= pos && pos < consdata->nvars);
6291 
6292  var = consdata->vars[pos];
6293  assert(var != NULL);
6294  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6295 
6296  /* delete the coefficient from the LP row */
6297  if( consdata->row != NULL )
6298  {
6299  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6300  }
6301 
6302  /* remove the rounding locks of variable */
6303  SCIP_CALL( unlockRounding(scip, cons, var) );
6304 
6305  /* drop events and mark constraint to be propagated and presolved */
6306  if( SCIPconsIsTransformed(cons) )
6307  {
6308  SCIP_CONSHDLRDATA* conshdlrdata;
6309 
6310  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6311  assert(conshdlrdata != NULL);
6313  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6314  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6315 
6316  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6317  consdata->presolvedtiming = 0;
6318  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6319  }
6320 
6321  /* decrease weight sums */
6322  updateWeightSums(consdata, var, -consdata->weights[pos]);
6323 
6324  /* move the last variable to the free slot */
6325  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6326  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6327  if( consdata->eventdata != NULL )
6328  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6329 
6330  /* release variable */
6331  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6332 
6333  /* try to use old clique partitions */
6334  if( consdata->cliquepartitioned )
6335  {
6336  assert(consdata->cliquepartition != NULL);
6337  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6338  * change the clique number */
6339  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6340  {
6341  int oldcliqenum;
6342 
6343  oldcliqenum = consdata->cliquepartition[pos];
6344  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6345 
6346  /* the following if and else cases assure that we have increasing clique numbers */
6347  if( consdata->cliquepartition[pos] > pos )
6348  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6349  else
6350  {
6351  int i;
6352  int cliquenumbefore;
6353 
6354  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6355  * occurs the same as the old one is still in the cliquepartition */
6356  if( oldcliqenum > consdata->cliquepartition[pos] )
6357  {
6358  for( i = 0; i < consdata->nvars; ++i )
6359  if( oldcliqenum == consdata->cliquepartition[i] )
6360  break;
6361  else if( oldcliqenum < consdata->cliquepartition[i] )
6362  {
6363  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6364  break;
6365  }
6366  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6367  * the biggest index, so decrease the number of cliques
6368  */
6369  if( i == consdata->nvars )
6370  --(consdata->ncliques);
6371  }
6372  /* if the old clique number was smaller than the new one we have to check the front for an element with
6373  * clique number minus 1 */
6374  else if( oldcliqenum < consdata->cliquepartition[pos] )
6375  {
6376  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6377  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6378 
6379  if( i < cliquenumbefore )
6380  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6381  }
6382  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6383  else if( pos == consdata->nvars - 1)
6384  {
6385  cliquenumbefore = consdata->cliquepartition[pos];
6386  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6387 
6388  if( i < cliquenumbefore )
6389  --(consdata->ncliques);
6390  }
6391  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6392  }
6393  }
6394  else
6395  --(consdata->ncliques);
6396  }
6397 
6398  if( consdata->negcliquepartitioned )
6399  {
6400  assert(consdata->negcliquepartition != NULL);
6401  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6402  * change the clique number */
6403  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6404  {
6405  int oldcliqenum;
6406 
6407  oldcliqenum = consdata->negcliquepartition[pos];
6408  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6409 
6410  /* the following if and else cases assure that we have increasing clique numbers */
6411  if( consdata->negcliquepartition[pos] > pos )
6412  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6413  else
6414  {
6415  int i;
6416  int cliquenumbefore;
6417 
6418  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6419  * occurs, the same as the old one occurs */
6420  if( oldcliqenum > consdata->negcliquepartition[pos] )
6421  {
6422  for( i = 0; i < consdata->nvars; ++i )
6423  if( oldcliqenum == consdata->negcliquepartition[i] )
6424  break;
6425  else if( oldcliqenum < consdata->negcliquepartition[i] )
6426  {
6427  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6428  break;
6429  }
6430  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6431  * the biggest index, so decrease the number of negated cliques
6432  */
6433  if( i == consdata->nvars )
6434  --(consdata->nnegcliques);
6435  }
6436  /* if the old clique number was smaller than the new one we have to check the front for an element with
6437  * clique number minus 1 */
6438  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6439  {
6440  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6441  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6442 
6443  if( i < cliquenumbefore )
6444  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6445  }
6446  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6447  else if( pos == consdata->nvars - 1)
6448  {
6449  cliquenumbefore = consdata->negcliquepartition[pos];
6450  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6451 
6452  if( i < cliquenumbefore )
6453  --(consdata->nnegcliques);
6454  }
6455  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6456  }
6457  }
6458  else
6459  --(consdata->nnegcliques);
6460  }
6461 
6462  --(consdata->nvars);
6463 
6464  return SCIP_OKAY;
6465 }
6466 
6467 /** removes all items with weight zero from knapsack constraint */
6468 static
6470  SCIP* scip, /**< SCIP data structure */
6471  SCIP_CONS* cons /**< knapsack constraint */
6472  )
6473 {
6474  SCIP_CONSDATA* consdata;
6475  int v;
6476 
6477  consdata = SCIPconsGetData(cons);
6478  assert(consdata != NULL);
6479 
6480  for( v = consdata->nvars-1; v >= 0; --v )
6481  {
6482  if( consdata->weights[v] == 0 )
6483  {
6484  SCIP_CALL( delCoefPos(scip, cons, v) );
6485  }
6486  }
6487 
6488  return SCIP_OKAY;
6489 }
6490 
6491 /* perform deletion of variables in all constraints of the constraint handler */
6492 static
6494  SCIP* scip, /**< SCIP data structure */
6495  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6496  SCIP_CONS** conss, /**< array of constraints */
6497  int nconss /**< number of constraints */
6498  )
6499 {
6500  SCIP_CONSDATA* consdata;
6501  int i;
6502  int v;
6503 
6504  assert(scip != NULL);
6505  assert(conshdlr != NULL);
6506  assert(conss != NULL);
6507  assert(nconss >= 0);
6508  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6509 
6510  /* iterate over all constraints */
6511  for( i = 0; i < nconss; i++ )
6512  {
6513  consdata = SCIPconsGetData(conss[i]);
6514 
6515  /* constraint is marked, that some of its variables were deleted */
6516  if( consdata->varsdeleted )
6517  {
6518  /* iterate over all variables of the constraint and delete them from the constraint */
6519  for( v = consdata->nvars - 1; v >= 0; --v )
6520  {
6521  if( SCIPvarIsDeleted(consdata->vars[v]) )
6522  {
6523  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6524  }
6525  }
6526  consdata->varsdeleted = FALSE;
6527  }
6528  }
6529 
6530  return SCIP_OKAY;
6531 }
6532 
6533 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6534 static
6536  SCIP* scip, /**< SCIP data structure */
6537  SCIP_CONS* cons, /**< knapsack constraint */
6538  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6539  )
6540 {
6541  SCIP_CONSDATA* consdata;
6542  int v;
6543  int prev;
6544 
6545  assert(scip != NULL);
6546  assert(cons != NULL);
6547  assert(cutoff != NULL);
6548 
6549  consdata = SCIPconsGetData(cons);
6550  assert(consdata != NULL);
6551 
6552  *cutoff = FALSE;
6553 
6554  if( consdata->merged )
6555  return SCIP_OKAY;
6556 
6557  if( consdata->nvars <= 1 )
6558  {
6559  consdata->merged = TRUE;
6560  return SCIP_OKAY;
6561  }
6562 
6563  assert(consdata->vars != NULL || consdata->nvars == 0);
6564 
6565  /* sorting array after indices of variables, that's only for faster merging */
6566  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6567  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6568 
6569  /* knapsack-sorting (decreasing weights) now lost */
6570  consdata->sorted = FALSE;
6571 
6572  v = consdata->nvars - 1;
6573  prev = v - 1;
6574  /* loop backwards through the items: deletion only affects rear items */
6575  while( prev >= 0 )
6576  {
6577  SCIP_VAR* var1;
6578  SCIP_VAR* var2;
6579  SCIP_Bool negated1;
6580  SCIP_Bool negated2;
6581 
6582  negated1 = FALSE;
6583  negated2 = FALSE;
6584 
6585  var1 = consdata->vars[v];
6586  assert(SCIPvarIsBinary(var1));
6587  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6589  {
6590  var1 = SCIPvarGetNegatedVar(var1);
6591  negated1 = TRUE;
6592  }
6593  assert(var1 != NULL);
6594 
6595  var2 = consdata->vars[prev];
6596  assert(SCIPvarIsBinary(var2));
6597  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6599  {
6600  var2 = SCIPvarGetNegatedVar(var2);
6601  negated2 = TRUE;
6602  }
6603  assert(var2 != NULL);
6604 
6605  if( var1 == var2 )
6606  {
6607  /* both variables are either active or negated */
6608  if( negated1 == negated2 )
6609  {
6610  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6611  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6612  SCIP_CALL( delCoefPos(scip, cons, v) );
6613  }
6614  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6615  * and delete item of smaller weight
6616  */
6617  else if( consdata->weights[v] == consdata->weights[prev] )
6618  {
6619  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6620  consdata->capacity -= consdata->weights[v];
6621  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6622  SCIP_CALL( delCoefPos(scip, cons, prev) );
6623 
6624  --prev;
6625  }
6626  else if( consdata->weights[v] < consdata->weights[prev] )
6627  {
6628  consdata->capacity -= consdata->weights[v];
6629  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6630  assert(consdata->weights[prev] > 0);
6631  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6632  }
6633  else
6634  {
6635  consdata->capacity -= consdata->weights[prev];
6636  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6637  assert(consdata->weights[v] > 0);
6638  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6639  /* restore order iff necessary */
6640  if( consdata->nvars != v ) /* otherwise the order still stands */
6641  {
6642  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6643  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6644  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6645  --prev;
6646  else /* we need to let v at the same position*/
6647  {
6648  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6649  /* don't decrease v, the same variable may exist up front */
6650  --prev;
6651  continue;
6652  }
6653  }
6654  }
6655  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6656  }
6657  v = prev;
6658  --prev;
6659  }
6660 
6661  consdata->merged = TRUE;
6662 
6663  /* check infeasibility */
6664  if( consdata->onesweightsum > consdata->capacity )
6665  {
6666  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6667  *cutoff = TRUE;
6668  return SCIP_OKAY;
6669  }
6670 
6671  return SCIP_OKAY;
6672 }
6673 
6674 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6675  * fixings (dual reductions)
6676  */
6677 static
6679  SCIP* scip, /**< SCIP data structure */
6680  SCIP_CONS* cons, /**< knapsack constraint */
6681  int* nfixedvars, /**< pointer to count number of fixings */
6682  int* ndelconss, /**< pointer to count number of deleted constraints */
6683  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6684  )
6685 {
6686  SCIP_CONSDATA* consdata;
6687  SCIP_VAR** vars;
6688  SCIP_Real* profits;
6689  int* solitems;
6690  int* nonsolitems;
6691  int* items;
6692  SCIP_Real solval;
6693  SCIP_Bool infeasible;
6694  SCIP_Bool tightened;
6695  SCIP_Bool applicable;
6696  int nsolitems;
6697  int nnonsolitems;
6698  int nvars;
6699  int v;
6700 
6701  assert(!SCIPconsIsModifiable(cons));
6702 
6703  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6704  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6705  * added to the problems have the check flag set to FALSE
6706  */
6707  if( !SCIPconsIsChecked(cons) )
6708  return SCIP_OKAY;
6709 
6710  consdata = SCIPconsGetData(cons);
6711  assert(consdata != NULL);
6712 
6713  nvars = consdata->nvars;
6714  vars = consdata->vars;
6715 
6716  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6717  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6718  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6719  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6720 
6721  applicable = TRUE;
6722 
6723  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6724  * collect object values which are the profits of the knapsack problem
6725  */
6726  for( v = 0; v < nvars; ++v )
6727  {
6728  SCIP_VAR* var;
6729  SCIP_Bool negated;
6730 
6731  var = vars[v];
6732  assert(var != NULL);
6733 
6734  /* the variable should not be (globally) fixed */
6735  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6736 
6737  if( SCIPvarGetNLocksDown(var) > 0 || SCIPvarGetNLocksUp(var) > 1 )
6738  {
6739  applicable = FALSE;
6740  break;
6741  }
6742 
6743  negated = FALSE;
6744 
6745  /* get the active variable */
6746  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6747  assert(SCIPvarIsActive(var));
6748 
6749  if( negated )
6750  profits[v] = SCIPvarGetObj(var);
6751  else
6752  profits[v] = -SCIPvarGetObj(var);
6753 
6754  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6755  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6756  items[v] = v;
6757  }
6758 
6759  if( applicable )
6760  {
6761  SCIP_Bool success;
6762 
6763  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6764  SCIPdebugPrintCons(scip, cons, NULL);
6765 
6766  /* solve knapsack problem exactly */
6767  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6768  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6769 
6770  if( success )
6771  {
6772  SCIP_VAR* var;
6773 
6774  /* apply solution of the knapsack as dual reductions */
6775  for( v = 0; v < nsolitems; ++v )
6776  {
6777  var = vars[solitems[v]];
6778  assert(var != NULL);
6779 
6780  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6782  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6783  assert(!infeasible);
6784  assert(tightened);
6785  (*nfixedvars)++;
6786  }
6787 
6788  for( v = 0; v < nnonsolitems; ++v )
6789  {
6790  var = vars[nonsolitems[v]];
6791  assert(var != NULL);
6792 
6793  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6795  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6796  assert(!infeasible);
6797  assert(tightened);
6798  (*nfixedvars)++;
6799  }
6800 
6801  SCIP_CALL( SCIPdelCons(scip, cons) );
6802  (*ndelconss)++;
6803  (*deleted) = TRUE;
6804  }
6805  }
6806 
6807  SCIPfreeBufferArray(scip, &nonsolitems);
6808  SCIPfreeBufferArray(scip, &solitems);
6809  SCIPfreeBufferArray(scip, &items);
6810  SCIPfreeBufferArray(scip, &profits);
6811 
6812  return SCIP_OKAY;
6813 }
6814 
6815 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6816  * constraint enters the LP by setting the initial and separated flag to FALSE
6817  */
6818 static
6820  SCIP* scip, /**< SCIP data structure */
6821  SCIP_CONS* cons, /**< knapsack constraint */
6822  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6823  )
6824 {
6825  SCIP_CONSDATA* consdata;
6826  SCIP_VAR** vars;
6827  SCIP_VAR* var;
6828  SCIP_Real offset;
6829  SCIP_Real scale;
6830  SCIP_Real objval;
6831  SCIP_Bool applicable;
6832  SCIP_Bool negated;
6833  int nobjvars;
6834  int nvars;
6835  int v;
6836 
6837  assert(scip != NULL);
6838  assert(cons != NULL);
6839  assert(conshdlrdata != NULL);
6840 
6841  consdata = SCIPconsGetData(cons);
6842  assert(consdata != NULL);
6843 
6844  nvars = consdata->nvars;
6845  nobjvars = SCIPgetNObjVars(scip);
6846 
6847  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6848  * and/or separated flag is set to FALSE
6849  */
6850  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6851  return SCIP_OKAY;
6852 
6853  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6854  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6855  */
6856  if( nobjvars == 0 )
6857  return SCIP_OKAY;
6858 
6859  vars = consdata->vars;
6860  assert(vars != NULL);
6861 
6862  applicable = TRUE;
6863  offset = 0.0;
6864  scale = 1.0;
6865 
6866  for( v = 0; v < nvars && applicable; ++v )
6867  {
6868  negated = FALSE;
6869  var = vars[v];
6870  assert(var != NULL);
6871 
6872  if( SCIPvarIsNegated(var) )
6873  {
6874  negated = TRUE;
6875  var = SCIPvarGetNegatedVar(var);
6876  assert(var != NULL);
6877  }
6878 
6879  objval = SCIPvarGetObj(var);
6880 
6881  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6882  if( SCIPisZero(scip, objval) )
6883  applicable = FALSE;
6884  else
6885  {
6886  SCIP_Real weight;
6887 
6888  weight = (SCIP_Real)consdata->weights[v];
6889 
6890  if( negated )
6891  {
6892  if( v == 0 )
6893  {
6894  /* the first variable defines the scale */
6895  scale = weight / -objval;
6896 
6897  offset += weight;
6898  }
6899  else if( SCIPisEQ(scip, -objval * scale, weight) )
6900  offset += weight;
6901  else
6902  applicable = FALSE;
6903  }
6904  else if( v == 0 )
6905  {
6906  /* the first variable define the scale */
6907  scale = weight / objval;
6908  }
6909  else if( !SCIPisEQ(scip, objval * scale, weight) )
6910  applicable = FALSE;
6911  }
6912  }
6913 
6914  if( applicable )
6915  {
6916  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6917  {
6918  SCIP_Real cutoffbound;
6919 
6920  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6921  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6922  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6923 
6924  cutoffbound = (consdata->capacity - offset) / scale;
6925 
6926  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6927  * still excepted
6928  */
6929  cutoffbound += SCIPcutoffbounddelta(scip);
6930 
6931  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6932  SCIPconsGetName(cons), cutoffbound);
6933 
6934  if( cutoffbound < SCIPgetCutoffbound(scip) )
6935  {
6936  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6937 
6938  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6939  }
6940  else
6941  {
6942  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6943  * propagation
6944  */
6945  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6946  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6947  }
6948  }
6949  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6950  {
6951  SCIP_Real lowerbound;
6952 
6953  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6954  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6955  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6956 
6957  lowerbound = (consdata->capacity - offset) / scale;
6958 
6959  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6960  SCIPconsGetName(cons), lowerbound);
6961 
6962  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6963  }
6964  }
6965 
6966  return SCIP_OKAY;
6967 }
6968 
6969 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6970  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
6971 static
6973  SCIP* scip, /**< SCIP data structure */
6974  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
6975  SCIP_VAR** vars, /**< array for sorted variables */
6976  SCIP_Longint* weights, /**< array for sorted weights */
6977  int* cliquestartposs, /**< starting position array for each clique */
6978  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
6979  )
6980 {
6981  SCIP_VAR** origvars;
6982  int norigvars;
6983  SCIP_Longint* origweights;
6984  int* cliquepartition;
6985  int ncliques;
6986 
6987  SCIP_VAR*** varpointers;
6988  SCIP_Longint** weightpointers;
6989  int* cliquecount;
6990 
6991  int nextpos;
6992  int c;
6993  int v;
6994 
6995  assert(scip != NULL);
6996  assert(consdata != NULL);
6997  assert(vars != NULL);
6998  assert(weights != NULL);
6999  assert(cliquestartposs != NULL);
7000 
7001  origweights = consdata->weights;
7002  origvars = consdata->vars;
7003  norigvars = consdata->nvars;
7004 
7005  assert(origvars != NULL || norigvars == 0);
7006  assert(origweights != NULL || norigvars == 0);
7007 
7008  if( norigvars == 0 )
7009  return SCIP_OKAY;
7010 
7011  if( usenegatedclique )
7012  {
7013  assert(consdata->negcliquepartitioned);
7014 
7015  cliquepartition = consdata->negcliquepartition;
7016  ncliques = consdata->nnegcliques;
7017  }
7018  else
7019  {
7020  assert(consdata->cliquepartitioned);
7021 
7022  cliquepartition = consdata->cliquepartition;
7023  ncliques = consdata->ncliques;
7024  }
7025 
7026  assert(cliquepartition != NULL);
7027  assert(ncliques > 0);
7028 
7029  /* we first count all clique items and alloc temporary memory for a bucket sort */
7030  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7031  BMSclearMemoryArray(cliquecount, ncliques);
7032 
7033  /* first we count for each clique the number of elements */
7034  for( v = norigvars - 1; v >= 0; --v )
7035  {
7036  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7037  ++(cliquecount[cliquepartition[v]]);
7038  }
7039 
7040  /*@todo: maybe it is better to put largest cliques up front */
7041 
7042 #ifndef NDEBUG
7043  BMSclearMemoryArray(vars, norigvars);
7044  BMSclearMemoryArray(weights, norigvars);
7045 #endif
7046  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7047  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7048 
7049  nextpos = 0;
7050  /* now we initialize all start pointers for each clique, so they will be ordered */
7051  for( c = 0; c < ncliques; ++c )
7052  {
7053  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7054  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7055  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7056  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7057  * vars[7]
7058  *
7059  */
7060  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7061  cliquestartposs[c] = nextpos;
7062  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7063  assert(cliquecount[c] > 0);
7064  nextpos += cliquecount[c];
7065  assert(nextpos > 0);
7066  }
7067  assert(nextpos == norigvars);
7068  cliquestartposs[c] = nextpos;
7069 
7070  /* now we copy all variable and weights to the right order */
7071  for( v = 0; v < norigvars; ++v )
7072  {
7073  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7074  ++(varpointers[cliquepartition[v]]);
7075  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7076  ++(weightpointers[cliquepartition[v]]);
7077  }
7078 #ifndef NDEBUG
7079  for( v = 0; v < norigvars; ++v )
7080  {
7081  assert(vars[v] != NULL);
7082  assert(weights[v] > 0);
7083  }
7084 #endif
7085 
7086  /* free temporary memory */
7087  SCIPfreeBufferArray(scip, &weightpointers);
7088  SCIPfreeBufferArray(scip, &varpointers);
7089  SCIPfreeBufferArray(scip, &cliquecount);
7090 
7091  return SCIP_OKAY;
7092 }
7093 
7094 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7095 static
7097  SCIP* scip, /**< SCIP data structure */
7098  SCIP_CONS* cons, /**< knapsack constraint */
7099  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7100  * information is not needed; in this case, we apply all fixings
7101  * instead of stopping after the first infeasible one */
7102  )
7103 {
7104  SCIP_CONSDATA* consdata;
7105  int v;
7106 
7107  assert(scip != NULL);
7108  assert(cons != NULL);
7109 
7110  consdata = SCIPconsGetData(cons);
7111  assert(consdata != NULL);
7112  assert(consdata->nvars == 0 || consdata->vars != NULL);
7113 
7114  if( cutoff != NULL )
7115  *cutoff = FALSE;
7116 
7117  SCIPdebugMsg(scip, "apply fixings:\n");
7118  SCIPdebugPrintCons(scip, cons, NULL);
7119 
7120  /* check infeasibility */
7121  if ( consdata->onesweightsum > consdata->capacity )
7122  {
7123  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7124 
7125  if( cutoff != NULL )
7126  *cutoff = TRUE;
7127 
7128  return SCIP_OKAY;
7129  }
7130 
7131  /* all multi-aggregations should be resolved */
7132  consdata->existmultaggr = FALSE;
7133 
7134  v = 0;
7135  while( v < consdata->nvars )
7136  {
7137  SCIP_VAR* var;
7138 
7139  var = consdata->vars[v];
7140  assert(SCIPvarIsBinary(var));
7141 
7142  if( SCIPvarGetLbGlobal(var) > 0.5 )
7143  {
7144  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7145  consdata->capacity -= consdata->weights[v];
7146  SCIP_CALL( delCoefPos(scip, cons, v) );
7147  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7148  }
7149  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7150  {
7151  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7152  SCIP_CALL( delCoefPos(scip, cons, v) );
7153  }
7154  else
7155  {
7156  SCIP_VAR* repvar;
7157  SCIP_VAR* negvar;
7158  SCIP_VAR* workvar;
7159  SCIP_Longint weight;
7160  SCIP_Bool negated;
7161 
7162  weight = consdata->weights[v];
7163 
7164  /* get binary representative of variable */
7165  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7166  assert(repvar != NULL);
7167 
7168  /* check for multi-aggregation */
7169  if( SCIPvarIsNegated(repvar) )
7170  {
7171  workvar = SCIPvarGetNegatedVar(repvar);
7172  assert(workvar != NULL);
7173  negated = TRUE;
7174  }
7175  else
7176  {
7177  workvar = repvar;
7178  negated = FALSE;
7179  }
7180 
7181  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7182  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7183  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7184  *
7185  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7186  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7187  *
7188  * The explanation for the following block:
7189  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7190  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7191  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7192  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7193  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7194  * 2) For all replacement variable we check:
7195  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7196  * capacity -= weight * a_i caused by the negation of y_i.
7197  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7198  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7199  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7200  * weight in this case.
7201  */
7202  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7203  {
7204  SCIP_VAR** aggrvars;
7205  SCIP_Real* aggrscalars;
7206  SCIP_Real aggrconst;
7207  int naggrvars;
7208  int i;
7209 
7210  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7211  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7212  aggrvars = SCIPvarGetMultaggrVars(workvar);
7213  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7214  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7215  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7216 
7217  if( !SCIPisIntegral(scip, weight * aggrconst) )
7218  {
7219  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7220  return SCIP_ERROR;
7221  }
7222 
7223  /* if workvar was negated, we have to flip the weight */
7224  if( negated )
7225  weight *= -1;
7226 
7227  for( i = naggrvars - 1; i >= 0; --i )
7228  {
7229  assert(aggrvars != NULL);
7230  assert(aggrscalars != NULL);
7231 
7232  if( !SCIPvarIsBinary(aggrvars[i]) )
7233  {
7234  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary variable <%s>\n", aggrvars[i]);
7235  return SCIP_ERROR;
7236  }
7237  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7238  {
7239  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7240  return SCIP_ERROR;
7241  }
7242  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7243  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7244  {
7245  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7246  assert(negvar != NULL);
7247  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7248  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7249  }
7250  else
7251  {
7252  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7253  }
7254  }
7255  /* delete old coefficient */
7256  SCIP_CALL( delCoefPos(scip, cons, v) );
7257 
7258  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7259  if( negated )
7260  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7261  else
7262  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7263 
7264  if( consdata->capacity < 0 )
7265  {
7266  if( cutoff != NULL )
7267  {
7268  *cutoff = TRUE;
7269  break;
7270  }
7271  }
7272  }
7273  /* check, if the variable should be replaced with the representative */
7274  else if( repvar != var )
7275  {
7276  /* delete old (aggregated) variable */
7277  SCIP_CALL( delCoefPos(scip, cons, v) );
7278 
7279  /* add representative instead */
7280  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7281  }
7282  else
7283  ++v;
7284  }
7285  }
7286  assert(consdata->onesweightsum == 0);
7287 
7288  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7289  SCIPdebugPrintCons(scip, cons, NULL);
7290 
7291  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7292  * clean up the constraint
7293  */
7294  if( cutoff != NULL && !(*cutoff) )
7295  {
7296  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7297  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7298  SCIPdebugPrintCons(scip, cons, NULL);
7299  }
7300 
7301  return SCIP_OKAY;
7302 }
7303 
7304 
7305 /** propagation method for knapsack constraints */
7306 static
7308  SCIP* scip, /**< SCIP data structure */
7309  SCIP_CONS* cons, /**< knapsack constraint */
7310  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7311  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7312  int* nfixedvars, /**< pointer to count number of fixings */
7313  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7314  )
7316  SCIP_CONSDATA* consdata;
7317  SCIP_Bool infeasible;
7318  SCIP_Bool tightened;
7319  SCIP_Longint* secondmaxweights;
7320  SCIP_Longint minweightsum;
7321  SCIP_Longint residualcapacity;
7322 
7323  int nvars;
7324  int i;
7325  int nnegcliques;
7326 
7327  SCIP_VAR** myvars;
7328  SCIP_Longint* myweights;
7329  int* cliquestartposs;
7330  int* cliqueendposs;
7331  SCIP_Longint localminweightsum;
7332  SCIP_Bool foundmax;
7333  int c;
7334 
7335  assert(scip != NULL);
7336  assert(cons != NULL);
7337  assert(cutoff != NULL);
7338  assert(redundant != NULL);
7339  assert(nfixedvars != NULL);
7340 
7341  consdata = SCIPconsGetData(cons);
7342  assert(consdata != NULL);
7343 
7344  *cutoff = FALSE;
7345  *redundant = FALSE;
7346 
7347  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7348 
7349  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7350  if( !SCIPinRepropagation(scip) )
7351  {
7352  SCIP_CALL( SCIPincConsAge(scip, cons) );
7353  }
7354 
7355 #ifndef NDEBUG
7356  /* assert that only active or negated variables are present */
7357  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7358  {
7359  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7360  }
7361 #endif
7362 
7363  usenegatedclique = usenegatedclique && consdata->merged;
7364 
7365  /* init for debugging */
7366  myvars = NULL;
7367  myweights = NULL;
7368  cliquestartposs = NULL;
7369  secondmaxweights = NULL;
7370  minweightsum = 0;
7371  nvars = consdata->nvars;
7372  /* make sure, the items are sorted by non-increasing weight */
7373  sortItems(consdata);
7374 
7375  do
7376  {
7377  localminweightsum = 0;
7378 
7379  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7380  * a negated clique means, that at most one of the clique variables can be zero
7381  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7382  *
7383  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7384  * since replacing i with the element of maximal weight leads to infeasibility
7385  */
7386  if( usenegatedclique && nvars > 0 )
7387  {
7388  SCIP_CONSHDLRDATA* conshdlrdata;
7389  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7390  assert(conshdlrdata != NULL);
7391 
7392  /* compute clique partitions */
7393  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7394  nnegcliques = consdata->nnegcliques;
7395 
7396  /* if we have no real negated cliques we can stop here */
7397  if( nnegcliques == nvars )
7398  {
7399  /* run the standard algorithm that does not involve cliques */
7400  usenegatedclique = FALSE;
7401  break;
7402  }
7403 
7404  /* allocate temporary memory and initialize it */
7405  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7406  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7407  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7408  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7409  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7410  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7411 
7412  /* resort variables to avoid quadratic algorithm later on */
7413  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7414 
7415  /* save the end positions of the cliques because start positions are moved in the following loop */
7416  for( c = 0; c < nnegcliques; ++c )
7417  {
7418  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7419  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7420  }
7421 
7422  c = 0;
7423  foundmax = FALSE;
7424  i = 0;
7425 
7426  while( i < nvars )
7427  {
7428  /* ignore variables of the negated clique which are fixed to one since these are counted in
7429  * consdata->onesweightsum
7430  */
7431 
7432  /* if there are only one variable negated cliques left we can stop */
7433  if( nnegcliques - c == nvars - i )
7434  {
7435  minweightsum += localminweightsum;
7436  localminweightsum = 0;
7437  break;
7438  }
7439 
7440  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7441  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7442  * other clique variables to one
7443  */
7444  if( cliquestartposs[c] == i )
7445  {
7446  assert(myweights[i] > 0);
7447  ++c;
7448  minweightsum += localminweightsum;
7449  localminweightsum = 0;
7450  foundmax = TRUE;
7451 
7452  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7453  foundmax = FALSE;
7454 
7455  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7456  {
7457  ++i;
7458  continue;
7459  }
7460  }
7461 
7462  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7463  {
7464  assert(myweights[i] > 0);
7465 
7466  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7467  {
7468  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7469 
7470  if( !foundmax )
7471  {
7472  foundmax = TRUE;
7473 
7474  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7475  cliquestartposs[c - 1] = i;
7476  ++i;
7477 
7478  continue;
7479  }
7480  /* memorize second max weight for each clique */
7481  if( secondmaxweights[c - 1] == 0 )
7482  secondmaxweights[c - 1] = myweights[i];
7483 
7484  localminweightsum += myweights[i];
7485  }
7486  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7487  else
7488  {
7489  int v;
7490  /* fix all other variables of the negated clique to 1 */
7491  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7492  {
7493  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7494  {
7495  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7496  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7497 
7498  if( infeasible )
7499  {
7500  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7501 
7502  /* analyze the infeasibility if conflict analysis is applicable */
7504  {
7505  /* conflict analysis can only be applied in solving stage */
7506  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7507 
7508  /* initialize the conflict analysis */
7510 
7511  /* add the two variables which are fixed to zero within a negated clique */
7512  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7513  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7514 
7515  /* start the conflict analysis */
7516  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7517  }
7518  *cutoff = TRUE;
7519  break;
7520  }
7521  assert(tightened);
7522  ++(*nfixedvars);
7523  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7524  }
7525  }
7526  if( *cutoff )
7527  break;
7528 
7529  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7530  localminweightsum = 0;
7531  /* we can jump to the end of this clique */
7532  i = cliqueendposs[c - 1];
7533  }
7534  }
7535  ++i;
7536  }
7537  /* add last clique minweightsum */
7538  minweightsum += localminweightsum;
7539 
7540  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7541  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7542 
7543  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7544  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7545  {
7546  SCIP_Longint maxcliqueweight = -1LL;
7547 
7548  /* loop over cliques */
7549  for( c = 0; c < nnegcliques; ++c )
7550  {
7551  SCIP_VAR* maxvar;
7552  SCIP_Bool maxvarfixed;
7553  int endvarposclique;
7554  int startvarposclique;
7555 
7556  assert(myvars != NULL);
7557  assert(nnegcliques == consdata->nnegcliques);
7558  assert(myweights != NULL);
7559  assert(secondmaxweights != NULL);
7560  assert(cliquestartposs != NULL);
7561 
7562  endvarposclique = cliqueendposs[c];
7563  startvarposclique = cliquestartposs[c];
7564 
7565  maxvar = myvars[startvarposclique];
7566 
7567  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7568  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7569  continue;
7570 
7571  maxcliqueweight = myweights[startvarposclique];
7572  maxvarfixed = FALSE;
7573  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7574  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7575  * exceeds the capacity the maximum weight variable can be fixed to zero.
7576  */
7577  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7578  {
7579  assert(maxcliqueweight >= secondmaxweights[c]);
7580  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7581 
7582  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7583  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7584  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7585  assert(!infeasible);
7586  assert(tightened);
7587  (*nfixedvars)++;
7588  maxvarfixed = TRUE;
7589  }
7590  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7591  * fits into the knapsack
7592  */
7593  else if( nnegcliques - c == nvars - startvarposclique )
7594  break;
7595  /* early termination of the remaining loop because no further variable fixings are possible:
7596  *
7597  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7598  * largest was set to 0) does not suffice to infer additional variable fixings because
7599  *
7600  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7601  * - their second largest elements are at least as large as the smallest weight of the knapsack
7602  */
7603  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7604  break;
7605 
7606  /* loop over items with non-maximal weight (omitting the first position) */
7607  for( i = endvarposclique; i > startvarposclique; --i )
7608  {
7609  /* there should be no variable fixed to 0 between and startvarposclique + 1 and endvarposclique unless we
7610  * messed up the clique preprocessing in the previous loop to filter those variables out */
7611  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7612 
7613  /* only check variables of negated cliques for which no variable is locally fixed */
7614  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7615  {
7616  assert(maxcliqueweight >= myweights[i]);
7617  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7618 
7619  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7620  *
7621  * the maxvar was already fixed to 0 because it has a huge gain.
7622  *
7623  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7624  * since replacing i with the element of maximal weight leads to infeasibility */
7625  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7626  {
7627  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7628  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7629  assert(!infeasible);
7630  assert(tightened);
7631  ++(*nfixedvars);
7632  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7633 
7634  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7635  * consdata->onesweightsum
7636  */
7637  minweightsum -= myweights[i];
7638  assert(minweightsum >= 0);
7639  }
7640  else
7641  break;
7642  }
7643  }
7644 #ifndef NDEBUG
7645  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7646  for( ; i > startvarposclique; --i )
7647  {
7648  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7649  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7650 
7651  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7652  assert(varisfixed || !exceedscapacity);
7653  }
7654 #endif
7655  }
7656  }
7657  SCIPfreeBufferArray(scip, &secondmaxweights);
7658  SCIPfreeBufferArray(scip, &cliqueendposs);
7659  SCIPfreeBufferArray(scip, &cliquestartposs);
7660  SCIPfreeBufferArray(scip, &myweights);
7661  SCIPfreeBufferArray(scip, &myvars);
7662  }
7663 
7664  assert(consdata->negcliquepartitioned || minweightsum == 0);
7665  }
7666  while( FALSE );
7667 
7668  assert(usenegatedclique || minweightsum == 0);
7669  /* check, if weights of fixed variables already exceed knapsack capacity */
7670  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7671  {
7672  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7673  consdata->onesweightsum, consdata->capacity);
7674 
7675  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7676  *cutoff = TRUE;
7677 
7678  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7680  {
7681  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7682  SCIP_Longint weight;
7683 
7684  weight = 0;
7685 
7687 
7688  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7689  {
7690  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7691  {
7692  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7693  weight += consdata->weights[i];
7694  }
7695  }
7696 
7697  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7698  }
7699 
7700  return SCIP_OKAY;
7701  }
7702 
7703  /* the algorithm below is a special case of propagation involving negated cliques */
7704  if( !usenegatedclique )
7705  {
7706  assert(consdata->sorted);
7707  residualcapacity = consdata->capacity - consdata->onesweightsum;
7708 
7709  /* fix all variables to zero, that don't fit into the knapsack anymore */
7710  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7711  {
7712  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7713  * to zero
7714  */
7715  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7716  {
7717  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7718  {
7719  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7720  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7721  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7722  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7723  assert(!infeasible);
7724  assert(tightened);
7725  (*nfixedvars)++;
7726  }
7727  }
7728  }
7729  }
7730 
7731  /* check if the knapsack is now redundant */
7732  if( !SCIPconsIsModifiable(cons) )
7733  {
7734  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7735 
7736  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7737  for( i = 0; i < nvars; ++i )
7738  {
7739  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7740  {
7741  unfixedweightsum += consdata->weights[i];
7742 
7743  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7744  if( unfixedweightsum > consdata->capacity )
7745  return SCIP_OKAY;
7746  }
7747  }
7748  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7749  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7750  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7751  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7752  *redundant = TRUE;
7753  }
7754 
7755  return SCIP_OKAY;
7756 }
7757 
7758 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7759  * containing all negated variables of this knapsack constraint
7760  */
7761 static
7763  SCIP* scip, /**< SCIP data structure */
7764  SCIP_CONS* cons, /**< knapsack constraint */
7765  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7766  int* naddconss /**< pointer to count number of added constraints */
7767  )
7768 {
7769  SCIP_CONS* newcons;
7770  SCIP_CONSDATA* consdata;
7771 
7772  assert(scip != NULL);
7773  assert(cons != NULL);
7774  assert(ndelconss != NULL);
7775  assert(naddconss != NULL);
7776 
7777  consdata = SCIPconsGetData(cons);
7778  assert(consdata != NULL);
7779  assert(consdata->nvars > 1);
7780 
7781  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7782  if( consdata->nvars == 2 )
7783  {
7784  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7785 
7786  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7790  SCIPconsIsStickingAtNode(cons)) );
7791  }
7792  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7793  * containing all negated variables of the knapsack
7794  */
7795  else
7796  {
7797  SCIP_VAR** consvars;
7798 
7799  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7800 
7801  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7802  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7803 
7804  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7808  SCIPconsIsStickingAtNode(cons)) );
7809 
7810  SCIPfreeBufferArray(scip, &consvars);
7811  }
7812 
7813  SCIP_CALL( SCIPaddCons(scip, newcons) );
7814  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7815  ++(*naddconss);
7816 
7817  SCIP_CALL( SCIPdelCons(scip, cons) );
7818  ++(*ndelconss);
7819 
7820  return SCIP_OKAY;
7821 }
7822 
7823 /** delete redundant variables
7824  *
7825  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7826  *
7827  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7828  * => x4, x5 always fits into the knapsack, so we can delete them
7829  *
7830  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7831  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7832  */
7833 static
7835  SCIP* scip, /**< SCIP data structure */
7836  SCIP_CONS* cons, /**< knapsack constraint */
7837  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7838  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7839  * first which did not fit */
7840  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7841  int* nchgsides, /**< pointer to store the amount of changed sides */
7842  int* naddconss /**< pointer to count number of added constraints */
7843  )
7844 {
7845  SCIP_CONSHDLRDATA* conshdlrdata;
7846  SCIP_CONSDATA* consdata;
7847  SCIP_VAR** vars;
7848  SCIP_Longint* weights;
7849  SCIP_Longint capacity;
7850  SCIP_Longint gcd;
7851  int nvars;
7852  int w;
7853 
7854  assert(scip != NULL);
7855  assert(cons != NULL);
7856  assert(nchgcoefs != NULL);
7857  assert(nchgsides != NULL);
7858  assert(naddconss != NULL);
7859 
7860  consdata = SCIPconsGetData(cons);
7861  assert(consdata != NULL);
7862  assert(0 < frontsum && frontsum < consdata->weightsum);
7863  assert(0 < splitpos && splitpos < consdata->nvars);
7864 
7865  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7866  assert(conshdlrdata != NULL);
7867 
7868  vars = consdata->vars;
7869  weights = consdata->weights;
7870  nvars = consdata->nvars;
7871  capacity = consdata->capacity;
7872 
7873  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7874  * weight must not be sorted by their index
7875  */
7876 #ifndef NDEBUG
7877  for( w = nvars - 1; w > 0; --w )
7878  assert(weights[w] <= weights[w-1]);
7879 #endif
7880 
7881  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7882  if( consdata->nvars - 1 == splitpos )
7883  return SCIP_OKAY;
7884 
7885  assert(frontsum + weights[splitpos] > capacity);
7886 
7887  /* detect redundant variables */
7888  if( consdata->weightsum - weights[splitpos] <= capacity )
7889  {
7890  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7891  * fit
7892  */
7893  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7894 
7895  /* delete items and update capacity */
7896  for( w = nvars - 1; w > splitpos; --w )
7897  {
7898  consdata->capacity -= weights[w];
7899  SCIP_CALL( delCoefPos(scip, cons, w) );
7900  }
7901  assert(w == splitpos);
7902 
7903  ++(*nchgsides);
7904  *nchgcoefs += (nvars - splitpos);
7905 
7906  /* division by greatest common divisor */
7907  gcd = weights[w];
7908  for( ; w >= 0 && gcd > 1; --w )
7909  {
7910  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7911  }
7912 
7913  /* normalize if possible */
7914  if( gcd > 1 )
7915  {
7916  for( w = splitpos; w >= 0; --w )
7917  {
7918  consdataChgWeight(consdata, w, weights[w]/gcd);
7919  }
7920  (*nchgcoefs) += nvars;
7921 
7922  consdata->capacity /= gcd;
7923  ++(*nchgsides);
7924  }
7925 
7926  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7927  * weight must not be sorted by their index
7928  */
7929 #ifndef NDEBUG
7930  for( w = consdata->nvars - 1; w > 0; --w )
7931  assert(weights[w] <= weights[w - 1]);
7932 #endif
7933  }
7934  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7935  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7936  * splitpos and needs to fit into the knapsack
7937  */
7938  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7939  {
7940  int* clqpart;
7941  int nclq;
7942  int len;
7943 
7944  len = nvars - (splitpos + 1);
7945  /* allocate temporary memory */
7946  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7947 
7948  /* calculate clique partition */
7949  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7950 
7951  /* check if we found at least one clique */
7952  if( nclq < len )
7953  {
7954  SCIP_Longint maxactduetoclq;
7955  int cliquenum;
7956 
7957  maxactduetoclq = 0;
7958  cliquenum = 0;
7959 
7960  /* calculate maximum activity due to cliques */
7961  for( w = 0; w < len; ++w )
7962  {
7963  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7964  if( clqpart[w] == cliquenum )
7965  {
7966  maxactduetoclq += weights[w + splitpos + 1];
7967  ++cliquenum;
7968  }
7969  }
7970 
7971  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
7972  * so delete them and create for all clique the corresponding clique constraints and update the capacity
7973  */
7974  if( frontsum + maxactduetoclq <= capacity )
7975  {
7976  SCIP_VAR** clqvars;
7977  int nclqvars;
7978  int c;
7979 
7980  assert(maxactduetoclq < weights[splitpos]);
7981 
7982  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
7983 
7984  /* allocate temporary memory */
7985  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
7986 
7987  for( c = 0; c < nclq; ++c )
7988  {
7989  nclqvars = 0;
7990  for( w = 0; w < len; ++w )
7991  {
7992  if( clqpart[w] == c )
7993  {
7994  clqvars[nclqvars] = vars[w + splitpos + 1];
7995  ++nclqvars;
7996  }
7997  }
7998 
7999  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8000  if( nclqvars > 1 )
8001  {
8002  SCIP_CONS* cliquecons;
8003  char name[SCIP_MAXSTRLEN];
8004 
8005  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8006  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8010  SCIPconsIsStickingAtNode(cons)) );
8011  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8012  SCIPdebugPrintCons(scip, cliquecons, NULL);
8013  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8014  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8015  ++(*naddconss);
8016  }
8017  }
8018 
8019  /* delete items and update capacity */
8020  for( w = nvars - 1; w > splitpos; --w )
8021  {
8022  SCIP_CALL( delCoefPos(scip, cons, w) );
8023  ++(*nchgcoefs);
8024  }
8025  consdata->capacity -= maxactduetoclq;
8026  assert(frontsum <= consdata->capacity);
8027  ++(*nchgsides);
8028 
8029  assert(w == splitpos);
8030 
8031  /* renew weights pointer */
8032  weights = consdata->weights;
8033 
8034  /* division by greatest common divisor */
8035  gcd = weights[w];
8036  for( ; w >= 0 && gcd > 1; --w )
8037  {
8038  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8039  }
8040 
8041  /* normalize if possible */
8042  if( gcd > 1 )
8043  {
8044  for( w = splitpos; w >= 0; --w )
8045  {
8046  consdataChgWeight(consdata, w, weights[w]/gcd);
8047  }
8048  (*nchgcoefs) += nvars;
8049 
8050  consdata->capacity /= gcd;
8051  ++(*nchgsides);
8052  }
8053 
8054  /* free temporary memory */
8055  SCIPfreeBufferArray(scip, &clqvars);
8056 
8057  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8058  * weight must not be sorted by their index
8059  */
8060 #ifndef NDEBUG
8061  for( w = consdata->nvars - 1; w > 0; --w )
8062  assert(weights[w] <= weights[w - 1]);
8063 #endif
8064  }
8065  }
8066 
8067  /* free temporary memory */
8068  SCIPfreeBufferArray(scip, &clqpart);
8069  }
8070 
8071  return SCIP_OKAY;
8072 }
8073 
8074 /* detect redundant variables which always fits into the knapsack
8075  *
8076  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8077  *
8078  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8079  * => x4, x5 always fits into the knapsack, so we can delete them
8080  *
8081  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8082  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8083  */
8084 static
8086  SCIP* scip, /**< SCIP data structure */
8087  SCIP_CONS* cons, /**< knapsack constraint */
8088  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8089  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8090  int* nchgsides, /**< pointer to store the amount of changed sides */
8091  int* naddconss /**< pointer to count number of added constraints */
8092  )
8094  SCIP_CONSHDLRDATA* conshdlrdata;
8095  SCIP_CONSDATA* consdata;
8096  SCIP_VAR** vars;
8097  SCIP_Longint* weights;
8098  SCIP_Longint capacity;
8099  SCIP_Longint sum;
8100  int noldchgcoefs;
8101  int nvars;
8102  int v;
8103  int w;
8104 
8105  assert(scip != NULL);
8106  assert(cons != NULL);
8107  assert(ndelconss != NULL);
8108  assert(nchgcoefs != NULL);
8109  assert(nchgsides != NULL);
8110  assert(naddconss != NULL);
8111 
8112  consdata = SCIPconsGetData(cons);
8113  assert(consdata != NULL);
8114  assert(consdata->nvars >= 2);
8115  assert(consdata->weightsum > consdata->capacity);
8116 
8117  noldchgcoefs = *nchgcoefs;
8118  vars = consdata->vars;
8119  weights = consdata->weights;
8120  nvars = consdata->nvars;
8121  capacity = consdata->capacity;
8122  sum = 0;
8123 
8124  /* search for maximal fitting items */
8125  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8126  sum += weights[v];
8127 
8128  assert(v < nvars);
8129 
8130  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8131  if( v == nvars - 1 )
8132  {
8133  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8134  assert(SCIPconsIsDeleted(cons));
8135 
8136  return SCIP_OKAY;
8137  }
8138 
8139  if( v < nvars - 1 )
8140  {
8141  /* try to delete variables */
8142  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8143  assert(consdata->nvars > 1);
8144 
8145  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8146  if( v == consdata->nvars - 1 )
8147  {
8148  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8149  assert(SCIPconsIsDeleted(cons));
8150  }
8151 
8152  return SCIP_OKAY;
8153  }
8154 
8155  /* if we already found some redundant variables, stop here */
8156  if( *nchgcoefs > noldchgcoefs )
8157  return SCIP_OKAY;
8158 
8159  assert(vars == consdata->vars);
8160  assert(weights == consdata->weights);
8161  assert(nvars == consdata->nvars);
8162  assert(capacity == consdata->capacity);
8163 
8164  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8165  assert(conshdlrdata != NULL);
8166  /* calculate clique partition */
8167  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8168 
8169  /* check for real existing cliques */
8170  if( consdata->cliquepartition[v] < v )
8171  {
8172  SCIP_Longint sumfront;
8173  SCIP_Longint maxactduetoclqfront;
8174  int* clqpart;
8175  int cliquenum;
8176 
8177 
8178  sumfront = 0;
8179  maxactduetoclqfront = 0;
8180 
8181  clqpart = consdata->cliquepartition;
8182  cliquenum = 0;
8183 
8184  /* calculate maximal activity due to cliques */
8185  for( w = 0; w < nvars; ++w )
8186  {
8187  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8188  if( clqpart[w] == cliquenum )
8189  {
8190  if( maxactduetoclqfront + weights[w] <= capacity )
8191  {
8192  maxactduetoclqfront += weights[w];
8193  ++cliquenum;
8194  }
8195  else
8196  break;
8197  }
8198  sumfront += weights[w];
8199  }
8200  assert(w >= v);
8201 
8202  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8203  * information
8204  */
8205  if( conshdlrdata->disaggregation && w == nvars )
8206  {
8207  SCIP_VAR** clqvars;
8208  int nclqvars;
8209  int c;
8210  int ncliques;
8211 
8212  assert(maxactduetoclqfront <= capacity);
8213 
8214  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8215 
8216  ncliques = consdata->ncliques;
8217 
8218  /* allocate temporary memory */
8219  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8220 
8221  for( c = 0; c < ncliques; ++c )
8222  {
8223  nclqvars = 0;
8224  for( w = 0; w < nvars; ++w )
8225  {
8226  if( clqpart[w] == c )
8227  {
8228  clqvars[nclqvars] = vars[w];
8229  ++nclqvars;
8230  }
8231  }
8232 
8233  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8234  if( nclqvars > 1 )
8235  {
8236  SCIP_CONS* cliquecons;
8237  char name[SCIP_MAXSTRLEN];
8238 
8239  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8240  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8244  SCIPconsIsStickingAtNode(cons)) );
8245  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8246  SCIPdebugPrintCons(scip, cliquecons, NULL);
8247  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8248  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8249  ++(*naddconss);
8250  }
8251  }
8252 
8253  /* delete old constraint */
8254  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8255  ++(*ndelconss);
8256 
8257  SCIPfreeBufferArray(scip, &clqvars);
8258 
8259  return SCIP_OKAY;
8260  }
8261 
8262  if( w > v && w < nvars - 1 )
8263  {
8264  /* try to delete variables */
8265  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8266  }
8267  }
8268 
8269  return SCIP_OKAY;
8270 }
8271 
8272 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8273 static
8274 void normalizeWeights(
8275  SCIP_CONS* cons, /**< knapsack constraint */
8276  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8277  int* nchgsides /**< pointer to count number of side changes */
8278  )
8279 {
8280  SCIP_CONSDATA* consdata;
8281  SCIP_Longint gcd;
8282  int i;
8283 
8284  assert(nchgcoefs != NULL);
8285  assert(nchgsides != NULL);
8286  assert(!SCIPconsIsModifiable(cons));
8287 
8288  consdata = SCIPconsGetData(cons);
8289  assert(consdata != NULL);
8290  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8291  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8292  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8293  assert(consdata->nvars >= 1);
8294 
8295  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8296  sortItems(consdata);
8297 
8298  gcd = consdata->weights[consdata->nvars-1];
8299  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8300  {
8301  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8302  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8303 
8304  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8305  }
8306 
8307  if( gcd >= 2 )
8308  {
8309  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8310 
8311  for( i = 0; i < consdata->nvars; ++i )
8312  {
8313  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8314  }
8315  consdata->capacity /= gcd;
8316  (*nchgcoefs) += consdata->nvars;
8317  (*nchgsides)++;
8318 
8319  /* weight should still be sorted, because the reduction preserves this */
8320 #ifndef NDEBUG
8321  for( i = consdata->nvars - 1; i > 0; --i )
8322  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8323 #endif
8324  consdata->sorted = TRUE;
8325  }
8326 }
8327 
8328 /** dual weights tightening for knapsack constraints
8329  *
8330  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8331  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8332  * constraint
8333  *
8334  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8335  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8336  *
8337  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8338  *
8339  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8340  *
8341  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8342  *
8343  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8344  *
8345  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8346  */
8347 static
8349  SCIP* scip, /**< SCIP data structure */
8350  SCIP_CONS* cons, /**< knapsack constraint */
8351  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8352  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8353  int* nchgsides, /**< pointer to store the amount of changed sides */
8354  int* naddconss /**< pointer to count number of added constraints */
8355  )
8357  SCIP_CONSDATA* consdata;
8358  SCIP_Longint* weights;
8359  SCIP_Longint dualcapacity;
8360  SCIP_Longint reductionsum;
8361  SCIP_Longint capacity;
8362  SCIP_Longint exceedsum;
8363  int oldnchgcoefs;
8364  int nvars;
8365  int vbig;
8366  int v;
8367  int w;
8368 #ifndef NDEBUG
8369  int oldnchgsides;
8370 #endif
8371 
8372  assert(scip != NULL);
8373  assert(cons != NULL);
8374  assert(ndelconss != NULL);
8375  assert(nchgcoefs != NULL);
8376  assert(nchgsides != NULL);
8377  assert(naddconss != NULL);
8378 
8379 #ifndef NDEBUG
8380  oldnchgsides = *nchgsides;
8381 #endif
8382 
8383  consdata = SCIPconsGetData(cons);
8384  assert(consdata != NULL);
8385  assert(consdata->weightsum > consdata->capacity);
8386  assert(consdata->nvars >= 2);
8387  assert(consdata->sorted);
8388 
8389  /* constraint should be merged */
8390  assert(consdata->merged);
8391 
8392  nvars = consdata->nvars;
8393  weights = consdata->weights;
8394  capacity = consdata->capacity;
8395 
8396  oldnchgcoefs = *nchgcoefs;
8397 
8398  /* case 1. */
8399  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8400  {
8401  SCIP_CONS* newcons;
8402 
8403  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8404  *
8405  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8406  */
8407  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8408 
8409  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8413  SCIPconsIsStickingAtNode(cons)) );
8414 
8415  SCIP_CALL( SCIPaddCons(scip, newcons) );
8416  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8417  ++(*naddconss);
8418 
8419  SCIP_CALL( SCIPdelCons(scip, cons) );
8420  ++(*ndelconss);
8421 
8422  return SCIP_OKAY;
8423  }
8424 
8425  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8426  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8427  {
8428  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8429  assert(SCIPconsIsDeleted(cons));
8430 
8431  return SCIP_OKAY;
8432  }
8433 
8434  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8435  /* @todo might be changed/removed when improving the coeffcients tightening */
8436  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8437  return SCIP_OKAY;
8438 
8439  /* case 2. */
8440 
8441  v = 0;
8442 
8443  /* @todo generalize the following algorithm for several parts of the knapsack
8444  *
8445  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8446  * variables each combination is a minimal cover, some examples
8447  *
8448  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8449  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8450  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8451  *
8452  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8453  *
8454  */
8455 
8456  /* determine big weights that fit only by itself */
8457  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8458  ++v;
8459 
8460  vbig = v;
8461  assert(vbig < nvars - 1);
8462  exceedsum = 0;
8463 
8464  /* determine the amount needed to exceed the capacity */
8465  while( v < nvars && exceedsum <= capacity )
8466  {
8467  exceedsum += weights[v];
8468  ++v;
8469  }
8470 
8471  /* if we exceeded the capacity we might reduce the weights */
8472  if( exceedsum > capacity )
8473  {
8474  assert(vbig > 0 || v < nvars);
8475 
8476  /* all small weights were needed to exceed the capacity */
8477  if( v == nvars )
8478  {
8479  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8480  assert(newweight > 0);
8481 
8482  /* reduce big weights */
8483  for( v = 0; v < vbig; ++v )
8484  {
8485  if( weights[v] > newweight )
8486  {
8487  consdataChgWeight(consdata, v, newweight);
8488  ++(*nchgcoefs);
8489  }
8490  }
8491 
8492  /* reduce small weights */
8493  for( ; v < nvars; ++v )
8494  {
8495  if( weights[v] > 1 )
8496  {
8497  consdataChgWeight(consdata, v, 1LL);
8498  ++(*nchgcoefs);
8499  }
8500  }
8501 
8502  consdata->capacity = newweight;
8503 
8504  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8505  * weight must not be sorted by their index
8506  */
8507 #ifndef NDEBUG
8508  for( v = nvars - 1; v > 0; --v )
8509  assert(weights[v] <= weights[v-1]);
8510 #endif
8511 
8512  return SCIP_OKAY;
8513  }
8514  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8515  * small weights
8516  */
8517  else
8518  {
8519  SCIP_Longint exceedsumback = 0;
8520  int nexceed = v - vbig;
8521 
8522  assert(nexceed > 1);
8523 
8524  /* determine weightsum of the same amount as before but of the smallest weight */
8525  for( w = nvars - 1; w >= nvars - nexceed; --w )
8526  exceedsumback += weights[w];
8527 
8528  assert(w >= 0);
8529 
8530  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8531  * combinations of all small weights
8532  */
8533  if( exceedsumback > capacity )
8534  {
8535  SCIP_Longint newweight = nexceed - 1;
8536 
8537  /* taking out the smallest element needs to fit */
8538  assert(exceedsumback - weights[nvars - 1] <= capacity);
8539 
8540  /* reduce big weights */
8541  for( v = 0; v < vbig; ++v )
8542  {
8543  if( weights[v] > newweight )
8544  {
8545  consdataChgWeight(consdata, v, newweight);
8546  ++(*nchgcoefs);
8547  }
8548  }
8549 
8550  /* reduce small weights */
8551  for( ; v < nvars; ++v )
8552  {
8553  if( weights[v] > 1 )
8554  {
8555  consdataChgWeight(consdata, v, 1LL);
8556  ++(*nchgcoefs);
8557  }
8558  }
8559 
8560  consdata->capacity = newweight;
8561 
8562  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8563  * weight must not be sorted by their index
8564  */
8565 #ifndef NDEBUG
8566  for( v = nvars - 1; v > 0; --v )
8567  assert(weights[v] <= weights[v-1]);
8568 #endif
8569  return SCIP_OKAY;
8570  }
8571  }
8572  }
8573  else
8574  {
8575  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8576  * not happen here
8577  */
8578  assert(vbig > 0 && vbig < nvars);
8579 
8580  /* either choose a big coefficients or all other variables
8581  *
8582  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8583  *
8584  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8585  * constraint to
8586  *
8587  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8588  */
8589 
8590  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8591  {
8592  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8593 #ifndef NDEBUG
8594  SCIP_Longint resweightsum = consdata->weightsum;
8595 
8596  for( v = 0; v < vbig; ++v )
8597  resweightsum -= weights[v];
8598 
8599  assert(exceedsum == resweightsum);
8600 #endif
8601  assert(newweight > 0);
8602 
8603  /* reduce big weights */
8604  for( v = 0; v < vbig; ++v )
8605  {
8606  if( weights[v] > newweight )
8607  {
8608  consdataChgWeight(consdata, v, newweight);
8609  ++(*nchgcoefs);
8610  }
8611  }
8612 
8613  /* reduce small weights */
8614  for( ; v < nvars; ++v )
8615  {
8616  if( weights[v] > 1 )
8617  {
8618  consdataChgWeight(consdata, v, 1LL);
8619  ++(*nchgcoefs);
8620  }
8621  }
8622 
8623  consdata->capacity = newweight;
8624 
8625  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8626  * weight must not be sorted by their index
8627  */
8628 #ifndef NDEBUG
8629  for( v = nvars - 1; v > 0; --v )
8630  assert(weights[v] <= weights[v-1]);
8631 #endif
8632  return SCIP_OKAY;
8633  }
8634  }
8635 
8636  /* case 3. */
8637 
8638  dualcapacity = consdata->weightsum - capacity;
8639  reductionsum = 0;
8640  v = 0;
8641 
8642  /* reduce big weights
8643  *
8644  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8645  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8646  * <=> x0 + x1 + x2 + x3 <= 3
8647  */
8648  while( weights[v] > dualcapacity )
8649  {
8650  reductionsum += (weights[v] - dualcapacity);
8651  consdataChgWeight(consdata, v, dualcapacity);
8652  ++v;
8653  assert(v < nvars);
8654  }
8655  (*nchgcoefs) += v;
8656 
8657  /* skip weights equal to the dualcapacity, because we cannot change them */
8658  while( v < nvars && weights[v] == dualcapacity )
8659  ++v;
8660 
8661  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8662  * after a possible removal of the last, redundant item
8663  *
8664  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8665  */
8666  if( v >= nvars - 1 )
8667  {
8668  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8669  if( v == nvars - 1 )
8670  {
8671  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8672  }
8673  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8674  assert(SCIPconsIsDeleted(cons));
8675 
8676  return SCIP_OKAY;
8677  }
8678  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8679  {
8680  /* @todo generalize the following algorithm for more than two variables */
8681 
8682  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8683  {
8684  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8685  * coefficients) of all or two variables of the rest
8686  *
8687  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8688  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8689  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8690  *
8691  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8692  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8693  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8694  *
8695  */
8696  if( v > 0 && weights[nvars - 2] > 1 )
8697  {
8698  int ncoefchg = 0;
8699 
8700  /* reduce all bigger weights */
8701  for( w = 0; w < v; ++w )
8702  {
8703  if( weights[w] > 2 )
8704  {
8705  consdataChgWeight(consdata, w, 2LL);
8706  ++ncoefchg;
8707  }
8708  else
8709  {
8710  assert(weights[0] == 2);
8711  assert(weights[v - 1] == 2);
8712  break;
8713  }
8714  }
8715 
8716  /* reduce all smaller weights */
8717  for( w = v; w < nvars; ++w )
8718  {
8719  if( weights[w] > 1 )
8720  {
8721  consdataChgWeight(consdata, w, 1LL);
8722  ++ncoefchg;
8723  }
8724  }
8725  assert(ncoefchg > 0);
8726 
8727  (*nchgcoefs) += ncoefchg;
8728 
8729  /* correct the capacity */
8730  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8731  assert(consdata->capacity > 0);
8732  assert(weights[0] <= consdata->capacity);
8733  assert(consdata->weightsum > consdata->capacity);
8734  /* reset the reductionsum */
8735  reductionsum = 0;
8736  }
8737  else if( v == 0 )
8738  {
8739  assert(weights[nvars - 2] == 1);
8740  }
8741  }
8742  else
8743  {
8744  SCIP_Longint minweight = weights[nvars - 1];
8745  SCIP_Longint newweight = dualcapacity - minweight;
8746  SCIP_Longint restsumweights = 0;
8747  SCIP_Longint sumcoef;
8748  SCIP_Bool sumcoefcase = FALSE;
8749  int startv = v;
8750  int end;
8751  int k;
8752 
8753  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8754 
8755  /* reduce big weights of pairs that exceed the dualcapacity
8756  *
8757  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8758  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8759  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8760  */
8761  while( weights[v] > newweight )
8762  {
8763  reductionsum += (weights[v] - newweight);
8764  consdataChgWeight(consdata, v, newweight);
8765  ++v;
8766  assert(v < nvars);
8767  }
8768  (*nchgcoefs) += (v - startv);
8769 
8770  /* skip equal weights */
8771  while( weights[v] == newweight )
8772  ++v;
8773 
8774  if( v > 0 )
8775  {
8776  for( w = v; w < nvars; ++w )
8777  restsumweights += weights[w];
8778  }
8779  else
8780  restsumweights = consdata->weightsum;
8781 
8782  if( restsumweights < dualcapacity )
8783  {
8784  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8785  *
8786  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8787  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8788  */
8789  if( startv == v )
8790  {
8791  /* remove redundant variables */
8792  for( w = nvars - 1; w >= v; --w )
8793  {
8794  SCIP_CALL( delCoefPos(scip, cons, v) );
8795  ++(*nchgcoefs);
8796  }
8797 
8798 #ifndef NDEBUG
8799  /* each coefficients should exceed the dualcapacity by itself */
8800  for( ; w >= 0; --w )
8801  assert(weights[w] == dualcapacity);
8802 #endif
8803  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8804  * upgrade this constraint
8805  */
8806  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8807  assert(SCIPconsIsDeleted(cons));
8808 
8809  return SCIP_OKAY;
8810  }
8811 
8812  /* special case where we have three different coefficient types
8813  *
8814  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8815  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8816  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8817  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8818  */
8819  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8820  {
8821  SCIP_Longint newcap;
8822 
8823  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8824  for( w = nvars - 1; w >= v; --w )
8825  {
8826  if( weights[w] > 1 )
8827  {
8828  consdataChgWeight(consdata, w, 1LL);
8829  ++(*nchgcoefs);
8830  }
8831  }
8832 
8833  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8834  * dualcapacity
8835  */
8836  newweight = (SCIP_Longint)nvars - v;
8837  assert(newweight > 1);
8838  for( ; w >= startv; --w )
8839  {
8840  if( weights[w] > newweight )
8841  {
8842  consdataChgWeight(consdata, w, newweight);
8843  ++(*nchgcoefs);
8844  }
8845  else
8846  assert(weights[w] == newweight);
8847  }
8848 
8849  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8850  ++newweight;
8851  assert(newweight > 2);
8852  for( ; w >= 0; --w )
8853  {
8854  if( weights[w] > newweight )
8855  {
8856  consdataChgWeight(consdata, w, newweight);
8857  ++(*nchgcoefs);
8858  }
8859  else
8860  assert(weights[w] == newweight);
8861  }
8862 
8863  /* update the capacity */
8864  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8865  if( consdata->capacity > newcap )
8866  {
8867  consdata->capacity = newcap;
8868  ++(*nchgsides);
8869  }
8870  else
8871  assert(consdata->capacity == newcap);
8872  }
8873  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8874 
8875  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8876  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8877 
8878  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8879  * weight must not be sorted by their index
8880  */
8881 #ifndef NDEBUG
8882  for( w = nvars - 1; w > 0; --w )
8883  assert(weights[w] <= weights[w - 1]);
8884 #endif
8885  return SCIP_OKAY;
8886  }
8887 
8888  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8889  end = nvars - 2;
8890  while( end >= 0 && weights[end] == weights[end + 1] )
8891  {
8892  assert(end >= v);
8893  --end;
8894  }
8895 
8896  if( v >= end )
8897  goto TERMINATE;
8898 
8899  end = nvars - 2;
8900 
8901  /* can we stop early, another special reduction case might exist */
8902  if( 2 * weights[end] > dualcapacity )
8903  {
8904  restsumweights = 0;
8905 
8906  /* determine capacity of the small items */
8907  for( w = end + 1; w < nvars; ++w )
8908  restsumweights += weights[w];
8909 
8910  if( restsumweights * 2 <= dualcapacity )
8911  {
8912  /* check for further posssible reductions in the middle */
8913  while( v < end && restsumweights + weights[v] >= dualcapacity )
8914  ++v;
8915 
8916  if( v >= end )
8917  goto TERMINATE;
8918 
8919  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8920  if( (dualcapacity & 1) == 0 )
8921  {
8922  newweight = dualcapacity / 2;
8923 
8924  /* set all middle coefficients */
8925  for( ; v <= end; ++v )
8926  {
8927  if( weights[v] > newweight )
8928  {
8929  reductionsum += (weights[v] - newweight);
8930  consdataChgWeight(consdata, v, newweight);
8931  ++(*nchgcoefs);
8932  }
8933  }
8934  }
8935  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8936  * other coefficients by 2
8937  */
8938  else
8939  {
8940  /* correct the reductionsum */
8941  reductionsum *= 2;
8942 
8943  /* multiply big coefficients by 2 */
8944  for( w = 0; w < v; ++w )
8945  {
8946  consdataChgWeight(consdata, w, weights[w] * 2);
8947  }
8948 
8949  newweight = dualcapacity;
8950  /* set all middle coefficients */
8951  for( ; v <= end; ++v )
8952  {
8953  reductionsum += (2 * weights[v] - newweight);
8954  consdataChgWeight(consdata, v, newweight);
8955  }
8956 
8957  /* multiply small coefficients by 2 */
8958  for( w = end + 1; w < nvars; ++w )
8959  {
8960  consdataChgWeight(consdata, w, weights[w] * 2);
8961  }
8962  (*nchgcoefs) += nvars;
8963 
8964  dualcapacity *= 2;
8965  consdata->capacity *= 2;
8966  ++(*nchgsides);
8967  }
8968  }
8969 
8970  goto TERMINATE;
8971  }
8972 
8973  /* further reductions using the next possible coefficient sum
8974  *
8975  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
8976  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
8977  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
8978  */
8979  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
8980  for( k = 0; k < 4; ++k )
8981  {
8982  /* determine next minimal coefficient sum */
8983  switch( k )
8984  {
8985  case 0:
8986  sumcoef = weights[nvars - 1] + weights[nvars - 2];
8987  break;
8988  case 1:
8989  assert(nvars >= 3);
8990  sumcoef = weights[nvars - 1] + weights[nvars - 3];
8991  break;
8992  case 2:
8993  assert(nvars >= 4);
8994  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
8995  {
8996  sumcoefcase = TRUE;
8997  sumcoef = weights[nvars - 1] + weights[nvars - 4];
8998  }
8999  else
9000  {
9001  sumcoefcase = FALSE;
9002  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9003  }
9004  break;
9005  case 3:
9006  assert(nvars >= 5);
9007  if( sumcoefcase )
9008  {
9009  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9010  }
9011  else
9012  {
9013  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9014  }
9015  break;
9016  default:
9017  return SCIP_ERROR;
9018  }
9019 
9020  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9021  minweight = weights[end];
9022  while( minweight <= sumcoef )
9023  {
9024  newweight = dualcapacity - minweight;
9025  startv = v;
9026  assert(v < nvars);
9027 
9028  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9029  /* shrink big coefficients */
9030  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9031  {
9032  reductionsum += (weights[v] - newweight);
9033  consdataChgWeight(consdata, v, newweight);
9034  ++v;
9035  assert(v < nvars);
9036  }
9037  (*nchgcoefs) += (v - startv);
9038 
9039  /* skip unchangable weights */
9040  while( weights[v] + minweight == dualcapacity )
9041  {
9042  assert(v < nvars);
9043  ++v;
9044  }
9045 
9046  --end;
9047  /* skip same end weights */
9048  while( end >= 0 && weights[end] == weights[end + 1] )
9049  --end;
9050 
9051  if( v >= end )
9052  goto TERMINATE;
9053 
9054  minweight = weights[end];
9055  }
9056 
9057  if( v >= end )
9058  goto TERMINATE;
9059 
9060  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9061  if( sumcoef < minweight )
9062  {
9063  minweight = sumcoef;
9064  newweight = dualcapacity - minweight;
9065  startv = v;
9066  assert(v < nvars);
9067 
9068  /* shrink big coefficients */
9069  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9070  {
9071  reductionsum += (weights[v] - newweight);
9072  consdataChgWeight(consdata, v, newweight);
9073  ++v;
9074  assert(v < nvars);
9075  }
9076  (*nchgcoefs) += (v - startv);
9077 
9078  /* skip unchangable weights */
9079  while( weights[v] + minweight == dualcapacity )
9080  {
9081  assert(v < nvars);
9082  ++v;
9083  }
9084  }
9085 
9086  if( v >= end )
9087  goto TERMINATE;
9088 
9089  /* can we stop early, another special reduction case might exist */
9090  if( 2 * weights[end] > dualcapacity )
9091  {
9092  restsumweights = 0;
9093 
9094  /* determine capacity of the small items */
9095  for( w = end + 1; w < nvars; ++w )
9096  restsumweights += weights[w];
9097 
9098  if( restsumweights * 2 <= dualcapacity )
9099  {
9100  /* check for further posssible reductions in the middle */
9101  while( v < end && restsumweights + weights[v] >= dualcapacity )
9102  ++v;
9103 
9104  if( v >= end )
9105  goto TERMINATE;
9106 
9107  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9108  if( (dualcapacity & 1) == 0 )
9109  {
9110  newweight = dualcapacity / 2;
9111 
9112  /* set all middle coefficients */
9113  for( ; v <= end; ++v )
9114  {
9115  if( weights[v] > newweight )
9116  {
9117  reductionsum += (weights[v] - newweight);
9118  consdataChgWeight(consdata, v, newweight);
9119  ++(*nchgcoefs);
9120  }
9121  }
9122  }
9123  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9124  * other coefficients by 2
9125  */
9126  else
9127  {
9128  /* correct the reductionsum */
9129  reductionsum *= 2;
9130 
9131  /* multiply big coefficients by 2 */
9132  for( w = 0; w < v; ++w )
9133  {
9134  consdataChgWeight(consdata, w, weights[w] * 2);
9135  }
9136 
9137  newweight = dualcapacity;
9138  /* set all middle coefficients */
9139  for( ; v <= end; ++v )
9140  {
9141  reductionsum += (2 * weights[v] - newweight);
9142  consdataChgWeight(consdata, v, newweight);
9143  }
9144 
9145  /* multiply small coefficients by 2 */
9146  for( w = end + 1; w < nvars; ++w )
9147  {
9148  consdataChgWeight(consdata, w, weights[w] * 2);
9149  }
9150  (*nchgcoefs) += nvars;
9151 
9152  dualcapacity *= 2;
9153  consdata->capacity *= 2;
9154  ++(*nchgsides);
9155  }
9156  }
9157 
9158  goto TERMINATE;
9159  }
9160 
9161  /* cannot tighten any further */
9162  if( 2 * sumcoef > dualcapacity )
9163  goto TERMINATE;
9164  }
9165  }
9166  }
9167 
9168 
9169  TERMINATE:
9170  /* correct capacity */
9171  if( reductionsum > 0 )
9172  {
9173  assert(v > 0);
9174 
9175  consdata->capacity -= reductionsum;
9176  ++(*nchgsides);
9177 
9178  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9179  }
9180  assert(weights[0] <= consdata->capacity);
9181 
9182  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9183  * weight must not be sorted by their index
9184  */
9185 #ifndef NDEBUG
9186  for( w = nvars - 1; w > 0; --w )
9187  assert(weights[w] <= weights[w - 1]);
9188 #endif
9189 
9190  if( oldnchgcoefs < *nchgcoefs )
9191  {
9192  assert(!SCIPconsIsDeleted(cons));
9193 
9194  /* it might be that we can divide the weights by their greatest common divisor */
9195  normalizeWeights(cons, nchgcoefs, nchgsides);
9196  }
9197  else
9198  {
9199  assert(oldnchgcoefs == *nchgcoefs);
9200  assert(oldnchgsides == *nchgsides);
9201  }
9202 
9203  return SCIP_OKAY;
9204 }
9205 
9206 
9207 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9208 static
9210  SCIP* scip, /**< SCIP data structure */
9211  SCIP_CONS* cons, /**< knapsack constraint */
9212  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9213  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9214  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9215  )
9216 {
9217  SCIP_VAR** vars;
9218  SCIP_CONSDATA* consdata;
9219  SCIP_Longint* weights;
9220  SCIP_Longint capacity;
9221  SCIP_Bool infeasible;
9222  SCIP_Bool fixed;
9223  int nvars;
9224  int v;
9225 
9226  assert(scip != NULL);
9227  assert(cons != NULL);
9228  assert(nfixedvars != NULL);
9229  assert(ndelconss != NULL);
9230  assert(nchgcoefs != NULL);
9231 
9232  consdata = SCIPconsGetData(cons);
9233  assert(consdata != NULL);
9234 
9235  nvars = consdata->nvars;
9236 
9237  /* no variables left, then delete constraint */
9238  if( nvars == 0 )
9239  {
9240  assert(consdata->capacity >= 0);
9241 
9242  SCIP_CALL( SCIPdelCons(scip, cons) );
9243  ++(*ndelconss);
9244 
9245  return SCIP_OKAY;
9246  }
9247 
9248  /* sort items */
9249  sortItems(consdata);
9250 
9251  vars = consdata->vars;
9252  weights = consdata->weights;
9253  capacity = consdata->capacity;
9254  v = 0;
9255 
9256  /* check for weights bigger than the capacity */
9257  while( v < nvars && weights[v] > capacity )
9258  {
9259  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9260  assert(!infeasible);
9261 
9262  if( fixed )
9263  ++(*nfixedvars);
9264 
9265  ++v;
9266  }
9267 
9268  /* if we fixed at least one variable we need to delete them from the constraint */
9269  if( v > 0 )
9270  {
9271  if( v == nvars )
9272  {
9273  SCIP_CALL( SCIPdelCons(scip, cons) );
9274  ++(*ndelconss);
9275 
9276  return SCIP_OKAY;
9277  }
9278 
9279  /* delete all position from back to front */
9280  for( --v; v >= 0; --v )
9281  {
9282  SCIP_CALL( delCoefPos(scip, cons, v) );
9283  ++(*nchgcoefs);
9284  }
9285 
9286  /* sort items again because of deletion */
9287  sortItems(consdata);
9288  assert(vars == consdata->vars);
9289  assert(weights == consdata->weights);
9290  }
9291  assert(consdata->sorted);
9292  assert(weights[0] <= capacity);
9293 
9294  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9295  {
9296  SCIP_CALL( SCIPdelCons(scip, cons) );
9297  ++(*ndelconss);
9298  }
9299 
9300  return SCIP_OKAY;
9301 }
9302 
9303 
9304 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9305  *
9306  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9307  *
9308  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9309  *
9310  * the above constraint can be changed to
9311  *
9312  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9313  *
9314  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9315  *
9316  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9317  *
9318  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9319  * constraint further, e.g.
9320  *
9321  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9322  * => 2x1 + x2 + x3 + x4 <= 2
9323  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9324  */
9325 static
9327  SCIP* scip, /**< SCIP data structure */
9328  SCIP_CONS* cons, /**< knapsack constraint */
9329  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9330  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9331  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9332  int* nchgsides, /**< pointer to store the amount of changed sides */
9333  int* naddconss, /**< pointer to count number of added constraints */
9334  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9335  )
9336 {
9337  SCIP_VAR** vars;
9338  SCIP_CONSDATA* consdata;
9339  SCIP_Longint* weights;
9340  SCIP_Longint restweight;
9341  SCIP_Longint newweight;
9342  SCIP_Longint weight;
9343  SCIP_Longint oldgcd;
9344  SCIP_Longint rest;
9345  SCIP_Longint gcd;
9346  int oldnchgcoefs;
9347  int oldnchgsides;
9348  int candpos;
9349  int candpos2;
9350  int offsetv;
9351  int nvars;
9352  int v;
9353 
9354  assert(scip != NULL);
9355  assert(cons != NULL);
9356  assert(nfixedvars != NULL);
9357  assert(ndelconss != NULL);
9358  assert(nchgcoefs != NULL);
9359  assert(nchgsides != NULL);
9360  assert(naddconss != NULL);
9361  assert(cutoff != NULL);
9362  assert(!SCIPconsIsModifiable(cons));
9363 
9364  consdata = SCIPconsGetData(cons);
9365  assert( consdata != NULL );
9366 
9367  *cutoff = FALSE;
9368 
9369  /* remove double enties and also combinations of active and negated variables */
9370  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9371  assert(consdata->merged);
9372  if( *cutoff )
9373  return SCIP_OKAY;
9374 
9375  assert(consdata->capacity >= 0);
9376 
9377  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9378  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9379 
9380  if( SCIPconsIsDeleted(cons) )
9381  return SCIP_OKAY;
9382 
9383  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9384  {
9385  /* 1. dual weights tightening */
9386  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9387 
9388  if( SCIPconsIsDeleted(cons) )
9389  return SCIP_OKAY;
9390  /* 2. delete redundant variables */
9391  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9392 
9393  if( SCIPconsIsDeleted(cons) )
9394  return SCIP_OKAY;
9395  }
9396 
9397  weights = consdata->weights;
9398  nvars = consdata->nvars;
9399 
9400 #ifndef NDEBUG
9401  /* constraint might not be sorted, but the weights are already sorted */
9402  for( v = nvars - 1; v > 0; --v )
9403  assert(weights[v] <= weights[v-1]);
9404 #endif
9405 
9406  /* determine greatest common divisor */
9407  gcd = weights[nvars - 1];
9408  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9409  {
9410  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9411  }
9412 
9413  /* divide the constraint by their greatest common divisor */
9414  if( gcd >= 2 )
9415  {
9416  for( v = nvars - 1; v >= 0; --v )
9417  {
9418  consdataChgWeight(consdata, v, weights[v]/gcd);
9419  }
9420  (*nchgcoefs) += nvars;
9421 
9422  consdata->capacity /= gcd;
9423  (*nchgsides)++;
9424  }
9425  assert(consdata->nvars == nvars);
9426 
9427  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9428  * must not be sorted by their index
9429  */
9430 #ifndef NDEBUG
9431  for( v = nvars - 1; v > 0; --v )
9432  assert(weights[v] <= weights[v-1]);
9433 #endif
9434 
9435  /* 3. start gcd procedure for all variables */
9436  do
9437  {
9438  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9439  SCIPdebug( oldnchgsides = *nchgsides; )
9440 
9441  vars = consdata->vars;
9442  weights = consdata->weights;
9443  nvars = consdata->nvars;
9444 
9445  /* stop if we have two coefficients which are one in absolute value */
9446  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9447  return SCIP_OKAY;
9448 
9449  v = 0;
9450  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9451  * gcd
9452  */
9453  while( weights[v] == consdata->capacity )
9454  {
9455  ++v;
9456  assert(v < nvars);
9457  }
9458 
9459  /* all but one variable are as big as the capacity, this is handled elsewhere */
9460  if( v == nvars - 1 )
9461  return SCIP_OKAY;
9462 
9463  offsetv = v;
9464 
9465  gcd = -1;
9466  candpos = -1;
9467  candpos2 = -1;
9468 
9469  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9470  * change the coefficient
9471  */
9472  for( v = nvars - 1; v >= offsetv; --v )
9473  {
9474  weight = weights[v];
9475  assert(weight >= 1);
9476 
9477  oldgcd = gcd;
9478 
9479  if( gcd == -1 )
9480  {
9481  gcd = weights[v];
9482  assert(gcd >= 1);
9483  }
9484  else
9485  {
9486  /* calculate greatest common divisor for all variables */
9487  gcd = SCIPcalcGreComDiv(gcd, weight);
9488  }
9489 
9490  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9491  * can terminate
9492  */
9493  if( gcd == 1 )
9494  {
9495  /* found candidate */
9496  if( candpos == -1 )
9497  {
9498  gcd = oldgcd;
9499  candpos = v;
9500 
9501  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9502  if( v == nvars - 2 )
9503  candpos2 = v + 1;
9504  }
9505  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9506  else
9507  {
9508  if( candpos == v + 1 && candpos2 == v + 2 )
9509  {
9510  assert(candpos2 == nvars - 1);
9511 
9512  /* take new candidates */
9513  candpos = candpos2;
9514 
9515  /* recalculate gcd from scratch */
9516  gcd = weights[v+1];
9517  assert(gcd >= 1);
9518 
9519  /* calculate greatest common divisor for variables */
9520  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9521  if( gcd == 1 )
9522  return SCIP_OKAY;
9523  }
9524  else
9525  /* cannot determine a possible coefficient for reduction */
9526  return SCIP_OKAY;
9527  }
9528  }
9529  }
9530  assert(gcd >= 2);
9531 
9532  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9533  * further
9534  */
9535  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9536 
9537  /* determine the remainder of the capacity and the gcd */
9538  rest = consdata->capacity % gcd;
9539  assert(rest >= 0);
9540  assert(rest < gcd);
9541 
9542  if( candpos == -1 )
9543  {
9544  /* we assume that the constraint was normalized */
9545  assert(rest > 0);
9546 
9547  /* replace old with new capacity */
9548  consdata->capacity -= rest;
9549  ++(*nchgsides);
9550 
9551  /* replace old big coefficients with new capacity */
9552  for( v = 0; v < offsetv; ++v )
9553  {
9554  consdataChgWeight(consdata, v, consdata->capacity);
9555  }
9556 
9557  *nchgcoefs += offsetv;
9558  goto CONTINUE;
9559  }
9560 
9561  /* determine the remainder of the coefficient candidate and the gcd */
9562  restweight = weights[candpos] % gcd;
9563  assert(restweight >= 1);
9564  assert(restweight < gcd);
9565 
9566  /* calculate new coefficient */
9567  if( restweight > rest )
9568  newweight = weights[candpos] - restweight + gcd;
9569  else
9570  newweight = weights[candpos] - restweight;
9571 
9572  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9573 
9574  SCIPdebugMsg(scip, "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);
9575 
9576  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9577  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9578  */
9579  if( newweight == 0 && offsetv > 0 )
9580  return SCIP_OKAY;
9581 
9582  if( rest > 0 )
9583  {
9584  /* replace old with new capacity */
9585  consdata->capacity -= rest;
9586  ++(*nchgsides);
9587 
9588  /* replace old big coefficients with new capacity */
9589  for( v = 0; v < offsetv; ++v )
9590  {
9591  consdataChgWeight(consdata, v, consdata->capacity);
9592  }
9593 
9594  *nchgcoefs += offsetv;
9595  }
9596 
9597  if( newweight == 0 )
9598  {
9599  /* delete redundant coefficient */
9600  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9601  assert(consdata->nvars == nvars - 1);
9602  --nvars;
9603  }
9604  else
9605  {
9606  /* replace old with new coefficient */
9607  consdataChgWeight(consdata, candpos, newweight);
9608  }
9609  ++(*nchgcoefs);
9610 
9611  assert(consdata->vars == vars);
9612  assert(consdata->nvars == nvars);
9613  assert(consdata->weights == weights);
9614 
9615  CONTINUE:
9616  /* now constraint can be normalized, dividing it by the gcd */
9617  for( v = nvars - 1; v >= 0; --v )
9618  {
9619  consdataChgWeight(consdata, v, weights[v]/gcd);
9620  }
9621  (*nchgcoefs) += nvars;
9622 
9623  consdata->capacity /= gcd;
9624  ++(*nchgsides);
9625 
9626  SCIPdebugPrintCons(scip, cons, NULL);
9627 
9628  SCIPdebugMsg(scip, "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));
9629  }
9630  while( nvars >= 2 );
9631 
9632  return SCIP_OKAY;
9633 }
9634 
9635 
9636 /** inserts an element into the list of binary zero implications */
9637 static
9639  SCIP* scip, /**< SCIP data structure */
9640  int** liftcands, /**< array of the lifting candidates */
9641  int* nliftcands, /**< number of lifting candidates */
9642  int** firstidxs, /**< array of first zeroitems indices */
9643  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9644  int** zeroitems, /**< pointer to zero items array */
9645  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9646  int* zeroitemssize, /**< pointer to size of zero items array */
9647  int* nzeroitems, /**< pointer to length of zero items array */
9648  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9649  SCIP_Bool value, /**< value v of variable y in implication */
9650  int knapsackidx, /**< index of variable x in knapsack */
9651  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9652  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9653  )
9654 {
9655  int nzeros;
9656 
9657  assert(liftcands != NULL);
9658  assert(liftcands[value] != NULL);
9659  assert(nliftcands != NULL);
9660  assert(firstidxs != NULL);
9661  assert(firstidxs[value] != NULL);
9662  assert(zeroweightsums != NULL);
9663  assert(zeroweightsums[value] != NULL);
9664  assert(zeroitems != NULL);
9665  assert(nextidxs != NULL);
9666  assert(zeroitemssize != NULL);
9667  assert(nzeroitems != NULL);
9668  assert(*nzeroitems <= *zeroitemssize);
9669  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9670  assert(memlimitreached != NULL);
9671 
9672  nzeros = *nzeroitems;
9673 
9674  /* allocate enough memory */
9675  if( nzeros == *zeroitemssize )
9676  {
9677  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9678  * this can be too huge - abort on memory limit
9679  */
9680  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9681  {
9682  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9683  *zeroitemssize);
9684  *memlimitreached = TRUE;
9685  return SCIP_OKAY;
9686  }
9687  *zeroitemssize *= 2;
9688  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9689  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9690  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9691  }
9692  assert(nzeros < *zeroitemssize);
9693 
9694  if( *memlimitreached )
9695  *memlimitreached = FALSE;
9696 
9697  /* insert element */
9698  (*zeroitems)[nzeros] = knapsackidx;
9699  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9700  if( firstidxs[value][probindex] == 0 )
9701  {
9702  liftcands[value][nliftcands[value]] = probindex;
9703  ++nliftcands[value];
9704  }
9705  firstidxs[value][probindex] = nzeros;
9706  ++(*nzeroitems);
9707  zeroweightsums[value][probindex] += knapsackweight;
9708 
9709  return SCIP_OKAY;
9710 }
9711 
9712 #define MAX_CLIQUELENGTH 50
9713 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9714  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9715  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9716  * if cliqueweightsum(xi == v) < capacity:
9717  * - fixing variable xi to v would make the knapsack constraint redundant
9718  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9719  * redundancy effect:
9720  * wi' := capacity - cliqueweightsum(xi == v)
9721  * this rule can also be applied to binary variables not in the knapsack!
9722  */
9723 static
9725  SCIP* scip, /**< SCIP data structure */
9726  SCIP_CONS* cons, /**< knapsack constraint */
9727  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9728  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9729  )
9730 {
9731  SCIP_CONSDATA* consdata;
9732  SCIP_VAR** binvars;
9733  int nbinvars;
9734  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9735  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9736  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9737  int* zeroitems; /* item number in knapsack that is implied to zero */
9738  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9739  int zeroitemssize;
9740  int nzeroitems;
9741  SCIP_Bool* zeroiteminserted[2];
9742  SCIP_Bool memlimitreached;
9743  int nliftcands[2];
9744  SCIP_Bool* cliqueused;
9745  SCIP_Bool* itemremoved;
9746  SCIP_Longint maxcliqueweightsum;
9747  SCIP_VAR** addvars;
9748  SCIP_Longint* addweights;
9749  SCIP_Longint addweightsum;
9750  int nvars;
9751  int cliquenum;
9752  int naddvars;
9753  int val;
9754  int i;
9755 
9756  int* tmpindices;
9757  SCIP_Bool* tmpboolindices;
9758  int* tmpindices2;
9759  SCIP_Bool* tmpboolindices2;
9760  int* tmpindices3;
9761  SCIP_Bool* tmpboolindices3;
9762  int tmp;
9763  int tmp2;
9764  int tmp3;
9765  SCIP_CONSHDLR* conshdlr;
9766  SCIP_CONSHDLRDATA* conshdlrdata;
9767 
9768  assert(nchgcoefs != NULL);
9769  assert(!SCIPconsIsModifiable(cons));
9770 
9771  consdata = SCIPconsGetData(cons);
9772  assert(consdata != NULL);
9773  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9774  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9775  assert(consdata->nvars > 0);
9776  assert(consdata->merged);
9777 
9778  nvars = consdata->nvars;
9779 
9780  /* check if the knapsack has too many items/cliques for applying this costly method */
9781  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9782  return SCIP_OKAY;
9783 
9784  /* sort items, s.t. the heaviest one is in the first position */
9785  sortItems(consdata);
9786 
9787  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9788  return SCIP_OKAY;
9789 
9790  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9791  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9792  assert(nbinvars > 0);
9793  binvars = SCIPgetVars(scip);
9794 
9795  /* get conshdlrdata to use cleared memory */
9796  conshdlr = SCIPconsGetHdlr(cons);
9797  assert(conshdlr != NULL);
9798  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9799  assert(conshdlrdata != NULL);
9800 
9801  /* allocate temporary memory for the list of implied to zero variables */
9802  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9803  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9804  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9805 
9806  assert(conshdlrdata->ints1size > 0);
9807  assert(conshdlrdata->ints2size > 0);
9808  assert(conshdlrdata->longints1size > 0);
9809  assert(conshdlrdata->longints2size > 0);
9810 
9811  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9812  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9813  * transform all integers into their binary representation then it maybe happens
9814  */
9815  if( conshdlrdata->ints1size < nbinvars )
9816  {
9817  int oldsize = conshdlrdata->ints1size;
9818 
9819  conshdlrdata->ints1size = nbinvars;
9820  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9821  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9822  }
9823  if( conshdlrdata->ints2size < nbinvars )
9824  {
9825  int oldsize = conshdlrdata->ints2size;
9826 
9827  conshdlrdata->ints2size = nbinvars;
9828  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9829  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9830  }
9831  if( conshdlrdata->longints1size < nbinvars )
9832  {
9833  int oldsize = conshdlrdata->longints1size;
9834 
9835  conshdlrdata->longints1size = nbinvars;
9836  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9837  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9838  }
9839  if( conshdlrdata->longints2size < nbinvars )
9840  {
9841  int oldsize = conshdlrdata->longints2size;
9842 
9843  conshdlrdata->longints2size = nbinvars;
9844  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9845  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9846  }
9847 
9848  firstidxs[0] = conshdlrdata->ints1;
9849  firstidxs[1] = conshdlrdata->ints2;
9850  zeroweightsums[0] = conshdlrdata->longints1;
9851  zeroweightsums[1] = conshdlrdata->longints2;
9852 
9853  /* check for cleared arrays, all entries are zero */
9854 #ifndef NDEBUG
9855  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9856  {
9857  assert(firstidxs[0][tmp] == 0);
9858  assert(firstidxs[1][tmp] == 0);
9859  assert(zeroweightsums[0][tmp] == 0);
9860  assert(zeroweightsums[1][tmp] == 0);
9861  }
9862 #endif
9863 
9864  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9865  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9866 
9867  zeroitems[0] = -1; /* dummy element */
9868  nextidxs[0] = -1;
9869  nzeroitems = 1;
9870  nliftcands[0] = 0;
9871  nliftcands[1] = 0;
9872 
9873  assert(conshdlrdata->bools1size > 0);
9874  assert(conshdlrdata->bools2size > 0);
9875 
9876  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9877  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9878  * transform all integers into their binary representation then it maybe happens
9879  */
9880  if( conshdlrdata->bools1size < nbinvars )
9881  {
9882  int oldsize = conshdlrdata->bools1size;
9883 
9884  conshdlrdata->bools1size = nbinvars;
9885  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9886  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9887  }
9888  if( conshdlrdata->bools2size < nbinvars )
9889  {
9890  int oldsize = conshdlrdata->bools2size;
9891 
9892  conshdlrdata->bools2size = nbinvars;
9893  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9894  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9895  }
9896 
9897  zeroiteminserted[0] = conshdlrdata->bools1;
9898  zeroiteminserted[1] = conshdlrdata->bools2;
9899 
9900  /* check for cleared arrays, all entries are zero */
9901 #ifndef NDEBUG
9902  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9903  {
9904  assert(zeroiteminserted[0][tmp] == 0);
9905  assert(zeroiteminserted[1][tmp] == 0);
9906  }
9907 #endif
9908 
9909  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9910  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9911  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9912  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9913  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9914  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9915  tmp2 = 0;
9916  tmp3 = 0;
9917 
9918  memlimitreached = FALSE;
9919  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9920  {
9921  SCIP_CLIQUE** cliques;
9922  SCIP_VAR* var;
9923  SCIP_Longint weight;
9924  SCIP_Bool value;
9925  int varprobindex;
9926  int ncliques;
9927  int j;
9928 
9929  tmp = 0;
9930 
9931  /* get corresponding active problem variable */
9932  var = consdata->vars[i];
9933  weight = consdata->weights[i];
9934  value = TRUE;
9935  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9936  varprobindex = SCIPvarGetProbindex(var);
9937  assert(0 <= varprobindex && varprobindex < nbinvars);
9938 
9939  /* update the zeroweightsum */
9940  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9941  tmpboolindices3[tmp3] = !value;
9942  tmpindices3[tmp3] = varprobindex;
9943  ++tmp3;
9944 
9945  /* initialize the arrays of inserted zero items */
9946  /* first add the implications (~x == 1 -> x == 0) */
9947  {
9948  SCIP_Bool implvalue;
9949  int probindex;
9950 
9951  probindex = SCIPvarGetProbindex(var);
9952  assert(0 <= probindex && probindex < nbinvars);
9953 
9954  implvalue = !value;
9955 
9956  /* insert the item into the list of the implied variable/value */
9957  assert( !zeroiteminserted[implvalue][probindex] );
9958 
9959  if( firstidxs[implvalue][probindex] == 0 )
9960  {
9961  tmpboolindices2[tmp2] = implvalue;
9962  tmpindices2[tmp2] = probindex;
9963  ++tmp2;
9964  }
9965  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
9966  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
9967  &memlimitreached) );
9968  zeroiteminserted[implvalue][probindex] = TRUE;
9969  tmpboolindices[tmp] = implvalue;
9970  tmpindices[tmp] = probindex;
9971  ++tmp;
9972  }
9973 
9974  /* get the cliques where the knapsack item is member of with value 1 */
9975  ncliques = SCIPvarGetNCliques(var, value);
9976  cliques = SCIPvarGetCliques(var, value);
9977  for( j = 0; j < ncliques && !memlimitreached; ++j )
9978  {
9979  SCIP_VAR** cliquevars;
9980  SCIP_Bool* cliquevalues;
9981  int ncliquevars;
9982  int k;
9983 
9984  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
9985 
9986  /* discard big cliques */
9987  if( ncliquevars > MAX_CLIQUELENGTH )
9988  continue;
9989 
9990  cliquevars = SCIPcliqueGetVars(cliques[j]);
9991  cliquevalues = SCIPcliqueGetValues(cliques[j]);
9992 
9993  for( k = ncliquevars - 1; k >= 0; --k )
9994  {
9995  SCIP_Bool implvalue;
9996  int probindex;
9997 
9998  if( var == cliquevars[k] )
9999  continue;
10000 
10001  probindex = SCIPvarGetProbindex(cliquevars[k]);
10002  if( probindex == -1 )
10003  continue;
10004 
10005  assert(0 <= probindex && probindex < nbinvars);
10006  implvalue = cliquevalues[k];
10007 
10008  /* insert the item into the list of the clique variable/value */
10009  if( !zeroiteminserted[implvalue][probindex] )
10010  {
10011  if( firstidxs[implvalue][probindex] == 0 )
10012  {
10013  tmpboolindices2[tmp2] = implvalue;
10014  tmpindices2[tmp2] = probindex;
10015  ++tmp2;
10016  }
10017 
10018  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10019  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10020  &memlimitreached) );
10021  zeroiteminserted[implvalue][probindex] = TRUE;
10022  tmpboolindices[tmp] = implvalue;
10023  tmpindices[tmp] = probindex;
10024  ++tmp;
10025 
10026  if( memlimitreached )
10027  break;
10028  }
10029  }
10030  }
10031  /* clear zeroiteminserted */
10032  for( --tmp; tmp >= 0; --tmp)
10033  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10034  }
10035  SCIPfreeBufferArray(scip, &tmpboolindices);
10036 
10037  /* calculate the clique partition and the maximal sum of weights using the clique information */
10038  assert(consdata->sorted);
10039  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10040 
10041  assert(conshdlrdata->bools3size > 0);
10042 
10043  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10044  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10045  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10046  */
10047  if( conshdlrdata->bools3size < consdata->nvars )
10048  {
10049  int oldsize = conshdlrdata->bools3size;
10050 
10051  conshdlrdata->bools3size = consdata->nvars;;
10052  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10053  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10054  }
10055 
10056  cliqueused = conshdlrdata->bools3;
10057 
10058  /* check for cleared array, all entries are zero */
10059 #ifndef NDEBUG
10060  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10061  assert(cliqueused[tmp] == 0);
10062 #endif
10063 
10064  maxcliqueweightsum = 0;
10065  tmp = 0;
10066 
10067  /* calculates maximal weight of cliques */
10068  for( i = 0; i < consdata->nvars; ++i )
10069  {
10070  cliquenum = consdata->cliquepartition[i];
10071  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10072 
10073  if( !cliqueused[cliquenum] )
10074  {
10075  maxcliqueweightsum += consdata->weights[i];
10076  cliqueused[cliquenum] = TRUE;
10077  tmpindices[tmp] = cliquenum;
10078  ++tmp;
10079  }
10080  }
10081  /* clear cliqueused */
10082  for( --tmp; tmp >= 0; --tmp)
10083  cliqueused[tmp] = FALSE;
10084 
10085  assert(conshdlrdata->bools4size > 0);
10086 
10087  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10088  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10089  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10090  */
10091  if( conshdlrdata->bools4size < consdata->nvars )
10092  {
10093  int oldsize = conshdlrdata->bools4size;
10094 
10095  conshdlrdata->bools4size = consdata->nvars;
10096  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10097  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10098  }
10099 
10100  itemremoved = conshdlrdata->bools4;
10101 
10102  /* check for cleared array, all entries are zero */
10103 #ifndef NDEBUG
10104  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10105  assert(itemremoved[tmp] == 0);
10106 #endif
10107 
10108  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10109  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10110  * included in subsequent cliqueweightsum calculations)
10111  */
10112  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10113  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10114  naddvars = 0;
10115  addweightsum = 0;
10116  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10117  {
10118  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10119  {
10120  SCIP_Longint cliqueweightsum;
10121  int probindex;
10122  int idx;
10123  int j;
10124 
10125  tmp = 0;
10126 
10127  probindex = liftcands[val][i];
10128  assert(0 <= probindex && probindex < nbinvars);
10129 
10130  /* ignore empty zero lists and variables that cannot be lifted anyways */
10131  if( firstidxs[val][probindex] == 0
10132  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10133  continue;
10134 
10135  /* mark the items that are implied to zero by setting the current variable to the current value */
10136  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10137  {
10138  assert(0 < idx && idx < nzeroitems);
10139  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10140  itemremoved[zeroitems[idx]] = TRUE;
10141  }
10142 
10143  /* calculate the residual cliqueweight sum */
10144  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10145  for( j = 0; j < consdata->nvars; ++j )
10146  {
10147  cliquenum = consdata->cliquepartition[j];
10148  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10149  if( !itemremoved[j] )
10150  {
10151  if( !cliqueused[cliquenum] )
10152  {
10153  cliqueweightsum += consdata->weights[j];
10154  cliqueused[cliquenum] = TRUE;
10155  tmpindices[tmp] = cliquenum;
10156  ++tmp;
10157  }
10158 
10159  if( cliqueweightsum >= consdata->capacity )
10160  break;
10161  }
10162  }
10163 
10164  /* check if the weight of the variable/value can be increased */
10165  if( cliqueweightsum < consdata->capacity )
10166  {
10167  SCIP_VAR* var;
10168  SCIP_Longint weight;
10169 
10170  /* insert the variable (with value TRUE) in the list of additional items */
10171  assert(naddvars < 2*nbinvars);
10172  var = binvars[probindex];
10173  if( val == FALSE )
10174  {
10175  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10176  }
10177  weight = consdata->capacity - cliqueweightsum;
10178  addvars[naddvars] = var;
10179  addweights[naddvars] = weight;
10180  addweightsum += weight;
10181  naddvars++;
10182 
10183  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10184  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10185  }
10186 
10187  /* clear itemremoved */
10188  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10189  {
10190  assert(0 < idx && idx < nzeroitems);
10191  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10192  itemremoved[zeroitems[idx]] = FALSE;
10193  }
10194  /* clear cliqueused */
10195  for( --tmp; tmp >= 0; --tmp)
10196  cliqueused[tmpindices[tmp]] = FALSE;
10197  }
10198  }
10199  SCIPfreeBufferArray(scip, &tmpindices);
10200 
10201  /* clear part of zeroweightsums */
10202  for( --tmp3; tmp3 >= 0; --tmp3)
10203  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10204 
10205  /* clear rest of zeroweightsums and firstidxs */
10206  for( --tmp2; tmp2 >= 0; --tmp2)
10207  {
10208  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10209  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10210  }
10211 
10212  SCIPfreeBufferArray(scip, &tmpindices2);
10213  SCIPfreeBufferArray(scip, &tmpindices3);
10214  SCIPfreeBufferArray(scip, &tmpboolindices2);
10215  SCIPfreeBufferArray(scip, &tmpboolindices3);
10216 
10217  /* add all additional item weights */
10218  for( i = 0; i < naddvars; ++i )
10219  {
10220  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10221  }
10222  *nchgcoefs += naddvars;
10223 
10224  if( naddvars > 0 )
10225  {
10226  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10227  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10228  }
10229 
10230  /* free temporary memory */
10231  SCIPfreeBufferArray(scip, &addweights);
10232  SCIPfreeBufferArray(scip, &addvars);
10233  SCIPfreeBufferArray(scip, &nextidxs);
10234  SCIPfreeBufferArray(scip, &zeroitems);
10235  SCIPfreeBufferArray(scip, &liftcands[1]);
10236  SCIPfreeBufferArray(scip, &liftcands[0]);
10237 
10238  return SCIP_OKAY;
10239 }
10240 
10241 /** tightens item weights and capacity in presolving:
10242  * given a knapsack sum(wi*xi) <= capacity
10243  * (1) let weightsum := sum(wi)
10244  * if weightsum - wi < capacity:
10245  * - not using item i would make the knapsack constraint redundant
10246  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10247  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10248  * - change coefficients:
10249  * wi' := weightsum - capacity
10250  * capacity' := capacity - (wi - wi')
10251  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10252  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10253  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10254  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10255  * can be multiple times the same weight, this can be improved
10256  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10257  * weight, to capacity - lastmininmalweightsum, e.g. :
10258  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10259  * -> minimal weightsums: 5, 5, 10, 10
10260  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10261  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10262  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10263  * (3) let W(C) be the maximal weight of clique C,
10264  * cliqueweightsum := sum(W(C))
10265  * if cliqueweightsum - W(C) < capacity:
10266  * - not using any item of C would make the knapsack constraint redundant
10267  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10268  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10269  * - change coefficients:
10270  * delta := capacity - (cliqueweightsum - W(C))
10271  * wi' := max(wi - delta, 0)
10272  * capacity' := capacity - delta
10273  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10274  * introduce infeasible solutions.
10275  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10276  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10277  * if cliqueweightsum(xi == v) < capacity:
10278  * - fixing variable xi to v would make the knapsack constraint redundant
10279  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10280  * redundancy effect:
10281  * wi' := capacity - cliqueweightsum(xi == v)
10282  * This rule can also be applied to binary variables not in the knapsack!
10283  * (5) if min{w} + wi > capacity:
10284  * - using item i would force to fix other items to zero
10285  * - wi can be increased to the capacity
10286  */
10287 static
10289  SCIP* scip, /**< SCIP data structure */
10290  SCIP_CONS* cons, /**< knapsack constraint */
10291  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10292  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10293  int* nchgsides, /**< pointer to count number of side changes */
10294  int* naddconss, /**< pointer to count number of added constraints */
10295  int* ndelconss, /**< pointer to count number of deleted constraints */
10296  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10297  )
10298 {
10299  SCIP_CONSHDLRDATA* conshdlrdata;
10300  SCIP_CONSDATA* consdata;
10301  SCIP_Longint* weights;
10302  SCIP_Longint sumcoef;
10303  SCIP_Longint capacity;
10304  SCIP_Longint newweight;
10305  SCIP_Longint maxweight;
10306  SCIP_Longint minweight;
10307  SCIP_Bool sumcoefcase = FALSE;
10308  int startpos;
10309  int backpos;
10310  int nvars;
10311  int pos;
10312  int k;
10313  int i;
10314 
10315  assert(nchgcoefs != NULL);
10316  assert(nchgsides != NULL);
10317  assert(!SCIPconsIsModifiable(cons));
10318 
10319  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10320  assert(conshdlrdata != NULL);
10321 
10322  consdata = SCIPconsGetData(cons);
10323  assert(consdata != NULL);
10324  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10325  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10326  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10327  assert(consdata->nvars > 0);
10328 
10329  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10330  if( *cutoff )
10331  return SCIP_OKAY;
10332 
10333  /* apply rule (1) */
10334  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10335  {
10336  do
10337  {
10338  assert(consdata->merged);
10339 
10340  /* sort items, s.t. the heaviest one is in the first position */
10341  sortItems(consdata);
10342 
10343  for( i = 0; i < consdata->nvars; ++i )
10344  {
10345  SCIP_Longint weight;
10346 
10347  weight = consdata->weights[i];
10348  if( consdata->weightsum - weight < consdata->capacity )
10349  {
10350  newweight = consdata->weightsum - consdata->capacity;
10351  consdataChgWeight(consdata, i, newweight);
10352  consdata->capacity -= (weight - newweight);
10353  (*nchgcoefs)++;
10354  (*nchgsides)++;
10355  assert(!consdata->sorted);
10356  SCIPdebugMsg(scip, "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",
10357  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10358  consdata->capacity + (weight-newweight), consdata->capacity);
10359  }
10360  else
10361  break;
10362  }
10363  }
10364  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10365  }
10366 
10367  /* check for redundancy */
10368  if( consdata->weightsum <= consdata->capacity )
10369  return SCIP_OKAY;
10370 
10371  pos = 0;
10372  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10373  ++pos;
10374 
10375  sumcoef = 0;
10376  weights = consdata->weights;
10377  nvars = consdata->nvars;
10378  capacity = consdata->capacity;
10379 
10380  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10381  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10382  {
10383  /* further reductions using the next possible coefficient sum
10384  *
10385  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10386  */
10387  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10388  for( k = 0; k < 4; ++k )
10389  {
10390  newweight = capacity - sumcoef;
10391 
10392  /* determine next minimal coefficient sum */
10393  switch( k )
10394  {
10395  case 0:
10396  sumcoef = weights[nvars - 1];
10397  backpos = nvars - 1;
10398  break;
10399  case 1:
10400  sumcoef = weights[nvars - 2];
10401  backpos = nvars - 2;
10402  break;
10403  case 2:
10404  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10405  {
10406  sumcoefcase = TRUE;
10407  sumcoef = weights[nvars - 3];
10408  backpos = nvars - 3;
10409  }
10410  else
10411  {
10412  sumcoefcase = FALSE;
10413  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10414  backpos = nvars - 2;
10415  }
10416  break;
10417  default:
10418  assert(k == 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  }
10439 
10440  if( backpos <= pos )
10441  break;
10442 
10443  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10444  maxweight = weights[pos];
10445  startpos = pos;
10446  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10447  {
10448  assert(newweight > weights[pos]);
10449 
10450  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10451  SCIPconsGetName(cons), maxweight, newweight);
10452 
10453  consdataChgWeight(consdata, pos, newweight);
10454 
10455  ++pos;
10456  assert(pos < nvars);
10457 
10458  maxweight = weights[pos];
10459 
10460  if( backpos <= pos )
10461  break;
10462  }
10463  (*nchgcoefs) += (pos - startpos);
10464 
10465  /* skip unchangable weights */
10466  while( pos < nvars && weights[pos] + sumcoef == capacity )
10467  ++pos;
10468 
10469  /* check special case were there is only one weight left to tighten
10470  *
10471  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10472  *
10473  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10474  *
10475  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10476  */
10477  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10478  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10479  {
10480  newweight = capacity - sumcoef;
10481  assert(newweight > weights[pos]);
10482 
10483  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10484  SCIPconsGetName(cons), maxweight, newweight);
10485 
10486  consdataChgWeight(consdata, pos, newweight);
10487 
10488  break;
10489  }
10490 
10491  if( backpos <= pos )
10492  break;
10493  }
10494  }
10495 
10496  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10497  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10498  {
10499  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10500  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10501  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10502  {
10503  SCIP_VAR** clqvars;
10504  SCIP_CONS* cliquecons;
10505  char name[SCIP_MAXSTRLEN];
10506  int* clqpart;
10507  int nclqvars;
10508  int nclq;
10509  int len;
10510  int c;
10511  int w;
10512 
10513  assert(!SCIPconsIsDeleted(cons));
10514 
10515  if( pos == consdata->nvars )
10516  {
10517  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10518 
10519  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10523  SCIPconsIsStickingAtNode(cons)) );
10524 
10525  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10526  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10527  ++(*naddconss);
10528 
10529  /* delete old constraint */
10530  SCIP_CALL( SCIPdelCons(scip, cons) );
10531  ++(*ndelconss);
10532 
10533  return SCIP_OKAY;
10534  }
10535 
10536  len = consdata->nvars - pos;
10537 
10538  /* allocate temporary memory */
10539  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10540 
10541  /* calculate clique partition */
10542  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10543  assert(nclq <= len);
10544 
10545 #ifndef NDEBUG
10546  /* clique numbers must be at least as high as the index */
10547  for( w = 0; w < nclq; ++w )
10548  assert(clqpart[w] <= w);
10549 #endif
10550 
10551  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10552 
10553  /* allocate temporary memory */
10554  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10555 
10556  /* copy corresponding variables with big coefficients */
10557  for( w = pos - 1; w >= 0; --w )
10558  clqvars[w] = consdata->vars[w];
10559 
10560  /* create for each clique a set-packing constraint */
10561  for( c = 0; c < nclq; ++c )
10562  {
10563  nclqvars = pos;
10564 
10565  for( w = c; w < len; ++w )
10566  {
10567  if( clqpart[w] == c )
10568  {
10569  assert(nclqvars < pos + len - nclq + 1);
10570  clqvars[nclqvars] = consdata->vars[w + pos];
10571  ++nclqvars;
10572  }
10573  }
10574 
10575  assert(nclqvars > 1);
10576 
10577  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10578  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10582  SCIPconsIsStickingAtNode(cons)) );
10583  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10584  SCIPdebugPrintCons(scip, cliquecons, NULL);
10585  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10586  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10587  ++(*naddconss);
10588  }
10589 
10590  /* delete old constraint */
10591  SCIP_CALL( SCIPdelCons(scip, cons) );
10592  ++(*ndelconss);
10593 
10594  SCIPfreeBufferArray(scip, &clqvars);
10595  SCIPfreeBufferArray(scip, &clqpart);
10596 
10597  return SCIP_OKAY;
10598  }
10599  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10600  {
10601  SCIP_Longint* maxcliqueweights;
10602  SCIP_Longint* newweightvals;
10603  int* newweightidxs;
10604  SCIP_Longint cliqueweightsum;
10605 
10606  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10607  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10608  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10609 
10610  /* repeat as long as changes have been applied */
10611  do
10612  {
10613  int ncliques;
10614  int cliquenum;
10615  SCIP_Bool zeroweights;
10616 
10617  assert(consdata->merged);
10618 
10619  /* sort items, s.t. the heaviest one is in the first position */
10620  sortItems(consdata);
10621 
10622  /* calculate a clique partition */
10623  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10624 
10625  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10626  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10627  break;
10628 
10629  /* calculate the maximal weight of the cliques and store the clique type */
10630  cliqueweightsum = 0;
10631  ncliques = 0;
10632 
10633  for( i = 0; i < consdata->nvars; ++i )
10634  {
10635  SCIP_Longint weight;
10636 
10637  cliquenum = consdata->cliquepartition[i];
10638  assert(0 <= cliquenum && cliquenum <= ncliques);
10639 
10640  weight = consdata->weights[i];
10641  assert(weight > 0);
10642 
10643  if( cliquenum == ncliques )
10644  {
10645  maxcliqueweights[ncliques] = weight;
10646  cliqueweightsum += weight;
10647  ++ncliques;
10648  }
10649 
10650  assert(maxcliqueweights[cliquenum] >= weight);
10651  }
10652 
10653  /* apply rule on every clique */
10654  zeroweights = FALSE;
10655  for( i = 0; i < ncliques; ++i )
10656  {
10657  SCIP_Longint delta;
10658 
10659  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10660  if( delta > 0 )
10661  {
10662  SCIP_Longint newcapacity;
10663 #ifndef NDEBUG
10664  SCIP_Longint newmincliqueweight;
10665 #endif
10666  SCIP_Longint newminweightsuminclique;
10667  SCIP_Bool forceclique;
10668  int nnewweights;
10669  int j;
10670 
10671  SCIPdebugMsg(scip, "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",
10672  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10673  newcapacity = consdata->capacity - delta;
10674  forceclique = FALSE;
10675  nnewweights = 0;
10676 #ifndef NDEBUG
10677  newmincliqueweight = newcapacity + 1;
10678  for( j = 0; j < i; ++j )
10679  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10680 #endif
10681  for( j = i; j < consdata->nvars; ++j )
10682  {
10683  if( consdata->cliquepartition[j] == i )
10684  {
10685  newweight = consdata->weights[j] - delta;
10686  newweight = MAX(newweight, 0);
10687 
10688  /* cache the new weight */
10689  assert(nnewweights < consdata->nvars);
10690  newweightvals[nnewweights] = newweight;
10691  newweightidxs[nnewweights] = j;
10692  nnewweights++;
10693 
10694 #ifndef NDEBUG
10695  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10696  newmincliqueweight = newweight;
10697 #endif
10698  }
10699  }
10700 
10701  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10702  if( nnewweights > 1 )
10703  {
10704 #ifndef NDEBUG
10705  j = newweightidxs[nnewweights - 2];
10706  assert(0 <= j && j < consdata->nvars);
10707  assert(consdata->cliquepartition[j] == i);
10708  j = newweightidxs[nnewweights - 1];
10709  assert(0 <= j && j < consdata->nvars);
10710  assert(consdata->cliquepartition[j] == i);
10711 #endif
10712 
10713  newminweightsuminclique = newweightvals[nnewweights - 2];
10714  newminweightsuminclique += newweightvals[nnewweights - 1];
10715 
10716  /* check if these new two minimal weights both fit into the knapsack;
10717  * if this is true, we have to add a clique constraint in order to enforce the clique
10718  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10719  * reduction might be infeasible, i.e., allows additional solutions)
10720  */
10721  if( newminweightsuminclique <= newcapacity )
10722  forceclique = TRUE;
10723  }
10724 
10725  /* check if we really want to apply the change */
10726  if( conshdlrdata->disaggregation || !forceclique )
10727  {
10728  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10729  consdata->capacity, newcapacity, forceclique);
10730  consdata->capacity = newcapacity;
10731  (*nchgsides)++;
10732 
10733  for( k = 0; k < nnewweights; ++k )
10734  {
10735  j = newweightidxs[k];
10736  assert(0 <= j && j < consdata->nvars);
10737  assert(consdata->cliquepartition[j] == i);
10738 
10739  /* apply the weight change */
10740  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10741  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10742  consdataChgWeight(consdata, j, newweightvals[k]);
10743  (*nchgcoefs)++;
10744  assert(!consdata->sorted);
10745  zeroweights = zeroweights || (newweightvals[k] == 0);
10746  }
10747  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10748  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10749  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10750  * knapsack constraint
10751  */
10752  if( forceclique )
10753  {
10754  SCIP_CONS* cliquecons;
10755  char name[SCIP_MAXSTRLEN];
10756  SCIP_VAR** cliquevars;
10757 
10758  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10759  for( k = 0; k < nnewweights; ++k )
10760  cliquevars[k] = consdata->vars[newweightidxs[k]];
10761 
10762  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10763  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10767  SCIPconsIsStickingAtNode(cons)) );
10768  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10769  SCIPdebugPrintCons(scip, cliquecons, NULL);
10770  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10771  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10772  SCIPfreeBufferArray(scip, &cliquevars);
10773  (*naddconss)++;
10774  }
10775  }
10776  }
10777  }
10778  if( zeroweights )
10779  {
10780  SCIP_CALL( removeZeroWeights(scip, cons) );
10781  }
10782  }
10783  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10784 
10785  /* free temporary memory */
10786  SCIPfreeBufferArray(scip, &newweightidxs);
10787  SCIPfreeBufferArray(scip, &newweightvals);
10788  SCIPfreeBufferArray(scip, &maxcliqueweights);
10789 
10790  /* check for redundancy */
10791  if( consdata->weightsum <= consdata->capacity )
10792  return SCIP_OKAY;
10793  }
10794  }
10795 
10796  /* apply rule (3) */
10797  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10798  {
10799  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10800  }
10801 
10802  /* check for redundancy */
10803  if( consdata->weightsum <= consdata->capacity )
10804  return SCIP_OKAY;
10805 
10806  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10807  {
10808  /* apply rule (4) (all but smallest weight) */
10809  assert(consdata->merged);
10810  sortItems(consdata);
10811  minweight = consdata->weights[consdata->nvars-1];
10812  for( i = 0; i < consdata->nvars-1; ++i )
10813  {
10814  SCIP_Longint weight;
10815 
10816  weight = consdata->weights[i];
10817  assert(weight >= minweight);
10818  if( minweight + weight > consdata->capacity )
10819  {
10820  if( weight < consdata->capacity )
10821  {
10822  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10823  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10824  assert(consdata->sorted);
10825  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10826  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10827  consdata->sorted = TRUE;
10828  (*nchgcoefs)++;
10829  }
10830  }
10831  else
10832  break;
10833  }
10834 
10835  /* apply rule (5) (smallest weight) */
10836  if( consdata->nvars >= 2 )
10837  {
10838  SCIP_Longint weight;
10839 
10840  minweight = consdata->weights[consdata->nvars-2];
10841  weight = consdata->weights[consdata->nvars-1];
10842  assert(minweight >= weight);
10843  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10844  {
10845  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10846  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10847  assert(consdata->sorted);
10848  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10849  assert(minweight >= consdata->weights[consdata->nvars-1]);
10850  consdata->sorted = TRUE;
10851  (*nchgcoefs)++;
10852  }
10853  }
10854  }
10855 
10856  return SCIP_OKAY;
10857 }
10858 
10859 
10860 #ifdef SCIP_DEBUG
10861 static
10862 void printClique(
10863  SCIP_VAR** cliquevars,
10864  int ncliquevars
10865  )
10866 {
10867  int b;
10868  SCIPdebugMessage("adding new Clique: ");
10869  for( b = 0; b < ncliquevars; ++b )
10870  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10871  SCIPdebugPrintf("\n");
10872 }
10873 #endif
10874 
10875 /** adds negated cliques of the knapsack constraint to the global clique table */
10876 static
10878  SCIP*const scip, /**< SCIP data structure */
10879  SCIP_CONS*const cons, /**< knapsack constraint */
10880  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10881  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10882  )
10883 {
10884  SCIP_CONSDATA* consdata;
10885  SCIP_CONSHDLRDATA* conshdlrdata;
10886  SCIP_VAR** poscliquevars;
10887  SCIP_VAR** cliquevars;
10888  SCIP_Longint* maxweights;
10889  SCIP_Longint* gainweights;
10890  int* gaincliquepartition;
10891  SCIP_Bool* cliqueused;
10892  SCIP_Longint minactduetonegcliques;
10893  SCIP_Longint freecapacity;
10894  SCIP_Longint lastweight;
10895  SCIP_Longint beforelastweight;
10896  int nposcliquevars;
10897  int ncliquevars;
10898  int nvars;
10899  int nnegcliques;
10900  int lastcliqueused;
10901  int thisnbdchgs;
10902  int v;
10903  int w;
10904 
10905  assert(scip != NULL);
10906  assert(cons != NULL);
10907  assert(cutoff != NULL);
10908  assert(nbdchgs != NULL);
10909 
10910  *cutoff = FALSE;
10911 
10912  consdata = SCIPconsGetData(cons);
10913  assert(consdata != NULL);
10914 
10915  nvars = consdata->nvars;
10916 
10917  /* check whether the cliques have already been added */
10918  if( consdata->cliquesadded || nvars == 0 )
10919  return SCIP_OKAY;
10920 
10921  /* make sure, the items are merged */
10922  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10923  if( *cutoff )
10924  return SCIP_OKAY;
10925 
10926  /* make sure, items are sorted by non-increasing weight */
10927  sortItems(consdata);
10928 
10929  assert(consdata->merged);
10930 
10931  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10932  assert(conshdlrdata != NULL);
10933 
10934  /* calculate a clique partition */
10935  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10936  nnegcliques = consdata->nnegcliques;
10937 
10938  /* if we have no negated cliques, stop */
10939  if( nnegcliques == nvars )
10940  return SCIP_OKAY;
10941 
10942  /* get temporary memory */
10943  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10944  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10945  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
10946  BMSclearMemoryArray(gainweights, nvars);
10947  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10948  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10949  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueused, nnegcliques) );
10950  BMSclearMemoryArray(cliqueused, nnegcliques);
10951 
10952  nnegcliques = 0;
10953  minactduetonegcliques = 0;
10954 
10955  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10956  for( v = 0; v < nvars; ++v )
10957  {
10958  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10959  assert(consdata->weights[v] > 0);
10960 
10961  if( consdata->negcliquepartition[v] == nnegcliques )
10962  {
10963  nnegcliques++;
10964  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
10965  }
10966  else
10967  minactduetonegcliques += consdata->weights[v];
10968  }
10969 
10970  nposcliquevars = 0;
10971 
10972  /* add cliques, using negated cliques information */
10973  if( minactduetonegcliques > 0 )
10974  {
10975  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
10976  freecapacity = consdata->capacity - minactduetonegcliques;
10977 
10978  SCIPdebugPrintCons(scip, cons, NULL);
10979  SCIPdebugMsg(scip, "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",
10980  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
10981 
10982  /* calculate possible gain by switching chosen items in negated cliques */
10983  for( v = 0; v < nvars; ++v )
10984  {
10985  if( !cliqueused[consdata->negcliquepartition[v]] )
10986  {
10987  cliqueused[consdata->negcliquepartition[v]] = TRUE;
10988  for( w = v + 1; w < nvars; ++w )
10989  {
10990  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
10991  * weight[w] (which are both in a negated clique) */
10992  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
10993  && consdata->weights[v] > consdata->weights[w] )
10994  {
10995  poscliquevars[nposcliquevars] = consdata->vars[w];
10996  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
10997  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
10998  ++nposcliquevars;
10999  }
11000  }
11001  }
11002  }
11003 
11004  /* try to create negated cliques */
11005  if( nposcliquevars > 0 )
11006  {
11007  /* sort possible gain per substitution of the clique members */
11008  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11009 
11010  for( v = 0; v < nposcliquevars; ++v )
11011  {
11012  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11013  ncliquevars = 1;
11014  lastweight = gainweights[v];
11015  beforelastweight = -1;
11016  lastcliqueused = gaincliquepartition[v];
11017  /* clear cliqueused to get an unused array */
11018  BMSclearMemoryArray(cliqueused, nnegcliques);
11019  cliqueused[gaincliquepartition[v]] = TRUE;
11020 
11021  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11022  * in the same negated clique and by taking two of them would exceed the free capacity */
11023  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11024  {
11025  beforelastweight = lastweight;
11026  lastweight = gainweights[w];
11027  lastcliqueused = gaincliquepartition[w];
11028  cliqueused[gaincliquepartition[w]] = TRUE;
11029  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11030  ++ncliquevars;
11031  }
11032 
11033  if( ncliquevars > 1 )
11034  {
11035  SCIPdebug( printClique(cliquevars, ncliquevars) );
11036  assert(beforelastweight > 0);
11037  /* add the clique to the clique table */
11038  /* this really happens, e.g., on enigma.mps from the short test set */
11039  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11040  if( *cutoff )
11041  goto TERMINATE;
11042  *nbdchgs += thisnbdchgs;
11043 
11044  /* reset last used clique to get slightly different cliques */
11045  cliqueused[lastcliqueused] = FALSE;
11046 
11047  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11048  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11049  {
11050  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11051  SCIPdebug( printClique(cliquevars, ncliquevars) );
11052  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11053  if( *cutoff )
11054  goto TERMINATE;
11055  *nbdchgs += thisnbdchgs;
11056  }
11057  }
11058  }
11059  }
11060  }
11061 
11062  TERMINATE:
11063  /* free temporary memory */
11064  SCIPfreeBufferArray(scip, &cliqueused);
11065  SCIPfreeBufferArray(scip, &gaincliquepartition);
11066  SCIPfreeBufferArray(scip, &maxweights);
11067  SCIPfreeBufferArray(scip, &gainweights);
11068  SCIPfreeBufferArray(scip, &cliquevars);
11069  SCIPfreeBufferArray(scip, &poscliquevars);
11070 
11071  return SCIP_OKAY;
11072 }
11073 
11074 /** greedy clique detection by considering weights and capacity
11075  *
11076  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11077  * 1) neighboring items which exceed the capacity together => one clique
11078  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11079  */
11080 static
11082  SCIP*const scip, /**< SCIP data structure */
11083  SCIP_VAR** items, /**< array of variable items */
11084  SCIP_Longint* weights, /**< weights of the items */
11085  int nitems, /**< the number of items */
11086  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11087  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11088  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11089  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11090  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11091  )
11092 {
11093  SCIP_Longint lastweight;
11094  int ncliquevars;
11095  int i;
11096  int thisnbdchgs;
11097 
11098  if( nitems <= 1 )
11099  return SCIP_OKAY;
11100 
11101  /* sort possible gain per substitution of the clique members */
11102  if( ! sorteditems )
11103  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11104 
11105  ncliquevars = 1;
11106  lastweight = weights[0];
11107 
11108  /* taking these two weights together violates the knapsack => include into clique */
11109  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11110  {
11111  lastweight = weights[i];
11112  ++ncliquevars;
11113  }
11114 
11115  if( ncliquevars > 1 )
11116  {
11117  SCIP_Longint compareweight;
11118  SCIP_VAR** cliquevars;
11119  int compareweightidx;
11120  int minclqsize;
11121 
11122  /* add the clique to the clique table */
11123  SCIPdebug( printClique(items, ncliquevars) );
11124  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11125 
11126  if( *cutoff )
11127  return SCIP_OKAY;
11128 
11129  *nbdchgs += thisnbdchgs;
11130 
11131  /* no more cliques to be found (don't know if this can actually happen, since the knapsack could be replaced by a set-packing constraint)*/
11132  if( ncliquevars == nitems )
11133  return SCIP_OKAY;
11134 
11135  /* copy items in order into buffer array and deduce more cliques */
11136  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11137 
11138  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11139  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11140  compareweightidx = ncliquevars - 2;
11141  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11142 
11143  /* determine minimum clique size for the following loop */
11144  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11145  minclqsize = MAX(minclqsize, 2);
11146 
11147  /* loop over the remaining variables and the larger items of the first clique until we find another clique or reach the size limit */
11148  while( compareweightidx >= 0 && i < nitems && ncliquevars >= minclqsize && ! (*cutoff) )
11149  {
11150  compareweight = weights[compareweightidx];
11151  assert(compareweight > 0);
11152 
11153  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11154  if( compareweight + weights[i] > capacity )
11155  {
11156  assert(compareweightidx == ncliquevars -2);
11157  cliquevars[ncliquevars - 1] = items[i];
11158  SCIPdebug( printClique(cliquevars, ncliquevars) );
11159  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11160 
11161  /* stop when there is a cutoff */
11162  if( ! (*cutoff) )
11163  *nbdchgs += thisnbdchgs;
11164 
11165  /* go to next smaller item */
11166  ++i;
11167  }
11168  else
11169  {
11170  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11171  compareweightidx--;
11172  ncliquevars --;
11173  }
11174 
11175  }
11176 
11177  SCIPfreeBufferArray(scip, &cliquevars);
11178  }
11179 
11180  return SCIP_OKAY;
11181 }
11182 
11183 /** adds cliques of the knapsack constraint to the global clique table */
11184 static
11186  SCIP*const scip, /**< SCIP data structure */
11187  SCIP_CONS*const cons, /**< knapsack constraint */
11188  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11189  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11190  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11191  )
11192 {
11193  SCIP_CONSDATA* consdata;
11194  SCIP_CONSHDLRDATA* conshdlrdata;
11195  int i;
11196  SCIP_Longint minactduetonegcliques;
11197  SCIP_Longint freecapacity;
11198  int nnegcliques;
11199  int cliquenum;
11200  SCIP_VAR** poscliquevars;
11201  SCIP_Longint* gainweights;
11202  int nposcliquevars;
11203  SCIP_Longint* secondmaxweights;
11204  int nvars;
11205 
11206  assert(scip != NULL);
11207  assert(cons != NULL);
11208  assert(cutoff != NULL);
11209  assert(nbdchgs != NULL);
11210 
11211  *cutoff = FALSE;
11212 
11213  consdata = SCIPconsGetData(cons);
11214  assert(consdata != NULL);
11215 
11216  nvars = consdata->nvars;
11217 
11218  /* check whether the cliques have already been added */
11219  if( consdata->cliquesadded || nvars == 0 )
11220  return SCIP_OKAY;
11221 
11222  /* make sure, the items are merged */
11223  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11224  if( *cutoff )
11225  return SCIP_OKAY;
11226 
11227  /* make sure, the items are sorted by non-increasing weight */
11228  sortItems(consdata);
11229 
11230  assert(consdata->merged);
11231 
11232  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11233  assert(conshdlrdata != NULL);
11234 
11235  /* calculate a clique partition */
11236  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11237  nnegcliques = consdata->nnegcliques;
11238  assert(nnegcliques <= nvars);
11239 
11240  /* get temporary memory */
11241  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11242  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11243  BMSclearMemoryArray(gainweights, nvars);
11244  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11245  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11246 
11247  minactduetonegcliques = 0;
11248 
11249  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11250  if( nnegcliques < nvars )
11251  {
11252  nnegcliques = 0;
11253 
11254  for( i = 0; i < nvars; ++i )
11255  {
11256  SCIP_Longint weight;
11257 
11258  cliquenum = consdata->negcliquepartition[i];
11259  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11260 
11261  weight = consdata->weights[i];
11262  assert(weight > 0);
11263 
11264  if( cliquenum == nnegcliques )
11265  nnegcliques++;
11266  else
11267  {
11268  minactduetonegcliques += weight;
11269  if( secondmaxweights[cliquenum] == 0 )
11270  secondmaxweights[cliquenum] = weight;
11271  }
11272  }
11273  }
11274 
11275  /* add cliques, using negated cliques information */
11276  if( minactduetonegcliques > 0 )
11277  {
11278  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11279  freecapacity = consdata->capacity - minactduetonegcliques;
11280 
11281  SCIPdebugPrintCons(scip, cons, NULL);
11282  SCIPdebugMsg(scip, "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",
11283  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11284 
11285  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11286  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11287 
11288  if( *cutoff )
11289  goto TERMINATE;
11290 
11291  nposcliquevars = 0;
11292 
11293  for( i = nvars - 1; i >= 0; --i )
11294  {
11295  /* if we would take the biggest weight instead of the second biggest */
11296  cliquenum = consdata->negcliquepartition[i];
11297  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11298  {
11299  poscliquevars[nposcliquevars] = consdata->vars[i];
11300  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11301  ++nposcliquevars;
11302  }
11303  }
11304 
11305  /* use the gain weights and free capacity to derive greedily cliques */
11306  if( nposcliquevars > 1 )
11307  {
11308  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11309 
11310  if( *cutoff )
11311  goto TERMINATE;
11312  }
11313  }
11314 
11315  /* build cliques by using the items with the maximal weights */
11316  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11317 
11318  TERMINATE:
11319  /* free temporary memory and mark the constraint */
11320  SCIPfreeBufferArray(scip, &secondmaxweights);
11321  SCIPfreeBufferArray(scip, &gainweights);
11322  SCIPfreeBufferArray(scip, &poscliquevars);
11323  consdata->cliquesadded = TRUE;
11324 
11325  return SCIP_OKAY;
11326 }
11327 
11328 
11329 /** gets the key of the given element */
11330 static
11331 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11332 { /*lint --e{715}*/
11333  /* the key is the element itself */
11334  return elem;
11335 }
11336 
11337 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11338  * same coefficients
11339  */
11340 static
11341 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11342 {
11343 #ifndef NDEBUG
11344  SCIP* scip;
11345 #endif
11346  SCIP_CONSDATA* consdata1;
11347  SCIP_CONSDATA* consdata2;
11348  int i;
11350  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11351  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11352  assert(consdata1->sorted);
11353  assert(consdata2->sorted);
11354 #ifndef NDEBUG
11355  scip = (SCIP*)userptr;
11356  assert(scip != NULL);
11357 #endif
11358 
11359  /* checks trivial case */
11360  if( consdata1->nvars != consdata2->nvars )
11361  return FALSE;
11362 
11363  for( i = consdata1->nvars - 1; i >= 0; --i )
11364  {
11365  /* tests if variables are equal */
11366  if( consdata1->vars[i] != consdata2->vars[i] )
11367  {
11368  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11369  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11370  return FALSE;
11371  }
11372  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11373 
11374  /* tests if weights are equal too */
11375  if( consdata1->weights[i] != consdata2->weights[i] )
11376  return FALSE;
11377  }
11378 
11379  return TRUE;
11380 }
11381 
11382 /** returns the hash value of the key */
11383 static
11384 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11385 {
11386 #ifndef NDEBUG
11387  SCIP* scip;
11388 #endif
11389  SCIP_CONSDATA* consdata;
11390  int minidx;
11391  int mididx;
11392  int maxidx;
11393 
11394  consdata = SCIPconsGetData((SCIP_CONS*)key);
11395  assert(consdata != NULL);
11396  assert(consdata->nvars > 0);
11397 
11398 #ifndef NDEBUG
11399  scip = (SCIP*)userptr;
11400  assert(scip != NULL);
11401 #endif
11402 
11403  /* sorts the constraints */
11404  sortItems(consdata);
11405 
11406  minidx = SCIPvarGetIndex(consdata->vars[0]);
11407  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11408  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11409  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11410 
11411  /* hash value depends on vectors of variable indices */
11412  return SCIPhashTwo(SCIPcombineFourInt(consdata->nvars, minidx, mididx, maxidx),
11413  consdata->weights[0]);
11414 }
11415 
11416 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11417  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11418  */
11419 static
11421  SCIP* scip, /**< SCIP data structure */
11422  BMS_BLKMEM* blkmem, /**< block memory */
11423  SCIP_CONS** conss, /**< constraint set */
11424  int nconss, /**< number of constraints in constraint set */
11425  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11426  int* ndelconss /**< pointer to count number of deleted constraints */
11427  )
11429  SCIP_HASHTABLE* hashtable;
11430  int hashtablesize;
11431  int c;
11432 
11433  assert(scip != NULL);
11434  assert(blkmem != NULL);
11435  assert(conss != NULL);
11436  assert(ndelconss != NULL);
11437 
11438  /* create a hash table for the constraint set */
11439  hashtablesize = nconss;
11440  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11441  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11442  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11443 
11444  /* check all constraints in the given set for redundancy */
11445  for( c = nconss - 1; c >= 0; --c )
11446  {
11447  SCIP_CONS* cons0;
11448  SCIP_CONS* cons1;
11449  SCIP_CONSDATA* consdata0;
11450 
11451  cons0 = conss[c];
11452 
11453  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11454  continue;
11455 
11456  consdata0 = SCIPconsGetData(cons0);
11457  assert(consdata0 != NULL);
11458  if( consdata0->nvars == 0 )
11459  {
11460  if( consdata0->capacity < 0 )
11461  {
11462  *cutoff = TRUE;
11463  goto TERMINATE;
11464  }
11465  else
11466  {
11467  SCIP_CALL( SCIPdelCons(scip, cons0) );
11468  ++(*ndelconss);
11469  continue;
11470  }
11471  }
11472 
11473  /* get constraint from current hash table with same variables and same weights as cons0 */
11474  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11475 
11476  if( cons1 != NULL )
11477  {
11478  SCIP_CONS* consstay;
11479  SCIP_CONS* consdel;
11480  SCIP_CONSDATA* consdata1;
11481 
11482  assert(SCIPconsIsActive(cons1));
11483  assert(!SCIPconsIsModifiable(cons1));
11484 
11485  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11486  * delete old constraints afterwards
11487  */
11488  consdata1 = SCIPconsGetData(cons1);
11489 
11490  assert(consdata1 != NULL);
11491  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11492 
11493  assert(consdata0->sorted && consdata1->sorted);
11494  assert(consdata0->vars[0] == consdata1->vars[0]);
11495  assert(consdata0->weights[0] == consdata1->weights[0]);
11496 
11497  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11498  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11499 
11500  /* check which constraint has to stay; */
11501  if( consdata0->capacity < consdata1->capacity )
11502  {
11503  consstay = cons0;
11504  consdel = cons1;
11505 
11506  /* exchange consdel with consstay in hashtable */
11507  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11508  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11509  }
11510  else
11511  {
11512  consstay = cons1;
11513  consdel = cons0;
11514  }
11515 
11516  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11517  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11518 
11519  /* delete consdel */
11520  SCIP_CALL( SCIPdelCons(scip, consdel) );
11521  ++(*ndelconss);
11522 
11523  assert(SCIPconsIsActive(consstay));
11524  }
11525  else
11526  {
11527  /* no such constraint in current hash table: insert cons0 into hash table */
11528  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11529  }
11530  }
11531 
11532  TERMINATE:
11533  /* free hash table */
11534  SCIPhashtableFree(&hashtable);
11535 
11536  return SCIP_OKAY;
11537 }
11538 
11539 
11540 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11541  * and removes or changes constraint accordingly
11542  */
11543 static
11545  SCIP* scip, /**< SCIP data structure */
11546  SCIP_CONS** conss, /**< constraint set */
11547  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11548  int chkind, /**< index of constraint to check against all prior indices upto startind */
11549  int* ndelconss /**< pointer to count number of deleted constraints */
11550  )
11551 {
11552  SCIP_CONS* cons0;
11553  SCIP_CONSDATA* consdata0;
11554  int c;
11555 
11556  assert(scip != NULL);
11557  assert(conss != NULL);
11558  assert(firstchange <= chkind);
11559  assert(ndelconss != NULL);
11560 
11561  /* get the constraint to be checked against all prior constraints */
11562  cons0 = conss[chkind];
11563  assert(cons0 != NULL);
11564  assert(SCIPconsIsActive(cons0));
11565  assert(!SCIPconsIsModifiable(cons0));
11566 
11567  consdata0 = SCIPconsGetData(cons0);
11568  assert(consdata0 != NULL);
11569  assert(consdata0->nvars >= 1);
11570  assert(consdata0->merged);
11571 
11572  /* sort the constraint */
11573  sortItems(consdata0);
11574 
11575  /* check constraint against all prior constraints */
11576  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11577  {
11578  SCIP_CONS* cons1;
11579  SCIP_CONSDATA* consdata1;
11580  SCIP_Bool iscons0incons1contained;
11581  SCIP_Bool iscons1incons0contained;
11582  SCIP_Real quotient;
11583  int v;
11584  int v0;
11585  int v1;
11586 
11587  cons1 = conss[c];
11588  assert(cons1 != NULL);
11589  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11590  continue;
11591 
11592  consdata1 = SCIPconsGetData(cons1);
11593  assert(consdata1 != NULL);
11594 
11595  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11596  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11597  continue;
11598 
11599  assert(consdata1->nvars >= 1);
11600  assert(consdata1->merged);
11601 
11602  /* sort the constraint */
11603  sortItems(consdata1);
11604 
11605  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11606 
11607  if( consdata0->nvars > consdata1->nvars )
11608  {
11609  iscons0incons1contained = FALSE;
11610  iscons1incons0contained = TRUE;
11611  v = consdata1->nvars - 1;
11612  }
11613  else if( consdata0->nvars < consdata1->nvars )
11614  {
11615  iscons0incons1contained = TRUE;
11616  iscons1incons0contained = FALSE;
11617  v = consdata0->nvars - 1;
11618  }
11619  else
11620  {
11621  iscons0incons1contained = TRUE;
11622  iscons1incons0contained = TRUE;
11623  v = consdata0->nvars - 1;
11624  }
11625 
11626  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11627 
11628  /* check consdata0 against consdata1:
11629  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11630  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11631  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11632  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11633  */
11634  v0 = consdata0->nvars - 1;
11635  v1 = consdata1->nvars - 1;
11636 
11637  while( v >= 0 )
11638  {
11639  assert(iscons0incons1contained || iscons1incons0contained);
11640 
11641  /* now there are more variables in cons1 left */
11642  if( v1 > v0 )
11643  {
11644  iscons1incons0contained = FALSE;
11645  if( !iscons0incons1contained )
11646  break;
11647  }
11648  /* now there are more variables in cons0 left */
11649  else if( v1 < v0 )
11650  {
11651  iscons0incons1contained = FALSE;
11652  if( !iscons1incons0contained )
11653  break;
11654  }
11655 
11656  assert(v == v0 || v == v1);
11657  assert(v0 >= 0);
11658  assert(v1 >= 0);
11659 
11660  /* both variables are the same */
11661  if( consdata0->vars[v0] == consdata1->vars[v1] )
11662  {
11663  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11664  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11665  {
11666  iscons1incons0contained = FALSE;
11667  if( !iscons0incons1contained )
11668  break;
11669  }
11670  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11671  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11672  {
11673  iscons0incons1contained = FALSE;
11674  if( !iscons1incons0contained )
11675  break;
11676  }
11677  --v0;
11678  --v1;
11679  --v;
11680  }
11681  else
11682  {
11683  /* both constraints have a variables which is not part of the other constraint, so stop */
11684  if( iscons0incons1contained && iscons1incons0contained )
11685  {
11686  iscons0incons1contained = FALSE;
11687  iscons1incons0contained = FALSE;
11688  break;
11689  }
11690  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11691  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11692  /* continue to the next variable */
11693  if( iscons0incons1contained )
11694  --v1;
11695  else
11696  --v0;
11697  }
11698  }
11699  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11700  * other
11701  */
11702  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11703 
11704  if( iscons1incons0contained )
11705  {
11706  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11707  SCIPdebugPrintCons(scip, cons1, NULL);
11708 
11709  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11710  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11711 
11712  SCIP_CALL( SCIPdelCons(scip, cons1) );
11713  ++(*ndelconss);
11714  }
11715  else if( iscons0incons1contained )
11716  {
11717  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11718  SCIPdebugPrintCons(scip, cons0, NULL);
11719 
11720  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11721  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11722 
11723  SCIP_CALL( SCIPdelCons(scip, cons0) );
11724  ++(*ndelconss);
11725  break;
11726  }
11727  }
11728 
11729  return SCIP_OKAY;
11730 }
11731 
11732 /** helper function to enforce constraints */
11733 static
11735  SCIP* scip, /**< SCIP data structure */
11736  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11737  SCIP_CONS** conss, /**< constraints to process */
11738  int nconss, /**< number of constraints */
11739  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11740  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11741  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11742  )
11743 {
11744  SCIP_CONSHDLRDATA* conshdlrdata;
11745  SCIP_Bool violated;
11746  SCIP_Bool cutoff = FALSE;
11747  int maxncuts;
11748  int ncuts = 0;
11749  int i;
11750 
11751  *result = SCIP_FEASIBLE;
11752 
11753  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11754  sol == NULL ? "LP" : "relaxation");
11755 
11756  /* get maximal number of cuts per round */
11757  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11758  assert(conshdlrdata != NULL);
11759  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11760 
11761  /* search for violated useful knapsack constraints */
11762  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11763  {
11764  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11765  if( violated )
11766  {
11767  /* add knapsack constraint as LP row to the relaxation */
11768  SCIP_CALL( addRelaxation(scip, conss[i], sol, &cutoff) );
11769  ncuts++;
11770  }
11771  }
11772 
11773  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11774  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11775  {
11776  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11777  if( violated )
11778  {
11779  /* add knapsack constraint as LP row to the relaxation */
11780  SCIP_CALL( addRelaxation(scip, conss[i], sol, &cutoff) );
11781  ncuts++;
11782  }
11783  }
11784 
11785  /* adjust the result code */
11786  if ( cutoff )
11787  *result = SCIP_CUTOFF;
11788  else if ( ncuts > 0 )
11789  *result = SCIP_SEPARATED;
11790 
11791  return SCIP_OKAY;
11792 }
11793 
11794 /*
11795  * Linear constraint upgrading
11796  */
11797 
11798 /** creates and captures a knapsack constraint out of a linear inequality */
11799 static
11801  SCIP* scip, /**< SCIP data structure */
11802  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11803  const char* name, /**< name of constraint */
11804  int nvars, /**< number of variables in the constraint */
11805  SCIP_VAR** vars, /**< array with variables of constraint entries */
11806  SCIP_Real* vals, /**< array with inequality coefficients */
11807  SCIP_Real lhs, /**< left hand side of inequality */
11808  SCIP_Real rhs, /**< right hand side of inequality */
11809  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11810  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11811  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11812  * Usually set to TRUE. */
11813  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11814  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11815  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11816  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11817  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11818  * Usually set to TRUE. */
11819  SCIP_Bool local, /**< is constraint only valid locally?
11820  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11821  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11822  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11823  * adds coefficients to this constraint. */
11824  SCIP_Bool dynamic, /**< is constraint subject to aging?
11825  * Usually set to FALSE. Set to TRUE for own cuts which
11826  * are separated as constraints. */
11827  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11828  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11829  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11830  * if it may be moved to a more global node?
11831  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11832  )
11833 {
11834  SCIP_VAR** transvars;
11835  SCIP_Longint* weights;
11836  SCIP_Longint capacity;
11837  SCIP_Longint weight;
11838  int mult;
11839  int v;
11840 
11841  assert(nvars == 0 || vars != NULL);
11842  assert(nvars == 0 || vals != NULL);
11843  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11844 
11845  /* get temporary memory */
11846  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11847  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11848 
11849  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11850  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11851  */
11852  if( SCIPisInfinity(scip, rhs) )
11853  {
11854  mult = -1;
11855  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11856  }
11857  else
11858  {
11859  mult = +1;
11860  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11861  }
11862 
11863  /* negate positive or negative variables */
11864  for( v = 0; v < nvars; ++v )
11865  {
11866  assert(SCIPisFeasIntegral(scip, vals[v]));
11867  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11868  if( weight > 0 )
11869  {
11870  transvars[v] = vars[v];
11871  weights[v] = weight;
11872  }
11873  else
11874  {
11875  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11876  weights[v] = -weight;
11877  capacity -= weight;
11878  }
11879  assert(transvars[v] != NULL);
11880  }
11881 
11882  /* create the constraint */
11883  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11884  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11885 
11886  /* free temporary memory */
11887  SCIPfreeBufferArray(scip, &weights);
11888  SCIPfreeBufferArray(scip, &transvars);
11889 
11890  return SCIP_OKAY;
11891 }
11892 
11893 /** tries to upgrade a linear constraint into a knapsack constraint */
11894 static
11895 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11896 { /*lint --e{715}*/
11897  SCIP_Bool upgrade;
11898 
11899  assert(upgdcons != NULL);
11900 
11901  /* check, if linear constraint can be upgraded to a knapsack constraint
11902  * - all variables must be binary
11903  * - all coefficients must be integral
11904  * - exactly one of the sides must be infinite
11905  */
11906  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11907  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11908  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11909 
11910  if( upgrade )
11911  {
11912  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11913 
11914  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11915  assert(!SCIPconsIsModifiable(cons));
11916  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11921  }
11922 
11923  return SCIP_OKAY;
11924 }
11925 
11926 
11927 /*
11928  * Callback methods of constraint handler
11929  */
11930 
11931 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11932 /**! [SnippetConsCopyKnapsack] */
11933 static
11934 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11935 { /*lint --e{715}*/
11936  assert(scip != NULL);
11937  assert(conshdlr != NULL);
11938  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11939 
11940  /* call inclusion method of constraint handler */
11943  *valid = TRUE;
11944 
11945  return SCIP_OKAY;
11946 }
11947 /**! [SnippetConsCopyKnapsack] */
11948 
11949 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11950 /**! [SnippetConsFreeKnapsack] */
11951 static
11952 SCIP_DECL_CONSFREE(consFreeKnapsack)
11953 { /*lint --e{715}*/
11954  SCIP_CONSHDLRDATA* conshdlrdata;
11955 
11956  /* free constraint handler data */
11957  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11958  assert(conshdlrdata != NULL);
11959 
11960  SCIPfreeBlockMemory(scip, &conshdlrdata);
11961 
11962  SCIPconshdlrSetData(conshdlr, NULL);
11963 
11964  return SCIP_OKAY;
11965 }
11966 /**! [SnippetConsFreeKnapsack] */
11967 
11968 
11969 /** initialization method of constraint handler (called after problem was transformed) */
11970 static
11971 SCIP_DECL_CONSINIT(consInitKnapsack)
11972 { /*lint --e{715}*/
11973  SCIP_CONSHDLRDATA* conshdlrdata;
11974  int nvars;
11975 
11976  assert( scip != NULL );
11977  assert( conshdlr != NULL );
11978 
11979  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11980  assert(conshdlrdata != NULL);
11981 
11982  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
11983  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
11984 
11985  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
11986  conshdlrdata->reals1size = nvars;
11987 
11988  return SCIP_OKAY;
11989 }
11990 
11991 /** deinitialization method of constraint handler (called before transformed problem is freed) */
11992 static
11993 SCIP_DECL_CONSEXIT(consExitKnapsack)
11994 { /*lint --e{715}*/
11995  SCIP_CONSHDLRDATA* conshdlrdata;
11996 
11997  assert( scip != NULL );
11998  assert( conshdlr != NULL );
11999 
12000  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12001  assert(conshdlrdata != NULL);
12002 
12003  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12004  conshdlrdata->reals1size = 0;
12005 
12006  return SCIP_OKAY;
12007 }
12008 
12009 
12010 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12011 static
12012 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12013 { /*lint --e{715}*/
12014  SCIP_CONSHDLRDATA* conshdlrdata;
12015  int nvars;
12016 
12017  assert(scip != NULL);
12018  assert(conshdlr != NULL);
12019  assert(nconss == 0 || conss != NULL);
12021  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12022  assert(conshdlrdata != NULL);
12023 
12024  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12025  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12026 
12027  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12028  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12029  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12030  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12031  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12032  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12033  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12034  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12035 
12036  conshdlrdata->ints1size = nvars;
12037  conshdlrdata->ints2size = nvars;
12038  conshdlrdata->longints1size = nvars;
12039  conshdlrdata->longints2size = nvars;
12040  conshdlrdata->bools1size = nvars;
12041  conshdlrdata->bools2size = nvars;
12042  conshdlrdata->bools3size = nvars;
12043  conshdlrdata->bools4size = nvars;
12044 
12045  return SCIP_OKAY;
12046 }
12047 
12048 
12049 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12050 static
12051 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12052 { /*lint --e{715}*/
12053  SCIP_CONSHDLRDATA* conshdlrdata;
12054  int c;
12055 
12056  assert(scip != NULL);
12057  assert(conshdlr != NULL);
12058 
12059  for( c = 0; c < nconss; ++c )
12060  {
12061  if( !SCIPconsIsDeleted(conss[c]) )
12062  {
12063  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12064  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12065  }
12066  }
12067 
12068  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12069  assert(conshdlrdata != NULL);
12070 
12071  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12072  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12073  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12074  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12075  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12076  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12077  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12078  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12079 
12080  conshdlrdata->ints1size = 0;
12081  conshdlrdata->ints2size = 0;
12082  conshdlrdata->longints1size = 0;
12083  conshdlrdata->longints2size = 0;
12084  conshdlrdata->bools1size = 0;
12085  conshdlrdata->bools2size = 0;
12086  conshdlrdata->bools3size = 0;
12087  conshdlrdata->bools4size = 0;
12088 
12089  return SCIP_OKAY;
12090 }
12091 
12092 
12093 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12094 static
12095 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12096 { /*lint --e{715}*/
12097  SCIP_CONSDATA* consdata;
12098  int c;
12099 
12100  assert( scip != NULL );
12101 
12102  /* release the rows of all constraints */
12103  for( c = 0; c < nconss; ++c )
12104  {
12105  consdata = SCIPconsGetData(conss[c]);
12106  assert(consdata != NULL);
12107 
12108  if( consdata->row != NULL )
12109  {
12110  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12111  }
12112  }
12113 
12114  return SCIP_OKAY;
12115 }
12116 
12117 /** frees specific constraint data */
12118 static
12119 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12120 { /*lint --e{715}*/
12121  SCIP_CONSHDLRDATA* conshdlrdata;
12122 
12123  assert(conshdlr != NULL);
12124  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12125 
12126  /* get event handler */
12127  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12128  assert(conshdlrdata != NULL);
12129  assert(conshdlrdata->eventhdlr != NULL);
12130 
12131  /* free knapsack constraint */
12132  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12133 
12134  return SCIP_OKAY;
12135 }
12136 
12137 /** transforms constraint data into data belonging to the transformed problem */
12138 /**! [SnippetConsTransKnapsack]*/
12139 static
12140 SCIP_DECL_CONSTRANS(consTransKnapsack)
12141 { /*lint --e{715}*/
12142  SCIP_CONSHDLRDATA* conshdlrdata;
12143  SCIP_CONSDATA* sourcedata;
12144  SCIP_CONSDATA* targetdata;
12145 
12146  assert(conshdlr != NULL);
12147  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12149  assert(sourcecons != NULL);
12150  assert(targetcons != NULL);
12151 
12152  sourcedata = SCIPconsGetData(sourcecons);
12153  assert(sourcedata != NULL);
12154  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12155 
12156  /* get event handler */
12157  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12158  assert(conshdlrdata != NULL);
12159  assert(conshdlrdata->eventhdlr != NULL);
12160 
12161  /* create target constraint data */
12162  SCIP_CALL( consdataCreate(scip, &targetdata,
12163  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12164 
12165  /* create target constraint */
12166  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12167  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12168  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12169  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12170  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12171 
12172  /* catch events for variables */
12173  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12174 
12175  return SCIP_OKAY;
12176 }
12177 /**! [SnippetConsTransKnapsack]*/
12178 
12179 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12180 static
12181 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12182 { /*lint --e{715}*/
12183  int i;
12184 
12185  *infeasible = FALSE;
12186 
12187  for( i = 0; i < nconss && !(*infeasible); i++ )
12188  {
12189  assert(SCIPconsIsInitial(conss[i]));
12190  SCIP_CALL( addRelaxation(scip, conss[i], NULL, infeasible) );
12191  }
12192 
12193  return SCIP_OKAY;
12194 }
12195 
12196 /** separation method of constraint handler for LP solutions */
12197 static
12198 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12199 { /*lint --e{715}*/
12200  SCIP_CONSHDLRDATA* conshdlrdata;
12201  SCIP_Bool sepacardinality;
12202  SCIP_Bool cutoff;
12203 
12204  SCIP_Real loclowerbound;
12205  SCIP_Real glblowerbound;
12206  SCIP_Real cutoffbound;
12207  SCIP_Real maxbound;
12208 
12209  int depth;
12210  int nrounds;
12211  int sepafreq;
12212  int sepacardfreq;
12213  int ncuts;
12214  int maxsepacuts;
12215  int i;
12216 
12217  *result = SCIP_DIDNOTRUN;
12218 
12219  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12220  assert(conshdlrdata != NULL);
12221 
12222  depth = SCIPgetDepth(scip);
12223  nrounds = SCIPgetNSepaRounds(scip);
12224 
12225  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12226  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12227 
12228  /* only call the separator a given number of times at each node */
12229  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12230  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12231  return SCIP_OKAY;
12232 
12233  /* check, if we should additionally separate knapsack cuts */
12234  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12235  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12236  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12237  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12238 
12239  /* check dual bound to see if we want to produce knapsack cuts at this node */
12240  loclowerbound = SCIPgetLocalLowerbound(scip);
12241  glblowerbound = SCIPgetLowerbound(scip);
12242  cutoffbound = SCIPgetCutoffbound(scip);
12243  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12244  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12245  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12246 
12247  /* get the maximal number of cuts allowed in a separation round */
12248  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12249 
12250  *result = SCIP_DIDNOTFIND;
12251  ncuts = 0;
12252  cutoff = FALSE;
12253 
12254  /* separate useful constraints */
12255  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12256  {
12257  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12258  }
12259 
12260  /* adjust return value */
12261  if ( cutoff )
12262  *result = SCIP_CUTOFF;
12263  else if ( ncuts > 0 )
12264  *result = SCIP_SEPARATED;
12265 
12266  return SCIP_OKAY;
12267 }
12268 
12269 
12270 /** separation method of constraint handler for arbitrary primal solutions */
12271 static
12272 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12273 { /*lint --e{715}*/
12274  SCIP_CONSHDLRDATA* conshdlrdata;
12275  SCIP_Bool sepacardinality;
12276  SCIP_Bool cutoff;
12277 
12278  int depth;
12279  int nrounds;
12280  int sepafreq;
12281  int sepacardfreq;
12282  int ncuts;
12283  int maxsepacuts;
12284  int i;
12285 
12286  *result = SCIP_DIDNOTRUN;
12287 
12288  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12289  assert(conshdlrdata != NULL);
12290 
12291  depth = SCIPgetDepth(scip);
12292  nrounds = SCIPgetNSepaRounds(scip);
12293 
12294  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12295  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12296 
12297  /* only call the separator a given number of times at each node */
12298  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12299  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12300  return SCIP_OKAY;
12301 
12302  /* check, if we should additionally separate knapsack cuts */
12303  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12304  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12305  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12306  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12307 
12308  /* get the maximal number of cuts allowed in a separation round */
12309  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12310 
12311  *result = SCIP_DIDNOTFIND;
12312  ncuts = 0;
12313  cutoff = FALSE;
12314 
12315  /* separate useful constraints */
12316  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12317  {
12318  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12319  }
12320 
12321  /* adjust return value */
12322  if ( cutoff )
12323  *result = SCIP_CUTOFF;
12324  else if( ncuts > 0 )
12325  *result = SCIP_SEPARATED;
12326 
12327  return SCIP_OKAY;
12328 }
12329 
12330 /** constraint enforcing method of constraint handler for LP solutions */
12331 static
12332 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12333 { /*lint --e{715}*/
12334  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12335 
12336  return SCIP_OKAY;
12337 }
12338 
12339 /** constraint enforcing method of constraint handler for relaxation solutions */
12340 static
12341 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12342 { /*lint --e{715}*/
12343  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12344 
12345  return SCIP_OKAY;
12346 }
12347 
12348 /** constraint enforcing method of constraint handler for pseudo solutions */
12349 static
12350 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12351 { /*lint --e{715}*/
12352  SCIP_Bool violated;
12353  int i;
12354 
12355  for( i = 0; i < nconss; i++ )
12356  {
12357  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12358  if( violated )
12359  {
12360  *result = SCIP_INFEASIBLE;
12361  return SCIP_OKAY;
12362  }
12363  }
12364  *result = SCIP_FEASIBLE;
12365 
12366  return SCIP_OKAY;
12367 }
12368 
12369 /** feasibility check method of constraint handler for integral solutions */
12370 static
12371 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12372 { /*lint --e{715}*/
12373  SCIP_Bool violated;
12374  int i;
12375 
12376  *result = SCIP_FEASIBLE;
12377 
12378  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12379  {
12380  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12381  if( violated )
12382  *result = SCIP_INFEASIBLE;
12383  }
12384 
12385  return SCIP_OKAY;
12386 }
12387 
12388 /** domain propagation method of constraint handler */
12389 static
12390 SCIP_DECL_CONSPROP(consPropKnapsack)
12391 { /*lint --e{715}*/
12392  SCIP_CONSHDLRDATA* conshdlrdata;
12393  SCIP_Bool cutoff;
12394  SCIP_Bool redundant;
12395  SCIP_Bool inpresolve;
12396  int nfixedvars;
12397  int i;
12399  cutoff = FALSE;
12400  nfixedvars = 0;
12401 
12402  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12403  assert(conshdlrdata != NULL);
12404 
12405  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12406  assert(!inpresolve || SCIPinProbing(scip));
12407 
12408  /* process useful constraints */
12409  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12410  {
12411  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12412  * otherwise the multi-aggregation should be resolved
12413  */
12414  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12415  continue;
12416 #ifndef NDEBUG
12417  else
12418  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12419 #endif
12420 
12421  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12422 
12423  /* unmark the constraint to be propagated */
12424  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12425 
12426  }
12427 
12428  /* adjust result code */
12429  if( cutoff )
12430  *result = SCIP_CUTOFF;
12431  else if( nfixedvars > 0 )
12432  *result = SCIP_REDUCEDDOM;
12433  else
12434  *result = SCIP_DIDNOTFIND;
12435 
12436  return SCIP_OKAY;
12437 }
12438 
12439 /** presolving method of constraint handler */
12440 static
12441 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12442 { /*lint --e{574,715}*/
12443  SCIP_CONSHDLRDATA* conshdlrdata;
12444  SCIP_CONSDATA* consdata;
12445  SCIP_CONS* cons;
12446  SCIP_Bool cutoff;
12447  SCIP_Bool redundant;
12448  SCIP_Bool success;
12449  int oldnfixedvars;
12450  int oldnchgbds;
12451  int oldndelconss;
12452  int oldnaddconss;
12453  int oldnchgcoefs;
12454  int oldnchgsides;
12455  int firstchange;
12456  int c;
12457  SCIP_Bool newchanges;
12458 
12459  /* remember old preprocessing counters */
12460  cutoff = FALSE;
12461  oldnfixedvars = *nfixedvars;
12462  oldnchgbds = *nchgbds;
12463  oldndelconss = *ndelconss;
12464  oldnaddconss = *naddconss;
12465  oldnchgcoefs = *nchgcoefs;
12466  oldnchgsides = *nchgsides;
12467  firstchange = INT_MAX;
12468 
12469  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12470 
12471  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12472  assert(conshdlrdata != NULL);
12473 
12474  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12475  {
12476  int thisnfixedvars;
12477  int thisnchgbds;
12478 
12479  cons = conss[c];
12480  consdata = SCIPconsGetData(cons);
12481  assert(consdata != NULL);
12482 
12483  /* update data structures */
12484  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12485  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12486  {
12487  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12488  if( cutoff )
12489  break;
12490  }
12491 
12492  /* force presolving the constraint in the initial round */
12493  if( nrounds == 0 )
12494  consdata->presolvedtiming = 0;
12495  else if( consdata->presolvedtiming >= presoltiming )
12496  continue;
12497 
12498  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12499  SCIPdebugPrintCons(scip, cons, NULL);
12500  consdata->presolvedtiming = presoltiming;
12501 
12502  thisnfixedvars = *nfixedvars;
12503  thisnchgbds = *nchgbds;
12504 
12505  /* merge constraint, so propagation works better */
12506  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12507  if( cutoff )
12508  break;
12509 
12510  /* add cliques in the knapsack to the clique table */
12511  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12512  {
12513  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12514  if( cutoff )
12515  break;
12516  }
12517 
12518  /* propagate constraint */
12519  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12520  {
12521  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12522 
12523  if( cutoff )
12524  break;
12525  if( redundant )
12526  {
12527  (*ndelconss)++;
12528  continue;
12529  }
12530  }
12531 
12532  /* remove again all fixed variables, if further fixings were found */
12533  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12534  {
12535  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12536  if( cutoff )
12537  break;
12538 
12539  thisnfixedvars = *nfixedvars;
12540  }
12541 
12542  if( !SCIPconsIsModifiable(cons) )
12543  {
12544  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12545  if( consdata->weightsum <= consdata->capacity )
12546  {
12547  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12548  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12549  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12550  continue;
12551  }
12552 
12553  /* divide weights by their greatest common divisor */
12554  normalizeWeights(cons, nchgcoefs, nchgsides);
12555 
12556  /* try to simplify inequalities */
12557  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12558  {
12559  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12560  if( cutoff )
12561  break;
12562 
12563  if( SCIPconsIsDeleted(cons) )
12564  continue;
12565 
12566  /* remove again all fixed variables, if further fixings were found */
12567  if( *nfixedvars > thisnfixedvars )
12568  {
12569  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12570  if( cutoff )
12571  break;
12572  }
12573  }
12574 
12575  /* tighten capacity and weights */
12576  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12577  if( cutoff )
12578  break;
12579 
12580  if( SCIPconsIsActive(cons) )
12581  {
12582  if( conshdlrdata->dualpresolving && SCIPallowDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12583  {
12584  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12585  * dual reduction
12586  */
12587  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12588  if( redundant )
12589  continue;
12590  }
12591 
12592  /* check if knapsack constraint is parallel to objective function */
12593  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12594  }
12595  }
12596  /* remember the first changed constraint to begin the next aggregation round with */
12597  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12598  firstchange = c;
12599  }
12600 
12601  /* preprocess pairs of knapsack constraints */
12602  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12603  {
12604  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12605  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12606  }
12607 
12608  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12609  success = TRUE;
12610  else
12611  success = FALSE;
12612 
12613  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12614  {
12615  SCIP_Longint npaircomparisons;
12616 
12617  npaircomparisons = 0;
12618  oldndelconss = *ndelconss;
12619  oldnchgsides = *nchgsides;
12620  oldnchgcoefs = *nchgcoefs;
12621 
12622  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12623  {
12624  cons = conss[c];
12625  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12626  continue;
12627 
12628  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12629 
12630  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12631 
12632  if( npaircomparisons > NMINCOMPARISONS )
12633  {
12634  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12635  success = TRUE;
12636  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12637  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12638  break;
12639  oldndelconss = *ndelconss;
12640  oldnchgsides = *nchgsides;
12641  oldnchgcoefs = *nchgcoefs;
12642  npaircomparisons = 0;
12643  }
12644  }
12645  }
12646 
12647  if( cutoff )
12648  *result = SCIP_CUTOFF;
12649  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12650  *result = SCIP_SUCCESS;
12651  else
12652  *result = SCIP_DIDNOTFIND;
12653 
12654  return SCIP_OKAY;
12655 }
12656 
12657 /** propagation conflict resolving method of constraint handler */
12658 static
12659 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12660 { /*lint --e{715}*/
12661  SCIP_CONSDATA* consdata;
12662  SCIP_Longint capsum;
12663  int i;
12664 
12665  assert(result != NULL);
12666 
12667  consdata = SCIPconsGetData(cons);
12668  assert(consdata != NULL);
12669 
12670  /* check if we fixed a binary variable to one (due to negated clique) */
12671  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12672  {
12673  for( i = 0; i < consdata->nvars; ++i )
12674  {
12675  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12676  {
12677  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12678  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12679  break;
12680  }
12681  }
12682  assert(i < consdata->nvars);
12683  }
12684  else
12685  {
12686  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12687  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12688  * knapsack constraint, see one above call of SCIPinferBinvarCons
12689  */
12690  if( inferinfo < 0 )
12691  capsum = 0;
12692  else
12693  {
12694  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12695  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12696  */
12697  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12698  capsum = consdata->weights[inferinfo];
12699  else
12700  {
12701  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12702  {}
12703  assert(i < consdata->nvars);
12704  capsum = consdata->weights[i];
12705  }
12706  }
12707 
12708  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12709  * the capacity
12710  */
12711  if( capsum <= consdata->capacity )
12712  {
12713  for( i = 0; i < consdata->nvars; i++ )
12714  {
12715  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12716  {
12717  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12718  capsum += consdata->weights[i];
12719  if( capsum > consdata->capacity )
12720  break;
12721  }
12722  }
12723  }
12724  }
12725 
12726  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12727  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12728  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12729  * used to fix variables to zero.
12730  *
12731  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12732  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12733  * one.
12734  */
12735  *result = SCIP_SUCCESS;
12736 
12737  return SCIP_OKAY;
12738 }
12739 
12740 /** variable rounding lock method of constraint handler */
12741 /**! [SnippetConsLockKnapsack] */
12742 static
12743 SCIP_DECL_CONSLOCK(consLockKnapsack)
12744 { /*lint --e{715}*/
12745  SCIP_CONSDATA* consdata;
12746  int i;
12747 
12748  consdata = SCIPconsGetData(cons);
12749  assert(consdata != NULL);
12750 
12751  for( i = 0; i < consdata->nvars; i++)
12752  {
12753  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[i], nlocksneg, nlockspos) );
12754  }
12755 
12756  return SCIP_OKAY;
12757 }
12758 /**! [SnippetConsLockKnapsack] */
12759 
12760 
12761 /** variable deletion method of constraint handler */
12762 static
12763 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
12764 {
12765  assert(scip != NULL);
12766  assert(conshdlr != NULL);
12767  assert(conss != NULL || nconss == 0);
12768 
12769  if( nconss > 0 )
12770  {
12771  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
12772  }
12773 
12774  return SCIP_OKAY;
12775 }
12776 
12777 /** constraint display method of constraint handler */
12778 static
12779 SCIP_DECL_CONSPRINT(consPrintKnapsack)
12780 { /*lint --e{715}*/
12781  SCIP_CONSDATA* consdata;
12782  int i;
12783 
12784  assert( scip != NULL );
12785  assert( conshdlr != NULL );
12786  assert( cons != NULL );
12788  consdata = SCIPconsGetData(cons);
12789  assert(consdata != NULL);
12790 
12791  for( i = 0; i < consdata->nvars; ++i )
12792  {
12793  if( i > 0 )
12794  SCIPinfoMessage(scip, file, " ");
12795  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
12796  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
12797  }
12798  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
12799 
12800  return SCIP_OKAY;
12801 }
12802 
12803 /** constraint copying method of constraint handler */
12804 static
12805 SCIP_DECL_CONSCOPY(consCopyKnapsack)
12806 { /*lint --e{715}*/
12807  SCIP_VAR** sourcevars;
12808  SCIP_Longint* weights;
12809  SCIP_Real* coefs;
12810  const char* consname;
12811  int nvars;
12812  int v;
12814  /* get variables and coefficients of the source constraint */
12815  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
12816  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
12817  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
12818 
12819  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
12820  for( v = 0; v < nvars; ++v )
12821  coefs[v] = (SCIP_Real) weights[v];
12822 
12823  if( name != NULL )
12824  consname = name;
12825  else
12826  consname = SCIPconsGetName(sourcecons);
12827 
12828  /* copy the logic using the linear constraint copy method */
12829  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
12830  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
12831  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
12832  assert(cons != NULL);
12833 
12834  SCIPfreeBufferArray(scip, &coefs);
12835 
12836  return SCIP_OKAY;
12837 }
12838 
12839 /** constraint parsing method of constraint handler */
12840 static
12841 SCIP_DECL_CONSPARSE(consParseKnapsack)
12842 { /*lint --e{715}*/
12843  SCIP_VAR* var;
12844  SCIP_Longint weight;
12845  SCIP_VAR** vars;
12846  SCIP_Longint* weights;
12847  SCIP_Longint capacity;
12848  char* endptr;
12849  int nread;
12850  int nvars;
12851  int varssize;
12852 
12853  assert(scip != NULL);
12854  assert(success != NULL);
12855  assert(str != NULL);
12856  assert(name != NULL);
12857  assert(cons != NULL);
12858 
12859  *success = TRUE;
12860 
12861  nvars = 0;
12862  varssize = 5;
12863  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
12864  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
12865 
12866  while( *str != '\0' )
12867  {
12868  /* try to parse coefficient, and stop if not successful (probably reached <=) */
12869  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
12870  break;
12871 
12872  str += nread;
12873 
12874  /* skip whitespace */
12875  while( isspace((int)*str) )
12876  ++str;
12877 
12878  /* parse variable name */
12879  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
12880  if( var == NULL )
12881  {
12882  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
12883  *success = FALSE;
12884  break;
12885  }
12886 
12887  str = endptr;
12888 
12889  /* store weight and variable */
12890  if( varssize <= nvars )
12891  {
12892  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
12893  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
12894  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
12895  }
12896 
12897  vars[nvars] = var;
12898  weights[nvars] = weight;
12899  ++nvars;
12900 
12901  /* skip whitespace */
12902  while( isspace((int)*str) )
12903  ++str;
12904  }
12905 
12906  if( *success )
12907  {
12908  if( strncmp(str, "<= ", 3) != 0 )
12909  {
12910  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
12911  *success = FALSE;
12912  }
12913  else
12914  {
12915  str += 3;
12916  }
12917  }
12918 
12919  if( *success )
12920  {
12921  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
12922  {
12923  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
12924  *success = FALSE;
12925  }
12926  else
12927  {
12928  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
12929  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
12930  }
12931  }
12932 
12933  SCIPfreeBufferArray(scip, &vars);
12934  SCIPfreeBufferArray(scip, &weights);
12935 
12936  return SCIP_OKAY;
12937 }
12938 
12939 /** constraint method of constraint handler which returns the variables (if possible) */
12940 static
12941 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
12942 { /*lint --e{715}*/
12943  SCIP_CONSDATA* consdata;
12944 
12945  consdata = SCIPconsGetData(cons);
12946  assert(consdata != NULL);
12947 
12948  if( varssize < consdata->nvars )
12949  (*success) = FALSE;
12950  else
12951  {
12952  assert(vars != NULL);
12953 
12954  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
12955  (*success) = TRUE;
12956  }
12957 
12958  return SCIP_OKAY;
12959 }
12960 
12961 /** constraint method of constraint handler which returns the number of variables (if possible) */
12962 static
12963 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
12964 { /*lint --e{715}*/
12965  SCIP_CONSDATA* consdata;
12966 
12967  consdata = SCIPconsGetData(cons);
12968  assert(consdata != NULL);
12969 
12970  (*nvars) = consdata->nvars;
12971  (*success) = TRUE;
12972 
12973  return SCIP_OKAY;
12974 }
12975 
12976 /*
12977  * Event handler
12978  */
12979 
12980 /** execution method of bound change event handler */
12981 static
12982 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
12983 { /*lint --e{715}*/
12984  SCIP_CONSDATA* consdata;
12985 
12986  assert(eventdata != NULL);
12987  assert(eventdata->cons != NULL);
12988 
12989  consdata = SCIPconsGetData(eventdata->cons);
12990  assert(consdata != NULL);
12991 
12992  switch( SCIPeventGetType(event) )
12993  {
12995  consdata->onesweightsum += eventdata->weight;
12996  consdata->presolvedtiming = 0;
12997  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
12998  break;
13000  consdata->onesweightsum -= eventdata->weight;
13001  break;
13003  consdata->presolvedtiming = 0;
13004  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13005  break;
13006  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13007  if( !consdata->existmultaggr )
13008  {
13009  SCIP_VAR* var;
13010  var = SCIPeventGetVar(event);
13011  assert(var != NULL);
13012 
13013  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13015  {
13016  consdata->existmultaggr = TRUE;
13017  consdata->merged = FALSE;
13018  }
13019  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED )
13020  consdata->merged = FALSE;
13021 
13022  }
13023  /*lint -fallthrough*/
13024  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13025  consdata->presolvedtiming = 0;
13026  break;
13028  consdata->varsdeleted = TRUE;
13029  break;
13030  default:
13031  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
13032  return SCIP_INVALIDDATA;
13033  }
13034 
13035  return SCIP_OKAY;
13036 }
13037 
13038 
13039 /*
13040  * constraint specific interface methods
13041  */
13042 
13043 /** creates the handler for knapsack constraints and includes it in SCIP */
13045  SCIP* scip /**< SCIP data structure */
13046  )
13047 {
13048  SCIP_EVENTHDLRDATA* eventhdlrdata;
13049  SCIP_CONSHDLRDATA* conshdlrdata;
13050  SCIP_CONSHDLR* conshdlr;
13051 
13052  /* create knapsack constraint handler data */
13053  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13054 
13055  /* include event handler for bound change events */
13056  eventhdlrdata = NULL;
13057  conshdlrdata->eventhdlr = NULL;
13058  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13059  eventExecKnapsack, eventhdlrdata) );
13060 
13061  /* get event handler for bound change events */
13062  if( conshdlrdata->eventhdlr == NULL )
13063  {
13064  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13065  return SCIP_PLUGINNOTFOUND;
13066  }
13067 
13068  /* include constraint handler */
13071  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13072  conshdlrdata) );
13073 
13074  assert(conshdlr != NULL);
13075 
13076  /* set non-fundamental callbacks via specific setter functions */
13077  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13078  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13079  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13080  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13081  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13082  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13083  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13084  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13085  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13086  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13087  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13088  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13089  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13090  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13091  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13092  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13094  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13095  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13097  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13098  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13099 
13100  if( SCIPfindConshdlr(scip,"linear") != NULL )
13101  {
13102  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13104  }
13105 
13106  /* add knapsack constraint handler parameters */
13107  SCIP_CALL( SCIPaddIntParam(scip,
13108  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13109  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13110  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13112  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13113  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13114  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13116  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13117  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13118  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13119  SCIP_CALL( SCIPaddIntParam(scip,
13120  "constraints/" CONSHDLR_NAME "/maxrounds",
13121  "maximal number of separation rounds per node (-1: unlimited)",
13122  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13123  SCIP_CALL( SCIPaddIntParam(scip,
13124  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13125  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13126  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13127  SCIP_CALL( SCIPaddIntParam(scip,
13128  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13129  "maximal number of cuts separated per separation round",
13130  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13131  SCIP_CALL( SCIPaddIntParam(scip,
13132  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13133  "maximal number of cuts separated per separation round in the root node",
13134  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13136  "constraints/" CONSHDLR_NAME "/disaggregation",
13137  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13138  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13140  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13141  "should presolving try to simplify knapsacks",
13142  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13144  "constraints/" CONSHDLR_NAME "/negatedclique",
13145  "should negated clique information be used in solving process",
13146  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13148  "constraints/" CONSHDLR_NAME "/presolpairwise",
13149  "should pairwise constraint comparison be performed in presolving?",
13150  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13152  "constraints/" CONSHDLR_NAME "/presolusehashing",
13153  "should hash table be used for detecting redundant constraints in advance",
13154  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13156  "constraints/" CONSHDLR_NAME "/dualpresolving",
13157  "should dual presolving steps be performed?",
13158  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13160  "constraints/" CONSHDLR_NAME "/usegubs",
13161  "should GUB information be used for separation?",
13162  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13164  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13165  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13166  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13168  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13169  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13170  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13172  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13173  "should clique partition information be updated when old partition seems outdated?",
13174  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13176  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13177  "factor on the growth of global cliques to decide when to update a previous "
13178  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13179  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13180 
13181  return SCIP_OKAY;
13182 }
13183 
13184 /** creates and captures a knapsack constraint
13185  *
13186  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13187  */
13188 /**! [SnippetConsCreationKnapsack] */
13190  SCIP* scip, /**< SCIP data structure */
13191  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13192  const char* name, /**< name of constraint */
13193  int nvars, /**< number of items in the knapsack */
13194  SCIP_VAR** vars, /**< array with item variables */
13195  SCIP_Longint* weights, /**< array with item weights */
13196  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13197  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13198  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13199  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13200  * Usually set to TRUE. */
13201  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13202  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13203  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13204  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13205  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13206  * Usually set to TRUE. */
13207  SCIP_Bool local, /**< is constraint only valid locally?
13208  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13209  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13210  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13211  * adds coefficients to this constraint. */
13212  SCIP_Bool dynamic, /**< is constraint subject to aging?
13213  * Usually set to FALSE. Set to TRUE for own cuts which
13214  * are separated as constraints. */
13215  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13216  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13217  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13218  * if it may be moved to a more global node?
13219  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13220  )
13221 {
13222  SCIP_CONSHDLRDATA* conshdlrdata;
13223  SCIP_CONSHDLR* conshdlr;
13224  SCIP_CONSDATA* consdata;
13225 
13226  /* find the knapsack constraint handler */
13227  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13228  if( conshdlr == NULL )
13229  {
13230  SCIPerrorMessage("knapsack constraint handler not found\n");
13231  return SCIP_PLUGINNOTFOUND;
13232  }
13233 
13234  /* get event handler */
13235  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13236  assert(conshdlrdata != NULL);
13237  assert(conshdlrdata->eventhdlr != NULL);
13238 
13239  /* create constraint data */
13240  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13241 
13242  /* create constraint */
13243  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13244  local, modifiable, dynamic, removable, stickingatnode) );
13245 
13246  /* catch events for variables */
13247  if( SCIPisTransformed(scip) )
13248  {
13249  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13250  }
13251 
13252  return SCIP_OKAY;
13253 }
13254 /**! [SnippetConsCreationKnapsack] */
13255 
13256 /** creates and captures a knapsack constraint
13257  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13258  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13259  *
13260  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13261  *
13262  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13263  */
13265  SCIP* scip, /**< SCIP data structure */
13266  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13267  const char* name, /**< name of constraint */
13268  int nvars, /**< number of items in the knapsack */
13269  SCIP_VAR** vars, /**< array with item variables */
13270  SCIP_Longint* weights, /**< array with item weights */
13271  SCIP_Longint capacity /**< capacity of knapsack */
13272  )
13273 {
13274  assert(scip != NULL);
13275 
13276  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13277  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13278 
13279  return SCIP_OKAY;
13280 }
13281 
13282 /** adds new item to knapsack constraint */
13284  SCIP* scip, /**< SCIP data structure */
13285  SCIP_CONS* cons, /**< constraint data */
13286  SCIP_VAR* var, /**< item variable */
13287  SCIP_Longint weight /**< item weight */
13288  )
13289 {
13290  assert(var != NULL);
13292  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13293  {
13294  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13295  return SCIP_INVALIDDATA;
13296  }
13297 
13298  SCIP_CALL( addCoef(scip, cons, var, weight) );
13299 
13300  return SCIP_OKAY;
13301 }
13302 
13303 /** gets the capacity of the knapsack constraint */
13305  SCIP* scip, /**< SCIP data structure */
13306  SCIP_CONS* cons /**< constraint data */
13307  )
13308 {
13309  SCIP_CONSDATA* consdata;
13310 
13311  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13312  {
13313  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13314  SCIPABORT();
13315  return 0; /*lint !e527*/
13316  }
13317 
13318  consdata = SCIPconsGetData(cons);
13319  assert(consdata != NULL);
13320 
13321  return consdata->capacity;
13322 }
13323 
13324 /** changes capacity of the knapsack constraint
13325  *
13326  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13327  */
13329  SCIP* scip, /**< SCIP data structure */
13330  SCIP_CONS* cons, /**< constraint data */
13331  SCIP_Longint capacity /**< new capacity of knapsack */
13332  )
13333 {
13334  SCIP_CONSDATA* consdata;
13335 
13337  {
13338  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13339  return SCIP_INVALIDDATA;
13340  }
13341 
13342  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13343  {
13344  SCIPerrorMessage("method can only be called during problem creation stage\n");
13345  return SCIP_INVALIDDATA;
13346  }
13347 
13348  consdata = SCIPconsGetData(cons);
13349  assert(consdata != NULL);
13350 
13351  consdata->capacity = capacity;
13352 
13353  return SCIP_OKAY;
13354 }
13355 
13356 /** gets the number of items in the knapsack constraint */
13358  SCIP* scip, /**< SCIP data structure */
13359  SCIP_CONS* cons /**< constraint data */
13360  )
13361 {
13362  SCIP_CONSDATA* consdata;
13363 
13364  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13365  {
13366  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13367  SCIPABORT();
13368  return -1; /*lint !e527*/
13369  }
13370 
13371  consdata = SCIPconsGetData(cons);
13372  assert(consdata != NULL);
13373 
13374  return consdata->nvars;
13375 }
13376 
13377 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13379  SCIP* scip, /**< SCIP data structure */
13380  SCIP_CONS* cons /**< constraint data */
13381  )
13382 {
13383  SCIP_CONSDATA* consdata;
13384 
13385  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13386  {
13387  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13388  SCIPABORT();
13389  return NULL; /*lint !e527*/
13390  }
13391 
13392  consdata = SCIPconsGetData(cons);
13393  assert(consdata != NULL);
13394 
13395  return consdata->vars;
13396 }
13397 
13398 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13400  SCIP* scip, /**< SCIP data structure */
13401  SCIP_CONS* cons /**< constraint data */
13402  )
13403 {
13404  SCIP_CONSDATA* consdata;
13405 
13406  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13407  {
13408  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13409  SCIPABORT();
13410  return NULL; /*lint !e527*/
13411  }
13412 
13413  consdata = SCIPconsGetData(cons);
13414  assert(consdata != NULL);
13415 
13416  return consdata->weights;
13417 }
13418 
13419 /** gets the dual solution of the knapsack constraint in the current LP */
13421  SCIP* scip, /**< SCIP data structure */
13422  SCIP_CONS* cons /**< constraint data */
13423  )
13424 {
13425  SCIP_CONSDATA* consdata;
13426 
13427  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13428  {
13429  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13430  SCIPABORT();
13431  return SCIP_INVALID; /*lint !e527*/
13432  }
13433 
13434  consdata = SCIPconsGetData(cons);
13435  assert(consdata != NULL);
13436 
13437  if( consdata->row != NULL )
13438  return SCIProwGetDualsol(consdata->row);
13439  else
13440  return 0.0;
13441 }
13442 
13443 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13445  SCIP* scip, /**< SCIP data structure */
13446  SCIP_CONS* cons /**< constraint data */
13447  )
13448 {
13449  SCIP_CONSDATA* consdata;
13450 
13451  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13452  {
13453  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13454  SCIPABORT();
13455  return SCIP_INVALID; /*lint !e527*/
13456  }
13457 
13458  consdata = SCIPconsGetData(cons);
13459  assert(consdata != NULL);
13460 
13461  if( consdata->row != NULL )
13462  return SCIProwGetDualfarkas(consdata->row);
13463  else
13464  return 0.0;
13465 }
13466 
13467 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13468  * the user must not modify the row!
13469  */
13471  SCIP* scip, /**< SCIP data structure */
13472  SCIP_CONS* cons /**< constraint data */
13473  )
13474 {
13475  SCIP_CONSDATA* consdata;
13476 
13477  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13478  {
13479  SCIPerrorMessage("constraint is not a knapsack\n");
13480  SCIPABORT();
13481  return NULL; /*lint !e527*/
13482  }
13483 
13484  consdata = SCIPconsGetData(cons);
13485  assert(consdata != NULL);
13486 
13487  return consdata->row;
13488 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define KNAPSACKRELAX_MAXSCALE
Definition: cons_knapsack.c:72
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21909
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int * gubconssidx
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4143
#define DEFAULT_DETECTCUTOFFBOUND
Definition: cons_knapsack.c:98
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:27934
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:21898
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18829
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6228
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:40508
static SCIP_RETCODE GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
GUBVarstatus
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17380
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_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:10785
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3305
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21892
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
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 SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22118
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30233
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19263
#define CONSHDLR_DESC
Definition: cons_knapsack.c:40
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46086
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:55
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:814
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8140
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16958
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6251
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip.c:18733
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
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:30080
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46099
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19123
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2254
static SCIP_DECL_CONSINIT(consInitKnapsack)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40275
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6541
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:42499
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30256
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17358
#define DEFAULT_CLQPARTUPDATEFAC
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_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17166
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6481
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)
GUBCONSSTATUS * gubconsstatus
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:11616
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
Definition: scip.c:42527
#define SCIP_MAXSTRLEN
Definition: def.h:215
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:42
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_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:5973
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21896
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:27962
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12481
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:45601
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16946
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30288
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip.c:27521
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:45876
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip.c:18696
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17222
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:26950
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45803
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17529
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:65
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8526
#define DEFAULT_CLIQUEEXTRACTFACTOR
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
SCIP_GUBCONS ** gubconss
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip.c:27674
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:17656
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18384
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16732
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:138
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip.c:6142
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)
#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_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46138
#define FALSE
Definition: def.h:64
#define MAX_CLIQUELENGTH
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:5831
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:49
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:45816
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:9340
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:45888
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:632
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_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28192
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)
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip.c:13222
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:46
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21255
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8160
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17400
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)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16859
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:779
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4769
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8190
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip.c:26717
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22234
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21907
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:57
#define SCIPdebugMessage
Definition: pub_message.h:77
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:5885
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17370
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:21933
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4999
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45751
#define SCIP_LONGINT_MAX
Definition: def.h:121
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:21937
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21890
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:1010
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip.c:36161
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip.c:6412
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8150
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6274
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:16331
#define SCIPdebugMsgPrint
Definition: scip.h:452
#define SCIPdebugMsg
Definition: scip.h:451
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:4202
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:18616
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:54
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6458
#define DEFAULT_PRESOLUSEHASHING
Definition: cons_knapsack.c:89
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7942
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17518
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1336
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11811
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:27146
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:45246
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
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:2015
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:46211
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:16982
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:16522
#define DEFAULT_SEPACARDFREQ
Definition: cons_knapsack.c:74
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:64
static SCIP_RETCODE GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:26695
static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
static SCIP_DECL_CONSPARSE(consParseKnapsack)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip.c:27446
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip.c:23815
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:75
#define DEFAULT_DISAGGREGATION
Definition: cons_knapsack.c:82
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17176
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11524
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:21904
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define CONSHDLR_SEPAPRIORITY
Definition: cons_knapsack.c:41
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip.c:33761
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
Constraint handler for knapsack constraints of the form , x binary and .
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5997
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
enum GUBVarstatus GUBVARSTATUS
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
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4113
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12410
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45764
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13111
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:38044
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
#define DEFAULT_PRESOLPAIRWISE
Definition: cons_knapsack.c:92
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
#define SCIPallocBuffer(scip, ptr)
Definition: scip.h:21923
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)
#define DEFAULT_DUALPRESOLVING
Definition: cons_knapsack.c:97
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip.c:33779
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:45519
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21383
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7881
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17432
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8100
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:71
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16552
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6022
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28164
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:159
#define DEFAULT_NEGATEDCLIQUE
Definition: cons_knapsack.c:84
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)
#define SCIP_CALL(x)
Definition: def.h:306
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:471
SCIP_Real SCIPgetLowerbound(SCIP *scip)
Definition: scip.c:42323
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17390
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46125
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16970
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2384
GUBVARSTATUS * gubvarsstatus
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46112
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition: scip.c:27097
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1353
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17422
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8120
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *cutoff)
#define KNAPSACKRELAX_MAXDNOM
Definition: cons_knapsack.c:71
#define DEFAULT_MAXSEPACUTSROOT
Definition: cons_knapsack.c:78
static SCIP_DECL_CONSFREE(consFreeKnapsack)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:6297
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:33869
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
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_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
void SCIPsortDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, int len)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:45839
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
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:9034
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21925
public data structures and miscellaneous methods
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
#define SCIP_Bool
Definition: def.h:61
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
#define MINGAINPERNMINCOMPARISONS
Definition: cons_knapsack.c:94
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_DECL_CONSPROP(consPropKnapsack)
#define MAXABSVBCOEF
Definition: cons_knapsack.c:86
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)
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:50
#define DEFAULT_MAXSEPACUTS
Definition: cons_knapsack.c:77
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:30022
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
#define DEFAULT_MAXCARDBOUNDDIST
Definition: cons_knapsack.c:79
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:42094
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:28652
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
#define MAX(x, y)
Definition: tclique_def.h:75
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip.c:24152
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7901
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11249
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3317
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:30051
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8010
#define DEFAULT_USEGUBS
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
#define KNAPSACKRELAX_MAXDELTA
Definition: cons_knapsack.c:70
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8080
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8050
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17014
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:68
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40321
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:58
#define CONSHDLR_NAME
Definition: cons_knapsack.c:39
#define SCIPcombineFourInt(a, b, c, d)
Definition: pub_misc.h:481
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:25141
#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 SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:16344
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21309
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6435
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
Constraint handler for linear constraints in their most general form, .
int SCIPgetNObjVars(SCIP *scip)
Definition: scip.c:11859
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2315
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16934
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:45827
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)
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)
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define SCIP_MAXTREEDEPTH
Definition: def.h:242
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35033
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2065
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11631
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip.c:13333
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6166
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_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30160
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
#define SCIPfreeBuffer(scip, ptr)
Definition: scip.h:21935
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
static SCIP_DECL_CONSLOCK(consLockKnapsack)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45790
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:45900
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7911
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6046
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:27471
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6070
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip.c:1861
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27323
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip.c:25447
#define DEFAULT_DETECTLOWERBOUND
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6190
#define HASHSIZE_KNAPSACKCONS
Definition: cons_knapsack.c:90
enum GUBConsstatus GUBCONSSTATUS
int SCIPgetNCliques(SCIP *scip)
Definition: scip.c:24472
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:67
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46163
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:11586
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16671
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip.c:24372
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18350
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:135
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8130
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1138
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11584
#define MIN(x, y)
Definition: memory.c:75
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6504
#define GUBCONSGROWVALUE
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8070
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
#define EVENTTYPE_KNAPSACK
Definition: cons_knapsack.c:59
#define SCIP_INVALID
Definition: def.h:155
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8060
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:30762
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17412
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
Definition: cons_knapsack.c:76
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:45
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:52
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
Definition: scip.c:45330
#define SCIP_Longint
Definition: def.h:120
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:8237
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16849
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_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:45864
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45777
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
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17232
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:21910
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3295
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:46187
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16694
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 lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
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:87
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
#define NMINCOMPARISONS
Definition: cons_knapsack.c:93
static SCIP_DECL_CONSTRANS(consTransKnapsack)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6118
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:278
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip.c:17353
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7945
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38007
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:16773
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)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
#define DEFAULT_UPDATECLIQUEPARTITIONS
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:4258
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:22634
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:45937
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:43
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:57
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip.c:18663
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 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:4176
int SCIPgetNSepaRounds(SCIP *scip)
Definition: scip.c:41933
#define DEFAULT_SIMPLIFYINEQUALITIES
Definition: cons_knapsack.c:83
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16839
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:16707
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:21929
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5931
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:27421
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)