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-2018 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  * @author Tobias Fischer
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #include <assert.h>
28 #include <string.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 
33 #include "scip/cons_knapsack.h"
34 #include "scip/cons_linear.h"
35 #include "scip/cons_logicor.h"
36 #include "scip/cons_setppc.h"
37 #include "scip/pub_misc.h"
38 
39 #ifdef WITH_CARDINALITY_UPGRADE
40 #include "scip/cons_cardinality.h"
41 #endif
42 
43 /* constraint handler properties */
44 #define CONSHDLR_NAME "knapsack"
45 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
46 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
47 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
48 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
49 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
50 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
51 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
52  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
53 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
54 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
55 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
56 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
57 
58 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
59 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
60 
61 #define EVENTHDLR_NAME "knapsack"
62 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
63 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
64  | SCIP_EVENTTYPE_UBTIGHTENED \
65  | SCIP_EVENTTYPE_VARFIXED \
66  | SCIP_EVENTTYPE_VARDELETED \
67  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
68 
69 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
70 
71 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
72 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
73 
74 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
75 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
76 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
77 
78 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
79 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
80 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
81 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
82 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
83 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
84  * to best node's dual bound for separating knapsack cuts */
85 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
86 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
87 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
88 
89 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
90 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
91 
92 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
93 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
94 
95 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
96 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
97 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
98  * comparison round */
99 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
100 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
101  * function defining an upper bound and prevent these constraints from
102  * entering the LP */
103 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
104  * function defining a lower bound and prevent these constraints from
105  * entering the LP */
106 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
107 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
109 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
110 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
111 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
112 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
113  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
114 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
115 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
116 #ifdef WITH_CARDINALITY_UPGRADE
117 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
118 #endif
120 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
121 
122 /*
123  * Data structures
124  */
125 
126 /** constraint handler data */
127 struct SCIP_ConshdlrData
128 {
129  int* ints1; /**< 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  int* ints2; /**< 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_Longint* longints1; /**< 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_Longint* longints2; /**< 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* bools1; /**< 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_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
140  * you have to clear it at the end, exists only in presolving stage */
141  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
142  * you have to clear it at the end, exists only in presolving stage */
143  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
144  * you have to clear it at the end, exists only in presolving stage */
145  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
146  * you have to clear it at the end */
147  int ints1size; /**< size of ints1 array */
148  int ints2size; /**< size of ints2 array */
149  int longints1size; /**< size of longints1 array */
150  int longints2size; /**< size of longints2 array */
151  int bools1size; /**< size of bools1 array */
152  int bools2size; /**< size of bools2 array */
153  int bools3size; /**< size of bools3 array */
154  int bools4size; /**< size of bools4 array */
155  int reals1size; /**< size of reals1 array */
156  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
157  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
158  * to best node's dual bound for separating knapsack cuts */
159  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
160  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
161  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
162  int maxsepacuts; /**< maximal number of cuts separated per separation round */
163  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
164  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
165  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
166  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
167  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
168  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
169  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
170  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
171  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
172  * function defining an upper bound and prevent these constraints from
173  * entering the LP */
174  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
175  * function defining a lower bound and prevent these constraints from
176  * entering the LP */
177  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
178  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
179  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
180  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
181 #ifdef WITH_CARDINALITY_UPGRADE
182  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
183  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
184 #endif
185 };
186 
187 
188 /** constraint data for knapsack constraints */
189 struct SCIP_ConsData
190 {
191  SCIP_VAR** vars; /**< variables in knapsack constraint */
192  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
193  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
194  int* cliquepartition; /**< clique indices of the clique partition */
195  int* negcliquepartition; /**< clique indices of the negated clique partition */
196  SCIP_ROW* row; /**< corresponding LP row */
197  int nvars; /**< number of variables in knapsack constraint */
198  int varssize; /**< size of vars, weights, and eventdata arrays */
199  int ncliques; /**< number of cliques in the clique partition */
200  int nnegcliques; /**< number of cliques in the negated clique partition */
201  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
202  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
203  SCIP_Longint capacity; /**< capacity of knapsack */
204  SCIP_Longint weightsum; /**< sum of all weights */
205  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
206  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
207  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
208  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
209  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
210  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
211  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
212  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
213  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
214 };
215 
216 /** event data for bound changes events */
217 struct SCIP_EventData
218 {
219  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
220  SCIP_Longint weight; /**< weight of variable */
221  int filterpos; /**< position of event in variable's event filter */
222 };
223 
224 
225 /** data structure to combine two sorting key values */
226 struct sortkeypair
227 {
228  SCIP_Real key1; /**< first sort key value */
229  SCIP_Real key2; /**< second sort key value */
230 };
231 typedef struct sortkeypair SORTKEYPAIR;
232 
233 /** status of GUB constraint */
234 enum GUBVarstatus
235 {
236  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
237  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
238  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
239  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
240  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
241  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
242 };
243 typedef enum GUBVarstatus GUBVARSTATUS;
245 /** status of variable in GUB constraint */
247 {
248  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
249  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
250  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
251  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
252  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
253  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
254 };
255 typedef enum GUBConsstatus GUBCONSSTATUS;
257 /** data structure of GUB constraints */
259 {
260  int* gubvars; /**< indices of GUB variables in knapsack constraint */
261  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
262  int ngubvars; /**< number of GUB variables */
263  int gubvarssize; /**< size of gubvars array */
264 };
265 typedef struct SCIP_GUBCons SCIP_GUBCONS;
267 /** data structure of a set of GUB constraints */
269 {
270  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
271  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
272  int ngubconss; /**< number of GUB constraints */
273  int nvars; /**< number of variables in knapsack constraint */
274  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
275  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
276 };
277 typedef struct SCIP_GUBSet SCIP_GUBSET;
279 /*
280  * Local methods
281  */
283 /** comparison method for two sorting key pairs */
284 static
285 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
286 {
287  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
288  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
289 
290  if( sortkeypair1->key1 < sortkeypair2->key1 )
291  return -1;
292  else if( sortkeypair1->key1 > sortkeypair2->key1 )
293  return +1;
294  else if( sortkeypair1->key2 < sortkeypair2->key2 )
295  return -1;
296  else if( sortkeypair1->key2 > sortkeypair2->key2 )
297  return +1;
298  else
299  return 0;
300 }
301 
302 /** creates event data */
303 static
305  SCIP* scip, /**< SCIP data structure */
306  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
307  SCIP_CONS* cons, /**< constraint */
308  SCIP_Longint weight /**< weight of variable */
309  )
310 {
311  assert(eventdata != NULL);
313  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
314  (*eventdata)->cons = cons;
315  (*eventdata)->weight = weight;
316 
317  return SCIP_OKAY;
318 }
319 
320 /** frees event data */
321 static
323  SCIP* scip, /**< SCIP data structure */
324  SCIP_EVENTDATA** eventdata /**< pointer to event data */
325  )
326 {
327  assert(eventdata != NULL);
328 
329  SCIPfreeBlockMemory(scip, eventdata);
331  return SCIP_OKAY;
332 }
333 
334 /** sorts items in knapsack with nonincreasing weights */
335 static
336 void sortItems(
337  SCIP_CONSDATA* consdata /**< constraint data */
338  )
339 {
340  assert(consdata != NULL);
341  assert(consdata->nvars == 0 || consdata->vars != NULL);
342  assert(consdata->nvars == 0 || consdata->weights != NULL);
343  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
344  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
345 
346  if( !consdata->sorted )
347  {
348  int pos;
349  int lastcliquenum;
350  int v;
351 
352  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
353  * sorted by first array in non-increasing order via sort template */
355  consdata->weights,
356  (void**)consdata->vars,
357  (void**)consdata->eventdata,
358  consdata->cliquepartition,
359  consdata->negcliquepartition,
360  consdata->nvars);
361 
362  v = consdata->nvars - 1;
363  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
364  while( v >= 0 )
365  {
366  int w = v - 1;
367 
368  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
369  --w;
370 
371  if( v - w > 1 )
372  {
373  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
375  (void**)(&(consdata->vars[w+1])),
376  (void**)(&(consdata->eventdata[w+1])),
377  &(consdata->cliquepartition[w+1]),
378  &(consdata->negcliquepartition[w+1]),
379  SCIPvarComp,
380  v - w);
381  }
382  v = w;
383  }
384 
385  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
386  if( consdata->cliquepartitioned )
387  {
388  lastcliquenum = 0;
389 
390  for( pos = 0; pos < consdata->nvars; ++pos )
391  {
392  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
393  * partition is invalid */
394  if( consdata->cliquepartition[pos] > lastcliquenum )
395  {
396  consdata->cliquepartitioned = FALSE;
397  break;
398  }
399  else if( consdata->cliquepartition[pos] == lastcliquenum )
400  ++lastcliquenum;
401  }
402  }
403  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
404  if( consdata->negcliquepartitioned )
405  {
406  lastcliquenum = 0;
407 
408  for( pos = 0; pos < consdata->nvars; ++pos )
409  {
410  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
411  * partition is invalid */
412  if( consdata->negcliquepartition[pos] > lastcliquenum )
413  {
414  consdata->negcliquepartitioned = FALSE;
415  break;
416  }
417  else if( consdata->negcliquepartition[pos] == lastcliquenum )
418  ++lastcliquenum;
419  }
420  }
421 
422  consdata->sorted = TRUE;
423  }
424 #ifndef NDEBUG
425  {
426  /* check if the weight array is sorted in a non-increasing way */
427  int i;
428  for( i = 0; i < consdata->nvars-1; ++i )
429  assert(consdata->weights[i] >= consdata->weights[i+1]);
430  }
431 #endif
432 }
433 
434 /** calculates a partition of the variables into cliques */
435 static
437  SCIP* scip, /**< SCIP data structure */
438  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
439  SCIP_CONSDATA* consdata, /**< constraint data */
440  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
441  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
442  )
443 {
444  SCIP_Bool ispartitionoutdated;
445  SCIP_Bool isnegpartitionoutdated;
446  assert(consdata != NULL);
447  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
448 
449  /* rerun eventually if number of global cliques increased considerably since last partition */
450  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
451  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
452 
453  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
454  {
455  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
456  consdata->cliquepartitioned = TRUE;
457  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
458  }
459 
460  /* rerun eventually if number of global cliques increased considerably since last negated partition */
461  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
462  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
463 
464  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
465  {
466  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
467  consdata->negcliquepartitioned = TRUE;
468  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
469  }
470  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
471  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
472 
473  return SCIP_OKAY;
474 }
475 
476 /** installs rounding locks for the given variable in the given knapsack constraint */
477 static
479  SCIP* scip, /**< SCIP data structure */
480  SCIP_CONS* cons, /**< knapsack constraint */
481  SCIP_VAR* var /**< variable of constraint entry */
482  )
483 {
484  /* rounding up may violate the constraint */
485  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
487  return SCIP_OKAY;
488 }
489 
490 /** removes rounding locks for the given variable in the given knapsack constraint */
491 static
493  SCIP* scip, /**< SCIP data structure */
494  SCIP_CONS* cons, /**< knapsack constraint */
495  SCIP_VAR* var /**< variable of constraint entry */
496  )
497 {
498  /* rounding up may violate the constraint */
499  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
501  return SCIP_OKAY;
502 }
503 
504 /** catches bound change events for variables in knapsack */
505 static
507  SCIP* scip, /**< SCIP data structure */
508  SCIP_CONS* cons, /**< constraint */
509  SCIP_CONSDATA* consdata, /**< constraint data */
510  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
511  )
512 {
513  int i;
515  assert(cons != NULL);
516  assert(consdata != NULL);
517  assert(consdata->nvars == 0 || consdata->vars != NULL);
518  assert(consdata->nvars == 0 || consdata->weights != NULL);
519  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
520 
521  for( i = 0; i < consdata->nvars; i++)
522  {
523  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
524  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
525  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
526  }
527 
528  return SCIP_OKAY;
529 }
530 
531 /** drops bound change events for variables in knapsack */
532 static
534  SCIP* scip, /**< SCIP data structure */
535  SCIP_CONSDATA* consdata, /**< constraint data */
536  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
537  )
538 {
539  int i;
540 
541  assert(consdata != NULL);
542  assert(consdata->nvars == 0 || consdata->vars != NULL);
543  assert(consdata->nvars == 0 || consdata->weights != NULL);
544  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
545 
546  for( i = 0; i < consdata->nvars; i++)
547  {
548  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
549  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
550  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
551  }
552 
553  return SCIP_OKAY;
554 }
555 
556 /** ensures, that vars and vals arrays can store at least num entries */
557 static
559  SCIP* scip, /**< SCIP data structure */
560  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
561  int num, /**< minimum number of entries to store */
562  SCIP_Bool transformed /**< is constraint from transformed problem? */
563  )
564 {
565  assert(consdata != NULL);
566  assert(consdata->nvars <= consdata->varssize);
567 
568  if( num > consdata->varssize )
569  {
570  int newsize;
571 
572  newsize = SCIPcalcMemGrowSize(scip, num);
573  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
574  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
575  if( transformed )
576  {
577  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
578  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
579  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
580  }
581  else
582  {
583  assert(consdata->eventdata == NULL);
584  assert(consdata->cliquepartition == NULL);
585  assert(consdata->negcliquepartition == NULL);
586  }
587  consdata->varssize = newsize;
588  }
589  assert(num <= consdata->varssize);
590 
591  return SCIP_OKAY;
592 }
593 
594 /** updates all weight sums for fixed and unfixed variables */
595 static
596 void updateWeightSums(
597  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
598  SCIP_VAR* var, /**< variable for this weight */
599  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
600  )
601 {
602  assert(consdata != NULL);
603  assert(var != NULL);
605  consdata->weightsum += weightdelta;
606 
607  if( SCIPvarGetLbLocal(var) > 0.5 )
608  consdata->onesweightsum += weightdelta;
609 
610  assert(consdata->weightsum >= 0);
611  assert(consdata->onesweightsum >= 0);
612 }
613 
614 /** creates knapsack constraint data */
615 static
617  SCIP* scip, /**< SCIP data structure */
618  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
619  int nvars, /**< number of variables in knapsack */
620  SCIP_VAR** vars, /**< variables of knapsack */
621  SCIP_Longint* weights, /**< weights of knapsack items */
622  SCIP_Longint capacity /**< capacity of knapsack */
623  )
624 {
625  int v;
626  SCIP_Longint constant;
627 
628  assert(consdata != NULL);
629 
630  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
631 
632  constant = 0L;
633  (*consdata)->vars = NULL;
634  (*consdata)->weights = NULL;
635  (*consdata)->nvars = 0;
636  if( nvars > 0 )
637  {
638  SCIP_VAR** varsbuffer;
639  SCIP_Longint* weightsbuffer;
640  int k;
641 
642  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
643  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
644 
645  k = 0;
646  for( v = 0; v < nvars; ++v )
647  {
648  assert(vars[v] != NULL);
649  assert(SCIPvarIsBinary(vars[v]));
650 
651  /* all weight have to be non negative */
652  assert( weights[v] >= 0 );
653 
654  if( weights[v] > 0 )
655  {
656  /* treat fixed variables as constants if problem compression is enabled */
657  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
658  {
659  /* only if the variable is fixed to 1, we add its weight to the constant */
660  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
661  constant += weights[v];
662  }
663  else
664  {
665  varsbuffer[k] = vars[v];
666  weightsbuffer[k] = weights[v];
667  ++k;
668  }
669  }
670  }
671  assert(k >= 0);
672 
673  (*consdata)->nvars = k;
674 
675  /* copy the active variables and weights into the constraint data structure */
676  if( k > 0 )
677  {
678  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
679  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
680  }
681 
682  /* free buffer storage */
683  SCIPfreeBufferArray(scip, &weightsbuffer);
684  SCIPfreeBufferArray(scip, &varsbuffer);
685  }
686 
687  /* capacity has to be greater or equal to zero */
688  assert(capacity >= 0);
689  assert(constant >= 0);
690 
691  (*consdata)->varssize = (*consdata)->nvars;
692  (*consdata)->capacity = capacity - constant;
693  (*consdata)->eventdata = NULL;
694  (*consdata)->cliquepartition = NULL;
695  (*consdata)->negcliquepartition = NULL;
696  (*consdata)->row = NULL;
697  (*consdata)->weightsum = 0;
698  (*consdata)->onesweightsum = 0;
699  (*consdata)->ncliques = 0;
700  (*consdata)->nnegcliques = 0;
701  (*consdata)->presolvedtiming = 0;
702  (*consdata)->sorted = FALSE;
703  (*consdata)->cliquepartitioned = FALSE;
704  (*consdata)->negcliquepartitioned = FALSE;
705  (*consdata)->ncliqueslastpart = -1;
706  (*consdata)->ncliqueslastnegpart = -1;
707  (*consdata)->merged = FALSE;
708  (*consdata)->cliquesadded = FALSE;
709  (*consdata)->varsdeleted = FALSE;
710  (*consdata)->existmultaggr = FALSE;
711 
712  /* get transformed variables, if we are in the transformed problem */
713  if( SCIPisTransformed(scip) )
714  {
715  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
716 
717  for( v = 0; v < (*consdata)->nvars; v++ )
718  {
719  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
720  assert(var != NULL);
721  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
722  }
723 
724  /* allocate memory for additional data structures */
725  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
726  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
727  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
728  }
729 
730  /* calculate sum of weights and capture variables */
731  for( v = 0; v < (*consdata)->nvars; ++v )
732  {
733  /* calculate sum of weights */
734  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
735 
736  /* capture variables */
737  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
738  }
739  return SCIP_OKAY;
740 }
741 
742 /** frees knapsack constraint data */
743 static
745  SCIP* scip, /**< SCIP data structure */
746  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
747  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
748  )
749 {
750  assert(consdata != NULL);
751  assert(*consdata != NULL);
753  if( (*consdata)->row != NULL )
754  {
755  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
756  }
757  if( (*consdata)->eventdata != NULL )
758  {
759  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
760  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
761  }
762  if( (*consdata)->negcliquepartition != NULL )
763  {
764  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
765  }
766  if( (*consdata)->cliquepartition != NULL )
767  {
768  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
769  }
770  if( (*consdata)->vars != NULL )
771  {
772  int v;
773 
774  /* release variables */
775  for( v = 0; v < (*consdata)->nvars; v++ )
776  {
777  assert((*consdata)->vars[v] != NULL);
778  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
779  }
780 
781  assert( (*consdata)->weights != NULL );
782  assert( (*consdata)->varssize > 0 );
783  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
784  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
785  }
786 
787  SCIPfreeBlockMemory(scip, consdata);
788 
789  return SCIP_OKAY;
790 }
791 
792 /** changes a single weight in knapsack constraint data */
793 static
794 void consdataChgWeight(
795  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
796  int item, /**< item number */
797  SCIP_Longint newweight /**< new weight of item */
798  )
799 {
800  SCIP_Longint oldweight;
801  SCIP_Longint weightdiff;
803  assert(consdata != NULL);
804  assert(0 <= item && item < consdata->nvars);
805 
806  oldweight = consdata->weights[item];
807  weightdiff = newweight - oldweight;
808  consdata->weights[item] = newweight;
809 
810 
811  /* update weight sums for all and fixed variables */
812  updateWeightSums(consdata, consdata->vars[item], weightdiff);
813 
814  if( consdata->eventdata != NULL )
815  {
816  assert(consdata->eventdata[item] != NULL);
817  assert(consdata->eventdata[item]->weight == oldweight);
818  consdata->eventdata[item]->weight = newweight;
819  }
820 
821  consdata->presolvedtiming = 0;
822  consdata->sorted = FALSE;
823 
824  /* recalculate cliques extraction after a weight was increased */
825  if( oldweight < newweight )
826  {
827  consdata->cliquesadded = FALSE;
828  }
829 }
830 
831 /** creates LP row corresponding to knapsack constraint */
832 static
834  SCIP* scip, /**< SCIP data structure */
835  SCIP_CONS* cons /**< knapsack constraint */
836  )
837 {
838  SCIP_CONSDATA* consdata;
839  int i;
840 
841  consdata = SCIPconsGetData(cons);
842  assert(consdata != NULL);
843  assert(consdata->row == NULL);
844 
845  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, SCIPconsGetHdlr(cons), SCIPconsGetName(cons),
846  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
848 
849  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
850  for( i = 0; i < consdata->nvars; ++i )
851  {
852  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
853  }
854  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
855 
856  return SCIP_OKAY;
857 }
858 
859 /** adds linear relaxation of knapsack constraint to the LP */
860 static
862  SCIP* scip, /**< SCIP data structure */
863  SCIP_CONS* cons, /**< knapsack constraint */
864  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
865  )
866 {
867  SCIP_CONSDATA* consdata;
868 
869  assert( cutoff != NULL );
870  *cutoff = FALSE;
871 
872  consdata = SCIPconsGetData(cons);
873  assert(consdata != NULL);
874 
875  if( consdata->row == NULL )
876  {
877  SCIP_CALL( createRelaxation(scip, cons) );
878  }
879  assert(consdata->row != NULL);
880 
881  /* insert LP row as cut */
882  if( !SCIProwIsInLP(consdata->row) )
883  {
884  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
885  SCIPconsGetName(cons), consdata->capacity);
886  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
887  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
888  }
889 
890  return SCIP_OKAY;
891 }
892 
893 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
894 static
896  SCIP* scip, /**< SCIP data structure */
897  SCIP_CONS* cons, /**< constraint to check */
898  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
899  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
900  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
901  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
902  )
903 {
904  SCIP_CONSDATA* consdata;
905 
906  assert(violated != NULL);
907 
908  consdata = SCIPconsGetData(cons);
909  assert(consdata != NULL);
910 
911  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
912  SCIPconsGetName(cons), (void*)sol, checklprows);
913 
914  *violated = FALSE;
915 
916  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
917  {
918  SCIP_Real sum;
919  SCIP_Longint integralsum;
920  SCIP_Bool ishuge;
921  SCIP_Real absviol;
922  SCIP_Real relviol;
923  int v;
924 
925  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
926  * enforcement
927  */
928  if( sol == NULL )
929  {
930  SCIP_CALL( SCIPincConsAge(scip, cons) );
931  }
932 
933  sum = 0.0;
934  integralsum = 0;
935  /* we perform a more exact comparison if the capacity does not exceed the huge value */
936  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
937  {
938  ishuge = TRUE;
939 
940  /* sum over all weight times the corresponding solution value */
941  for( v = consdata->nvars - 1; v >= 0; --v )
942  {
943  assert(SCIPvarIsBinary(consdata->vars[v]));
944  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
945  }
946  }
947  else
948  {
949  ishuge = FALSE;
950 
951  /* sum over all weight for which the variable has a solution value of 1 in feastol */
952  for( v = consdata->nvars - 1; v >= 0; --v )
953  {
954  assert(SCIPvarIsBinary(consdata->vars[v]));
955 
956  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
957  integralsum += consdata->weights[v];
958  }
959  }
960 
961  /* calculate constraint violation and update it in solution */
962  absviol = ishuge ? sum : (SCIP_Real)integralsum;
963  absviol -= consdata->capacity;
964  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
965  if( sol != NULL )
966  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
967 
968  if( SCIPisFeasPositive(scip, absviol) )
969  {
970  *violated = TRUE;
971 
972  /* only reset constraint age if we are in enforcement */
973  if( sol == NULL )
974  {
975  SCIP_CALL( SCIPresetConsAge(scip, cons) );
976  }
977 
978  if( printreason )
979  {
980  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
981 
982  SCIPinfoMessage(scip, NULL, ";\n");
983  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
984  }
985  }
986 
987  }
988 
989  return SCIP_OKAY;
990 }
991 
992 /* IDX computes the integer index for the optimal solution array */
993 #define IDX(j,d) ((j)*(intcap)+(d))
994 
995 /** solves knapsack problem in maximization form exactly using dynamic programming;
996  * if needed, one can provide arrays to store all selected items and all not selected items
997  *
998  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part as well
999  */
1001  SCIP* scip, /**< SCIP data structure */
1002  int nitems, /**< number of available items */
1003  SCIP_Longint* weights, /**< item weights */
1004  SCIP_Real* profits, /**< item profits */
1005  SCIP_Longint capacity, /**< capacity of knapsack */
1006  int* items, /**< item numbers */
1007  int* solitems, /**< array to store items in solution, or NULL */
1008  int* nonsolitems, /**< array to store items not in solution, or NULL */
1009  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1010  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1011  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1012  SCIP_Bool* success /**< pointer to store if an error occured during solving
1013  * (normally a memory problem) */
1014  )
1015 {
1016  SCIP_RETCODE retcode;
1017  SCIP_Real* tempsort;
1018  SCIP_Real* optvalues;
1019  int intcap;
1020  int d;
1021  int j;
1022  SCIP_Longint weightsum;
1023  int* myitems;
1024  SCIP_Longint* myweights;
1025  int* allcurrminweight;
1026  SCIP_Real* myprofits;
1027  int nmyitems;
1028  SCIP_Longint gcd;
1029  SCIP_Longint minweight;
1030  SCIP_Longint maxweight;
1031  int currminweight;
1032  SCIP_Longint greedycap;
1033  SCIP_Longint greedysolweight;
1034  SCIP_Real greedysolvalue;
1035  SCIP_Bool eqweights;
1036  SCIP_Bool isoptimal;
1037  const size_t maxsize_t = (size_t)(-1);
1038 
1039  assert(weights != NULL);
1040  assert(profits != NULL);
1041  assert(capacity >= 0);
1042  assert(items != NULL);
1043  assert(nitems >= 0);
1044  assert(success != NULL);
1045 
1046  *success = TRUE;
1047 
1048 #ifndef NDEBUG
1049  for( j = nitems - 1; j >= 0; --j )
1050  assert(weights[j] >= 0);
1051 #endif
1052 
1053  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1054 
1055  /* initializing solution value */
1056  if( solval != NULL )
1057  *solval = 0.0;
1058 
1059  /* produces optimal solution by following the table */
1060  if( solitems != NULL)
1061  {
1062  assert(items != NULL);
1063  assert(nsolitems != NULL);
1064  assert(nonsolitems != NULL);
1065  assert(nnonsolitems != NULL);
1066 
1067  *nnonsolitems = 0;
1068  *nsolitems = 0;
1069  }
1070 
1071  /* allocate temporary memory */
1072  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1073  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1074  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1075  nmyitems = 0;
1076  weightsum = 0;
1077  minweight = SCIP_LONGINT_MAX;
1078  maxweight = 0;
1079 
1080  /* remove unnecessary items */
1081  for( j = 0; j < nitems; ++j )
1082  {
1083  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1084  /* items does not fit */
1085  if( weights[j] > capacity )
1086  {
1087  if( solitems != NULL)
1088  {
1089  nonsolitems[*nnonsolitems] = items[j];
1090  ++(*nnonsolitems);
1091  }
1092  }
1093  /* items we does not want */
1094  else if( profits[j] <= 0.0 )
1095  {
1096  if( solitems != NULL)
1097  {
1098  nonsolitems[*nnonsolitems] = items[j];
1099  ++(*nnonsolitems);
1100  }
1101  }
1102  /* items which always fit */
1103  else if( weights[j] == 0 )
1104  {
1105  if( solitems != NULL)
1106  {
1107  solitems[*nsolitems] = items[j];
1108  ++(*nsolitems);
1109  }
1110  if( solval != NULL )
1111  *solval += profits[j];
1112  }
1113  /* all important items */
1114  else
1115  {
1116  myweights[nmyitems] = weights[j];
1117  myprofits[nmyitems] = profits[j];
1118  myitems[nmyitems] = items[j];
1119 
1120  /* remember smallest item */
1121  if( myweights[nmyitems] < minweight )
1122  minweight = myweights[nmyitems];
1123 
1124  /* remember bigest item */
1125  if( myweights[nmyitems] > maxweight )
1126  maxweight = myweights[nmyitems];
1127 
1128  weightsum += myweights[nmyitems];
1129  ++nmyitems;
1130  }
1131  }
1132 
1133  /* no item is left then goto end */
1134  if( nmyitems == 0 )
1135  {
1136  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1137 
1138  goto TERMINATE;
1139  }
1140  /* if all items fit, we also do not need to do the expensive stuff later on */
1141  else if( weightsum > 0 && weightsum <= capacity )
1142  {
1143  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1144 
1145  for( j = nmyitems - 1; j >= 0; --j )
1146  {
1147  if( solitems != NULL )
1148  {
1149  solitems[*nsolitems] = myitems[j];
1150  ++(*nsolitems);
1151  }
1152  if( solval != NULL )
1153  *solval += myprofits[j];
1154  }
1155 
1156  goto TERMINATE;
1157  }
1158 
1159  assert(minweight > 0);
1160  assert(maxweight > 0);
1161 
1162  if( maxweight > 1 )
1163  {
1164  /* determine greatest common divisor */
1165  gcd = myweights[nmyitems - 1];
1166  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1167  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1168 
1169  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1170 
1171  /* divide by greatest common divisor */
1172  if( gcd > 1 )
1173  {
1174  eqweights = TRUE;
1175  for( j = nmyitems - 1; j >= 0; --j )
1176  {
1177  myweights[j] /= gcd;
1178  eqweights = eqweights && (myweights[j] == 1);
1179  }
1180  capacity /= gcd;
1181  minweight /= gcd;
1182  }
1183  else
1184  eqweights = FALSE;
1185  }
1186  else
1187  {
1188  assert(maxweight == 1);
1189  eqweights = TRUE;
1190  }
1191 
1192  assert(minweight <= capacity);
1193 
1194  /* only one item fits, than take the best */
1195  if( minweight > capacity / 2 )
1196  {
1197  int p;
1198 
1199  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1200 
1201  p = nmyitems - 1;
1202 
1203  /* find best item */
1204  for( j = nmyitems - 2; j >= 0; --j )
1205  if( myprofits[j] > myprofits[p] )
1206  p = j;
1207 
1208  /* update solution information */
1209  if( solitems != NULL)
1210  {
1211  solitems[*nsolitems] = myitems[p];
1212  ++(*nsolitems);
1213  for( j = nmyitems - 1; j >= 0; --j )
1214  if( j != p )
1215  {
1216  nonsolitems[*nnonsolitems] = myitems[j];
1217  ++(*nnonsolitems);
1218  }
1219  }
1220  /* update solution value */
1221  if( solval != NULL )
1222  *solval += myprofits[p];
1223 
1224  goto TERMINATE;
1225  }
1226 
1227  /* all items have the same weight, than take the best */
1228  if( eqweights )
1229  {
1230  SCIP_Real addval;
1231 
1232  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1233 
1234  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1235 
1236  addval = 0.0;
1237  /* update solution information */
1238  if( solitems != NULL || solval != NULL )
1239  {
1240  SCIP_Longint i;
1241 
1242  /* if all items would fit we had handled this case before */
1243  assert((SCIP_Longint) nmyitems > capacity);
1244 
1245  /* take the first best items into the solution */
1246  for( i = capacity - 1; i >= 0; --i )
1247  {
1248  if( solitems != NULL)
1249  {
1250  assert(nonsolitems != NULL);
1251  solitems[*nsolitems] = myitems[i];
1252  ++(*nsolitems);
1253  }
1254  addval += myprofits[i];
1255  }
1256 
1257  if( solitems != NULL)
1258  {
1259  assert(nonsolitems != NULL);
1260 
1261  /* the rest are not in the solution */
1262  for( i = nmyitems - 1; i >= capacity; --i )
1263  {
1264  nonsolitems[*nnonsolitems] = myitems[i];
1265  ++(*nnonsolitems);
1266  }
1267  }
1268  }
1269  /* update solution value */
1270  if( solval != NULL )
1271  {
1272  assert(addval > 0.0);
1273  *solval += addval;
1274  }
1275 
1276  goto TERMINATE;
1277  }
1278 
1279  /* in the following table we do not need the first minweight columns */
1280  capacity -= (minweight - 1);
1281 
1282  /* we can only handle integers */
1283  if( capacity >= INT_MAX )
1284  {
1285  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1286 
1287  *success = FALSE;
1288  goto TERMINATE;
1289  }
1290  assert(capacity < INT_MAX);
1291 
1292  intcap = (int)capacity;
1293  assert(intcap >= 0);
1294  assert(nmyitems > 0);
1295  assert(sizeof(size_t) >= sizeof(int)); /* no following conversion should be messed up */
1296 
1297  /* this condition checks if we will try to allocate a correct number of bytes and do not have an overflow, while
1298  * computing the size for the allocation
1299  */
1300  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*/
1301  {
1302  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1303 
1304  *success = FALSE;
1305  goto TERMINATE;
1306  }
1307 
1308  /* allocate temporary memory and check for memory exceeding */
1309  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1310  if( retcode == SCIP_NOMEMORY )
1311  {
1312  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1313 
1314  *success = FALSE;
1315  goto TERMINATE;
1316  }
1317  else
1318  {
1319  SCIP_CALL( retcode );
1320  }
1321 
1322  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1323  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only use for greedy solution
1324  */
1325  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1326  for( j = nmyitems - 1; j >= 0; --j )
1327  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1328 
1329  SCIPsortDownRealLongRealInt(tempsort, myweights, myprofits, myitems, nmyitems);
1330 
1331  /* initialize values for greedy solution information */
1332  greedysolweight = 0;
1333  greedysolvalue = 0.0;
1334  isoptimal = TRUE;
1335  greedycap = capacity + (minweight - 1);
1336 
1337  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1338 
1339  /* determine greedy solution */
1340  for( j = 0; j < nmyitems; ++j )
1341  {
1342  assert(myweights[j] <= greedycap);
1343 
1344  /* take all fitting items */
1345  if( myweights[j] + greedysolweight <= greedycap )
1346  {
1347  /* update greedy solution weight and value */
1348  greedysolweight += myweights[j];
1349  greedysolvalue += myprofits[j];
1350  continue;
1351  }
1352  else if( greedysolweight < greedycap )
1353  isoptimal = FALSE;
1354  break;
1355  }
1356  assert(greedysolweight > 0);
1357  assert(greedysolvalue > 0.0);
1358 
1359  /* greedy solution is optimal */
1360  if( isoptimal )
1361  {
1362  assert(greedysolweight == greedycap);
1363 
1364  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1365 
1366  greedysolweight = 0;
1367 
1368  /* update solution information */
1369  if( solitems != NULL)
1370  {
1371  /* take the first best items into the solution */
1372  for( j = 0; j < nmyitems; ++j )
1373  {
1374  /* take all fitting items */
1375  if( myweights[j] + greedysolweight <= greedycap )
1376  {
1377  solitems[*nsolitems] = myitems[j];
1378  ++(*nsolitems);
1379  greedysolweight += myweights[j];
1380  }
1381  else
1382  {
1383  nonsolitems[*nnonsolitems] = myitems[j];
1384  ++(*nnonsolitems);
1385  }
1386  }
1387  }
1388  /* update solution value */
1389  if( solval != NULL )
1390  {
1391  assert(greedysolvalue > 0.0);
1392  *solval += greedysolvalue;
1393  }
1394 
1395  SCIPfreeBufferArray(scip, &tempsort);
1396  SCIPfreeBufferArray(scip, &optvalues);
1397 
1398  goto TERMINATE;
1399  }
1400 
1401  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1402 
1403  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1404  * all values entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1405  * invalid, a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1406  * 'nmyitem' values
1407  */
1408  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1409  assert(myweights[0] - minweight < INT_MAX);
1410  currminweight = (int) (myweights[0] - minweight);
1411  allcurrminweight[0] = currminweight;
1412 
1413  /* fills first row of dynamic programming table with optimal values */
1414  for( d = currminweight; d < intcap; ++d )
1415  optvalues[d] = myprofits[0];
1416  /* fills dynamic programming table with optimal values */
1417  for( j = 1; j < nmyitems; ++j )
1418  {
1419  int intweight;
1420 
1421  /* compute important part of weight, which will be represented in the table */
1422  intweight = (int)(myweights[j] - minweight);
1423  assert(0 <= intweight && intweight < intcap);
1424 
1425  /* copy all nonzeros from row above */
1426  for( d = currminweight; d < intweight && d < intcap; ++d )
1427  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1428 
1429  /* update corresponding row */
1430  for( d = intweight; d < intcap; ++d )
1431  {
1432  /* if index d is smaller the the current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should
1433  * be 0
1434  */
1435  if( d < currminweight )
1436  {
1437  optvalues[IDX(j,d)] = myprofits[j];
1438  }
1439  else
1440  {
1441  SCIP_Real sumprofit;
1442 
1443  if( d - myweights[j] < currminweight )
1444  sumprofit = myprofits[j];
1445  else
1446  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1447 
1448  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1449  }
1450  }
1451  /* update currminweight */
1452  if( intweight < currminweight )
1453  currminweight = intweight;
1454 
1455  allcurrminweight[j] = currminweight;
1456  }
1457 
1458  /* update optimal solution by following the table */
1459  if( solitems != NULL)
1460  {
1461  d = intcap - 1;
1462 
1463  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1464 
1465  /* insert all items in (non-) solution vector */
1466  for( j = nmyitems - 1; j > 0; --j )
1467  {
1468  /* if we cannot find any item anymore which is in our solution stop, if the following condition holds this
1469  * means all remaining items does not fit anymore
1470  */
1471  if( d < allcurrminweight[j] )
1472  {
1473  /* we cannot have exceeded our capacity */
1474  assert((SCIP_Longint) d >= -minweight);
1475  break;
1476  }
1477  /* collect solution items, first condition means that no next item can fit anymore, but this does */
1478  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1479  {
1480  solitems[*nsolitems] = myitems[j];
1481  ++(*nsolitems);
1482 
1483  /* check that we do not have an underflow */
1484  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1485  d = (int)(d - myweights[j]);
1486  }
1487  /* collect non-solution items */
1488  else
1489  {
1490  nonsolitems[*nnonsolitems] = myitems[j];
1491  ++(*nnonsolitems);
1492  }
1493  }
1494 
1495  /* insert remaining items */
1496  if( d >= allcurrminweight[j] )
1497  {
1498  assert(j == 0);
1499  solitems[*nsolitems] = myitems[j];
1500  ++(*nsolitems);
1501  }
1502  else
1503  {
1504  assert(j >= 0);
1505  assert(d < allcurrminweight[j]);
1506 
1507  for( ; j >= 0; --j )
1508  {
1509  nonsolitems[*nnonsolitems] = myitems[j];
1510  ++(*nnonsolitems);
1511  }
1512  }
1513 
1514  assert(*nsolitems + *nnonsolitems == nitems);
1515  }
1516 
1517  /* update solution value */
1518  if( solval != NULL )
1519  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1520 
1521  SCIPfreeBufferArray(scip, &allcurrminweight);
1522 
1523  /* free all temporary memory */
1524  SCIPfreeBufferArray(scip, &tempsort);
1525  SCIPfreeBufferArray(scip, &optvalues);
1526 
1527  TERMINATE:
1528  SCIPfreeBufferArray(scip, &myitems);
1529  SCIPfreeBufferArray(scip, &myprofits);
1530  SCIPfreeBufferArray(scip, &myweights);
1531 
1532  return SCIP_OKAY;
1533 }
1534 
1535 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1536  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1537  * selected items
1538  */
1540  SCIP* scip, /**< SCIP data structure */
1541  int nitems, /**< number of available items */
1542  SCIP_Longint* weights, /**< item weights */
1543  SCIP_Real* profits, /**< item profits */
1544  SCIP_Longint capacity, /**< capacity of knapsack */
1545  int* items, /**< item numbers */
1546  int* solitems, /**< array to store items in solution, or NULL */
1547  int* nonsolitems, /**< array to store items not in solution, or NULL */
1548  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1549  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1550  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1551  )
1552 {
1553  SCIP_Real* tempsort;
1554  SCIP_Longint solitemsweight;
1555  SCIP_Real* realweights;
1556  int j;
1557  int criticalindex;
1558 
1559  assert(weights != NULL);
1560  assert(profits != NULL);
1561  assert(capacity >= 0);
1562  assert(items != NULL);
1563  assert(nitems >= 0);
1564 
1565  if( solitems != NULL )
1566  {
1567  *nsolitems = 0;
1568  *nnonsolitems = 0;
1569  }
1570  if( solval != NULL )
1571  *solval = 0.0;
1572 
1573  /* initialize data for median search */
1574  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1575  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1576  for( j = nitems - 1; j >= 0; --j )
1577  {
1578  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1579  realweights[j] = (SCIP_Real)weights[j];
1580 
1581  }
1582 
1583  /* partially sort indices such that all elements that are larger than the break item appear first */
1584  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1585 
1586  /* selects items as long as they fit into the knapsack */
1587  solitemsweight = 0;
1588  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1589  {
1590  if( solitems != NULL )
1591  {
1592  solitems[*nsolitems] = items[j];
1593  (*nsolitems)++;
1594  }
1595  if( solval != NULL )
1596  (*solval) += profits[j];
1597  solitemsweight += weights[j];
1598  }
1599  for( ; j < nitems && solitems != NULL; j++ )
1600  {
1601  nonsolitems[*nnonsolitems] = items[j];
1602  (*nnonsolitems)++;
1603  }
1604 
1605  SCIPfreeBufferArray(scip, &realweights);
1606  SCIPfreeBufferArray(scip, &tempsort);
1607 
1608  return SCIP_OKAY;
1609 }
1610 
1611 #ifdef SCIP_DEBUG
1612 /** prints all nontrivial GUB constraints and their LP solution values */
1613 static
1614 void GUBsetPrint(
1615  SCIP* scip, /**< SCIP data structure */
1616  SCIP_GUBSET* gubset, /**< GUB set data structure */
1617  SCIP_VAR** vars, /**< variables in knapsack constraint */
1618  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1619  )
1620 {
1621  int nnontrivialgubconss;
1622  int c;
1623 
1624  nnontrivialgubconss = 0;
1625 
1626  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1627 
1628  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1629  for( c = 0; c < gubset->ngubconss; c++ )
1630  {
1631  SCIP_Real gubsolval;
1632 
1633  assert(gubset->gubconss[c]->ngubvars >= 0);
1634 
1635  /* nontrivial GUB */
1636  if( gubset->gubconss[c]->ngubvars > 1 )
1637  {
1638  int v;
1639 
1640  gubsolval = 0.0;
1641  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1642 
1643  /* print GUB var */
1644  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1645  {
1646  int currentvar;
1647 
1648  currentvar = gubset->gubconss[c]->gubvars[v];
1649  if( solvals != NULL )
1650  {
1651  gubsolval += solvals[currentvar];
1652  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1653  }
1654  else
1655  {
1656  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1657  }
1658  }
1659 
1660  /* check whether LP solution satisfies the GUB constraint */
1661  if( solvals != NULL )
1662  {
1663  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1664  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1665  }
1666  else
1667  {
1668  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1669  }
1670  nnontrivialgubconss++;
1671  }
1672  }
1673 
1674  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1675 }
1676 #endif
1677 
1678 /** creates an empty GUB constraint */
1679 static
1681  SCIP* scip, /**< SCIP data structure */
1682  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1683  )
1684 {
1685  assert(scip != NULL);
1686  assert(gubcons != NULL);
1687 
1688  /* allocate memory for GUB constraint data structures */
1689  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1690  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1691  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1692  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1693 
1694  (*gubcons)->ngubvars = 0;
1695 
1696  return SCIP_OKAY;
1697 }
1698 
1699 /** frees GUB constraint */
1700 static
1702  SCIP* scip, /**< SCIP data structure */
1703  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1704  )
1705 {
1706  assert(scip != NULL);
1707  assert(gubcons != NULL);
1708  assert((*gubcons)->gubvars != NULL);
1709  assert((*gubcons)->gubvarsstatus != NULL);
1710 
1711  /* free allocated memory */
1712  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1713  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1714  SCIPfreeBuffer(scip, gubcons);
1715 
1716  return SCIP_OKAY;
1717 }
1718 
1719 /** adds variable to given GUB constraint */
1720 static
1722  SCIP* scip, /**< SCIP data structure */
1723  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1724  int var /**< index of given variable in knapsack constraint */
1725  )
1726 {
1727  assert(scip != NULL);
1728  assert(gubcons != NULL);
1729  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1730  assert(gubcons->gubvars != NULL);
1731  assert(gubcons->gubvarsstatus != NULL);
1732  assert(var >= 0);
1733 
1734  /* add variable to GUB constraint */
1735  gubcons->gubvars[gubcons->ngubvars] = var;
1736  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1737  gubcons->ngubvars++;
1738 
1739  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1740  if( gubcons->ngubvars == gubcons->gubvarssize )
1741  {
1742  int newlen;
1743 
1744  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1745  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1746  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1747 
1748  gubcons->gubvarssize = newlen;
1749  }
1750 
1751  return SCIP_OKAY;
1752 }
1753 
1754 /** deletes variable from its current GUB constraint */
1755 static
1757  SCIP* scip, /**< SCIP data structure */
1758  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1759  int var, /**< index of given variable in knapsack constraint */
1760  int gubvarsidx /**< index of the variable in its current GUB constraint */
1761  )
1762 {
1763  assert(scip != NULL);
1764  assert(gubcons != NULL);
1765  assert(var >= 0);
1766  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1767  assert(gubcons->ngubvars >= gubvarsidx+1);
1768  assert(gubcons->gubvars[gubvarsidx] == var);
1769 
1770  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1771  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1772  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1773  gubcons->ngubvars--;
1774 
1775  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1776  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1777  {
1778  int newlen;
1779 
1780  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1781 
1782  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1783  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1784 
1785  gubcons->gubvarssize = newlen;
1786  }
1787 
1788  return SCIP_OKAY;
1789 }
1790 
1791 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1792 static
1794  SCIP* scip, /**< SCIP data structure */
1795  SCIP_GUBSET* gubset, /**< GUB set data structure */
1796  SCIP_VAR** vars, /**< variables in knapsack constraint */
1797  int var, /**< index of given variable in knapsack constraint */
1798  int oldgubcons, /**< index of old GUB constraint of given variable */
1799  int newgubcons /**< index of new GUB constraint of given variable */
1800  )
1802  int oldgubvaridx;
1803  int replacevar;
1804  int j;
1805 
1806  assert(scip != NULL);
1807  assert(gubset != NULL);
1808  assert(var >= 0);
1809  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1810  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1811  assert(oldgubcons != newgubcons);
1812  assert(gubset->gubconssidx[var] == oldgubcons);
1813  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1814  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1815 
1816  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1817 
1818  oldgubvaridx = gubset->gubvarsidx[var];
1819 
1820  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1821  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1822 
1823  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1824  * replacement variable is given by old position of the deleted variable
1825  */
1826  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1827  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1828  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1829 
1830  /* add variable to the end of new GUB constraint */
1831  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1832  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1833 
1834  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1835  gubset->gubconssidx[var] = newgubcons;
1836  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1837 
1838  /* delete old GUB constraint if it became empty */
1839  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1840  {
1841  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1842 #ifdef SCIP_DEBUG
1843  GUBsetPrint(scip, gubset, vars, NULL);
1844 #endif
1845 
1846  /* free old GUB constraint */
1847  SCIP_CALL( GUBconsFree(scip, &gubset->gubconss[oldgubcons]) );
1848 
1849  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1850  if( oldgubcons != gubset->ngubconss-1 )
1851  {
1852  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1853  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1854 
1855  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1856  * replacement GUB is given by old position of the deleted GUB
1857  */
1858  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1859  {
1860  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1861  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1862  }
1863  }
1864 
1865  /* update number of GUB constraints */
1866  gubset->ngubconss--;
1867 
1868  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1869  * (because it was at the end of the GUB constraint array)
1870  */
1871  assert(gubset->gubconssidx[var] == newgubcons
1872  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1873  }
1874 #ifndef NDEBUG
1875  else
1876  assert(gubset->gubconssidx[var] == newgubcons);
1877 #endif
1878 
1879  return SCIP_OKAY;
1880 }
1881 
1882 /** swaps two variables in the same GUB constraint */
1883 static
1884 void GUBsetSwapVars(
1885  SCIP* scip, /**< SCIP data structure */
1886  SCIP_GUBSET* gubset, /**< GUB set data structure */
1887  int var1, /**< first variable to be swapped */
1888  int var2 /**< second variable to be swapped */
1889  )
1890 {
1891  int gubcons;
1892  int var1idx;
1893  GUBVARSTATUS var1status;
1894  int var2idx;
1895  GUBVARSTATUS var2status;
1896 
1897  assert(scip != NULL);
1898  assert(gubset != NULL);
1899 
1900  gubcons = gubset->gubconssidx[var1];
1901  assert(gubcons == gubset->gubconssidx[var2]);
1902 
1903  /* nothing to be done if both variables are the same */
1904  if( var1 == var2 )
1905  return;
1906 
1907  /* swap index and status of variables in GUB constraint */
1908  var1idx = gubset->gubvarsidx[var1];
1909  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1910  var2idx = gubset->gubvarsidx[var2];
1911  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1912 
1913  gubset->gubvarsidx[var1] = var2idx;
1914  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1915  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1916 
1917  gubset->gubvarsidx[var2] = var1idx;
1918  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1919  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1920 }
1921 
1922 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1923 static
1925  SCIP* scip, /**< SCIP data structure */
1926  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1927  int nvars, /**< number of variables in the knapsack constraint */
1928  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1929  SCIP_Longint capacity /**< capacity of knapsack */
1930  )
1931 {
1932  int i;
1933 
1934  assert(scip != NULL);
1935  assert(gubset != NULL);
1936  assert(nvars > 0);
1937  assert(weights != NULL);
1938  assert(capacity >= 0);
1939 
1940  /* allocate memory for GUB set data structures */
1941  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1942  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1943  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1944  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1945  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1946  (*gubset)->ngubconss = nvars;
1947  (*gubset)->nvars = nvars;
1948 
1949  /* initialize the set of GUB constraints */
1950  for( i = 0; i < nvars; i++ )
1951  {
1952  /* assign each variable to a new (trivial) GUB constraint */
1953  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1954  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1955 
1956  /* set status of GUB constraint to initial */
1957  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1958 
1959  (*gubset)->gubconssidx[i] = i;
1960  (*gubset)->gubvarsidx[i] = 0;
1961  assert((*gubset)->gubconss[i]->ngubvars == 1);
1962 
1963  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1964  if( weights[i] > capacity )
1965  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1966 
1967  }
1968 
1969  return SCIP_OKAY;
1970 }
1971 
1972 /** frees GUB set data structure */
1973 static
1975  SCIP* scip, /**< SCIP data structure */
1976  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1977  )
1978 {
1979  int i;
1980 
1981  assert(scip != NULL);
1982  assert(gubset != NULL);
1983  assert((*gubset)->gubconss != NULL);
1984  assert((*gubset)->gubconsstatus != NULL);
1985  assert((*gubset)->gubconssidx != NULL);
1986  assert((*gubset)->gubvarsidx != NULL);
1987 
1988  /* free all GUB constraints */
1989  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1990  {
1991  assert((*gubset)->gubconss[i] != NULL);
1992  SCIP_CALL( GUBconsFree(scip, &(*gubset)->gubconss[i]) );
1993  }
1994 
1995  /* free allocated memory */
1996  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1997  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1998  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1999  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2000  SCIPfreeBuffer(scip, gubset);
2001 
2002  return SCIP_OKAY;
2003 }
2004 
2005 #ifndef NDEBUG
2006 /** checks whether GUB set data structure is consistent */
2007 static
2009  SCIP* scip, /**< SCIP data structure */
2010  SCIP_GUBSET* gubset, /**< GUB set data structure */
2011  SCIP_VAR** vars /**< variables in the knapsack constraint */
2012  )
2013 {
2014  int i;
2015  int gubconsidx;
2016  int gubvaridx;
2017  SCIP_VAR* var1;
2018  SCIP_VAR* var2;
2019  SCIP_Bool var1negated;
2020  SCIP_Bool var2negated;
2021 
2022  assert(scip != NULL);
2023  assert(gubset != NULL);
2024 
2025  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2026 
2027  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2028  for( i = 0; i < gubset->nvars; i++ )
2029  {
2030  gubconsidx = gubset->gubconssidx[i];
2031  gubvaridx = gubset->gubvarsidx[i];
2032 
2033  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2034  {
2035  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2036  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2037  }
2038  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2039  }
2040 
2041  /* checks for each GUB whether all pairs of its variables have a common clique */
2042  for( i = 0; i < gubset->ngubconss; i++ )
2043  {
2044  int j;
2045 
2046  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2047  {
2048  int k;
2049 
2050  /* get corresponding active problem variable */
2051  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2052  var1negated = FALSE;
2053  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2054 
2055  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2056  {
2057  /* get corresponding active problem variable */
2058  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2059  var2negated = FALSE;
2060  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2061 
2062  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2063  {
2064  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2065  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2066  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2067  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2068  SCIPvarGetName(var1), k,
2069  SCIPvarGetName(var2));
2070  }
2071 
2072  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2073  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2074  }
2075  }
2076  }
2077  SCIPdebugMsg(scip, " --> successful\n");
2078 
2079  return SCIP_OKAY;
2080 }
2081 #endif
2082 
2083 /** calculates a partition of the given set of binary variables into cliques;
2084  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2085  * were assigned to the same clique;
2086  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2087  * the preceding variables was assigned to clique i-1;
2088  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2089  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2090  */
2091 
2092 static
2094  SCIP*const scip, /**< SCIP data structure */
2095  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2096  int const nvars, /**< number of variables in the clique */
2097  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2098  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2099  SCIP_Real* solvals /**< solution values of all given binary variables */
2100  )
2102  SCIP_VAR** tmpvars;
2103  SCIP_VAR** cliquevars;
2104  SCIP_Bool* cliquevalues;
2105  SCIP_Bool* tmpvalues;
2106  int* varseq;
2107  int* sortkeys;
2108  int ncliquevars;
2109  int maxncliquevarscomp;
2110  int nignorevars;
2111  int nvarsused;
2112  int i;
2113 
2114  assert(scip != NULL);
2115  assert(nvars == 0 || vars != NULL);
2116  assert(nvars == 0 || cliquepartition != NULL);
2117  assert(ncliques != NULL);
2118 
2119  if( nvars == 0 )
2120  {
2121  *ncliques = 0;
2122  return SCIP_OKAY;
2123  }
2124 
2125  /* allocate temporary memory for storing the variables of the current clique */
2126  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2127  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2128  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2129  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2130  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2131  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2132 
2133  /* initialize the cliquepartition array with -1 */
2134  /* initialize the tmpvalues array */
2135  for( i = nvars - 1; i >= 0; --i )
2136  {
2137  tmpvalues[i] = TRUE;
2138  cliquepartition[i] = -1;
2139  }
2140 
2141  /* get corresponding active problem variables */
2142  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2143 
2144  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2145  * by nondecreasing number of cliques the variables are in
2146  */
2147  nignorevars = 0;
2148  nvarsused = 0;
2149  for( i = 0; i < nvars; i++ )
2150  {
2151  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2152  {
2153  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2154  varseq[nvars-1-nignorevars] = i;
2155  nignorevars++;
2156  }
2157  else
2158  {
2159  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2160  varseq[nvarsused] = i;
2161  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2162  nvarsused++;
2163  }
2164  }
2165  assert(nvarsused + nignorevars == nvars);
2166 
2167  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2168  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2169 
2170  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2171 
2172  /* calculate the clique partition */
2173  *ncliques = 0;
2174  for( i = 0; i < nvars; ++i )
2175  {
2176  if( cliquepartition[varseq[i]] == -1 )
2177  {
2178  int j;
2179 
2180  /* variable starts a new clique */
2181  cliquepartition[varseq[i]] = *ncliques;
2182  cliquevars[0] = tmpvars[varseq[i]];
2183  cliquevalues[0] = tmpvalues[varseq[i]];
2184  ncliquevars = 1;
2185 
2186  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2187  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2188  */
2189  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2190  {
2191  /* greedily fill up the clique */
2192  for( j = i + 1; j < nvarsused; ++j )
2193  {
2194  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2195  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2196  {
2197  int k;
2198 
2199  /* check if every variable in the actual clique is in clique with the new variable */
2200  for( k = ncliquevars - 1; k >= 0; --k )
2201  {
2202  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2203  cliquevalues[k], TRUE) )
2204  break;
2205  }
2206 
2207  if( k == -1 )
2208  {
2209  /* put the variable into the same clique */
2210  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2211  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2212  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2213  ++ncliquevars;
2214  }
2215  }
2216  }
2217  }
2218 
2219  /* this clique is finished */
2220  ++(*ncliques);
2221  }
2222  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2223 
2224  /* break if we reached the maximal number of comparisons */
2225  if( i * nvars > maxncliquevarscomp )
2226  break;
2227  }
2228  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2229  for( ; i < nvars; ++i )
2230  {
2231  if( cliquepartition[varseq[i]] == -1 )
2232  {
2233  cliquepartition[varseq[i]] = *ncliques;
2234  ++(*ncliques);
2235  }
2236  }
2237 
2238  /* free temporary memory */
2239  SCIPfreeBufferArray(scip, &sortkeys);
2240  SCIPfreeBufferArray(scip, &varseq);
2241  SCIPfreeBufferArray(scip, &tmpvars);
2242  SCIPfreeBufferArray(scip, &tmpvalues);
2243  SCIPfreeBufferArray(scip, &cliquevalues);
2244  SCIPfreeBufferArray(scip, &cliquevars);
2245 
2246  return SCIP_OKAY;
2247 }
2248 
2249 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2250 static
2252  SCIP* scip, /**< SCIP data structure */
2253  SCIP_GUBSET* gubset, /**< GUB set data structure */
2254  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2255  SCIP_Real* solvals /**< solution values of all knapsack variables */
2256  )
2257 {
2258  int* cliquepartition;
2259  int* gubfirstvar;
2260  int ncliques;
2261  int currentgubconsidx;
2262  int newgubconsidx;
2263  int cliqueidx;
2264  int nvars;
2265  int i;
2266 
2267  assert(scip != NULL);
2268  assert(gubset != NULL);
2269  assert(vars != NULL);
2270 
2271  nvars = gubset->nvars;
2272  assert(nvars >= 0);
2273 
2274  /* allocate temporary memory for clique partition */
2275  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2276 
2277  /* compute sophisticated clique partition */
2278  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2279 
2280  /* allocate temporary memory for GUB set data structure */
2281  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2282 
2283  /* translate GUB partition into GUB set data structure */
2284  for( i = 0; i < ncliques; i++ )
2285  {
2286  /* initialize first variable for every GUB */
2287  gubfirstvar[i] = -1;
2288  }
2289  /* move every knapsack variable into GUB defined by clique partition */
2290  for( i = 0; i < nvars; i++ )
2291  {
2292  assert(cliquepartition[i] >= 0);
2293 
2294  cliqueidx = cliquepartition[i];
2295  currentgubconsidx = gubset->gubconssidx[i];
2296  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2297 
2298  /* variable is first element in GUB constraint defined by clique partition */
2299  if( gubfirstvar[cliqueidx] == -1 )
2300  {
2301  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2302  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2303  */
2304  assert(gubset->gubvarsidx[i] == 0);
2305  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2306 
2307  /* remember the first variable found for the current GUB */
2308  gubfirstvar[cliqueidx] = i;
2309  }
2310  /* variable is additional element of GUB constraint defined by clique partition */
2311  else
2312  {
2313  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2314 
2315  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2316  * first variable of this GUB constraint
2317  */
2318  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2319  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2320  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2321 
2322  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2323  }
2324  }
2325 
2326 #ifdef SCIP_DEBUG
2327  /* prints GUB set data structure */
2328  GUBsetPrint(scip, gubset, vars, solvals);
2329 #endif
2330 
2331 #ifndef NDEBUG
2332  /* checks consistency of GUB set data structure */
2333  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2334 #endif
2335 
2336  /* free temporary memory */
2337  SCIPfreeBufferArray(scip, &gubfirstvar);
2338  SCIPfreeBufferArray(scip, &cliquepartition);
2339 
2340  return SCIP_OKAY;
2341 }
2342 
2343 /** 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$
2344  * 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
2345  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2346  */
2347 static
2349  SCIP* scip, /**< SCIP data structure */
2350  SCIP_VAR** vars, /**< variables in knapsack constraint */
2351  int nvars, /**< number of variables in knapsack constraint */
2352  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2353  SCIP_Longint capacity, /**< capacity of knapsack */
2354  SCIP_Real* solvals, /**< solution values of all problem variables */
2355  int* covervars, /**< pointer to store cover variables */
2356  int* noncovervars, /**< pointer to store noncover variables */
2357  int* ncovervars, /**< pointer to store number of cover variables */
2358  int* nnoncovervars, /**< pointer to store number of noncover variables */
2359  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2360  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2361  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2362  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2363  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2364  )
2365 {
2366  SCIP_Longint* transweights;
2367  SCIP_Real* transprofits;
2368  SCIP_Longint transcapacity;
2369  SCIP_Longint fixedonesweight;
2370  SCIP_Longint itemsweight;
2371  SCIP_Bool infeasible;
2372  int* fixedones;
2373  int* fixedzeros;
2374  int* items;
2375  int nfixedones;
2376  int nfixedzeros;
2377  int nitems;
2378  int j;
2379 
2380  assert(scip != NULL);
2381  assert(vars != NULL);
2382  assert(nvars > 0);
2383  assert(weights != NULL);
2384  assert(capacity >= 0);
2385  assert(solvals != NULL);
2386  assert(covervars != NULL);
2387  assert(noncovervars != NULL);
2388  assert(ncovervars != NULL);
2389  assert(nnoncovervars != NULL);
2390  assert(coverweight != NULL);
2391  assert(found != NULL);
2392  assert(ntightened != NULL);
2393  assert(fractional != NULL);
2394 
2395  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2396 
2397  /* allocates temporary memory */
2398  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2399  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2400  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2401  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2402  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2403 
2404  *found = FALSE;
2405  *ncovervars = 0;
2406  *nnoncovervars = 0;
2407  *coverweight = 0;
2408  *fractional = TRUE;
2409 
2410  /* gets the following sets
2411  * N_1 = {j in N : x*_j = 1} (fixedones),
2412  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2413  * N\(N_0 & N_1) (items),
2414  * where x*_j is the solution value of variable x_j
2415  */
2416  nfixedones = 0;
2417  nfixedzeros = 0;
2418  nitems = 0;
2419  fixedonesweight = 0;
2420  itemsweight = 0;
2421  *ntightened = 0;
2422  for( j = 0; j < nvars; j++ )
2423  {
2424  assert(SCIPvarIsBinary(vars[j]));
2425 
2426  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2427  if( weights[j] > capacity )
2428  {
2429  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2430  assert(!infeasible);
2431  (*ntightened)++;
2432  continue;
2433  }
2434 
2435  /* variable x_j has solution value one */
2436  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2437  {
2438  fixedones[nfixedones] = j;
2439  nfixedones++;
2440  fixedonesweight += weights[j];
2441  }
2442  /* variable x_j has solution value zero */
2443  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2444  {
2445  fixedzeros[nfixedzeros] = j;
2446  nfixedzeros++;
2447  }
2448  /* variable x_j has fractional solution value */
2449  else
2450  {
2451  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2452  items[nitems] = j;
2453  nitems++;
2454  itemsweight += weights[j];
2455  }
2456  }
2457  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2458 
2459  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2460  * the separation routine
2461  */
2462  assert(nitems >= 0);
2463  if( nitems == 0 )
2464  {
2465  *fractional = FALSE;
2466  goto TERMINATE;
2467  }
2468  assert(*fractional);
2469 
2470  /* transforms the traditional separation problem (under consideration of the following fixing:
2471  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2472  *
2473  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2474  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2475  * z_j in {0,1}, j in N\(N_0 & N_1)
2476  *
2477  * to a knapsack problem in maximization form by complementing the variables
2478  *
2479  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2480  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2481  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2482  * z_j in {0,1}, j in N\(N_0 & N_1)
2483  */
2484 
2485  /* gets weight and profit of variables in transformed knapsack problem */
2486  for( j = 0; j < nitems; j++ )
2487  {
2488  transweights[j] = weights[items[j]];
2489  transprofits[j] = 1.0 - solvals[items[j]];
2490  }
2491  /* gets capacity of transformed knapsack problem */
2492  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2493 
2494  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2495  * (when variables fixed to zero are not used)
2496  */
2497  if( transcapacity < 0 )
2498  {
2499  assert(!(*found));
2500  goto TERMINATE;
2501  }
2502 
2503  if( modtransused )
2504  {
2505  /* transforms the modified separation problem (under consideration of the following fixing:
2506  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2507  *
2508  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2509  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2510  * z_j in {0,1}, j in N\(N_0 & N_1)
2511  *
2512  * to a knapsack problem in maximization form by complementing the variables
2513  *
2514  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2515  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2516  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2517  * z_j in {0,1}, j in N\(N_0 & N_1)
2518  */
2519 
2520  /* gets weight and profit of variables in modified transformed knapsack problem */
2521  for( j = 0; j < nitems; j++ )
2522  {
2523  transprofits[j] *= weights[items[j]];
2524  assert(SCIPisFeasPositive(scip, transprofits[j]));
2525  }
2526  }
2527 
2528  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2529  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2530  * let z* be the solution, then
2531  * j in C, if z*_j = 0 and
2532  * i in N\C, if z*_j = 1.
2533  */
2534  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2535  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2536  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2537 
2538  /* constructs cover C (sum_{j in C} a_j > a_0) */
2539  for( j = 0; j < *ncovervars; j++ )
2540  {
2541  (*coverweight) += weights[covervars[j]];
2542  }
2543 
2544  /* adds all variables from N_1 to C */
2545  for( j = 0; j < nfixedones; j++ )
2546  {
2547  covervars[*ncovervars] = fixedones[j];
2548  (*ncovervars)++;
2549  (*coverweight) += weights[fixedones[j]];
2550  }
2551 
2552  /* adds all variables from N_0 to N\C */
2553  for( j = 0; j < nfixedzeros; j++ )
2554  {
2555  noncovervars[*nnoncovervars] = fixedzeros[j];
2556  (*nnoncovervars)++;
2557  }
2558  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2559  assert((*coverweight) > capacity);
2560  *found = TRUE;
2561 
2562  TERMINATE:
2563  /* frees temporary memory */
2564  SCIPfreeBufferArray(scip, &items);
2565  SCIPfreeBufferArray(scip, &fixedzeros);
2566  SCIPfreeBufferArray(scip, &fixedones);
2567  SCIPfreeBufferArray(scip, &transprofits);
2568  SCIPfreeBufferArray(scip, &transweights);
2569 
2570  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2571 
2572  return SCIP_OKAY;
2573 }
2574 
2575 #ifndef NDEBUG
2576 /** checks if minweightidx is set correctly
2577  */
2578 static
2580  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2581  SCIP_Longint capacity, /**< capacity of knapsack */
2582  int* covervars, /**< pointer to store cover variables */
2583  int ncovervars, /**< pointer to store number of cover variables */
2584  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2585  int minweightidx, /**< index of variable in cover variables with minimum weight */
2586  int j /**< current index in cover variables */
2587  )
2588 {
2589  SCIP_Longint minweight;
2590  int i;
2591 
2592  assert(weights != NULL);
2593  assert(covervars != NULL);
2594  assert(ncovervars > 0);
2595 
2596  minweight = weights[covervars[minweightidx]];
2597 
2598  /* checks if all cover variables before index j have weight greater than minweight */
2599  for( i = 0; i < j; i++ )
2600  {
2601  assert(weights[covervars[i]] > minweight);
2602  if( weights[covervars[i]] <= minweight )
2603  return FALSE;
2604  }
2605 
2606  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2607  for( i = 0; i < j; i++ )
2608  {
2609  assert(coverweight - weights[covervars[i]] <= capacity);
2610  if( coverweight - weights[covervars[i]] > capacity )
2611  return FALSE;
2612  }
2613  return TRUE;
2614 }
2615 #endif
2616 
2617 
2618 /** 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$,
2619  * 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$
2620  */
2621 static
2623  SCIP* scip, /**< SCIP data structure */
2624  SCIP_Real* solvals, /**< solution values of all problem variables */
2625  int* covervars, /**< cover variables */
2626  int ncovervars, /**< number of cover variables */
2627  int* varsC1, /**< pointer to store variables in C1 */
2628  int* varsC2, /**< pointer to store variables in C2 */
2629  int* nvarsC1, /**< pointer to store number of variables in C1 */
2630  int* nvarsC2 /**< pointer to store number of variables in C2 */
2631  )
2632 {
2633  int j;
2634 
2635  assert(scip != NULL);
2636  assert(ncovervars >= 0);
2637  assert(solvals != NULL);
2638  assert(covervars != NULL);
2639  assert(varsC1 != NULL);
2640  assert(varsC2 != NULL);
2641  assert(nvarsC1 != NULL);
2642  assert(nvarsC2 != NULL);
2643 
2644  *nvarsC1 = 0;
2645  *nvarsC2 = 0;
2646  for( j = 0; j < ncovervars; j++ )
2647  {
2648  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2649 
2650  /* variable has solution value one */
2651  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2652  {
2653  varsC2[*nvarsC2] = covervars[j];
2654  (*nvarsC2)++;
2655  }
2656  /* variable has solution value less than one */
2657  else
2658  {
2659  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2660  varsC1[*nvarsC1] = covervars[j];
2661  (*nvarsC1)++;
2662  }
2663  }
2664  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2665 }
2666 
2667 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2668  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2669  */
2670 static
2672  SCIP* scip, /**< SCIP data structure */
2673  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2674  int* varsC1, /**< pointer to store variables in C1 */
2675  int* varsC2, /**< pointer to store variables in C2 */
2676  int* nvarsC1, /**< pointer to store number of variables in C1 */
2677  int* nvarsC2 /**< pointer to store number of variables in C2 */
2678  )
2680  SCIP_Real* sortkeysC2;
2681  int j;
2682 
2683  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2684  assert(*nvarsC2 > 0);
2685 
2686  /* allocates temporary memory */
2687  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2688 
2689  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2690  for( j = 0; j < *nvarsC2; j++ )
2691  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2692  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2693 
2694  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2695  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2696  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2697  {
2698  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2699  (*nvarsC1)++;
2700  (*nvarsC2)--;
2701  }
2702 
2703  /* frees temporary memory */
2704  SCIPfreeBufferArray(scip, &sortkeysC2);
2705 
2706  return SCIP_OKAY;
2707 }
2708 
2709 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2710 static
2712  SCIP* scip, /**< SCIP data structure */
2713  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2714  int* varsC1, /**< pointer to store variables in C1 */
2715  int* varsC2, /**< pointer to store variables in C2 */
2716  int* nvarsC1, /**< pointer to store number of variables in C1 */
2717  int* nvarsC2 /**< pointer to store number of variables in C2 */
2718  )
2720  SCIP_Real* sortkeysC2;
2721  int j;
2722 
2723  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2724  assert(*nvarsC2 > 0);
2725 
2726  /* allocates temporary memory */
2727  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2728 
2729  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2730  for( j = 0; j < *nvarsC2; j++ )
2731  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2732  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2733 
2734  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2735  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2736  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2737  (*nvarsC1)++;
2738  (*nvarsC2)--;
2739 
2740  /* frees temporary memory */
2741  SCIPfreeBufferArray(scip, &sortkeysC2);
2742 
2743  return SCIP_OKAY;
2744 }
2745 
2746 
2747 /** 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$
2748  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2749  * \f$F = (N \setminus C) \setminus F\f$
2750  */
2751 static
2753  SCIP* scip, /**< SCIP data structure */
2754  SCIP_Real* solvals, /**< solution values of all problem variables */
2755  int* noncovervars, /**< noncover variables */
2756  int nnoncovervars, /**< number of noncover variables */
2757  int* varsF, /**< pointer to store variables in F */
2758  int* varsR, /**< pointer to store variables in R */
2759  int* nvarsF, /**< pointer to store number of variables in F */
2760  int* nvarsR /**< pointer to store number of variables in R */
2761  )
2762 {
2763  int j;
2764 
2765  assert(scip != NULL);
2766  assert(nnoncovervars >= 0);
2767  assert(solvals != NULL);
2768  assert(noncovervars != NULL);
2769  assert(varsF != NULL);
2770  assert(varsR != NULL);
2771  assert(nvarsF != NULL);
2772  assert(nvarsR != NULL);
2773 
2774  *nvarsF = 0;
2775  *nvarsR = 0;
2776 
2777  for( j = 0; j < nnoncovervars; j++ )
2778  {
2779  /* variable has solution value zero */
2780  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2781  {
2782  varsR[*nvarsR] = noncovervars[j];
2783  (*nvarsR)++;
2784  }
2785  /* variable has solution value greater than zero */
2786  else
2787  {
2788  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2789  varsF[*nvarsF] = noncovervars[j];
2790  (*nvarsF)++;
2791  }
2792  }
2793  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2794 }
2795 
2796 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2797  * lifting procedure
2798  */
2799 static
2801  SCIP* scip, /**< SCIP data structure */
2802  SCIP_Real* solvals, /**< solution values of all problem variables */
2803  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2804  int* varsF, /**< pointer to store variables in F */
2805  int* varsC2, /**< pointer to store variables in C2 */
2806  int* varsR, /**< pointer to store variables in R */
2807  int nvarsF, /**< number of variables in F */
2808  int nvarsC2, /**< number of variables in C2 */
2809  int nvarsR /**< number of variables in R */
2810  )
2811 {
2812  SORTKEYPAIR** sortkeypairsF;
2813  SORTKEYPAIR* sortkeypairsFstore;
2814  SCIP_Real* sortkeysC2;
2815  SCIP_Real* sortkeysR;
2816  int j;
2817 
2818  assert(scip != NULL);
2819  assert(solvals != NULL);
2820  assert(weights != NULL);
2821  assert(varsF != NULL);
2822  assert(varsC2 != NULL);
2823  assert(varsR != NULL);
2824  assert(nvarsF >= 0);
2825  assert(nvarsC2 >= 0);
2826  assert(nvarsR >= 0);
2827 
2828  /* allocates temporary memory */
2829  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2830  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2831  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2832  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2833 
2834  /* gets sorting key for variables in F corresponding to the following lifting sequence
2835  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2836  * x*_1 >= x*_2 >= ... >= x*_|F|
2837  * in case of equality uses
2838  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2839  */
2840  for( j = 0; j < nvarsF; j++ )
2841  {
2842  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2843  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2844  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2845  }
2846 
2847  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2848  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2849  */
2850  for( j = 0; j < nvarsC2; j++ )
2851  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2852 
2853  /* gets sorting key for variables in R corresponding to the following lifting sequence
2854  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2855  */
2856  for( j = 0; j < nvarsR; j++ )
2857  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2858 
2859  /* sorts F, C2 and R */
2860  if( nvarsF > 0 )
2861  {
2862  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2863  }
2864  if( nvarsC2 > 0 )
2865  {
2866  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2867  }
2868  if( nvarsR > 0)
2869  {
2870  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2871  }
2872 
2873  /* frees temporary memory */
2874  SCIPfreeBufferArray(scip, &sortkeysR);
2875  SCIPfreeBufferArray(scip, &sortkeysC2);
2876  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2877  SCIPfreeBufferArray(scip, &sortkeypairsF);
2878 
2879  return SCIP_OKAY;
2880 }
2881 
2882 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2883  * for the sequential GUB wise lifting procedure
2884  */
2885 static
2887  SCIP* scip, /**< SCIP data structure */
2888  SCIP_GUBSET* gubset, /**< GUB set data structure */
2889  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2890  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2891  int* varsC1, /**< variables in C1 */
2892  int* varsC2, /**< variables in C2 */
2893  int* varsF, /**< variables in F */
2894  int* varsR, /**< variables in R */
2895  int nvarsC1, /**< number of variables in C1 */
2896  int nvarsC2, /**< number of variables in C2 */
2897  int nvarsF, /**< number of variables in F */
2898  int nvarsR, /**< number of variables in R */
2899  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2900  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2901  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2902  int* gubconsGR, /**< pointer to store GUBs in GR */
2903  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2904  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2905  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2906  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2907  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2908  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2909  )
2910 {
2911 #if 0 /* not required */
2912  SORTKEYPAIR** sortkeypairsF;
2913 #endif
2914  SORTKEYPAIR** sortkeypairsGFC1;
2915  SORTKEYPAIR* sortkeypairsGFC1store;
2916  SCIP_Real* sortkeysC1;
2917  SCIP_Real* sortkeysC2;
2918  SCIP_Real* sortkeysR;
2919  int* nC1varsingubcons;
2920  int var;
2921  int gubconsidx;
2922  int varidx;
2923  int ngubconss;
2924  int ngubconsGOC1;
2925  int targetvar;
2926  int nvarsprocessed;
2927  int i;
2928  int j;
2929 
2930 #if GUBSPLITGNC1GUBS
2931  SCIP_Bool gubconswithF;
2932  int origngubconss;
2933  origngubconss = gubset->ngubconss;
2934 #endif
2935 
2936  assert(scip != NULL);
2937  assert(gubset != NULL);
2938  assert(solvals != NULL);
2939  assert(weights != NULL);
2940  assert(varsC1 != NULL);
2941  assert(varsC2 != NULL);
2942  assert(varsF != NULL);
2943  assert(varsR != NULL);
2944  assert(nvarsC1 > 0);
2945  assert(nvarsC2 >= 0);
2946  assert(nvarsF >= 0);
2947  assert(nvarsR >= 0);
2948  assert(gubconsGC1 != NULL);
2949  assert(gubconsGC2 != NULL);
2950  assert(gubconsGFC1 != NULL);
2951  assert(gubconsGR != NULL);
2952  assert(ngubconsGC1 != NULL);
2953  assert(ngubconsGC2 != NULL);
2954  assert(ngubconsGFC1 != NULL);
2955  assert(ngubconsGR != NULL);
2956  assert(maxgubvarssize != NULL);
2957 
2958  ngubconss = gubset->ngubconss;
2959  nvarsprocessed = 0;
2960  ngubconsGOC1 = 0;
2961 
2962  /* GUBs are categorized into different types according to the variables in volved
2963  * - GOC1: involves variables in C1 only -- no C2, R, F
2964  * - GNC1: involves variables in C1 and F (and R) -- no C2
2965  * - GF: involves variables in F (and R) only -- no C1, C2
2966  * - GC2: involves variables in C2 only -- no C1, R, F
2967  * - GR: involves variables in R only -- no C1, C2, F
2968  * which requires splitting GUBs in case they include variable in F and R.
2969  *
2970  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2971  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2972  * - second ordering level is
2973  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2974  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2975  * GR: non-increasing max{ a_k : k in GR_j}
2976  *
2977  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2978  * - GC1: GUBs of category GOC1 and GNC1
2979  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2980  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2981  */
2982 
2983  /* allocates temporary memory */
2984  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2985 #if 0 /* not required */
2986  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2987 #endif
2988  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2989  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2990 
2991 
2992  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2993  * - F: non-increasing x*_j and non-increasing a_j in case of equality
2994  * - C2: non-increasing a_j
2995  * - R: non-increasing a_j
2996  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2997  */
2998 
2999  /* gets sorting key for variables in C1 corresponding to the following ordering
3000  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3001  */
3002  for( j = 0; j < nvarsC1; j++ )
3003  {
3004  /* gets sortkeys */
3005  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3006 
3007  /* update status of variable in its gub constraint */
3008  gubconsidx = gubset->gubconssidx[varsC1[j]];
3009  varidx = gubset->gubvarsidx[varsC1[j]];
3010  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3011  }
3012 
3013  /* gets sorting key for variables in F corresponding to the following ordering
3014  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3015  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3016  * and updates status of each variable in F in GUB set data structure
3017  */
3018  for( j = 0; j < nvarsF; j++ )
3019  {
3020 #if 0 /* not required */
3021  /* gets sortkeys */
3022  SCIP_CALL( SCIPallocBuffer(scip, &sortkeypairsF[j]) );
3023  sortkeypairsF[j]->key1 = solvals[varsF[j]];
3024  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
3025 #endif
3026 
3027  /* update status of variable in its gub constraint */
3028  gubconsidx = gubset->gubconssidx[varsF[j]];
3029  varidx = gubset->gubvarsidx[varsF[j]];
3030  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3031  }
3032 
3033  /* gets sorting key for variables in C2 corresponding to the following ordering
3034  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3035  * and updates status of each variable in F in GUB set data structure
3036  */
3037  for( j = 0; j < nvarsC2; j++ )
3038  {
3039  /* gets sortkeys */
3040  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3041 
3042  /* update status of variable in its gub constraint */
3043  gubconsidx = gubset->gubconssidx[varsC2[j]];
3044  varidx = gubset->gubvarsidx[varsC2[j]];
3045  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3046  }
3047 
3048  /* gets sorting key for variables in R corresponding to the following ordering
3049  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3050  * and updates status of each variable in F in GUB set data structure
3051  */
3052  for( j = 0; j < nvarsR; j++ )
3053  {
3054  /* gets sortkeys */
3055  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3056 
3057  /* update status of variable in its gub constraint */
3058  gubconsidx = gubset->gubconssidx[varsR[j]];
3059  varidx = gubset->gubvarsidx[varsR[j]];
3060  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3061  }
3062 
3063  /* sorts C1, F, C2 and R */
3064  if( nvarsC1 > 0 )
3065  {
3066  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3067  }
3068 #if 0 /* not required */
3069  if( nvarsF > 0 )
3070  {
3071  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
3072  }
3073 #endif
3074  if( nvarsC2 > 0 )
3075  {
3076  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3077  }
3078  if( nvarsR > 0)
3079  {
3080  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3081  }
3082 
3083  /* frees temporary memory */
3084  SCIPfreeBufferArray(scip, &sortkeysR);
3085  SCIPfreeBufferArray(scip, &sortkeysC2);
3086 #if 0 /* not required */
3087  for( j = nvarsF-1; j >= 0; j-- )
3088  SCIPfreeBuffer(scip, &sortkeypairsF[j]);
3089  SCIPfreeBufferArray(scip, &sortkeypairsF);
3090 #endif
3091  SCIPfreeBufferArray(scip, &sortkeysC1);
3092 
3093  /* allocate and initialize temporary memory for sorting GUB constraints */
3094  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3095  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3096  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3097  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3098  for( i = 0; i < ngubconss; i++)
3099  {
3100  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3101  sortkeypairsGFC1[i]->key1 = 0.0;
3102  sortkeypairsGFC1[i]->key2 = 0.0;
3103  }
3104  *ngubconsGC1 = 0;
3105  *ngubconsGC2 = 0;
3106  *ngubconsGFC1 = 0;
3107  *ngubconsGR = 0;
3108  *ngubconscapexceed = 0;
3109  *maxgubvarssize = 0;
3110 
3111 #ifndef NDEBUG
3112  for( i = 0; i < gubset->ngubconss; i++ )
3113  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3114 #endif
3115 
3116  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3117  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3118  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3119  * non-increasing number of variables in F, and
3120  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3121  */
3122  for( i = 0; i < nvarsC1; i++ )
3123  {
3124  int nvarsC1capexceed;
3125 
3126  nvarsC1capexceed = 0;
3127 
3128  var = varsC1[i];
3129  gubconsidx = gubset->gubconssidx[var];
3130  varidx = gubset->gubvarsidx[var];
3131 
3132  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3133  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3134 
3135  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3136  * note that variables in C1 are already sorted by non-decreasing weigth
3137  */
3138  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3139  GUBsetSwapVars(scip, gubset, var, targetvar);
3140  nC1varsingubcons[gubconsidx]++;
3141 
3142  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3143  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3144  {
3145  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3146  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3147  continue;
3148  }
3149 
3150  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3151  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3152  */
3153 #if GUBSPLITGNC1GUBS
3154  gubconswithF = FALSE;
3155 #endif
3156  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3157  {
3158  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3159 
3160  /* C1-variable: update number of C1/capacity exceeding variables */
3161  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3162  {
3163  nvarsC1capexceed++;
3164  nvarsprocessed++;
3165  }
3166  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3167  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3168  {
3169 #if GUBSPLITGNC1GUBS
3170  gubconswithF = TRUE;
3171 #endif
3172  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3173 
3174  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3175  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3176  }
3177  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3178  {
3179  nvarsC1capexceed++;
3180  }
3181  else
3182  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3183  }
3184 
3185  /* update set of GC1 GUBs */
3186  gubconsGC1[*ngubconsGC1] = gubconsidx;
3187  (*ngubconsGC1)++;
3188 
3189  /* update maximum size of all GUB constraints */
3190  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3191  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3192 
3193  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3194  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3195  {
3196  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3197  ngubconsGOC1++;
3198  }
3199  else
3200  {
3201 #if GUBSPLITGNC1GUBS
3202  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3203  if( !gubconswithF )
3204  {
3205  GUBVARSTATUS movevarstatus;
3206 
3207  assert(gubset->ngubconss < gubset->nvars);
3208 
3209  /* create a new GUB for GR part of splitting */
3210  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3211  gubset->ngubconss++;
3212  ngubconss = gubset->ngubconss;
3213 
3214  /* fill GR with R variables in current GUB */
3215  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3216  {
3217  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3218  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3219  {
3220  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3221  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3222  gubconsidx, ngubconss-1) );
3223  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3224  movevarstatus;
3225  }
3226  }
3227 
3228  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3229  ngubconsGOC1++;
3230 
3231  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3232  gubconsGR[*ngubconsGR] = ngubconss-1;
3233  (*ngubconsGR)++;
3234  }
3235  /* variables in C1, F, and maybe R: GNC1 GUB */
3236  else
3237  {
3238  assert(gubconswithF);
3239 
3240  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3241  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3242  (*ngubconsGFC1)++;
3243  }
3244 #else
3245  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3246  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3247  (*ngubconsGFC1)++;
3248 #endif
3249  }
3250  }
3251 
3252  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3253  * are already sorted correctly
3254  */
3255  for( i = 0; i < nvarsC2; i++ )
3256  {
3257  var = varsC2[i];
3258  gubconsidx = gubset->gubconssidx[var];
3259  varidx = gubset->gubvarsidx[var];
3260 
3261  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3262  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3263  assert(varidx == 0);
3264  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3265  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3266 
3267  /* set status of GC2 GUB */
3268  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3269 
3270  /* update group of GC2 GUBs */
3271  gubconsGC2[*ngubconsGC2] = gubconsidx;
3272  (*ngubconsGC2)++;
3273 
3274  /* update maximum size of all GUB constraints */
3275  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3276  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3277 
3278  nvarsprocessed++;
3279  }
3280 
3281  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3282  * non-increasing number of variables in F, and
3283  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3284  */
3285  for( i = 0; i < nvarsF; i++ )
3286  {
3287  var = varsF[i];
3288  gubconsidx = gubset->gubconssidx[var];
3289  varidx = gubset->gubvarsidx[var];
3290 
3291  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3292  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3293 
3294  nvarsprocessed++;
3295 
3296  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3297  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3298  {
3299  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3300  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3301  continue;
3302  }
3303 
3304  /* set status of GF GUB */
3305  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3306 
3307  /* update sorting key of corresponding GFC1 GUB */
3308  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3309  {
3310  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3311  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3312 
3313  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3314  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3315  {
3316  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3317 
3318  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3319  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3320  }
3321  }
3322 
3323  /* update set of GFC1 GUBs */
3324  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3325  (*ngubconsGFC1)++;
3326 
3327  /* update maximum size of all GUB constraints */
3328  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3329  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3330  }
3331 
3332  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3333  * correctly
3334  */
3335  for( i = 0; i < nvarsR; i++ )
3336  {
3337  var = varsR[i];
3338  gubconsidx = gubset->gubconssidx[var];
3339  varidx = gubset->gubvarsidx[var];
3340 
3341  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3342  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3343 
3344  nvarsprocessed++;
3345 
3346  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3347  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3348  {
3349  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3350  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3351  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3352  continue;
3353  }
3354 
3355  /* set status of GR GUB */
3356  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3357 
3358  /* update set of GR GUBs */
3359  gubconsGR[*ngubconsGR] = gubconsidx;
3360  (*ngubconsGR)++;
3361 
3362  /* update maximum size of all GUB constraints */
3363  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3364  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3365  }
3366  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3367 
3368  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3369  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3370  assert(*ngubconscapexceed >= 0);
3371 #ifndef NDEBUG
3372  {
3373  int check;
3374 
3375  check = 0;
3376 
3377  /* remaining not handled GUBs should only contain capacity exceeding variables */
3378  for( i = 0; i < ngubconss; i++ )
3379  {
3380  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3381  check++;
3382  }
3383  assert(check == *ngubconscapexceed);
3384  }
3385 #endif
3386 
3387  /* sort GFCI GUBs according to computed sorting keys */
3388  if( (*ngubconsGFC1) > 0 )
3389  {
3390  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3391  }
3392 
3393  /* free temporary memory */
3394 #if GUBSPLITGNC1GUBS
3395  ngubconss = origngubconss;
3396 #endif
3397  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3398  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3399  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3400 
3401  return SCIP_OKAY;
3402 }
3403 
3404 /** enlarges minweight table to at least the given length */
3405 static
3407  SCIP* scip, /**< SCIP data structure */
3408  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3409  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3410  int* minweightssize, /**< pointer to current size of minweights table */
3411  int newlen /**< new length of minweights table */
3412  )
3413 {
3414  int j;
3415 
3416  assert(minweightsptr != NULL);
3417  assert(*minweightsptr != NULL);
3418  assert(minweightslen != NULL);
3419  assert(*minweightslen >= 0);
3420  assert(minweightssize != NULL);
3421  assert(*minweightssize >= 0);
3422 
3423  if( newlen > *minweightssize )
3424  {
3425  int newsize;
3426 
3427  /* reallocate table memory */
3428  newsize = SCIPcalcMemGrowSize(scip, newlen);
3429  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3430  *minweightssize = newsize;
3431  }
3432  assert(newlen <= *minweightssize);
3433 
3434  /* initialize new elements */
3435  for( j = *minweightslen; j < newlen; ++j )
3436  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3437  *minweightslen = newlen;
3438 
3439  return SCIP_OKAY;
3440 }
3441 
3442 /** lifts given inequality
3443  * sum_{j in M_1} x_j <= alpha_0
3444  * valid for
3445  * 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 }
3446  * to a valid inequality
3447  * 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
3448  * <= alpha_0 + sum_{j in M_2} alpha_j
3449  * for
3450  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3451  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3452  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3453  * extended weight inequalities.
3454  */
3455 static
3457  SCIP* scip, /**< SCIP data structure */
3458  SCIP_VAR** vars, /**< variables in knapsack constraint */
3459  int nvars, /**< number of variables in knapsack constraint */
3460  int ntightened, /**< number of variables with tightened upper bound */
3461  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3462  SCIP_Longint capacity, /**< capacity of knapsack */
3463  SCIP_Real* solvals, /**< solution values of all problem variables */
3464  int* varsM1, /**< variables in M_1 */
3465  int* varsM2, /**< variables in M_2 */
3466  int* varsF, /**< variables in F */
3467  int* varsR, /**< variables in R */
3468  int nvarsM1, /**< number of variables in M_1 */
3469  int nvarsM2, /**< number of variables in M_2 */
3470  int nvarsF, /**< number of variables in F */
3471  int nvarsR, /**< number of variables in R */
3472  int alpha0, /**< rights hand side of given valid inequality */
3473  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3474  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3475  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3476  )
3477 {
3478  SCIP_Longint* minweights;
3479  SCIP_Real* sortkeys;
3480  SCIP_Longint fixedonesweight;
3481  int minweightssize;
3482  int minweightslen;
3483  int j;
3484  int w;
3485 
3486  assert(scip != NULL);
3487  assert(vars != NULL);
3488  assert(nvars >= 0);
3489  assert(weights != NULL);
3490  assert(capacity >= 0);
3491  assert(solvals != NULL);
3492  assert(varsM1 != NULL);
3493  assert(varsM2 != NULL);
3494  assert(varsF != NULL);
3495  assert(varsR != NULL);
3496  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3497  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3498  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3499  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3500  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3501  assert(alpha0 >= 0);
3502  assert(liftcoefs != NULL);
3503  assert(cutact != NULL);
3504  assert(liftrhs != NULL);
3505 
3506  /* allocates temporary memory */
3507  minweightssize = nvarsM1 + 1;
3508  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3509  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3510 
3511  /* initializes data structures */
3512  BMSclearMemoryArray(liftcoefs, nvars);
3513  *cutact = 0.0;
3514 
3515  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3516  * and calculates activity of the current valid inequality
3517  */
3518  for( j = 0; j < nvarsM1; j++ )
3519  {
3520  assert(liftcoefs[varsM1[j]] == 0);
3521  liftcoefs[varsM1[j]] = 1;
3522  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3523  (*cutact) += solvals[varsM1[j]];
3524  }
3525 
3526  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3527 
3528  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3529  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3530  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3531  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3532  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3533  */
3534  minweights[0] = 0;
3535  for( w = 1; w <= nvarsM1; w++ )
3536  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3537  minweightslen = nvarsM1 + 1;
3538 
3539  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3540  fixedonesweight = 0;
3541  for( j = 0; j < nvarsM2; j++ )
3542  fixedonesweight += weights[varsM2[j]];
3543  assert(fixedonesweight >= 0);
3544 
3545  /* initializes right hand side of lifted valid inequality */
3546  *liftrhs = alpha0;
3547 
3548  /* sequentially up-lifts all variables in F: */
3549  for( j = 0; j < nvarsF; j++ )
3550  {
3551  SCIP_Longint weight;
3552  int liftvar;
3553  int liftcoef;
3554  int z;
3555 
3556  liftvar = varsF[j];
3557  weight = weights[liftvar];
3558  assert(liftvar >= 0 && liftvar < nvars);
3559  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3560  assert(weight > 0);
3561 
3562  /* knapsack problem is infeasible:
3563  * sets z = 0
3564  */
3565  if( capacity - fixedonesweight - weight < 0 )
3566  {
3567  z = 0;
3568  }
3569  /* knapsack problem is feasible:
3570  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3571  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3572  */
3573  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3574  {
3575  z = *liftrhs;
3576  }
3577  /* knapsack problem is feasible:
3578  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3579  */
3580  else
3581  {
3582  int left;
3583  int right;
3584  int middle;
3585 
3586  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3587  left = 0;
3588  right = (*liftrhs) + 1;
3589  while( left < right - 1 )
3590  {
3591  middle = (left + right) / 2;
3592  assert(0 <= middle && middle < minweightslen);
3593  if( minweights[middle] <= capacity - fixedonesweight - weight )
3594  left = middle;
3595  else
3596  right = middle;
3597  }
3598  assert(left == right - 1);
3599  assert(0 <= left && left < minweightslen);
3600  assert(minweights[left] <= capacity - fixedonesweight - weight );
3601  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3602 
3603  /* now z = left */
3604  z = left;
3605  assert(z <= *liftrhs);
3606  }
3607 
3608  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3609  liftcoef = (*liftrhs) - z;
3610  liftcoefs[liftvar] = liftcoef;
3611  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3612 
3613  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3614  if( liftcoef == 0 )
3615  continue;
3616 
3617  /* updates activity of current valid inequality */
3618  (*cutact) += liftcoef * solvals[liftvar];
3619 
3620  /* enlarges current minweight table:
3621  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3622  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3623  * and sets minweights_i[w] = infinity for
3624  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3625  */
3626  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3627 
3628  /* updates minweight table: minweight_i+1[w] =
3629  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3630  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3631  */
3632  for( w = minweightslen - 1; w >= 0; w-- )
3633  {
3634  SCIP_Longint min;
3635  if( w < liftcoef )
3636  {
3637  min = MIN(minweights[w], weight);
3638  minweights[w] = min;
3639  }
3640  else
3641  {
3642  assert(w >= liftcoef);
3643  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3644  minweights[w] = min;
3645  }
3646  }
3647  }
3648  assert(minweights[0] == 0);
3649 
3650  /* sequentially down-lifts all variables in M_2: */
3651  for( j = 0; j < nvarsM2; j++ )
3652  {
3653  SCIP_Longint weight;
3654  int liftvar;
3655  int liftcoef;
3656  int left;
3657  int right;
3658  int middle;
3659  int z;
3660 
3661  liftvar = varsM2[j];
3662  weight = weights[liftvar];
3663  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3664  assert(liftvar >= 0 && liftvar < nvars);
3665  assert(weight > 0);
3666 
3667  /* uses binary search to find
3668  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3669  */
3670  left = 0;
3671  right = minweightslen;
3672  while( left < right - 1 )
3673  {
3674  middle = (left + right) / 2;
3675  assert(0 <= middle && middle < minweightslen);
3676  if( minweights[middle] <= capacity - fixedonesweight + weight )
3677  left = middle;
3678  else
3679  right = middle;
3680  }
3681  assert(left == right - 1);
3682  assert(0 <= left && left < minweightslen);
3683  assert(minweights[left] <= capacity - fixedonesweight + weight );
3684  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3685 
3686  /* now z = left */
3687  z = left;
3688  assert(z >= *liftrhs);
3689 
3690  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3691  liftcoef = z - (*liftrhs);
3692  liftcoefs[liftvar] = liftcoef;
3693  assert(liftcoef >= 0);
3694 
3695  /* updates sum of weights of variables fixed to one */
3696  fixedonesweight -= weight;
3697 
3698  /* updates right-hand side of current valid inequality */
3699  (*liftrhs) += liftcoef;
3700  assert(*liftrhs >= alpha0);
3701 
3702  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3703  if( liftcoef == 0 )
3704  continue;
3705 
3706  /* updates activity of current valid inequality */
3707  (*cutact) += liftcoef * solvals[liftvar];
3708 
3709  /* enlarges current minweight table:
3710  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3711  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3712  * and sets minweights_i[w] = infinity for
3713  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3714  */
3715  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3716 
3717  /* updates minweight table: minweight_i+1[w] =
3718  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3719  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3720  */
3721  for( w = minweightslen - 1; w >= 0; w-- )
3722  {
3723  SCIP_Longint min;
3724  if( w < liftcoef )
3725  {
3726  min = MIN(minweights[w], weight);
3727  minweights[w] = min;
3728  }
3729  else
3730  {
3731  assert(w >= liftcoef);
3732  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3733  minweights[w] = min;
3734  }
3735  }
3736  }
3737  assert(fixedonesweight == 0);
3738  assert(*liftrhs >= alpha0);
3739 
3740  /* sequentially up-lifts all variables in R: */
3741  for( j = 0; j < nvarsR; j++ )
3742  {
3743  SCIP_Longint weight;
3744  int liftvar;
3745  int liftcoef;
3746  int z;
3747 
3748  liftvar = varsR[j];
3749  weight = weights[liftvar];
3750  assert(liftvar >= 0 && liftvar < nvars);
3751  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3752  assert(weight > 0);
3753  assert(capacity - weight >= 0);
3754  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3755 
3756  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3757  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3758  */
3759  if( minweights[*liftrhs] <= capacity - weight )
3760  {
3761  z = *liftrhs;
3762  }
3763  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3764  */
3765  else
3766  {
3767  int left;
3768  int right;
3769  int middle;
3770 
3771  left = 0;
3772  right = (*liftrhs) + 1;
3773  while( left < right - 1)
3774  {
3775  middle = (left + right) / 2;
3776  assert(0 <= middle && middle < minweightslen);
3777  if( minweights[middle] <= capacity - weight )
3778  left = middle;
3779  else
3780  right = middle;
3781  }
3782  assert(left == right - 1);
3783  assert(0 <= left && left < minweightslen);
3784  assert(minweights[left] <= capacity - weight );
3785  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3786 
3787  /* now z = left */
3788  z = left;
3789  assert(z <= *liftrhs);
3790  }
3791 
3792  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3793  liftcoef = (*liftrhs) - z;
3794  liftcoefs[liftvar] = liftcoef;
3795  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3796 
3797  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3798  if( liftcoef == 0 )
3799  continue;
3800 
3801  /* updates activity of current valid inequality */
3802  (*cutact) += liftcoef * solvals[liftvar];
3803 
3804  /* updates minweight table: minweight_i+1[w] =
3805  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3806  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3807  */
3808  for( w = *liftrhs; w >= 0; w-- )
3809  {
3810  SCIP_Longint min;
3811  if( w < liftcoef )
3812  {
3813  min = MIN(minweights[w], weight);
3814  minweights[w] = min;
3815  }
3816  else
3817  {
3818  assert(w >= liftcoef);
3819  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3820  minweights[w] = min;
3821  }
3822  }
3823  }
3824 
3825  /* frees temporary memory */
3826  SCIPfreeBufferArray(scip, &sortkeys);
3827  SCIPfreeBufferArray(scip, &minweights);
3828 
3829  return SCIP_OKAY;
3830 }
3831 
3832 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3833 static
3835  SCIP_Longint val1, /**< first value to add */
3836  SCIP_Longint val2 /**< second value to add */
3837  )
3838 {
3839  assert(val1 >= 0);
3840  assert(val2 >= 0);
3841 
3842  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3843  return SCIP_LONGINT_MAX;
3844  else
3845  {
3846  assert(val1 <= SCIP_LONGINT_MAX - val2);
3847  return (val1 + val2);
3848  }
3849 }
3850 
3851 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3852 static
3854  SCIP_Longint* minweights, /**< minweight table to compute */
3855  SCIP_Longint* finished, /**< given finished table */
3856  SCIP_Longint* unfinished, /**< given unfinished table */
3857  int minweightslen /**< length of minweight, finished, and unfinished tables */
3858  )
3859 {
3860  int w1;
3861  int w2;
3862 
3863  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3864  * note that finished and unfished arrays sorted by non-decreasing weight
3865  */
3866 
3867  /* initialize minweight with w2 = 0 */
3868  w2 = 0;
3869  assert(unfinished[w2] == 0);
3870  for( w1 = 0; w1 < minweightslen; w1++ )
3871  minweights[w1] = finished[w1];
3872 
3873  /* consider w2 = 1, ..., minweightslen-1 */
3874  for( w2 = 1; w2 < minweightslen; w2++ )
3875  {
3876  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3877  break;
3878 
3879  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3880  {
3881  SCIP_Longint temp;
3882 
3883  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3884  if( temp <= minweights[w1+w2] )
3885  minweights[w1+w2] = temp;
3886  }
3887  }
3888 }
3889 
3890 /** lifts given inequality
3891  * sum_{j in C_1} x_j <= alpha_0
3892  * valid for
3893  * 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;
3894  * sum_{j in Q_i} x_j <= 1, forall i in I }
3895  * to a valid inequality
3896  * 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
3897  * <= alpha_0 + sum_{j in C_2} alpha_j
3898  * for
3899  * 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 };
3900  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3901  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3902  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3903  */
3904 static
3906  SCIP* scip, /**< SCIP data structure */
3907  SCIP_GUBSET* gubset, /**< GUB set data structure */
3908  SCIP_VAR** vars, /**< variables in knapsack constraint */
3909  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3910  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3911  SCIP_Longint capacity, /**< capacity of knapsack */
3912  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3913  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3914  int* gubconsGC2, /**< GUBs in GC2 */
3915  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3916  int* gubconsGR, /**< GUBs in GR */
3917  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3918  int ngubconsGC2, /**< number of GUBs in GC2 */
3919  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3920  int ngubconsGR, /**< number of GUBs in GR */
3921  int alpha0, /**< rights hand side of given valid inequality */
3922  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3923  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3924  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3925  int maxgubvarssize /**< maximal size of GUB constraints */
3926  )
3927 {
3928  SCIP_Longint* minweights;
3929  SCIP_Longint* finished;
3930  SCIP_Longint* unfinished;
3931  int* gubconsGOC1;
3932  int* gubconsGNC1;
3933  int* liftgubvars;
3934  SCIP_Longint fixedonesweight;
3935  SCIP_Longint weight;
3936  SCIP_Longint weightdiff1;
3937  SCIP_Longint weightdiff2;
3938  SCIP_Longint min;
3939  int minweightssize;
3940  int minweightslen;
3941  int nvars;
3942  int varidx;
3943  int liftgubconsidx;
3944  int liftvar;
3945  int sumliftcoef;
3946  int liftcoef;
3947  int ngubconsGOC1;
3948  int ngubconsGNC1;
3949  int left;
3950  int right;
3951  int middle;
3952  int nliftgubvars;
3953  int tmplen;
3954  int tmpsize;
3955  int j;
3956  int k;
3957  int w;
3958  int z;
3959 #ifndef NDEBUG
3960  int ngubconss;
3961  int nliftgubC1;
3962 
3963  assert(gubset != NULL);
3964  ngubconss = gubset->ngubconss;
3965 #else
3966  assert(gubset != NULL);
3967 #endif
3968 
3969  nvars = gubset->nvars;
3970 
3971  assert(scip != NULL);
3972  assert(vars != NULL);
3973  assert(nvars >= 0);
3974  assert(weights != NULL);
3975  assert(capacity >= 0);
3976  assert(solvals != NULL);
3977  assert(gubconsGC1 != NULL);
3978  assert(gubconsGC2 != NULL);
3979  assert(gubconsGFC1 != NULL);
3980  assert(gubconsGR != NULL);
3981  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3982  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3983  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3984  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3985  assert(alpha0 >= 0);
3986  assert(liftcoefs != NULL);
3987  assert(cutact != NULL);
3988  assert(liftrhs != NULL);
3989 
3990  minweightssize = ngubconsGC1+1;
3991 
3992  /* allocates temporary memory */
3993  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3994  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3995  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3996  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3997  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3998  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3999 
4000  /* initializes data structures */
4001  BMSclearMemoryArray(liftcoefs, nvars);
4002  *cutact = 0.0;
4003 
4004  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4005  * valid inequality
4006  */
4007  ngubconsGOC1 = 0;
4008  ngubconsGNC1 = 0;
4009  for( j = 0; j < ngubconsGC1; j++ )
4010  {
4011  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4012  {
4013  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4014  ngubconsGOC1++;
4015  }
4016  else
4017  {
4018  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4019  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4020  ngubconsGNC1++;
4021  }
4022  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4023  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4024  {
4025  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4026  assert(varidx >= 0 && varidx < nvars);
4027  assert(liftcoefs[varidx] == 0);
4028 
4029  liftcoefs[varidx] = 1;
4030  (*cutact) += solvals[varidx];
4031  }
4032  assert(k >= 1);
4033  }
4034  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4035  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4036 
4037  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4038  * - finished_i[w] =
4039  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4040  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4041  * sum_{j in Q_k} x_j <= 1
4042  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4043  * - unfinished_i[w] =
4044  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4045  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4046  * sum_{j in Q_k} x_j <= 1
4047  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4048  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4049  */
4050 
4051  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4052  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4053  * 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
4054  * comes from the first variable in the GUB
4055  */
4056  assert(ngubconsGOC1 <= ngubconsGC1);
4057  finished[0] = 0;
4058  for( w = 1; w <= ngubconsGOC1; w++ )
4059  {
4060  liftgubconsidx = gubconsGOC1[w-1];
4061 
4062  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4063  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4064 
4065  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4066 
4067  assert(varidx >= 0 && varidx < nvars);
4068  assert(liftcoefs[varidx] == 1);
4069 
4070  min = weights[varidx];
4071  finished[w] = finished[w-1] + min;
4072 
4073 #ifndef NDEBUG
4074  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4075  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4076  {
4077  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4078  assert(varidx >= 0 && varidx < nvars);
4079  assert(liftcoefs[varidx] == 1);
4080  assert(weights[varidx] >= min);
4081  }
4082 #endif
4083  }
4084  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4085  finished[w] = SCIP_LONGINT_MAX;
4086 
4087  /* initialize unfinished table; note that variables in GNC1 GUBs
4088  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4089  * 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
4090  * comes from the first variable in the GUB
4091  */
4092  assert(ngubconsGNC1 <= ngubconsGC1);
4093  unfinished[0] = 0;
4094  for( w = 1; w <= ngubconsGNC1; w++ )
4095  {
4096  liftgubconsidx = gubconsGNC1[w-1];
4097 
4098  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4099  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4100 
4101  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4102 
4103  assert(varidx >= 0 && varidx < nvars);
4104  assert(liftcoefs[varidx] == 1);
4105 
4106  min = weights[varidx];
4107  unfinished[w] = unfinished[w-1] + min;
4108 
4109 #ifndef NDEBUG
4110  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4111  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4112  {
4113  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4114  assert(varidx >= 0 && varidx < nvars);
4115  assert(liftcoefs[varidx] == 1);
4116  assert(weights[varidx] >= min );
4117  }
4118 #endif
4119  }
4120  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4121  unfinished[w] = SCIP_LONGINT_MAX;
4122 
4123  /* initialize minweights table; note that variables in GC1 GUBs
4124  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4125  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4126  * consuming) because is it has to be build using weights from C1 only.
4127  */
4128  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4129  minweights[0] = 0;
4130  for( w = 1; w <= ngubconsGC1; w++ )
4131  {
4132  liftgubconsidx = gubconsGC1[w-1];
4133 
4134  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4135  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4136  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4137 
4138  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4139 
4140  assert(varidx >= 0 && varidx < nvars);
4141  assert(liftcoefs[varidx] == 1);
4142 
4143  min = weights[varidx];
4144  minweights[w] = minweights[w-1] + min;
4145 
4146 #ifndef NDEBUG
4147  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4148  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4149  {
4150  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4151  assert(varidx >= 0 && varidx < nvars);
4152  assert(liftcoefs[varidx] == 1);
4153  assert(weights[varidx] >= min);
4154  }
4155 #endif
4156  }
4157  minweightslen = ngubconsGC1 + 1;
4158 
4159  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4160  fixedonesweight = 0;
4161  for( j = 0; j < ngubconsGC2; j++ )
4162  {
4163  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4164 
4165  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4166  assert(varidx >= 0 && varidx < nvars);
4167  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4168 
4169  fixedonesweight += weights[varidx];
4170  }
4171  assert(fixedonesweight >= 0);
4172 
4173  /* initializes right hand side of lifted valid inequality */
4174  *liftrhs = alpha0;
4175 
4176  /* sequentially up-lifts all variables in GFC1 GUBs */
4177  for( j = 0; j < ngubconsGFC1; j++ )
4178  {
4179  liftgubconsidx = gubconsGFC1[j];
4180  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4181 
4182  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4183  * compute minweight table via updated unfinished table and aleady upto date finished table;
4184  */
4185  k = 0;
4186  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4187  {
4188  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4189  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4190  assert(ngubconsGNC1 > 0);
4191 
4192  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4193  * are considered for the lifting, i.e., not capacity exceeding
4194  */
4195  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4196  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4197  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4198  assert(k >= 1);
4199 
4200  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4201  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4202  */
4203  weight = weights[liftgubvars[0]];
4204 
4205  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4206  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4207  for( w = ngubconsGNC1-1; w >= 1; w-- )
4208  {
4209  weightdiff1 = weightdiff2;
4210  weightdiff2 = unfinished[w] - weight;
4211 
4212  if( unfinished[w] < weightdiff1 )
4213  unfinished[w] = weightdiff1;
4214  else
4215  break;
4216  }
4217  ngubconsGNC1--;
4218 
4219  /* computes minweights table by combining unfished and fished tables */
4220  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4221  assert(minweights[0] == 0);
4222  }
4223  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4224  * are therefore not in the unfinished table
4225  */
4226  else
4227  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4228 
4229 #ifndef NDEBUG
4230  nliftgubC1 = k;
4231 #endif
4232  nliftgubvars = k;
4233  sumliftcoef = 0;
4234 
4235  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4236  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4237  {
4238  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4239  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4240  {
4241  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4242  weight = weights[liftvar];
4243  assert(weight > 0);
4244  assert(liftvar >= 0 && liftvar < nvars);
4245  assert(capacity - weight >= 0);
4246 
4247  /* put variable into array of variables in GUB that are considered for the lifting,
4248  * i.e., not capacity exceeding
4249  */
4250  liftgubvars[nliftgubvars] = liftvar;
4251  nliftgubvars++;
4252 
4253  /* knapsack problem is infeasible:
4254  * sets z = 0
4255  */
4256  if( capacity - fixedonesweight - weight < 0 )
4257  {
4258  z = 0;
4259  }
4260  /* knapsack problem is feasible:
4261  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4262  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4263  */
4264  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4265  {
4266  z = *liftrhs;
4267  }
4268  /* knapsack problem is feasible:
4269  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4270  */
4271  else
4272  {
4273  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4274  left = 0;
4275  right = (*liftrhs) + 1;
4276  while( left < right - 1 )
4277  {
4278  middle = (left + right) / 2;
4279  assert(0 <= middle && middle < minweightslen);
4280  if( minweights[middle] <= capacity - fixedonesweight - weight )
4281  left = middle;
4282  else
4283  right = middle;
4284  }
4285  assert(left == right - 1);
4286  assert(0 <= left && left < minweightslen);
4287  assert(minweights[left] <= capacity - fixedonesweight - weight);
4288  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4289 
4290  /* now z = left */
4291  z = left;
4292  assert(z <= *liftrhs);
4293  }
4294 
4295  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4296  liftcoef = (*liftrhs) - z;
4297  liftcoefs[liftvar] = liftcoef;
4298  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4299 
4300  /* updates activity of current valid inequality */
4301  (*cutact) += liftcoef * solvals[liftvar];
4302 
4303  /* updates sum of all lifting coefficients in GUB */
4304  sumliftcoef += liftcoefs[liftvar];
4305  }
4306  else
4307  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4308  }
4309  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4310  assert(nliftgubvars > nliftgubC1);
4311 
4312  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4313  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4314  * not needed for GF GUBs
4315  */
4316  if( sumliftcoef == 0 )
4317  {
4318  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4319  {
4320  weight = weights[liftgubvars[0]];
4321  /* update finished table and minweights table by applying special case of
4322  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4323  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4324  */
4325  for( w = minweightslen-1; w >= 1; w-- )
4326  {
4327  SCIP_Longint tmpval;
4328 
4329  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4330  finished[w] = MIN(finished[w], tmpval);
4331 
4332  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4333  minweights[w] = MIN(minweights[w], tmpval);
4334  }
4335  }
4336  else
4337  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4338 
4339  continue;
4340  }
4341 
4342  /* enlarges current minweights tables(finished, unfinished, minweights):
4343  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4344  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4345  * and sets minweights_i[w] = infinity for
4346  * 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
4347  */
4348  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4349  tmpsize = minweightssize;
4350  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4351  tmplen = minweightslen;
4352  tmpsize = minweightssize;
4353  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4354  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4355 
4356  /* update finished table and minweight table;
4357  * note that instead of computing minweight table from updated finished and updated unfinished table again
4358  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4359  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4360  * not needed because only finished table changed at this point and the change was "adding" one weight)
4361  *
4362  * update formular for minweight table is: minweight_i+1[w] =
4363  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4364  * formular for finished table has the same pattern.
4365  */
4366  for( w = minweightslen-1; w >= 0; w-- )
4367  {
4368  SCIP_Longint minminweight;
4369  SCIP_Longint minfinished;
4370 
4371  for( k = 0; k < nliftgubvars; k++ )
4372  {
4373  liftcoef = liftcoefs[liftgubvars[k]];
4374  weight = weights[liftgubvars[k]];
4375 
4376  if( w < liftcoef )
4377  {
4378  minfinished = MIN(finished[w], weight);
4379  minminweight = MIN(minweights[w], weight);
4380 
4381  finished[w] = minfinished;
4382  minweights[w] = minminweight;
4383  }
4384  else
4385  {
4386  SCIP_Longint tmpval;
4387 
4388  assert(w >= liftcoef);
4389 
4390  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4391  minfinished = MIN(finished[w], tmpval);
4392 
4393  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4394  minminweight = MIN(minweights[w], tmpval);
4395 
4396  finished[w] = minfinished;
4397  minweights[w] = minminweight;
4398  }
4399  }
4400  }
4401  assert(minweights[0] == 0);
4402  }
4403  assert(ngubconsGNC1 == 0);
4404 
4405  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4406  * therefore, only work with minweight table from here on
4407  */
4408 
4409  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4410  for( j = 0; j < ngubconsGC2; j++ )
4411  {
4412  liftgubconsidx = gubconsGC2[j];
4413 
4414  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4415  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4416  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4417  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4418 
4419  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4420  weight = weights[liftvar];
4421 
4422  assert(liftvar >= 0 && liftvar < nvars);
4423  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4424  assert(weight > 0);
4425 
4426  /* uses binary search to find
4427  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4428  */
4429  left = 0;
4430  right = minweightslen;
4431  while( left < right - 1 )
4432  {
4433  middle = (left + right) / 2;
4434  assert(0 <= middle && middle < minweightslen);
4435  if( minweights[middle] <= capacity - fixedonesweight + weight )
4436  left = middle;
4437  else
4438  right = middle;
4439  }
4440  assert(left == right - 1);
4441  assert(0 <= left && left < minweightslen);
4442  assert(minweights[left] <= capacity - fixedonesweight + weight);
4443  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4444 
4445  /* now z = left */
4446  z = left;
4447  assert(z >= *liftrhs);
4448 
4449  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4450  liftcoef = z - (*liftrhs);
4451  liftcoefs[liftvar] = liftcoef;
4452  assert(liftcoef >= 0);
4453 
4454  /* updates sum of weights of variables fixed to one */
4455  fixedonesweight -= weight;
4456 
4457  /* updates right-hand side of current valid inequality */
4458  (*liftrhs) += liftcoef;
4459  assert(*liftrhs >= alpha0);
4460 
4461  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4462  if( liftcoef == 0 )
4463  continue;
4464 
4465  /* updates activity of current valid inequality */
4466  (*cutact) += liftcoef * solvals[liftvar];
4467 
4468  /* enlarges current minweight table:
4469  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4470  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4471  * and sets minweights_i[w] = infinity for
4472  * 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
4473  */
4474  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4475 
4476  /* updates minweight table: minweight_i+1[w] =
4477  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4478  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4479  */
4480  for( w = minweightslen - 1; w >= 0; w-- )
4481  {
4482  if( w < liftcoef )
4483  {
4484  min = MIN(minweights[w], weight);
4485  minweights[w] = min;
4486  }
4487  else
4488  {
4489  SCIP_Longint tmpval;
4490 
4491  assert(w >= liftcoef);
4492 
4493  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4494  min = MIN(minweights[w], tmpval);
4495  minweights[w] = min;
4496  }
4497  }
4498  }
4499  assert(fixedonesweight == 0);
4500  assert(*liftrhs >= alpha0);
4501 
4502  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4503  for( j = 0; j < ngubconsGR; j++ )
4504  {
4505  liftgubconsidx = gubconsGR[j];
4506 
4507  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4508  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4509 
4510  sumliftcoef = 0;
4511  nliftgubvars = 0;
4512  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4513  {
4514  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4515  {
4516  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4517  weight = weights[liftvar];
4518  assert(weight > 0);
4519  assert(liftvar >= 0 && liftvar < nvars);
4520  assert(capacity - weight >= 0);
4521  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4522 
4523  /* put variable into array of variables in GUB that are considered for the lifting,
4524  * i.e., not capacity exceeding
4525  */
4526  liftgubvars[nliftgubvars] = liftvar;
4527  nliftgubvars++;
4528 
4529  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4530  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4531  */
4532  if( minweights[*liftrhs] <= capacity - weight )
4533  {
4534  z = *liftrhs;
4535  }
4536  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4537  */
4538  else
4539  {
4540  left = 0;
4541  right = (*liftrhs) + 1;
4542  while( left < right - 1 )
4543  {
4544  middle = (left + right) / 2;
4545  assert(0 <= middle && middle < minweightslen);
4546  if( minweights[middle] <= capacity - weight )
4547  left = middle;
4548  else
4549  right = middle;
4550  }
4551  assert(left == right - 1);
4552  assert(0 <= left && left < minweightslen);
4553  assert(minweights[left] <= capacity - weight);
4554  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4555 
4556  /* now z = left */
4557  z = left;
4558  assert(z <= *liftrhs);
4559  }
4560  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4561  liftcoef = (*liftrhs) - z;
4562  liftcoefs[liftvar] = liftcoef;
4563  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4564 
4565  /* updates activity of current valid inequality */
4566  (*cutact) += liftcoef * solvals[liftvar];
4567 
4568  /* updates sum of all lifting coefficients in GUB */
4569  sumliftcoef += liftcoefs[liftvar];
4570  }
4571  else
4572  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4573  }
4574  assert(nliftgubvars >= 1); /* at least one variable is in R */
4575 
4576  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4577  if( sumliftcoef == 0 )
4578  continue;
4579 
4580  /* updates minweight table: minweight_i+1[w] =
4581  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4582  */
4583  for( w = *liftrhs; w >= 0; w-- )
4584  {
4585  for( k = 0; k < nliftgubvars; k++ )
4586  {
4587  liftcoef = liftcoefs[liftgubvars[k]];
4588  weight = weights[liftgubvars[k]];
4589 
4590  if( w < liftcoef )
4591  {
4592  min = MIN(minweights[w], weight);
4593  minweights[w] = min;
4594  }
4595  else
4596  {
4597  SCIP_Longint tmpval;
4598 
4599  assert(w >= liftcoef);
4600 
4601  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4602  min = MIN(minweights[w], tmpval);
4603  minweights[w] = min;
4604  }
4605  }
4606  }
4607  assert(minweights[0] == 0);
4608  }
4609 
4610  /* frees temporary memory */
4611  SCIPfreeBufferArray(scip, &minweights);
4612  SCIPfreeBufferArray(scip, &finished);
4613  SCIPfreeBufferArray(scip, &unfinished);
4614  SCIPfreeBufferArray(scip, &liftgubvars);
4615  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4616  SCIPfreeBufferArray(scip, &gubconsGNC1);
4617 
4618  return SCIP_OKAY;
4619 }
4620 
4621 /** lifts given minimal cover inequality
4622  * \f[
4623  * \sum_{j \in C} x_j \leq |C| - 1
4624  * \f]
4625  * valid for
4626  * \f[
4627  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4628  * \f]
4629  * to a valid inequality
4630  * \f[
4631  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4632  * \f]
4633  * for
4634  * \f[
4635  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4636  * \f]
4637  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4638  */
4639 static
4641  SCIP* scip, /**< SCIP data structure */
4642  SCIP_VAR** vars, /**< variables in knapsack constraint */
4643  int nvars, /**< number of variables in knapsack constraint */
4644  int ntightened, /**< number of variables with tightened upper bound */
4645  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4646  SCIP_Longint capacity, /**< capacity of knapsack */
4647  SCIP_Real* solvals, /**< solution values of all problem variables */
4648  int* covervars, /**< cover variables */
4649  int* noncovervars, /**< noncover variables */
4650  int ncovervars, /**< number of cover variables */
4651  int nnoncovervars, /**< number of noncover variables */
4652  SCIP_Longint coverweight, /**< weight of cover */
4653  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4654  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4655  )
4656 {
4657  SCIP_Longint* maxweightsums;
4658  SCIP_Longint* intervalends;
4659  SCIP_Longint* rhos;
4660  SCIP_Real* sortkeys;
4661  SCIP_Longint lambda;
4662  int j;
4663  int h;
4664 
4665  assert(scip != NULL);
4666  assert(vars != NULL);
4667  assert(nvars >= 0);
4668  assert(weights != NULL);
4669  assert(capacity >= 0);
4670  assert(solvals != NULL);
4671  assert(covervars != NULL);
4672  assert(noncovervars != NULL);
4673  assert(ncovervars > 0 && ncovervars <= nvars);
4674  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4675  assert(ncovervars + nnoncovervars == nvars - ntightened);
4676  assert(liftcoefs != NULL);
4677  assert(cutact != NULL);
4678 
4679  /* allocates temporary memory */
4680  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4681  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4682  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4683  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4684 
4685  /* initializes data structures */
4686  BMSclearMemoryArray(liftcoefs, nvars);
4687  *cutact = 0.0;
4688 
4689  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4690  * and calculates activity of current valid inequality
4691  */
4692  for( j = 0; j < ncovervars; j++ )
4693  {
4694  assert(liftcoefs[covervars[j]] == 0.0);
4695  liftcoefs[covervars[j]] = 1.0;
4696  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4697  (*cutact) += solvals[covervars[j]];
4698  }
4699  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4700 
4701  /* calculates weight excess of cover C */
4702  lambda = coverweight - capacity;
4703  assert(lambda > 0);
4704 
4705  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4706  maxweightsums[0] = 0;
4707  for( h = 1; h <= ncovervars; h++ )
4708  {
4709  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4710  intervalends[h-1] = maxweightsums[h] - lambda;
4711  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4712  }
4713 
4714  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4715  for( j = 0; j < nnoncovervars; j++ )
4716  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4717  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4718 
4719  /* calculates lifting coefficient for all variables in N\C */
4720  h = 0;
4721  for( j = 0; j < nnoncovervars; j++ )
4722  {
4723  int liftvar;
4724  SCIP_Longint weight;
4725  SCIP_Real liftcoef;
4726 
4727  liftvar = noncovervars[j];
4728  weight = weights[liftvar];
4729 
4730  while( intervalends[h] < weight )
4731  h++;
4732 
4733  if( h == 0 )
4734  liftcoef = h;
4735  else
4736  {
4737  if( weight <= intervalends[h-1] + rhos[h] )
4738  {
4739  SCIP_Real tmp1;
4740  SCIP_Real tmp2;
4741  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4742  tmp2 = (SCIP_Real) rhos[1];
4743  liftcoef = h - ( tmp1 / tmp2 );
4744  }
4745  else
4746  liftcoef = h;
4747  }
4748 
4749  /* sets lifting coefficient */
4750  assert(liftcoefs[liftvar] == 0.0);
4751  liftcoefs[liftvar] = liftcoef;
4752 
4753  /* updates activity of current valid inequality */
4754  (*cutact) += liftcoef * solvals[liftvar];
4755  }
4756 
4757  /* frees temporary memory */
4758  SCIPfreeBufferArray(scip, &rhos);
4759  SCIPfreeBufferArray(scip, &intervalends);
4760  SCIPfreeBufferArray(scip, &maxweightsums);
4761  SCIPfreeBufferArray(scip, &sortkeys);
4762 
4763  return SCIP_OKAY;
4764 }
4765 
4766 
4767 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4768  * given knapsack problem
4769 */
4770 static
4772  SCIP* scip, /**< SCIP data structure */
4773  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4774  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4775  SCIP_VAR** vars, /**< variables in knapsack constraint */
4776  int nvars, /**< number of variables in knapsack constraint */
4777  int ntightened, /**< number of variables with tightened upper bound */
4778  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4779  SCIP_Longint capacity, /**< capacity of knapsack */
4780  SCIP_Real* solvals, /**< solution values of all problem variables */
4781  int* mincovervars, /**< mincover variables */
4782  int* nonmincovervars, /**< nonmincover variables */
4783  int nmincovervars, /**< number of mincover variables */
4784  int nnonmincovervars, /**< number of nonmincover variables */
4785  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4786  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4787  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4788  int* ncuts /**< pointer to add up the number of found cuts */
4789  )
4790 {
4791  int* varsC1;
4792  int* varsC2;
4793  int* varsF;
4794  int* varsR;
4795  int nvarsC1;
4796  int nvarsC2;
4797  int nvarsF;
4798  int nvarsR;
4799  SCIP_Real cutact;
4800  int* liftcoefs;
4801  int liftrhs;
4802 
4803  assert( cutoff != NULL );
4804  *cutoff = FALSE;
4805 
4806  /* allocates temporary memory */
4807  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4808  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4809  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4810  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4811  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4812 
4813  /* 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
4814  * as follows
4815  * C_2 = { j in C : x*_j = 1 } and
4816  * C_1 = C\C_2
4817  */
4818  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4819  assert(nvarsC1 + nvarsC2 == nmincovervars);
4820  assert(nmincovervars > 0);
4821  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4822 
4823  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4824  if( nvarsC1 < 2 && nvarsC2 > 0)
4825  {
4826  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4827  assert(nvarsC1 >= 1);
4828  }
4829  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4830 
4831  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4832  * R = { j in N\C : x*_j = 0 } and
4833  * F = (N\C)\F
4834  */
4835  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4836  assert(nvarsF + nvarsR == nnonmincovervars);
4837  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4838 
4839  /* lift cuts without GUB information */
4840  if( gubset == NULL )
4841  {
4842  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4843  * lifting procedure
4844  */
4845  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4846 
4847  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4848  *
4849  * 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 }
4850  *
4851  * 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
4852  *
4853  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4854  *
4855  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4856  * up-lifting for the variables in R according to the second level lifting sequence
4857  */
4858  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4859  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4860  }
4861  /* lift cuts with GUB information */
4862  else
4863  {
4864  int* gubconsGC1;
4865  int* gubconsGC2;
4866  int* gubconsGFC1;
4867  int* gubconsGR;
4868  int ngubconsGC1;
4869  int ngubconsGC2;
4870  int ngubconsGFC1;
4871  int ngubconsGR;
4872  int ngubconss;
4873  int nconstightened;
4874  int maxgubvarssize;
4875 
4876  assert(nvars == gubset->nvars);
4877 
4878  ngubconsGC1 = 0;
4879  ngubconsGC2 = 0;
4880  ngubconsGFC1 = 0;
4881  ngubconsGR = 0;
4882  ngubconss = gubset->ngubconss;
4883  nconstightened = 0;
4884  maxgubvarssize = 0;
4885 
4886  /* allocates temporary memory */
4887  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4888  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4889  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4890  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4891 
4892  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4893  * the GUBs for the sequential GUB wise lifting procedure
4894  */
4895  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4896  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4897  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4898 
4899  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4900  *
4901  * 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,
4902  * sum_{j in Q_i} x_j <= 1, forall i in I }
4903  *
4904  * 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
4905  *
4906  * 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 },
4907  *
4908  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4909  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4910  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4911  */
4912  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4913  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4914  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4915 
4916  /* frees temporary memory */
4917  SCIPfreeBufferArray(scip, &gubconsGR);
4918  SCIPfreeBufferArray(scip, &gubconsGFC1);
4919  SCIPfreeBufferArray(scip, &gubconsGC2);
4920  SCIPfreeBufferArray(scip, &gubconsGC1);
4921  }
4922 
4923  /* checks, if lifting yielded a violated cut */
4924  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4925  {
4926  SCIP_ROW* row;
4927  char name[SCIP_MAXSTRLEN];
4928  int j;
4929 
4930  /* creates LP row */
4931  assert( cons == NULL || sepa == NULL );
4932  if ( cons != NULL )
4933  {
4934  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4935  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4936  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4937  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4938  }
4939  else if ( sepa != NULL )
4940  {
4941  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4942  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4943  }
4944  else
4945  {
4946  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
4947  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4948  }
4949 
4950  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4951  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4952  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4953  for( j = 0; j < nvarsC1; j++ )
4954  {
4955  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4956  }
4957  for( j = 0; j < nvarsC2; j++ )
4958  {
4959  if( liftcoefs[varsC2[j]] > 0 )
4960  {
4961  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4962  }
4963  }
4964  for( j = 0; j < nvarsF; j++ )
4965  {
4966  if( liftcoefs[varsF[j]] > 0 )
4967  {
4968  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4969  }
4970  }
4971  for( j = 0; j < nvarsR; j++ )
4972  {
4973  if( liftcoefs[varsR[j]] > 0 )
4974  {
4975  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4976  }
4977  }
4978  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4979 
4980  /* checks, if cut is violated enough */
4981  if( SCIPisCutEfficacious(scip, sol, row) )
4982  {
4983  if( cons != NULL )
4984  {
4985  SCIP_CALL( SCIPresetConsAge(scip, cons) );
4986  }
4987  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
4988  (*ncuts)++;
4989  }
4990  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4991  }
4992 
4993  /* frees temporary memory */
4994  SCIPfreeBufferArray(scip, &liftcoefs);
4995  SCIPfreeBufferArray(scip, &varsR);
4996  SCIPfreeBufferArray(scip, &varsF);
4997  SCIPfreeBufferArray(scip, &varsC2);
4998  SCIPfreeBufferArray(scip, &varsC1);
4999 
5000  return SCIP_OKAY;
5001 }
5002 
5003 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5004 static
5006  SCIP* scip, /**< SCIP data structure */
5007  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5008  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5009  SCIP_VAR** vars, /**< variables in knapsack constraint */
5010  int nvars, /**< number of variables in knapsack constraint */
5011  int ntightened, /**< number of variables with tightened upper bound */
5012  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5013  SCIP_Longint capacity, /**< capacity of knapsack */
5014  SCIP_Real* solvals, /**< solution values of all problem variables */
5015  int* feassetvars, /**< variables in feasible set */
5016  int* nonfeassetvars, /**< variables not in feasible set */
5017  int nfeassetvars, /**< number of variables in feasible set */
5018  int nnonfeassetvars, /**< number of variables not in feasible set */
5019  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5020  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5021  int* ncuts /**< pointer to add up the number of found cuts */
5022  )
5023 {
5024  int* varsT1;
5025  int* varsT2;
5026  int* varsF;
5027  int* varsR;
5028  int* liftcoefs;
5029  SCIP_Real cutact;
5030  int nvarsT1;
5031  int nvarsT2;
5032  int nvarsF;
5033  int nvarsR;
5034  int liftrhs;
5035  int j;
5036 
5037  assert( cutoff != NULL );
5038  *cutoff = FALSE;
5039 
5040  /* allocates temporary memory */
5041  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5042  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5043  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5044  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5045  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5046 
5047  /* 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
5048  * as follows
5049  * T_2 = { j in T : x*_j = 1 } and
5050  * T_1 = T\T_2
5051  */
5052  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5053  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5054 
5055  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5056  if( nvarsT1 == 0 && nvarsT2 > 0)
5057  {
5058  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5059  assert(nvarsT1 == 1);
5060  }
5061  assert(nvarsT2 == 0 || nvarsT1 > 0);
5062 
5063  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5064  * R = { j in N\T : x*_j = 0 } and
5065  * F = (N\T)\F
5066  */
5067  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5068  assert(nvarsF + nvarsR == nnonfeassetvars);
5069  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5070 
5071  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5072  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5073  * is included in the sorting routine)
5074  */
5075  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5076 
5077  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5078  *
5079  * 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 }
5080  *
5081  * 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
5082  *
5083  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5084  *
5085  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5086  * up-lifting for the variabels in R according to the second level lifting sequence
5087  */
5088  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5089  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5090 
5091  /* checks, if lifting yielded a violated cut */
5092  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5093  {
5094  SCIP_ROW* row;
5095  char name[SCIP_MAXSTRLEN];
5096 
5097  /* creates LP row */
5098  assert( cons == NULL || sepa == NULL );
5099  if( cons != NULL )
5100  {
5101  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5102  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5103  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5104  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5105  }
5106  else if ( sepa != NULL )
5107  {
5108  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5109  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5110  }
5111  else
5112  {
5113  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
5114  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5115  }
5116 
5117  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5118  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5119  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5120  for( j = 0; j < nvarsT1; j++ )
5121  {
5122  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5123  }
5124  for( j = 0; j < nvarsT2; j++ )
5125  {
5126  if( liftcoefs[varsT2[j]] > 0 )
5127  {
5128  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5129  }
5130  }
5131  for( j = 0; j < nvarsF; j++ )
5132  {
5133  if( liftcoefs[varsF[j]] > 0 )
5134  {
5135  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5136  }
5137  }
5138  for( j = 0; j < nvarsR; j++ )
5139  {
5140  if( liftcoefs[varsR[j]] > 0 )
5141  {
5142  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5143  }
5144  }
5145  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5146 
5147  /* checks, if cut is violated enough */
5148  if( SCIPisCutEfficacious(scip, sol, row) )
5149  {
5150  if( cons != NULL )
5151  {
5152  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5153  }
5154  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5155  (*ncuts)++;
5156  }
5157  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5158  }
5159 
5160  /* frees temporary memory */
5161  SCIPfreeBufferArray(scip, &liftcoefs);
5162  SCIPfreeBufferArray(scip, &varsR);
5163  SCIPfreeBufferArray(scip, &varsF);
5164  SCIPfreeBufferArray(scip, &varsT2);
5165  SCIPfreeBufferArray(scip, &varsT1);
5166 
5167  return SCIP_OKAY;
5168 }
5169 
5170 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5171 static
5173  SCIP* scip, /**< SCIP data structure */
5174  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5175  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5176  SCIP_VAR** vars, /**< variables in knapsack constraint */
5177  int nvars, /**< number of variables in knapsack constraint */
5178  int ntightened, /**< number of variables with tightened upper bound */
5179  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5180  SCIP_Longint capacity, /**< capacity of knapsack */
5181  SCIP_Real* solvals, /**< solution values of all problem variables */
5182  int* mincovervars, /**< mincover variables */
5183  int* nonmincovervars, /**< nonmincover variables */
5184  int nmincovervars, /**< number of mincover variables */
5185  int nnonmincovervars, /**< number of nonmincover variables */
5186  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5187  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5188  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5189  int* ncuts /**< pointer to add up the number of found cuts */
5190  )
5191 {
5192  SCIP_Real* realliftcoefs;
5193  SCIP_Real cutact;
5194  int liftrhs;
5195 
5196  assert( cutoff != NULL );
5197  *cutoff = FALSE;
5198  cutact = 0.0;
5199 
5200  /* allocates temporary memory */
5201  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5202 
5203  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5204  *
5205  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5206  *
5207  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5208  *
5209  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5210  *
5211  * uses superadditive up-lifting for the variables in N\C.
5212  */
5213  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5214  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5215  liftrhs = nmincovervars - 1;
5216 
5217  /* checks, if lifting yielded a violated cut */
5218  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5219  {
5220  SCIP_ROW* row;
5221  char name[SCIP_MAXSTRLEN];
5222  int j;
5223 
5224  /* creates LP row */
5225  assert( cons == NULL || sepa == NULL );
5226  if ( cons != NULL )
5227  {
5228  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5229  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5230  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5231  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5232  }
5233  else if ( sepa != NULL )
5234  {
5235  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5236  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5237  }
5238  else
5239  {
5240  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%" SCIP_LONGINT_FORMAT "", *ncuts);
5241  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5242  }
5243 
5244  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5245  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5246  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5247  for( j = 0; j < nmincovervars; j++ )
5248  {
5249  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5250  }
5251  for( j = 0; j < nnonmincovervars; j++ )
5252  {
5253  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5254  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5255  {
5256  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5257  }
5258  }
5259  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5260 
5261  /* checks, if cut is violated enough */
5262  if( SCIPisCutEfficacious(scip, sol, row) )
5263  {
5264  if( cons != NULL )
5265  {
5266  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5267  }
5268  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5269  (*ncuts)++;
5270  }
5271  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5272  }
5273 
5274  /* frees temporary memory */
5275  SCIPfreeBufferArray(scip, &realliftcoefs);
5276 
5277  return SCIP_OKAY;
5278 }
5279 
5280 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5281  * 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
5282  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5283  * note that all variables with x*_j = 1 will be removed last
5284  */
5285 static
5287  SCIP* scip, /**< SCIP data structure */
5288  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5289  SCIP_Longint capacity, /**< capacity of knapsack */
5290  SCIP_Real* solvals, /**< solution values of all problem variables */
5291  int* covervars, /**< pointer to store cover variables */
5292  int* noncovervars, /**< pointer to store noncover variables */
5293  int* ncovervars, /**< pointer to store number of cover variables */
5294  int* nnoncovervars, /**< pointer to store number of noncover variables */
5295  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5296  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5297  )
5298 {
5299  SORTKEYPAIR** sortkeypairs;
5300  SCIP_Longint minweight;
5301  int nsortkeypairs;
5302  int minweightidx;
5303  int j;
5304  int k;
5305 
5306  assert(scip != NULL);
5307  assert(covervars != NULL);
5308  assert(noncovervars != NULL);
5309  assert(ncovervars != NULL);
5310  assert(*ncovervars > 0);
5311  assert(nnoncovervars != NULL);
5312  assert(*nnoncovervars >= 0);
5313  assert(coverweight != NULL);
5314  assert(*coverweight > 0);
5315  assert(*coverweight > capacity);
5316 
5317  /* allocates temporary memory */
5318  nsortkeypairs = *ncovervars;
5319  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5320 
5321  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5322  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5323  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5324  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5325  */
5326  assert(*ncovervars == nsortkeypairs);
5327  if( modtransused )
5328  {
5329  for( j = 0; j < *ncovervars; j++ )
5330  {
5331  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5332 
5333  sortkeypairs[j]->key1 = solvals[covervars[j]];
5334  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5335  }
5336  }
5337  else
5338  {
5339  for( j = 0; j < *ncovervars; j++ )
5340  {
5341  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5342 
5343  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5344  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5345  }
5346  }
5347  SCIPsortPtrInt((void**)sortkeypairs, covervars, compSortkeypairs, *ncovervars);
5348 
5349  /* gets j' with a_j' = min{ a_j : j in C } */
5350  minweightidx = 0;
5351  minweight = weights[covervars[minweightidx]];
5352  for( j = 1; j < *ncovervars; j++ )
5353  {
5354  if( weights[covervars[j]] <= minweight )
5355  {
5356  minweightidx = j;
5357  minweight = weights[covervars[minweightidx]];
5358  }
5359  }
5360  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5361  assert(minweight > 0 && minweight <= *coverweight);
5362 
5363  j = 0;
5364  /* removes variables from C until the remaining variables form a minimal cover */
5365  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5366  {
5367  assert(minweightidx >= j);
5368  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5369 
5370  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5371  if( (*coverweight) - weights[covervars[j]] <= capacity )
5372  {
5373  ++j;
5374  continue;
5375  }
5376 
5377  /* adds j to N\C */
5378  noncovervars[*nnoncovervars] = covervars[j];
5379  (*nnoncovervars)++;
5380 
5381  /* removes j from C */
5382  (*coverweight) -= weights[covervars[j]];
5383  for( k = j; k < (*ncovervars) - 1; k++ )
5384  covervars[k] = covervars[k+1];
5385  (*ncovervars)--;
5386 
5387  /* updates j' with a_j' = min{ a_j : j in C } */
5388  if( j == minweightidx )
5389  {
5390  minweightidx = 0;
5391  minweight = weights[covervars[minweightidx]];
5392  for( k = 1; k < *ncovervars; k++ )
5393  {
5394  if( weights[covervars[k]] <= minweight )
5395  {
5396  minweightidx = k;
5397  minweight = weights[covervars[minweightidx]];
5398  }
5399  }
5400  assert(minweight > 0 && minweight <= *coverweight);
5401  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5402  }
5403  else
5404  {
5405  assert(minweightidx > j);
5406  minweightidx--;
5407  }
5408  /* j needs to stay the same */
5409  }
5410  assert((*coverweight) > capacity);
5411  assert((*coverweight) - minweight <= capacity);
5412 
5413  /* frees temporary memory */
5414  for( j = nsortkeypairs-1; j >= 0; j-- )
5415  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5416  SCIPfreeBufferArray(scip, &sortkeypairs);
5417 
5418  return SCIP_OKAY;
5419 }
5420 
5421 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5422  * they were chosen to be in C_init:
5423  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5424  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5425  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5426  * and all subsequent feasible sets.
5427  */
5428 static
5430  SCIP* scip, /**< SCIP data structure */
5431  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5432  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5433  SCIP_VAR** vars, /**< variables in knapsack constraint */
5434  int nvars, /**< number of variables in knapsack constraint */
5435  int ntightened, /**< number of variables with tightened upper bound */
5436  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5437  SCIP_Longint capacity, /**< capacity of knapsack */
5438  SCIP_Real* solvals, /**< solution values of all problem variables */
5439  int* covervars, /**< pointer to store cover variables */
5440  int* noncovervars, /**< pointer to store noncover variables */
5441  int* ncovervars, /**< pointer to store number of cover variables */
5442  int* nnoncovervars, /**< pointer to store number of noncover variables */
5443  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5444  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5445  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5446  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5447  int* ncuts /**< pointer to add up the number of found cuts */
5448  )
5449 {
5450  SCIP_Real* sortkeys;
5451  int j;
5452  int k;
5453 
5454  assert(scip != NULL);
5455  assert(covervars != NULL);
5456  assert(noncovervars != NULL);
5457  assert(ncovervars != NULL);
5458  assert(*ncovervars > 0);
5459  assert(nnoncovervars != NULL);
5460  assert(*nnoncovervars >= 0);
5461  assert(coverweight != NULL);
5462  assert(*coverweight > 0);
5463  assert(*coverweight > capacity);
5464  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5465  assert(cutoff != NULL);
5466 
5467  *cutoff = FALSE;
5468 
5469  /* allocates temporary memory */
5470  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5471 
5472  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5473  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5474  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5475  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5476  */
5477  if( modtransused )
5478  {
5479  for( j = 0; j < *ncovervars; j++ )
5480  {
5481  sortkeys[j] = solvals[covervars[j]];
5482  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5483  }
5484  }
5485  else
5486  {
5487  for( j = 0; j < *ncovervars; j++ )
5488  {
5489  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5490  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5491  }
5492  }
5493  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5494 
5495  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5496  * in addition to an extended weight inequality this gives cardinality inequalities */
5497  while( *ncovervars >= 2 )
5498  {
5499  /* adds first element of C_init to N\C_init */
5500  noncovervars[*nnoncovervars] = covervars[0];
5501  (*nnoncovervars)++;
5502 
5503  /* removes first element from C_init */
5504  (*coverweight) -= weights[covervars[0]];
5505  for( k = 0; k < (*ncovervars) - 1; k++ )
5506  covervars[k] = covervars[k+1];
5507  (*ncovervars)--;
5508 
5509  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5510  if( (*coverweight) <= capacity )
5511  {
5512  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5513  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5514  }
5515 
5516  /* stop if cover is too large */
5517  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5518  break;
5519  }
5520 
5521  /* frees temporary memory */
5522  SCIPfreeBufferArray(scip, &sortkeys);
5523 
5524  return SCIP_OKAY;
5525 }
5526 
5527 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5529  SCIP* scip, /**< SCIP data structure */
5530  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5531  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5532  SCIP_VAR** vars, /**< variables in knapsack constraint */
5533  int nvars, /**< number of variables in knapsack constraint */
5534  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5535  SCIP_Longint capacity, /**< capacity of knapsack */
5536  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5537  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5538  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5539  int* ncuts /**< pointer to add up the number of found cuts */
5540  )
5541 {
5542  SCIP_Real* solvals;
5543  int* covervars;
5544  int* noncovervars;
5545  SCIP_Bool coverfound;
5546  SCIP_Bool fractional;
5547  SCIP_Bool modtransused;
5548  SCIP_Longint coverweight;
5549  int ncovervars;
5550  int nnoncovervars;
5551  int ntightened;
5552 
5553  assert(scip != NULL);
5554  assert(capacity >= 0);
5555  assert(cutoff != NULL);
5556  assert(ncuts != NULL);
5557 
5558  *cutoff = FALSE;
5559 
5560  if( nvars == 0 )
5561  return SCIP_OKAY;
5562 
5563  assert(vars != NULL);
5564  assert(nvars > 0);
5565  assert(weights != NULL);
5566 
5567  /* increase age of constraint (age is reset to zero, if a cut was found) */
5568  if( cons != NULL )
5569  {
5570  SCIP_CALL( SCIPincConsAge(scip, cons) );
5571  }
5572 
5573  /* allocates temporary memory */
5574  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5575  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5576  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5577 
5578  /* gets solution values of all problem variables */
5579  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5580 
5581 #ifdef SCIP_DEBUG
5582  {
5583  int i;
5584 
5585  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5586  cons == NULL ? "-" : SCIPconsGetName(cons));
5587  for( i = 0; i < nvars; ++i )
5588  {
5589  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5590  }
5591  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5592  }
5593 #endif
5594 
5595  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5596  */
5597  if( usegubs )
5598  {
5599  SCIP_GUBSET* gubset;
5600 
5601  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5602 
5603  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5604  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5605 
5606  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5607  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5608  assert(gubset->ngubconss <= nvars);
5609 
5610  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5611  * MODIFIED transformed separation problem and taking into account the following fixing:
5612  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5613  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5614  * if one exists
5615  */
5616  modtransused = TRUE;
5617  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5618  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5619 
5620  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5621 
5622  /* if x* is not fractional we stop the separation routine */
5623  if( !fractional )
5624  {
5625  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5626 
5627  /* frees memory for GUB set data structure */
5628  SCIP_CALL( GUBsetFree(scip, &gubset) );
5629 
5630  goto TERMINATE;
5631  }
5632 
5633  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5634  if( coverfound )
5635  {
5636  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5637  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5638  */
5639  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5640  &nnoncovervars, &coverweight, modtransused) );
5641 
5642  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5643  if( gubset->ngubconss < nvars )
5644  {
5645  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5646  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5647  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5648  }
5649  else
5650  {
5651  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5652  * GUB information
5653  */
5654  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5655  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5656  }
5657  }
5658 
5659  /* frees memory for GUB set data structure */
5660  SCIP_CALL( GUBsetFree(scip, &gubset) );
5661  }
5662  else
5663  {
5664  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5665  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5666  */
5667 
5668  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5669  * MODIFIED transformed separation problem and taking into account the following fixing:
5670  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5671  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5672  * if one exists
5673  */
5674  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5675  modtransused = TRUE;
5676  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5677  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5678  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5679 
5680  /* if x* is not fractional we stop the separation routine */
5681  if( !fractional )
5682  goto TERMINATE;
5683 
5684  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5685  if( coverfound )
5686  {
5687  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5688  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5689  */
5690  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5691  &nnoncovervars, &coverweight, modtransused) );
5692 
5693  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5694  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5695  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5696 
5697  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5698  {
5699  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5700  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5701  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5702  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5703  }
5704  }
5705  }
5706 
5707  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5708  if ( ! (*cutoff) )
5709  {
5710  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5711  * transformed separation problem and taking into account the following fixing:
5712  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5713  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5714  * if one exists
5715  */
5716  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5717  modtransused = FALSE;
5718  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5719  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5720  assert(fractional);
5721  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5722 
5723  /* if no cover was found we stop the separation routine */
5724  if( coverfound )
5725  {
5726  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5727  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5728  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5729  */
5730  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5731  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5732  }
5733  }
5734 
5735  TERMINATE:
5736  /* frees temporary memory */
5737  SCIPfreeBufferArray(scip, &noncovervars);
5738  SCIPfreeBufferArray(scip, &covervars);
5739  SCIPfreeBufferArray(scip, &solvals);
5740 
5741  return SCIP_OKAY;
5742 }
5743 
5744 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5746  SCIP* scip, /**< SCIP data structure */
5747  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5748  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5749  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5750  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5751  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5752  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5753  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5754  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5755  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5756  int* ncuts /**< pointer to add up the number of found cuts */
5757  )
5758 {
5759  SCIP_VAR** binvars;
5760  SCIP_VAR** consvars;
5761  SCIP_Real* binvals;
5762  SCIP_Longint* consvals;
5763  SCIP_Longint minact;
5764  SCIP_Longint maxact;
5765  SCIP_Real intscalar;
5766  SCIP_Bool success;
5767  int nbinvars;
5768  int nconsvars;
5769  int i;
5770 
5771  int* tmpindices;
5772  int tmp;
5773  SCIP_CONSHDLR* conshdlr;
5774  SCIP_CONSHDLRDATA* conshdlrdata;
5775  SCIP_Bool noknapsackconshdlr;
5776  SCIP_Bool usegubs;
5777 
5778  assert(nknapvars > 0);
5779  assert(knapvars != NULL);
5780  assert(cutoff != NULL);
5781 
5782  tmpindices = NULL;
5783 
5784  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5785  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5786 
5787  binvars = SCIPgetVars(scip);
5788 
5789  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5790  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5791 
5792  *cutoff = FALSE;
5793 
5794  if( nbinvars == 0 )
5795  return SCIP_OKAY;
5796 
5797  /* set up data structures */
5798  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5799  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5800 
5801  /* get conshdlrdata to use cleared memory */
5802  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5803  if( conshdlr == NULL )
5804  {
5805  noknapsackconshdlr = TRUE;
5806  usegubs = DEFAULT_USEGUBS;
5807 
5808  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5809  BMSclearMemoryArray(binvals, nbinvars);
5810  }
5811  else
5812  {
5813  noknapsackconshdlr = FALSE;
5814  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5815  assert(conshdlrdata != NULL);
5816  usegubs = conshdlrdata->usegubs;
5817 
5818  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5819 
5820  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5821  * change their types to SCIP_VARTYPE_BINARY during presolving
5822  */
5823  if( conshdlrdata->reals1size == 0 )
5824  {
5825  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5826  conshdlrdata->reals1size = 1;
5827  conshdlrdata->reals1[0] = 0.0;
5828  }
5829 
5830  assert(conshdlrdata->reals1size > 0);
5831 
5832  /* next if condition should normally not be true, because it means that presolving has created more binary
5833  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5834  * transform all integers into their binary representation then it maybe happens
5835  */
5836  if( conshdlrdata->reals1size < nbinvars )
5837  {
5838  int oldsize = conshdlrdata->reals1size;
5839 
5840  conshdlrdata->reals1size = nbinvars;
5841  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5842  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5843  }
5844  binvals = conshdlrdata->reals1;
5845 
5846  /* check for cleared array, all entries have to be zero */
5847 #ifndef NDEBUG
5848  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5849  {
5850  assert(binvals[tmp] == 0);
5851  }
5852 #endif
5853  }
5854 
5855  tmp = 0;
5856 
5857  /* relax continuous knapsack constraint:
5858  * 1. make all variables binary:
5859  * if x_j is continuous or integer variable substitute:
5860  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5861  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5862  * 2. convert coefficients of all variables to positive integers:
5863  * - scale all coefficients a_j to a~_j integral
5864  * - substitute x~_j = 1 - x_j if a~_j < 0
5865  */
5866 
5867  /* replace integer and continuous variables with binary variables */
5868  for( i = 0; i < nknapvars; i++ )
5869  {
5870  SCIP_VAR* var;
5871 
5872  var = knapvars[i];
5873 
5874  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5875  {
5876  SCIP_Real solval;
5877  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5878 
5879  solval = SCIPgetSolVal(scip, sol, var);
5880 
5881  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5882  if( SCIPisFeasLT(scip, solval, 0.0 )
5883  || SCIPisFeasGT(scip, solval, 1.0) )
5884  {
5885  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5886  solval, SCIPvarGetName(var));
5887  goto TERMINATE;
5888  }
5889 
5890  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5891  if( !noknapsackconshdlr )
5892  {
5893  assert(tmpindices != NULL);
5894 
5895  tmpindices[tmp] = SCIPvarGetProbindex(var);
5896  ++tmp;
5897  }
5898  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5899  }
5900  else if( valscale * knapvals[i] > 0.0 )
5901  {
5902  SCIP_VAR** zvlb;
5903  SCIP_Real* bvlb;
5904  SCIP_Real* dvlb;
5905  SCIP_Real bestlbsol;
5906  int bestlbtype;
5907  int nvlb;
5908  int j;
5909 
5910  /* a_j > 0: substitution with lb or vlb */
5911  nvlb = SCIPvarGetNVlbs(var);
5912  zvlb = SCIPvarGetVlbVars(var);
5913  bvlb = SCIPvarGetVlbCoefs(var);
5914  dvlb = SCIPvarGetVlbConstants(var);
5915 
5916  /* search for lb or vlb with maximal bound value */
5917  bestlbsol = SCIPvarGetLbGlobal(var);
5918  bestlbtype = -1;
5919  for( j = 0; j < nvlb; j++ )
5920  {
5921  /* use only numerical stable vlb with binary variable z */
5922  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5923  {
5924  SCIP_Real vlbsol;
5925 
5926  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5927  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5928  {
5929  *cutoff = TRUE;
5930  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5932  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5933  goto TERMINATE;
5934  }
5935 
5936  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5937  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5938  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5939  {
5940  bestlbsol = vlbsol;
5941  bestlbtype = j;
5942  }
5943  }
5944  }
5945 
5946  /* if no lb or vlb with binary variable was found, we have to abort */
5947  if( SCIPisInfinity(scip, -bestlbsol) )
5948  goto TERMINATE;
5949 
5950  if( bestlbtype == -1 )
5951  {
5952  rhs -= valscale * knapvals[i] * bestlbsol;
5953  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5954  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5955  }
5956  else
5957  {
5958  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5959  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5960  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5961 
5962  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5963  goto TERMINATE;
5964 
5965  if( !noknapsackconshdlr )
5966  {
5967  assert(tmpindices != NULL);
5968 
5969  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5970  ++tmp;
5971  }
5972  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5973  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5974  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5975  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5976  }
5977  }
5978  else
5979  {
5980  SCIP_VAR** zvub;
5981  SCIP_Real* bvub;
5982  SCIP_Real* dvub;
5983  SCIP_Real bestubsol;
5984  int bestubtype;
5985  int nvub;
5986  int j;
5987 
5988  assert(valscale * knapvals[i] < 0.0);
5989 
5990  /* a_j < 0: substitution with ub or vub */
5991  nvub = SCIPvarGetNVubs(var);
5992  zvub = SCIPvarGetVubVars(var);
5993  bvub = SCIPvarGetVubCoefs(var);
5994  dvub = SCIPvarGetVubConstants(var);
5995 
5996  /* search for ub or vub with minimal bound value */
5997  bestubsol = SCIPvarGetUbGlobal(var);
5998  bestubtype = -1;
5999  for( j = 0; j < nvub; j++ )
6000  {
6001  /* use only numerical stable vub with active binary variable z */
6002  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6003  {
6004  SCIP_Real vubsol;
6005 
6006  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6007  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6008  {
6009  *cutoff = TRUE;
6010  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6012  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6013  goto TERMINATE;
6014  }
6015 
6016  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6017  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6018  if( SCIPisLE(scip, vubsol, bestubsol) )
6019  {
6020  bestubsol = vubsol;
6021  bestubtype = j;
6022  }
6023  }
6024  }
6025 
6026  /* if no ub or vub with binary variable was found, we have to abort */
6027  if( SCIPisInfinity(scip, bestubsol) )
6028  goto TERMINATE;
6029 
6030  if( bestubtype == -1 )
6031  {
6032  rhs -= valscale * knapvals[i] * bestubsol;
6033  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6034  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6035  }
6036  else
6037  {
6038  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6039  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6040  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6041 
6042  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6043  goto TERMINATE;
6044 
6045  if( !noknapsackconshdlr )
6046  {
6047  assert(tmpindices != NULL);
6048 
6049  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6050  ++tmp;
6051  }
6052  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6053  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6054  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6055  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6056  }
6057  }
6058  }
6059 
6060  /* convert coefficients of all (now binary) variables to positive integers:
6061  * - make all coefficients integral
6062  * - make all coefficients positive (substitute negated variable)
6063  */
6064  nconsvars = 0;
6065 
6066  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6067  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6068  */
6070  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6071  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6072 
6073  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6074  if( !success )
6075  intscalar = 1.0;
6076 
6077  /* make all coefficients integral and positive:
6078  * - scale a~_j = a_j * intscalar
6079  * - substitute x~_j = 1 - x_j if a~_j < 0
6080  */
6081  rhs = rhs*intscalar;
6082 
6083  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6084  minact = 0;
6085  maxact = 0;
6086  for( i = 0; i < nbinvars; i++ )
6087  {
6088  SCIP_VAR* var;
6089  SCIP_Longint val;
6090 
6091  val = (SCIP_Longint)SCIPfloor(scip, binvals[i]*intscalar);
6092  if( val == 0 )
6093  continue;
6094 
6095  if( val > 0 )
6096  {
6097  var = binvars[i];
6098  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6099  val, SCIPvarGetName(var), binvals[i], rhs);
6100  }
6101  else
6102  {
6103  assert(val < 0);
6104 
6105  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6106  val = -val;
6107  rhs += val;
6108  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6109  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6110  }
6111 
6112  if( SCIPvarGetLbLocal(var) > 0.5 )
6113  minact += val;
6114  if( SCIPvarGetUbLocal(var) > 0.5 )
6115  maxact += val;
6116  consvals[nconsvars] = val;
6117  consvars[nconsvars] = var;
6118  nconsvars++;
6119  }
6120 
6121  if( nconsvars > 0 )
6122  {
6123  SCIP_Longint capacity;
6124 
6125  assert(consvars != NULL);
6126  assert(consvals != NULL);
6127  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6128 
6129 #ifdef SCIP_DEBUG
6130  {
6131  SCIP_Real act;
6132 
6133  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6134  act = 0.0;
6135  for( i = 0; i < nconsvars; ++i )
6136  {
6137  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6138  SCIPgetSolVal(scip, sol, consvars[i]));
6139  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6140  }
6141  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6142  capacity, rhs, act, minact, maxact);
6143  }
6144 #endif
6145 
6146  if( minact > capacity )
6147  {
6148  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6149  *cutoff = TRUE;
6150  goto TERMINATE;
6151  }
6152 
6153  if( maxact > capacity )
6154  {
6155  /* separate lifted cut from relaxed knapsack constraint */
6156  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6157  }
6158  }
6159 
6160  TERMINATE:
6161  /* free data structures */
6162  if( noknapsackconshdlr)
6163  {
6164  SCIPfreeBufferArray(scip, &binvals);
6165  }
6166  else
6167  {
6168  /* clear binvals */
6169  for( --tmp; tmp >= 0; --tmp)
6170  {
6171  assert(tmpindices != NULL);
6172  binvals[tmpindices[tmp]] = 0;
6173  }
6174  SCIPfreeBufferArray(scip, &tmpindices);
6175  }
6176  SCIPfreeBufferArray(scip, &consvals);
6177  SCIPfreeBufferArray(scip, &consvars);
6178 
6179  return SCIP_OKAY;
6180 }
6181 
6182 /** separates given knapsack constraint */
6183 static
6185  SCIP* scip, /**< SCIP data structure */
6186  SCIP_CONS* cons, /**< knapsack constraint */
6187  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6188  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6189  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6190  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6191  int* ncuts /**< pointer to add up the number of found cuts */
6192  )
6193 {
6194  SCIP_CONSDATA* consdata;
6195  SCIP_Bool violated;
6196 
6197  assert(ncuts != NULL);
6198  assert(cutoff != NULL);
6199  *cutoff = FALSE;
6200 
6201  consdata = SCIPconsGetData(cons);
6202  assert(consdata != NULL);
6203 
6204  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6205 
6206  /* check knapsack constraint itself for feasibility */
6207  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6208 
6209  if( violated )
6210  {
6211  /* add knapsack constraint as LP row to the LP */
6212  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6213  (*ncuts)++;
6214  }
6215  else if( sepacuts )
6216  {
6217  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6218  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6219  }
6220 
6221  return SCIP_OKAY;
6222 }
6223 
6224 /** adds coefficient to constraint data */
6225 static
6227  SCIP* scip, /**< SCIP data structure */
6228  SCIP_CONS* cons, /**< knapsack constraint */
6229  SCIP_VAR* var, /**< variable to add to knapsack */
6230  SCIP_Longint weight /**< weight of variable in knapsack */
6231  )
6232 {
6233  SCIP_CONSDATA* consdata;
6235  consdata = SCIPconsGetData(cons);
6236  assert(consdata != NULL);
6237  assert(SCIPvarIsBinary(var));
6238  assert(weight > 0);
6239 
6240  /* add the new coefficient to the LP row */
6241  if( consdata->row != NULL )
6242  {
6243  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6244  }
6245 
6246  /* check for fixed variable */
6247  if( SCIPvarGetLbGlobal(var) > 0.5 )
6248  {
6249  /* variable is fixed to one: reduce capacity */
6250  consdata->capacity -= weight;
6251  }
6252  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6253  {
6254  SCIP_Bool negated;
6255 
6256  /* get binary representative of variable */
6257  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6258 
6259  /* insert coefficient */
6260  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6261  consdata->vars[consdata->nvars] = var;
6262  consdata->weights[consdata->nvars] = weight;
6263  consdata->nvars++;
6264 
6265  /* capture variable */
6266  SCIP_CALL( SCIPcaptureVar(scip, var) );
6267 
6268  /* install the rounding locks of variable */
6269  SCIP_CALL( lockRounding(scip, cons, var) );
6270 
6271  /* catch events */
6272  if( SCIPconsIsTransformed(cons) )
6273  {
6274  SCIP_CONSHDLRDATA* conshdlrdata;
6275 
6276  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6277  assert(conshdlrdata != NULL);
6278  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6280  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6281  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6282 
6283  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6284  consdata->existmultaggr = TRUE;
6285 
6286  /* mark constraint to be propagated and presolved */
6287  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6288  consdata->presolvedtiming = 0;
6289  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6290  }
6291 
6292  /* update weight sums */
6293  updateWeightSums(consdata, var, weight);
6294 
6295  consdata->sorted = FALSE;
6296  consdata->cliquepartitioned = FALSE;
6297  consdata->negcliquepartitioned = FALSE;
6298  consdata->merged = FALSE;
6299  }
6300 
6301  return SCIP_OKAY;
6302 }
6303 
6304 /** deletes coefficient at given position from constraint data */
6305 static
6307  SCIP* scip, /**< SCIP data structure */
6308  SCIP_CONS* cons, /**< knapsack constraint */
6309  int pos /**< position of coefficient to delete */
6310  )
6311 {
6312  SCIP_CONSDATA* consdata;
6313  SCIP_VAR* var;
6315  consdata = SCIPconsGetData(cons);
6316  assert(consdata != NULL);
6317  assert(0 <= pos && pos < consdata->nvars);
6318 
6319  var = consdata->vars[pos];
6320  assert(var != NULL);
6321  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6322 
6323  /* delete the coefficient from the LP row */
6324  if( consdata->row != NULL )
6325  {
6326  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6327  }
6328 
6329  /* remove the rounding locks of variable */
6330  SCIP_CALL( unlockRounding(scip, cons, var) );
6331 
6332  /* drop events and mark constraint to be propagated and presolved */
6333  if( SCIPconsIsTransformed(cons) )
6334  {
6335  SCIP_CONSHDLRDATA* conshdlrdata;
6336 
6337  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6338  assert(conshdlrdata != NULL);
6340  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6341  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6342 
6343  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6344  consdata->presolvedtiming = 0;
6345  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6346  }
6347 
6348  /* decrease weight sums */
6349  updateWeightSums(consdata, var, -consdata->weights[pos]);
6350 
6351  /* move the last variable to the free slot */
6352  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6353  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6354  if( consdata->eventdata != NULL )
6355  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6356 
6357  /* release variable */
6358  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6359 
6360  /* try to use old clique partitions */
6361  if( consdata->cliquepartitioned )
6362  {
6363  assert(consdata->cliquepartition != NULL);
6364  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6365  * change the clique number */
6366  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6367  {
6368  int oldcliqenum;
6369 
6370  oldcliqenum = consdata->cliquepartition[pos];
6371  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6372 
6373  /* the following if and else cases assure that we have increasing clique numbers */
6374  if( consdata->cliquepartition[pos] > pos )
6375  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6376  else
6377  {
6378  int i;
6379  int cliquenumbefore;
6380 
6381  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6382  * occurs the same as the old one is still in the cliquepartition */
6383  if( oldcliqenum > consdata->cliquepartition[pos] )
6384  {
6385  for( i = 0; i < consdata->nvars; ++i )
6386  if( oldcliqenum == consdata->cliquepartition[i] )
6387  break;
6388  else if( oldcliqenum < consdata->cliquepartition[i] )
6389  {
6390  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6391  break;
6392  }
6393  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6394  * the biggest index, so decrease the number of cliques
6395  */
6396  if( i == consdata->nvars )
6397  --(consdata->ncliques);
6398  }
6399  /* if the old clique number was smaller than the new one we have to check the front for an element with
6400  * clique number minus 1 */
6401  else if( oldcliqenum < consdata->cliquepartition[pos] )
6402  {
6403  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6404  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6405 
6406  if( i < cliquenumbefore )
6407  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6408  }
6409  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6410  else if( pos == consdata->nvars - 1)
6411  {
6412  cliquenumbefore = consdata->cliquepartition[pos];
6413  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6414 
6415  if( i < cliquenumbefore )
6416  --(consdata->ncliques);
6417  }
6418  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6419  }
6420  }
6421  else
6422  --(consdata->ncliques);
6423  }
6424 
6425  if( consdata->negcliquepartitioned )
6426  {
6427  assert(consdata->negcliquepartition != NULL);
6428  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6429  * change the clique number */
6430  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6431  {
6432  int oldcliqenum;
6433 
6434  oldcliqenum = consdata->negcliquepartition[pos];
6435  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6436 
6437  /* the following if and else cases assure that we have increasing clique numbers */
6438  if( consdata->negcliquepartition[pos] > pos )
6439  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6440  else
6441  {
6442  int i;
6443  int cliquenumbefore;
6444 
6445  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6446  * occurs, the same as the old one occurs */
6447  if( oldcliqenum > consdata->negcliquepartition[pos] )
6448  {
6449  for( i = 0; i < consdata->nvars; ++i )
6450  if( oldcliqenum == consdata->negcliquepartition[i] )
6451  break;
6452  else if( oldcliqenum < consdata->negcliquepartition[i] )
6453  {
6454  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6455  break;
6456  }
6457  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6458  * the biggest index, so decrease the number of negated cliques
6459  */
6460  if( i == consdata->nvars )
6461  --(consdata->nnegcliques);
6462  }
6463  /* if the old clique number was smaller than the new one we have to check the front for an element with
6464  * clique number minus 1 */
6465  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6466  {
6467  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6468  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6469 
6470  if( i < cliquenumbefore )
6471  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6472  }
6473  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6474  else if( pos == consdata->nvars - 1)
6475  {
6476  cliquenumbefore = consdata->negcliquepartition[pos];
6477  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6478 
6479  if( i < cliquenumbefore )
6480  --(consdata->nnegcliques);
6481  }
6482  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6483  }
6484  }
6485  else
6486  --(consdata->nnegcliques);
6487  }
6488 
6489  --(consdata->nvars);
6490 
6491  return SCIP_OKAY;
6492 }
6493 
6494 /** removes all items with weight zero from knapsack constraint */
6495 static
6497  SCIP* scip, /**< SCIP data structure */
6498  SCIP_CONS* cons /**< knapsack constraint */
6499  )
6500 {
6501  SCIP_CONSDATA* consdata;
6502  int v;
6503 
6504  consdata = SCIPconsGetData(cons);
6505  assert(consdata != NULL);
6506 
6507  for( v = consdata->nvars-1; v >= 0; --v )
6508  {
6509  if( consdata->weights[v] == 0 )
6510  {
6511  SCIP_CALL( delCoefPos(scip, cons, v) );
6512  }
6513  }
6514 
6515  return SCIP_OKAY;
6516 }
6517 
6518 /* perform deletion of variables in all constraints of the constraint handler */
6519 static
6521  SCIP* scip, /**< SCIP data structure */
6522  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6523  SCIP_CONS** conss, /**< array of constraints */
6524  int nconss /**< number of constraints */
6525  )
6526 {
6527  SCIP_CONSDATA* consdata;
6528  int i;
6529  int v;
6530 
6531  assert(scip != NULL);
6532  assert(conshdlr != NULL);
6533  assert(conss != NULL);
6534  assert(nconss >= 0);
6535  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6536 
6537  /* iterate over all constraints */
6538  for( i = 0; i < nconss; i++ )
6539  {
6540  consdata = SCIPconsGetData(conss[i]);
6541 
6542  /* constraint is marked, that some of its variables were deleted */
6543  if( consdata->varsdeleted )
6544  {
6545  /* iterate over all variables of the constraint and delete them from the constraint */
6546  for( v = consdata->nvars - 1; v >= 0; --v )
6547  {
6548  if( SCIPvarIsDeleted(consdata->vars[v]) )
6549  {
6550  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6551  }
6552  }
6553  consdata->varsdeleted = FALSE;
6554  }
6555  }
6556 
6557  return SCIP_OKAY;
6558 }
6559 
6560 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6561 static
6563  SCIP* scip, /**< SCIP data structure */
6564  SCIP_CONS* cons, /**< knapsack constraint */
6565  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6566  )
6567 {
6568  SCIP_CONSDATA* consdata;
6569  int v;
6570  int prev;
6571 
6572  assert(scip != NULL);
6573  assert(cons != NULL);
6574  assert(cutoff != NULL);
6575 
6576  consdata = SCIPconsGetData(cons);
6577  assert(consdata != NULL);
6578 
6579  *cutoff = FALSE;
6580 
6581  if( consdata->merged )
6582  return SCIP_OKAY;
6583 
6584  if( consdata->nvars <= 1 )
6585  {
6586  consdata->merged = TRUE;
6587  return SCIP_OKAY;
6588  }
6589 
6590  assert(consdata->vars != NULL || consdata->nvars == 0);
6591 
6592  /* sorting array after indices of variables, that's only for faster merging */
6593  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6594  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6595 
6596  /* knapsack-sorting (decreasing weights) now lost */
6597  consdata->sorted = FALSE;
6598 
6599  v = consdata->nvars - 1;
6600  prev = v - 1;
6601  /* loop backwards through the items: deletion only affects rear items */
6602  while( prev >= 0 )
6603  {
6604  SCIP_VAR* var1;
6605  SCIP_VAR* var2;
6606  SCIP_Bool negated1;
6607  SCIP_Bool negated2;
6608 
6609  negated1 = FALSE;
6610  negated2 = FALSE;
6611 
6612  var1 = consdata->vars[v];
6613  assert(SCIPvarIsBinary(var1));
6614  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6616  {
6617  var1 = SCIPvarGetNegatedVar(var1);
6618  negated1 = TRUE;
6619  }
6620  assert(var1 != NULL);
6621 
6622  var2 = consdata->vars[prev];
6623  assert(SCIPvarIsBinary(var2));
6624  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6626  {
6627  var2 = SCIPvarGetNegatedVar(var2);
6628  negated2 = TRUE;
6629  }
6630  assert(var2 != NULL);
6631 
6632  if( var1 == var2 )
6633  {
6634  /* both variables are either active or negated */
6635  if( negated1 == negated2 )
6636  {
6637  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6638  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6639  SCIP_CALL( delCoefPos(scip, cons, v) );
6640  }
6641  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6642  * and delete item of smaller weight
6643  */
6644  else if( consdata->weights[v] == consdata->weights[prev] )
6645  {
6646  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6647  consdata->capacity -= consdata->weights[v];
6648  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6649  SCIP_CALL( delCoefPos(scip, cons, prev) );
6650 
6651  --prev;
6652  }
6653  else if( consdata->weights[v] < consdata->weights[prev] )
6654  {
6655  consdata->capacity -= consdata->weights[v];
6656  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6657  assert(consdata->weights[prev] > 0);
6658  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6659  }
6660  else
6661  {
6662  consdata->capacity -= consdata->weights[prev];
6663  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6664  assert(consdata->weights[v] > 0);
6665  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6666  /* restore order iff necessary */
6667  if( consdata->nvars != v ) /* otherwise the order still stands */
6668  {
6669  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6670  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6671  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6672  --prev;
6673  else /* we need to let v at the same position*/
6674  {
6675  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6676  /* don't decrease v, the same variable may exist up front */
6677  --prev;
6678  continue;
6679  }
6680  }
6681  }
6682  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6683  }
6684  v = prev;
6685  --prev;
6686  }
6687 
6688  consdata->merged = TRUE;
6689 
6690  /* check infeasibility */
6691  if( consdata->onesweightsum > consdata->capacity )
6692  {
6693  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6694  *cutoff = TRUE;
6695  return SCIP_OKAY;
6696  }
6697 
6698  return SCIP_OKAY;
6699 }
6700 
6701 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6702  * fixings (dual reductions)
6703  */
6704 static
6706  SCIP* scip, /**< SCIP data structure */
6707  SCIP_CONS* cons, /**< knapsack constraint */
6708  int* nfixedvars, /**< pointer to count number of fixings */
6709  int* ndelconss, /**< pointer to count number of deleted constraints */
6710  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6711  )
6712 {
6713  SCIP_CONSDATA* consdata;
6714  SCIP_VAR** vars;
6715  SCIP_Real* profits;
6716  int* solitems;
6717  int* nonsolitems;
6718  int* items;
6719  SCIP_Real solval;
6720  SCIP_Bool infeasible;
6721  SCIP_Bool tightened;
6722  SCIP_Bool applicable;
6723  int nsolitems;
6724  int nnonsolitems;
6725  int nvars;
6726  int v;
6727 
6728  assert(!SCIPconsIsModifiable(cons));
6729 
6730  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6731  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6732  * added to the problems have the check flag set to FALSE
6733  */
6734  if( !SCIPconsIsChecked(cons) )
6735  return SCIP_OKAY;
6736 
6737  consdata = SCIPconsGetData(cons);
6738  assert(consdata != NULL);
6739 
6740  nvars = consdata->nvars;
6741  vars = consdata->vars;
6742 
6743  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6744  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6745  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6746  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6747 
6748  applicable = TRUE;
6749 
6750  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6751  * collect object values which are the profits of the knapsack problem
6752  */
6753  for( v = 0; v < nvars; ++v )
6754  {
6755  SCIP_VAR* var;
6756  SCIP_Bool negated;
6757 
6758  var = vars[v];
6759  assert(var != NULL);
6760 
6761  /* the variable should not be (globally) fixed */
6762  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6763 
6764  if( SCIPvarGetNLocksDown(var) > 0 || SCIPvarGetNLocksUp(var) > 1 )
6765  {
6766  applicable = FALSE;
6767  break;
6768  }
6769 
6770  negated = FALSE;
6771 
6772  /* get the active variable */
6773  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6774  assert(SCIPvarIsActive(var));
6775 
6776  if( negated )
6777  profits[v] = SCIPvarGetObj(var);
6778  else
6779  profits[v] = -SCIPvarGetObj(var);
6780 
6781  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6782  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6783  items[v] = v;
6784  }
6785 
6786  if( applicable )
6787  {
6788  SCIP_Bool success;
6789 
6790  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6791  SCIPdebugPrintCons(scip, cons, NULL);
6792 
6793  /* solve knapsack problem exactly */
6794  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6795  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6796 
6797  if( success )
6798  {
6799  SCIP_VAR* var;
6800 
6801  /* apply solution of the knapsack as dual reductions */
6802  for( v = 0; v < nsolitems; ++v )
6803  {
6804  var = vars[solitems[v]];
6805  assert(var != NULL);
6806 
6807  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6809  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6810  assert(!infeasible);
6811  assert(tightened);
6812  (*nfixedvars)++;
6813  }
6814 
6815  for( v = 0; v < nnonsolitems; ++v )
6816  {
6817  var = vars[nonsolitems[v]];
6818  assert(var != NULL);
6819 
6820  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6822  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6823  assert(!infeasible);
6824  assert(tightened);
6825  (*nfixedvars)++;
6826  }
6827 
6828  SCIP_CALL( SCIPdelCons(scip, cons) );
6829  (*ndelconss)++;
6830  (*deleted) = TRUE;
6831  }
6832  }
6833 
6834  SCIPfreeBufferArray(scip, &nonsolitems);
6835  SCIPfreeBufferArray(scip, &solitems);
6836  SCIPfreeBufferArray(scip, &items);
6837  SCIPfreeBufferArray(scip, &profits);
6838 
6839  return SCIP_OKAY;
6840 }
6841 
6842 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6843  * constraint enters the LP by setting the initial and separated flag to FALSE
6844  */
6845 static
6847  SCIP* scip, /**< SCIP data structure */
6848  SCIP_CONS* cons, /**< knapsack constraint */
6849  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6850  )
6851 {
6852  SCIP_CONSDATA* consdata;
6853  SCIP_VAR** vars;
6854  SCIP_VAR* var;
6855  SCIP_Real offset;
6856  SCIP_Real scale;
6857  SCIP_Real objval;
6858  SCIP_Bool applicable;
6859  SCIP_Bool negated;
6860  int nobjvars;
6861  int nvars;
6862  int v;
6863 
6864  assert(scip != NULL);
6865  assert(cons != NULL);
6866  assert(conshdlrdata != NULL);
6867 
6868  consdata = SCIPconsGetData(cons);
6869  assert(consdata != NULL);
6870 
6871  nvars = consdata->nvars;
6872  nobjvars = SCIPgetNObjVars(scip);
6873 
6874  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6875  * and/or separated flag is set to FALSE
6876  */
6877  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6878  return SCIP_OKAY;
6879 
6880  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6881  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6882  */
6883  if( nobjvars == 0 )
6884  return SCIP_OKAY;
6885 
6886  vars = consdata->vars;
6887  assert(vars != NULL);
6888 
6889  applicable = TRUE;
6890  offset = 0.0;
6891  scale = 1.0;
6892 
6893  for( v = 0; v < nvars && applicable; ++v )
6894  {
6895  negated = FALSE;
6896  var = vars[v];
6897  assert(var != NULL);
6898 
6899  if( SCIPvarIsNegated(var) )
6900  {
6901  negated = TRUE;
6902  var = SCIPvarGetNegatedVar(var);
6903  assert(var != NULL);
6904  }
6905 
6906  objval = SCIPvarGetObj(var);
6907 
6908  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6909  if( SCIPisZero(scip, objval) )
6910  applicable = FALSE;
6911  else
6912  {
6913  SCIP_Real weight;
6914 
6915  weight = (SCIP_Real)consdata->weights[v];
6916 
6917  if( negated )
6918  {
6919  if( v == 0 )
6920  {
6921  /* the first variable defines the scale */
6922  scale = weight / -objval;
6923 
6924  offset += weight;
6925  }
6926  else if( SCIPisEQ(scip, -objval * scale, weight) )
6927  offset += weight;
6928  else
6929  applicable = FALSE;
6930  }
6931  else if( v == 0 )
6932  {
6933  /* the first variable define the scale */
6934  scale = weight / objval;
6935  }
6936  else if( !SCIPisEQ(scip, objval * scale, weight) )
6937  applicable = FALSE;
6938  }
6939  }
6940 
6941  if( applicable )
6942  {
6943  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6944  {
6945  SCIP_Real cutoffbound;
6946 
6947  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6948  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6949  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6950 
6951  cutoffbound = (consdata->capacity - offset) / scale;
6952 
6953  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6954  * still excepted
6955  */
6956  cutoffbound += SCIPcutoffbounddelta(scip);
6957 
6958  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6959  SCIPconsGetName(cons), cutoffbound);
6960 
6961  if( cutoffbound < SCIPgetCutoffbound(scip) )
6962  {
6963  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6964 
6965  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6966  }
6967  else
6968  {
6969  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6970  * propagation
6971  */
6972  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6973  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6974  }
6975  }
6976  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6977  {
6978  SCIP_Real lowerbound;
6979 
6980  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6981  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6982  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6983 
6984  lowerbound = (consdata->capacity - offset) / scale;
6985 
6986  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6987  SCIPconsGetName(cons), lowerbound);
6988 
6989  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6990  }
6991  }
6992 
6993  return SCIP_OKAY;
6994 }
6995 
6996 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6997  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
6998 static
7000  SCIP* scip, /**< SCIP data structure */
7001  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7002  SCIP_VAR** vars, /**< array for sorted variables */
7003  SCIP_Longint* weights, /**< array for sorted weights */
7004  int* cliquestartposs, /**< starting position array for each clique */
7005  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7006  )
7007 {
7008  SCIP_VAR** origvars;
7009  int norigvars;
7010  SCIP_Longint* origweights;
7011  int* cliquepartition;
7012  int ncliques;
7013 
7014  SCIP_VAR*** varpointers;
7015  SCIP_Longint** weightpointers;
7016  int* cliquecount;
7017 
7018  int nextpos;
7019  int c;
7020  int v;
7021 
7022  assert(scip != NULL);
7023  assert(consdata != NULL);
7024  assert(vars != NULL);
7025  assert(weights != NULL);
7026  assert(cliquestartposs != NULL);
7027 
7028  origweights = consdata->weights;
7029  origvars = consdata->vars;
7030  norigvars = consdata->nvars;
7031 
7032  assert(origvars != NULL || norigvars == 0);
7033  assert(origweights != NULL || norigvars == 0);
7034 
7035  if( norigvars == 0 )
7036  return SCIP_OKAY;
7037 
7038  if( usenegatedclique )
7039  {
7040  assert(consdata->negcliquepartitioned);
7041 
7042  cliquepartition = consdata->negcliquepartition;
7043  ncliques = consdata->nnegcliques;
7044  }
7045  else
7046  {
7047  assert(consdata->cliquepartitioned);
7048 
7049  cliquepartition = consdata->cliquepartition;
7050  ncliques = consdata->ncliques;
7051  }
7052 
7053  assert(cliquepartition != NULL);
7054  assert(ncliques > 0);
7055 
7056  /* we first count all clique items and alloc temporary memory for a bucket sort */
7057  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7058  BMSclearMemoryArray(cliquecount, ncliques);
7059 
7060  /* first we count for each clique the number of elements */
7061  for( v = norigvars - 1; v >= 0; --v )
7062  {
7063  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7064  ++(cliquecount[cliquepartition[v]]);
7065  }
7066 
7067  /*@todo: maybe it is better to put largest cliques up front */
7068 
7069 #ifndef NDEBUG
7070  BMSclearMemoryArray(vars, norigvars);
7071  BMSclearMemoryArray(weights, norigvars);
7072 #endif
7073  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7074  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7075 
7076  nextpos = 0;
7077  /* now we initialize all start pointers for each clique, so they will be ordered */
7078  for( c = 0; c < ncliques; ++c )
7079  {
7080  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7081  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7082  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7083  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7084  * vars[7]
7085  *
7086  */
7087  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7088  cliquestartposs[c] = nextpos;
7089  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7090  assert(cliquecount[c] > 0);
7091  nextpos += cliquecount[c];
7092  assert(nextpos > 0);
7093  }
7094  assert(nextpos == norigvars);
7095  cliquestartposs[c] = nextpos;
7096 
7097  /* now we copy all variable and weights to the right order */
7098  for( v = 0; v < norigvars; ++v )
7099  {
7100  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7101  ++(varpointers[cliquepartition[v]]);
7102  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7103  ++(weightpointers[cliquepartition[v]]);
7104  }
7105 #ifndef NDEBUG
7106  for( v = 0; v < norigvars; ++v )
7107  {
7108  assert(vars[v] != NULL);
7109  assert(weights[v] > 0);
7110  }
7111 #endif
7112 
7113  /* free temporary memory */
7114  SCIPfreeBufferArray(scip, &weightpointers);
7115  SCIPfreeBufferArray(scip, &varpointers);
7116  SCIPfreeBufferArray(scip, &cliquecount);
7117 
7118  return SCIP_OKAY;
7119 }
7120 
7121 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7122 static
7124  SCIP* scip, /**< SCIP data structure */
7125  SCIP_CONS* cons, /**< knapsack constraint */
7126  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7127  * information is not needed; in this case, we apply all fixings
7128  * instead of stopping after the first infeasible one */
7129  )
7130 {
7131  SCIP_CONSDATA* consdata;
7132  int v;
7133 
7134  assert(scip != NULL);
7135  assert(cons != NULL);
7136 
7137  consdata = SCIPconsGetData(cons);
7138  assert(consdata != NULL);
7139  assert(consdata->nvars == 0 || consdata->vars != NULL);
7140 
7141  if( cutoff != NULL )
7142  *cutoff = FALSE;
7143 
7144  SCIPdebugMsg(scip, "apply fixings:\n");
7145  SCIPdebugPrintCons(scip, cons, NULL);
7146 
7147  /* check infeasibility */
7148  if ( consdata->onesweightsum > consdata->capacity )
7149  {
7150  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7151 
7152  if( cutoff != NULL )
7153  *cutoff = TRUE;
7154 
7155  return SCIP_OKAY;
7156  }
7157 
7158  /* all multi-aggregations should be resolved */
7159  consdata->existmultaggr = FALSE;
7160 
7161  v = 0;
7162  while( v < consdata->nvars )
7163  {
7164  SCIP_VAR* var;
7165 
7166  var = consdata->vars[v];
7167  assert(SCIPvarIsBinary(var));
7168 
7169  if( SCIPvarGetLbGlobal(var) > 0.5 )
7170  {
7171  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7172  consdata->capacity -= consdata->weights[v];
7173  SCIP_CALL( delCoefPos(scip, cons, v) );
7174  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7175  }
7176  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7177  {
7178  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7179  SCIP_CALL( delCoefPos(scip, cons, v) );
7180  }
7181  else
7182  {
7183  SCIP_VAR* repvar;
7184  SCIP_VAR* negvar;
7185  SCIP_VAR* workvar;
7186  SCIP_Longint weight;
7187  SCIP_Bool negated;
7188 
7189  weight = consdata->weights[v];
7190 
7191  /* get binary representative of variable */
7192  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7193  assert(repvar != NULL);
7194 
7195  /* check for multi-aggregation */
7196  if( SCIPvarIsNegated(repvar) )
7197  {
7198  workvar = SCIPvarGetNegatedVar(repvar);
7199  assert(workvar != NULL);
7200  negated = TRUE;
7201  }
7202  else
7203  {
7204  workvar = repvar;
7205  negated = FALSE;
7206  }
7207 
7208  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7209  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7210  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7211  *
7212  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7213  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7214  *
7215  * The explanation for the following block:
7216  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7217  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7218  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7219  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7220  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7221  * 2) For all replacement variable we check:
7222  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7223  * capacity -= weight * a_i caused by the negation of y_i.
7224  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7225  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7226  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7227  * weight in this case.
7228  */
7229  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7230  {
7231  SCIP_VAR** aggrvars;
7232  SCIP_Real* aggrscalars;
7233  SCIP_Real aggrconst;
7234  int naggrvars;
7235  int i;
7236 
7237  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7238  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7239  aggrvars = SCIPvarGetMultaggrVars(workvar);
7240  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7241  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7242  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7243 
7244  if( !SCIPisIntegral(scip, weight * aggrconst) )
7245  {
7246  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7247  return SCIP_ERROR;
7248  }
7249 
7250  /* if workvar was negated, we have to flip the weight */
7251  if( negated )
7252  weight *= -1;
7253 
7254  for( i = naggrvars - 1; i >= 0; --i )
7255  {
7256  assert(aggrvars != NULL);
7257  assert(aggrscalars != NULL);
7258 
7259  if( !SCIPvarIsBinary(aggrvars[i]) )
7260  {
7261  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary variable <%s>\n", aggrvars[i]);
7262  return SCIP_ERROR;
7263  }
7264  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7265  {
7266  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7267  return SCIP_ERROR;
7268  }
7269  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7270  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7271  {
7272  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7273  assert(negvar != NULL);
7274  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7275  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7276  }
7277  else
7278  {
7279  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7280  }
7281  }
7282  /* delete old coefficient */
7283  SCIP_CALL( delCoefPos(scip, cons, v) );
7284 
7285  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7286  if( negated )
7287  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7288  else
7289  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7290 
7291  if( consdata->capacity < 0 )
7292  {
7293  if( cutoff != NULL )
7294  {
7295  *cutoff = TRUE;
7296  break;
7297  }
7298  }
7299  }
7300  /* check, if the variable should be replaced with the representative */
7301  else if( repvar != var )
7302  {
7303  /* delete old (aggregated) variable */
7304  SCIP_CALL( delCoefPos(scip, cons, v) );
7305 
7306  /* add representative instead */
7307  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7308  }
7309  else
7310  ++v;
7311  }
7312  }
7313  assert(consdata->onesweightsum == 0);
7314 
7315  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7316  SCIPdebugPrintCons(scip, cons, NULL);
7317 
7318  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7319  * clean up the constraint
7320  */
7321  if( cutoff != NULL && !(*cutoff) )
7322  {
7323  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7324  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7325  SCIPdebugPrintCons(scip, cons, NULL);
7326  }
7327 
7328  return SCIP_OKAY;
7329 }
7330 
7331 
7332 /** propagation method for knapsack constraints */
7333 static
7335  SCIP* scip, /**< SCIP data structure */
7336  SCIP_CONS* cons, /**< knapsack constraint */
7337  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7338  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7339  int* nfixedvars, /**< pointer to count number of fixings */
7340  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7341  )
7343  SCIP_CONSDATA* consdata;
7344  SCIP_Bool infeasible;
7345  SCIP_Bool tightened;
7346  SCIP_Longint* secondmaxweights;
7347  SCIP_Longint minweightsum;
7348  SCIP_Longint residualcapacity;
7349 
7350  int nvars;
7351  int i;
7352  int nnegcliques;
7353 
7354  SCIP_VAR** myvars;
7355  SCIP_Longint* myweights;
7356  int* cliquestartposs;
7357  int* cliqueendposs;
7358  SCIP_Longint localminweightsum;
7359  SCIP_Bool foundmax;
7360  int c;
7361 
7362  assert(scip != NULL);
7363  assert(cons != NULL);
7364  assert(cutoff != NULL);
7365  assert(redundant != NULL);
7366  assert(nfixedvars != NULL);
7367 
7368  consdata = SCIPconsGetData(cons);
7369  assert(consdata != NULL);
7370 
7371  *cutoff = FALSE;
7372  *redundant = FALSE;
7373 
7374  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7375 
7376  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7377  if( !SCIPinRepropagation(scip) )
7378  {
7379  SCIP_CALL( SCIPincConsAge(scip, cons) );
7380  }
7381 
7382 #ifndef NDEBUG
7383  /* assert that only active or negated variables are present */
7384  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7385  {
7386  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7387  }
7388 #endif
7389 
7390  usenegatedclique = usenegatedclique && consdata->merged;
7391 
7392  /* init for debugging */
7393  myvars = NULL;
7394  myweights = NULL;
7395  cliquestartposs = NULL;
7396  secondmaxweights = NULL;
7397  minweightsum = 0;
7398  nvars = consdata->nvars;
7399  /* make sure, the items are sorted by non-increasing weight */
7400  sortItems(consdata);
7401 
7402  do
7403  {
7404  localminweightsum = 0;
7405 
7406  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7407  * a negated clique means, that at most one of the clique variables can be zero
7408  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7409  *
7410  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7411  * since replacing i with the element of maximal weight leads to infeasibility
7412  */
7413  if( usenegatedclique && nvars > 0 )
7414  {
7415  SCIP_CONSHDLRDATA* conshdlrdata;
7416  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7417  assert(conshdlrdata != NULL);
7418 
7419  /* compute clique partitions */
7420  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7421  nnegcliques = consdata->nnegcliques;
7422 
7423  /* if we have no real negated cliques we can stop here */
7424  if( nnegcliques == nvars )
7425  {
7426  /* run the standard algorithm that does not involve cliques */
7427  usenegatedclique = FALSE;
7428  break;
7429  }
7430 
7431  /* allocate temporary memory and initialize it */
7432  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7433  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7434  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7435  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7436  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7437  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7438 
7439  /* resort variables to avoid quadratic algorithm later on */
7440  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7441 
7442  /* save the end positions of the cliques because start positions are moved in the following loop */
7443  for( c = 0; c < nnegcliques; ++c )
7444  {
7445  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7446  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7447  }
7448 
7449  c = 0;
7450  foundmax = FALSE;
7451  i = 0;
7452 
7453  while( i < nvars )
7454  {
7455  /* ignore variables of the negated clique which are fixed to one since these are counted in
7456  * consdata->onesweightsum
7457  */
7458 
7459  /* if there are only one variable negated cliques left we can stop */
7460  if( nnegcliques - c == nvars - i )
7461  {
7462  minweightsum += localminweightsum;
7463  localminweightsum = 0;
7464  break;
7465  }
7466 
7467  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7468  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7469  * other clique variables to one
7470  */
7471  if( cliquestartposs[c] == i )
7472  {
7473  assert(myweights[i] > 0);
7474  ++c;
7475  minweightsum += localminweightsum;
7476  localminweightsum = 0;
7477  foundmax = TRUE;
7478 
7479  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7480  foundmax = FALSE;
7481 
7482  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7483  {
7484  ++i;
7485  continue;
7486  }
7487  }
7488 
7489  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7490  {
7491  assert(myweights[i] > 0);
7492 
7493  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7494  {
7495  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7496 
7497  if( !foundmax )
7498  {
7499  foundmax = TRUE;
7500 
7501  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7502  cliquestartposs[c - 1] = i;
7503  ++i;
7504 
7505  continue;
7506  }
7507  /* memorize second max weight for each clique */
7508  if( secondmaxweights[c - 1] == 0 )
7509  secondmaxweights[c - 1] = myweights[i];
7510 
7511  localminweightsum += myweights[i];
7512  }
7513  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7514  else
7515  {
7516  int v;
7517  /* fix all other variables of the negated clique to 1 */
7518  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7519  {
7520  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7521  {
7522  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7523  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7524 
7525  if( infeasible )
7526  {
7527  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7528 
7529  /* analyze the infeasibility if conflict analysis is applicable */
7531  {
7532  /* conflict analysis can only be applied in solving stage */
7533  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7534 
7535  /* initialize the conflict analysis */
7537 
7538  /* add the two variables which are fixed to zero within a negated clique */
7539  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7540  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7541 
7542  /* start the conflict analysis */
7543  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7544  }
7545  *cutoff = TRUE;
7546  break;
7547  }
7548  assert(tightened);
7549  ++(*nfixedvars);
7550  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7551  }
7552  }
7553  if( *cutoff )
7554  break;
7555 
7556  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7557  localminweightsum = 0;
7558  /* we can jump to the end of this clique */
7559  i = cliqueendposs[c - 1];
7560  }
7561  }
7562  ++i;
7563  }
7564  /* add last clique minweightsum */
7565  minweightsum += localminweightsum;
7566 
7567  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7568  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7569 
7570  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7571  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7572  {
7573  SCIP_Longint maxcliqueweight = -1LL;
7574 
7575  /* loop over cliques */
7576  for( c = 0; c < nnegcliques; ++c )
7577  {
7578  SCIP_VAR* maxvar;
7579  SCIP_Bool maxvarfixed;
7580  int endvarposclique;
7581  int startvarposclique;
7582 
7583  assert(myvars != NULL);
7584  assert(nnegcliques == consdata->nnegcliques);
7585  assert(myweights != NULL);
7586  assert(secondmaxweights != NULL);
7587  assert(cliquestartposs != NULL);
7588 
7589  endvarposclique = cliqueendposs[c];
7590  startvarposclique = cliquestartposs[c];
7591 
7592  maxvar = myvars[startvarposclique];
7593 
7594  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7595  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7596  continue;
7597 
7598  maxcliqueweight = myweights[startvarposclique];
7599  maxvarfixed = FALSE;
7600  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7601  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7602  * exceeds the capacity the maximum weight variable can be fixed to zero.
7603  */
7604  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7605  {
7606 #ifndef NDEBUG
7607  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7608 #endif
7609  assert(maxcliqueweight >= secondmaxweights[c]);
7610  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7611 
7612  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7613  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7614  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7615  assert(consdata->onesweightsum == oldonesweightsum);
7616  assert(!infeasible);
7617  assert(tightened);
7618  (*nfixedvars)++;
7619  maxvarfixed = TRUE;
7620  }
7621  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7622  * fits into the knapsack
7623  */
7624  else if( nnegcliques - c == nvars - startvarposclique )
7625  break;
7626  /* early termination of the remaining loop because no further variable fixings are possible:
7627  *
7628  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7629  * largest was set to 0) does not suffice to infer additional variable fixings because
7630  *
7631  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7632  * - their second largest elements are at least as large as the smallest weight of the knapsack
7633  */
7634  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7635  break;
7636 
7637  /* loop over items with non-maximal weight (omitting the first position) */
7638  for( i = endvarposclique; i > startvarposclique; --i )
7639  {
7640  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7641  * messed up the clique preprocessing in the previous loop to filter those variables out */
7642  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7643 
7644  /* only check variables of negated cliques for which no variable is locally fixed */
7645  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7646  {
7647  assert(maxcliqueweight >= myweights[i]);
7648  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7649 
7650  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7651  *
7652  * the maxvar was already fixed to 0 because it has a huge gain.
7653  *
7654  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7655  * since replacing i with the element of maximal weight leads to infeasibility */
7656  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7657  {
7658 #ifndef NDEBUG
7659  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7660 #endif
7661  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7662  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7663  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7664  assert(!infeasible);
7665  assert(tightened);
7666  ++(*nfixedvars);
7667  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7668 
7669  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7670  * consdata->onesweightsum
7671  */
7672  minweightsum -= myweights[i];
7673  assert(minweightsum >= 0);
7674  }
7675  else
7676  break;
7677  }
7678  }
7679 #ifndef NDEBUG
7680  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7681  for( ; i > startvarposclique; --i )
7682  {
7683  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7684  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7685 
7686  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7687  assert(varisfixed || !exceedscapacity);
7688  }
7689 #endif
7690  }
7691  }
7692  SCIPfreeBufferArray(scip, &secondmaxweights);
7693  SCIPfreeBufferArray(scip, &cliqueendposs);
7694  SCIPfreeBufferArray(scip, &cliquestartposs);
7695  SCIPfreeBufferArray(scip, &myweights);
7696  SCIPfreeBufferArray(scip, &myvars);
7697  }
7698 
7699  assert(consdata->negcliquepartitioned || minweightsum == 0);
7700  }
7701  while( FALSE );
7702 
7703  assert(usenegatedclique || minweightsum == 0);
7704  /* check, if weights of fixed variables already exceed knapsack capacity */
7705  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7706  {
7707  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7708  consdata->onesweightsum, consdata->capacity);
7709 
7710  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7711  *cutoff = TRUE;
7712 
7713  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7715  {
7716  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7717  SCIP_Longint weight;
7718 
7719  weight = 0;
7720 
7722 
7723  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7724  {
7725  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7726  {
7727  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7728  weight += consdata->weights[i];
7729  }
7730  }
7731 
7732  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7733  }
7734 
7735  return SCIP_OKAY;
7736  }
7737 
7738  /* the algorithm below is a special case of propagation involving negated cliques */
7739  if( !usenegatedclique )
7740  {
7741  assert(consdata->sorted);
7742  residualcapacity = consdata->capacity - consdata->onesweightsum;
7743 
7744  /* fix all variables to zero, that don't fit into the knapsack anymore */
7745  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7746  {
7747  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7748  * to zero
7749  */
7750  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7751  {
7752  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7753  {
7754  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7755  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7756  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7757  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7758  assert(!infeasible);
7759  assert(tightened);
7760  (*nfixedvars)++;
7761  }
7762  }
7763  }
7764  }
7765 
7766  /* check if the knapsack is now redundant */
7767  if( !SCIPconsIsModifiable(cons) )
7768  {
7769  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7770 
7771  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7772  for( i = 0; i < nvars; ++i )
7773  {
7774  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7775  {
7776  unfixedweightsum += consdata->weights[i];
7777 
7778  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7779  if( unfixedweightsum > consdata->capacity )
7780  return SCIP_OKAY;
7781  }
7782  }
7783  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7784  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7785  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7786  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7787  *redundant = TRUE;
7788  }
7789 
7790  return SCIP_OKAY;
7791 }
7792 
7793 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7794  * containing all negated variables of this knapsack constraint
7795  */
7796 static
7798  SCIP* scip, /**< SCIP data structure */
7799  SCIP_CONS* cons, /**< knapsack constraint */
7800  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7801  int* naddconss /**< pointer to count number of added constraints */
7802  )
7803 {
7804  SCIP_CONS* newcons;
7805  SCIP_CONSDATA* consdata;
7806 
7807  assert(scip != NULL);
7808  assert(cons != NULL);
7809  assert(ndelconss != NULL);
7810  assert(naddconss != NULL);
7811 
7812  consdata = SCIPconsGetData(cons);
7813  assert(consdata != NULL);
7814  assert(consdata->nvars > 1);
7815 
7816  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7817  if( consdata->nvars == 2 )
7818  {
7819  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7820 
7821  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7825  SCIPconsIsStickingAtNode(cons)) );
7826  }
7827  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7828  * containing all negated variables of the knapsack
7829  */
7830  else
7831  {
7832  SCIP_VAR** consvars;
7833 
7834  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7835 
7836  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7837  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7838 
7839  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7843  SCIPconsIsStickingAtNode(cons)) );
7844 
7845  SCIPfreeBufferArray(scip, &consvars);
7846  }
7847 
7848  SCIP_CALL( SCIPaddCons(scip, newcons) );
7849  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7850  ++(*naddconss);
7851 
7852  SCIP_CALL( SCIPdelCons(scip, cons) );
7853  ++(*ndelconss);
7854 
7855  return SCIP_OKAY;
7856 }
7857 
7858 /** delete redundant variables
7859  *
7860  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7861  *
7862  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7863  * => x4, x5 always fits into the knapsack, so we can delete them
7864  *
7865  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7866  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7867  */
7868 static
7870  SCIP* scip, /**< SCIP data structure */
7871  SCIP_CONS* cons, /**< knapsack constraint */
7872  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7873  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7874  * first which did not fit */
7875  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7876  int* nchgsides, /**< pointer to store the amount of changed sides */
7877  int* naddconss /**< pointer to count number of added constraints */
7878  )
7879 {
7880  SCIP_CONSHDLRDATA* conshdlrdata;
7881  SCIP_CONSDATA* consdata;
7882  SCIP_VAR** vars;
7883  SCIP_Longint* weights;
7884  SCIP_Longint capacity;
7885  SCIP_Longint gcd;
7886  int nvars;
7887  int w;
7888 
7889  assert(scip != NULL);
7890  assert(cons != NULL);
7891  assert(nchgcoefs != NULL);
7892  assert(nchgsides != NULL);
7893  assert(naddconss != NULL);
7894 
7895  consdata = SCIPconsGetData(cons);
7896  assert(consdata != NULL);
7897  assert(0 < frontsum && frontsum < consdata->weightsum);
7898  assert(0 < splitpos && splitpos < consdata->nvars);
7899 
7900  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7901  assert(conshdlrdata != NULL);
7902 
7903  vars = consdata->vars;
7904  weights = consdata->weights;
7905  nvars = consdata->nvars;
7906  capacity = consdata->capacity;
7907 
7908  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7909  * weight must not be sorted by their index
7910  */
7911 #ifndef NDEBUG
7912  for( w = nvars - 1; w > 0; --w )
7913  assert(weights[w] <= weights[w-1]);
7914 #endif
7915 
7916  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7917  if( consdata->nvars - 1 == splitpos )
7918  return SCIP_OKAY;
7919 
7920  assert(frontsum + weights[splitpos] > capacity);
7921 
7922  /* detect redundant variables */
7923  if( consdata->weightsum - weights[splitpos] <= capacity )
7924  {
7925  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7926  * fit
7927  */
7928  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7929 
7930  /* delete items and update capacity */
7931  for( w = nvars - 1; w > splitpos; --w )
7932  {
7933  consdata->capacity -= weights[w];
7934  SCIP_CALL( delCoefPos(scip, cons, w) );
7935  }
7936  assert(w == splitpos);
7937 
7938  ++(*nchgsides);
7939  *nchgcoefs += (nvars - splitpos);
7940 
7941  /* division by greatest common divisor */
7942  gcd = weights[w];
7943  for( ; w >= 0 && gcd > 1; --w )
7944  {
7945  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7946  }
7947 
7948  /* normalize if possible */
7949  if( gcd > 1 )
7950  {
7951  for( w = splitpos; w >= 0; --w )
7952  {
7953  consdataChgWeight(consdata, w, weights[w]/gcd);
7954  }
7955  (*nchgcoefs) += nvars;
7956 
7957  consdata->capacity /= gcd;
7958  ++(*nchgsides);
7959  }
7960 
7961  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7962  * weight must not be sorted by their index
7963  */
7964 #ifndef NDEBUG
7965  for( w = consdata->nvars - 1; w > 0; --w )
7966  assert(weights[w] <= weights[w - 1]);
7967 #endif
7968  }
7969  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7970  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7971  * splitpos and needs to fit into the knapsack
7972  */
7973  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7974  {
7975  int* clqpart;
7976  int nclq;
7977  int len;
7978 
7979  len = nvars - (splitpos + 1);
7980  /* allocate temporary memory */
7981  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7982 
7983  /* calculate clique partition */
7984  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7985 
7986  /* check if we found at least one clique */
7987  if( nclq < len )
7988  {
7989  SCIP_Longint maxactduetoclq;
7990  int cliquenum;
7991 
7992  maxactduetoclq = 0;
7993  cliquenum = 0;
7994 
7995  /* calculate maximum activity due to cliques */
7996  for( w = 0; w < len; ++w )
7997  {
7998  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7999  if( clqpart[w] == cliquenum )
8000  {
8001  maxactduetoclq += weights[w + splitpos + 1];
8002  ++cliquenum;
8003  }
8004  }
8005 
8006  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8007  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8008  */
8009  if( frontsum + maxactduetoclq <= capacity )
8010  {
8011  SCIP_VAR** clqvars;
8012  int nclqvars;
8013  int c;
8014 
8015  assert(maxactduetoclq < weights[splitpos]);
8016 
8017  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8018 
8019  /* allocate temporary memory */
8020  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8021 
8022  for( c = 0; c < nclq; ++c )
8023  {
8024  nclqvars = 0;
8025  for( w = 0; w < len; ++w )
8026  {
8027  if( clqpart[w] == c )
8028  {
8029  clqvars[nclqvars] = vars[w + splitpos + 1];
8030  ++nclqvars;
8031  }
8032  }
8033 
8034  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8035  if( nclqvars > 1 )
8036  {
8037  SCIP_CONS* cliquecons;
8038  char name[SCIP_MAXSTRLEN];
8039 
8040  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8041  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8045  SCIPconsIsStickingAtNode(cons)) );
8046  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8047  SCIPdebugPrintCons(scip, cliquecons, NULL);
8048  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8049  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8050  ++(*naddconss);
8051  }
8052  }
8053 
8054  /* delete items and update capacity */
8055  for( w = nvars - 1; w > splitpos; --w )
8056  {
8057  SCIP_CALL( delCoefPos(scip, cons, w) );
8058  ++(*nchgcoefs);
8059  }
8060  consdata->capacity -= maxactduetoclq;
8061  assert(frontsum <= consdata->capacity);
8062  ++(*nchgsides);
8063 
8064  assert(w == splitpos);
8065 
8066  /* renew weights pointer */
8067  weights = consdata->weights;
8068 
8069  /* division by greatest common divisor */
8070  gcd = weights[w];
8071  for( ; w >= 0 && gcd > 1; --w )
8072  {
8073  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8074  }
8075 
8076  /* normalize if possible */
8077  if( gcd > 1 )
8078  {
8079  for( w = splitpos; w >= 0; --w )
8080  {
8081  consdataChgWeight(consdata, w, weights[w]/gcd);
8082  }
8083  (*nchgcoefs) += nvars;
8084 
8085  consdata->capacity /= gcd;
8086  ++(*nchgsides);
8087  }
8088 
8089  /* free temporary memory */
8090  SCIPfreeBufferArray(scip, &clqvars);
8091 
8092  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8093  * weight must not be sorted by their index
8094  */
8095 #ifndef NDEBUG
8096  for( w = consdata->nvars - 1; w > 0; --w )
8097  assert(weights[w] <= weights[w - 1]);
8098 #endif
8099  }
8100  }
8101 
8102  /* free temporary memory */
8103  SCIPfreeBufferArray(scip, &clqpart);
8104  }
8105 
8106  return SCIP_OKAY;
8107 }
8108 
8109 /* detect redundant variables which always fits into the knapsack
8110  *
8111  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8112  *
8113  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8114  * => x4, x5 always fits into the knapsack, so we can delete them
8115  *
8116  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8117  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8118  */
8119 static
8121  SCIP* scip, /**< SCIP data structure */
8122  SCIP_CONS* cons, /**< knapsack constraint */
8123  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8124  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8125  int* nchgsides, /**< pointer to store the amount of changed sides */
8126  int* naddconss /**< pointer to count number of added constraints */
8127  )
8129  SCIP_CONSHDLRDATA* conshdlrdata;
8130  SCIP_CONSDATA* consdata;
8131  SCIP_VAR** vars;
8132  SCIP_Longint* weights;
8133  SCIP_Longint capacity;
8134  SCIP_Longint sum;
8135  int noldchgcoefs;
8136  int nvars;
8137  int v;
8138  int w;
8139 
8140  assert(scip != NULL);
8141  assert(cons != NULL);
8142  assert(ndelconss != NULL);
8143  assert(nchgcoefs != NULL);
8144  assert(nchgsides != NULL);
8145  assert(naddconss != NULL);
8146 
8147  consdata = SCIPconsGetData(cons);
8148  assert(consdata != NULL);
8149  assert(consdata->nvars >= 2);
8150  assert(consdata->weightsum > consdata->capacity);
8151 
8152  noldchgcoefs = *nchgcoefs;
8153  vars = consdata->vars;
8154  weights = consdata->weights;
8155  nvars = consdata->nvars;
8156  capacity = consdata->capacity;
8157  sum = 0;
8158 
8159  /* search for maximal fitting items */
8160  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8161  sum += weights[v];
8162 
8163  assert(v < nvars);
8164 
8165  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8166  if( v == nvars - 1 )
8167  {
8168  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8169  assert(SCIPconsIsDeleted(cons));
8170 
8171  return SCIP_OKAY;
8172  }
8173 
8174  if( v < nvars - 1 )
8175  {
8176  /* try to delete variables */
8177  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8178  assert(consdata->nvars > 1);
8179 
8180  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8181  if( v == consdata->nvars - 1 )
8182  {
8183  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8184  assert(SCIPconsIsDeleted(cons));
8185  }
8186 
8187  return SCIP_OKAY;
8188  }
8189 
8190  /* if we already found some redundant variables, stop here */
8191  if( *nchgcoefs > noldchgcoefs )
8192  return SCIP_OKAY;
8193 
8194  assert(vars == consdata->vars);
8195  assert(weights == consdata->weights);
8196  assert(nvars == consdata->nvars);
8197  assert(capacity == consdata->capacity);
8198 
8199  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8200  assert(conshdlrdata != NULL);
8201  /* calculate clique partition */
8202  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8203 
8204  /* check for real existing cliques */
8205  if( consdata->cliquepartition[v] < v )
8206  {
8207  SCIP_Longint sumfront;
8208  SCIP_Longint maxactduetoclqfront;
8209  int* clqpart;
8210  int cliquenum;
8211 
8212 
8213  sumfront = 0;
8214  maxactduetoclqfront = 0;
8215 
8216  clqpart = consdata->cliquepartition;
8217  cliquenum = 0;
8218 
8219  /* calculate maximal activity due to cliques */
8220  for( w = 0; w < nvars; ++w )
8221  {
8222  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8223  if( clqpart[w] == cliquenum )
8224  {
8225  if( maxactduetoclqfront + weights[w] <= capacity )
8226  {
8227  maxactduetoclqfront += weights[w];
8228  ++cliquenum;
8229  }
8230  else
8231  break;
8232  }
8233  sumfront += weights[w];
8234  }
8235  assert(w >= v);
8236 
8237  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8238  * information
8239  */
8240  if( conshdlrdata->disaggregation && w == nvars )
8241  {
8242  SCIP_VAR** clqvars;
8243  int nclqvars;
8244  int c;
8245  int ncliques;
8246 
8247  assert(maxactduetoclqfront <= capacity);
8248 
8249  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8250 
8251  ncliques = consdata->ncliques;
8252 
8253  /* allocate temporary memory */
8254  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8255 
8256  for( c = 0; c < ncliques; ++c )
8257  {
8258  nclqvars = 0;
8259  for( w = 0; w < nvars; ++w )
8260  {
8261  if( clqpart[w] == c )
8262  {
8263  clqvars[nclqvars] = vars[w];
8264  ++nclqvars;
8265  }
8266  }
8267 
8268  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8269  if( nclqvars > 1 )
8270  {
8271  SCIP_CONS* cliquecons;
8272  char name[SCIP_MAXSTRLEN];
8273 
8274  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8275  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8279  SCIPconsIsStickingAtNode(cons)) );
8280  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8281  SCIPdebugPrintCons(scip, cliquecons, NULL);
8282  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8283  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8284  ++(*naddconss);
8285  }
8286  }
8287 
8288  /* delete old constraint */
8289  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8290  ++(*ndelconss);
8291 
8292  SCIPfreeBufferArray(scip, &clqvars);
8293 
8294  return SCIP_OKAY;
8295  }
8296 
8297  if( w > v && w < nvars - 1 )
8298  {
8299  /* try to delete variables */
8300  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8301  }
8302  }
8303 
8304  return SCIP_OKAY;
8305 }
8306 
8307 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8308 static
8309 void normalizeWeights(
8310  SCIP_CONS* cons, /**< knapsack constraint */
8311  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8312  int* nchgsides /**< pointer to count number of side changes */
8313  )
8314 {
8315  SCIP_CONSDATA* consdata;
8316  SCIP_Longint gcd;
8317  int i;
8318 
8319  assert(nchgcoefs != NULL);
8320  assert(nchgsides != NULL);
8321  assert(!SCIPconsIsModifiable(cons));
8322 
8323  consdata = SCIPconsGetData(cons);
8324  assert(consdata != NULL);
8325  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8326  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8327  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8328  assert(consdata->nvars >= 1);
8329 
8330  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8331  sortItems(consdata);
8332 
8333  gcd = consdata->weights[consdata->nvars-1];
8334  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8335  {
8336  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8337  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8338 
8339  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8340  }
8341 
8342  if( gcd >= 2 )
8343  {
8344  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8345 
8346  for( i = 0; i < consdata->nvars; ++i )
8347  {
8348  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8349  }
8350  consdata->capacity /= gcd;
8351  (*nchgcoefs) += consdata->nvars;
8352  (*nchgsides)++;
8353 
8354  /* weight should still be sorted, because the reduction preserves this */
8355 #ifndef NDEBUG
8356  for( i = consdata->nvars - 1; i > 0; --i )
8357  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8358 #endif
8359  consdata->sorted = TRUE;
8360  }
8361 }
8362 
8363 /** dual weights tightening for knapsack constraints
8364  *
8365  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8366  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8367  * constraint
8368  *
8369  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8370  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8371  *
8372  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8373  *
8374  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8375  *
8376  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8377  *
8378  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8379  *
8380  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8381  */
8382 static
8384  SCIP* scip, /**< SCIP data structure */
8385  SCIP_CONS* cons, /**< knapsack constraint */
8386  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8387  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8388  int* nchgsides, /**< pointer to store the amount of changed sides */
8389  int* naddconss /**< pointer to count number of added constraints */
8390  )
8392  SCIP_CONSDATA* consdata;
8393  SCIP_Longint* weights;
8394  SCIP_Longint dualcapacity;
8395  SCIP_Longint reductionsum;
8396  SCIP_Longint capacity;
8397  SCIP_Longint exceedsum;
8398  int oldnchgcoefs;
8399  int nvars;
8400  int vbig;
8401  int v;
8402  int w;
8403 #ifndef NDEBUG
8404  int oldnchgsides;
8405 #endif
8406 
8407  assert(scip != NULL);
8408  assert(cons != NULL);
8409  assert(ndelconss != NULL);
8410  assert(nchgcoefs != NULL);
8411  assert(nchgsides != NULL);
8412  assert(naddconss != NULL);
8413 
8414 #ifndef NDEBUG
8415  oldnchgsides = *nchgsides;
8416 #endif
8417 
8418  consdata = SCIPconsGetData(cons);
8419  assert(consdata != NULL);
8420  assert(consdata->weightsum > consdata->capacity);
8421  assert(consdata->nvars >= 2);
8422  assert(consdata->sorted);
8423 
8424  /* constraint should be merged */
8425  assert(consdata->merged);
8426 
8427  nvars = consdata->nvars;
8428  weights = consdata->weights;
8429  capacity = consdata->capacity;
8430 
8431  oldnchgcoefs = *nchgcoefs;
8432 
8433  /* case 1. */
8434  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8435  {
8436  SCIP_CONS* newcons;
8437 
8438  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8439  *
8440  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8441  */
8442  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8443 
8444  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8448  SCIPconsIsStickingAtNode(cons)) );
8449 
8450  SCIP_CALL( SCIPaddCons(scip, newcons) );
8451  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8452  ++(*naddconss);
8453 
8454  SCIP_CALL( SCIPdelCons(scip, cons) );
8455  ++(*ndelconss);
8456 
8457  return SCIP_OKAY;
8458  }
8459 
8460  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8461  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8462  {
8463  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8464  assert(SCIPconsIsDeleted(cons));
8465 
8466  return SCIP_OKAY;
8467  }
8468 
8469  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8470  /* @todo might be changed/removed when improving the coeffcients tightening */
8471  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8472  return SCIP_OKAY;
8473 
8474  /* case 2. */
8475 
8476  v = 0;
8477 
8478  /* @todo generalize the following algorithm for several parts of the knapsack
8479  *
8480  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8481  * variables each combination is a minimal cover, some examples
8482  *
8483  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8484  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8485  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8486  *
8487  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8488  *
8489  */
8490 
8491  /* determine big weights that fit only by itself */
8492  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8493  ++v;
8494 
8495  vbig = v;
8496  assert(vbig < nvars - 1);
8497  exceedsum = 0;
8498 
8499  /* determine the amount needed to exceed the capacity */
8500  while( v < nvars && exceedsum <= capacity )
8501  {
8502  exceedsum += weights[v];
8503  ++v;
8504  }
8505 
8506  /* if we exceeded the capacity we might reduce the weights */
8507  if( exceedsum > capacity )
8508  {
8509  assert(vbig > 0 || v < nvars);
8510 
8511  /* all small weights were needed to exceed the capacity */
8512  if( v == nvars )
8513  {
8514  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8515  assert(newweight > 0);
8516 
8517  /* reduce big weights */
8518  for( v = 0; v < vbig; ++v )
8519  {
8520  if( weights[v] > newweight )
8521  {
8522  consdataChgWeight(consdata, v, newweight);
8523  ++(*nchgcoefs);
8524  }
8525  }
8526 
8527  /* reduce small weights */
8528  for( ; v < nvars; ++v )
8529  {
8530  if( weights[v] > 1 )
8531  {
8532  consdataChgWeight(consdata, v, 1LL);
8533  ++(*nchgcoefs);
8534  }
8535  }
8536 
8537  consdata->capacity = newweight;
8538 
8539  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8540  * weight must not be sorted by their index
8541  */
8542 #ifndef NDEBUG
8543  for( v = nvars - 1; v > 0; --v )
8544  assert(weights[v] <= weights[v-1]);
8545 #endif
8546 
8547  return SCIP_OKAY;
8548  }
8549  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8550  * small weights
8551  */
8552  else
8553  {
8554  SCIP_Longint exceedsumback = 0;
8555  int nexceed = v - vbig;
8556 
8557  assert(nexceed > 1);
8558 
8559  /* determine weightsum of the same amount as before but of the smallest weight */
8560  for( w = nvars - 1; w >= nvars - nexceed; --w )
8561  exceedsumback += weights[w];
8562 
8563  assert(w >= 0);
8564 
8565  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8566  * combinations of all small weights
8567  */
8568  if( exceedsumback > capacity )
8569  {
8570  SCIP_Longint newweight = nexceed - 1;
8571 
8572  /* taking out the smallest element needs to fit */
8573  assert(exceedsumback - weights[nvars - 1] <= capacity);
8574 
8575  /* reduce big weights */
8576  for( v = 0; v < vbig; ++v )
8577  {
8578  if( weights[v] > newweight )
8579  {
8580  consdataChgWeight(consdata, v, newweight);
8581  ++(*nchgcoefs);
8582  }
8583  }
8584 
8585  /* reduce small weights */
8586  for( ; v < nvars; ++v )
8587  {
8588  if( weights[v] > 1 )
8589  {
8590  consdataChgWeight(consdata, v, 1LL);
8591  ++(*nchgcoefs);
8592  }
8593  }
8594 
8595  consdata->capacity = newweight;
8596 
8597  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8598  * weight must not be sorted by their index
8599  */
8600 #ifndef NDEBUG
8601  for( v = nvars - 1; v > 0; --v )
8602  assert(weights[v] <= weights[v-1]);
8603 #endif
8604  return SCIP_OKAY;
8605  }
8606  }
8607  }
8608  else
8609  {
8610  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8611  * not happen here
8612  */
8613  assert(vbig > 0 && vbig < nvars);
8614 
8615  /* either choose a big coefficients or all other variables
8616  *
8617  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8618  *
8619  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8620  * constraint to
8621  *
8622  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8623  */
8624 
8625  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8626  {
8627  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8628 #ifndef NDEBUG
8629  SCIP_Longint resweightsum = consdata->weightsum;
8630 
8631  for( v = 0; v < vbig; ++v )
8632  resweightsum -= weights[v];
8633 
8634  assert(exceedsum == resweightsum);
8635 #endif
8636  assert(newweight > 0);
8637 
8638  /* reduce big weights */
8639  for( v = 0; v < vbig; ++v )
8640  {
8641  if( weights[v] > newweight )
8642  {
8643  consdataChgWeight(consdata, v, newweight);
8644  ++(*nchgcoefs);
8645  }
8646  }
8647 
8648  /* reduce small weights */
8649  for( ; v < nvars; ++v )
8650  {
8651  if( weights[v] > 1 )
8652  {
8653  consdataChgWeight(consdata, v, 1LL);
8654  ++(*nchgcoefs);
8655  }
8656  }
8657 
8658  consdata->capacity = newweight;
8659 
8660  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8661  * weight must not be sorted by their index
8662  */
8663 #ifndef NDEBUG
8664  for( v = nvars - 1; v > 0; --v )
8665  assert(weights[v] <= weights[v-1]);
8666 #endif
8667  return SCIP_OKAY;
8668  }
8669  }
8670 
8671  /* case 3. */
8672 
8673  dualcapacity = consdata->weightsum - capacity;
8674  reductionsum = 0;
8675  v = 0;
8676 
8677  /* reduce big weights
8678  *
8679  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8680  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8681  * <=> x0 + x1 + x2 + x3 <= 3
8682  */
8683  while( weights[v] > dualcapacity )
8684  {
8685  reductionsum += (weights[v] - dualcapacity);
8686  consdataChgWeight(consdata, v, dualcapacity);
8687  ++v;
8688  assert(v < nvars);
8689  }
8690  (*nchgcoefs) += v;
8691 
8692  /* skip weights equal to the dualcapacity, because we cannot change them */
8693  while( v < nvars && weights[v] == dualcapacity )
8694  ++v;
8695 
8696  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8697  * after a possible removal of the last, redundant item
8698  *
8699  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8700  */
8701  if( v >= nvars - 1 )
8702  {
8703  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8704  if( v == nvars - 1 )
8705  {
8706  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8707  }
8708  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8709  assert(SCIPconsIsDeleted(cons));
8710 
8711  return SCIP_OKAY;
8712  }
8713  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8714  {
8715  /* @todo generalize the following algorithm for more than two variables */
8716 
8717  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8718  {
8719  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8720  * coefficients) of all or two variables of the rest
8721  *
8722  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8723  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8724  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8725  *
8726  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8727  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8728  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8729  *
8730  */
8731  if( v > 0 && weights[nvars - 2] > 1 )
8732  {
8733  int ncoefchg = 0;
8734 
8735  /* reduce all bigger weights */
8736  for( w = 0; w < v; ++w )
8737  {
8738  if( weights[w] > 2 )
8739  {
8740  consdataChgWeight(consdata, w, 2LL);
8741  ++ncoefchg;
8742  }
8743  else
8744  {
8745  assert(weights[0] == 2);
8746  assert(weights[v - 1] == 2);
8747  break;
8748  }
8749  }
8750 
8751  /* reduce all smaller weights */
8752  for( w = v; w < nvars; ++w )
8753  {
8754  if( weights[w] > 1 )
8755  {
8756  consdataChgWeight(consdata, w, 1LL);
8757  ++ncoefchg;
8758  }
8759  }
8760  assert(ncoefchg > 0);
8761 
8762  (*nchgcoefs) += ncoefchg;
8763 
8764  /* correct the capacity */
8765  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8766  assert(consdata->capacity > 0);
8767  assert(weights[0] <= consdata->capacity);
8768  assert(consdata->weightsum > consdata->capacity);
8769  /* reset the reductionsum */
8770  reductionsum = 0;
8771  }
8772  else if( v == 0 )
8773  {
8774  assert(weights[nvars - 2] == 1);
8775  }
8776  }
8777  else
8778  {
8779  SCIP_Longint minweight = weights[nvars - 1];
8780  SCIP_Longint newweight = dualcapacity - minweight;
8781  SCIP_Longint restsumweights = 0;
8782  SCIP_Longint sumcoef;
8783  SCIP_Bool sumcoefcase = FALSE;
8784  int startv = v;
8785  int end;
8786  int k;
8787 
8788  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8789 
8790  /* reduce big weights of pairs that exceed the dualcapacity
8791  *
8792  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8793  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8794  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8795  */
8796  while( weights[v] > newweight )
8797  {
8798  reductionsum += (weights[v] - newweight);
8799  consdataChgWeight(consdata, v, newweight);
8800  ++v;
8801  assert(v < nvars);
8802  }
8803  (*nchgcoefs) += (v - startv);
8804 
8805  /* skip equal weights */
8806  while( weights[v] == newweight )
8807  ++v;
8808 
8809  if( v > 0 )
8810  {
8811  for( w = v; w < nvars; ++w )
8812  restsumweights += weights[w];
8813  }
8814  else
8815  restsumweights = consdata->weightsum;
8816 
8817  if( restsumweights < dualcapacity )
8818  {
8819  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8820  *
8821  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8822  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8823  */
8824  if( startv == v )
8825  {
8826  /* remove redundant variables */
8827  for( w = nvars - 1; w >= v; --w )
8828  {
8829  SCIP_CALL( delCoefPos(scip, cons, v) );
8830  ++(*nchgcoefs);
8831  }
8832 
8833 #ifndef NDEBUG
8834  /* each coefficients should exceed the dualcapacity by itself */
8835  for( ; w >= 0; --w )
8836  assert(weights[w] == dualcapacity);
8837 #endif
8838  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8839  * upgrade this constraint
8840  */
8841  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8842  assert(SCIPconsIsDeleted(cons));
8843 
8844  return SCIP_OKAY;
8845  }
8846 
8847  /* special case where we have three different coefficient types
8848  *
8849  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8850  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8851  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8852  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8853  */
8854  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8855  {
8856  SCIP_Longint newcap;
8857 
8858  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8859  for( w = nvars - 1; w >= v; --w )
8860  {
8861  if( weights[w] > 1 )
8862  {
8863  consdataChgWeight(consdata, w, 1LL);
8864  ++(*nchgcoefs);
8865  }
8866  }
8867 
8868  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8869  * dualcapacity
8870  */
8871  newweight = (SCIP_Longint)nvars - v;
8872  assert(newweight > 1);
8873  for( ; w >= startv; --w )
8874  {
8875  if( weights[w] > newweight )
8876  {
8877  consdataChgWeight(consdata, w, newweight);
8878  ++(*nchgcoefs);
8879  }
8880  else
8881  assert(weights[w] == newweight);
8882  }
8883 
8884  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8885  ++newweight;
8886  assert(newweight > 2);
8887  for( ; w >= 0; --w )
8888  {
8889  if( weights[w] > newweight )
8890  {
8891  consdataChgWeight(consdata, w, newweight);
8892  ++(*nchgcoefs);
8893  }
8894  else
8895  assert(weights[w] == newweight);
8896  }
8897 
8898  /* update the capacity */
8899  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8900  if( consdata->capacity > newcap )
8901  {
8902  consdata->capacity = newcap;
8903  ++(*nchgsides);
8904  }
8905  else
8906  assert(consdata->capacity == newcap);
8907  }
8908  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8909 
8910  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8911  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8912 
8913  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8914  * weight must not be sorted by their index
8915  */
8916 #ifndef NDEBUG
8917  for( w = nvars - 1; w > 0; --w )
8918  assert(weights[w] <= weights[w - 1]);
8919 #endif
8920  return SCIP_OKAY;
8921  }
8922 
8923  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8924  end = nvars - 2;
8925  while( end >= 0 && weights[end] == weights[end + 1] )
8926  {
8927  assert(end >= v);
8928  --end;
8929  }
8930 
8931  if( v >= end )
8932  goto TERMINATE;
8933 
8934  end = nvars - 2;
8935 
8936  /* can we stop early, another special reduction case might exist */
8937  if( 2 * weights[end] > dualcapacity )
8938  {
8939  restsumweights = 0;
8940 
8941  /* determine capacity of the small items */
8942  for( w = end + 1; w < nvars; ++w )
8943  restsumweights += weights[w];
8944 
8945  if( restsumweights * 2 <= dualcapacity )
8946  {
8947  /* check for further posssible reductions in the middle */
8948  while( v < end && restsumweights + weights[v] >= dualcapacity )
8949  ++v;
8950 
8951  if( v >= end )
8952  goto TERMINATE;
8953 
8954  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8955  if( (dualcapacity & 1) == 0 )
8956  {
8957  newweight = dualcapacity / 2;
8958 
8959  /* set all middle coefficients */
8960  for( ; v <= end; ++v )
8961  {
8962  if( weights[v] > newweight )
8963  {
8964  reductionsum += (weights[v] - newweight);
8965  consdataChgWeight(consdata, v, newweight);
8966  ++(*nchgcoefs);
8967  }
8968  }
8969  }
8970  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8971  * other coefficients by 2
8972  */
8973  else
8974  {
8975  /* correct the reductionsum */
8976  reductionsum *= 2;
8977 
8978  /* multiply big coefficients by 2 */
8979  for( w = 0; w < v; ++w )
8980  {
8981  consdataChgWeight(consdata, w, weights[w] * 2);
8982  }
8983 
8984  newweight = dualcapacity;
8985  /* set all middle coefficients */
8986  for( ; v <= end; ++v )
8987  {
8988  reductionsum += (2 * weights[v] - newweight);
8989  consdataChgWeight(consdata, v, newweight);
8990  }
8991 
8992  /* multiply small coefficients by 2 */
8993  for( w = end + 1; w < nvars; ++w )
8994  {
8995  consdataChgWeight(consdata, w, weights[w] * 2);
8996  }
8997  (*nchgcoefs) += nvars;
8998 
8999  dualcapacity *= 2;
9000  consdata->capacity *= 2;
9001  ++(*nchgsides);
9002  }
9003  }
9004 
9005  goto TERMINATE;
9006  }
9007 
9008  /* further reductions using the next possible coefficient sum
9009  *
9010  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9011  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9012  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9013  */
9014  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9015  for( k = 0; k < 4; ++k )
9016  {
9017  /* determine next minimal coefficient sum */
9018  switch( k )
9019  {
9020  case 0:
9021  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9022  break;
9023  case 1:
9024  assert(nvars >= 3);
9025  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9026  break;
9027  case 2:
9028  assert(nvars >= 4);
9029  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9030  {
9031  sumcoefcase = TRUE;
9032  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9033  }
9034  else
9035  {
9036  sumcoefcase = FALSE;
9037  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9038  }
9039  break;
9040  case 3:
9041  assert(nvars >= 5);
9042  if( sumcoefcase )
9043  {
9044  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9045  }
9046  else
9047  {
9048  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9049  }
9050  break;
9051  default:
9052  return SCIP_ERROR;
9053  }
9054 
9055  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9056  minweight = weights[end];
9057  while( minweight <= sumcoef )
9058  {
9059  newweight = dualcapacity - minweight;
9060  startv = v;
9061  assert(v < nvars);
9062 
9063  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9064  /* shrink big coefficients */
9065  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9066  {
9067  reductionsum += (weights[v] - newweight);
9068  consdataChgWeight(consdata, v, newweight);
9069  ++v;
9070  assert(v < nvars);
9071  }
9072  (*nchgcoefs) += (v - startv);
9073 
9074  /* skip unchangable weights */
9075  while( weights[v] + minweight == dualcapacity )
9076  {
9077  assert(v < nvars);
9078  ++v;
9079  }
9080 
9081  --end;
9082  /* skip same end weights */
9083  while( end >= 0 && weights[end] == weights[end + 1] )
9084  --end;
9085 
9086  if( v >= end )
9087  goto TERMINATE;
9088 
9089  minweight = weights[end];
9090  }
9091 
9092  if( v >= end )
9093  goto TERMINATE;
9094 
9095  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9096  if( sumcoef < minweight )
9097  {
9098  minweight = sumcoef;
9099  newweight = dualcapacity - minweight;
9100  startv = v;
9101  assert(v < nvars);
9102 
9103  /* shrink big coefficients */
9104  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9105  {
9106  reductionsum += (weights[v] - newweight);
9107  consdataChgWeight(consdata, v, newweight);
9108  ++v;
9109  assert(v < nvars);
9110  }
9111  (*nchgcoefs) += (v - startv);
9112 
9113  /* skip unchangable weights */
9114  while( weights[v] + minweight == dualcapacity )
9115  {
9116  assert(v < nvars);
9117  ++v;
9118  }
9119  }
9120 
9121  if( v >= end )
9122  goto TERMINATE;
9123 
9124  /* can we stop early, another special reduction case might exist */
9125  if( 2 * weights[end] > dualcapacity )
9126  {
9127  restsumweights = 0;
9128 
9129  /* determine capacity of the small items */
9130  for( w = end + 1; w < nvars; ++w )
9131  restsumweights += weights[w];
9132 
9133  if( restsumweights * 2 <= dualcapacity )
9134  {
9135  /* check for further posssible reductions in the middle */
9136  while( v < end && restsumweights + weights[v] >= dualcapacity )
9137  ++v;
9138 
9139  if( v >= end )
9140  goto TERMINATE;
9141 
9142  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9143  if( (dualcapacity & 1) == 0 )
9144  {
9145  newweight = dualcapacity / 2;
9146 
9147  /* set all middle coefficients */
9148  for( ; v <= end; ++v )
9149  {
9150  if( weights[v] > newweight )
9151  {
9152  reductionsum += (weights[v] - newweight);
9153  consdataChgWeight(consdata, v, newweight);
9154  ++(*nchgcoefs);
9155  }
9156  }
9157  }
9158  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9159  * other coefficients by 2
9160  */
9161  else
9162  {
9163  /* correct the reductionsum */
9164  reductionsum *= 2;
9165 
9166  /* multiply big coefficients by 2 */
9167  for( w = 0; w < v; ++w )
9168  {
9169  consdataChgWeight(consdata, w, weights[w] * 2);
9170  }
9171 
9172  newweight = dualcapacity;
9173  /* set all middle coefficients */
9174  for( ; v <= end; ++v )
9175  {
9176  reductionsum += (2 * weights[v] - newweight);
9177  consdataChgWeight(consdata, v, newweight);
9178  }
9179 
9180  /* multiply small coefficients by 2 */
9181  for( w = end + 1; w < nvars; ++w )
9182  {
9183  consdataChgWeight(consdata, w, weights[w] * 2);
9184  }
9185  (*nchgcoefs) += nvars;
9186 
9187  dualcapacity *= 2;
9188  consdata->capacity *= 2;
9189  ++(*nchgsides);
9190  }
9191  }
9192 
9193  goto TERMINATE;
9194  }
9195 
9196  /* cannot tighten any further */
9197  if( 2 * sumcoef > dualcapacity )
9198  goto TERMINATE;
9199  }
9200  }
9201  }
9202 
9203 
9204  TERMINATE:
9205  /* correct capacity */
9206  if( reductionsum > 0 )
9207  {
9208  assert(v > 0);
9209 
9210  consdata->capacity -= reductionsum;
9211  ++(*nchgsides);
9212 
9213  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9214  }
9215  assert(weights[0] <= consdata->capacity);
9216 
9217  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9218  * weight must not be sorted by their index
9219  */
9220 #ifndef NDEBUG
9221  for( w = nvars - 1; w > 0; --w )
9222  assert(weights[w] <= weights[w - 1]);
9223 #endif
9224 
9225  if( oldnchgcoefs < *nchgcoefs )
9226  {
9227  assert(!SCIPconsIsDeleted(cons));
9228 
9229  /* it might be that we can divide the weights by their greatest common divisor */
9230  normalizeWeights(cons, nchgcoefs, nchgsides);
9231  }
9232  else
9233  {
9234  assert(oldnchgcoefs == *nchgcoefs);
9235  assert(oldnchgsides == *nchgsides);
9236  }
9237 
9238  return SCIP_OKAY;
9239 }
9240 
9241 
9242 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9243 static
9245  SCIP* scip, /**< SCIP data structure */
9246  SCIP_CONS* cons, /**< knapsack constraint */
9247  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9248  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9249  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9250  )
9251 {
9252  SCIP_VAR** vars;
9253  SCIP_CONSDATA* consdata;
9254  SCIP_Longint* weights;
9255  SCIP_Longint capacity;
9256  SCIP_Bool infeasible;
9257  SCIP_Bool fixed;
9258  int nvars;
9259  int v;
9260 
9261  assert(scip != NULL);
9262  assert(cons != NULL);
9263  assert(nfixedvars != NULL);
9264  assert(ndelconss != NULL);
9265  assert(nchgcoefs != NULL);
9266 
9267  consdata = SCIPconsGetData(cons);
9268  assert(consdata != NULL);
9269 
9270  nvars = consdata->nvars;
9271 
9272  /* no variables left, then delete constraint */
9273  if( nvars == 0 )
9274  {
9275  assert(consdata->capacity >= 0);
9276 
9277  SCIP_CALL( SCIPdelCons(scip, cons) );
9278  ++(*ndelconss);
9279 
9280  return SCIP_OKAY;
9281  }
9282 
9283  /* sort items */
9284  sortItems(consdata);
9285 
9286  vars = consdata->vars;
9287  weights = consdata->weights;
9288  capacity = consdata->capacity;
9289  v = 0;
9290 
9291  /* check for weights bigger than the capacity */
9292  while( v < nvars && weights[v] > capacity )
9293  {
9294  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9295  assert(!infeasible);
9296 
9297  if( fixed )
9298  ++(*nfixedvars);
9299 
9300  ++v;
9301  }
9302 
9303  /* if we fixed at least one variable we need to delete them from the constraint */
9304  if( v > 0 )
9305  {
9306  if( v == nvars )
9307  {
9308  SCIP_CALL( SCIPdelCons(scip, cons) );
9309  ++(*ndelconss);
9310 
9311  return SCIP_OKAY;
9312  }
9313 
9314  /* delete all position from back to front */
9315  for( --v; v >= 0; --v )
9316  {
9317  SCIP_CALL( delCoefPos(scip, cons, v) );
9318  ++(*nchgcoefs);
9319  }
9320 
9321  /* sort items again because of deletion */
9322  sortItems(consdata);
9323  assert(vars == consdata->vars);
9324  assert(weights == consdata->weights);
9325  }
9326  assert(consdata->sorted);
9327  assert(weights[0] <= capacity);
9328 
9329  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9330  {
9331  SCIP_CALL( SCIPdelCons(scip, cons) );
9332  ++(*ndelconss);
9333  }
9334 
9335  return SCIP_OKAY;
9336 }
9337 
9338 
9339 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9340  *
9341  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9342  *
9343  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9344  *
9345  * the above constraint can be changed to
9346  *
9347  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9348  *
9349  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9350  *
9351  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9352  *
9353  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9354  * constraint further, e.g.
9355  *
9356  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9357  * => 2x1 + x2 + x3 + x4 <= 2
9358  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9359  */
9360 static
9362  SCIP* scip, /**< SCIP data structure */
9363  SCIP_CONS* cons, /**< knapsack constraint */
9364  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9365  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9366  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9367  int* nchgsides, /**< pointer to store the amount of changed sides */
9368  int* naddconss, /**< pointer to count number of added constraints */
9369  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9370  )
9371 {
9372  SCIP_VAR** vars;
9373  SCIP_CONSDATA* consdata;
9374  SCIP_Longint* weights;
9375  SCIP_Longint restweight;
9376  SCIP_Longint newweight;
9377  SCIP_Longint weight;
9378  SCIP_Longint oldgcd;
9379  SCIP_Longint rest;
9380  SCIP_Longint gcd;
9381  int oldnchgcoefs;
9382  int oldnchgsides;
9383  int candpos;
9384  int candpos2;
9385  int offsetv;
9386  int nvars;
9387  int v;
9388 
9389  assert(scip != NULL);
9390  assert(cons != NULL);
9391  assert(nfixedvars != NULL);
9392  assert(ndelconss != NULL);
9393  assert(nchgcoefs != NULL);
9394  assert(nchgsides != NULL);
9395  assert(naddconss != NULL);
9396  assert(cutoff != NULL);
9397  assert(!SCIPconsIsModifiable(cons));
9398 
9399  consdata = SCIPconsGetData(cons);
9400  assert( consdata != NULL );
9401 
9402  *cutoff = FALSE;
9403 
9404  /* remove double enties and also combinations of active and negated variables */
9405  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9406  assert(consdata->merged);
9407  if( *cutoff )
9408  return SCIP_OKAY;
9409 
9410  assert(consdata->capacity >= 0);
9411 
9412  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9413  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9414 
9415  if( SCIPconsIsDeleted(cons) )
9416  return SCIP_OKAY;
9417 
9418  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9419  {
9420  /* 1. dual weights tightening */
9421  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9422 
9423  if( SCIPconsIsDeleted(cons) )
9424  return SCIP_OKAY;
9425  /* 2. delete redundant variables */
9426  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9427 
9428  if( SCIPconsIsDeleted(cons) )
9429  return SCIP_OKAY;
9430  }
9431 
9432  weights = consdata->weights;
9433  nvars = consdata->nvars;
9434 
9435 #ifndef NDEBUG
9436  /* constraint might not be sorted, but the weights are already sorted */
9437  for( v = nvars - 1; v > 0; --v )
9438  assert(weights[v] <= weights[v-1]);
9439 #endif
9440 
9441  /* determine greatest common divisor */
9442  gcd = weights[nvars - 1];
9443  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9444  {
9445  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9446  }
9447 
9448  /* divide the constraint by their greatest common divisor */
9449  if( gcd >= 2 )
9450  {
9451  for( v = nvars - 1; v >= 0; --v )
9452  {
9453  consdataChgWeight(consdata, v, weights[v]/gcd);
9454  }
9455  (*nchgcoefs) += nvars;
9456 
9457  consdata->capacity /= gcd;
9458  (*nchgsides)++;
9459  }
9460  assert(consdata->nvars == nvars);
9461 
9462  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9463  * must not be sorted by their index
9464  */
9465 #ifndef NDEBUG
9466  for( v = nvars - 1; v > 0; --v )
9467  assert(weights[v] <= weights[v-1]);
9468 #endif
9469 
9470  /* 3. start gcd procedure for all variables */
9471  do
9472  {
9473  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9474  SCIPdebug( oldnchgsides = *nchgsides; )
9475 
9476  vars = consdata->vars;
9477  weights = consdata->weights;
9478  nvars = consdata->nvars;
9479 
9480  /* stop if we have two coefficients which are one in absolute value */
9481  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9482  return SCIP_OKAY;
9483 
9484  v = 0;
9485  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9486  * gcd
9487  */
9488  while( weights[v] == consdata->capacity )
9489  {
9490  ++v;
9491  assert(v < nvars);
9492  }
9493 
9494  /* all but one variable are as big as the capacity, this is handled elsewhere */
9495  if( v == nvars - 1 )
9496  return SCIP_OKAY;
9497 
9498  offsetv = v;
9499 
9500  gcd = -1;
9501  candpos = -1;
9502  candpos2 = -1;
9503 
9504  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9505  * change the coefficient
9506  */
9507  for( v = nvars - 1; v >= offsetv; --v )
9508  {
9509  weight = weights[v];
9510  assert(weight >= 1);
9511 
9512  oldgcd = gcd;
9513 
9514  if( gcd == -1 )
9515  {
9516  gcd = weights[v];
9517  assert(gcd >= 1);
9518  }
9519  else
9520  {
9521  /* calculate greatest common divisor for all variables */
9522  gcd = SCIPcalcGreComDiv(gcd, weight);
9523  }
9524 
9525  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9526  * can terminate
9527  */
9528  if( gcd == 1 )
9529  {
9530  /* found candidate */
9531  if( candpos == -1 )
9532  {
9533  gcd = oldgcd;
9534  candpos = v;
9535 
9536  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9537  if( v == nvars - 2 )
9538  candpos2 = v + 1;
9539  }
9540  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9541  else
9542  {
9543  if( candpos == v + 1 && candpos2 == v + 2 )
9544  {
9545  assert(candpos2 == nvars - 1);
9546 
9547  /* take new candidates */
9548  candpos = candpos2;
9549 
9550  /* recalculate gcd from scratch */
9551  gcd = weights[v+1];
9552  assert(gcd >= 1);
9553 
9554  /* calculate greatest common divisor for variables */
9555  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9556  if( gcd == 1 )
9557  return SCIP_OKAY;
9558  }
9559  else
9560  /* cannot determine a possible coefficient for reduction */
9561  return SCIP_OKAY;
9562  }
9563  }
9564  }
9565  assert(gcd >= 2);
9566 
9567  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9568  * further
9569  */
9570  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9571 
9572  /* determine the remainder of the capacity and the gcd */
9573  rest = consdata->capacity % gcd;
9574  assert(rest >= 0);
9575  assert(rest < gcd);
9576 
9577  if( candpos == -1 )
9578  {
9579  /* we assume that the constraint was normalized */
9580  assert(rest > 0);
9581 
9582  /* replace old with new capacity */
9583  consdata->capacity -= rest;
9584  ++(*nchgsides);
9585 
9586  /* replace old big coefficients with new capacity */
9587  for( v = 0; v < offsetv; ++v )
9588  {
9589  consdataChgWeight(consdata, v, consdata->capacity);
9590  }
9591 
9592  *nchgcoefs += offsetv;
9593  goto CONTINUE;
9594  }
9595 
9596  /* determine the remainder of the coefficient candidate and the gcd */
9597  restweight = weights[candpos] % gcd;
9598  assert(restweight >= 1);
9599  assert(restweight < gcd);
9600 
9601  /* calculate new coefficient */
9602  if( restweight > rest )
9603  newweight = weights[candpos] - restweight + gcd;
9604  else
9605  newweight = weights[candpos] - restweight;
9606 
9607  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9608 
9609  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);
9610 
9611  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9612  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9613  */
9614  if( newweight == 0 && offsetv > 0 )
9615  return SCIP_OKAY;
9616 
9617  if( rest > 0 )
9618  {
9619  /* replace old with new capacity */
9620  consdata->capacity -= rest;
9621  ++(*nchgsides);
9622 
9623  /* replace old big coefficients with new capacity */
9624  for( v = 0; v < offsetv; ++v )
9625  {
9626  consdataChgWeight(consdata, v, consdata->capacity);
9627  }
9628 
9629  *nchgcoefs += offsetv;
9630  }
9631 
9632  if( newweight == 0 )
9633  {
9634  /* delete redundant coefficient */
9635  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9636  assert(consdata->nvars == nvars - 1);
9637  --nvars;
9638  }
9639  else
9640  {
9641  /* replace old with new coefficient */
9642  consdataChgWeight(consdata, candpos, newweight);
9643  }
9644  ++(*nchgcoefs);
9645 
9646  assert(consdata->vars == vars);
9647  assert(consdata->nvars == nvars);
9648  assert(consdata->weights == weights);
9649 
9650  CONTINUE:
9651  /* now constraint can be normalized, dividing it by the gcd */
9652  for( v = nvars - 1; v >= 0; --v )
9653  {
9654  consdataChgWeight(consdata, v, weights[v]/gcd);
9655  }
9656  (*nchgcoefs) += nvars;
9657 
9658  consdata->capacity /= gcd;
9659  ++(*nchgsides);
9660 
9661  SCIPdebugPrintCons(scip, cons, NULL);
9662 
9663  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));
9664  }
9665  while( nvars >= 2 );
9666 
9667  return SCIP_OKAY;
9668 }
9669 
9670 
9671 /** inserts an element into the list of binary zero implications */
9672 static
9674  SCIP* scip, /**< SCIP data structure */
9675  int** liftcands, /**< array of the lifting candidates */
9676  int* nliftcands, /**< number of lifting candidates */
9677  int** firstidxs, /**< array of first zeroitems indices */
9678  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9679  int** zeroitems, /**< pointer to zero items array */
9680  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9681  int* zeroitemssize, /**< pointer to size of zero items array */
9682  int* nzeroitems, /**< pointer to length of zero items array */
9683  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9684  SCIP_Bool value, /**< value v of variable y in implication */
9685  int knapsackidx, /**< index of variable x in knapsack */
9686  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9687  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9688  )
9689 {
9690  int nzeros;
9691 
9692  assert(liftcands != NULL);
9693  assert(liftcands[value] != NULL);
9694  assert(nliftcands != NULL);
9695  assert(firstidxs != NULL);
9696  assert(firstidxs[value] != NULL);
9697  assert(zeroweightsums != NULL);
9698  assert(zeroweightsums[value] != NULL);
9699  assert(zeroitems != NULL);
9700  assert(nextidxs != NULL);
9701  assert(zeroitemssize != NULL);
9702  assert(nzeroitems != NULL);
9703  assert(*nzeroitems <= *zeroitemssize);
9704  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9705  assert(memlimitreached != NULL);
9706 
9707  nzeros = *nzeroitems;
9708 
9709  /* allocate enough memory */
9710  if( nzeros == *zeroitemssize )
9711  {
9712  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9713  * this can be too huge - abort on memory limit
9714  */
9715  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9716  {
9717  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9718  *zeroitemssize);
9719  *memlimitreached = TRUE;
9720  return SCIP_OKAY;
9721  }
9722  *zeroitemssize *= 2;
9723  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9724  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9725  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9726  }
9727  assert(nzeros < *zeroitemssize);
9728 
9729  if( *memlimitreached )
9730  *memlimitreached = FALSE;
9731 
9732  /* insert element */
9733  (*zeroitems)[nzeros] = knapsackidx;
9734  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9735  if( firstidxs[value][probindex] == 0 )
9736  {
9737  liftcands[value][nliftcands[value]] = probindex;
9738  ++nliftcands[value];
9739  }
9740  firstidxs[value][probindex] = nzeros;
9741  ++(*nzeroitems);
9742  zeroweightsums[value][probindex] += knapsackweight;
9743 
9744  return SCIP_OKAY;
9745 }
9746 
9747 #define MAX_CLIQUELENGTH 50
9748 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9749  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9750  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9751  * if cliqueweightsum(xi == v) < capacity:
9752  * - fixing variable xi to v would make the knapsack constraint redundant
9753  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9754  * redundancy effect:
9755  * wi' := capacity - cliqueweightsum(xi == v)
9756  * this rule can also be applied to binary variables not in the knapsack!
9757  */
9758 static
9760  SCIP* scip, /**< SCIP data structure */
9761  SCIP_CONS* cons, /**< knapsack constraint */
9762  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9763  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9764  )
9765 {
9766  SCIP_CONSDATA* consdata;
9767  SCIP_VAR** binvars;
9768  int nbinvars;
9769  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9770  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9771  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9772  int* zeroitems; /* item number in knapsack that is implied to zero */
9773  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9774  int zeroitemssize;
9775  int nzeroitems;
9776  SCIP_Bool* zeroiteminserted[2];
9777  SCIP_Bool memlimitreached;
9778  int nliftcands[2];
9779  SCIP_Bool* cliqueused;
9780  SCIP_Bool* itemremoved;
9781  SCIP_Longint maxcliqueweightsum;
9782  SCIP_VAR** addvars;
9783  SCIP_Longint* addweights;
9784  SCIP_Longint addweightsum;
9785  int nvars;
9786  int cliquenum;
9787  int naddvars;
9788  int val;
9789  int i;
9790 
9791  int* tmpindices;
9792  SCIP_Bool* tmpboolindices;
9793  int* tmpindices2;
9794  SCIP_Bool* tmpboolindices2;
9795  int* tmpindices3;
9796  SCIP_Bool* tmpboolindices3;
9797  int tmp;
9798  int tmp2;
9799  int tmp3;
9800  SCIP_CONSHDLR* conshdlr;
9801  SCIP_CONSHDLRDATA* conshdlrdata;
9802 
9803  assert(nchgcoefs != NULL);
9804  assert(!SCIPconsIsModifiable(cons));
9805 
9806  consdata = SCIPconsGetData(cons);
9807  assert(consdata != NULL);
9808  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9809  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9810  assert(consdata->nvars > 0);
9811  assert(consdata->merged);
9812 
9813  nvars = consdata->nvars;
9814 
9815  /* check if the knapsack has too many items/cliques for applying this costly method */
9816  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9817  return SCIP_OKAY;
9818 
9819  /* sort items, s.t. the heaviest one is in the first position */
9820  sortItems(consdata);
9821 
9822  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9823  return SCIP_OKAY;
9824 
9825  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9826  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9827  assert(nbinvars > 0);
9828  binvars = SCIPgetVars(scip);
9829 
9830  /* get conshdlrdata to use cleared memory */
9831  conshdlr = SCIPconsGetHdlr(cons);
9832  assert(conshdlr != NULL);
9833  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9834  assert(conshdlrdata != NULL);
9835 
9836  /* allocate temporary memory for the list of implied to zero variables */
9837  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9838  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9839  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9840 
9841  assert(conshdlrdata->ints1size > 0);
9842  assert(conshdlrdata->ints2size > 0);
9843  assert(conshdlrdata->longints1size > 0);
9844  assert(conshdlrdata->longints2size > 0);
9845 
9846  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9847  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9848  * transform all integers into their binary representation then it maybe happens
9849  */
9850  if( conshdlrdata->ints1size < nbinvars )
9851  {
9852  int oldsize = conshdlrdata->ints1size;
9853 
9854  conshdlrdata->ints1size = nbinvars;
9855  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9856  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9857  }
9858  if( conshdlrdata->ints2size < nbinvars )
9859  {
9860  int oldsize = conshdlrdata->ints2size;
9861 
9862  conshdlrdata->ints2size = nbinvars;
9863  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9864  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9865  }
9866  if( conshdlrdata->longints1size < nbinvars )
9867  {
9868  int oldsize = conshdlrdata->longints1size;
9869 
9870  conshdlrdata->longints1size = nbinvars;
9871  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9872  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9873  }
9874  if( conshdlrdata->longints2size < nbinvars )
9875  {
9876  int oldsize = conshdlrdata->longints2size;
9877 
9878  conshdlrdata->longints2size = nbinvars;
9879  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9880  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9881  }
9882 
9883  firstidxs[0] = conshdlrdata->ints1;
9884  firstidxs[1] = conshdlrdata->ints2;
9885  zeroweightsums[0] = conshdlrdata->longints1;
9886  zeroweightsums[1] = conshdlrdata->longints2;
9887 
9888  /* check for cleared arrays, all entries are zero */
9889 #ifndef NDEBUG
9890  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9891  {
9892  assert(firstidxs[0][tmp] == 0);
9893  assert(firstidxs[1][tmp] == 0);
9894  assert(zeroweightsums[0][tmp] == 0);
9895  assert(zeroweightsums[1][tmp] == 0);
9896  }
9897 #endif
9898 
9899  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9900  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9901 
9902  zeroitems[0] = -1; /* dummy element */
9903  nextidxs[0] = -1;
9904  nzeroitems = 1;
9905  nliftcands[0] = 0;
9906  nliftcands[1] = 0;
9907 
9908  assert(conshdlrdata->bools1size > 0);
9909  assert(conshdlrdata->bools2size > 0);
9910 
9911  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9912  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9913  * transform all integers into their binary representation then it maybe happens
9914  */
9915  if( conshdlrdata->bools1size < nbinvars )
9916  {
9917  int oldsize = conshdlrdata->bools1size;
9918 
9919  conshdlrdata->bools1size = nbinvars;
9920  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9921  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9922  }
9923  if( conshdlrdata->bools2size < nbinvars )
9924  {
9925  int oldsize = conshdlrdata->bools2size;
9926 
9927  conshdlrdata->bools2size = nbinvars;
9928  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9929  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9930  }
9931 
9932  zeroiteminserted[0] = conshdlrdata->bools1;
9933  zeroiteminserted[1] = conshdlrdata->bools2;
9934 
9935  /* check for cleared arrays, all entries are zero */
9936 #ifndef NDEBUG
9937  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9938  {
9939  assert(zeroiteminserted[0][tmp] == 0);
9940  assert(zeroiteminserted[1][tmp] == 0);
9941  }
9942 #endif
9943 
9944  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9945  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9946  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9947  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9948  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9949  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9950  tmp2 = 0;
9951  tmp3 = 0;
9952 
9953  memlimitreached = FALSE;
9954  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9955  {
9956  SCIP_CLIQUE** cliques;
9957  SCIP_VAR* var;
9958  SCIP_Longint weight;
9959  SCIP_Bool value;
9960  int varprobindex;
9961  int ncliques;
9962  int j;
9963 
9964  tmp = 0;
9965 
9966  /* get corresponding active problem variable */
9967  var = consdata->vars[i];
9968  weight = consdata->weights[i];
9969  value = TRUE;
9970  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9971  varprobindex = SCIPvarGetProbindex(var);
9972  assert(0 <= varprobindex && varprobindex < nbinvars);
9973 
9974  /* update the zeroweightsum */
9975  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9976  tmpboolindices3[tmp3] = !value;
9977  tmpindices3[tmp3] = varprobindex;
9978  ++tmp3;
9979 
9980  /* initialize the arrays of inserted zero items */
9981  /* first add the implications (~x == 1 -> x == 0) */
9982  {
9983  SCIP_Bool implvalue;
9984  int probindex;
9985 
9986  probindex = SCIPvarGetProbindex(var);
9987  assert(0 <= probindex && probindex < nbinvars);
9988 
9989  implvalue = !value;
9990 
9991  /* insert the item into the list of the implied variable/value */
9992  assert( !zeroiteminserted[implvalue][probindex] );
9993 
9994  if( firstidxs[implvalue][probindex] == 0 )
9995  {
9996  tmpboolindices2[tmp2] = implvalue;
9997  tmpindices2[tmp2] = probindex;
9998  ++tmp2;
9999  }
10000  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10001  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10002  &memlimitreached) );
10003  zeroiteminserted[implvalue][probindex] = TRUE;
10004  tmpboolindices[tmp] = implvalue;
10005  tmpindices[tmp] = probindex;
10006  ++tmp;
10007  }
10008 
10009  /* get the cliques where the knapsack item is member of with value 1 */
10010  ncliques = SCIPvarGetNCliques(var, value);
10011  cliques = SCIPvarGetCliques(var, value);
10012  for( j = 0; j < ncliques && !memlimitreached; ++j )
10013  {
10014  SCIP_VAR** cliquevars;
10015  SCIP_Bool* cliquevalues;
10016  int ncliquevars;
10017  int k;
10018 
10019  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10020 
10021  /* discard big cliques */
10022  if( ncliquevars > MAX_CLIQUELENGTH )
10023  continue;
10024 
10025  cliquevars = SCIPcliqueGetVars(cliques[j]);
10026  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10027 
10028  for( k = ncliquevars - 1; k >= 0; --k )
10029  {
10030  SCIP_Bool implvalue;
10031  int probindex;
10032 
10033  if( var == cliquevars[k] )
10034  continue;
10035 
10036  probindex = SCIPvarGetProbindex(cliquevars[k]);
10037  if( probindex == -1 )
10038  continue;
10039 
10040  assert(0 <= probindex && probindex < nbinvars);
10041  implvalue = cliquevalues[k];
10042 
10043  /* insert the item into the list of the clique variable/value */
10044  if( !zeroiteminserted[implvalue][probindex] )
10045  {
10046  if( firstidxs[implvalue][probindex] == 0 )
10047  {
10048  tmpboolindices2[tmp2] = implvalue;
10049  tmpindices2[tmp2] = probindex;
10050  ++tmp2;
10051  }
10052 
10053  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10054  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10055  &memlimitreached) );
10056  zeroiteminserted[implvalue][probindex] = TRUE;
10057  tmpboolindices[tmp] = implvalue;
10058  tmpindices[tmp] = probindex;
10059  ++tmp;
10060 
10061  if( memlimitreached )
10062  break;
10063  }
10064  }
10065  }
10066  /* clear zeroiteminserted */
10067  for( --tmp; tmp >= 0; --tmp)
10068  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10069  }
10070  SCIPfreeBufferArray(scip, &tmpboolindices);
10071 
10072  /* calculate the clique partition and the maximal sum of weights using the clique information */
10073  assert(consdata->sorted);
10074  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10075 
10076  assert(conshdlrdata->bools3size > 0);
10077 
10078  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10079  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10080  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10081  */
10082  if( conshdlrdata->bools3size < consdata->nvars )
10083  {
10084  int oldsize = conshdlrdata->bools3size;
10085 
10086  conshdlrdata->bools3size = consdata->nvars;;
10087  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10088  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10089  }
10090 
10091  cliqueused = conshdlrdata->bools3;
10092 
10093  /* check for cleared array, all entries are zero */
10094 #ifndef NDEBUG
10095  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10096  assert(cliqueused[tmp] == 0);
10097 #endif
10098 
10099  maxcliqueweightsum = 0;
10100  tmp = 0;
10101 
10102  /* calculates maximal weight of cliques */
10103  for( i = 0; i < consdata->nvars; ++i )
10104  {
10105  cliquenum = consdata->cliquepartition[i];
10106  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10107 
10108  if( !cliqueused[cliquenum] )
10109  {
10110  maxcliqueweightsum += consdata->weights[i];
10111  cliqueused[cliquenum] = TRUE;
10112  tmpindices[tmp] = cliquenum;
10113  ++tmp;
10114  }
10115  }
10116  /* clear cliqueused */
10117  for( --tmp; tmp >= 0; --tmp)
10118  cliqueused[tmp] = FALSE;
10119 
10120  assert(conshdlrdata->bools4size > 0);
10121 
10122  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10123  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10124  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10125  */
10126  if( conshdlrdata->bools4size < consdata->nvars )
10127  {
10128  int oldsize = conshdlrdata->bools4size;
10129 
10130  conshdlrdata->bools4size = consdata->nvars;
10131  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10132  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10133  }
10134 
10135  itemremoved = conshdlrdata->bools4;
10136 
10137  /* check for cleared array, all entries are zero */
10138 #ifndef NDEBUG
10139  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10140  assert(itemremoved[tmp] == 0);
10141 #endif
10142 
10143  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10144  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10145  * included in subsequent cliqueweightsum calculations)
10146  */
10147  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10148  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10149  naddvars = 0;
10150  addweightsum = 0;
10151  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10152  {
10153  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10154  {
10155  SCIP_Longint cliqueweightsum;
10156  int probindex;
10157  int idx;
10158  int j;
10159 
10160  tmp = 0;
10161 
10162  probindex = liftcands[val][i];
10163  assert(0 <= probindex && probindex < nbinvars);
10164 
10165  /* ignore empty zero lists and variables that cannot be lifted anyways */
10166  if( firstidxs[val][probindex] == 0
10167  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10168  continue;
10169 
10170  /* mark the items that are implied to zero by setting the current variable to the current value */
10171  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10172  {
10173  assert(0 < idx && idx < nzeroitems);
10174  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10175  itemremoved[zeroitems[idx]] = TRUE;
10176  }
10177 
10178  /* calculate the residual cliqueweight sum */
10179  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10180  for( j = 0; j < consdata->nvars; ++j )
10181  {
10182  cliquenum = consdata->cliquepartition[j];
10183  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10184  if( !itemremoved[j] )
10185  {
10186  if( !cliqueused[cliquenum] )
10187  {
10188  cliqueweightsum += consdata->weights[j];
10189  cliqueused[cliquenum] = TRUE;
10190  tmpindices[tmp] = cliquenum;
10191  ++tmp;
10192  }
10193 
10194  if( cliqueweightsum >= consdata->capacity )
10195  break;
10196  }
10197  }
10198 
10199  /* check if the weight of the variable/value can be increased */
10200  if( cliqueweightsum < consdata->capacity )
10201  {
10202  SCIP_VAR* var;
10203  SCIP_Longint weight;
10204 
10205  /* insert the variable (with value TRUE) in the list of additional items */
10206  assert(naddvars < 2*nbinvars);
10207  var = binvars[probindex];
10208  if( val == FALSE )
10209  {
10210  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10211  }
10212  weight = consdata->capacity - cliqueweightsum;
10213  addvars[naddvars] = var;
10214  addweights[naddvars] = weight;
10215  addweightsum += weight;
10216  naddvars++;
10217 
10218  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10219  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10220  }
10221 
10222  /* clear itemremoved */
10223  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10224  {
10225  assert(0 < idx && idx < nzeroitems);
10226  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10227  itemremoved[zeroitems[idx]] = FALSE;
10228  }
10229  /* clear cliqueused */
10230  for( --tmp; tmp >= 0; --tmp)
10231  cliqueused[tmpindices[tmp]] = FALSE;
10232  }
10233  }
10234  SCIPfreeBufferArray(scip, &tmpindices);
10235 
10236  /* clear part of zeroweightsums */
10237  for( --tmp3; tmp3 >= 0; --tmp3)
10238  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10239 
10240  /* clear rest of zeroweightsums and firstidxs */
10241  for( --tmp2; tmp2 >= 0; --tmp2)
10242  {
10243  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10244  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10245  }
10246 
10247  SCIPfreeBufferArray(scip, &tmpindices2);
10248  SCIPfreeBufferArray(scip, &tmpindices3);
10249  SCIPfreeBufferArray(scip, &tmpboolindices2);
10250  SCIPfreeBufferArray(scip, &tmpboolindices3);
10251 
10252  /* add all additional item weights */
10253  for( i = 0; i < naddvars; ++i )
10254  {
10255  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10256  }
10257  *nchgcoefs += naddvars;
10258 
10259  if( naddvars > 0 )
10260  {
10261  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10262  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10263  }
10264 
10265  /* free temporary memory */
10266  SCIPfreeBufferArray(scip, &addweights);
10267  SCIPfreeBufferArray(scip, &addvars);
10268  SCIPfreeBufferArray(scip, &nextidxs);
10269  SCIPfreeBufferArray(scip, &zeroitems);
10270  SCIPfreeBufferArray(scip, &liftcands[1]);
10271  SCIPfreeBufferArray(scip, &liftcands[0]);
10272 
10273  return SCIP_OKAY;
10274 }
10275 
10276 /** tightens item weights and capacity in presolving:
10277  * given a knapsack sum(wi*xi) <= capacity
10278  * (1) let weightsum := sum(wi)
10279  * if weightsum - wi < capacity:
10280  * - not using item i would make the knapsack constraint redundant
10281  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10282  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10283  * - change coefficients:
10284  * wi' := weightsum - capacity
10285  * capacity' := capacity - (wi - wi')
10286  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10287  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10288  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10289  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10290  * can be multiple times the same weight, this can be improved
10291  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10292  * weight, to capacity - lastmininmalweightsum, e.g. :
10293  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10294  * -> minimal weightsums: 5, 5, 10, 10
10295  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10296  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10297  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10298  * (3) let W(C) be the maximal weight of clique C,
10299  * cliqueweightsum := sum(W(C))
10300  * if cliqueweightsum - W(C) < capacity:
10301  * - not using any item of C would make the knapsack constraint redundant
10302  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10303  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10304  * - change coefficients:
10305  * delta := capacity - (cliqueweightsum - W(C))
10306  * wi' := max(wi - delta, 0)
10307  * capacity' := capacity - delta
10308  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10309  * introduce infeasible solutions.
10310  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10311  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10312  * if cliqueweightsum(xi == v) < capacity:
10313  * - fixing variable xi to v would make the knapsack constraint redundant
10314  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10315  * redundancy effect:
10316  * wi' := capacity - cliqueweightsum(xi == v)
10317  * This rule can also be applied to binary variables not in the knapsack!
10318  * (5) if min{w} + wi > capacity:
10319  * - using item i would force to fix other items to zero
10320  * - wi can be increased to the capacity
10321  */
10322 static
10324  SCIP* scip, /**< SCIP data structure */
10325  SCIP_CONS* cons, /**< knapsack constraint */
10326  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10327  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10328  int* nchgsides, /**< pointer to count number of side changes */
10329  int* naddconss, /**< pointer to count number of added constraints */
10330  int* ndelconss, /**< pointer to count number of deleted constraints */
10331  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10332  )
10333 {
10334  SCIP_CONSHDLRDATA* conshdlrdata;
10335  SCIP_CONSDATA* consdata;
10336  SCIP_Longint* weights;
10337  SCIP_Longint sumcoef;
10338  SCIP_Longint capacity;
10339  SCIP_Longint newweight;
10340  SCIP_Longint maxweight;
10341  SCIP_Longint minweight;
10342  SCIP_Bool sumcoefcase = FALSE;
10343  int startpos;
10344  int backpos;
10345  int nvars;
10346  int pos;
10347  int k;
10348  int i;
10349 
10350  assert(nchgcoefs != NULL);
10351  assert(nchgsides != NULL);
10352  assert(!SCIPconsIsModifiable(cons));
10353 
10354  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10355  assert(conshdlrdata != NULL);
10356 
10357  consdata = SCIPconsGetData(cons);
10358  assert(consdata != NULL);
10359  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10360  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10361  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10362  assert(consdata->nvars > 0);
10363 
10364  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10365  if( *cutoff )
10366  return SCIP_OKAY;
10367 
10368  /* apply rule (1) */
10369  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10370  {
10371  do
10372  {
10373  assert(consdata->merged);
10374 
10375  /* sort items, s.t. the heaviest one is in the first position */
10376  sortItems(consdata);
10377 
10378  for( i = 0; i < consdata->nvars; ++i )
10379  {
10380  SCIP_Longint weight;
10381 
10382  weight = consdata->weights[i];
10383  if( consdata->weightsum - weight < consdata->capacity )
10384  {
10385  newweight = consdata->weightsum - consdata->capacity;
10386  consdataChgWeight(consdata, i, newweight);
10387  consdata->capacity -= (weight - newweight);
10388  (*nchgcoefs)++;
10389  (*nchgsides)++;
10390  assert(!consdata->sorted);
10391  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",
10392  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10393  consdata->capacity + (weight-newweight), consdata->capacity);
10394  }
10395  else
10396  break;
10397  }
10398  }
10399  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10400  }
10401 
10402  /* check for redundancy */
10403  if( consdata->weightsum <= consdata->capacity )
10404  return SCIP_OKAY;
10405 
10406  pos = 0;
10407  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10408  ++pos;
10409 
10410  sumcoef = 0;
10411  weights = consdata->weights;
10412  nvars = consdata->nvars;
10413  capacity = consdata->capacity;
10414 
10415  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10416  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10417  {
10418  /* further reductions using the next possible coefficient sum
10419  *
10420  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10421  */
10422  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10423  for( k = 0; k < 4; ++k )
10424  {
10425  newweight = capacity - sumcoef;
10426 
10427  /* determine next minimal coefficient sum */
10428  switch( k )
10429  {
10430  case 0:
10431  sumcoef = weights[nvars - 1];
10432  backpos = nvars - 1;
10433  break;
10434  case 1:
10435  sumcoef = weights[nvars - 2];
10436  backpos = nvars - 2;
10437  break;
10438  case 2:
10439  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10440  {
10441  sumcoefcase = TRUE;
10442  sumcoef = weights[nvars - 3];
10443  backpos = nvars - 3;
10444  }
10445  else
10446  {
10447  sumcoefcase = FALSE;
10448  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10449  backpos = nvars - 2;
10450  }
10451  break;
10452  default:
10453  assert(k == 3);
10454  if( sumcoefcase )
10455  {
10456  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10457  {
10458  sumcoef = weights[nvars - 4];
10459  backpos = nvars - 4;
10460  }
10461  else
10462  {
10463  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10464  backpos = nvars - 2;
10465  }
10466  }
10467  else
10468  {
10469  sumcoef = weights[nvars - 3];
10470  backpos = nvars - 3;
10471  }
10472  break;
10473  }
10474 
10475  if( backpos <= pos )
10476  break;
10477 
10478  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10479  maxweight = weights[pos];
10480  startpos = pos;
10481  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10482  {
10483  assert(newweight > weights[pos]);
10484 
10485  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10486  SCIPconsGetName(cons), maxweight, newweight);
10487 
10488  consdataChgWeight(consdata, pos, newweight);
10489 
10490  ++pos;
10491  assert(pos < nvars);
10492 
10493  maxweight = weights[pos];
10494 
10495  if( backpos <= pos )
10496  break;
10497  }
10498  (*nchgcoefs) += (pos - startpos);
10499 
10500  /* skip unchangable weights */
10501  while( pos < nvars && weights[pos] + sumcoef == capacity )
10502  ++pos;
10503 
10504  /* check special case were there is only one weight left to tighten
10505  *
10506  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10507  *
10508  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10509  *
10510  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10511  */
10512  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10513  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10514  {
10515  newweight = capacity - sumcoef;
10516  assert(newweight > weights[pos]);
10517 
10518  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10519  SCIPconsGetName(cons), maxweight, newweight);
10520 
10521  consdataChgWeight(consdata, pos, newweight);
10522 
10523  break;
10524  }
10525 
10526  if( backpos <= pos )
10527  break;
10528  }
10529  }
10530 
10531  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10532  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10533  {
10534  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10535  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10536  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10537  {
10538  SCIP_VAR** clqvars;
10539  SCIP_CONS* cliquecons;
10540  char name[SCIP_MAXSTRLEN];
10541  int* clqpart;
10542  int nclqvars;
10543  int nclq;
10544  int len;
10545  int c;
10546  int w;
10547 
10548  assert(!SCIPconsIsDeleted(cons));
10549 
10550  if( pos == consdata->nvars )
10551  {
10552  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10553 
10554  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10558  SCIPconsIsStickingAtNode(cons)) );
10559 
10560  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10561  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10562  ++(*naddconss);
10563 
10564  /* delete old constraint */
10565  SCIP_CALL( SCIPdelCons(scip, cons) );
10566  ++(*ndelconss);
10567 
10568  return SCIP_OKAY;
10569  }
10570 
10571  len = consdata->nvars - pos;
10572 
10573  /* allocate temporary memory */
10574  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10575 
10576  /* calculate clique partition */
10577  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10578  assert(nclq <= len);
10579 
10580 #ifndef NDEBUG
10581  /* clique numbers must be at least as high as the index */
10582  for( w = 0; w < nclq; ++w )
10583  assert(clqpart[w] <= w);
10584 #endif
10585 
10586  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10587 
10588  /* allocate temporary memory */
10589  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10590 
10591  /* copy corresponding variables with big coefficients */
10592  for( w = pos - 1; w >= 0; --w )
10593  clqvars[w] = consdata->vars[w];
10594 
10595  /* create for each clique a set-packing constraint */
10596  for( c = 0; c < nclq; ++c )
10597  {
10598  nclqvars = pos;
10599 
10600  for( w = c; w < len; ++w )
10601  {
10602  if( clqpart[w] == c )
10603  {
10604  assert(nclqvars < pos + len - nclq + 1);
10605  clqvars[nclqvars] = consdata->vars[w + pos];
10606  ++nclqvars;
10607  }
10608  }
10609 
10610  assert(nclqvars > 1);
10611 
10612  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10613  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10617  SCIPconsIsStickingAtNode(cons)) );
10618  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10619  SCIPdebugPrintCons(scip, cliquecons, NULL);
10620  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10621  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10622  ++(*naddconss);
10623  }
10624 
10625  /* delete old constraint */
10626  SCIP_CALL( SCIPdelCons(scip, cons) );
10627  ++(*ndelconss);
10628 
10629  SCIPfreeBufferArray(scip, &clqvars);
10630  SCIPfreeBufferArray(scip, &clqpart);
10631 
10632  return SCIP_OKAY;
10633  }
10634  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10635  {
10636  SCIP_Longint* maxcliqueweights;
10637  SCIP_Longint* newweightvals;
10638  int* newweightidxs;
10639  SCIP_Longint cliqueweightsum;
10640 
10641  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10642  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10643  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10644 
10645  /* repeat as long as changes have been applied */
10646  do
10647  {
10648  int ncliques;
10649  int cliquenum;
10650  SCIP_Bool zeroweights;
10651 
10652  assert(consdata->merged);
10653 
10654  /* sort items, s.t. the heaviest one is in the first position */
10655  sortItems(consdata);
10656 
10657  /* calculate a clique partition */
10658  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10659 
10660  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10661  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10662  break;
10663 
10664  /* calculate the maximal weight of the cliques and store the clique type */
10665  cliqueweightsum = 0;
10666  ncliques = 0;
10667 
10668  for( i = 0; i < consdata->nvars; ++i )
10669  {
10670  SCIP_Longint weight;
10671 
10672  cliquenum = consdata->cliquepartition[i];
10673  assert(0 <= cliquenum && cliquenum <= ncliques);
10674 
10675  weight = consdata->weights[i];
10676  assert(weight > 0);
10677 
10678  if( cliquenum == ncliques )
10679  {
10680  maxcliqueweights[ncliques] = weight;
10681  cliqueweightsum += weight;
10682  ++ncliques;
10683  }
10684 
10685  assert(maxcliqueweights[cliquenum] >= weight);
10686  }
10687 
10688  /* apply rule on every clique */
10689  zeroweights = FALSE;
10690  for( i = 0; i < ncliques; ++i )
10691  {
10692  SCIP_Longint delta;
10693 
10694  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10695  if( delta > 0 )
10696  {
10697  SCIP_Longint newcapacity;
10698 #ifndef NDEBUG
10699  SCIP_Longint newmincliqueweight;
10700 #endif
10701  SCIP_Longint newminweightsuminclique;
10702  SCIP_Bool forceclique;
10703  int nnewweights;
10704  int j;
10705 
10706  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",
10707  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10708  newcapacity = consdata->capacity - delta;
10709  forceclique = FALSE;
10710  nnewweights = 0;
10711 #ifndef NDEBUG
10712  newmincliqueweight = newcapacity + 1;
10713  for( j = 0; j < i; ++j )
10714  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10715 #endif
10716  for( j = i; j < consdata->nvars; ++j )
10717  {
10718  if( consdata->cliquepartition[j] == i )
10719  {
10720  newweight = consdata->weights[j] - delta;
10721  newweight = MAX(newweight, 0);
10722 
10723  /* cache the new weight */
10724  assert(nnewweights < consdata->nvars);
10725  newweightvals[nnewweights] = newweight;
10726  newweightidxs[nnewweights] = j;
10727  nnewweights++;
10728 
10729 #ifndef NDEBUG
10730  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10731  newmincliqueweight = newweight;
10732 #endif
10733  }
10734  }
10735 
10736  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10737  if( nnewweights > 1 )
10738  {
10739 #ifndef NDEBUG
10740  j = newweightidxs[nnewweights - 2];
10741  assert(0 <= j && j < consdata->nvars);
10742  assert(consdata->cliquepartition[j] == i);
10743  j = newweightidxs[nnewweights - 1];
10744  assert(0 <= j && j < consdata->nvars);
10745  assert(consdata->cliquepartition[j] == i);
10746 #endif
10747 
10748  newminweightsuminclique = newweightvals[nnewweights - 2];
10749  newminweightsuminclique += newweightvals[nnewweights - 1];
10750 
10751  /* check if these new two minimal weights both fit into the knapsack;
10752  * if this is true, we have to add a clique constraint in order to enforce the clique
10753  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10754  * reduction might be infeasible, i.e., allows additional solutions)
10755  */
10756  if( newminweightsuminclique <= newcapacity )
10757  forceclique = TRUE;
10758  }
10759 
10760  /* check if we really want to apply the change */
10761  if( conshdlrdata->disaggregation || !forceclique )
10762  {
10763  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10764  consdata->capacity, newcapacity, forceclique);
10765  consdata->capacity = newcapacity;
10766  (*nchgsides)++;
10767 
10768  for( k = 0; k < nnewweights; ++k )
10769  {
10770  j = newweightidxs[k];
10771  assert(0 <= j && j < consdata->nvars);
10772  assert(consdata->cliquepartition[j] == i);
10773 
10774  /* apply the weight change */
10775  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10776  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10777  consdataChgWeight(consdata, j, newweightvals[k]);
10778  (*nchgcoefs)++;
10779  assert(!consdata->sorted);
10780  zeroweights = zeroweights || (newweightvals[k] == 0);
10781  }
10782  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10783  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10784  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10785  * knapsack constraint
10786  */
10787  if( forceclique )
10788  {
10789  SCIP_CONS* cliquecons;
10790  char name[SCIP_MAXSTRLEN];
10791  SCIP_VAR** cliquevars;
10792 
10793  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10794  for( k = 0; k < nnewweights; ++k )
10795  cliquevars[k] = consdata->vars[newweightidxs[k]];
10796 
10797  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10798  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10802  SCIPconsIsStickingAtNode(cons)) );
10803  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10804  SCIPdebugPrintCons(scip, cliquecons, NULL);
10805  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10806  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10807  SCIPfreeBufferArray(scip, &cliquevars);
10808  (*naddconss)++;
10809  }
10810  }
10811  }
10812  }
10813  if( zeroweights )
10814  {
10815  SCIP_CALL( removeZeroWeights(scip, cons) );
10816  }
10817  }
10818  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10819 
10820  /* free temporary memory */
10821  SCIPfreeBufferArray(scip, &newweightidxs);
10822  SCIPfreeBufferArray(scip, &newweightvals);
10823  SCIPfreeBufferArray(scip, &maxcliqueweights);
10824 
10825  /* check for redundancy */
10826  if( consdata->weightsum <= consdata->capacity )
10827  return SCIP_OKAY;
10828  }
10829  }
10830 
10831  /* apply rule (3) */
10832  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10833  {
10834  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10835  }
10836 
10837  /* check for redundancy */
10838  if( consdata->weightsum <= consdata->capacity )
10839  return SCIP_OKAY;
10840 
10841  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10842  {
10843  /* apply rule (4) (all but smallest weight) */
10844  assert(consdata->merged);
10845  sortItems(consdata);
10846  minweight = consdata->weights[consdata->nvars-1];
10847  for( i = 0; i < consdata->nvars-1; ++i )
10848  {
10849  SCIP_Longint weight;
10850 
10851  weight = consdata->weights[i];
10852  assert(weight >= minweight);
10853  if( minweight + weight > consdata->capacity )
10854  {
10855  if( weight < consdata->capacity )
10856  {
10857  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10858  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10859  assert(consdata->sorted);
10860  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10861  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10862  consdata->sorted = TRUE;
10863  (*nchgcoefs)++;
10864  }
10865  }
10866  else
10867  break;
10868  }
10869 
10870  /* apply rule (5) (smallest weight) */
10871  if( consdata->nvars >= 2 )
10872  {
10873  SCIP_Longint weight;
10874 
10875  minweight = consdata->weights[consdata->nvars-2];
10876  weight = consdata->weights[consdata->nvars-1];
10877  assert(minweight >= weight);
10878  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10879  {
10880  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10881  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10882  assert(consdata->sorted);
10883  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10884  assert(minweight >= consdata->weights[consdata->nvars-1]);
10885  consdata->sorted = TRUE;
10886  (*nchgcoefs)++;
10887  }
10888  }
10889  }
10890 
10891  return SCIP_OKAY;
10892 }
10893 
10894 
10895 #ifdef SCIP_DEBUG
10896 static
10897 void printClique(
10898  SCIP_VAR** cliquevars,
10899  int ncliquevars
10900  )
10901 {
10902  int b;
10903  SCIPdebugMessage("adding new Clique: ");
10904  for( b = 0; b < ncliquevars; ++b )
10905  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10906  SCIPdebugPrintf("\n");
10907 }
10908 #endif
10909 
10910 /** adds negated cliques of the knapsack constraint to the global clique table */
10911 static
10913  SCIP*const scip, /**< SCIP data structure */
10914  SCIP_CONS*const cons, /**< knapsack constraint */
10915  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10916  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10917  )
10918 {
10919  SCIP_CONSDATA* consdata;
10920  SCIP_CONSHDLRDATA* conshdlrdata;
10921  SCIP_VAR** poscliquevars;
10922  SCIP_VAR** cliquevars;
10923  SCIP_Longint* maxweights;
10924  SCIP_Longint* gainweights;
10925  int* gaincliquepartition;
10926  SCIP_Bool* cliqueused;
10927  SCIP_Longint minactduetonegcliques;
10928  SCIP_Longint freecapacity;
10929  SCIP_Longint lastweight;
10930  SCIP_Longint beforelastweight;
10931  int nposcliquevars;
10932  int ncliquevars;
10933  int nvars;
10934  int nnegcliques;
10935  int lastcliqueused;
10936  int thisnbdchgs;
10937  int v;
10938  int w;
10939 
10940  assert(scip != NULL);
10941  assert(cons != NULL);
10942  assert(cutoff != NULL);
10943  assert(nbdchgs != NULL);
10944 
10945  *cutoff = FALSE;
10946 
10947  consdata = SCIPconsGetData(cons);
10948  assert(consdata != NULL);
10949 
10950  nvars = consdata->nvars;
10951 
10952  /* check whether the cliques have already been added */
10953  if( consdata->cliquesadded || nvars == 0 )
10954  return SCIP_OKAY;
10955 
10956  /* make sure, the items are merged */
10957  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10958  if( *cutoff )
10959  return SCIP_OKAY;
10960 
10961  /* make sure, items are sorted by non-increasing weight */
10962  sortItems(consdata);
10963 
10964  assert(consdata->merged);
10965 
10966  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10967  assert(conshdlrdata != NULL);
10968 
10969  /* calculate a clique partition */
10970  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10971  nnegcliques = consdata->nnegcliques;
10972 
10973  /* if we have no negated cliques, stop */
10974  if( nnegcliques == nvars )
10975  return SCIP_OKAY;
10976 
10977  /* get temporary memory */
10978  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10979  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10980  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
10981  BMSclearMemoryArray(gainweights, nvars);
10982  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10983  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10984  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueused, nnegcliques) );
10985  BMSclearMemoryArray(cliqueused, nnegcliques);
10986 
10987  nnegcliques = 0;
10988  minactduetonegcliques = 0;
10989 
10990  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10991  for( v = 0; v < nvars; ++v )
10992  {
10993  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10994  assert(consdata->weights[v] > 0);
10995 
10996  if( consdata->negcliquepartition[v] == nnegcliques )
10997  {
10998  nnegcliques++;
10999  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11000  }
11001  else
11002  minactduetonegcliques += consdata->weights[v];
11003  }
11004 
11005  nposcliquevars = 0;
11006 
11007  /* add cliques, using negated cliques information */
11008  if( minactduetonegcliques > 0 )
11009  {
11010  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11011  freecapacity = consdata->capacity - minactduetonegcliques;
11012 
11013  SCIPdebugPrintCons(scip, cons, NULL);
11014  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",
11015  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11016 
11017  /* calculate possible gain by switching chosen items in negated cliques */
11018  for( v = 0; v < nvars; ++v )
11019  {
11020  if( !cliqueused[consdata->negcliquepartition[v]] )
11021  {
11022  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11023  for( w = v + 1; w < nvars; ++w )
11024  {
11025  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11026  * weight[w] (which are both in a negated clique) */
11027  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11028  && consdata->weights[v] > consdata->weights[w] )
11029  {
11030  poscliquevars[nposcliquevars] = consdata->vars[w];
11031  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11032  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11033  ++nposcliquevars;
11034  }
11035  }
11036  }
11037  }
11038 
11039  /* try to create negated cliques */
11040  if( nposcliquevars > 0 )
11041  {
11042  /* sort possible gain per substitution of the clique members */
11043  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11044 
11045  for( v = 0; v < nposcliquevars; ++v )
11046  {
11047  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11048  ncliquevars = 1;
11049  lastweight = gainweights[v];
11050  beforelastweight = -1;
11051  lastcliqueused = gaincliquepartition[v];
11052  /* clear cliqueused to get an unused array */
11053  BMSclearMemoryArray(cliqueused, nnegcliques);
11054  cliqueused[gaincliquepartition[v]] = TRUE;
11055 
11056  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11057  * in the same negated clique and by taking two of them would exceed the free capacity */
11058  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11059  {
11060  beforelastweight = lastweight;
11061  lastweight = gainweights[w];
11062  lastcliqueused = gaincliquepartition[w];
11063  cliqueused[gaincliquepartition[w]] = TRUE;
11064  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11065  ++ncliquevars;
11066  }
11067 
11068  if( ncliquevars > 1 )
11069  {
11070  SCIPdebug( printClique(cliquevars, ncliquevars) );
11071  assert(beforelastweight > 0);
11072  /* add the clique to the clique table */
11073  /* this really happens, e.g., on enigma.mps from the short test set */
11074  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11075  if( *cutoff )
11076  goto TERMINATE;
11077  *nbdchgs += thisnbdchgs;
11078 
11079  /* reset last used clique to get slightly different cliques */
11080  cliqueused[lastcliqueused] = FALSE;
11081 
11082  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11083  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11084  {
11085  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11086  SCIPdebug( printClique(cliquevars, ncliquevars) );
11087  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11088  if( *cutoff )
11089  goto TERMINATE;
11090  *nbdchgs += thisnbdchgs;
11091  }
11092  }
11093  }
11094  }
11095  }
11096 
11097  TERMINATE:
11098  /* free temporary memory */
11099  SCIPfreeBufferArray(scip, &cliqueused);
11100  SCIPfreeBufferArray(scip, &gaincliquepartition);
11101  SCIPfreeBufferArray(scip, &maxweights);
11102  SCIPfreeBufferArray(scip, &gainweights);
11103  SCIPfreeBufferArray(scip, &cliquevars);
11104  SCIPfreeBufferArray(scip, &poscliquevars);
11105 
11106  return SCIP_OKAY;
11107 }
11108 
11109 /** greedy clique detection by considering weights and capacity
11110  *
11111  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11112  * 1) neighboring items which exceed the capacity together => one clique
11113  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11114  */
11115 static
11117  SCIP*const scip, /**< SCIP data structure */
11118  SCIP_VAR** items, /**< array of variable items */
11119  SCIP_Longint* weights, /**< weights of the items */
11120  int nitems, /**< the number of items */
11121  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11122  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11123  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11124  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11125  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11126  )
11127 {
11128  SCIP_Longint lastweight;
11129  int ncliquevars;
11130  int i;
11131  int thisnbdchgs;
11132 
11133  if( nitems <= 1 )
11134  return SCIP_OKAY;
11135 
11136  /* sort possible gain per substitution of the clique members */
11137  if( ! sorteditems )
11138  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11139 
11140  ncliquevars = 1;
11141  lastweight = weights[0];
11142 
11143  /* taking these two weights together violates the knapsack => include into clique */
11144  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11145  {
11146  lastweight = weights[i];
11147  ++ncliquevars;
11148  }
11149 
11150  if( ncliquevars > 1 )
11151  {
11152  SCIP_Longint compareweight;
11153  SCIP_VAR** cliquevars;
11154  int compareweightidx;
11155  int minclqsize;
11156  int nnzadded;
11157 
11158  /* add the clique to the clique table */
11159  SCIPdebug( printClique(items, ncliquevars) );
11160  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11161 
11162  if( *cutoff )
11163  return SCIP_OKAY;
11164 
11165  *nbdchgs += thisnbdchgs;
11166  nnzadded = ncliquevars;
11167 
11168  /* 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)*/
11169  if( ncliquevars == nitems )
11170  return SCIP_OKAY;
11171 
11172  /* copy items in order into buffer array and deduce more cliques */
11173  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11174 
11175  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11176  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11177  compareweightidx = ncliquevars - 2;
11178  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11179 
11180  /* determine minimum clique size for the following loop */
11181  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11182  minclqsize = MAX(minclqsize, 2);
11183 
11184  /* loop over the remaining variables and the larger items of the first clique until we
11185  * find another clique or reach the size limit */
11186  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11187  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11188  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11189  )
11190  {
11191  compareweight = weights[compareweightidx];
11192  assert(compareweight > 0);
11193 
11194  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11195  if( compareweight + weights[i] > capacity )
11196  {
11197  assert(compareweightidx == ncliquevars -2);
11198  cliquevars[ncliquevars - 1] = items[i];
11199  SCIPdebug( printClique(cliquevars, ncliquevars) );
11200  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11201 
11202  nnzadded += ncliquevars;
11203 
11204  /* stop when there is a cutoff */
11205  if( ! (*cutoff) )
11206  *nbdchgs += thisnbdchgs;
11207 
11208  /* go to next smaller item */
11209  ++i;
11210  }
11211  else
11212  {
11213  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11214  compareweightidx--;
11215  ncliquevars --;
11216  }
11217 
11218  }
11219 
11220  SCIPfreeBufferArray(scip, &cliquevars);
11221  }
11222 
11223  return SCIP_OKAY;
11224 }
11225 
11226 /** adds cliques of the knapsack constraint to the global clique table */
11227 static
11229  SCIP*const scip, /**< SCIP data structure */
11230  SCIP_CONS*const cons, /**< knapsack constraint */
11231  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11232  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11233  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11234  )
11235 {
11236  SCIP_CONSDATA* consdata;
11237  SCIP_CONSHDLRDATA* conshdlrdata;
11238  int i;
11239  SCIP_Longint minactduetonegcliques;
11240  SCIP_Longint freecapacity;
11241  int nnegcliques;
11242  int cliquenum;
11243  SCIP_VAR** poscliquevars;
11244  SCIP_Longint* gainweights;
11245  int nposcliquevars;
11246  SCIP_Longint* secondmaxweights;
11247  int nvars;
11248 
11249  assert(scip != NULL);
11250  assert(cons != NULL);
11251  assert(cutoff != NULL);
11252  assert(nbdchgs != NULL);
11253 
11254  *cutoff = FALSE;
11255 
11256  consdata = SCIPconsGetData(cons);
11257  assert(consdata != NULL);
11258 
11259  nvars = consdata->nvars;
11260 
11261  /* check whether the cliques have already been added */
11262  if( consdata->cliquesadded || nvars == 0 )
11263  return SCIP_OKAY;
11264 
11265  /* make sure, the items are merged */
11266  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11267  if( *cutoff )
11268  return SCIP_OKAY;
11269 
11270  /* make sure, the items are sorted by non-increasing weight */
11271  sortItems(consdata);
11272 
11273  assert(consdata->merged);
11274 
11275  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11276  assert(conshdlrdata != NULL);
11277 
11278  /* calculate a clique partition */
11279  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11280  nnegcliques = consdata->nnegcliques;
11281  assert(nnegcliques <= nvars);
11282 
11283  /* get temporary memory */
11284  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11285  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11286  BMSclearMemoryArray(gainweights, nvars);
11287  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11288  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11289 
11290  minactduetonegcliques = 0;
11291 
11292  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11293  if( nnegcliques < nvars )
11294  {
11295  nnegcliques = 0;
11296 
11297  for( i = 0; i < nvars; ++i )
11298  {
11299  SCIP_Longint weight;
11300 
11301  cliquenum = consdata->negcliquepartition[i];
11302  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11303 
11304  weight = consdata->weights[i];
11305  assert(weight > 0);
11306 
11307  if( cliquenum == nnegcliques )
11308  nnegcliques++;
11309  else
11310  {
11311  minactduetonegcliques += weight;
11312  if( secondmaxweights[cliquenum] == 0 )
11313  secondmaxweights[cliquenum] = weight;
11314  }
11315  }
11316  }
11317 
11318  /* add cliques, using negated cliques information */
11319  if( minactduetonegcliques > 0 )
11320  {
11321  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11322  freecapacity = consdata->capacity - minactduetonegcliques;
11323 
11324  SCIPdebugPrintCons(scip, cons, NULL);
11325  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",
11326  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11327 
11328  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11329  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11330 
11331  if( *cutoff )
11332  goto TERMINATE;
11333 
11334  nposcliquevars = 0;
11335 
11336  for( i = nvars - 1; i >= 0; --i )
11337  {
11338  /* if we would take the biggest weight instead of the second biggest */
11339  cliquenum = consdata->negcliquepartition[i];
11340  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11341  {
11342  poscliquevars[nposcliquevars] = consdata->vars[i];
11343  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11344  ++nposcliquevars;
11345  }
11346  }
11347 
11348  /* use the gain weights and free capacity to derive greedily cliques */
11349  if( nposcliquevars > 1 )
11350  {
11351  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11352 
11353  if( *cutoff )
11354  goto TERMINATE;
11355  }
11356  }
11357 
11358  /* build cliques by using the items with the maximal weights */
11359  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11360 
11361  TERMINATE:
11362  /* free temporary memory and mark the constraint */
11363  SCIPfreeBufferArray(scip, &secondmaxweights);
11364  SCIPfreeBufferArray(scip, &gainweights);
11365  SCIPfreeBufferArray(scip, &poscliquevars);
11366  consdata->cliquesadded = TRUE;
11367 
11368  return SCIP_OKAY;
11369 }
11370 
11371 
11372 /** gets the key of the given element */
11373 static
11374 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11375 { /*lint --e{715}*/
11376  /* the key is the element itself */
11377  return elem;
11378 }
11379 
11380 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11381  * same coefficients
11382  */
11383 static
11384 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11385 {
11386 #ifndef NDEBUG
11387  SCIP* scip;
11388 #endif
11389  SCIP_CONSDATA* consdata1;
11390  SCIP_CONSDATA* consdata2;
11391  int i;
11393  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11394  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11395  assert(consdata1->sorted);
11396  assert(consdata2->sorted);
11397 #ifndef NDEBUG
11398  scip = (SCIP*)userptr;
11399  assert(scip != NULL);
11400 #endif
11401 
11402  /* checks trivial case */
11403  if( consdata1->nvars != consdata2->nvars )
11404  return FALSE;
11405 
11406  for( i = consdata1->nvars - 1; i >= 0; --i )
11407  {
11408  /* tests if variables are equal */
11409  if( consdata1->vars[i] != consdata2->vars[i] )
11410  {
11411  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11412  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11413  return FALSE;
11414  }
11415  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11416 
11417  /* tests if weights are equal too */
11418  if( consdata1->weights[i] != consdata2->weights[i] )
11419  return FALSE;
11420  }
11421 
11422  return TRUE;
11423 }
11424 
11425 /** returns the hash value of the key */
11426 static
11427 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11428 {
11429 #ifndef NDEBUG
11430  SCIP* scip;
11431 #endif
11432  SCIP_CONSDATA* consdata;
11433  int minidx;
11434  int mididx;
11435  int maxidx;
11436 
11437  consdata = SCIPconsGetData((SCIP_CONS*)key);
11438  assert(consdata != NULL);
11439  assert(consdata->nvars > 0);
11440 
11441 #ifndef NDEBUG
11442  scip = (SCIP*)userptr;
11443  assert(scip != NULL);
11444 #endif
11445 
11446  /* sorts the constraints */
11447  sortItems(consdata);
11448 
11449  minidx = SCIPvarGetIndex(consdata->vars[0]);
11450  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11451  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11452  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11453 
11454  /* hash value depends on vectors of variable indices */
11455  return SCIPhashTwo(SCIPcombineFourInt(consdata->nvars, minidx, mididx, maxidx),
11456  consdata->weights[0]);
11457 }
11458 
11459 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11460  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11461  */
11462 static
11464  SCIP* scip, /**< SCIP data structure */
11465  BMS_BLKMEM* blkmem, /**< block memory */
11466  SCIP_CONS** conss, /**< constraint set */
11467  int nconss, /**< number of constraints in constraint set */
11468  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11469  int* ndelconss /**< pointer to count number of deleted constraints */
11470  )
11472  SCIP_HASHTABLE* hashtable;
11473  int hashtablesize;
11474  int c;
11475 
11476  assert(scip != NULL);
11477  assert(blkmem != NULL);
11478  assert(conss != NULL);
11479  assert(ndelconss != NULL);
11480 
11481  /* create a hash table for the constraint set */
11482  hashtablesize = nconss;
11483  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11484  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11485  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11486 
11487  /* check all constraints in the given set for redundancy */
11488  for( c = nconss - 1; c >= 0; --c )
11489  {
11490  SCIP_CONS* cons0;
11491  SCIP_CONS* cons1;
11492  SCIP_CONSDATA* consdata0;
11493 
11494  cons0 = conss[c];
11495 
11496  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11497  continue;
11498 
11499  consdata0 = SCIPconsGetData(cons0);
11500  assert(consdata0 != NULL);
11501  if( consdata0->nvars == 0 )
11502  {
11503  if( consdata0->capacity < 0 )
11504  {
11505  *cutoff = TRUE;
11506  goto TERMINATE;
11507  }
11508  else
11509  {
11510  SCIP_CALL( SCIPdelCons(scip, cons0) );
11511  ++(*ndelconss);
11512  continue;
11513  }
11514  }
11515 
11516  /* get constraint from current hash table with same variables and same weights as cons0 */
11517  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11518 
11519  if( cons1 != NULL )
11520  {
11521  SCIP_CONS* consstay;
11522  SCIP_CONS* consdel;
11523  SCIP_CONSDATA* consdata1;
11524 
11525  assert(SCIPconsIsActive(cons1));
11526  assert(!SCIPconsIsModifiable(cons1));
11527 
11528  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11529  * delete old constraints afterwards
11530  */
11531  consdata1 = SCIPconsGetData(cons1);
11532 
11533  assert(consdata1 != NULL);
11534  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11535 
11536  assert(consdata0->sorted && consdata1->sorted);
11537  assert(consdata0->vars[0] == consdata1->vars[0]);
11538  assert(consdata0->weights[0] == consdata1->weights[0]);
11539 
11540  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11541  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11542 
11543  /* check which constraint has to stay; */
11544  if( consdata0->capacity < consdata1->capacity )
11545  {
11546  consstay = cons0;
11547  consdel = cons1;
11548 
11549  /* exchange consdel with consstay in hashtable */
11550  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11551  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11552  }
11553  else
11554  {
11555  consstay = cons1;
11556  consdel = cons0;
11557  }
11558 
11559  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11560  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11561 
11562  /* delete consdel */
11563  SCIP_CALL( SCIPdelCons(scip, consdel) );
11564  ++(*ndelconss);
11565 
11566  assert(SCIPconsIsActive(consstay));
11567  }
11568  else
11569  {
11570  /* no such constraint in current hash table: insert cons0 into hash table */
11571  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11572  }
11573  }
11574 
11575  TERMINATE:
11576  /* free hash table */
11577  SCIPhashtableFree(&hashtable);
11578 
11579  return SCIP_OKAY;
11580 }
11581 
11582 
11583 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11584  * and removes or changes constraint accordingly
11585  */
11586 static
11588  SCIP* scip, /**< SCIP data structure */
11589  SCIP_CONS** conss, /**< constraint set */
11590  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11591  int chkind, /**< index of constraint to check against all prior indices upto startind */
11592  int* ndelconss /**< pointer to count number of deleted constraints */
11593  )
11594 {
11595  SCIP_CONS* cons0;
11596  SCIP_CONSDATA* consdata0;
11597  int c;
11598 
11599  assert(scip != NULL);
11600  assert(conss != NULL);
11601  assert(firstchange <= chkind);
11602  assert(ndelconss != NULL);
11603 
11604  /* get the constraint to be checked against all prior constraints */
11605  cons0 = conss[chkind];
11606  assert(cons0 != NULL);
11607  assert(SCIPconsIsActive(cons0));
11608  assert(!SCIPconsIsModifiable(cons0));
11609 
11610  consdata0 = SCIPconsGetData(cons0);
11611  assert(consdata0 != NULL);
11612  assert(consdata0->nvars >= 1);
11613  assert(consdata0->merged);
11614 
11615  /* sort the constraint */
11616  sortItems(consdata0);
11617 
11618  /* check constraint against all prior constraints */
11619  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11620  {
11621  SCIP_CONS* cons1;
11622  SCIP_CONSDATA* consdata1;
11623  SCIP_Bool iscons0incons1contained;
11624  SCIP_Bool iscons1incons0contained;
11625  SCIP_Real quotient;
11626  int v;
11627  int v0;
11628  int v1;
11629 
11630  cons1 = conss[c];
11631  assert(cons1 != NULL);
11632  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11633  continue;
11634 
11635  consdata1 = SCIPconsGetData(cons1);
11636  assert(consdata1 != NULL);
11637 
11638  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11639  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11640  continue;
11641 
11642  assert(consdata1->nvars >= 1);
11643  assert(consdata1->merged);
11644 
11645  /* sort the constraint */
11646  sortItems(consdata1);
11647 
11648  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11649 
11650  if( consdata0->nvars > consdata1->nvars )
11651  {
11652  iscons0incons1contained = FALSE;
11653  iscons1incons0contained = TRUE;
11654  v = consdata1->nvars - 1;
11655  }
11656  else if( consdata0->nvars < consdata1->nvars )
11657  {
11658  iscons0incons1contained = TRUE;
11659  iscons1incons0contained = FALSE;
11660  v = consdata0->nvars - 1;
11661  }
11662  else
11663  {
11664  iscons0incons1contained = TRUE;
11665  iscons1incons0contained = TRUE;
11666  v = consdata0->nvars - 1;
11667  }
11668 
11669  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11670 
11671  /* check consdata0 against consdata1:
11672  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11673  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11674  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11675  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11676  */
11677  v0 = consdata0->nvars - 1;
11678  v1 = consdata1->nvars - 1;
11679 
11680  while( v >= 0 )
11681  {
11682  assert(iscons0incons1contained || iscons1incons0contained);
11683 
11684  /* now there are more variables in cons1 left */
11685  if( v1 > v0 )
11686  {
11687  iscons1incons0contained = FALSE;
11688  if( !iscons0incons1contained )
11689  break;
11690  }
11691  /* now there are more variables in cons0 left */
11692  else if( v1 < v0 )
11693  {
11694  iscons0incons1contained = FALSE;
11695  if( !iscons1incons0contained )
11696  break;
11697  }
11698 
11699  assert(v == v0 || v == v1);
11700  assert(v0 >= 0);
11701  assert(v1 >= 0);
11702 
11703  /* both variables are the same */
11704  if( consdata0->vars[v0] == consdata1->vars[v1] )
11705  {
11706  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11707  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11708  {
11709  iscons1incons0contained = FALSE;
11710  if( !iscons0incons1contained )
11711  break;
11712  }
11713  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11714  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11715  {
11716  iscons0incons1contained = FALSE;
11717  if( !iscons1incons0contained )
11718  break;
11719  }
11720  --v0;
11721  --v1;
11722  --v;
11723  }
11724  else
11725  {
11726  /* both constraints have a variables which is not part of the other constraint, so stop */
11727  if( iscons0incons1contained && iscons1incons0contained )
11728  {
11729  iscons0incons1contained = FALSE;
11730  iscons1incons0contained = FALSE;
11731  break;
11732  }
11733  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11734  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11735  /* continue to the next variable */
11736  if( iscons0incons1contained )
11737  --v1;
11738  else
11739  --v0;
11740  }
11741  }
11742  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11743  * other
11744  */
11745  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11746 
11747  if( iscons1incons0contained )
11748  {
11749  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11750  SCIPdebugPrintCons(scip, cons1, NULL);
11751 
11752  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11753  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11754 
11755  SCIP_CALL( SCIPdelCons(scip, cons1) );
11756  ++(*ndelconss);
11757  }
11758  else if( iscons0incons1contained )
11759  {
11760  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11761  SCIPdebugPrintCons(scip, cons0, NULL);
11762 
11763  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11764  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11765 
11766  SCIP_CALL( SCIPdelCons(scip, cons0) );
11767  ++(*ndelconss);
11768  break;
11769  }
11770  }
11771 
11772  return SCIP_OKAY;
11773 }
11774 
11775 /** helper function to enforce constraints */
11776 static
11778  SCIP* scip, /**< SCIP data structure */
11779  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11780  SCIP_CONS** conss, /**< constraints to process */
11781  int nconss, /**< number of constraints */
11782  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11783  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11784  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11785  )
11786 {
11787  SCIP_CONSHDLRDATA* conshdlrdata;
11788  SCIP_Bool violated;
11789  SCIP_Bool cutoff = FALSE;
11790  int maxncuts;
11791  int ncuts = 0;
11792  int i;
11793 
11794  *result = SCIP_FEASIBLE;
11795 
11796  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11797  sol == NULL ? "LP" : "relaxation");
11798 
11799  /* get maximal number of cuts per round */
11800  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11801  assert(conshdlrdata != NULL);
11802  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11803 
11804  /* search for violated useful knapsack constraints */
11805  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11806  {
11807  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11808  if( violated )
11809  {
11810  /* add knapsack constraint as LP row to the relaxation */
11811  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11812  ncuts++;
11813  }
11814  }
11815 
11816  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11817  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11818  {
11819  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11820  if( violated )
11821  {
11822  /* add knapsack constraint as LP row to the relaxation */
11823  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11824  ncuts++;
11825  }
11826  }
11827 
11828  /* adjust the result code */
11829  if ( cutoff )
11830  *result = SCIP_CUTOFF;
11831  else if ( ncuts > 0 )
11832  *result = SCIP_SEPARATED;
11833 
11834  return SCIP_OKAY;
11835 }
11836 
11837 /*
11838  * Linear constraint upgrading
11839  */
11840 
11841 /** creates and captures a knapsack constraint out of a linear inequality */
11842 static
11844  SCIP* scip, /**< SCIP data structure */
11845  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11846  const char* name, /**< name of constraint */
11847  int nvars, /**< number of variables in the constraint */
11848  SCIP_VAR** vars, /**< array with variables of constraint entries */
11849  SCIP_Real* vals, /**< array with inequality coefficients */
11850  SCIP_Real lhs, /**< left hand side of inequality */
11851  SCIP_Real rhs, /**< right hand side of inequality */
11852  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11853  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11854  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11855  * Usually set to TRUE. */
11856  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11857  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11858  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11859  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11860  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11861  * Usually set to TRUE. */
11862  SCIP_Bool local, /**< is constraint only valid locally?
11863  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11864  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11865  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11866  * adds coefficients to this constraint. */
11867  SCIP_Bool dynamic, /**< is constraint subject to aging?
11868  * Usually set to FALSE. Set to TRUE for own cuts which
11869  * are separated as constraints. */
11870  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11871  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11872  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11873  * if it may be moved to a more global node?
11874  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11875  )
11876 {
11877  SCIP_VAR** transvars;
11878  SCIP_Longint* weights;
11879  SCIP_Longint capacity;
11880  SCIP_Longint weight;
11881  int mult;
11882  int v;
11883 
11884  assert(nvars == 0 || vars != NULL);
11885  assert(nvars == 0 || vals != NULL);
11886  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11887 
11888  /* get temporary memory */
11889  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11890  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11891 
11892  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11893  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11894  */
11895  if( SCIPisInfinity(scip, rhs) )
11896  {
11897  mult = -1;
11898  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11899  }
11900  else
11901  {
11902  mult = +1;
11903  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11904  }
11905 
11906  /* negate positive or negative variables */
11907  for( v = 0; v < nvars; ++v )
11908  {
11909  assert(SCIPisFeasIntegral(scip, vals[v]));
11910  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11911  if( weight > 0 )
11912  {
11913  transvars[v] = vars[v];
11914  weights[v] = weight;
11915  }
11916  else
11917  {
11918  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11919  weights[v] = -weight;
11920  capacity -= weight;
11921  }
11922  assert(transvars[v] != NULL);
11923  }
11924 
11925  /* create the constraint */
11926  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11927  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11928 
11929  /* free temporary memory */
11930  SCIPfreeBufferArray(scip, &weights);
11931  SCIPfreeBufferArray(scip, &transvars);
11932 
11933  return SCIP_OKAY;
11934 }
11935 
11936 /** tries to upgrade a linear constraint into a knapsack constraint */
11937 static
11938 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11939 { /*lint --e{715}*/
11940  SCIP_Bool upgrade;
11941 
11942  assert(upgdcons != NULL);
11943 
11944  /* check, if linear constraint can be upgraded to a knapsack constraint
11945  * - all variables must be binary
11946  * - all coefficients must be integral
11947  * - exactly one of the sides must be infinite
11948  */
11949  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11950  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11951  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11952 
11953  if( upgrade )
11954  {
11955  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11956 
11957  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11958  assert(!SCIPconsIsModifiable(cons));
11959  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11964  }
11965 
11966  return SCIP_OKAY;
11967 }
11968 
11969 
11970 /*
11971  * Callback methods of constraint handler
11972  */
11973 
11974 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11975 /**! [SnippetConsCopyKnapsack] */
11976 static
11977 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11978 { /*lint --e{715}*/
11979  assert(scip != NULL);
11980  assert(conshdlr != NULL);
11981  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11982 
11983  /* call inclusion method of constraint handler */
11986  *valid = TRUE;
11987 
11988  return SCIP_OKAY;
11989 }
11990 /**! [SnippetConsCopyKnapsack] */
11991 
11992 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11993 /**! [SnippetConsFreeKnapsack] */
11994 static
11995 SCIP_DECL_CONSFREE(consFreeKnapsack)
11996 { /*lint --e{715}*/
11997  SCIP_CONSHDLRDATA* conshdlrdata;
11998 
11999  /* free constraint handler data */
12000  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12001  assert(conshdlrdata != NULL);
12002 
12003  SCIPfreeBlockMemory(scip, &conshdlrdata);
12004 
12005  SCIPconshdlrSetData(conshdlr, NULL);
12006 
12007  return SCIP_OKAY;
12008 }
12009 /**! [SnippetConsFreeKnapsack] */
12010 
12011 
12012 /** initialization method of constraint handler (called after problem was transformed) */
12013 static
12014 SCIP_DECL_CONSINIT(consInitKnapsack)
12015 { /*lint --e{715}*/
12016  SCIP_CONSHDLRDATA* conshdlrdata;
12017  int nvars;
12018 
12019  assert( scip != NULL );
12020  assert( conshdlr != NULL );
12021 
12022  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12023  assert(conshdlrdata != NULL);
12024 
12025  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12026  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12027 
12028  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12029  conshdlrdata->reals1size = nvars;
12030 
12031  return SCIP_OKAY;
12032 }
12033 
12034 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12035 static
12036 SCIP_DECL_CONSEXIT(consExitKnapsack)
12037 { /*lint --e{715}*/
12038  SCIP_CONSHDLRDATA* conshdlrdata;
12039 
12040  assert( scip != NULL );
12041  assert( conshdlr != NULL );
12042 
12043  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12044  assert(conshdlrdata != NULL);
12045 
12046  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12047  conshdlrdata->reals1size = 0;
12048 
12049  return SCIP_OKAY;
12050 }
12051 
12052 
12053 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12054 static
12055 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12056 { /*lint --e{715}*/
12057  SCIP_CONSHDLRDATA* conshdlrdata;
12058  int nvars;
12059 
12060  assert(scip != NULL);
12061  assert(conshdlr != NULL);
12062  assert(nconss == 0 || conss != NULL);
12064  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12065  assert(conshdlrdata != NULL);
12066 
12067  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12068  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12069 
12070  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12071  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12072  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12073  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12074  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12075  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12076  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12077  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12078 
12079  conshdlrdata->ints1size = nvars;
12080  conshdlrdata->ints2size = nvars;
12081  conshdlrdata->longints1size = nvars;
12082  conshdlrdata->longints2size = nvars;
12083  conshdlrdata->bools1size = nvars;
12084  conshdlrdata->bools2size = nvars;
12085  conshdlrdata->bools3size = nvars;
12086  conshdlrdata->bools4size = nvars;
12087 
12088 #ifdef WITH_CARDINALITY_UPGRADE
12089  conshdlrdata->upgradedcard = FALSE;
12090 #endif
12091 
12092  return SCIP_OKAY;
12093 }
12094 
12095 
12096 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12097 static
12098 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12099 { /*lint --e{715}*/
12100  SCIP_CONSHDLRDATA* conshdlrdata;
12101  int c;
12102 
12103  assert(scip != NULL);
12104  assert(conshdlr != NULL);
12105 
12106  for( c = 0; c < nconss; ++c )
12107  {
12108  if( !SCIPconsIsDeleted(conss[c]) )
12109  {
12110  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12111  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12112  }
12113  }
12114 
12115  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12116  assert(conshdlrdata != NULL);
12117 
12118  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12119  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12120  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12121  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12122  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12123  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12124  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12125  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12126 
12127  conshdlrdata->ints1size = 0;
12128  conshdlrdata->ints2size = 0;
12129  conshdlrdata->longints1size = 0;
12130  conshdlrdata->longints2size = 0;
12131  conshdlrdata->bools1size = 0;
12132  conshdlrdata->bools2size = 0;
12133  conshdlrdata->bools3size = 0;
12134  conshdlrdata->bools4size = 0;
12135 
12136  return SCIP_OKAY;
12137 }
12138 
12139 
12140 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12141 static
12142 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12143 { /*lint --e{715}*/
12144  SCIP_CONSDATA* consdata;
12145  int c;
12146 
12147  assert( scip != NULL );
12148 
12149  /* release the rows of all constraints */
12150  for( c = 0; c < nconss; ++c )
12151  {
12152  consdata = SCIPconsGetData(conss[c]);
12153  assert(consdata != NULL);
12154 
12155  if( consdata->row != NULL )
12156  {
12157  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12158  }
12159  }
12160 
12161  return SCIP_OKAY;
12162 }
12163 
12164 /** frees specific constraint data */
12165 static
12166 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12167 { /*lint --e{715}*/
12168  SCIP_CONSHDLRDATA* conshdlrdata;
12169 
12170  assert(conshdlr != NULL);
12171  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12172 
12173  /* get event handler */
12174  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12175  assert(conshdlrdata != NULL);
12176  assert(conshdlrdata->eventhdlr != NULL);
12177 
12178  /* free knapsack constraint */
12179  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12180 
12181  return SCIP_OKAY;
12182 }
12183 
12184 /** transforms constraint data into data belonging to the transformed problem */
12185 /**! [SnippetConsTransKnapsack]*/
12186 static
12187 SCIP_DECL_CONSTRANS(consTransKnapsack)
12188 { /*lint --e{715}*/
12189  SCIP_CONSHDLRDATA* conshdlrdata;
12190  SCIP_CONSDATA* sourcedata;
12191  SCIP_CONSDATA* targetdata;
12192 
12193  assert(conshdlr != NULL);
12194  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12196  assert(sourcecons != NULL);
12197  assert(targetcons != NULL);
12198 
12199  sourcedata = SCIPconsGetData(sourcecons);
12200  assert(sourcedata != NULL);
12201  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12202 
12203  /* get event handler */
12204  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12205  assert(conshdlrdata != NULL);
12206  assert(conshdlrdata->eventhdlr != NULL);
12207 
12208  /* create target constraint data */
12209  SCIP_CALL( consdataCreate(scip, &targetdata,
12210  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12211 
12212  /* create target constraint */
12213  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12214  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12215  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12216  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12217  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12218 
12219  /* catch events for variables */
12220  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12221 
12222  return SCIP_OKAY;
12223 }
12224 /**! [SnippetConsTransKnapsack]*/
12225 
12226 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12227 static
12228 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12229 { /*lint --e{715}*/
12230  int i;
12231 
12232  *infeasible = FALSE;
12233 
12234  for( i = 0; i < nconss && !(*infeasible); i++ )
12235  {
12236  assert(SCIPconsIsInitial(conss[i]));
12237  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12238  }
12239 
12240  return SCIP_OKAY;
12241 }
12242 
12243 /** separation method of constraint handler for LP solutions */
12244 static
12245 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12246 { /*lint --e{715}*/
12247  SCIP_CONSHDLRDATA* conshdlrdata;
12248  SCIP_Bool sepacardinality;
12249  SCIP_Bool cutoff;
12250 
12251  SCIP_Real loclowerbound;
12252  SCIP_Real glblowerbound;
12253  SCIP_Real cutoffbound;
12254  SCIP_Real maxbound;
12255 
12256  int depth;
12257  int nrounds;
12258  int sepafreq;
12259  int sepacardfreq;
12260  int ncuts;
12261  int maxsepacuts;
12262  int i;
12263 
12264  *result = SCIP_DIDNOTRUN;
12265 
12266  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12267  assert(conshdlrdata != NULL);
12268 
12269  depth = SCIPgetDepth(scip);
12270  nrounds = SCIPgetNSepaRounds(scip);
12271 
12272  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12273  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12274 
12275  /* only call the separator a given number of times at each node */
12276  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12277  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12278  return SCIP_OKAY;
12279 
12280  /* check, if we should additionally separate knapsack cuts */
12281  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12282  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12283  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12284  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12285 
12286  /* check dual bound to see if we want to produce knapsack cuts at this node */
12287  loclowerbound = SCIPgetLocalLowerbound(scip);
12288  glblowerbound = SCIPgetLowerbound(scip);
12289  cutoffbound = SCIPgetCutoffbound(scip);
12290  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12291  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12292  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12293 
12294  /* get the maximal number of cuts allowed in a separation round */
12295  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12296 
12297  *result = SCIP_DIDNOTFIND;
12298  ncuts = 0;
12299  cutoff = FALSE;
12300 
12301  /* separate useful constraints */
12302  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12303  {
12304  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12305  }
12306 
12307  /* adjust return value */
12308  if ( cutoff )
12309  *result = SCIP_CUTOFF;
12310  else if ( ncuts > 0 )
12311  *result = SCIP_SEPARATED;
12312 
12313  return SCIP_OKAY;
12314 }
12315 
12316 
12317 /** separation method of constraint handler for arbitrary primal solutions */
12318 static
12319 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12320 { /*lint --e{715}*/
12321  SCIP_CONSHDLRDATA* conshdlrdata;
12322  SCIP_Bool sepacardinality;
12323  SCIP_Bool cutoff;
12324 
12325  int depth;
12326  int nrounds;
12327  int sepafreq;
12328  int sepacardfreq;
12329  int ncuts;
12330  int maxsepacuts;
12331  int i;
12332 
12333  *result = SCIP_DIDNOTRUN;
12334 
12335  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12336  assert(conshdlrdata != NULL);
12337 
12338  depth = SCIPgetDepth(scip);
12339  nrounds = SCIPgetNSepaRounds(scip);
12340 
12341  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12342  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12343 
12344  /* only call the separator a given number of times at each node */
12345  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12346  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12347  return SCIP_OKAY;
12348 
12349  /* check, if we should additionally separate knapsack cuts */
12350  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12351  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12352  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12353  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12354 
12355  /* get the maximal number of cuts allowed in a separation round */
12356  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12357 
12358  *result = SCIP_DIDNOTFIND;
12359  ncuts = 0;
12360  cutoff = FALSE;
12361 
12362  /* separate useful constraints */
12363  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12364  {
12365  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12366  }
12367 
12368  /* adjust return value */
12369  if ( cutoff )
12370  *result = SCIP_CUTOFF;
12371  else if( ncuts > 0 )
12372  *result = SCIP_SEPARATED;
12373 
12374  return SCIP_OKAY;
12375 }
12376 
12377 /** constraint enforcing method of constraint handler for LP solutions */
12378 static
12379 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12380 { /*lint --e{715}*/
12381  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12382 
12383  return SCIP_OKAY;
12384 }
12385 
12386 /** constraint enforcing method of constraint handler for relaxation solutions */
12387 static
12388 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12389 { /*lint --e{715}*/
12390  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12391 
12392  return SCIP_OKAY;
12393 }
12394 
12395 /** constraint enforcing method of constraint handler for pseudo solutions */
12396 static
12397 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12398 { /*lint --e{715}*/
12399  SCIP_Bool violated;
12400  int i;
12401 
12402  for( i = 0; i < nconss; i++ )
12403  {
12404  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12405  if( violated )
12406  {
12407  *result = SCIP_INFEASIBLE;
12408  return SCIP_OKAY;
12409  }
12410  }
12411  *result = SCIP_FEASIBLE;
12412 
12413  return SCIP_OKAY;
12414 }
12415 
12416 /** feasibility check method of constraint handler for integral solutions */
12417 static
12418 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12419 { /*lint --e{715}*/
12420  SCIP_Bool violated;
12421  int i;
12422 
12423  *result = SCIP_FEASIBLE;
12424 
12425  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12426  {
12427  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12428  if( violated )
12429  *result = SCIP_INFEASIBLE;
12430  }
12431 
12432  return SCIP_OKAY;
12433 }
12434 
12435 /** domain propagation method of constraint handler */
12436 static
12437 SCIP_DECL_CONSPROP(consPropKnapsack)
12438 { /*lint --e{715}*/
12439  SCIP_CONSHDLRDATA* conshdlrdata;
12440  SCIP_Bool cutoff;
12441  SCIP_Bool redundant;
12442  SCIP_Bool inpresolve;
12443  int nfixedvars;
12444  int i;
12446  cutoff = FALSE;
12447  nfixedvars = 0;
12448 
12449  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12450  assert(conshdlrdata != NULL);
12451 
12452  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12453  assert(!inpresolve || SCIPinProbing(scip));
12454 
12455  /* process useful constraints */
12456  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12457  {
12458  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12459  * otherwise the multi-aggregation should be resolved
12460  */
12461  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12462  continue;
12463 #ifndef NDEBUG
12464  else
12465  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12466 #endif
12467 
12468  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12469 
12470  /* unmark the constraint to be propagated */
12471  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12472 
12473  }
12474 
12475  /* adjust result code */
12476  if( cutoff )
12477  *result = SCIP_CUTOFF;
12478  else if( nfixedvars > 0 )
12479  *result = SCIP_REDUCEDDOM;
12480  else
12481  *result = SCIP_DIDNOTFIND;
12482 
12483  return SCIP_OKAY;
12484 }
12485 
12486 /** presolving method of constraint handler */
12487 static
12488 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12489 { /*lint --e{574,715}*/
12490  SCIP_CONSHDLRDATA* conshdlrdata;
12491  SCIP_CONSDATA* consdata;
12492  SCIP_CONS* cons;
12493  SCIP_Bool cutoff;
12494  SCIP_Bool redundant;
12495  SCIP_Bool success;
12496  int oldnfixedvars;
12497  int oldnchgbds;
12498  int oldndelconss;
12499  int oldnaddconss;
12500  int oldnchgcoefs;
12501  int oldnchgsides;
12502  int firstchange;
12503  int c;
12504  SCIP_Bool newchanges;
12505 
12506  /* remember old preprocessing counters */
12507  cutoff = FALSE;
12508  oldnfixedvars = *nfixedvars;
12509  oldnchgbds = *nchgbds;
12510  oldndelconss = *ndelconss;
12511  oldnaddconss = *naddconss;
12512  oldnchgcoefs = *nchgcoefs;
12513  oldnchgsides = *nchgsides;
12514  firstchange = INT_MAX;
12515 
12516  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12517 
12518  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12519  assert(conshdlrdata != NULL);
12520 
12521  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12522  {
12523  int thisnfixedvars;
12524  int thisnchgbds;
12525 
12526  cons = conss[c];
12527  consdata = SCIPconsGetData(cons);
12528  assert(consdata != NULL);
12529 
12530  /* update data structures */
12531  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12532  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12533  {
12534  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12535  if( cutoff )
12536  break;
12537  }
12538 
12539  /* force presolving the constraint in the initial round */
12540  if( nrounds == 0 )
12541  consdata->presolvedtiming = 0;
12542  else if( consdata->presolvedtiming >= presoltiming )
12543  continue;
12544 
12545  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12546  SCIPdebugPrintCons(scip, cons, NULL);
12547  consdata->presolvedtiming = presoltiming;
12548 
12549  thisnfixedvars = *nfixedvars;
12550  thisnchgbds = *nchgbds;
12551 
12552  /* merge constraint, so propagation works better */
12553  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12554  if( cutoff )
12555  break;
12556 
12557  /* add cliques in the knapsack to the clique table */
12558  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12559  {
12560  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12561  if( cutoff )
12562  break;
12563  }
12564 
12565  /* propagate constraint */
12566  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12567  {
12568  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12569 
12570  if( cutoff )
12571  break;
12572  if( redundant )
12573  {
12574  (*ndelconss)++;
12575  continue;
12576  }
12577  }
12578 
12579  /* remove again all fixed variables, if further fixings were found */
12580  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12581  {
12582  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12583  if( cutoff )
12584  break;
12585 
12586  thisnfixedvars = *nfixedvars;
12587  }
12588 
12589  if( !SCIPconsIsModifiable(cons) )
12590  {
12591  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12592  if( consdata->weightsum <= consdata->capacity )
12593  {
12594  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12595  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12596  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12597  continue;
12598  }
12599 
12600  /* divide weights by their greatest common divisor */
12601  normalizeWeights(cons, nchgcoefs, nchgsides);
12602 
12603  /* try to simplify inequalities */
12604  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12605  {
12606  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12607  if( cutoff )
12608  break;
12609 
12610  if( SCIPconsIsDeleted(cons) )
12611  continue;
12612 
12613  /* remove again all fixed variables, if further fixings were found */
12614  if( *nfixedvars > thisnfixedvars )
12615  {
12616  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12617  if( cutoff )
12618  break;
12619  }
12620  }
12621 
12622  /* tighten capacity and weights */
12623  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12624  if( cutoff )
12625  break;
12626 
12627  if( SCIPconsIsActive(cons) )
12628  {
12629  if( conshdlrdata->dualpresolving && SCIPallowDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12630  {
12631  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12632  * dual reduction
12633  */
12634  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12635  if( redundant )
12636  continue;
12637  }
12638 
12639  /* check if knapsack constraint is parallel to objective function */
12640  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12641  }
12642  }
12643  /* remember the first changed constraint to begin the next aggregation round with */
12644  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12645  firstchange = c;
12646  }
12647 
12648  /* preprocess pairs of knapsack constraints */
12649  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12650  {
12651  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12652  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12653  }
12654 
12655  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12656  success = TRUE;
12657  else
12658  success = FALSE;
12659 
12660  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12661  {
12662  SCIP_Longint npaircomparisons;
12663 
12664  npaircomparisons = 0;
12665  oldndelconss = *ndelconss;
12666  oldnchgsides = *nchgsides;
12667  oldnchgcoefs = *nchgcoefs;
12668 
12669  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12670  {
12671  cons = conss[c];
12672  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12673  continue;
12674 
12675  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12676 
12677  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12678 
12679  if( npaircomparisons > NMINCOMPARISONS )
12680  {
12681  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12682  success = TRUE;
12683  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12684  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12685  break;
12686  oldndelconss = *ndelconss;
12687  oldnchgsides = *nchgsides;
12688  oldnchgcoefs = *nchgcoefs;
12689  npaircomparisons = 0;
12690  }
12691  }
12692  }
12693 #ifdef WITH_CARDINALITY_UPGRADE
12694  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12695  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12696  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12697  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12698  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12699  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12700  * as well, we better keep this code disabled. */
12701  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12702  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12703  {
12704  SCIP_HASHMAP* varhash;
12705  SCIP_VAR** cardvars;
12706  SCIP_Real* cardweights;
12707  int noldupgdconss;
12708  int nscipvars;
12709  int makeupgrade;
12710 
12711  noldupgdconss = *nupgdconss;
12712  nscipvars = SCIPgetNVars(scip);
12713  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12714  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12715 
12716  /* set up hash map */
12717  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12718 
12719  /* We loop through all cardinality constraints twice:
12720  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12721  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12722  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12723  * - Second, upgrade knapsack constraints to cardinality constraints. */
12724  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12725  {
12726  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12727  {
12728  SCIP_CONS* cardcons;
12729  SCIP_VAR** vars;
12730  SCIP_Longint* weights;
12731  int nvars;
12732  int v;
12733 
12734  cons = conss[c];
12735  assert( cons != NULL );
12736  consdata = SCIPconsGetData(cons);
12737  assert( consdata != NULL );
12738 
12739  nvars = consdata->nvars;
12740  vars = consdata->vars;
12741  weights = consdata->weights;
12742 
12743  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12744  * - all variables must be binary (always true)
12745  * - all coefficients must be 1.0
12746  * - the right hand side must be smaller than nvars
12747  */
12748  if ( consdata->capacity >= nvars )
12749  continue;
12750 
12751  /* the weights are sorted: check first and last weight */
12752  assert( consdata->sorted );
12753  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12754  continue;
12755 
12756  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12757  for (v = 0; v < nvars; ++v)
12758  {
12759  SCIP_BOUNDTYPE* impltypes;
12760  SCIP_Real* implbounds;
12761  SCIP_VAR** implvars;
12762  SCIP_VAR* var;
12763  int nimpls;
12764  int j;
12765 
12766  var = consdata->vars[v];
12767  assert( var != NULL );
12768  assert( SCIPvarIsBinary(var) );
12769 
12770  /* ignore non-active variables */
12771  if ( ! SCIPvarIsActive(var) )
12772  break;
12773 
12774  /* be sure that implication variable has zero objective */
12775  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12776  break;
12777 
12778  nimpls = SCIPvarGetNImpls(var, FALSE);
12779  implvars = SCIPvarGetImplVars(var, FALSE);
12780  implbounds = SCIPvarGetImplBounds(var, FALSE);
12781  impltypes = SCIPvarGetImplTypes(var, FALSE);
12782 
12783  for (j = 0; j < nimpls; ++j)
12784  {
12785  /* be sure that continuous variable is fixed to 0 */
12786  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12787  continue;
12788 
12789  /* cannot currently deal with nonzero fixings */
12790  if ( ! SCIPisZero(scip, implbounds[j]) )
12791  continue;
12792 
12793  /* number of down locks should be one */
12794  if ( SCIPvarGetNLocksDown(vars[v]) != 1 )
12795  continue;
12796 
12797  cardvars[v] = implvars[j];
12798  cardweights[v] = (SCIP_Real) v;
12799 
12800  break;
12801  }
12802 
12803  /* found no variable upper bound candidate -> exit */
12804  if ( j >= nimpls )
12805  break;
12806  }
12807 
12808  /* did not find fitting variable upper bound for some variable -> exit */
12809  if ( v < nvars )
12810  break;
12811 
12812  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12813  * in which the binary variable is involved in */
12814  if ( makeupgrade == 0 )
12815  {
12816  for (v = 0; v < nvars; ++v)
12817  {
12818  if ( SCIPhashmapExists(varhash, vars[v]) )
12819  {
12820  int image;
12821 
12822  image = (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]);
12823  SCIP_CALL( SCIPhashmapSetImage(varhash, vars[v], (void*) (size_t) (image + 1)) );/*lint !e776*/
12824  assert( image + 1 == (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) );
12825  }
12826  else
12827  {
12828  SCIP_CALL( SCIPhashmapInsert(varhash, vars[v], (void*) (size_t) 1) );/*lint !e571*/
12829  assert( 1 == (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) );
12830  assert( SCIPhashmapExists(varhash, vars[v]) );
12831  }
12832  }
12833  }
12834  else
12835  {
12836  SCIP_CONS* origcons;
12837 
12838  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12839  * knapsack constraint coincides with the number of variable up locks */
12840  for (v = 0; v < nvars; ++v)
12841  {
12842  assert( SCIPhashmapExists(varhash, vars[v]) );
12843  if ( SCIPvarGetNLocksUp(vars[v]) != (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) )
12844  break;
12845  }
12846  if ( v < nvars )
12847  break;
12848 
12849  /* store that we have upgraded */
12850  conshdlrdata->upgradedcard = TRUE;
12851 
12852  /* at this point we found suitable variable upper bounds */
12853  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12854 
12855  /* create cardinality constraint */
12856  assert( ! SCIPconsIsModifiable(cons) );
12857  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12861 #ifdef SCIP_DEBUG
12862  SCIPprintCons(scip, cons, NULL);
12863  SCIPinfoMessage(scip, NULL, "\n");
12864  SCIPprintCons(scip, cardcons, NULL);
12865  SCIPinfoMessage(scip, NULL, "\n");
12866 #endif
12867  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12868  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12869  ++(*nupgdconss);
12870 
12871  /* delete oknapsack constraint */
12872  SCIP_CALL( SCIPdelCons(scip, cons) );
12873  ++(*ndelconss);
12874 
12875  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12876  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12877  * although the cardinality constraint is satisfied. */
12878  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12879  assert( origcons != NULL );
12880  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12881 
12882  for (v = 0; v < nvars; ++v)
12883  {
12884  int image;
12885 
12886  assert ( SCIPhashmapExists(varhash, vars[v]) );
12887  image = (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]);
12888  SCIP_CALL( SCIPhashmapSetImage(varhash, vars[v], (void*) (size_t) (image - 1)) );
12889  assert( image - 1 == (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) );
12890  }
12891  }
12892  }
12893  }
12894  SCIPhashmapFree(&varhash);
12895  SCIPfreeBufferArray(scip, &cardweights);
12896  SCIPfreeBufferArray(scip, &cardvars);
12897 
12898  if ( *nupgdconss > noldupgdconss )
12899  success = TRUE;
12900  }
12901 #endif
12902 
12903  if( cutoff )
12904  *result = SCIP_CUTOFF;
12905  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12906  *result = SCIP_SUCCESS;
12907  else
12908  *result = SCIP_DIDNOTFIND;
12909 
12910  return SCIP_OKAY;
12911 }
12912 
12913 /** propagation conflict resolving method of constraint handler */
12914 static
12915 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12916 { /*lint --e{715}*/
12917  SCIP_CONSDATA* consdata;
12918  SCIP_Longint capsum;
12919  int i;
12920 
12921  assert(result != NULL);
12922 
12923  consdata = SCIPconsGetData(cons);
12924  assert(consdata != NULL);
12925 
12926  /* check if we fixed a binary variable to one (due to negated clique) */
12927  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12928  {
12929  for( i = 0; i < consdata->nvars; ++i )
12930  {
12931  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12932  {
12933  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12934  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12935  break;
12936  }
12937  }
12938  assert(i < consdata->nvars);
12939  }
12940  else
12941  {
12942  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12943  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12944  * knapsack constraint, see one above call of SCIPinferBinvarCons
12945  */
12946  if( inferinfo < 0 )
12947  capsum = 0;
12948  else
12949  {
12950  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12951  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12952  */
12953  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12954  capsum = consdata->weights[inferinfo];
12955  else
12956  {
12957  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12958  {}
12959  assert(i < consdata->nvars);
12960  capsum = consdata->weights[i];
12961  }
12962  }
12963 
12964  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12965  * the capacity
12966  */
12967  if( capsum <= consdata->capacity )
12968  {
12969  for( i = 0; i < consdata->nvars; i++ )
12970  {
12971  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12972  {
12973  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12974  capsum += consdata->weights[i];
12975  if( capsum > consdata->capacity )
12976  break;
12977  }
12978  }
12979  }
12980  }
12981 
12982  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12983  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12984  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12985  * used to fix variables to zero.
12986  *
12987  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12988  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12989  * one.
12990  */
12991  *result = SCIP_SUCCESS;
12992 
12993  return SCIP_OKAY;
12994 }
12995 
12996 /** variable rounding lock method of constraint handler */
12997 /**! [SnippetConsLockKnapsack] */
12998 static
12999 SCIP_DECL_CONSLOCK(consLockKnapsack)
13000 { /*lint --e{715}*/
13001  SCIP_CONSDATA* consdata;
13002  int i;
13003 
13004  consdata = SCIPconsGetData(cons);
13005  assert(consdata != NULL);
13006 
13007  for( i = 0; i < consdata->nvars; i++)
13008  {
13009  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[i], nlocksneg, nlockspos) );
13010  }
13011 
13012  return SCIP_OKAY;
13013 }
13014 /**! [SnippetConsLockKnapsack] */
13015 
13016 
13017 /** variable deletion method of constraint handler */
13018 static
13019 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13020 {
13021  assert(scip != NULL);
13022  assert(conshdlr != NULL);
13023  assert(conss != NULL || nconss == 0);
13024 
13025  if( nconss > 0 )
13026  {
13027  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13028  }
13029 
13030  return SCIP_OKAY;
13031 }
13032 
13033 /** constraint display method of constraint handler */
13034 static
13035 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13036 { /*lint --e{715}*/
13037  SCIP_CONSDATA* consdata;
13038  int i;
13039 
13040  assert( scip != NULL );
13041  assert( conshdlr != NULL );
13042  assert( cons != NULL );
13044  consdata = SCIPconsGetData(cons);
13045  assert(consdata != NULL);
13046 
13047  for( i = 0; i < consdata->nvars; ++i )
13048  {
13049  if( i > 0 )
13050  SCIPinfoMessage(scip, file, " ");
13051  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13052  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13053  }
13054  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13055 
13056  return SCIP_OKAY;
13057 }
13058 
13059 /** constraint copying method of constraint handler */
13060 static
13061 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13062 { /*lint --e{715}*/
13063  SCIP_VAR** sourcevars;
13064  SCIP_Longint* weights;
13065  SCIP_Real* coefs;
13066  const char* consname;
13067  int nvars;
13068  int v;
13070  /* get variables and coefficients of the source constraint */
13071  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13072  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13073  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13074 
13075  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13076  for( v = 0; v < nvars; ++v )
13077  coefs[v] = (SCIP_Real) weights[v];
13078 
13079  if( name != NULL )
13080  consname = name;
13081  else
13082  consname = SCIPconsGetName(sourcecons);
13083 
13084  /* copy the logic using the linear constraint copy method */
13085  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13086  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13087  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13088  assert(cons != NULL);
13089 
13090  SCIPfreeBufferArray(scip, &coefs);
13091 
13092  return SCIP_OKAY;
13093 }
13094 
13095 /** constraint parsing method of constraint handler */
13096 static
13097 SCIP_DECL_CONSPARSE(consParseKnapsack)
13098 { /*lint --e{715}*/
13099  SCIP_VAR* var;
13100  SCIP_Longint weight;
13101  SCIP_VAR** vars;
13102  SCIP_Longint* weights;
13103  SCIP_Longint capacity;
13104  char* endptr;
13105  int nread;
13106  int nvars;
13107  int varssize;
13108 
13109  assert(scip != NULL);
13110  assert(success != NULL);
13111  assert(str != NULL);
13112  assert(name != NULL);
13113  assert(cons != NULL);
13114 
13115  *success = TRUE;
13116 
13117  nvars = 0;
13118  varssize = 5;
13119  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13120  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13121 
13122  while( *str != '\0' )
13123  {
13124  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13125  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13126  break;
13127 
13128  str += nread;
13129 
13130  /* skip whitespace */
13131  while( isspace((int)*str) )
13132  ++str;
13133 
13134  /* parse variable name */
13135  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13136  if( var == NULL )
13137  {
13138  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13139  *success = FALSE;
13140  break;
13141  }
13142 
13143  str = endptr;
13144 
13145  /* store weight and variable */
13146  if( varssize <= nvars )
13147  {
13148  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13149  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13150  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13151  }
13152 
13153  vars[nvars] = var;
13154  weights[nvars] = weight;
13155  ++nvars;
13156 
13157  /* skip whitespace */
13158  while( isspace((int)*str) )
13159  ++str;
13160  }
13161 
13162  if( *success )
13163  {
13164  if( strncmp(str, "<= ", 3) != 0 )
13165  {
13166  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13167  *success = FALSE;
13168  }
13169  else
13170  {
13171  str += 3;
13172  }
13173  }
13174 
13175  if( *success )
13176  {
13177  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13178  {
13179  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13180  *success = FALSE;
13181  }
13182  else
13183  {
13184  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13185  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13186  }
13187  }
13188 
13189  SCIPfreeBufferArray(scip, &vars);
13190  SCIPfreeBufferArray(scip, &weights);
13191 
13192  return SCIP_OKAY;
13193 }
13194 
13195 /** constraint method of constraint handler which returns the variables (if possible) */
13196 static
13197 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13198 { /*lint --e{715}*/
13199  SCIP_CONSDATA* consdata;
13200 
13201  consdata = SCIPconsGetData(cons);
13202  assert(consdata != NULL);
13203 
13204  if( varssize < consdata->nvars )
13205  (*success) = FALSE;
13206  else
13207  {
13208  assert(vars != NULL);
13209 
13210  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13211  (*success) = TRUE;
13212  }
13213 
13214  return SCIP_OKAY;
13215 }
13216 
13217 /** constraint method of constraint handler which returns the number of variables (if possible) */
13218 static
13219 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13220 { /*lint --e{715}*/
13221  SCIP_CONSDATA* consdata;
13222 
13223  consdata = SCIPconsGetData(cons);
13224  assert(consdata != NULL);
13225 
13226  (*nvars) = consdata->nvars;
13227  (*success) = TRUE;
13228 
13229  return SCIP_OKAY;
13230 }
13231 
13232 /*
13233  * Event handler
13234  */
13235 
13236 /** execution method of bound change event handler */
13237 static
13238 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13239 { /*lint --e{715}*/
13240  SCIP_CONSDATA* consdata;
13241 
13242  assert(eventdata != NULL);
13243  assert(eventdata->cons != NULL);
13244 
13245  consdata = SCIPconsGetData(eventdata->cons);
13246  assert(consdata != NULL);
13247 
13248  switch( SCIPeventGetType(event) )
13249  {
13251  consdata->onesweightsum += eventdata->weight;
13252  consdata->presolvedtiming = 0;
13253  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13254  break;
13256  consdata->onesweightsum -= eventdata->weight;
13257  break;
13259  consdata->presolvedtiming = 0;
13260  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13261  break;
13262  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13263  if( !consdata->existmultaggr )
13264  {
13265  SCIP_VAR* var;
13266  var = SCIPeventGetVar(event);
13267  assert(var != NULL);
13268 
13269  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13271  {
13272  consdata->existmultaggr = TRUE;
13273  consdata->merged = FALSE;
13274  }
13275  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13277  consdata->merged = FALSE;
13278 
13279  }
13280  /*lint -fallthrough*/
13281  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13282  consdata->presolvedtiming = 0;
13283  break;
13285  consdata->varsdeleted = TRUE;
13286  break;
13287  default:
13288  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
13289  return SCIP_INVALIDDATA;
13290  }
13291 
13292  return SCIP_OKAY;
13293 }
13294 
13295 
13296 /*
13297  * constraint specific interface methods
13298  */
13299 
13300 /** creates the handler for knapsack constraints and includes it in SCIP */
13302  SCIP* scip /**< SCIP data structure */
13303  )
13304 {
13305  SCIP_EVENTHDLRDATA* eventhdlrdata;
13306  SCIP_CONSHDLRDATA* conshdlrdata;
13307  SCIP_CONSHDLR* conshdlr;
13308 
13309  /* create knapsack constraint handler data */
13310  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13311 
13312  /* include event handler for bound change events */
13313  eventhdlrdata = NULL;
13314  conshdlrdata->eventhdlr = NULL;
13315  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13316  eventExecKnapsack, eventhdlrdata) );
13317 
13318  /* get event handler for bound change events */
13319  if( conshdlrdata->eventhdlr == NULL )
13320  {
13321  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13322  return SCIP_PLUGINNOTFOUND;
13323  }
13324 
13325  /* include constraint handler */
13328  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13329  conshdlrdata) );
13330 
13331  assert(conshdlr != NULL);
13332 
13333  /* set non-fundamental callbacks via specific setter functions */
13334  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13335  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13336  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13337  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13338  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13339  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13340  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13341  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13342  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13343  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13344  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13345  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13346  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13347  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13348  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13349  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13351  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13352  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13354  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13355  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13356 
13357  if( SCIPfindConshdlr(scip,"linear") != NULL )
13358  {
13359  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13361  }
13362 
13363  /* add knapsack constraint handler parameters */
13364  SCIP_CALL( SCIPaddIntParam(scip,
13365  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13366  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13367  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13369  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13370  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13371  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13373  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13374  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13375  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13376  SCIP_CALL( SCIPaddIntParam(scip,
13377  "constraints/" CONSHDLR_NAME "/maxrounds",
13378  "maximal number of separation rounds per node (-1: unlimited)",
13379  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13380  SCIP_CALL( SCIPaddIntParam(scip,
13381  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13382  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13383  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13384  SCIP_CALL( SCIPaddIntParam(scip,
13385  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13386  "maximal number of cuts separated per separation round",
13387  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13388  SCIP_CALL( SCIPaddIntParam(scip,
13389  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13390  "maximal number of cuts separated per separation round in the root node",
13391  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13393  "constraints/" CONSHDLR_NAME "/disaggregation",
13394  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13395  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13397  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13398  "should presolving try to simplify knapsacks",
13399  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13401  "constraints/" CONSHDLR_NAME "/negatedclique",
13402  "should negated clique information be used in solving process",
13403  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13405  "constraints/" CONSHDLR_NAME "/presolpairwise",
13406  "should pairwise constraint comparison be performed in presolving?",
13407  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13409  "constraints/" CONSHDLR_NAME "/presolusehashing",
13410  "should hash table be used for detecting redundant constraints in advance",
13411  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13413  "constraints/" CONSHDLR_NAME "/dualpresolving",
13414  "should dual presolving steps be performed?",
13415  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13417  "constraints/" CONSHDLR_NAME "/usegubs",
13418  "should GUB information be used for separation?",
13419  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13421  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13422  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13423  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13425  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13426  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13427  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13429  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13430  "should clique partition information be updated when old partition seems outdated?",
13431  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13433  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13434  "factor on the growth of global cliques to decide when to update a previous "
13435  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13436  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13437 #ifdef WITH_CARDINALITY_UPGRADE
13439  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13440  "if TRUE then try to update knapsack constraints to cardinality constraints",
13441  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13442 #endif
13443  return SCIP_OKAY;
13444 }
13445 
13446 /** creates and captures a knapsack constraint
13447  *
13448  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13449  */
13450 /**! [SnippetConsCreationKnapsack] */
13452  SCIP* scip, /**< SCIP data structure */
13453  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13454  const char* name, /**< name of constraint */
13455  int nvars, /**< number of items in the knapsack */
13456  SCIP_VAR** vars, /**< array with item variables */
13457  SCIP_Longint* weights, /**< array with item weights */
13458  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13459  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13460  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13461  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13462  * Usually set to TRUE. */
13463  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13464  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13465  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13466  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13467  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13468  * Usually set to TRUE. */
13469  SCIP_Bool local, /**< is constraint only valid locally?
13470  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13471  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13472  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13473  * adds coefficients to this constraint. */
13474  SCIP_Bool dynamic, /**< is constraint subject to aging?
13475  * Usually set to FALSE. Set to TRUE for own cuts which
13476  * are separated as constraints. */
13477  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13478  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13479  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13480  * if it may be moved to a more global node?
13481  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13482  )
13483 {
13484  SCIP_CONSHDLRDATA* conshdlrdata;
13485  SCIP_CONSHDLR* conshdlr;
13486  SCIP_CONSDATA* consdata;
13487 
13488  /* find the knapsack constraint handler */
13489  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13490  if( conshdlr == NULL )
13491  {
13492  SCIPerrorMessage("knapsack constraint handler not found\n");
13493  return SCIP_PLUGINNOTFOUND;
13494  }
13495 
13496  /* get event handler */
13497  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13498  assert(conshdlrdata != NULL);
13499  assert(conshdlrdata->eventhdlr != NULL);
13500 
13501  /* create constraint data */
13502  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13503 
13504  /* create constraint */
13505  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13506  local, modifiable, dynamic, removable, stickingatnode) );
13507 
13508  /* catch events for variables */
13509  if( SCIPisTransformed(scip) )
13510  {
13511  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13512  }
13513 
13514  return SCIP_OKAY;
13515 }
13516 /**! [SnippetConsCreationKnapsack] */
13517 
13518 /** creates and captures a knapsack constraint
13519  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13520  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13521  *
13522  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13523  *
13524  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13525  */
13527  SCIP* scip, /**< SCIP data structure */
13528  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13529  const char* name, /**< name of constraint */
13530  int nvars, /**< number of items in the knapsack */
13531  SCIP_VAR** vars, /**< array with item variables */
13532  SCIP_Longint* weights, /**< array with item weights */
13533  SCIP_Longint capacity /**< capacity of knapsack */
13534  )
13535 {
13536  assert(scip != NULL);
13537 
13538  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13539  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13540 
13541  return SCIP_OKAY;
13542 }
13543 
13544 /** adds new item to knapsack constraint */
13546  SCIP* scip, /**< SCIP data structure */
13547  SCIP_CONS* cons, /**< constraint data */
13548  SCIP_VAR* var, /**< item variable */
13549  SCIP_Longint weight /**< item weight */
13550  )
13551 {
13552  assert(var != NULL);
13554  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13555  {
13556  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13557  return SCIP_INVALIDDATA;
13558  }
13559 
13560  SCIP_CALL( addCoef(scip, cons, var, weight) );
13561 
13562  return SCIP_OKAY;
13563 }
13564 
13565 /** gets the capacity of the knapsack constraint */
13567  SCIP* scip, /**< SCIP data structure */
13568  SCIP_CONS* cons /**< constraint data */
13569  )
13570 {
13571  SCIP_CONSDATA* consdata;
13572 
13573  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13574  {
13575  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13576  SCIPABORT();
13577  return 0; /*lint !e527*/
13578  }
13579 
13580  consdata = SCIPconsGetData(cons);
13581  assert(consdata != NULL);
13582 
13583  return consdata->capacity;
13584 }
13585 
13586 /** changes capacity of the knapsack constraint
13587  *
13588  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13589  */
13591  SCIP* scip, /**< SCIP data structure */
13592  SCIP_CONS* cons, /**< constraint data */
13593  SCIP_Longint capacity /**< new capacity of knapsack */
13594  )
13595 {
13596  SCIP_CONSDATA* consdata;
13597 
13599  {
13600  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13601  return SCIP_INVALIDDATA;
13602  }
13603 
13604  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13605  {
13606  SCIPerrorMessage("method can only be called during problem creation stage\n");
13607  return SCIP_INVALIDDATA;
13608  }
13609 
13610  consdata = SCIPconsGetData(cons);
13611  assert(consdata != NULL);
13612 
13613  consdata->capacity = capacity;
13614 
13615  return SCIP_OKAY;
13616 }
13617 
13618 /** gets the number of items in the knapsack constraint */
13620  SCIP* scip, /**< SCIP data structure */
13621  SCIP_CONS* cons /**< constraint data */
13622  )
13623 {
13624  SCIP_CONSDATA* consdata;
13625 
13626  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13627  {
13628  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13629  SCIPABORT();
13630  return -1; /*lint !e527*/
13631  }
13632 
13633  consdata = SCIPconsGetData(cons);
13634  assert(consdata != NULL);
13635 
13636  return consdata->nvars;
13637 }
13638 
13639 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13641  SCIP* scip, /**< SCIP data structure */
13642  SCIP_CONS* cons /**< constraint data */
13643  )
13644 {
13645  SCIP_CONSDATA* consdata;
13646 
13647  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13648  {
13649  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13650  SCIPABORT();
13651  return NULL; /*lint !e527*/
13652  }
13653 
13654  consdata = SCIPconsGetData(cons);
13655  assert(consdata != NULL);
13656 
13657  return consdata->vars;
13658 }
13659 
13660 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13662  SCIP* scip, /**< SCIP data structure */
13663  SCIP_CONS* cons /**< constraint data */
13664  )
13665 {
13666  SCIP_CONSDATA* consdata;
13667 
13668  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13669  {
13670  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13671  SCIPABORT();
13672  return NULL; /*lint !e527*/
13673  }
13674 
13675  consdata = SCIPconsGetData(cons);
13676  assert(consdata != NULL);
13677 
13678  return consdata->weights;
13679 }
13680 
13681 /** gets the dual solution of the knapsack constraint in the current LP */
13683  SCIP* scip, /**< SCIP data structure */
13684  SCIP_CONS* cons /**< constraint data */
13685  )
13686 {
13687  SCIP_CONSDATA* consdata;
13688 
13689  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13690  {
13691  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13692  SCIPABORT();
13693  return SCIP_INVALID; /*lint !e527*/
13694  }
13695 
13696  consdata = SCIPconsGetData(cons);
13697  assert(consdata != NULL);
13698 
13699  if( consdata->row != NULL )
13700  return SCIProwGetDualsol(consdata->row);
13701  else
13702  return 0.0;
13703 }
13704 
13705 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13707  SCIP* scip, /**< SCIP data structure */
13708  SCIP_CONS* cons /**< constraint data */
13709  )
13710 {
13711  SCIP_CONSDATA* consdata;
13712 
13713  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13714  {
13715  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13716  SCIPABORT();
13717  return SCIP_INVALID; /*lint !e527*/
13718  }
13719 
13720  consdata = SCIPconsGetData(cons);
13721  assert(consdata != NULL);
13722 
13723  if( consdata->row != NULL )
13724  return SCIProwGetDualfarkas(consdata->row);
13725  else
13726  return 0.0;
13727 }
13728 
13729 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13730  * the user must not modify the row!
13731  */
13733  SCIP* scip, /**< SCIP data structure */
13734  SCIP_CONS* cons /**< constraint data */
13735  )
13736 {
13737  SCIP_CONSDATA* consdata;
13738 
13739  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13740  {
13741  SCIPerrorMessage("constraint is not a knapsack\n");
13742  SCIPABORT();
13743  return NULL; /*lint !e527*/
13744  }
13745 
13746  consdata = SCIPconsGetData(cons);
13747  assert(consdata != NULL);
13748 
13749  return consdata->row;
13750 }
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:77
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int * gubconssidx
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4143
#define DEFAULT_DETECTCUTOFFBOUND
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28372
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:22593
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:19211
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6291
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:41459
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:17490
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:10889
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3353
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22587
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:22523
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30613
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19649
#define CONSHDLR_DESC
Definition: cons_knapsack.c:45
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47298
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:60
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17068
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6314
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip.c:19115
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:30460
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47311
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:19509
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2265
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:41226
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6604
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:43453
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30636
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip.h:22622
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17468
#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:17276
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6544
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:11720
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
Definition: scip.c:43481
#define SCIP_MAXSTRLEN
Definition: def.h:259
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:47
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:6036
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22591
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28400
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12663
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:46813
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17056
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30668
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip.c:27959
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47088
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip.c:19078
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27388
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47015
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17639
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:70
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8611
#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:28112
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:18038
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18766
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16842
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:6205
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:49
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:47350
#define FALSE
Definition: def.h:64
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10289
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:5894
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:54
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10011
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47100
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:646
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:28630
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:13408
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:51
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21660
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8265
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17510
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:16969
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:793
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:8295
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip.c:27155
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22639
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:62
#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:5948
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17480
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:22628
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4999
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46963
#define SCIP_LONGINT_MAX
Definition: def.h:135
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:1017
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip.c:37034
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip.c:6475
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8255
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6337
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:16504
#define SCIPdebugMsgPrint
Definition: scip.h:456
#define SCIPdebugMsg
Definition: scip.h:455
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:4265
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:18998
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:59
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6521
#define DEFAULT_PRESOLUSEHASHING
Definition: cons_knapsack.c:94
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8047
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17628
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:1343
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11992
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:27584
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:46415
#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:2014
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:47423
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:17092
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:16695
#define DEFAULT_SEPACARDFREQ
Definition: cons_knapsack.c:79
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
#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:27133
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:27884
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip.c:24222
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:80
#define DEFAULT_DISAGGREGATION
Definition: cons_knapsack.c:87
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11628
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:22599
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:46
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip.c:34528
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1054
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:6060
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:12591
#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:46976
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:13297
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:38948
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
#define DEFAULT_PRESOLPAIRWISE
Definition: cons_knapsack.c:97
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
#define SCIPallocBuffer(scip, ptr)
Definition: scip.h:22618
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
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip.c:12718
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip.c:34546
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21788
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip.c:27934
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7986
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17542
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8205
#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:16662
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6085
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
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)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28602
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:173
#define DEFAULT_NEGATEDCLIQUE
Definition: cons_knapsack.c:89
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:350
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:473
SCIP_Real SCIPgetLowerbound(SCIP *scip)
Definition: scip.c:43277
#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:17500
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47337
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17080
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2395
GUBVARSTATUS * gubvarsstatus
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip.c:13802
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47324
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition: scip.c:27535
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1360
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17532
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8225
#define KNAPSACKRELAX_MAXDNOM
Definition: cons_knapsack.c:76
#define DEFAULT_MAXSEPACUTSROOT
Definition: cons_knapsack.c:83
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 SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:34661
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:6360
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:47051
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:9092
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
public data structures and miscellaneous methods
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17586
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:99
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:91
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:55
#define DEFAULT_MAXSEPACUTS
Definition: cons_knapsack.c:82
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:30402
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
#define DEFAULT_MAXCARDBOUNDDIST
Definition: cons_knapsack.c:84
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:43045
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17554
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:29091
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:24559
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8006
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11353
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3365
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:30431
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8115
#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:75
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8185
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8155
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17124
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:73
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41272
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:63
#define CONSHDLR_NAME
Definition: cons_knapsack.c:44
#define SCIPcombineFourInt(a, b, c, d)
Definition: pub_misc.h:483
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:25575
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:56
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:16517
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21714
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:6498
#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:12040
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2326
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17044
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:47039
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)
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17600
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:286
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35836
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11812
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip.c:13519
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17571
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6229
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:30540
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
#define SCIPfreeBuffer(scip, ptr)
Definition: scip.h:22630
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_DECL_CONSLOCK(consLockKnapsack)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:47112
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8016
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6109
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:27909
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6133
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip.c:1870
constraint handler for cardinality constraints
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27761
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:25885
#define DEFAULT_DETECTLOWERBOUND
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6253
#define HASHSIZE_KNAPSACKCONS
Definition: cons_knapsack.c:95
enum GUBConsstatus GUBCONSSTATUS
int SCIPgetNCliques(SCIP *scip)
Definition: scip.c:24879
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:72
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47375
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:11767
SCIP_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2971
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16781
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip.c:24779
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18732
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:149
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8235
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1145
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11688
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6567
#define GUBCONSGROWVALUE
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8175
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:64
#define SCIP_INVALID
Definition: def.h:169
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8165
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:31160
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17522
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
Definition: cons_knapsack.c:81
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:50
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:57
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
Definition: scip.c:46499
#define SCIP_Longint
Definition: def.h:134
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:8881
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16959
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:47076
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46989
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:17342
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:22605
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3343
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:47399
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16804
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)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
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:92
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:419
#define NMINCOMPARISONS
Definition: cons_knapsack.c:98
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:6181
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:322
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip.c:17735
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8448
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38911
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:16883
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:4321
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:23039
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:47149
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:48
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:57
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip.c:19045
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:4239
int SCIPgetNSepaRounds(SCIP *scip)
Definition: scip.c:42884
#define DEFAULT_SIMPLIFYINEQUALITIES
Definition: cons_knapsack.c:88
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16949
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:16817
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:22624
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5994
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:27859
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)