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-2020 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 visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_knapsack.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
19  * @author Tobias Achterberg
20  * @author Xin Liu
21  * @author Kati Wolter
22  * @author Michael Winkler
23  * @author Tobias Fischer
24  */
25 
26 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
27 
28 #include "blockmemshell/memory.h"
29 #include "scip/cons_knapsack.h"
30 #include "scip/cons_linear.h"
31 #include "scip/cons_logicor.h"
32 #include "scip/cons_setppc.h"
33 #include "scip/pub_cons.h"
34 #include "scip/pub_event.h"
35 #include "scip/pub_implics.h"
36 #include "scip/pub_lp.h"
37 #include "scip/pub_message.h"
38 #include "scip/pub_misc.h"
39 #include "scip/pub_misc_select.h"
40 #include "scip/pub_misc_sort.h"
41 #include "scip/pub_sepa.h"
42 #include "scip/pub_var.h"
43 #include "scip/scip_branch.h"
44 #include "scip/scip_conflict.h"
45 #include "scip/scip_cons.h"
46 #include "scip/scip_copy.h"
47 #include "scip/scip_cut.h"
48 #include "scip/scip_event.h"
49 #include "scip/scip_general.h"
50 #include "scip/scip_lp.h"
51 #include "scip/scip_mem.h"
52 #include "scip/scip_message.h"
53 #include "scip/scip_numerics.h"
54 #include "scip/scip_param.h"
55 #include "scip/scip_prob.h"
56 #include "scip/scip_probing.h"
57 #include "scip/scip_sol.h"
58 #include "scip/scip_solvingstats.h"
59 #include "scip/scip_tree.h"
60 #include "scip/scip_var.h"
61 #include <ctype.h>
62 #include <string.h>
63 
64 #ifdef WITH_CARDINALITY_UPGRADE
65 #include "scip/cons_cardinality.h"
66 #endif
67 
68 /* constraint handler properties */
69 #define CONSHDLR_NAME "knapsack"
70 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
71 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
72 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
73 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
74 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
75 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
76 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
77  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
78 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
79 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
80 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
81 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
82 
83 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
84 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
85 
86 #define EVENTHDLR_NAME "knapsack"
87 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
88 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
89  | SCIP_EVENTTYPE_UBTIGHTENED \
90  | SCIP_EVENTTYPE_VARFIXED \
91  | SCIP_EVENTTYPE_VARDELETED \
92  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
93 
94 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
95 
96 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
97 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
98 
99 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
100 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
101 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
103 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
104 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
105 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
106 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
107 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
108 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
109  * to best node's dual bound for separating knapsack cuts */
110 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
111 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
112 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
114 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
115 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
117 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
118 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
120 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
121 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
122 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
123  * comparison round */
124 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
125 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
126  * function defining an upper bound and prevent these constraints from
127  * entering the LP */
128 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
129  * function defining a lower bound and prevent these constraints from
130  * entering the LP */
131 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
132 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
134 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
135 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
136 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
137 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
138  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
139 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
140 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
141 #ifdef WITH_CARDINALITY_UPGRADE
142 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
143 #endif
145 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
146 
147 /*
148  * Data structures
149  */
150 
151 /** constraint handler data */
152 struct SCIP_ConshdlrData
153 {
154  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
155  * you have to clear it at the end, exists only in presolving stage */
156  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
157  * you have to clear it at the end, exists only in presolving stage */
158  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
159  * you have to clear it at the end, exists only in presolving stage */
160  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
161  * you have to clear it at the end, exists only in presolving stage */
162  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
163  * you have to clear it at the end, exists only in presolving stage */
164  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
165  * you have to clear it at the end, exists only in presolving stage */
166  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167  * you have to clear it at the end, exists only in presolving stage */
168  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169  * you have to clear it at the end, exists only in presolving stage */
170  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
171  * you have to clear it at the end */
172  int ints1size; /**< size of ints1 array */
173  int ints2size; /**< size of ints2 array */
174  int longints1size; /**< size of longints1 array */
175  int longints2size; /**< size of longints2 array */
176  int bools1size; /**< size of bools1 array */
177  int bools2size; /**< size of bools2 array */
178  int bools3size; /**< size of bools3 array */
179  int bools4size; /**< size of bools4 array */
180  int reals1size; /**< size of reals1 array */
181  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
182  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
183  * to best node's dual bound for separating knapsack cuts */
184  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
185  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
186  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
187  int maxsepacuts; /**< maximal number of cuts separated per separation round */
188  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
189  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
190  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
191  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
192  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
193  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
194  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
195  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
196  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
197  * function defining an upper bound and prevent these constraints from
198  * entering the LP */
199  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
200  * function defining a lower bound and prevent these constraints from
201  * entering the LP */
202  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
203  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
204  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
205  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
206 #ifdef WITH_CARDINALITY_UPGRADE
207  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
208  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
209 #endif
210 };
211 
212 
213 /** constraint data for knapsack constraints */
214 struct SCIP_ConsData
215 {
216  SCIP_VAR** vars; /**< variables in knapsack constraint */
217  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
218  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
219  int* cliquepartition; /**< clique indices of the clique partition */
220  int* negcliquepartition; /**< clique indices of the negated clique partition */
221  SCIP_ROW* row; /**< corresponding LP row */
222  int nvars; /**< number of variables in knapsack constraint */
223  int varssize; /**< size of vars, weights, and eventdata arrays */
224  int ncliques; /**< number of cliques in the clique partition */
225  int nnegcliques; /**< number of cliques in the negated clique partition */
226  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
227  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
228  SCIP_Longint capacity; /**< capacity of knapsack */
229  SCIP_Longint weightsum; /**< sum of all weights */
230  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
231  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
232  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
233  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
234  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
235  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
236  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
237  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
238  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
239 };
240 
241 /** event data for bound changes events */
242 struct SCIP_EventData
243 {
244  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
245  SCIP_Longint weight; /**< weight of variable */
246  int filterpos; /**< position of event in variable's event filter */
247 };
248 
249 
250 /** data structure to combine two sorting key values */
251 struct sortkeypair
252 {
253  SCIP_Real key1; /**< first sort key value */
254  SCIP_Real key2; /**< second sort key value */
255 };
256 typedef struct sortkeypair SORTKEYPAIR;
257 
258 /** status of GUB constraint */
259 enum GUBVarstatus
260 {
261  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
262  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
263  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
264  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
265  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
266  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
267 };
268 typedef enum GUBVarstatus GUBVARSTATUS;
270 /** status of variable in GUB constraint */
272 {
273  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
274  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
275  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
276  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
277  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
278  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
279 };
280 typedef enum GUBConsstatus GUBCONSSTATUS;
282 /** data structure of GUB constraints */
284 {
285  int* gubvars; /**< indices of GUB variables in knapsack constraint */
286  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
287  int ngubvars; /**< number of GUB variables */
288  int gubvarssize; /**< size of gubvars array */
289 };
290 typedef struct SCIP_GUBCons SCIP_GUBCONS;
292 /** data structure of a set of GUB constraints */
294 {
295  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
296  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
297  int ngubconss; /**< number of GUB constraints */
298  int nvars; /**< number of variables in knapsack constraint */
299  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
300  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
301 };
302 typedef struct SCIP_GUBSet SCIP_GUBSET;
304 /*
305  * Local methods
306  */
308 /** comparison method for two sorting key pairs */
309 static
310 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
311 {
312  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
313  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
314 
315  if( sortkeypair1->key1 < sortkeypair2->key1 )
316  return -1;
317  else if( sortkeypair1->key1 > sortkeypair2->key1 )
318  return +1;
319  else if( sortkeypair1->key2 < sortkeypair2->key2 )
320  return -1;
321  else if( sortkeypair1->key2 > sortkeypair2->key2 )
322  return +1;
323  else
324  return 0;
325 }
326 
327 /** creates event data */
328 static
330  SCIP* scip, /**< SCIP data structure */
331  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
332  SCIP_CONS* cons, /**< constraint */
333  SCIP_Longint weight /**< weight of variable */
334  )
335 {
336  assert(eventdata != NULL);
338  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
339  (*eventdata)->cons = cons;
340  (*eventdata)->weight = weight;
341 
342  return SCIP_OKAY;
343 }
344 
345 /** frees event data */
346 static
348  SCIP* scip, /**< SCIP data structure */
349  SCIP_EVENTDATA** eventdata /**< pointer to event data */
350  )
351 {
352  assert(eventdata != NULL);
353 
354  SCIPfreeBlockMemory(scip, eventdata);
356  return SCIP_OKAY;
357 }
358 
359 /** sorts items in knapsack with nonincreasing weights */
360 static
361 void sortItems(
362  SCIP_CONSDATA* consdata /**< constraint data */
363  )
364 {
365  assert(consdata != NULL);
366  assert(consdata->nvars == 0 || consdata->vars != NULL);
367  assert(consdata->nvars == 0 || consdata->weights != NULL);
368  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
369  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
370 
371  if( !consdata->sorted )
372  {
373  int pos;
374  int lastcliquenum;
375  int v;
376 
377  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
378  * sorted by first array in non-increasing order via sort template */
380  consdata->weights,
381  (void**)consdata->vars,
382  (void**)consdata->eventdata,
383  consdata->cliquepartition,
384  consdata->negcliquepartition,
385  consdata->nvars);
386 
387  v = consdata->nvars - 1;
388  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
389  while( v >= 0 )
390  {
391  int w = v - 1;
392 
393  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
394  --w;
395 
396  if( v - w > 1 )
397  {
398  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
400  (void**)(&(consdata->vars[w+1])),
401  (void**)(&(consdata->eventdata[w+1])),
402  &(consdata->cliquepartition[w+1]),
403  &(consdata->negcliquepartition[w+1]),
404  SCIPvarComp,
405  v - w);
406  }
407  v = w;
408  }
409 
410  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
411  if( consdata->cliquepartitioned )
412  {
413  lastcliquenum = 0;
414 
415  for( pos = 0; pos < consdata->nvars; ++pos )
416  {
417  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
418  * partition is invalid */
419  if( consdata->cliquepartition[pos] > lastcliquenum )
420  {
421  consdata->cliquepartitioned = FALSE;
422  break;
423  }
424  else if( consdata->cliquepartition[pos] == lastcliquenum )
425  ++lastcliquenum;
426  }
427  }
428  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
429  if( consdata->negcliquepartitioned )
430  {
431  lastcliquenum = 0;
432 
433  for( pos = 0; pos < consdata->nvars; ++pos )
434  {
435  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
436  * partition is invalid */
437  if( consdata->negcliquepartition[pos] > lastcliquenum )
438  {
439  consdata->negcliquepartitioned = FALSE;
440  break;
441  }
442  else if( consdata->negcliquepartition[pos] == lastcliquenum )
443  ++lastcliquenum;
444  }
445  }
446 
447  consdata->sorted = TRUE;
448  }
449 #ifndef NDEBUG
450  {
451  /* check if the weight array is sorted in a non-increasing way */
452  int i;
453  for( i = 0; i < consdata->nvars-1; ++i )
454  assert(consdata->weights[i] >= consdata->weights[i+1]);
455  }
456 #endif
457 }
458 
459 /** calculates a partition of the variables into cliques */
460 static
462  SCIP* scip, /**< SCIP data structure */
463  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
464  SCIP_CONSDATA* consdata, /**< constraint data */
465  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
466  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
467  )
468 {
469  SCIP_Bool ispartitionoutdated;
470  SCIP_Bool isnegpartitionoutdated;
471  assert(consdata != NULL);
472  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
473 
474  /* rerun eventually if number of global cliques increased considerably since last partition */
475  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
476  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
477 
478  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
479  {
480  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
481  consdata->cliquepartitioned = TRUE;
482  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
483  }
484 
485  /* rerun eventually if number of global cliques increased considerably since last negated partition */
486  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
487  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
488 
489  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
490  {
491  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
492  consdata->negcliquepartitioned = TRUE;
493  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
494  }
495  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
496  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
497 
498  return SCIP_OKAY;
499 }
500 
501 /** installs rounding locks for the given variable in the given knapsack constraint */
502 static
504  SCIP* scip, /**< SCIP data structure */
505  SCIP_CONS* cons, /**< knapsack constraint */
506  SCIP_VAR* var /**< variable of constraint entry */
507  )
508 {
509  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
510 
511  return SCIP_OKAY;
512 }
513 
514 /** removes rounding locks for the given variable in the given knapsack constraint */
515 static
517  SCIP* scip, /**< SCIP data structure */
518  SCIP_CONS* cons, /**< knapsack constraint */
519  SCIP_VAR* var /**< variable of constraint entry */
520  )
521 {
522  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
523 
524  return SCIP_OKAY;
525 }
526 
527 /** catches bound change events for variables in knapsack */
528 static
530  SCIP* scip, /**< SCIP data structure */
531  SCIP_CONS* cons, /**< constraint */
532  SCIP_CONSDATA* consdata, /**< constraint data */
533  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
534  )
535 {
536  int i;
538  assert(cons != NULL);
539  assert(consdata != NULL);
540  assert(consdata->nvars == 0 || consdata->vars != NULL);
541  assert(consdata->nvars == 0 || consdata->weights != NULL);
542  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
543 
544  for( i = 0; i < consdata->nvars; i++)
545  {
546  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
547  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
548  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
549  }
550 
551  return SCIP_OKAY;
552 }
553 
554 /** drops bound change events for variables in knapsack */
555 static
557  SCIP* scip, /**< SCIP data structure */
558  SCIP_CONSDATA* consdata, /**< constraint data */
559  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
560  )
561 {
562  int i;
563 
564  assert(consdata != NULL);
565  assert(consdata->nvars == 0 || consdata->vars != NULL);
566  assert(consdata->nvars == 0 || consdata->weights != NULL);
567  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
568 
569  for( i = 0; i < consdata->nvars; i++)
570  {
571  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
572  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
573  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
574  }
575 
576  return SCIP_OKAY;
577 }
578 
579 /** ensures, that vars and vals arrays can store at least num entries */
580 static
582  SCIP* scip, /**< SCIP data structure */
583  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
584  int num, /**< minimum number of entries to store */
585  SCIP_Bool transformed /**< is constraint from transformed problem? */
586  )
587 {
588  assert(consdata != NULL);
589  assert(consdata->nvars <= consdata->varssize);
590 
591  if( num > consdata->varssize )
592  {
593  int newsize;
594 
595  newsize = SCIPcalcMemGrowSize(scip, num);
596  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
597  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
598  if( transformed )
599  {
600  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
601  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
602  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
603  }
604  else
605  {
606  assert(consdata->eventdata == NULL);
607  assert(consdata->cliquepartition == NULL);
608  assert(consdata->negcliquepartition == NULL);
609  }
610  consdata->varssize = newsize;
611  }
612  assert(num <= consdata->varssize);
613 
614  return SCIP_OKAY;
615 }
616 
617 /** updates all weight sums for fixed and unfixed variables */
618 static
619 void updateWeightSums(
620  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
621  SCIP_VAR* var, /**< variable for this weight */
622  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
623  )
624 {
625  assert(consdata != NULL);
626  assert(var != NULL);
628  consdata->weightsum += weightdelta;
629 
630  if( SCIPvarGetLbLocal(var) > 0.5 )
631  consdata->onesweightsum += weightdelta;
632 
633  assert(consdata->weightsum >= 0);
634  assert(consdata->onesweightsum >= 0);
635 }
636 
637 /** creates knapsack constraint data */
638 static
640  SCIP* scip, /**< SCIP data structure */
641  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
642  int nvars, /**< number of variables in knapsack */
643  SCIP_VAR** vars, /**< variables of knapsack */
644  SCIP_Longint* weights, /**< weights of knapsack items */
645  SCIP_Longint capacity /**< capacity of knapsack */
646  )
647 {
648  int v;
649  SCIP_Longint constant;
650 
651  assert(consdata != NULL);
652 
653  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
654 
655  constant = 0L;
656  (*consdata)->vars = NULL;
657  (*consdata)->weights = NULL;
658  (*consdata)->nvars = 0;
659  if( nvars > 0 )
660  {
661  SCIP_VAR** varsbuffer;
662  SCIP_Longint* weightsbuffer;
663  int k;
664 
665  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
666  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
667 
668  k = 0;
669  for( v = 0; v < nvars; ++v )
670  {
671  assert(vars[v] != NULL);
672  assert(SCIPvarIsBinary(vars[v]));
673 
674  /* all weight have to be non negative */
675  assert( weights[v] >= 0 );
676 
677  if( weights[v] > 0 )
678  {
679  /* treat fixed variables as constants if problem compression is enabled */
680  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
681  {
682  /* only if the variable is fixed to 1, we add its weight to the constant */
683  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
684  constant += weights[v];
685  }
686  else
687  {
688  varsbuffer[k] = vars[v];
689  weightsbuffer[k] = weights[v];
690  ++k;
691  }
692  }
693  }
694  assert(k >= 0);
695 
696  (*consdata)->nvars = k;
697 
698  /* copy the active variables and weights into the constraint data structure */
699  if( k > 0 )
700  {
701  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
702  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
703  }
704 
705  /* free buffer storage */
706  SCIPfreeBufferArray(scip, &weightsbuffer);
707  SCIPfreeBufferArray(scip, &varsbuffer);
708  }
709 
710  /* capacity has to be greater or equal to zero */
711  assert(capacity >= 0);
712  assert(constant >= 0);
713 
714  (*consdata)->varssize = (*consdata)->nvars;
715  (*consdata)->capacity = capacity - constant;
716  (*consdata)->eventdata = NULL;
717  (*consdata)->cliquepartition = NULL;
718  (*consdata)->negcliquepartition = NULL;
719  (*consdata)->row = NULL;
720  (*consdata)->weightsum = 0;
721  (*consdata)->onesweightsum = 0;
722  (*consdata)->ncliques = 0;
723  (*consdata)->nnegcliques = 0;
724  (*consdata)->presolvedtiming = 0;
725  (*consdata)->sorted = FALSE;
726  (*consdata)->cliquepartitioned = FALSE;
727  (*consdata)->negcliquepartitioned = FALSE;
728  (*consdata)->ncliqueslastpart = -1;
729  (*consdata)->ncliqueslastnegpart = -1;
730  (*consdata)->merged = FALSE;
731  (*consdata)->cliquesadded = FALSE;
732  (*consdata)->varsdeleted = FALSE;
733  (*consdata)->existmultaggr = FALSE;
734 
735  /* get transformed variables, if we are in the transformed problem */
736  if( SCIPisTransformed(scip) )
737  {
738  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
739 
740  for( v = 0; v < (*consdata)->nvars; v++ )
741  {
742  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
743  assert(var != NULL);
744  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
745  }
746 
747  /* allocate memory for additional data structures */
748  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
749  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
750  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
751  }
752 
753  /* calculate sum of weights and capture variables */
754  for( v = 0; v < (*consdata)->nvars; ++v )
755  {
756  /* calculate sum of weights */
757  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
758 
759  /* capture variables */
760  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
761  }
762  return SCIP_OKAY;
763 }
764 
765 /** frees knapsack constraint data */
766 static
768  SCIP* scip, /**< SCIP data structure */
769  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
770  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
771  )
772 {
773  assert(consdata != NULL);
774  assert(*consdata != NULL);
776  if( (*consdata)->row != NULL )
777  {
778  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
779  }
780  if( (*consdata)->eventdata != NULL )
781  {
782  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
783  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
784  }
785  if( (*consdata)->negcliquepartition != NULL )
786  {
787  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
788  }
789  if( (*consdata)->cliquepartition != NULL )
790  {
791  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
792  }
793  if( (*consdata)->vars != NULL )
794  {
795  int v;
796 
797  /* release variables */
798  for( v = 0; v < (*consdata)->nvars; v++ )
799  {
800  assert((*consdata)->vars[v] != NULL);
801  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
802  }
803 
804  assert( (*consdata)->weights != NULL );
805  assert( (*consdata)->varssize > 0 );
806  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
807  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
808  }
809 
810  SCIPfreeBlockMemory(scip, consdata);
811 
812  return SCIP_OKAY;
813 }
814 
815 /** changes a single weight in knapsack constraint data */
816 static
817 void consdataChgWeight(
818  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
819  int item, /**< item number */
820  SCIP_Longint newweight /**< new weight of item */
821  )
822 {
823  SCIP_Longint oldweight;
824  SCIP_Longint weightdiff;
826  assert(consdata != NULL);
827  assert(0 <= item && item < consdata->nvars);
828 
829  oldweight = consdata->weights[item];
830  weightdiff = newweight - oldweight;
831  consdata->weights[item] = newweight;
832 
833  /* update weight sums for all and fixed variables */
834  updateWeightSums(consdata, consdata->vars[item], weightdiff);
835 
836  if( consdata->eventdata != NULL )
837  {
838  assert(consdata->eventdata[item] != NULL);
839  assert(consdata->eventdata[item]->weight == oldweight);
840  consdata->eventdata[item]->weight = newweight;
841  }
842 
843  consdata->presolvedtiming = 0;
844  consdata->sorted = FALSE;
845 
846  /* recalculate cliques extraction after a weight was increased */
847  if( oldweight < newweight )
848  {
849  consdata->cliquesadded = FALSE;
850  }
851 }
852 
853 /** creates LP row corresponding to knapsack constraint */
854 static
856  SCIP* scip, /**< SCIP data structure */
857  SCIP_CONS* cons /**< knapsack constraint */
858  )
859 {
860  SCIP_CONSDATA* consdata;
861  int i;
862 
863  consdata = SCIPconsGetData(cons);
864  assert(consdata != NULL);
865  assert(consdata->row == NULL);
866 
867  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
868  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
870 
871  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
872  for( i = 0; i < consdata->nvars; ++i )
873  {
874  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
875  }
876  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
877 
878  return SCIP_OKAY;
879 }
880 
881 /** adds linear relaxation of knapsack constraint to the LP */
882 static
884  SCIP* scip, /**< SCIP data structure */
885  SCIP_CONS* cons, /**< knapsack constraint */
886  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
887  )
888 {
889  SCIP_CONSDATA* consdata;
890 
891  assert( cutoff != NULL );
892  *cutoff = FALSE;
893 
894  consdata = SCIPconsGetData(cons);
895  assert(consdata != NULL);
896 
897  if( consdata->row == NULL )
898  {
899  SCIP_CALL( createRelaxation(scip, cons) );
900  }
901  assert(consdata->row != NULL);
902 
903  /* insert LP row as cut */
904  if( !SCIProwIsInLP(consdata->row) )
905  {
906  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
907  SCIPconsGetName(cons), consdata->capacity);
908  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
909  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
910  }
911 
912  return SCIP_OKAY;
913 }
914 
915 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
916 static
918  SCIP* scip, /**< SCIP data structure */
919  SCIP_CONS* cons, /**< constraint to check */
920  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
921  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
922  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
923  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
924  )
925 {
926  SCIP_CONSDATA* consdata;
927 
928  assert(violated != NULL);
929 
930  consdata = SCIPconsGetData(cons);
931  assert(consdata != NULL);
932 
933  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
934  SCIPconsGetName(cons), (void*)sol, checklprows);
935 
936  *violated = FALSE;
937 
938  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
939  {
940  SCIP_Real sum;
941  SCIP_Longint integralsum;
942  SCIP_Bool ishuge;
943  SCIP_Real absviol;
944  SCIP_Real relviol;
945  int v;
946 
947  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
948  * enforcement
949  */
950  if( sol == NULL )
951  {
952  SCIP_CALL( SCIPincConsAge(scip, cons) );
953  }
954 
955  sum = 0.0;
956  integralsum = 0;
957  /* we perform a more exact comparison if the capacity does not exceed the huge value */
958  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
959  {
960  ishuge = TRUE;
961 
962  /* sum over all weight times the corresponding solution value */
963  for( v = consdata->nvars - 1; v >= 0; --v )
964  {
965  assert(SCIPvarIsBinary(consdata->vars[v]));
966  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
967  }
968  }
969  else
970  {
971  ishuge = FALSE;
972 
973  /* sum over all weight for which the variable has a solution value of 1 in feastol */
974  for( v = consdata->nvars - 1; v >= 0; --v )
975  {
976  assert(SCIPvarIsBinary(consdata->vars[v]));
977 
978  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
979  integralsum += consdata->weights[v];
980  }
981  }
982 
983  /* calculate constraint violation and update it in solution */
984  absviol = ishuge ? sum : (SCIP_Real)integralsum;
985  absviol -= consdata->capacity;
986  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
987  if( sol != NULL )
988  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
989 
990  if( SCIPisFeasPositive(scip, absviol) )
991  {
992  *violated = TRUE;
993 
994  /* only reset constraint age if we are in enforcement */
995  if( sol == NULL )
996  {
997  SCIP_CALL( SCIPresetConsAge(scip, cons) );
998  }
999 
1000  if( printreason )
1001  {
1002  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1003 
1004  SCIPinfoMessage(scip, NULL, ";\n");
1005  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1006  }
1007  }
1008  }
1009 
1010  return SCIP_OKAY;
1011 }
1012 
1013 /* IDX computes the integer index for the optimal solution array */
1014 #define IDX(j,d) ((j)*(intcap)+(d))
1015 
1016 /** solves knapsack problem in maximization form exactly using dynamic programming;
1017  * if needed, one can provide arrays to store all selected items and all not selected items
1018  *
1019  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1020  *
1021  * @note the algorithm will first compute a greedy solution and terminate
1022  * if the greedy solution is proven to be optimal.
1023  * The dynamic programming algorithm runs with a time and space complexity
1024  * of O(nitems * capacity).
1025  *
1026  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1027  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1028  * to be checked whether they are faster and whether they can reconstruct the solution.
1029  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1030  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1031  * This could be implemented, however, it would be technically a bit cumbersome,
1032  * since one needs the greedy solution and the LP-value for this.
1033  * This is currently only available after the redundant items have already been sorted out.
1034  */
1036  SCIP* scip, /**< SCIP data structure */
1037  int nitems, /**< number of available items */
1038  SCIP_Longint* weights, /**< item weights */
1039  SCIP_Real* profits, /**< item profits */
1040  SCIP_Longint capacity, /**< capacity of knapsack */
1041  int* items, /**< item numbers */
1042  int* solitems, /**< array to store items in solution, or NULL */
1043  int* nonsolitems, /**< array to store items not in solution, or NULL */
1044  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1045  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1046  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1047  SCIP_Bool* success /**< pointer to store if an error occured during solving
1048  * (normally a memory problem) */
1049  )
1050 {
1051  SCIP_RETCODE retcode;
1052  SCIP_Real* tempsort;
1053  SCIP_Real* optvalues;
1054  int intcap;
1055  int d;
1056  int j;
1057  int greedymedianpos;
1058  SCIP_Longint weightsum;
1059  int* myitems;
1060  SCIP_Longint* myweights;
1061  SCIP_Real* realweights;
1062  int* allcurrminweight;
1063  SCIP_Real* myprofits;
1064  int nmyitems;
1065  SCIP_Longint gcd;
1066  SCIP_Longint minweight;
1067  SCIP_Longint maxweight;
1068  int currminweight;
1069  SCIP_Longint greedysolweight;
1070  SCIP_Real greedysolvalue;
1071  SCIP_Real greedyupperbound;
1072  SCIP_Bool eqweights;
1073  SCIP_Bool intprofits;
1074 
1075  assert(weights != NULL);
1076  assert(profits != NULL);
1077  assert(capacity >= 0);
1078  assert(items != NULL);
1079  assert(nitems >= 0);
1080  assert(success != NULL);
1081 
1082  *success = TRUE;
1083 
1084 #ifndef NDEBUG
1085  for( j = nitems - 1; j >= 0; --j )
1086  assert(weights[j] >= 0);
1087 #endif
1088 
1089  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1090 
1091  /* initializing solution value */
1092  if( solval != NULL )
1093  *solval = 0.0;
1094 
1095  /* init solution information */
1096  if( solitems != NULL )
1097  {
1098  assert(items != NULL);
1099  assert(nsolitems != NULL);
1100  assert(nonsolitems != NULL);
1101  assert(nnonsolitems != NULL);
1102 
1103  *nnonsolitems = 0;
1104  *nsolitems = 0;
1105  }
1106 
1107  /* allocate temporary memory */
1108  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1109  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1110  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1111  nmyitems = 0;
1112  weightsum = 0;
1113  minweight = SCIP_LONGINT_MAX;
1114  maxweight = 0;
1115 
1116  /* remove unnecessary items */
1117  for( j = 0; j < nitems; ++j )
1118  {
1119  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1120 
1121  /* item does not fit */
1122  if( weights[j] > capacity )
1123  {
1124  if( solitems != NULL )
1125  nonsolitems[(*nnonsolitems)++] = items[j];
1126  }
1127  /* item is not profitable */
1128  else if( profits[j] <= 0.0 )
1129  {
1130  if( solitems != NULL )
1131  nonsolitems[(*nnonsolitems)++] = items[j];
1132  }
1133  /* item always fits */
1134  else if( weights[j] == 0 )
1135  {
1136  if( solitems != NULL )
1137  solitems[(*nsolitems)++] = items[j];
1138 
1139  if( solval != NULL )
1140  *solval += profits[j];
1141  }
1142  /* all important items */
1143  else
1144  {
1145  myweights[nmyitems] = weights[j];
1146  myprofits[nmyitems] = profits[j];
1147  myitems[nmyitems] = items[j];
1148 
1149  /* remember smallest item */
1150  if( myweights[nmyitems] < minweight )
1151  minweight = myweights[nmyitems];
1152 
1153  /* remember bigest item */
1154  if( myweights[nmyitems] > maxweight )
1155  maxweight = myweights[nmyitems];
1156 
1157  weightsum += myweights[nmyitems];
1158  ++nmyitems;
1159  }
1160  }
1161 
1162  intprofits = TRUE;
1163  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1164  for( j = 0; j < nmyitems && intprofits; ++j )
1165  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1166 
1167  /* if no item is left then goto end */
1168  if( nmyitems == 0 )
1169  {
1170  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1171 
1172  goto TERMINATE;
1173  }
1174 
1175  /* if all items fit, we also do not need to do the expensive stuff later on */
1176  if( weightsum > 0 && weightsum <= capacity )
1177  {
1178  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1179 
1180  for( j = nmyitems - 1; j >= 0; --j )
1181  {
1182  if( solitems != NULL )
1183  solitems[(*nsolitems)++] = myitems[j];
1184 
1185  if( solval != NULL )
1186  *solval += myprofits[j];
1187  }
1188 
1189  goto TERMINATE;
1190  }
1191 
1192  assert(0 < minweight && minweight <= capacity );
1193  assert(0 < maxweight && maxweight <= capacity);
1194 
1195  /* make weights relatively prime */
1196  eqweights = TRUE;
1197  if( maxweight > 1 )
1198  {
1199  /* determine greatest common divisor */
1200  gcd = myweights[nmyitems - 1];
1201  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1202  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1203 
1204  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1205 
1206  /* divide by greatest common divisor */
1207  if( gcd > 1 )
1208  {
1209  for( j = nmyitems - 1; j >= 0; --j )
1210  {
1211  myweights[j] /= gcd;
1212  eqweights = eqweights && (myweights[j] == 1);
1213  }
1214  capacity /= gcd;
1215  minweight /= gcd;
1216  }
1217  else
1218  eqweights = FALSE;
1219  }
1220  assert(minweight <= capacity);
1221 
1222  /* if only one item fits, then take the best */
1223  if( minweight > capacity / 2 )
1224  {
1225  int p;
1226 
1227  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1228 
1229  p = nmyitems - 1;
1230 
1231  /* find best item */
1232  for( j = nmyitems - 2; j >= 0; --j )
1233  {
1234  if( myprofits[j] > myprofits[p] )
1235  p = j;
1236  }
1237 
1238  /* update solution information */
1239  if( solitems != NULL )
1240  {
1241  solitems[(*nsolitems)++] = myitems[p];
1242  for( j = nmyitems - 1; j >= 0; --j )
1243  {
1244  if( j != p )
1245  nonsolitems[(*nnonsolitems)++] = myitems[j];
1246  }
1247  }
1248  /* update solution value */
1249  if( solval != NULL )
1250  *solval += myprofits[p];
1251 
1252  goto TERMINATE;
1253  }
1254 
1255  /* if all items have the same weight, then take the best */
1256  if( eqweights )
1257  {
1258  SCIP_Real addval = 0.0;
1259 
1260  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1261 
1262  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1263 
1264  /* update solution information */
1265  if( solitems != NULL || solval != NULL )
1266  {
1267  SCIP_Longint i;
1268 
1269  /* if all items would fit we had handled this case before */
1270  assert((SCIP_Longint) nmyitems > capacity);
1271 
1272  /* take the first best items into the solution */
1273  for( i = capacity - 1; i >= 0; --i )
1274  {
1275  if( solitems != NULL )
1276  solitems[(*nsolitems)++] = myitems[i];
1277  addval += myprofits[i];
1278  }
1279 
1280  if( solitems != NULL )
1281  {
1282  /* the rest are not in the solution */
1283  for( i = nmyitems - 1; i >= capacity; --i )
1284  nonsolitems[(*nnonsolitems)++] = myitems[i];
1285  }
1286  }
1287  /* update solution value */
1288  if( solval != NULL )
1289  {
1290  assert(addval > 0.0);
1291  *solval += addval;
1292  }
1293 
1294  goto TERMINATE;
1295  }
1296 
1297  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1298 
1299  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1300  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1301  */
1302  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1303  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1304 
1305  for( j = 0; j < nmyitems; ++j )
1306  {
1307  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1308  realweights[j] = (SCIP_Real)myweights[j];
1309  }
1310 
1311  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1312  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1313 
1314  SCIPfreeBufferArray(scip, &realweights);
1315  SCIPfreeBufferArray(scip, &tempsort);
1316 
1317  /* initialize values for greedy solution information */
1318  greedysolweight = 0;
1319  greedysolvalue = 0.0;
1320 
1321  /* determine greedy solution */
1322  for( j = 0; j < greedymedianpos; ++j )
1323  {
1324  assert(myweights[j] <= capacity);
1325 
1326  /* update greedy solution weight and value */
1327  greedysolweight += myweights[j];
1328  greedysolvalue += myprofits[j];
1329  }
1330 
1331  assert(0 < greedysolweight && greedysolweight <= capacity);
1332  assert(greedysolvalue > 0.0);
1333 
1334  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1335  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1336  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1337  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1338  if( intprofits )
1339  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1340  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1341  {
1342  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1343 
1344  /* update solution information */
1345  if( solitems != NULL )
1346  {
1347  int l;
1348 
1349  /* collect items */
1350  for( l = 0; l < j; ++l )
1351  solitems[(*nsolitems)++] = myitems[l];
1352  for ( ; l < nmyitems; ++l )
1353  nonsolitems[(*nnonsolitems)++] = myitems[l];
1354  }
1355  /* update solution value */
1356  if( solval != NULL )
1357  {
1358  assert(greedysolvalue > 0.0);
1359  *solval += greedysolvalue;
1360  }
1361 
1362  goto TERMINATE;
1363  }
1364 
1365  /* in the following table we do not need the first minweight columns */
1366  capacity -= (minweight - 1);
1367 
1368  /* we can only handle integers */
1369  if( capacity >= INT_MAX )
1370  {
1371  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1372 
1373  *success = FALSE;
1374  goto TERMINATE;
1375  }
1376  assert(capacity < INT_MAX);
1377 
1378  intcap = (int)capacity;
1379  assert(intcap >= 0);
1380  assert(nmyitems > 0);
1381  assert(sizeof(size_t) >= sizeof(int)); /* no following conversion should be messed up */
1382 
1383  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1384  * computing the size for the allocation
1385  */
1386  if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1387  {
1388  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1389 
1390  *success = FALSE;
1391  goto TERMINATE;
1392  }
1393 
1394  /* allocate temporary memory and check for memory exceedance */
1395  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1396  if( retcode == SCIP_NOMEMORY )
1397  {
1398  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1399 
1400  *success = FALSE;
1401  goto TERMINATE;
1402  }
1403  else
1404  {
1405  SCIP_CALL( retcode );
1406  }
1407 
1408  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1409 
1410  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1411  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1412  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1413  * 'nmyitem' values
1414  */
1415  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1416  assert(myweights[0] - minweight < INT_MAX);
1417  currminweight = (int) (myweights[0] - minweight);
1418  allcurrminweight[0] = currminweight;
1419 
1420  /* fills first row of dynamic programming table with optimal values */
1421  for( d = currminweight; d < intcap; ++d )
1422  optvalues[d] = myprofits[0];
1423 
1424  /* fills dynamic programming table with optimal values */
1425  for( j = 1; j < nmyitems; ++j )
1426  {
1427  int intweight;
1428 
1429  /* compute important part of weight, which will be represented in the table */
1430  intweight = (int)(myweights[j] - minweight);
1431  assert(0 <= intweight && intweight < intcap);
1432 
1433  /* copy all nonzeros from row above */
1434  for( d = currminweight; d < intweight && d < intcap; ++d )
1435  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1436 
1437  /* update corresponding row */
1438  for( d = intweight; d < intcap; ++d )
1439  {
1440  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1441  if( d < currminweight )
1442  optvalues[IDX(j,d)] = myprofits[j];
1443  else
1444  {
1445  SCIP_Real sumprofit;
1446 
1447  if( d - myweights[j] < currminweight )
1448  sumprofit = myprofits[j];
1449  else
1450  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1451 
1452  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1453  }
1454  }
1455 
1456  /* update currminweight */
1457  if( intweight < currminweight )
1458  currminweight = intweight;
1459 
1460  allcurrminweight[j] = currminweight;
1461  }
1462 
1463  /* update optimal solution by following the table */
1464  if( solitems != NULL )
1465  {
1466  d = intcap - 1;
1467 
1468  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1469 
1470  /* insert all items in (non-) solution vector */
1471  for( j = nmyitems - 1; j > 0; --j )
1472  {
1473  /* if the following condition holds this means all remaining items does not fit anymore */
1474  if( d < allcurrminweight[j] )
1475  {
1476  /* we cannot have exceeded our capacity */
1477  assert((SCIP_Longint) d >= -minweight);
1478  break;
1479  }
1480 
1481  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1482  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1483  {
1484  solitems[(*nsolitems)++] = myitems[j];
1485 
1486  /* check that we do not have an underflow */
1487  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1488  d = (int)(d - myweights[j]);
1489  }
1490  /* collect non-solution items */
1491  else
1492  nonsolitems[(*nnonsolitems)++] = myitems[j];
1493  }
1494 
1495  /* insert remaining items */
1496  if( d >= allcurrminweight[j] )
1497  {
1498  assert(j == 0);
1499  solitems[(*nsolitems)++] = myitems[j];
1500  }
1501  else
1502  {
1503  assert(j >= 0);
1504  assert(d < allcurrminweight[j]);
1505 
1506  for( ; j >= 0; --j )
1507  nonsolitems[(*nnonsolitems)++] = myitems[j];
1508  }
1509 
1510  assert(*nsolitems + *nnonsolitems == nitems);
1511  }
1512 
1513  /* update solution value */
1514  if( solval != NULL )
1515  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1516  SCIPfreeBufferArray(scip, &allcurrminweight);
1517 
1518  /* free all temporary memory */
1519  SCIPfreeBufferArray(scip, &optvalues);
1520 
1521  TERMINATE:
1522  SCIPfreeBufferArray(scip, &myitems);
1523  SCIPfreeBufferArray(scip, &myprofits);
1524  SCIPfreeBufferArray(scip, &myweights);
1525 
1526  return SCIP_OKAY;
1527 }
1528 
1529 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1530  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1531  * selected items
1532  */
1534  SCIP* scip, /**< SCIP data structure */
1535  int nitems, /**< number of available items */
1536  SCIP_Longint* weights, /**< item weights */
1537  SCIP_Real* profits, /**< item profits */
1538  SCIP_Longint capacity, /**< capacity of knapsack */
1539  int* items, /**< item numbers */
1540  int* solitems, /**< array to store items in solution, or NULL */
1541  int* nonsolitems, /**< array to store items not in solution, or NULL */
1542  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1543  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1544  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1545  )
1546 {
1547  SCIP_Real* tempsort;
1548  SCIP_Longint solitemsweight;
1549  SCIP_Real* realweights;
1550  int j;
1551  int criticalindex;
1552 
1553  assert(weights != NULL);
1554  assert(profits != NULL);
1555  assert(capacity >= 0);
1556  assert(items != NULL);
1557  assert(nitems >= 0);
1558 
1559  if( solitems != NULL )
1560  {
1561  *nsolitems = 0;
1562  *nnonsolitems = 0;
1563  }
1564  if( solval != NULL )
1565  *solval = 0.0;
1566 
1567  /* initialize data for median search */
1568  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1569  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1570  for( j = nitems - 1; j >= 0; --j )
1571  {
1572  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1573  realweights[j] = (SCIP_Real)weights[j];
1574  }
1575 
1576  /* partially sort indices such that all elements that are larger than the break item appear first */
1577  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1578 
1579  /* selects items as long as they fit into the knapsack */
1580  solitemsweight = 0;
1581  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1582  {
1583  if( solitems != NULL )
1584  solitems[(*nsolitems)++] = items[j];
1585 
1586  if( solval != NULL )
1587  (*solval) += profits[j];
1588  solitemsweight += weights[j];
1589  }
1590  if ( solitems != NULL )
1591  {
1592  for( ; j < nitems; j++ )
1593  nonsolitems[(*nnonsolitems)++] = items[j];
1594  }
1595 
1596  SCIPfreeBufferArray(scip, &realweights);
1597  SCIPfreeBufferArray(scip, &tempsort);
1598 
1599  return SCIP_OKAY;
1600 }
1601 
1602 #ifdef SCIP_DEBUG
1603 /** prints all nontrivial GUB constraints and their LP solution values */
1604 static
1605 void GUBsetPrint(
1606  SCIP* scip, /**< SCIP data structure */
1607  SCIP_GUBSET* gubset, /**< GUB set data structure */
1608  SCIP_VAR** vars, /**< variables in knapsack constraint */
1609  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1610  )
1611 {
1612  int nnontrivialgubconss;
1613  int c;
1614 
1615  nnontrivialgubconss = 0;
1616 
1617  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1618 
1619  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1620  for( c = 0; c < gubset->ngubconss; c++ )
1621  {
1622  SCIP_Real gubsolval;
1623 
1624  assert(gubset->gubconss[c]->ngubvars >= 0);
1625 
1626  /* nontrivial GUB */
1627  if( gubset->gubconss[c]->ngubvars > 1 )
1628  {
1629  int v;
1630 
1631  gubsolval = 0.0;
1632  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1633 
1634  /* print GUB var */
1635  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1636  {
1637  int currentvar;
1638 
1639  currentvar = gubset->gubconss[c]->gubvars[v];
1640  if( solvals != NULL )
1641  {
1642  gubsolval += solvals[currentvar];
1643  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1644  }
1645  else
1646  {
1647  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1648  }
1649  }
1650 
1651  /* check whether LP solution satisfies the GUB constraint */
1652  if( solvals != NULL )
1653  {
1654  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1655  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1656  }
1657  else
1658  {
1659  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1660  }
1661  nnontrivialgubconss++;
1662  }
1663  }
1664 
1665  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1666 }
1667 #endif
1668 
1669 /** creates an empty GUB constraint */
1670 static
1672  SCIP* scip, /**< SCIP data structure */
1673  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1674  )
1675 {
1676  assert(scip != NULL);
1677  assert(gubcons != NULL);
1678 
1679  /* allocate memory for GUB constraint data structures */
1680  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1681  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1682  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1683  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1684 
1685  (*gubcons)->ngubvars = 0;
1686 
1687  return SCIP_OKAY;
1688 }
1689 
1690 /** frees GUB constraint */
1691 static
1692 void GUBconsFree(
1693  SCIP* scip, /**< SCIP data structure */
1694  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1695  )
1696 {
1697  assert(scip != NULL);
1698  assert(gubcons != NULL);
1699  assert((*gubcons)->gubvars != NULL);
1700  assert((*gubcons)->gubvarsstatus != NULL);
1701 
1702  /* free allocated memory */
1703  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1704  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1705  SCIPfreeBuffer(scip, gubcons);
1706 }
1707 
1708 /** adds variable to given GUB constraint */
1709 static
1711  SCIP* scip, /**< SCIP data structure */
1712  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1713  int var /**< index of given variable in knapsack constraint */
1714  )
1715 {
1716  assert(scip != NULL);
1717  assert(gubcons != NULL);
1718  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1719  assert(gubcons->gubvars != NULL);
1720  assert(gubcons->gubvarsstatus != NULL);
1721  assert(var >= 0);
1722 
1723  /* add variable to GUB constraint */
1724  gubcons->gubvars[gubcons->ngubvars] = var;
1725  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1726  gubcons->ngubvars++;
1727 
1728  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1729  if( gubcons->ngubvars == gubcons->gubvarssize )
1730  {
1731  int newlen;
1732 
1733  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1734  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1735  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1736 
1737  gubcons->gubvarssize = newlen;
1738  }
1739 
1740  return SCIP_OKAY;
1741 }
1742 
1743 /** deletes variable from its current GUB constraint */
1744 static
1746  SCIP* scip, /**< SCIP data structure */
1747  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1748  int var, /**< index of given variable in knapsack constraint */
1749  int gubvarsidx /**< index of the variable in its current GUB constraint */
1750  )
1751 {
1752  assert(scip != NULL);
1753  assert(gubcons != NULL);
1754  assert(var >= 0);
1755  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1756  assert(gubcons->ngubvars >= gubvarsidx+1);
1757  assert(gubcons->gubvars[gubvarsidx] == var);
1758 
1759  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1760  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1761  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1762  gubcons->ngubvars--;
1763 
1764  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1765  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1766  {
1767  int newlen;
1768 
1769  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1770 
1771  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1772  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1773 
1774  gubcons->gubvarssize = newlen;
1775  }
1776 
1777  return SCIP_OKAY;
1778 }
1779 
1780 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1781 static
1783  SCIP* scip, /**< SCIP data structure */
1784  SCIP_GUBSET* gubset, /**< GUB set data structure */
1785  SCIP_VAR** vars, /**< variables in knapsack constraint */
1786  int var, /**< index of given variable in knapsack constraint */
1787  int oldgubcons, /**< index of old GUB constraint of given variable */
1788  int newgubcons /**< index of new GUB constraint of given variable */
1789  )
1791  int oldgubvaridx;
1792  int replacevar;
1793  int j;
1794 
1795  assert(scip != NULL);
1796  assert(gubset != NULL);
1797  assert(var >= 0);
1798  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1799  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1800  assert(oldgubcons != newgubcons);
1801  assert(gubset->gubconssidx[var] == oldgubcons);
1802  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1803  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1804 
1805  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1806 
1807  oldgubvaridx = gubset->gubvarsidx[var];
1808 
1809  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1810  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1811 
1812  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1813  * replacement variable is given by old position of the deleted variable
1814  */
1815  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1816  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1817  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1818 
1819  /* add variable to the end of new GUB constraint */
1820  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1821  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1822 
1823  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1824  gubset->gubconssidx[var] = newgubcons;
1825  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1826 
1827  /* delete old GUB constraint if it became empty */
1828  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1829  {
1830  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1831 #ifdef SCIP_DEBUG
1832  GUBsetPrint(scip, gubset, vars, NULL);
1833 #endif
1834 
1835  /* free old GUB constraint */
1836  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1837 
1838  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1839  if( oldgubcons != gubset->ngubconss-1 )
1840  {
1841  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1842  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1843 
1844  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1845  * replacement GUB is given by old position of the deleted GUB
1846  */
1847  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1848  {
1849  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1850  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1851  }
1852  }
1853 
1854  /* update number of GUB constraints */
1855  gubset->ngubconss--;
1856 
1857  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1858  * (because it was at the end of the GUB constraint array)
1859  */
1860  assert(gubset->gubconssidx[var] == newgubcons
1861  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1862  }
1863 #ifndef NDEBUG
1864  else
1865  assert(gubset->gubconssidx[var] == newgubcons);
1866 #endif
1867 
1868  return SCIP_OKAY;
1869 }
1870 
1871 /** swaps two variables in the same GUB constraint */
1872 static
1873 void GUBsetSwapVars(
1874  SCIP* scip, /**< SCIP data structure */
1875  SCIP_GUBSET* gubset, /**< GUB set data structure */
1876  int var1, /**< first variable to be swapped */
1877  int var2 /**< second variable to be swapped */
1878  )
1879 {
1880  int gubcons;
1881  int var1idx;
1882  GUBVARSTATUS var1status;
1883  int var2idx;
1884  GUBVARSTATUS var2status;
1885 
1886  assert(scip != NULL);
1887  assert(gubset != NULL);
1888 
1889  gubcons = gubset->gubconssidx[var1];
1890  assert(gubcons == gubset->gubconssidx[var2]);
1891 
1892  /* nothing to be done if both variables are the same */
1893  if( var1 == var2 )
1894  return;
1895 
1896  /* swap index and status of variables in GUB constraint */
1897  var1idx = gubset->gubvarsidx[var1];
1898  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1899  var2idx = gubset->gubvarsidx[var2];
1900  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1901 
1902  gubset->gubvarsidx[var1] = var2idx;
1903  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1904  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1905 
1906  gubset->gubvarsidx[var2] = var1idx;
1907  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1908  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1909 }
1910 
1911 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1912 static
1914  SCIP* scip, /**< SCIP data structure */
1915  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1916  int nvars, /**< number of variables in the knapsack constraint */
1917  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1918  SCIP_Longint capacity /**< capacity of knapsack */
1919  )
1920 {
1921  int i;
1922 
1923  assert(scip != NULL);
1924  assert(gubset != NULL);
1925  assert(nvars > 0);
1926  assert(weights != NULL);
1927  assert(capacity >= 0);
1928 
1929  /* allocate memory for GUB set data structures */
1930  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1931  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1932  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1933  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1934  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1935  (*gubset)->ngubconss = nvars;
1936  (*gubset)->nvars = nvars;
1937 
1938  /* initialize the set of GUB constraints */
1939  for( i = 0; i < nvars; i++ )
1940  {
1941  /* assign each variable to a new (trivial) GUB constraint */
1942  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1943  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1944 
1945  /* set status of GUB constraint to initial */
1946  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1947 
1948  (*gubset)->gubconssidx[i] = i;
1949  (*gubset)->gubvarsidx[i] = 0;
1950  assert((*gubset)->gubconss[i]->ngubvars == 1);
1951 
1952  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1953  if( weights[i] > capacity )
1954  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1955  }
1956 
1957  return SCIP_OKAY;
1958 }
1959 
1960 /** frees GUB set data structure */
1961 static
1962 void GUBsetFree(
1963  SCIP* scip, /**< SCIP data structure */
1964  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1965  )
1966 {
1967  int i;
1968 
1969  assert(scip != NULL);
1970  assert(gubset != NULL);
1971  assert((*gubset)->gubconss != NULL);
1972  assert((*gubset)->gubconsstatus != NULL);
1973  assert((*gubset)->gubconssidx != NULL);
1974  assert((*gubset)->gubvarsidx != NULL);
1975 
1976  /* free all GUB constraints */
1977  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1978  {
1979  assert((*gubset)->gubconss[i] != NULL);
1980  GUBconsFree(scip, &(*gubset)->gubconss[i]);
1981  }
1982 
1983  /* free allocated memory */
1984  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1985  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1986  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1987  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
1988  SCIPfreeBuffer(scip, gubset);
1989 }
1990 
1991 #ifndef NDEBUG
1992 /** checks whether GUB set data structure is consistent */
1993 static
1995  SCIP* scip, /**< SCIP data structure */
1996  SCIP_GUBSET* gubset, /**< GUB set data structure */
1997  SCIP_VAR** vars /**< variables in the knapsack constraint */
1998  )
1999 {
2000  int i;
2001  int gubconsidx;
2002  int gubvaridx;
2003  SCIP_VAR* var1;
2004  SCIP_VAR* var2;
2005  SCIP_Bool var1negated;
2006  SCIP_Bool var2negated;
2007 
2008  assert(scip != NULL);
2009  assert(gubset != NULL);
2010 
2011  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2012 
2013  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2014  for( i = 0; i < gubset->nvars; i++ )
2015  {
2016  gubconsidx = gubset->gubconssidx[i];
2017  gubvaridx = gubset->gubvarsidx[i];
2018 
2019  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2020  {
2021  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2022  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2023  }
2024  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2025  }
2026 
2027  /* checks for each GUB whether all pairs of its variables have a common clique */
2028  for( i = 0; i < gubset->ngubconss; i++ )
2029  {
2030  int j;
2031 
2032  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2033  {
2034  int k;
2035 
2036  /* get corresponding active problem variable */
2037  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2038  var1negated = FALSE;
2039  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2040 
2041  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2042  {
2043  /* get corresponding active problem variable */
2044  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2045  var2negated = FALSE;
2046  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2047 
2048  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2049  {
2050  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2051  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2052  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2053  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2054  SCIPvarGetName(var1), k,
2055  SCIPvarGetName(var2));
2056  }
2057 
2058  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2059  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2060  }
2061  }
2062  }
2063  SCIPdebugMsg(scip, " --> successful\n");
2064 
2065  return SCIP_OKAY;
2066 }
2067 #endif
2068 
2069 /** calculates a partition of the given set of binary variables into cliques;
2070  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2071  * were assigned to the same clique;
2072  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2073  * the preceding variables was assigned to clique i-1;
2074  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2075  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2076  */
2077 
2078 static
2080  SCIP*const scip, /**< SCIP data structure */
2081  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2082  int const nvars, /**< number of variables in the clique */
2083  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2084  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2085  SCIP_Real* solvals /**< solution values of all given binary variables */
2086  )
2088  SCIP_VAR** tmpvars;
2089  SCIP_VAR** cliquevars;
2090  SCIP_Bool* cliquevalues;
2091  SCIP_Bool* tmpvalues;
2092  int* varseq;
2093  int* sortkeys;
2094  int ncliquevars;
2095  int maxncliquevarscomp;
2096  int nignorevars;
2097  int nvarsused;
2098  int i;
2099 
2100  assert(scip != NULL);
2101  assert(nvars == 0 || vars != NULL);
2102  assert(nvars == 0 || cliquepartition != NULL);
2103  assert(ncliques != NULL);
2104 
2105  if( nvars == 0 )
2106  {
2107  *ncliques = 0;
2108  return SCIP_OKAY;
2109  }
2110 
2111  /* allocate temporary memory for storing the variables of the current clique */
2112  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2113  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2114  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2115  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2116  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2117  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2118 
2119  /* initialize the cliquepartition array with -1 */
2120  /* initialize the tmpvalues array */
2121  for( i = nvars - 1; i >= 0; --i )
2122  {
2123  tmpvalues[i] = TRUE;
2124  cliquepartition[i] = -1;
2125  }
2126 
2127  /* get corresponding active problem variables */
2128  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2129 
2130  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2131  * by nondecreasing number of cliques the variables are in
2132  */
2133  nignorevars = 0;
2134  nvarsused = 0;
2135  for( i = 0; i < nvars; i++ )
2136  {
2137  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2138  {
2139  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2140  varseq[nvars-1-nignorevars] = i;
2141  nignorevars++;
2142  }
2143  else
2144  {
2145  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2146  varseq[nvarsused] = i;
2147  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2148  nvarsused++;
2149  }
2150  }
2151  assert(nvarsused + nignorevars == nvars);
2152 
2153  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2154  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2155 
2156  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2157 
2158  /* calculate the clique partition */
2159  *ncliques = 0;
2160  for( i = 0; i < nvars; ++i )
2161  {
2162  if( cliquepartition[varseq[i]] == -1 )
2163  {
2164  int j;
2165 
2166  /* variable starts a new clique */
2167  cliquepartition[varseq[i]] = *ncliques;
2168  cliquevars[0] = tmpvars[varseq[i]];
2169  cliquevalues[0] = tmpvalues[varseq[i]];
2170  ncliquevars = 1;
2171 
2172  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2173  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2174  */
2175  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2176  {
2177  /* greedily fill up the clique */
2178  for( j = i + 1; j < nvarsused; ++j )
2179  {
2180  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2181  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2182  {
2183  int k;
2184 
2185  /* check if every variable in the actual clique is in clique with the new variable */
2186  for( k = ncliquevars - 1; k >= 0; --k )
2187  {
2188  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2189  cliquevalues[k], TRUE) )
2190  break;
2191  }
2192 
2193  if( k == -1 )
2194  {
2195  /* put the variable into the same clique */
2196  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2197  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2198  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2199  ++ncliquevars;
2200  }
2201  }
2202  }
2203  }
2204 
2205  /* this clique is finished */
2206  ++(*ncliques);
2207  }
2208  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2209 
2210  /* break if we reached the maximal number of comparisons */
2211  if( i * nvars > maxncliquevarscomp )
2212  break;
2213  }
2214  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2215  for( ; i < nvars; ++i )
2216  {
2217  if( cliquepartition[varseq[i]] == -1 )
2218  {
2219  cliquepartition[varseq[i]] = *ncliques;
2220  ++(*ncliques);
2221  }
2222  }
2223 
2224  /* free temporary memory */
2225  SCIPfreeBufferArray(scip, &sortkeys);
2226  SCIPfreeBufferArray(scip, &varseq);
2227  SCIPfreeBufferArray(scip, &tmpvars);
2228  SCIPfreeBufferArray(scip, &tmpvalues);
2229  SCIPfreeBufferArray(scip, &cliquevalues);
2230  SCIPfreeBufferArray(scip, &cliquevars);
2231 
2232  return SCIP_OKAY;
2233 }
2234 
2235 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2236 static
2238  SCIP* scip, /**< SCIP data structure */
2239  SCIP_GUBSET* gubset, /**< GUB set data structure */
2240  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2241  SCIP_Real* solvals /**< solution values of all knapsack variables */
2242  )
2243 {
2244  int* cliquepartition;
2245  int* gubfirstvar;
2246  int ncliques;
2247  int currentgubconsidx;
2248  int newgubconsidx;
2249  int cliqueidx;
2250  int nvars;
2251  int i;
2252 
2253  assert(scip != NULL);
2254  assert(gubset != NULL);
2255  assert(vars != NULL);
2256 
2257  nvars = gubset->nvars;
2258  assert(nvars >= 0);
2259 
2260  /* allocate temporary memory for clique partition */
2261  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2262 
2263  /* compute sophisticated clique partition */
2264  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2265 
2266  /* allocate temporary memory for GUB set data structure */
2267  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2268 
2269  /* translate GUB partition into GUB set data structure */
2270  for( i = 0; i < ncliques; i++ )
2271  {
2272  /* initialize first variable for every GUB */
2273  gubfirstvar[i] = -1;
2274  }
2275  /* move every knapsack variable into GUB defined by clique partition */
2276  for( i = 0; i < nvars; i++ )
2277  {
2278  assert(cliquepartition[i] >= 0);
2279 
2280  cliqueidx = cliquepartition[i];
2281  currentgubconsidx = gubset->gubconssidx[i];
2282  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2283 
2284  /* variable is first element in GUB constraint defined by clique partition */
2285  if( gubfirstvar[cliqueidx] == -1 )
2286  {
2287  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2288  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2289  */
2290  assert(gubset->gubvarsidx[i] == 0);
2291  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2292 
2293  /* remember the first variable found for the current GUB */
2294  gubfirstvar[cliqueidx] = i;
2295  }
2296  /* variable is additional element of GUB constraint defined by clique partition */
2297  else
2298  {
2299  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2300 
2301  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2302  * first variable of this GUB constraint
2303  */
2304  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2305  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2306  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2307 
2308  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2309  }
2310  }
2311 
2312 #ifdef SCIP_DEBUG
2313  /* prints GUB set data structure */
2314  GUBsetPrint(scip, gubset, vars, solvals);
2315 #endif
2316 
2317 #ifndef NDEBUG
2318  /* checks consistency of GUB set data structure */
2319  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2320 #endif
2321 
2322  /* free temporary memory */
2323  SCIPfreeBufferArray(scip, &gubfirstvar);
2324  SCIPfreeBufferArray(scip, &cliquepartition);
2325 
2326  return SCIP_OKAY;
2327 }
2328 
2329 /** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
2330  * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
2331  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2332  */
2333 static
2335  SCIP* scip, /**< SCIP data structure */
2336  SCIP_VAR** vars, /**< variables in knapsack constraint */
2337  int nvars, /**< number of variables in knapsack constraint */
2338  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2339  SCIP_Longint capacity, /**< capacity of knapsack */
2340  SCIP_Real* solvals, /**< solution values of all problem variables */
2341  int* covervars, /**< pointer to store cover variables */
2342  int* noncovervars, /**< pointer to store noncover variables */
2343  int* ncovervars, /**< pointer to store number of cover variables */
2344  int* nnoncovervars, /**< pointer to store number of noncover variables */
2345  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2346  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2347  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2348  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2349  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2350  )
2351 {
2352  SCIP_Longint* transweights;
2353  SCIP_Real* transprofits;
2354  SCIP_Longint transcapacity;
2355  SCIP_Longint fixedonesweight;
2356  SCIP_Longint itemsweight;
2357  SCIP_Bool infeasible;
2358  int* fixedones;
2359  int* fixedzeros;
2360  int* items;
2361  int nfixedones;
2362  int nfixedzeros;
2363  int nitems;
2364  int j;
2365 
2366  assert(scip != NULL);
2367  assert(vars != NULL);
2368  assert(nvars > 0);
2369  assert(weights != NULL);
2370  assert(capacity >= 0);
2371  assert(solvals != NULL);
2372  assert(covervars != NULL);
2373  assert(noncovervars != NULL);
2374  assert(ncovervars != NULL);
2375  assert(nnoncovervars != NULL);
2376  assert(coverweight != NULL);
2377  assert(found != NULL);
2378  assert(ntightened != NULL);
2379  assert(fractional != NULL);
2380 
2381  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2382 
2383  /* allocates temporary memory */
2384  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2385  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2386  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2387  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2388  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2389 
2390  *found = FALSE;
2391  *ncovervars = 0;
2392  *nnoncovervars = 0;
2393  *coverweight = 0;
2394  *fractional = TRUE;
2395 
2396  /* gets the following sets
2397  * N_1 = {j in N : x*_j = 1} (fixedones),
2398  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2399  * N\(N_0 & N_1) (items),
2400  * where x*_j is the solution value of variable x_j
2401  */
2402  nfixedones = 0;
2403  nfixedzeros = 0;
2404  nitems = 0;
2405  fixedonesweight = 0;
2406  itemsweight = 0;
2407  *ntightened = 0;
2408  for( j = 0; j < nvars; j++ )
2409  {
2410  assert(SCIPvarIsBinary(vars[j]));
2411 
2412  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2413  if( weights[j] > capacity )
2414  {
2415  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2416  assert(!infeasible);
2417  (*ntightened)++;
2418  continue;
2419  }
2420 
2421  /* variable x_j has solution value one */
2422  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2423  {
2424  fixedones[nfixedones] = j;
2425  nfixedones++;
2426  fixedonesweight += weights[j];
2427  }
2428  /* variable x_j has solution value zero */
2429  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2430  {
2431  fixedzeros[nfixedzeros] = j;
2432  nfixedzeros++;
2433  }
2434  /* variable x_j has fractional solution value */
2435  else
2436  {
2437  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2438  items[nitems] = j;
2439  nitems++;
2440  itemsweight += weights[j];
2441  }
2442  }
2443  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2444 
2445  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2446  * the separation routine
2447  */
2448  assert(nitems >= 0);
2449  if( nitems == 0 )
2450  {
2451  *fractional = FALSE;
2452  goto TERMINATE;
2453  }
2454  assert(*fractional);
2455 
2456  /* transforms the traditional separation problem (under consideration of the following fixing:
2457  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2458  *
2459  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2460  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2461  * z_j in {0,1}, j in N\(N_0 & N_1)
2462  *
2463  * to a knapsack problem in maximization form by complementing the variables
2464  *
2465  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2466  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2467  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2468  * z_j in {0,1}, j in N\(N_0 & N_1)
2469  */
2470 
2471  /* gets weight and profit of variables in transformed knapsack problem */
2472  for( j = 0; j < nitems; j++ )
2473  {
2474  transweights[j] = weights[items[j]];
2475  transprofits[j] = 1.0 - solvals[items[j]];
2476  }
2477  /* gets capacity of transformed knapsack problem */
2478  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2479 
2480  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2481  * (when variables fixed to zero are not used)
2482  */
2483  if( transcapacity < 0 )
2484  {
2485  assert(!(*found));
2486  goto TERMINATE;
2487  }
2488 
2489  if( modtransused )
2490  {
2491  /* transforms the modified separation problem (under consideration of the following fixing:
2492  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2493  *
2494  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2495  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2496  * z_j in {0,1}, j in N\(N_0 & N_1)
2497  *
2498  * to a knapsack problem in maximization form by complementing the variables
2499  *
2500  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2501  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2502  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2503  * z_j in {0,1}, j in N\(N_0 & N_1)
2504  */
2505 
2506  /* gets weight and profit of variables in modified transformed knapsack problem */
2507  for( j = 0; j < nitems; j++ )
2508  {
2509  transprofits[j] *= weights[items[j]];
2510  assert(SCIPisFeasPositive(scip, transprofits[j]));
2511  }
2512  }
2513 
2514  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2515  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2516  * let z* be the solution, then
2517  * j in C, if z*_j = 0 and
2518  * i in N\C, if z*_j = 1.
2519  */
2520  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2521  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2522  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2523 
2524  /* constructs cover C (sum_{j in C} a_j > a_0) */
2525  for( j = 0; j < *ncovervars; j++ )
2526  {
2527  (*coverweight) += weights[covervars[j]];
2528  }
2529 
2530  /* adds all variables from N_1 to C */
2531  for( j = 0; j < nfixedones; j++ )
2532  {
2533  covervars[*ncovervars] = fixedones[j];
2534  (*ncovervars)++;
2535  (*coverweight) += weights[fixedones[j]];
2536  }
2537 
2538  /* adds all variables from N_0 to N\C */
2539  for( j = 0; j < nfixedzeros; j++ )
2540  {
2541  noncovervars[*nnoncovervars] = fixedzeros[j];
2542  (*nnoncovervars)++;
2543  }
2544  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2545  assert((*coverweight) > capacity);
2546  *found = TRUE;
2547 
2548  TERMINATE:
2549  /* frees temporary memory */
2550  SCIPfreeBufferArray(scip, &items);
2551  SCIPfreeBufferArray(scip, &fixedzeros);
2552  SCIPfreeBufferArray(scip, &fixedones);
2553  SCIPfreeBufferArray(scip, &transprofits);
2554  SCIPfreeBufferArray(scip, &transweights);
2555 
2556  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2557 
2558  return SCIP_OKAY;
2559 }
2560 
2561 #ifndef NDEBUG
2562 /** checks if minweightidx is set correctly
2563  */
2564 static
2566  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2567  SCIP_Longint capacity, /**< capacity of knapsack */
2568  int* covervars, /**< pointer to store cover variables */
2569  int ncovervars, /**< pointer to store number of cover variables */
2570  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2571  int minweightidx, /**< index of variable in cover variables with minimum weight */
2572  int j /**< current index in cover variables */
2573  )
2574 {
2575  SCIP_Longint minweight;
2576  int i;
2577 
2578  assert(weights != NULL);
2579  assert(covervars != NULL);
2580  assert(ncovervars > 0);
2581 
2582  minweight = weights[covervars[minweightidx]];
2583 
2584  /* checks if all cover variables before index j have weight greater than minweight */
2585  for( i = 0; i < j; i++ )
2586  {
2587  assert(weights[covervars[i]] > minweight);
2588  if( weights[covervars[i]] <= minweight )
2589  return FALSE;
2590  }
2591 
2592  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2593  for( i = 0; i < j; i++ )
2594  {
2595  assert(coverweight - weights[covervars[i]] <= capacity);
2596  if( coverweight - weights[covervars[i]] > capacity )
2597  return FALSE;
2598  }
2599  return TRUE;
2600 }
2601 #endif
2602 
2603 
2604 /** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
2605  * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
2606  */
2607 static
2609  SCIP* scip, /**< SCIP data structure */
2610  SCIP_Real* solvals, /**< solution values of all problem variables */
2611  int* covervars, /**< cover variables */
2612  int ncovervars, /**< number of cover variables */
2613  int* varsC1, /**< pointer to store variables in C1 */
2614  int* varsC2, /**< pointer to store variables in C2 */
2615  int* nvarsC1, /**< pointer to store number of variables in C1 */
2616  int* nvarsC2 /**< pointer to store number of variables in C2 */
2617  )
2618 {
2619  int j;
2620 
2621  assert(scip != NULL);
2622  assert(ncovervars >= 0);
2623  assert(solvals != NULL);
2624  assert(covervars != NULL);
2625  assert(varsC1 != NULL);
2626  assert(varsC2 != NULL);
2627  assert(nvarsC1 != NULL);
2628  assert(nvarsC2 != NULL);
2629 
2630  *nvarsC1 = 0;
2631  *nvarsC2 = 0;
2632  for( j = 0; j < ncovervars; j++ )
2633  {
2634  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2635 
2636  /* variable has solution value one */
2637  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2638  {
2639  varsC2[*nvarsC2] = covervars[j];
2640  (*nvarsC2)++;
2641  }
2642  /* variable has solution value less than one */
2643  else
2644  {
2645  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2646  varsC1[*nvarsC1] = covervars[j];
2647  (*nvarsC1)++;
2648  }
2649  }
2650  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2651 }
2652 
2653 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2654  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2655  */
2656 static
2658  SCIP* scip, /**< SCIP data structure */
2659  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2660  int* varsC1, /**< pointer to store variables in C1 */
2661  int* varsC2, /**< pointer to store variables in C2 */
2662  int* nvarsC1, /**< pointer to store number of variables in C1 */
2663  int* nvarsC2 /**< pointer to store number of variables in C2 */
2664  )
2666  SCIP_Real* sortkeysC2;
2667  int j;
2668 
2669  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2670  assert(*nvarsC2 > 0);
2671 
2672  /* allocates temporary memory */
2673  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2674 
2675  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2676  for( j = 0; j < *nvarsC2; j++ )
2677  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2678  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2679 
2680  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2681  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2682  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2683  {
2684  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2685  (*nvarsC1)++;
2686  (*nvarsC2)--;
2687  }
2688 
2689  /* frees temporary memory */
2690  SCIPfreeBufferArray(scip, &sortkeysC2);
2691 
2692  return SCIP_OKAY;
2693 }
2694 
2695 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2696 static
2698  SCIP* scip, /**< SCIP data structure */
2699  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2700  int* varsC1, /**< pointer to store variables in C1 */
2701  int* varsC2, /**< pointer to store variables in C2 */
2702  int* nvarsC1, /**< pointer to store number of variables in C1 */
2703  int* nvarsC2 /**< pointer to store number of variables in C2 */
2704  )
2706  SCIP_Real* sortkeysC2;
2707  int j;
2708 
2709  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2710  assert(*nvarsC2 > 0);
2711 
2712  /* allocates temporary memory */
2713  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2714 
2715  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2716  for( j = 0; j < *nvarsC2; j++ )
2717  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2718  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2719 
2720  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2721  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2722  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2723  (*nvarsC1)++;
2724  (*nvarsC2)--;
2725 
2726  /* frees temporary memory */
2727  SCIPfreeBufferArray(scip, &sortkeysC2);
2728 
2729  return SCIP_OKAY;
2730 }
2731 
2732 
2733 /** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
2734  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2735  * \f$F = (N \setminus C) \setminus F\f$
2736  */
2737 static
2739  SCIP* scip, /**< SCIP data structure */
2740  SCIP_Real* solvals, /**< solution values of all problem variables */
2741  int* noncovervars, /**< noncover variables */
2742  int nnoncovervars, /**< number of noncover variables */
2743  int* varsF, /**< pointer to store variables in F */
2744  int* varsR, /**< pointer to store variables in R */
2745  int* nvarsF, /**< pointer to store number of variables in F */
2746  int* nvarsR /**< pointer to store number of variables in R */
2747  )
2748 {
2749  int j;
2750 
2751  assert(scip != NULL);
2752  assert(nnoncovervars >= 0);
2753  assert(solvals != NULL);
2754  assert(noncovervars != NULL);
2755  assert(varsF != NULL);
2756  assert(varsR != NULL);
2757  assert(nvarsF != NULL);
2758  assert(nvarsR != NULL);
2759 
2760  *nvarsF = 0;
2761  *nvarsR = 0;
2762 
2763  for( j = 0; j < nnoncovervars; j++ )
2764  {
2765  /* variable has solution value zero */
2766  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2767  {
2768  varsR[*nvarsR] = noncovervars[j];
2769  (*nvarsR)++;
2770  }
2771  /* variable has solution value greater than zero */
2772  else
2773  {
2774  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2775  varsF[*nvarsF] = noncovervars[j];
2776  (*nvarsF)++;
2777  }
2778  }
2779  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2780 }
2781 
2782 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2783  * lifting procedure
2784  */
2785 static
2787  SCIP* scip, /**< SCIP data structure */
2788  SCIP_Real* solvals, /**< solution values of all problem variables */
2789  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2790  int* varsF, /**< pointer to store variables in F */
2791  int* varsC2, /**< pointer to store variables in C2 */
2792  int* varsR, /**< pointer to store variables in R */
2793  int nvarsF, /**< number of variables in F */
2794  int nvarsC2, /**< number of variables in C2 */
2795  int nvarsR /**< number of variables in R */
2796  )
2797 {
2798  SORTKEYPAIR** sortkeypairsF;
2799  SORTKEYPAIR* sortkeypairsFstore;
2800  SCIP_Real* sortkeysC2;
2801  SCIP_Real* sortkeysR;
2802  int j;
2803 
2804  assert(scip != NULL);
2805  assert(solvals != NULL);
2806  assert(weights != NULL);
2807  assert(varsF != NULL);
2808  assert(varsC2 != NULL);
2809  assert(varsR != NULL);
2810  assert(nvarsF >= 0);
2811  assert(nvarsC2 >= 0);
2812  assert(nvarsR >= 0);
2813 
2814  /* allocates temporary memory */
2815  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2816  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2817  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2818  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2819 
2820  /* gets sorting key for variables in F corresponding to the following lifting sequence
2821  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2822  * x*_1 >= x*_2 >= ... >= x*_|F|
2823  * in case of equality uses
2824  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2825  */
2826  for( j = 0; j < nvarsF; j++ )
2827  {
2828  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2829  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2830  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2831  }
2832 
2833  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2834  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2835  */
2836  for( j = 0; j < nvarsC2; j++ )
2837  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2838 
2839  /* gets sorting key for variables in R corresponding to the following lifting sequence
2840  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2841  */
2842  for( j = 0; j < nvarsR; j++ )
2843  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2844 
2845  /* sorts F, C2 and R */
2846  if( nvarsF > 0 )
2847  {
2848  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2849  }
2850  if( nvarsC2 > 0 )
2851  {
2852  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2853  }
2854  if( nvarsR > 0)
2855  {
2856  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2857  }
2858 
2859  /* frees temporary memory */
2860  SCIPfreeBufferArray(scip, &sortkeysR);
2861  SCIPfreeBufferArray(scip, &sortkeysC2);
2862  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2863  SCIPfreeBufferArray(scip, &sortkeypairsF);
2864 
2865  return SCIP_OKAY;
2866 }
2867 
2868 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2869  * for the sequential GUB wise lifting procedure
2870  */
2871 static
2873  SCIP* scip, /**< SCIP data structure */
2874  SCIP_GUBSET* gubset, /**< GUB set data structure */
2875  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2876  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2877  int* varsC1, /**< variables in C1 */
2878  int* varsC2, /**< variables in C2 */
2879  int* varsF, /**< variables in F */
2880  int* varsR, /**< variables in R */
2881  int nvarsC1, /**< number of variables in C1 */
2882  int nvarsC2, /**< number of variables in C2 */
2883  int nvarsF, /**< number of variables in F */
2884  int nvarsR, /**< number of variables in R */
2885  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2886  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2887  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2888  int* gubconsGR, /**< pointer to store GUBs in GR */
2889  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2890  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2891  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2892  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2893  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2894  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2895  )
2896 {
2897  SORTKEYPAIR** sortkeypairsGFC1;
2898  SORTKEYPAIR* sortkeypairsGFC1store;
2899  SCIP_Real* sortkeysC1;
2900  SCIP_Real* sortkeysC2;
2901  SCIP_Real* sortkeysR;
2902  int* nC1varsingubcons;
2903  int var;
2904  int gubconsidx;
2905  int varidx;
2906  int ngubconss;
2907  int ngubconsGOC1;
2908  int targetvar;
2909  int nvarsprocessed;
2910  int i;
2911  int j;
2912 
2913 #if GUBSPLITGNC1GUBS
2914  SCIP_Bool gubconswithF;
2915  int origngubconss;
2916  origngubconss = gubset->ngubconss;
2917 #endif
2918 
2919  assert(scip != NULL);
2920  assert(gubset != NULL);
2921  assert(solvals != NULL);
2922  assert(weights != NULL);
2923  assert(varsC1 != NULL);
2924  assert(varsC2 != NULL);
2925  assert(varsF != NULL);
2926  assert(varsR != NULL);
2927  assert(nvarsC1 > 0);
2928  assert(nvarsC2 >= 0);
2929  assert(nvarsF >= 0);
2930  assert(nvarsR >= 0);
2931  assert(gubconsGC1 != NULL);
2932  assert(gubconsGC2 != NULL);
2933  assert(gubconsGFC1 != NULL);
2934  assert(gubconsGR != NULL);
2935  assert(ngubconsGC1 != NULL);
2936  assert(ngubconsGC2 != NULL);
2937  assert(ngubconsGFC1 != NULL);
2938  assert(ngubconsGR != NULL);
2939  assert(maxgubvarssize != NULL);
2940 
2941  ngubconss = gubset->ngubconss;
2942  nvarsprocessed = 0;
2943  ngubconsGOC1 = 0;
2944 
2945  /* GUBs are categorized into different types according to the variables in volved
2946  * - GOC1: involves variables in C1 only -- no C2, R, F
2947  * - GNC1: involves variables in C1 and F (and R) -- no C2
2948  * - GF: involves variables in F (and R) only -- no C1, C2
2949  * - GC2: involves variables in C2 only -- no C1, R, F
2950  * - GR: involves variables in R only -- no C1, C2, F
2951  * which requires splitting GUBs in case they include variable in F and R.
2952  *
2953  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2954  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2955  * - second ordering level is
2956  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2957  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2958  * GR: non-increasing max{ a_k : k in GR_j}
2959  *
2960  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2961  * - GC1: GUBs of category GOC1 and GNC1
2962  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2963  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2964  */
2965 
2966  /* allocates temporary memory */
2967  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2968  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2969  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2970 
2971  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2972  * - F: non-increasing x*_j and non-increasing a_j in case of equality
2973  * - C2: non-increasing a_j
2974  * - R: non-increasing a_j
2975  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2976  */
2977 
2978  /* gets sorting key for variables in C1 corresponding to the following ordering
2979  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
2980  */
2981  for( j = 0; j < nvarsC1; j++ )
2982  {
2983  /* gets sortkeys */
2984  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
2985 
2986  /* update status of variable in its gub constraint */
2987  gubconsidx = gubset->gubconssidx[varsC1[j]];
2988  varidx = gubset->gubvarsidx[varsC1[j]];
2989  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
2990  }
2991 
2992  /* gets sorting key for variables in F corresponding to the following ordering
2993  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
2994  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
2995  * and updates status of each variable in F in GUB set data structure
2996  */
2997  for( j = 0; j < nvarsF; j++ )
2998  {
2999  /* update status of variable in its gub constraint */
3000  gubconsidx = gubset->gubconssidx[varsF[j]];
3001  varidx = gubset->gubvarsidx[varsF[j]];
3002  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3003  }
3004 
3005  /* gets sorting key for variables in C2 corresponding to the following ordering
3006  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3007  * and updates status of each variable in F in GUB set data structure
3008  */
3009  for( j = 0; j < nvarsC2; j++ )
3010  {
3011  /* gets sortkeys */
3012  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3013 
3014  /* update status of variable in its gub constraint */
3015  gubconsidx = gubset->gubconssidx[varsC2[j]];
3016  varidx = gubset->gubvarsidx[varsC2[j]];
3017  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3018  }
3019 
3020  /* gets sorting key for variables in R corresponding to the following ordering
3021  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3022  * and updates status of each variable in F in GUB set data structure
3023  */
3024  for( j = 0; j < nvarsR; j++ )
3025  {
3026  /* gets sortkeys */
3027  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3028 
3029  /* update status of variable in its gub constraint */
3030  gubconsidx = gubset->gubconssidx[varsR[j]];
3031  varidx = gubset->gubvarsidx[varsR[j]];
3032  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3033  }
3034 
3035  /* sorts C1, F, C2 and R */
3036  assert(nvarsC1 > 0);
3037  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3038 
3039  if( nvarsC2 > 0 )
3040  {
3041  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3042  }
3043  if( nvarsR > 0)
3044  {
3045  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3046  }
3047 
3048  /* frees temporary memory */
3049  SCIPfreeBufferArray(scip, &sortkeysR);
3050  SCIPfreeBufferArray(scip, &sortkeysC2);
3051  SCIPfreeBufferArray(scip, &sortkeysC1);
3052 
3053  /* allocate and initialize temporary memory for sorting GUB constraints */
3054  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3055  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3056  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3057  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3058  for( i = 0; i < ngubconss; i++)
3059  {
3060  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3061  sortkeypairsGFC1[i]->key1 = 0.0;
3062  sortkeypairsGFC1[i]->key2 = 0.0;
3063  }
3064  *ngubconsGC1 = 0;
3065  *ngubconsGC2 = 0;
3066  *ngubconsGFC1 = 0;
3067  *ngubconsGR = 0;
3068  *ngubconscapexceed = 0;
3069  *maxgubvarssize = 0;
3070 
3071 #ifndef NDEBUG
3072  for( i = 0; i < gubset->ngubconss; i++ )
3073  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3074 #endif
3075 
3076  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3077  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3078  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3079  * non-increasing number of variables in F, and
3080  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3081  */
3082  for( i = 0; i < nvarsC1; i++ )
3083  {
3084  int nvarsC1capexceed;
3085 
3086  nvarsC1capexceed = 0;
3087 
3088  var = varsC1[i];
3089  gubconsidx = gubset->gubconssidx[var];
3090  varidx = gubset->gubvarsidx[var];
3091 
3092  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3093  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3094 
3095  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3096  * note that variables in C1 are already sorted by non-decreasing weigth
3097  */
3098  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3099  GUBsetSwapVars(scip, gubset, var, targetvar);
3100  nC1varsingubcons[gubconsidx]++;
3101 
3102  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3103  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3104  {
3105  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3106  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3107  continue;
3108  }
3109 
3110  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3111  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3112  */
3113 #if GUBSPLITGNC1GUBS
3114  gubconswithF = FALSE;
3115 #endif
3116  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3117  {
3118  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3119 
3120  /* C1-variable: update number of C1/capacity exceeding variables */
3121  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3122  {
3123  nvarsC1capexceed++;
3124  nvarsprocessed++;
3125  }
3126  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3127  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3128  {
3129 #if GUBSPLITGNC1GUBS
3130  gubconswithF = TRUE;
3131 #endif
3132  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3133 
3134  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3135  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3136  }
3137  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3138  {
3139  nvarsC1capexceed++;
3140  }
3141  else
3142  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3143  }
3144 
3145  /* update set of GC1 GUBs */
3146  gubconsGC1[*ngubconsGC1] = gubconsidx;
3147  (*ngubconsGC1)++;
3148 
3149  /* update maximum size of all GUB constraints */
3150  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3151  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3152 
3153  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3154  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3155  {
3156  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3157  ngubconsGOC1++;
3158  }
3159  else
3160  {
3161 #if GUBSPLITGNC1GUBS
3162  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3163  if( !gubconswithF )
3164  {
3165  GUBVARSTATUS movevarstatus;
3166 
3167  assert(gubset->ngubconss < gubset->nvars);
3168 
3169  /* create a new GUB for GR part of splitting */
3170  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3171  gubset->ngubconss++;
3172  ngubconss = gubset->ngubconss;
3173 
3174  /* fill GR with R variables in current GUB */
3175  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3176  {
3177  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3178  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3179  {
3180  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3181  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3182  gubconsidx, ngubconss-1) );
3183  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3184  movevarstatus;
3185  }
3186  }
3187 
3188  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3189  ngubconsGOC1++;
3190 
3191  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3192  gubconsGR[*ngubconsGR] = ngubconss-1;
3193  (*ngubconsGR)++;
3194  }
3195  /* variables in C1, F, and maybe R: GNC1 GUB */
3196  else
3197  {
3198  assert(gubconswithF);
3199 
3200  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3201  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3202  (*ngubconsGFC1)++;
3203  }
3204 #else
3205  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3206  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3207  (*ngubconsGFC1)++;
3208 #endif
3209  }
3210  }
3211 
3212  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3213  * are already sorted correctly
3214  */
3215  for( i = 0; i < nvarsC2; i++ )
3216  {
3217  var = varsC2[i];
3218  gubconsidx = gubset->gubconssidx[var];
3219  varidx = gubset->gubvarsidx[var];
3220 
3221  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3222  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3223  assert(varidx == 0);
3224  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3225  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3226 
3227  /* set status of GC2 GUB */
3228  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3229 
3230  /* update group of GC2 GUBs */
3231  gubconsGC2[*ngubconsGC2] = gubconsidx;
3232  (*ngubconsGC2)++;
3233 
3234  /* update maximum size of all GUB constraints */
3235  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3236  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3237 
3238  nvarsprocessed++;
3239  }
3240 
3241  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3242  * non-increasing number of variables in F, and
3243  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3244  */
3245  for( i = 0; i < nvarsF; i++ )
3246  {
3247  var = varsF[i];
3248  gubconsidx = gubset->gubconssidx[var];
3249  varidx = gubset->gubvarsidx[var];
3250 
3251  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3252  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3253 
3254  nvarsprocessed++;
3255 
3256  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3257  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3258  {
3259  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3260  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3261  continue;
3262  }
3263 
3264  /* set status of GF GUB */
3265  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3266 
3267  /* update sorting key of corresponding GFC1 GUB */
3268  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3269  {
3270  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3271  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3272 
3273  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3274  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3275  {
3276  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3277 
3278  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3279  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3280  }
3281  }
3282 
3283  /* update set of GFC1 GUBs */
3284  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3285  (*ngubconsGFC1)++;
3286 
3287  /* update maximum size of all GUB constraints */
3288  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3289  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3290  }
3291 
3292  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3293  * correctly
3294  */
3295  for( i = 0; i < nvarsR; i++ )
3296  {
3297  var = varsR[i];
3298  gubconsidx = gubset->gubconssidx[var];
3299  varidx = gubset->gubvarsidx[var];
3300 
3301  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3302  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3303 
3304  nvarsprocessed++;
3305 
3306  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3307  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3308  {
3309  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3310  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3311  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3312  continue;
3313  }
3314 
3315  /* set status of GR GUB */
3316  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3317 
3318  /* update set of GR GUBs */
3319  gubconsGR[*ngubconsGR] = gubconsidx;
3320  (*ngubconsGR)++;
3321 
3322  /* update maximum size of all GUB constraints */
3323  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3324  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3325  }
3326  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3327 
3328  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3329  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3330  assert(*ngubconscapexceed >= 0);
3331 #ifndef NDEBUG
3332  {
3333  int check;
3334 
3335  check = 0;
3336 
3337  /* remaining not handled GUBs should only contain capacity exceeding variables */
3338  for( i = 0; i < ngubconss; i++ )
3339  {
3340  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3341  check++;
3342  }
3343  assert(check == *ngubconscapexceed);
3344  }
3345 #endif
3346 
3347  /* sort GFCI GUBs according to computed sorting keys */
3348  if( (*ngubconsGFC1) > 0 )
3349  {
3350  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3351  }
3352 
3353  /* free temporary memory */
3354 #if GUBSPLITGNC1GUBS
3355  ngubconss = origngubconss;
3356 #endif
3357  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3358  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3359  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3360 
3361  return SCIP_OKAY;
3362 }
3363 
3364 /** enlarges minweight table to at least the given length */
3365 static
3367  SCIP* scip, /**< SCIP data structure */
3368  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3369  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3370  int* minweightssize, /**< pointer to current size of minweights table */
3371  int newlen /**< new length of minweights table */
3372  )
3373 {
3374  int j;
3375 
3376  assert(minweightsptr != NULL);
3377  assert(*minweightsptr != NULL);
3378  assert(minweightslen != NULL);
3379  assert(*minweightslen >= 0);
3380  assert(minweightssize != NULL);
3381  assert(*minweightssize >= 0);
3382 
3383  if( newlen > *minweightssize )
3384  {
3385  int newsize;
3386 
3387  /* reallocate table memory */
3388  newsize = SCIPcalcMemGrowSize(scip, newlen);
3389  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3390  *minweightssize = newsize;
3391  }
3392  assert(newlen <= *minweightssize);
3393 
3394  /* initialize new elements */
3395  for( j = *minweightslen; j < newlen; ++j )
3396  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3397  *minweightslen = newlen;
3398 
3399  return SCIP_OKAY;
3400 }
3401 
3402 /** lifts given inequality
3403  * sum_{j in M_1} x_j <= alpha_0
3404  * valid for
3405  * 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 }
3406  * to a valid inequality
3407  * 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
3408  * <= alpha_0 + sum_{j in M_2} alpha_j
3409  * for
3410  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3411  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3412  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3413  * extended weight inequalities.
3414  */
3415 static
3417  SCIP* scip, /**< SCIP data structure */
3418  SCIP_VAR** vars, /**< variables in knapsack constraint */
3419  int nvars, /**< number of variables in knapsack constraint */
3420  int ntightened, /**< number of variables with tightened upper bound */
3421  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3422  SCIP_Longint capacity, /**< capacity of knapsack */
3423  SCIP_Real* solvals, /**< solution values of all problem variables */
3424  int* varsM1, /**< variables in M_1 */
3425  int* varsM2, /**< variables in M_2 */
3426  int* varsF, /**< variables in F */
3427  int* varsR, /**< variables in R */
3428  int nvarsM1, /**< number of variables in M_1 */
3429  int nvarsM2, /**< number of variables in M_2 */
3430  int nvarsF, /**< number of variables in F */
3431  int nvarsR, /**< number of variables in R */
3432  int alpha0, /**< rights hand side of given valid inequality */
3433  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3434  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3435  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3436  )
3437 {
3438  SCIP_Longint* minweights;
3439  SCIP_Real* sortkeys;
3440  SCIP_Longint fixedonesweight;
3441  int minweightssize;
3442  int minweightslen;
3443  int j;
3444  int w;
3445 
3446  assert(scip != NULL);
3447  assert(vars != NULL);
3448  assert(nvars >= 0);
3449  assert(weights != NULL);
3450  assert(capacity >= 0);
3451  assert(solvals != NULL);
3452  assert(varsM1 != NULL);
3453  assert(varsM2 != NULL);
3454  assert(varsF != NULL);
3455  assert(varsR != NULL);
3456  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3457  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3458  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3459  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3460  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3461  assert(alpha0 >= 0);
3462  assert(liftcoefs != NULL);
3463  assert(cutact != NULL);
3464  assert(liftrhs != NULL);
3465 
3466  /* allocates temporary memory */
3467  minweightssize = nvarsM1 + 1;
3468  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3469  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3470 
3471  /* initializes data structures */
3472  BMSclearMemoryArray(liftcoefs, nvars);
3473  *cutact = 0.0;
3474 
3475  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3476  * and calculates activity of the current valid inequality
3477  */
3478  for( j = 0; j < nvarsM1; j++ )
3479  {
3480  assert(liftcoefs[varsM1[j]] == 0);
3481  liftcoefs[varsM1[j]] = 1;
3482  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3483  (*cutact) += solvals[varsM1[j]];
3484  }
3485 
3486  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3487 
3488  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3489  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3490  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3491  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3492  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3493  */
3494  minweights[0] = 0;
3495  for( w = 1; w <= nvarsM1; w++ )
3496  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3497  minweightslen = nvarsM1 + 1;
3498 
3499  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3500  fixedonesweight = 0;
3501  for( j = 0; j < nvarsM2; j++ )
3502  fixedonesweight += weights[varsM2[j]];
3503  assert(fixedonesweight >= 0);
3504 
3505  /* initializes right hand side of lifted valid inequality */
3506  *liftrhs = alpha0;
3507 
3508  /* sequentially up-lifts all variables in F: */
3509  for( j = 0; j < nvarsF; j++ )
3510  {
3511  SCIP_Longint weight;
3512  int liftvar;
3513  int liftcoef;
3514  int z;
3515 
3516  liftvar = varsF[j];
3517  weight = weights[liftvar];
3518  assert(liftvar >= 0 && liftvar < nvars);
3519  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3520  assert(weight > 0);
3521 
3522  /* knapsack problem is infeasible:
3523  * sets z = 0
3524  */
3525  if( capacity - fixedonesweight - weight < 0 )
3526  {
3527  z = 0;
3528  }
3529  /* knapsack problem is feasible:
3530  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3531  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3532  */
3533  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3534  {
3535  z = *liftrhs;
3536  }
3537  /* knapsack problem is feasible:
3538  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3539  */
3540  else
3541  {
3542  int left;
3543  int right;
3544  int middle;
3545 
3546  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3547  left = 0;
3548  right = (*liftrhs) + 1;
3549  while( left < right - 1 )
3550  {
3551  middle = (left + right) / 2;
3552  assert(0 <= middle && middle < minweightslen);
3553  if( minweights[middle] <= capacity - fixedonesweight - weight )
3554  left = middle;
3555  else
3556  right = middle;
3557  }
3558  assert(left == right - 1);
3559  assert(0 <= left && left < minweightslen);
3560  assert(minweights[left] <= capacity - fixedonesweight - weight );
3561  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3562 
3563  /* now z = left */
3564  z = left;
3565  assert(z <= *liftrhs);
3566  }
3567 
3568  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3569  liftcoef = (*liftrhs) - z;
3570  liftcoefs[liftvar] = liftcoef;
3571  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3572 
3573  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3574  if( liftcoef == 0 )
3575  continue;
3576 
3577  /* updates activity of current valid inequality */
3578  (*cutact) += liftcoef * solvals[liftvar];
3579 
3580  /* enlarges current minweight table:
3581  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3582  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3583  * and sets minweights_i[w] = infinity for
3584  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3585  */
3586  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3587 
3588  /* updates minweight table: minweight_i+1[w] =
3589  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3590  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3591  */
3592  for( w = minweightslen - 1; w >= 0; w-- )
3593  {
3594  SCIP_Longint min;
3595  if( w < liftcoef )
3596  {
3597  min = MIN(minweights[w], weight);
3598  minweights[w] = min;
3599  }
3600  else
3601  {
3602  assert(w >= liftcoef);
3603  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3604  minweights[w] = min;
3605  }
3606  }
3607  }
3608  assert(minweights[0] == 0);
3609 
3610  /* sequentially down-lifts all variables in M_2: */
3611  for( j = 0; j < nvarsM2; j++ )
3612  {
3613  SCIP_Longint weight;
3614  int liftvar;
3615  int liftcoef;
3616  int left;
3617  int right;
3618  int middle;
3619  int z;
3620 
3621  liftvar = varsM2[j];
3622  weight = weights[liftvar];
3623  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3624  assert(liftvar >= 0 && liftvar < nvars);
3625  assert(weight > 0);
3626 
3627  /* uses binary search to find
3628  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3629  */
3630  left = 0;
3631  right = minweightslen;
3632  while( left < right - 1 )
3633  {
3634  middle = (left + right) / 2;
3635  assert(0 <= middle && middle < minweightslen);
3636  if( minweights[middle] <= capacity - fixedonesweight + weight )
3637  left = middle;
3638  else
3639  right = middle;
3640  }
3641  assert(left == right - 1);
3642  assert(0 <= left && left < minweightslen);
3643  assert(minweights[left] <= capacity - fixedonesweight + weight );
3644  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3645 
3646  /* now z = left */
3647  z = left;
3648  assert(z >= *liftrhs);
3649 
3650  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3651  liftcoef = z - (*liftrhs);
3652  liftcoefs[liftvar] = liftcoef;
3653  assert(liftcoef >= 0);
3654 
3655  /* updates sum of weights of variables fixed to one */
3656  fixedonesweight -= weight;
3657 
3658  /* updates right-hand side of current valid inequality */
3659  (*liftrhs) += liftcoef;
3660  assert(*liftrhs >= alpha0);
3661 
3662  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3663  if( liftcoef == 0 )
3664  continue;
3665 
3666  /* updates activity of current valid inequality */
3667  (*cutact) += liftcoef * solvals[liftvar];
3668 
3669  /* enlarges current minweight table:
3670  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3671  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3672  * and sets minweights_i[w] = infinity for
3673  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3674  */
3675  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3676 
3677  /* updates minweight table: minweight_i+1[w] =
3678  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3679  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3680  */
3681  for( w = minweightslen - 1; w >= 0; w-- )
3682  {
3683  SCIP_Longint min;
3684  if( w < liftcoef )
3685  {
3686  min = MIN(minweights[w], weight);
3687  minweights[w] = min;
3688  }
3689  else
3690  {
3691  assert(w >= liftcoef);
3692  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3693  minweights[w] = min;
3694  }
3695  }
3696  }
3697  assert(fixedonesweight == 0);
3698  assert(*liftrhs >= alpha0);
3699 
3700  /* sequentially up-lifts all variables in R: */
3701  for( j = 0; j < nvarsR; j++ )
3702  {
3703  SCIP_Longint weight;
3704  int liftvar;
3705  int liftcoef;
3706  int z;
3707 
3708  liftvar = varsR[j];
3709  weight = weights[liftvar];
3710  assert(liftvar >= 0 && liftvar < nvars);
3711  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3712  assert(weight > 0);
3713  assert(capacity - weight >= 0);
3714  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3715 
3716  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3717  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3718  */
3719  if( minweights[*liftrhs] <= capacity - weight )
3720  {
3721  z = *liftrhs;
3722  }
3723  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3724  */
3725  else
3726  {
3727  int left;
3728  int right;
3729  int middle;
3730 
3731  left = 0;
3732  right = (*liftrhs) + 1;
3733  while( left < right - 1)
3734  {
3735  middle = (left + right) / 2;
3736  assert(0 <= middle && middle < minweightslen);
3737  if( minweights[middle] <= capacity - weight )
3738  left = middle;
3739  else
3740  right = middle;
3741  }
3742  assert(left == right - 1);
3743  assert(0 <= left && left < minweightslen);
3744  assert(minweights[left] <= capacity - weight );
3745  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3746 
3747  /* now z = left */
3748  z = left;
3749  assert(z <= *liftrhs);
3750  }
3751 
3752  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3753  liftcoef = (*liftrhs) - z;
3754  liftcoefs[liftvar] = liftcoef;
3755  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3756 
3757  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3758  if( liftcoef == 0 )
3759  continue;
3760 
3761  /* updates activity of current valid inequality */
3762  (*cutact) += liftcoef * solvals[liftvar];
3763 
3764  /* updates minweight table: minweight_i+1[w] =
3765  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3766  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3767  */
3768  for( w = *liftrhs; w >= 0; w-- )
3769  {
3770  SCIP_Longint min;
3771  if( w < liftcoef )
3772  {
3773  min = MIN(minweights[w], weight);
3774  minweights[w] = min;
3775  }
3776  else
3777  {
3778  assert(w >= liftcoef);
3779  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3780  minweights[w] = min;
3781  }
3782  }
3783  }
3784 
3785  /* frees temporary memory */
3786  SCIPfreeBufferArray(scip, &sortkeys);
3787  SCIPfreeBufferArray(scip, &minweights);
3788 
3789  return SCIP_OKAY;
3790 }
3791 
3792 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3793 static
3795  SCIP_Longint val1, /**< first value to add */
3796  SCIP_Longint val2 /**< second value to add */
3797  )
3798 {
3799  assert(val1 >= 0);
3800  assert(val2 >= 0);
3801 
3802  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3803  return SCIP_LONGINT_MAX;
3804  else
3805  {
3806  assert(val1 <= SCIP_LONGINT_MAX - val2);
3807  return (val1 + val2);
3808  }
3809 }
3810 
3811 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3812 static
3814  SCIP_Longint* minweights, /**< minweight table to compute */
3815  SCIP_Longint* finished, /**< given finished table */
3816  SCIP_Longint* unfinished, /**< given unfinished table */
3817  int minweightslen /**< length of minweight, finished, and unfinished tables */
3818  )
3819 {
3820  int w1;
3821  int w2;
3822 
3823  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3824  * note that finished and unfished arrays sorted by non-decreasing weight
3825  */
3826 
3827  /* initialize minweight with w2 = 0 */
3828  w2 = 0;
3829  assert(unfinished[w2] == 0);
3830  for( w1 = 0; w1 < minweightslen; w1++ )
3831  minweights[w1] = finished[w1];
3832 
3833  /* consider w2 = 1, ..., minweightslen-1 */
3834  for( w2 = 1; w2 < minweightslen; w2++ )
3835  {
3836  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3837  break;
3838 
3839  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3840  {
3841  SCIP_Longint temp;
3842 
3843  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3844  if( temp <= minweights[w1+w2] )
3845  minweights[w1+w2] = temp;
3846  }
3847  }
3848 }
3849 
3850 /** lifts given inequality
3851  * sum_{j in C_1} x_j <= alpha_0
3852  * valid for
3853  * 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;
3854  * sum_{j in Q_i} x_j <= 1, forall i in I }
3855  * to a valid inequality
3856  * 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
3857  * <= alpha_0 + sum_{j in C_2} alpha_j
3858  * for
3859  * 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 };
3860  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3861  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3862  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3863  */
3864 static
3866  SCIP* scip, /**< SCIP data structure */
3867  SCIP_GUBSET* gubset, /**< GUB set data structure */
3868  SCIP_VAR** vars, /**< variables in knapsack constraint */
3869  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3870  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3871  SCIP_Longint capacity, /**< capacity of knapsack */
3872  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3873  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3874  int* gubconsGC2, /**< GUBs in GC2 */
3875  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3876  int* gubconsGR, /**< GUBs in GR */
3877  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3878  int ngubconsGC2, /**< number of GUBs in GC2 */
3879  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3880  int ngubconsGR, /**< number of GUBs in GR */
3881  int alpha0, /**< rights hand side of given valid inequality */
3882  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3883  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3884  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3885  int maxgubvarssize /**< maximal size of GUB constraints */
3886  )
3887 {
3888  SCIP_Longint* minweights;
3889  SCIP_Longint* finished;
3890  SCIP_Longint* unfinished;
3891  int* gubconsGOC1;
3892  int* gubconsGNC1;
3893  int* liftgubvars;
3894  SCIP_Longint fixedonesweight;
3895  SCIP_Longint weight;
3896  SCIP_Longint weightdiff1;
3897  SCIP_Longint weightdiff2;
3898  SCIP_Longint min;
3899  int minweightssize;
3900  int minweightslen;
3901  int nvars;
3902  int varidx;
3903  int liftgubconsidx;
3904  int liftvar;
3905  int sumliftcoef;
3906  int liftcoef;
3907  int ngubconsGOC1;
3908  int ngubconsGNC1;
3909  int left;
3910  int right;
3911  int middle;
3912  int nliftgubvars;
3913  int tmplen;
3914  int tmpsize;
3915  int j;
3916  int k;
3917  int w;
3918  int z;
3919 #ifndef NDEBUG
3920  int ngubconss;
3921  int nliftgubC1;
3922 
3923  assert(gubset != NULL);
3924  ngubconss = gubset->ngubconss;
3925 #else
3926  assert(gubset != NULL);
3927 #endif
3928 
3929  nvars = gubset->nvars;
3930 
3931  assert(scip != NULL);
3932  assert(vars != NULL);
3933  assert(nvars >= 0);
3934  assert(weights != NULL);
3935  assert(capacity >= 0);
3936  assert(solvals != NULL);
3937  assert(gubconsGC1 != NULL);
3938  assert(gubconsGC2 != NULL);
3939  assert(gubconsGFC1 != NULL);
3940  assert(gubconsGR != NULL);
3941  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3942  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3943  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3944  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3945  assert(alpha0 >= 0);
3946  assert(liftcoefs != NULL);
3947  assert(cutact != NULL);
3948  assert(liftrhs != NULL);
3949 
3950  minweightssize = ngubconsGC1+1;
3951 
3952  /* allocates temporary memory */
3953  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3954  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3955  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3956  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3957  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3958  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3959 
3960  /* initializes data structures */
3961  BMSclearMemoryArray(liftcoefs, nvars);
3962  *cutact = 0.0;
3963 
3964  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
3965  * valid inequality
3966  */
3967  ngubconsGOC1 = 0;
3968  ngubconsGNC1 = 0;
3969  for( j = 0; j < ngubconsGC1; j++ )
3970  {
3971  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
3972  {
3973  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
3974  ngubconsGOC1++;
3975  }
3976  else
3977  {
3978  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3979  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
3980  ngubconsGNC1++;
3981  }
3982  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
3983  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
3984  {
3985  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
3986  assert(varidx >= 0 && varidx < nvars);
3987  assert(liftcoefs[varidx] == 0);
3988 
3989  liftcoefs[varidx] = 1;
3990  (*cutact) += solvals[varidx];
3991  }
3992  assert(k >= 1);
3993  }
3994  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
3995  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
3996 
3997  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
3998  * - finished_i[w] =
3999  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4000  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4001  * sum_{j in Q_k} x_j <= 1
4002  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4003  * - unfinished_i[w] =
4004  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4005  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4006  * sum_{j in Q_k} x_j <= 1
4007  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4008  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4009  */
4010 
4011  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4012  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4013  * 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
4014  * comes from the first variable in the GUB
4015  */
4016  assert(ngubconsGOC1 <= ngubconsGC1);
4017  finished[0] = 0;
4018  for( w = 1; w <= ngubconsGOC1; w++ )
4019  {
4020  liftgubconsidx = gubconsGOC1[w-1];
4021 
4022  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4023  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4024 
4025  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4026 
4027  assert(varidx >= 0 && varidx < nvars);
4028  assert(liftcoefs[varidx] == 1);
4029 
4030  min = weights[varidx];
4031  finished[w] = finished[w-1] + min;
4032 
4033 #ifndef NDEBUG
4034  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4035  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4036  {
4037  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4038  assert(varidx >= 0 && varidx < nvars);
4039  assert(liftcoefs[varidx] == 1);
4040  assert(weights[varidx] >= min);
4041  }
4042 #endif
4043  }
4044  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4045  finished[w] = SCIP_LONGINT_MAX;
4046 
4047  /* initialize unfinished table; note that variables in GNC1 GUBs
4048  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4049  * 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
4050  * comes from the first variable in the GUB
4051  */
4052  assert(ngubconsGNC1 <= ngubconsGC1);
4053  unfinished[0] = 0;
4054  for( w = 1; w <= ngubconsGNC1; w++ )
4055  {
4056  liftgubconsidx = gubconsGNC1[w-1];
4057 
4058  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4059  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4060 
4061  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4062 
4063  assert(varidx >= 0 && varidx < nvars);
4064  assert(liftcoefs[varidx] == 1);
4065 
4066  min = weights[varidx];
4067  unfinished[w] = unfinished[w-1] + min;
4068 
4069 #ifndef NDEBUG
4070  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4071  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4072  {
4073  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4074  assert(varidx >= 0 && varidx < nvars);
4075  assert(liftcoefs[varidx] == 1);
4076  assert(weights[varidx] >= min );
4077  }
4078 #endif
4079  }
4080  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4081  unfinished[w] = SCIP_LONGINT_MAX;
4082 
4083  /* initialize minweights table; note that variables in GC1 GUBs
4084  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4085  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4086  * consuming) because is it has to be build using weights from C1 only.
4087  */
4088  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4089  minweights[0] = 0;
4090  for( w = 1; w <= ngubconsGC1; w++ )
4091  {
4092  liftgubconsidx = gubconsGC1[w-1];
4093 
4094  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4095  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4096  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4097 
4098  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4099 
4100  assert(varidx >= 0 && varidx < nvars);
4101  assert(liftcoefs[varidx] == 1);
4102 
4103  min = weights[varidx];
4104  minweights[w] = minweights[w-1] + min;
4105 
4106 #ifndef NDEBUG
4107  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4108  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4109  {
4110  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4111  assert(varidx >= 0 && varidx < nvars);
4112  assert(liftcoefs[varidx] == 1);
4113  assert(weights[varidx] >= min);
4114  }
4115 #endif
4116  }
4117  minweightslen = ngubconsGC1 + 1;
4118 
4119  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4120  fixedonesweight = 0;
4121  for( j = 0; j < ngubconsGC2; j++ )
4122  {
4123  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4124 
4125  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4126  assert(varidx >= 0 && varidx < nvars);
4127  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4128 
4129  fixedonesweight += weights[varidx];
4130  }
4131  assert(fixedonesweight >= 0);
4132 
4133  /* initializes right hand side of lifted valid inequality */
4134  *liftrhs = alpha0;
4135 
4136  /* sequentially up-lifts all variables in GFC1 GUBs */
4137  for( j = 0; j < ngubconsGFC1; j++ )
4138  {
4139  liftgubconsidx = gubconsGFC1[j];
4140  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4141 
4142  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4143  * compute minweight table via updated unfinished table and aleady upto date finished table;
4144  */
4145  k = 0;
4146  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4147  {
4148  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4149  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4150  assert(ngubconsGNC1 > 0);
4151 
4152  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4153  * are considered for the lifting, i.e., not capacity exceeding
4154  */
4155  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4156  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4157  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4158  assert(k >= 1);
4159 
4160  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4161  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4162  */
4163  weight = weights[liftgubvars[0]];
4164 
4165  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4166  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4167  for( w = ngubconsGNC1-1; w >= 1; w-- )
4168  {
4169  weightdiff1 = weightdiff2;
4170  weightdiff2 = unfinished[w] - weight;
4171 
4172  if( unfinished[w] < weightdiff1 )
4173  unfinished[w] = weightdiff1;
4174  else
4175  break;
4176  }
4177  ngubconsGNC1--;
4178 
4179  /* computes minweights table by combining unfished and fished tables */
4180  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4181  assert(minweights[0] == 0);
4182  }
4183  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4184  * are therefore not in the unfinished table
4185  */
4186  else
4187  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4188 
4189 #ifndef NDEBUG
4190  nliftgubC1 = k;
4191 #endif
4192  nliftgubvars = k;
4193  sumliftcoef = 0;
4194 
4195  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4196  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4197  {
4198  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4199  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4200  {
4201  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4202  weight = weights[liftvar];
4203  assert(weight > 0);
4204  assert(liftvar >= 0 && liftvar < nvars);
4205  assert(capacity - weight >= 0);
4206 
4207  /* put variable into array of variables in GUB that are considered for the lifting,
4208  * i.e., not capacity exceeding
4209  */
4210  liftgubvars[nliftgubvars] = liftvar;
4211  nliftgubvars++;
4212 
4213  /* knapsack problem is infeasible:
4214  * sets z = 0
4215  */
4216  if( capacity - fixedonesweight - weight < 0 )
4217  {
4218  z = 0;
4219  }
4220  /* knapsack problem is feasible:
4221  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4222  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4223  */
4224  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4225  {
4226  z = *liftrhs;
4227  }
4228  /* knapsack problem is feasible:
4229  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4230  */
4231  else
4232  {
4233  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4234  left = 0;
4235  right = (*liftrhs) + 1;
4236  while( left < right - 1 )
4237  {
4238  middle = (left + right) / 2;
4239  assert(0 <= middle && middle < minweightslen);
4240  if( minweights[middle] <= capacity - fixedonesweight - weight )
4241  left = middle;
4242  else
4243  right = middle;
4244  }
4245  assert(left == right - 1);
4246  assert(0 <= left && left < minweightslen);
4247  assert(minweights[left] <= capacity - fixedonesweight - weight);
4248  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4249 
4250  /* now z = left */
4251  z = left;
4252  assert(z <= *liftrhs);
4253  }
4254 
4255  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4256  liftcoef = (*liftrhs) - z;
4257  liftcoefs[liftvar] = liftcoef;
4258  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4259 
4260  /* updates activity of current valid inequality */
4261  (*cutact) += liftcoef * solvals[liftvar];
4262 
4263  /* updates sum of all lifting coefficients in GUB */
4264  sumliftcoef += liftcoefs[liftvar];
4265  }
4266  else
4267  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4268  }
4269  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4270  assert(nliftgubvars > nliftgubC1);
4271 
4272  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4273  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4274  * not needed for GF GUBs
4275  */
4276  if( sumliftcoef == 0 )
4277  {
4278  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4279  {
4280  weight = weights[liftgubvars[0]];
4281  /* update finished table and minweights table by applying special case of
4282  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4283  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4284  */
4285  for( w = minweightslen-1; w >= 1; w-- )
4286  {
4287  SCIP_Longint tmpval;
4288 
4289  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4290  finished[w] = MIN(finished[w], tmpval);
4291 
4292  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4293  minweights[w] = MIN(minweights[w], tmpval);
4294  }
4295  }
4296  else
4297  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4298 
4299  continue;
4300  }
4301 
4302  /* enlarges current minweights tables(finished, unfinished, minweights):
4303  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4304  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4305  * and sets minweights_i[w] = infinity for
4306  * 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
4307  */
4308  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4309  tmpsize = minweightssize;
4310  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4311  tmplen = minweightslen;
4312  tmpsize = minweightssize;
4313  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4314  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4315 
4316  /* update finished table and minweight table;
4317  * note that instead of computing minweight table from updated finished and updated unfinished table again
4318  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4319  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4320  * not needed because only finished table changed at this point and the change was "adding" one weight)
4321  *
4322  * update formular for minweight table is: minweight_i+1[w] =
4323  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4324  * formular for finished table has the same pattern.
4325  */
4326  for( w = minweightslen-1; w >= 0; w-- )
4327  {
4328  SCIP_Longint minminweight;
4329  SCIP_Longint minfinished;
4330 
4331  for( k = 0; k < nliftgubvars; k++ )
4332  {
4333  liftcoef = liftcoefs[liftgubvars[k]];
4334  weight = weights[liftgubvars[k]];
4335 
4336  if( w < liftcoef )
4337  {
4338  minfinished = MIN(finished[w], weight);
4339  minminweight = MIN(minweights[w], weight);
4340 
4341  finished[w] = minfinished;
4342  minweights[w] = minminweight;
4343  }
4344  else
4345  {
4346  SCIP_Longint tmpval;
4347 
4348  assert(w >= liftcoef);
4349 
4350  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4351  minfinished = MIN(finished[w], tmpval);
4352 
4353  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4354  minminweight = MIN(minweights[w], tmpval);
4355 
4356  finished[w] = minfinished;
4357  minweights[w] = minminweight;
4358  }
4359  }
4360  }
4361  assert(minweights[0] == 0);
4362  }
4363  assert(ngubconsGNC1 == 0);
4364 
4365  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4366  * therefore, only work with minweight table from here on
4367  */
4368 
4369  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4370  for( j = 0; j < ngubconsGC2; j++ )
4371  {
4372  liftgubconsidx = gubconsGC2[j];
4373 
4374  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4375  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4376  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4377  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4378 
4379  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4380  weight = weights[liftvar];
4381 
4382  assert(liftvar >= 0 && liftvar < nvars);
4383  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4384  assert(weight > 0);
4385 
4386  /* uses binary search to find
4387  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4388  */
4389  left = 0;
4390  right = minweightslen;
4391  while( left < right - 1 )
4392  {
4393  middle = (left + right) / 2;
4394  assert(0 <= middle && middle < minweightslen);
4395  if( minweights[middle] <= capacity - fixedonesweight + weight )
4396  left = middle;
4397  else
4398  right = middle;
4399  }
4400  assert(left == right - 1);
4401  assert(0 <= left && left < minweightslen);
4402  assert(minweights[left] <= capacity - fixedonesweight + weight);
4403  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4404 
4405  /* now z = left */
4406  z = left;
4407  assert(z >= *liftrhs);
4408 
4409  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4410  liftcoef = z - (*liftrhs);
4411  liftcoefs[liftvar] = liftcoef;
4412  assert(liftcoef >= 0);
4413 
4414  /* updates sum of weights of variables fixed to one */
4415  fixedonesweight -= weight;
4416 
4417  /* updates right-hand side of current valid inequality */
4418  (*liftrhs) += liftcoef;
4419  assert(*liftrhs >= alpha0);
4420 
4421  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4422  if( liftcoef == 0 )
4423  continue;
4424 
4425  /* updates activity of current valid inequality */
4426  (*cutact) += liftcoef * solvals[liftvar];
4427 
4428  /* enlarges current minweight table:
4429  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4430  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4431  * and sets minweights_i[w] = infinity for
4432  * 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
4433  */
4434  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4435 
4436  /* updates minweight table: minweight_i+1[w] =
4437  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4438  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4439  */
4440  for( w = minweightslen - 1; w >= 0; w-- )
4441  {
4442  if( w < liftcoef )
4443  {
4444  min = MIN(minweights[w], weight);
4445  minweights[w] = min;
4446  }
4447  else
4448  {
4449  SCIP_Longint tmpval;
4450 
4451  assert(w >= liftcoef);
4452 
4453  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4454  min = MIN(minweights[w], tmpval);
4455  minweights[w] = min;
4456  }
4457  }
4458  }
4459  assert(fixedonesweight == 0);
4460  assert(*liftrhs >= alpha0);
4461 
4462  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4463  for( j = 0; j < ngubconsGR; j++ )
4464  {
4465  liftgubconsidx = gubconsGR[j];
4466 
4467  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4468  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4469 
4470  sumliftcoef = 0;
4471  nliftgubvars = 0;
4472  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4473  {
4474  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4475  {
4476  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4477  weight = weights[liftvar];
4478  assert(weight > 0);
4479  assert(liftvar >= 0 && liftvar < nvars);
4480  assert(capacity - weight >= 0);
4481  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4482 
4483  /* put variable into array of variables in GUB that are considered for the lifting,
4484  * i.e., not capacity exceeding
4485  */
4486  liftgubvars[nliftgubvars] = liftvar;
4487  nliftgubvars++;
4488 
4489  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4490  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4491  */
4492  if( minweights[*liftrhs] <= capacity - weight )
4493  {
4494  z = *liftrhs;
4495  }
4496  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4497  */
4498  else
4499  {
4500  left = 0;
4501  right = (*liftrhs) + 1;
4502  while( left < right - 1 )
4503  {
4504  middle = (left + right) / 2;
4505  assert(0 <= middle && middle < minweightslen);
4506  if( minweights[middle] <= capacity - weight )
4507  left = middle;
4508  else
4509  right = middle;
4510  }
4511  assert(left == right - 1);
4512  assert(0 <= left && left < minweightslen);
4513  assert(minweights[left] <= capacity - weight);
4514  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4515 
4516  /* now z = left */
4517  z = left;
4518  assert(z <= *liftrhs);
4519  }
4520  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4521  liftcoef = (*liftrhs) - z;
4522  liftcoefs[liftvar] = liftcoef;
4523  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4524 
4525  /* updates activity of current valid inequality */
4526  (*cutact) += liftcoef * solvals[liftvar];
4527 
4528  /* updates sum of all lifting coefficients in GUB */
4529  sumliftcoef += liftcoefs[liftvar];
4530  }
4531  else
4532  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4533  }
4534  assert(nliftgubvars >= 1); /* at least one variable is in R */
4535 
4536  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4537  if( sumliftcoef == 0 )
4538  continue;
4539 
4540  /* updates minweight table: minweight_i+1[w] =
4541  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4542  */
4543  for( w = *liftrhs; w >= 0; w-- )
4544  {
4545  for( k = 0; k < nliftgubvars; k++ )
4546  {
4547  liftcoef = liftcoefs[liftgubvars[k]];
4548  weight = weights[liftgubvars[k]];
4549 
4550  if( w < liftcoef )
4551  {
4552  min = MIN(minweights[w], weight);
4553  minweights[w] = min;
4554  }
4555  else
4556  {
4557  SCIP_Longint tmpval;
4558 
4559  assert(w >= liftcoef);
4560 
4561  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4562  min = MIN(minweights[w], tmpval);
4563  minweights[w] = min;
4564  }
4565  }
4566  }
4567  assert(minweights[0] == 0);
4568  }
4569 
4570  /* frees temporary memory */
4571  SCIPfreeBufferArray(scip, &minweights);
4572  SCIPfreeBufferArray(scip, &finished);
4573  SCIPfreeBufferArray(scip, &unfinished);
4574  SCIPfreeBufferArray(scip, &liftgubvars);
4575  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4576  SCIPfreeBufferArray(scip, &gubconsGNC1);
4577 
4578  return SCIP_OKAY;
4579 }
4580 
4581 /** lifts given minimal cover inequality
4582  * \f[
4583  * \sum_{j \in C} x_j \leq |C| - 1
4584  * \f]
4585  * valid for
4586  * \f[
4587  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4588  * \f]
4589  * to a valid inequality
4590  * \f[
4591  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4592  * \f]
4593  * for
4594  * \f[
4595  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4596  * \f]
4597  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4598  */
4599 static
4601  SCIP* scip, /**< SCIP data structure */
4602  SCIP_VAR** vars, /**< variables in knapsack constraint */
4603  int nvars, /**< number of variables in knapsack constraint */
4604  int ntightened, /**< number of variables with tightened upper bound */
4605  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4606  SCIP_Longint capacity, /**< capacity of knapsack */
4607  SCIP_Real* solvals, /**< solution values of all problem variables */
4608  int* covervars, /**< cover variables */
4609  int* noncovervars, /**< noncover variables */
4610  int ncovervars, /**< number of cover variables */
4611  int nnoncovervars, /**< number of noncover variables */
4612  SCIP_Longint coverweight, /**< weight of cover */
4613  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4614  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4615  )
4616 {
4617  SCIP_Longint* maxweightsums;
4618  SCIP_Longint* intervalends;
4619  SCIP_Longint* rhos;
4620  SCIP_Real* sortkeys;
4621  SCIP_Longint lambda;
4622  int j;
4623  int h;
4624 
4625  assert(scip != NULL);
4626  assert(vars != NULL);
4627  assert(nvars >= 0);
4628  assert(weights != NULL);
4629  assert(capacity >= 0);
4630  assert(solvals != NULL);
4631  assert(covervars != NULL);
4632  assert(noncovervars != NULL);
4633  assert(ncovervars > 0 && ncovervars <= nvars);
4634  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4635  assert(ncovervars + nnoncovervars == nvars - ntightened);
4636  assert(liftcoefs != NULL);
4637  assert(cutact != NULL);
4638 
4639  /* allocates temporary memory */
4640  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4641  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4642  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4643  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4644 
4645  /* initializes data structures */
4646  BMSclearMemoryArray(liftcoefs, nvars);
4647  *cutact = 0.0;
4648 
4649  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4650  * and calculates activity of current valid inequality
4651  */
4652  for( j = 0; j < ncovervars; j++ )
4653  {
4654  assert(liftcoefs[covervars[j]] == 0.0);
4655  liftcoefs[covervars[j]] = 1.0;
4656  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4657  (*cutact) += solvals[covervars[j]];
4658  }
4659  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4660 
4661  /* calculates weight excess of cover C */
4662  lambda = coverweight - capacity;
4663  assert(lambda > 0);
4664 
4665  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4666  maxweightsums[0] = 0;
4667  for( h = 1; h <= ncovervars; h++ )
4668  {
4669  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4670  intervalends[h-1] = maxweightsums[h] - lambda;
4671  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4672  }
4673 
4674  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4675  for( j = 0; j < nnoncovervars; j++ )
4676  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4677  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4678 
4679  /* calculates lifting coefficient for all variables in N\C */
4680  h = 0;
4681  for( j = 0; j < nnoncovervars; j++ )
4682  {
4683  int liftvar;
4684  SCIP_Longint weight;
4685  SCIP_Real liftcoef;
4686 
4687  liftvar = noncovervars[j];
4688  weight = weights[liftvar];
4689 
4690  while( intervalends[h] < weight )
4691  h++;
4692 
4693  if( h == 0 )
4694  liftcoef = h;
4695  else
4696  {
4697  if( weight <= intervalends[h-1] + rhos[h] )
4698  {
4699  SCIP_Real tmp1;
4700  SCIP_Real tmp2;
4701  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4702  tmp2 = (SCIP_Real) rhos[1];
4703  liftcoef = h - ( tmp1 / tmp2 );
4704  }
4705  else
4706  liftcoef = h;
4707  }
4708 
4709  /* sets lifting coefficient */
4710  assert(liftcoefs[liftvar] == 0.0);
4711  liftcoefs[liftvar] = liftcoef;
4712 
4713  /* updates activity of current valid inequality */
4714  (*cutact) += liftcoef * solvals[liftvar];
4715  }
4716 
4717  /* frees temporary memory */
4718  SCIPfreeBufferArray(scip, &rhos);
4719  SCIPfreeBufferArray(scip, &intervalends);
4720  SCIPfreeBufferArray(scip, &maxweightsums);
4721  SCIPfreeBufferArray(scip, &sortkeys);
4722 
4723  return SCIP_OKAY;
4724 }
4725 
4726 
4727 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4728  * given knapsack problem
4729 */
4730 static
4732  SCIP* scip, /**< SCIP data structure */
4733  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4734  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4735  SCIP_VAR** vars, /**< variables in knapsack constraint */
4736  int nvars, /**< number of variables in knapsack constraint */
4737  int ntightened, /**< number of variables with tightened upper bound */
4738  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4739  SCIP_Longint capacity, /**< capacity of knapsack */
4740  SCIP_Real* solvals, /**< solution values of all problem variables */
4741  int* mincovervars, /**< mincover variables */
4742  int* nonmincovervars, /**< nonmincover variables */
4743  int nmincovervars, /**< number of mincover variables */
4744  int nnonmincovervars, /**< number of nonmincover variables */
4745  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4746  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4747  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4748  int* ncuts /**< pointer to add up the number of found cuts */
4749  )
4750 {
4751  int* varsC1;
4752  int* varsC2;
4753  int* varsF;
4754  int* varsR;
4755  int nvarsC1;
4756  int nvarsC2;
4757  int nvarsF;
4758  int nvarsR;
4759  SCIP_Real cutact;
4760  int* liftcoefs;
4761  int liftrhs;
4762 
4763  assert( cutoff != NULL );
4764  *cutoff = FALSE;
4765 
4766  /* allocates temporary memory */
4767  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4768  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4769  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4770  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4771  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4772 
4773  /* 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
4774  * as follows
4775  * C_2 = { j in C : x*_j = 1 } and
4776  * C_1 = C\C_2
4777  */
4778  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4779  assert(nvarsC1 + nvarsC2 == nmincovervars);
4780  assert(nmincovervars > 0);
4781  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4782 
4783  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4784  if( nvarsC1 < 2 && nvarsC2 > 0)
4785  {
4786  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4787  assert(nvarsC1 >= 1);
4788  }
4789  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4790 
4791  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4792  * R = { j in N\C : x*_j = 0 } and
4793  * F = (N\C)\F
4794  */
4795  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4796  assert(nvarsF + nvarsR == nnonmincovervars);
4797  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4798 
4799  /* lift cuts without GUB information */
4800  if( gubset == NULL )
4801  {
4802  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4803  * lifting procedure
4804  */
4805  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4806 
4807  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4808  *
4809  * 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 }
4810  *
4811  * 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
4812  *
4813  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4814  *
4815  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4816  * up-lifting for the variables in R according to the second level lifting sequence
4817  */
4818  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4819  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4820  }
4821  /* lift cuts with GUB information */
4822  else
4823  {
4824  int* gubconsGC1;
4825  int* gubconsGC2;
4826  int* gubconsGFC1;
4827  int* gubconsGR;
4828  int ngubconsGC1;
4829  int ngubconsGC2;
4830  int ngubconsGFC1;
4831  int ngubconsGR;
4832  int ngubconss;
4833  int nconstightened;
4834  int maxgubvarssize;
4835 
4836  assert(nvars == gubset->nvars);
4837 
4838  ngubconsGC1 = 0;
4839  ngubconsGC2 = 0;
4840  ngubconsGFC1 = 0;
4841  ngubconsGR = 0;
4842  ngubconss = gubset->ngubconss;
4843  nconstightened = 0;
4844  maxgubvarssize = 0;
4845 
4846  /* allocates temporary memory */
4847  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4848  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4849  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4850  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4851 
4852  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4853  * the GUBs for the sequential GUB wise lifting procedure
4854  */
4855  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4856  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4857  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4858 
4859  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4860  *
4861  * 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,
4862  * sum_{j in Q_i} x_j <= 1, forall i in I }
4863  *
4864  * 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
4865  *
4866  * 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 },
4867  *
4868  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4869  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4870  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4871  */
4872  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4873  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4874  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4875 
4876  /* frees temporary memory */
4877  SCIPfreeBufferArray(scip, &gubconsGR);
4878  SCIPfreeBufferArray(scip, &gubconsGFC1);
4879  SCIPfreeBufferArray(scip, &gubconsGC2);
4880  SCIPfreeBufferArray(scip, &gubconsGC1);
4881  }
4882 
4883  /* checks, if lifting yielded a violated cut */
4884  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4885  {
4886  SCIP_ROW* row;
4887  char name[SCIP_MAXSTRLEN];
4888  int j;
4889 
4890  /* creates LP row */
4891  assert( cons == NULL || sepa == NULL );
4892  if ( cons != NULL )
4893  {
4894  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4895  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4896  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4897  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4898  }
4899  else if ( sepa != NULL )
4900  {
4901  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4902  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4903  }
4904  else
4905  {
4906  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
4907  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4908  }
4909 
4910  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4911  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4912  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4913  for( j = 0; j < nvarsC1; j++ )
4914  {
4915  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4916  }
4917  for( j = 0; j < nvarsC2; j++ )
4918  {
4919  if( liftcoefs[varsC2[j]] > 0 )
4920  {
4921  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4922  }
4923  }
4924  for( j = 0; j < nvarsF; j++ )
4925  {
4926  if( liftcoefs[varsF[j]] > 0 )
4927  {
4928  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4929  }
4930  }
4931  for( j = 0; j < nvarsR; j++ )
4932  {
4933  if( liftcoefs[varsR[j]] > 0 )
4934  {
4935  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4936  }
4937  }
4938  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4939 
4940  /* checks, if cut is violated enough */
4941  if( SCIPisCutEfficacious(scip, sol, row) )
4942  {
4943  if( cons != NULL )
4944  {
4945  SCIP_CALL( SCIPresetConsAge(scip, cons) );
4946  }
4947  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
4948  (*ncuts)++;
4949  }
4950  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4951  }
4952 
4953  /* frees temporary memory */
4954  SCIPfreeBufferArray(scip, &liftcoefs);
4955  SCIPfreeBufferArray(scip, &varsR);
4956  SCIPfreeBufferArray(scip, &varsF);
4957  SCIPfreeBufferArray(scip, &varsC2);
4958  SCIPfreeBufferArray(scip, &varsC1);
4959 
4960  return SCIP_OKAY;
4961 }
4962 
4963 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
4964 static
4966  SCIP* scip, /**< SCIP data structure */
4967  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
4968  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4969  SCIP_VAR** vars, /**< variables in knapsack constraint */
4970  int nvars, /**< number of variables in knapsack constraint */
4971  int ntightened, /**< number of variables with tightened upper bound */
4972  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4973  SCIP_Longint capacity, /**< capacity of knapsack */
4974  SCIP_Real* solvals, /**< solution values of all problem variables */
4975  int* feassetvars, /**< variables in feasible set */
4976  int* nonfeassetvars, /**< variables not in feasible set */
4977  int nfeassetvars, /**< number of variables in feasible set */
4978  int nnonfeassetvars, /**< number of variables not in feasible set */
4979  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4980  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
4981  int* ncuts /**< pointer to add up the number of found cuts */
4982  )
4983 {
4984  int* varsT1;
4985  int* varsT2;
4986  int* varsF;
4987  int* varsR;
4988  int* liftcoefs;
4989  SCIP_Real cutact;
4990  int nvarsT1;
4991  int nvarsT2;
4992  int nvarsF;
4993  int nvarsR;
4994  int liftrhs;
4995  int j;
4996 
4997  assert( cutoff != NULL );
4998  *cutoff = FALSE;
4999 
5000  /* allocates temporary memory */
5001  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5002  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5003  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5004  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5005  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5006 
5007  /* 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
5008  * as follows
5009  * T_2 = { j in T : x*_j = 1 } and
5010  * T_1 = T\T_2
5011  */
5012  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5013  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5014 
5015  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5016  if( nvarsT1 == 0 && nvarsT2 > 0)
5017  {
5018  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5019  assert(nvarsT1 == 1);
5020  }
5021  assert(nvarsT2 == 0 || nvarsT1 > 0);
5022 
5023  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5024  * R = { j in N\T : x*_j = 0 } and
5025  * F = (N\T)\F
5026  */
5027  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5028  assert(nvarsF + nvarsR == nnonfeassetvars);
5029  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5030 
5031  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5032  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5033  * is included in the sorting routine)
5034  */
5035  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5036 
5037  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5038  *
5039  * 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 }
5040  *
5041  * 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
5042  *
5043  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5044  *
5045  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5046  * up-lifting for the variabels in R according to the second level lifting sequence
5047  */
5048  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5049  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5050 
5051  /* checks, if lifting yielded a violated cut */
5052  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5053  {
5054  SCIP_ROW* row;
5055  char name[SCIP_MAXSTRLEN];
5056 
5057  /* creates LP row */
5058  assert( cons == NULL || sepa == NULL );
5059  if( cons != NULL )
5060  {
5061  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5062  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5063  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5064  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5065  }
5066  else if ( sepa != NULL )
5067  {
5068  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5069  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5070  }
5071  else
5072  {
5073  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
5074  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5075  }
5076 
5077  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5078  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5079  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5080  for( j = 0; j < nvarsT1; j++ )
5081  {
5082  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5083  }
5084  for( j = 0; j < nvarsT2; j++ )
5085  {
5086  if( liftcoefs[varsT2[j]] > 0 )
5087  {
5088  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5089  }
5090  }
5091  for( j = 0; j < nvarsF; j++ )
5092  {
5093  if( liftcoefs[varsF[j]] > 0 )
5094  {
5095  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5096  }
5097  }
5098  for( j = 0; j < nvarsR; j++ )
5099  {
5100  if( liftcoefs[varsR[j]] > 0 )
5101  {
5102  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5103  }
5104  }
5105  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5106 
5107  /* checks, if cut is violated enough */
5108  if( SCIPisCutEfficacious(scip, sol, row) )
5109  {
5110  if( cons != NULL )
5111  {
5112  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5113  }
5114  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5115  (*ncuts)++;
5116  }
5117  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5118  }
5119 
5120  /* frees temporary memory */
5121  SCIPfreeBufferArray(scip, &liftcoefs);
5122  SCIPfreeBufferArray(scip, &varsR);
5123  SCIPfreeBufferArray(scip, &varsF);
5124  SCIPfreeBufferArray(scip, &varsT2);
5125  SCIPfreeBufferArray(scip, &varsT1);
5126 
5127  return SCIP_OKAY;
5128 }
5129 
5130 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5131 static
5133  SCIP* scip, /**< SCIP data structure */
5134  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5135  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5136  SCIP_VAR** vars, /**< variables in knapsack constraint */
5137  int nvars, /**< number of variables in knapsack constraint */
5138  int ntightened, /**< number of variables with tightened upper bound */
5139  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5140  SCIP_Longint capacity, /**< capacity of knapsack */
5141  SCIP_Real* solvals, /**< solution values of all problem variables */
5142  int* mincovervars, /**< mincover variables */
5143  int* nonmincovervars, /**< nonmincover variables */
5144  int nmincovervars, /**< number of mincover variables */
5145  int nnonmincovervars, /**< number of nonmincover variables */
5146  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5147  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5148  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5149  int* ncuts /**< pointer to add up the number of found cuts */
5150  )
5151 {
5152  SCIP_Real* realliftcoefs;
5153  SCIP_Real cutact;
5154  int liftrhs;
5155 
5156  assert( cutoff != NULL );
5157  *cutoff = FALSE;
5158  cutact = 0.0;
5159 
5160  /* allocates temporary memory */
5161  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5162 
5163  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5164  *
5165  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5166  *
5167  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5168  *
5169  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5170  *
5171  * uses superadditive up-lifting for the variables in N\C.
5172  */
5173  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5174  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5175  liftrhs = nmincovervars - 1;
5176 
5177  /* checks, if lifting yielded a violated cut */
5178  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5179  {
5180  SCIP_ROW* row;
5181  char name[SCIP_MAXSTRLEN];
5182  int j;
5183 
5184  /* creates LP row */
5185  assert( cons == NULL || sepa == NULL );
5186  if ( cons != NULL )
5187  {
5188  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5189  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5190  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5191  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5192  }
5193  else if ( sepa != NULL )
5194  {
5195  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5196  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5197  }
5198  else
5199  {
5200  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%" SCIP_LONGINT_FORMAT "", *ncuts);
5201  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5202  }
5203 
5204  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5205  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5206  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5207  for( j = 0; j < nmincovervars; j++ )
5208  {
5209  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5210  }
5211  for( j = 0; j < nnonmincovervars; j++ )
5212  {
5213  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5214  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5215  {
5216  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5217  }
5218  }
5219  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5220 
5221  /* checks, if cut is violated enough */
5222  if( SCIPisCutEfficacious(scip, sol, row) )
5223  {
5224  if( cons != NULL )
5225  {
5226  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5227  }
5228  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5229  (*ncuts)++;
5230  }
5231  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5232  }
5233 
5234  /* frees temporary memory */
5235  SCIPfreeBufferArray(scip, &realliftcoefs);
5236 
5237  return SCIP_OKAY;
5238 }
5239 
5240 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5241  * 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
5242  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5243  * note that all variables with x*_j = 1 will be removed last
5244  */
5245 static
5247  SCIP* scip, /**< SCIP data structure */
5248  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5249  SCIP_Longint capacity, /**< capacity of knapsack */
5250  SCIP_Real* solvals, /**< solution values of all problem variables */
5251  int* covervars, /**< pointer to store cover variables */
5252  int* noncovervars, /**< pointer to store noncover variables */
5253  int* ncovervars, /**< pointer to store number of cover variables */
5254  int* nnoncovervars, /**< pointer to store number of noncover variables */
5255  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5256  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5257  )
5258 {
5259  SORTKEYPAIR** sortkeypairs;
5260  SORTKEYPAIR** sortkeypairssorted;
5261  SCIP_Longint minweight;
5262  int nsortkeypairs;
5263  int minweightidx;
5264  int j;
5265  int k;
5266 
5267  assert(scip != NULL);
5268  assert(covervars != NULL);
5269  assert(noncovervars != NULL);
5270  assert(ncovervars != NULL);
5271  assert(*ncovervars > 0);
5272  assert(nnoncovervars != NULL);
5273  assert(*nnoncovervars >= 0);
5274  assert(coverweight != NULL);
5275  assert(*coverweight > 0);
5276  assert(*coverweight > capacity);
5277 
5278  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5279  * order */
5280  nsortkeypairs = *ncovervars;
5281  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5282  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5283 
5284  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5285  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5286  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5287  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5288  */
5289  assert(*ncovervars == nsortkeypairs);
5290  if( modtransused )
5291  {
5292  for( j = 0; j < *ncovervars; j++ )
5293  {
5294  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5295  sortkeypairssorted[j] = sortkeypairs[j];
5296 
5297  sortkeypairs[j]->key1 = solvals[covervars[j]];
5298  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5299  }
5300  }
5301  else
5302  {
5303  for( j = 0; j < *ncovervars; j++ )
5304  {
5305  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5306  sortkeypairssorted[j] = sortkeypairs[j];
5307 
5308  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5309  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5310  }
5311  }
5312  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5313 
5314  /* gets j' with a_j' = min{ a_j : j in C } */
5315  minweightidx = 0;
5316  minweight = weights[covervars[minweightidx]];
5317  for( j = 1; j < *ncovervars; j++ )
5318  {
5319  if( weights[covervars[j]] <= minweight )
5320  {
5321  minweightidx = j;
5322  minweight = weights[covervars[minweightidx]];
5323  }
5324  }
5325  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5326  assert(minweight > 0 && minweight <= *coverweight);
5327 
5328  j = 0;
5329  /* removes variables from C until the remaining variables form a minimal cover */
5330  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5331  {
5332  assert(minweightidx >= j);
5333  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5334 
5335  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5336  if( (*coverweight) - weights[covervars[j]] <= capacity )
5337  {
5338  ++j;
5339  continue;
5340  }
5341 
5342  /* adds j to N\C */
5343  noncovervars[*nnoncovervars] = covervars[j];
5344  (*nnoncovervars)++;
5345 
5346  /* removes j from C */
5347  (*coverweight) -= weights[covervars[j]];
5348  for( k = j; k < (*ncovervars) - 1; k++ )
5349  covervars[k] = covervars[k+1];
5350  (*ncovervars)--;
5351 
5352  /* updates j' with a_j' = min{ a_j : j in C } */
5353  if( j == minweightidx )
5354  {
5355  minweightidx = 0;
5356  minweight = weights[covervars[minweightidx]];
5357  for( k = 1; k < *ncovervars; k++ )
5358  {
5359  if( weights[covervars[k]] <= minweight )
5360  {
5361  minweightidx = k;
5362  minweight = weights[covervars[minweightidx]];
5363  }
5364  }
5365  assert(minweight > 0 && minweight <= *coverweight);
5366  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5367  }
5368  else
5369  {
5370  assert(minweightidx > j);
5371  minweightidx--;
5372  }
5373  /* j needs to stay the same */
5374  }
5375  assert((*coverweight) > capacity);
5376  assert((*coverweight) - minweight <= capacity);
5377 
5378  /* frees temporary memory */
5379  for( j = nsortkeypairs-1; j >= 0; j-- )
5380  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5381  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5382  SCIPfreeBufferArray(scip, &sortkeypairs);
5383 
5384  return SCIP_OKAY;
5385 }
5386 
5387 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5388  * they were chosen to be in C_init:
5389  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5390  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5391  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5392  * and all subsequent feasible sets.
5393  */
5394 static
5396  SCIP* scip, /**< SCIP data structure */
5397  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5398  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5399  SCIP_VAR** vars, /**< variables in knapsack constraint */
5400  int nvars, /**< number of variables in knapsack constraint */
5401  int ntightened, /**< number of variables with tightened upper bound */
5402  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5403  SCIP_Longint capacity, /**< capacity of knapsack */
5404  SCIP_Real* solvals, /**< solution values of all problem variables */
5405  int* covervars, /**< pointer to store cover variables */
5406  int* noncovervars, /**< pointer to store noncover variables */
5407  int* ncovervars, /**< pointer to store number of cover variables */
5408  int* nnoncovervars, /**< pointer to store number of noncover variables */
5409  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5410  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5411  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5412  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5413  int* ncuts /**< pointer to add up the number of found cuts */
5414  )
5415 {
5416  SCIP_Real* sortkeys;
5417  int j;
5418  int k;
5419 
5420  assert(scip != NULL);
5421  assert(covervars != NULL);
5422  assert(noncovervars != NULL);
5423  assert(ncovervars != NULL);
5424  assert(*ncovervars > 0);
5425  assert(nnoncovervars != NULL);
5426  assert(*nnoncovervars >= 0);
5427  assert(coverweight != NULL);
5428  assert(*coverweight > 0);
5429  assert(*coverweight > capacity);
5430  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5431  assert(cutoff != NULL);
5432 
5433  *cutoff = FALSE;
5434 
5435  /* allocates temporary memory */
5436  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5437 
5438  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5439  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5440  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5441  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5442  */
5443  if( modtransused )
5444  {
5445  for( j = 0; j < *ncovervars; j++ )
5446  {
5447  sortkeys[j] = solvals[covervars[j]];
5448  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5449  }
5450  }
5451  else
5452  {
5453  for( j = 0; j < *ncovervars; j++ )
5454  {
5455  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5456  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5457  }
5458  }
5459  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5460 
5461  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5462  * in addition to an extended weight inequality this gives cardinality inequalities */
5463  while( *ncovervars >= 2 )
5464  {
5465  /* adds first element of C_init to N\C_init */
5466  noncovervars[*nnoncovervars] = covervars[0];
5467  (*nnoncovervars)++;
5468 
5469  /* removes first element from C_init */
5470  (*coverweight) -= weights[covervars[0]];
5471  for( k = 0; k < (*ncovervars) - 1; k++ )
5472  covervars[k] = covervars[k+1];
5473  (*ncovervars)--;
5474 
5475  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5476  if( (*coverweight) <= capacity )
5477  {
5478  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5479  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5480  }
5481 
5482  /* stop if cover is too large */
5483  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5484  break;
5485  }
5486 
5487  /* frees temporary memory */
5488  SCIPfreeBufferArray(scip, &sortkeys);
5489 
5490  return SCIP_OKAY;
5491 }
5492 
5493 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5495  SCIP* scip, /**< SCIP data structure */
5496  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5497  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5498  SCIP_VAR** vars, /**< variables in knapsack constraint */
5499  int nvars, /**< number of variables in knapsack constraint */
5500  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5501  SCIP_Longint capacity, /**< capacity of knapsack */
5502  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5503  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5504  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5505  int* ncuts /**< pointer to add up the number of found cuts */
5506  )
5507 {
5508  SCIP_Real* solvals;
5509  int* covervars;
5510  int* noncovervars;
5511  SCIP_Bool coverfound;
5512  SCIP_Bool fractional;
5513  SCIP_Bool modtransused;
5514  SCIP_Longint coverweight;
5515  int ncovervars;
5516  int nnoncovervars;
5517  int ntightened;
5518 
5519  assert(scip != NULL);
5520  assert(capacity >= 0);
5521  assert(cutoff != NULL);
5522  assert(ncuts != NULL);
5523 
5524  *cutoff = FALSE;
5525 
5526  if( nvars == 0 )
5527  return SCIP_OKAY;
5528 
5529  assert(vars != NULL);
5530  assert(nvars > 0);
5531  assert(weights != NULL);
5532 
5533  /* increase age of constraint (age is reset to zero, if a cut was found) */
5534  if( cons != NULL )
5535  {
5536  SCIP_CALL( SCIPincConsAge(scip, cons) );
5537  }
5538 
5539  /* allocates temporary memory */
5540  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5541  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5542  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5543 
5544  /* gets solution values of all problem variables */
5545  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5546 
5547 #ifdef SCIP_DEBUG
5548  {
5549  int i;
5550 
5551  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5552  cons == NULL ? "-" : SCIPconsGetName(cons));
5553  for( i = 0; i < nvars; ++i )
5554  {
5555  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5556  }
5557  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5558  }
5559 #endif
5560 
5561  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5562  */
5563  if( usegubs )
5564  {
5565  SCIP_GUBSET* gubset;
5566 
5567  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5568 
5569  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5570  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5571 
5572  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5573  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5574  assert(gubset->ngubconss <= nvars);
5575 
5576  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5577  * MODIFIED transformed separation problem and taking into account the following fixing:
5578  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5579  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5580  * if one exists
5581  */
5582  modtransused = TRUE;
5583  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5584  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5585 
5586  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5587 
5588  /* if x* is not fractional we stop the separation routine */
5589  if( !fractional )
5590  {
5591  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5592 
5593  /* frees memory for GUB set data structure */
5594  GUBsetFree(scip, &gubset);
5595 
5596  goto TERMINATE;
5597  }
5598 
5599  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5600  if( coverfound )
5601  {
5602  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5603  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5604  */
5605  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5606  &nnoncovervars, &coverweight, modtransused) );
5607 
5608  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5609  if( gubset->ngubconss < nvars )
5610  {
5611  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5612  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5613  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5614  }
5615  else
5616  {
5617  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5618  * GUB information
5619  */
5620  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5621  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5622  }
5623  }
5624 
5625  /* frees memory for GUB set data structure */
5626  GUBsetFree(scip, &gubset);
5627  }
5628  else
5629  {
5630  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5631  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5632  */
5633 
5634  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5635  * MODIFIED transformed separation problem and taking into account the following fixing:
5636  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5637  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5638  * if one exists
5639  */
5640  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5641  modtransused = TRUE;
5642  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5643  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5644  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5645 
5646  /* if x* is not fractional we stop the separation routine */
5647  if( !fractional )
5648  goto TERMINATE;
5649 
5650  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5651  if( coverfound )
5652  {
5653  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5654  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5655  */
5656  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5657  &nnoncovervars, &coverweight, modtransused) );
5658 
5659  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5660  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5661  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5662 
5663  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5664  {
5665  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5666  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5667  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5668  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5669  }
5670  }
5671  }
5672 
5673  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5674  if ( ! (*cutoff) )
5675  {
5676  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5677  * transformed separation problem and taking into account the following fixing:
5678  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5679  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5680  * if one exists
5681  */
5682  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5683  modtransused = FALSE;
5684  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5685  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5686  assert(fractional);
5687  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5688 
5689  /* if no cover was found we stop the separation routine */
5690  if( coverfound )
5691  {
5692  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5693  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5694  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5695  */
5696  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5697  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5698  }
5699  }
5700 
5701  TERMINATE:
5702  /* frees temporary memory */
5703  SCIPfreeBufferArray(scip, &noncovervars);
5704  SCIPfreeBufferArray(scip, &covervars);
5705  SCIPfreeBufferArray(scip, &solvals);
5706 
5707  return SCIP_OKAY;
5708 }
5709 
5710 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5712  SCIP* scip, /**< SCIP data structure */
5713  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5714  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5715  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5716  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5717  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5718  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5719  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5720  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5721  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5722  int* ncuts /**< pointer to add up the number of found cuts */
5723  )
5724 {
5725  SCIP_VAR** binvars;
5726  SCIP_VAR** consvars;
5727  SCIP_Real* binvals;
5728  SCIP_Longint* consvals;
5729  SCIP_Longint minact;
5730  SCIP_Longint maxact;
5731  SCIP_Real intscalar;
5732  SCIP_Bool success;
5733  int nbinvars;
5734  int nconsvars;
5735  int i;
5736 
5737  int* tmpindices;
5738  int tmp;
5739  SCIP_CONSHDLR* conshdlr;
5740  SCIP_CONSHDLRDATA* conshdlrdata;
5741  SCIP_Bool noknapsackconshdlr;
5742  SCIP_Bool usegubs;
5743 
5744  assert(nknapvars > 0);
5745  assert(knapvars != NULL);
5746  assert(cutoff != NULL);
5747 
5748  tmpindices = NULL;
5749 
5750  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5751  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5752 
5753  binvars = SCIPgetVars(scip);
5754 
5755  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5756  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5757 
5758  *cutoff = FALSE;
5759 
5760  if( nbinvars == 0 )
5761  return SCIP_OKAY;
5762 
5763  /* set up data structures */
5764  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5765  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5766 
5767  /* get conshdlrdata to use cleared memory */
5768  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5769  if( conshdlr == NULL )
5770  {
5771  noknapsackconshdlr = TRUE;
5772  usegubs = DEFAULT_USEGUBS;
5773 
5774  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5775  BMSclearMemoryArray(binvals, nbinvars);
5776  }
5777  else
5778  {
5779  noknapsackconshdlr = FALSE;
5780  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5781  assert(conshdlrdata != NULL);
5782  usegubs = conshdlrdata->usegubs;
5783 
5784  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5785 
5786  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5787  * change their types to SCIP_VARTYPE_BINARY during presolving
5788  */
5789  if( conshdlrdata->reals1size == 0 )
5790  {
5791  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5792  conshdlrdata->reals1size = 1;
5793  conshdlrdata->reals1[0] = 0.0;
5794  }
5795 
5796  assert(conshdlrdata->reals1size > 0);
5797 
5798  /* next if condition should normally not be true, because it means that presolving has created more binary
5799  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5800  * transform all integers into their binary representation then it maybe happens
5801  */
5802  if( conshdlrdata->reals1size < nbinvars )
5803  {
5804  int oldsize = conshdlrdata->reals1size;
5805 
5806  conshdlrdata->reals1size = nbinvars;
5807  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5808  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5809  }
5810  binvals = conshdlrdata->reals1;
5811 
5812  /* check for cleared array, all entries have to be zero */
5813 #ifndef NDEBUG
5814  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5815  {
5816  assert(binvals[tmp] == 0);
5817  }
5818 #endif
5819  }
5820 
5821  tmp = 0;
5822 
5823  /* relax continuous knapsack constraint:
5824  * 1. make all variables binary:
5825  * if x_j is continuous or integer variable substitute:
5826  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5827  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5828  * 2. convert coefficients of all variables to positive integers:
5829  * - scale all coefficients a_j to a~_j integral
5830  * - substitute x~_j = 1 - x_j if a~_j < 0
5831  */
5832 
5833  /* replace integer and continuous variables with binary variables */
5834  for( i = 0; i < nknapvars; i++ )
5835  {
5836  SCIP_VAR* var;
5837 
5838  var = knapvars[i];
5839 
5840  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5841  {
5842  SCIP_Real solval;
5843  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5844 
5845  solval = SCIPgetSolVal(scip, sol, var);
5846 
5847  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5848  if( SCIPisFeasLT(scip, solval, 0.0 )
5849  || SCIPisFeasGT(scip, solval, 1.0) )
5850  {
5851  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5852  solval, SCIPvarGetName(var));
5853  goto TERMINATE;
5854  }
5855 
5856  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5857  if( !noknapsackconshdlr )
5858  {
5859  assert(tmpindices != NULL);
5860 
5861  tmpindices[tmp] = SCIPvarGetProbindex(var);
5862  ++tmp;
5863  }
5864  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5865  }
5866  else if( valscale * knapvals[i] > 0.0 )
5867  {
5868  SCIP_VAR** zvlb;
5869  SCIP_Real* bvlb;
5870  SCIP_Real* dvlb;
5871  SCIP_Real bestlbsol;
5872  int bestlbtype;
5873  int nvlb;
5874  int j;
5875 
5876  /* a_j > 0: substitution with lb or vlb */
5877  nvlb = SCIPvarGetNVlbs(var);
5878  zvlb = SCIPvarGetVlbVars(var);
5879  bvlb = SCIPvarGetVlbCoefs(var);
5880  dvlb = SCIPvarGetVlbConstants(var);
5881 
5882  /* search for lb or vlb with maximal bound value */
5883  bestlbsol = SCIPvarGetLbGlobal(var);
5884  bestlbtype = -1;
5885  for( j = 0; j < nvlb; j++ )
5886  {
5887  /* use only numerical stable vlb with binary variable z */
5888  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5889  {
5890  SCIP_Real vlbsol;
5891 
5892  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5893  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5894  {
5895  *cutoff = TRUE;
5896  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5898  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5899  goto TERMINATE;
5900  }
5901 
5902  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5903  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5904  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5905  {
5906  bestlbsol = vlbsol;
5907  bestlbtype = j;
5908  }
5909  }
5910  }
5911 
5912  /* if no lb or vlb with binary variable was found, we have to abort */
5913  if( SCIPisInfinity(scip, -bestlbsol) )
5914  goto TERMINATE;
5915 
5916  if( bestlbtype == -1 )
5917  {
5918  rhs -= valscale * knapvals[i] * bestlbsol;
5919  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5920  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5921  }
5922  else
5923  {
5924  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5925  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5926  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5927 
5928  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5929  goto TERMINATE;
5930 
5931  if( !noknapsackconshdlr )
5932  {
5933  assert(tmpindices != NULL);
5934 
5935  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5936  ++tmp;
5937  }
5938  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5939  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5940  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5941  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5942  }
5943  }
5944  else
5945  {
5946  SCIP_VAR** zvub;
5947  SCIP_Real* bvub;
5948  SCIP_Real* dvub;
5949  SCIP_Real bestubsol;
5950  int bestubtype;
5951  int nvub;
5952  int j;
5953 
5954  assert(valscale * knapvals[i] < 0.0);
5955 
5956  /* a_j < 0: substitution with ub or vub */
5957  nvub = SCIPvarGetNVubs(var);
5958  zvub = SCIPvarGetVubVars(var);
5959  bvub = SCIPvarGetVubCoefs(var);
5960  dvub = SCIPvarGetVubConstants(var);
5961 
5962  /* search for ub or vub with minimal bound value */
5963  bestubsol = SCIPvarGetUbGlobal(var);
5964  bestubtype = -1;
5965  for( j = 0; j < nvub; j++ )
5966  {
5967  /* use only numerical stable vub with active binary variable z */
5968  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
5969  {
5970  SCIP_Real vubsol;
5971 
5972  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
5973  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
5974  {
5975  *cutoff = TRUE;
5976  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
5978  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
5979  goto TERMINATE;
5980  }
5981 
5982  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
5983  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
5984  if( SCIPisLE(scip, vubsol, bestubsol) )
5985  {
5986  bestubsol = vubsol;
5987  bestubtype = j;
5988  }
5989  }
5990  }
5991 
5992  /* if no ub or vub with binary variable was found, we have to abort */
5993  if( SCIPisInfinity(scip, bestubsol) )
5994  goto TERMINATE;
5995 
5996  if( bestubtype == -1 )
5997  {
5998  rhs -= valscale * knapvals[i] * bestubsol;
5999  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6000  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6001  }
6002  else
6003  {
6004  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6005  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6006  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6007 
6008  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6009  goto TERMINATE;
6010 
6011  if( !noknapsackconshdlr )
6012  {
6013  assert(tmpindices != NULL);
6014 
6015  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6016  ++tmp;
6017  }
6018  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6019  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6020  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6021  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6022  }
6023  }
6024  }
6025 
6026  /* convert coefficients of all (now binary) variables to positive integers:
6027  * - make all coefficients integral
6028  * - make all coefficients positive (substitute negated variable)
6029  */
6030  nconsvars = 0;
6031 
6032  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6033  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6034  */
6036  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6037  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6038 
6039  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6040  if( !success )
6041  intscalar = 1.0;
6042 
6043  /* make all coefficients integral and positive:
6044  * - scale a~_j = a_j * intscalar
6045  * - substitute x~_j = 1 - x_j if a~_j < 0
6046  */
6047  rhs = rhs * intscalar;
6048 
6049  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6050  minact = 0;
6051  maxact = 0;
6052  for( i = 0; i < nbinvars; i++ )
6053  {
6054  SCIP_VAR* var;
6055  SCIP_Longint val;
6056 
6057  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6058  if( val == 0 )
6059  continue;
6060 
6061  if( val > 0 )
6062  {
6063  var = binvars[i];
6064  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6065  val, SCIPvarGetName(var), binvals[i], rhs);
6066  }
6067  else
6068  {
6069  assert(val < 0);
6070 
6071  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6072  val = -val; /*lint !e2704*/
6073  rhs += val;
6074  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6075  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6076  }
6077 
6078  if( SCIPvarGetLbLocal(var) > 0.5 )
6079  minact += val;
6080  if( SCIPvarGetUbLocal(var) > 0.5 )
6081  maxact += val;
6082  consvals[nconsvars] = val;
6083  consvars[nconsvars] = var;
6084  nconsvars++;
6085  }
6086 
6087  if( nconsvars > 0 )
6088  {
6089  SCIP_Longint capacity;
6090 
6091  assert(consvars != NULL);
6092  assert(consvals != NULL);
6093  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6094 
6095 #ifdef SCIP_DEBUG
6096  {
6097  SCIP_Real act;
6098 
6099  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6100  act = 0.0;
6101  for( i = 0; i < nconsvars; ++i )
6102  {
6103  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6104  SCIPgetSolVal(scip, sol, consvars[i]));
6105  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6106  }
6107  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6108  capacity, rhs, act, minact, maxact);
6109  }
6110 #endif
6111 
6112  if( minact > capacity )
6113  {
6114  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6115  *cutoff = TRUE;
6116  goto TERMINATE;
6117  }
6118 
6119  if( maxact > capacity )
6120  {
6121  /* separate lifted cut from relaxed knapsack constraint */
6122  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6123  }
6124  }
6125 
6126  TERMINATE:
6127  /* free data structures */
6128  if( noknapsackconshdlr)
6129  {
6130  SCIPfreeBufferArray(scip, &binvals);
6131  }
6132  else
6133  {
6134  /* clear binvals */
6135  for( --tmp; tmp >= 0; --tmp)
6136  {
6137  assert(tmpindices != NULL);
6138  binvals[tmpindices[tmp]] = 0;
6139  }
6140  SCIPfreeBufferArray(scip, &tmpindices);
6141  }
6142  SCIPfreeBufferArray(scip, &consvals);
6143  SCIPfreeBufferArray(scip, &consvars);
6144 
6145  return SCIP_OKAY;
6146 }
6147 
6148 /** separates given knapsack constraint */
6149 static
6151  SCIP* scip, /**< SCIP data structure */
6152  SCIP_CONS* cons, /**< knapsack constraint */
6153  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6154  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6155  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6156  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6157  int* ncuts /**< pointer to add up the number of found cuts */
6158  )
6159 {
6160  SCIP_CONSDATA* consdata;
6161  SCIP_Bool violated;
6162 
6163  assert(ncuts != NULL);
6164  assert(cutoff != NULL);
6165  *cutoff = FALSE;
6166 
6167  consdata = SCIPconsGetData(cons);
6168  assert(consdata != NULL);
6169 
6170  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6171 
6172  /* check knapsack constraint itself for feasibility */
6173  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6174 
6175  if( violated )
6176  {
6177  /* add knapsack constraint as LP row to the LP */
6178  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6179  (*ncuts)++;
6180  }
6181  else if( sepacuts )
6182  {
6183  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6184  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6185  }
6186 
6187  return SCIP_OKAY;
6188 }
6189 
6190 /** adds coefficient to constraint data */
6191 static
6193  SCIP* scip, /**< SCIP data structure */
6194  SCIP_CONS* cons, /**< knapsack constraint */
6195  SCIP_VAR* var, /**< variable to add to knapsack */
6196  SCIP_Longint weight /**< weight of variable in knapsack */
6197  )
6198 {
6199  SCIP_CONSDATA* consdata;
6201  consdata = SCIPconsGetData(cons);
6202  assert(consdata != NULL);
6203  assert(SCIPvarIsBinary(var));
6204  assert(weight > 0);
6205 
6206  /* add the new coefficient to the LP row */
6207  if( consdata->row != NULL )
6208  {
6209  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6210  }
6211 
6212  /* check for fixed variable */
6213  if( SCIPvarGetLbGlobal(var) > 0.5 )
6214  {
6215  /* variable is fixed to one: reduce capacity */
6216  consdata->capacity -= weight;
6217  }
6218  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6219  {
6220  SCIP_Bool negated;
6221 
6222  /* get binary representative of variable */
6223  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6224 
6225  /* insert coefficient */
6226  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6227  consdata->vars[consdata->nvars] = var;
6228  consdata->weights[consdata->nvars] = weight;
6229  consdata->nvars++;
6230 
6231  /* capture variable */
6232  SCIP_CALL( SCIPcaptureVar(scip, var) );
6233 
6234  /* install the rounding locks of variable */
6235  SCIP_CALL( lockRounding(scip, cons, var) );
6236 
6237  /* catch events */
6238  if( SCIPconsIsTransformed(cons) )
6239  {
6240  SCIP_CONSHDLRDATA* conshdlrdata;
6241 
6242  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6243  assert(conshdlrdata != NULL);
6244  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6246  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6247  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6248 
6249  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6250  consdata->existmultaggr = TRUE;
6251 
6252  /* mark constraint to be propagated and presolved */
6253  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6254  consdata->presolvedtiming = 0;
6255  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6256  }
6257 
6258  /* update weight sums */
6259  updateWeightSums(consdata, var, weight);
6260 
6261  consdata->sorted = FALSE;
6262  consdata->cliquepartitioned = FALSE;
6263  consdata->negcliquepartitioned = FALSE;
6264  consdata->merged = FALSE;
6265  }
6266 
6267  return SCIP_OKAY;
6268 }
6269 
6270 /** deletes coefficient at given position from constraint data */
6271 static
6273  SCIP* scip, /**< SCIP data structure */
6274  SCIP_CONS* cons, /**< knapsack constraint */
6275  int pos /**< position of coefficient to delete */
6276  )
6277 {
6278  SCIP_CONSDATA* consdata;
6279  SCIP_VAR* var;
6281  consdata = SCIPconsGetData(cons);
6282  assert(consdata != NULL);
6283  assert(0 <= pos && pos < consdata->nvars);
6284 
6285  var = consdata->vars[pos];
6286  assert(var != NULL);
6287  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6288 
6289  /* delete the coefficient from the LP row */
6290  if( consdata->row != NULL )
6291  {
6292  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6293  }
6294 
6295  /* remove the rounding locks of variable */
6296  SCIP_CALL( unlockRounding(scip, cons, var) );
6297 
6298  /* drop events and mark constraint to be propagated and presolved */
6299  if( SCIPconsIsTransformed(cons) )
6300  {
6301  SCIP_CONSHDLRDATA* conshdlrdata;
6302 
6303  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6304  assert(conshdlrdata != NULL);
6306  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6307  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6308 
6309  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6310  consdata->presolvedtiming = 0;
6311  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6312  }
6313 
6314  /* decrease weight sums */
6315  updateWeightSums(consdata, var, -consdata->weights[pos]);
6316 
6317  /* move the last variable to the free slot */
6318  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6319  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6320  if( consdata->eventdata != NULL )
6321  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6322 
6323  /* release variable */
6324  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6325 
6326  /* try to use old clique partitions */
6327  if( consdata->cliquepartitioned )
6328  {
6329  assert(consdata->cliquepartition != NULL);
6330  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6331  * change the clique number */
6332  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6333  {
6334  int oldcliqenum;
6335 
6336  oldcliqenum = consdata->cliquepartition[pos];
6337  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6338 
6339  /* the following if and else cases assure that we have increasing clique numbers */
6340  if( consdata->cliquepartition[pos] > pos )
6341  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6342  else
6343  {
6344  int i;
6345  int cliquenumbefore;
6346 
6347  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6348  * occurs the same as the old one is still in the cliquepartition */
6349  if( oldcliqenum > consdata->cliquepartition[pos] )
6350  {
6351  for( i = 0; i < consdata->nvars; ++i )
6352  if( oldcliqenum == consdata->cliquepartition[i] )
6353  break;
6354  else if( oldcliqenum < consdata->cliquepartition[i] )
6355  {
6356  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6357  break;
6358  }
6359  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6360  * the biggest index, so decrease the number of cliques
6361  */
6362  if( i == consdata->nvars )
6363  --(consdata->ncliques);
6364  }
6365  /* if the old clique number was smaller than the new one we have to check the front for an element with
6366  * clique number minus 1 */
6367  else if( oldcliqenum < consdata->cliquepartition[pos] )
6368  {
6369  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6370  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6371 
6372  if( i < cliquenumbefore )
6373  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6374  }
6375  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6376  else if( pos == consdata->nvars - 1)
6377  {
6378  cliquenumbefore = consdata->cliquepartition[pos];
6379  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6380 
6381  if( i < cliquenumbefore )
6382  --(consdata->ncliques);
6383  }
6384  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6385  }
6386  }
6387  else
6388  --(consdata->ncliques);
6389  }
6390 
6391  if( consdata->negcliquepartitioned )
6392  {
6393  assert(consdata->negcliquepartition != NULL);
6394  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6395  * change the clique number */
6396  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6397  {
6398  int oldcliqenum;
6399 
6400  oldcliqenum = consdata->negcliquepartition[pos];
6401  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6402 
6403  /* the following if and else cases assure that we have increasing clique numbers */
6404  if( consdata->negcliquepartition[pos] > pos )
6405  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6406  else
6407  {
6408  int i;
6409  int cliquenumbefore;
6410 
6411  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6412  * occurs, the same as the old one occurs */
6413  if( oldcliqenum > consdata->negcliquepartition[pos] )
6414  {
6415  for( i = 0; i < consdata->nvars; ++i )
6416  if( oldcliqenum == consdata->negcliquepartition[i] )
6417  break;
6418  else if( oldcliqenum < consdata->negcliquepartition[i] )
6419  {
6420  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6421  break;
6422  }
6423  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6424  * the biggest index, so decrease the number of negated cliques
6425  */
6426  if( i == consdata->nvars )
6427  --(consdata->nnegcliques);
6428  }
6429  /* if the old clique number was smaller than the new one we have to check the front for an element with
6430  * clique number minus 1 */
6431  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6432  {
6433  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6434  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6435 
6436  if( i < cliquenumbefore )
6437  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6438  }
6439  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6440  else if( pos == consdata->nvars - 1)
6441  {
6442  cliquenumbefore = consdata->negcliquepartition[pos];
6443  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6444 
6445  if( i < cliquenumbefore )
6446  --(consdata->nnegcliques);
6447  }
6448  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6449  }
6450  }
6451  else
6452  --(consdata->nnegcliques);
6453  }
6454 
6455  --(consdata->nvars);
6456 
6457  return SCIP_OKAY;
6458 }
6459 
6460 /** removes all items with weight zero from knapsack constraint */
6461 static
6463  SCIP* scip, /**< SCIP data structure */
6464  SCIP_CONS* cons /**< knapsack constraint */
6465  )
6466 {
6467  SCIP_CONSDATA* consdata;
6468  int v;
6469 
6470  consdata = SCIPconsGetData(cons);
6471  assert(consdata != NULL);
6472 
6473  for( v = consdata->nvars-1; v >= 0; --v )
6474  {
6475  if( consdata->weights[v] == 0 )
6476  {
6477  SCIP_CALL( delCoefPos(scip, cons, v) );
6478  }
6479  }
6480 
6481  return SCIP_OKAY;
6482 }
6483 
6484 /* perform deletion of variables in all constraints of the constraint handler */
6485 static
6487  SCIP* scip, /**< SCIP data structure */
6488  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6489  SCIP_CONS** conss, /**< array of constraints */
6490  int nconss /**< number of constraints */
6491  )
6492 {
6493  SCIP_CONSDATA* consdata;
6494  int i;
6495  int v;
6496 
6497  assert(scip != NULL);
6498  assert(conshdlr != NULL);
6499  assert(conss != NULL);
6500  assert(nconss >= 0);
6501  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6502 
6503  /* iterate over all constraints */
6504  for( i = 0; i < nconss; i++ )
6505  {
6506  consdata = SCIPconsGetData(conss[i]);
6507 
6508  /* constraint is marked, that some of its variables were deleted */
6509  if( consdata->varsdeleted )
6510  {
6511  /* iterate over all variables of the constraint and delete them from the constraint */
6512  for( v = consdata->nvars - 1; v >= 0; --v )
6513  {
6514  if( SCIPvarIsDeleted(consdata->vars[v]) )
6515  {
6516  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6517  }
6518  }
6519  consdata->varsdeleted = FALSE;
6520  }
6521  }
6522 
6523  return SCIP_OKAY;
6524 }
6525 
6526 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6527 static
6529  SCIP* scip, /**< SCIP data structure */
6530  SCIP_CONS* cons, /**< knapsack constraint */
6531  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6532  )
6533 {
6534  SCIP_CONSDATA* consdata;
6535  int v;
6536  int prev;
6537 
6538  assert(scip != NULL);
6539  assert(cons != NULL);
6540  assert(cutoff != NULL);
6541 
6542  consdata = SCIPconsGetData(cons);
6543  assert(consdata != NULL);
6544 
6545  *cutoff = FALSE;
6546 
6547  if( consdata->merged )
6548  return SCIP_OKAY;
6549 
6550  if( consdata->nvars <= 1 )
6551  {
6552  consdata->merged = TRUE;
6553  return SCIP_OKAY;
6554  }
6555 
6556  assert(consdata->vars != NULL || consdata->nvars == 0);
6557 
6558  /* sorting array after indices of variables, that's only for faster merging */
6559  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6560  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6561 
6562  /* knapsack-sorting (decreasing weights) now lost */
6563  consdata->sorted = FALSE;
6564 
6565  v = consdata->nvars - 1;
6566  prev = v - 1;
6567  /* loop backwards through the items: deletion only affects rear items */
6568  while( prev >= 0 )
6569  {
6570  SCIP_VAR* var1;
6571  SCIP_VAR* var2;
6572  SCIP_Bool negated1;
6573  SCIP_Bool negated2;
6574 
6575  negated1 = FALSE;
6576  negated2 = FALSE;
6577 
6578  var1 = consdata->vars[v];
6579  assert(SCIPvarIsBinary(var1));
6580  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6582  {
6583  var1 = SCIPvarGetNegatedVar(var1);
6584  negated1 = TRUE;
6585  }
6586  assert(var1 != NULL);
6587 
6588  var2 = consdata->vars[prev];
6589  assert(SCIPvarIsBinary(var2));
6590  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6592  {
6593  var2 = SCIPvarGetNegatedVar(var2);
6594  negated2 = TRUE;
6595  }
6596  assert(var2 != NULL);
6597 
6598  if( var1 == var2 )
6599  {
6600  /* both variables are either active or negated */
6601  if( negated1 == negated2 )
6602  {
6603  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6604  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6605  SCIP_CALL( delCoefPos(scip, cons, v) );
6606  }
6607  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6608  * and delete item of smaller weight
6609  */
6610  else if( consdata->weights[v] == consdata->weights[prev] )
6611  {
6612  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6613  consdata->capacity -= consdata->weights[v];
6614  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6615  SCIP_CALL( delCoefPos(scip, cons, prev) );
6616 
6617  --prev;
6618  }
6619  else if( consdata->weights[v] < consdata->weights[prev] )
6620  {
6621  consdata->capacity -= consdata->weights[v];
6622  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6623  assert(consdata->weights[prev] > 0);
6624  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6625  }
6626  else
6627  {
6628  consdata->capacity -= consdata->weights[prev];
6629  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6630  assert(consdata->weights[v] > 0);
6631  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6632  /* restore order iff necessary */
6633  if( consdata->nvars != v ) /* otherwise the order still stands */
6634  {
6635  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6636  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6637  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6638  --prev;
6639  else /* we need to let v at the same position*/
6640  {
6641  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6642  /* don't decrease v, the same variable may exist up front */
6643  --prev;
6644  continue;
6645  }
6646  }
6647  }
6648  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6649  }
6650  v = prev;
6651  --prev;
6652  }
6653 
6654  consdata->merged = TRUE;
6655 
6656  /* check infeasibility */
6657  if( consdata->onesweightsum > consdata->capacity )
6658  {
6659  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6660  *cutoff = TRUE;
6661  return SCIP_OKAY;
6662  }
6663 
6664  return SCIP_OKAY;
6665 }
6666 
6667 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6668  * fixings (dual reductions)
6669  */
6670 static
6672  SCIP* scip, /**< SCIP data structure */
6673  SCIP_CONS* cons, /**< knapsack constraint */
6674  int* nfixedvars, /**< pointer to count number of fixings */
6675  int* ndelconss, /**< pointer to count number of deleted constraints */
6676  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6677  )
6678 {
6679  SCIP_CONSDATA* consdata;
6680  SCIP_VAR** vars;
6681  SCIP_Real* profits;
6682  int* solitems;
6683  int* nonsolitems;
6684  int* items;
6685  SCIP_Real solval;
6686  SCIP_Bool infeasible;
6687  SCIP_Bool tightened;
6688  SCIP_Bool applicable;
6689  int nsolitems;
6690  int nnonsolitems;
6691  int nvars;
6692  int v;
6693 
6694  assert(!SCIPconsIsModifiable(cons));
6695 
6696  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6697  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6698  * added to the problems have the check flag set to FALSE
6699  */
6700  if( !SCIPconsIsChecked(cons) )
6701  return SCIP_OKAY;
6702 
6703  consdata = SCIPconsGetData(cons);
6704  assert(consdata != NULL);
6705 
6706  nvars = consdata->nvars;
6707  vars = consdata->vars;
6708 
6709  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6710  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6711  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6712  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6713 
6714  applicable = TRUE;
6715 
6716  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6717  * collect object values which are the profits of the knapsack problem
6718  */
6719  for( v = 0; v < nvars; ++v )
6720  {
6721  SCIP_VAR* var;
6722  SCIP_Bool negated;
6723 
6724  var = vars[v];
6725  assert(var != NULL);
6726 
6727  /* the variable should not be (globally) fixed */
6728  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6729 
6732  {
6733  applicable = FALSE;
6734  break;
6735  }
6736 
6737  negated = FALSE;
6738 
6739  /* get the active variable */
6740  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6741  assert(SCIPvarIsActive(var));
6742 
6743  if( negated )
6744  profits[v] = SCIPvarGetObj(var);
6745  else
6746  profits[v] = -SCIPvarGetObj(var);
6747 
6748  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6749  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6750  items[v] = v;
6751  }
6752 
6753  if( applicable )
6754  {
6755  SCIP_Bool success;
6756 
6757  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6758  SCIPdebugPrintCons(scip, cons, NULL);
6759 
6760  /* solve knapsack problem exactly */
6761  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6762  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6763 
6764  if( success )
6765  {
6766  SCIP_VAR* var;
6767 
6768  /* apply solution of the knapsack as dual reductions */
6769  for( v = 0; v < nsolitems; ++v )
6770  {
6771  var = vars[solitems[v]];
6772  assert(var != NULL);
6773 
6774  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6776  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6777  assert(!infeasible);
6778  assert(tightened);
6779  (*nfixedvars)++;
6780  }
6781 
6782  for( v = 0; v < nnonsolitems; ++v )
6783  {
6784  var = vars[nonsolitems[v]];
6785  assert(var != NULL);
6786 
6787  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6789  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6790  assert(!infeasible);
6791  assert(tightened);
6792  (*nfixedvars)++;
6793  }
6794 
6795  SCIP_CALL( SCIPdelCons(scip, cons) );
6796  (*ndelconss)++;
6797  (*deleted) = TRUE;
6798  }
6799  }
6800 
6801  SCIPfreeBufferArray(scip, &nonsolitems);
6802  SCIPfreeBufferArray(scip, &solitems);
6803  SCIPfreeBufferArray(scip, &items);
6804  SCIPfreeBufferArray(scip, &profits);
6805 
6806  return SCIP_OKAY;
6807 }
6808 
6809 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6810  * constraint enters the LP by setting the initial and separated flag to FALSE
6811  */
6812 static
6814  SCIP* scip, /**< SCIP data structure */
6815  SCIP_CONS* cons, /**< knapsack constraint */
6816  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6817  )
6818 {
6819  SCIP_CONSDATA* consdata;
6820  SCIP_VAR** vars;
6821  SCIP_VAR* var;
6822  SCIP_Real offset;
6823  SCIP_Real scale;
6824  SCIP_Real objval;
6825  SCIP_Bool applicable;
6826  SCIP_Bool negated;
6827  int nobjvars;
6828  int nvars;
6829  int v;
6830 
6831  assert(scip != NULL);
6832  assert(cons != NULL);
6833  assert(conshdlrdata != NULL);
6834 
6835  consdata = SCIPconsGetData(cons);
6836  assert(consdata != NULL);
6837 
6838  nvars = consdata->nvars;
6839  nobjvars = SCIPgetNObjVars(scip);
6840 
6841  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6842  * and/or separated flag is set to FALSE
6843  */
6844  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6845  return SCIP_OKAY;
6846 
6847  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6848  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6849  */
6850  if( nobjvars == 0 )
6851  return SCIP_OKAY;
6852 
6853  vars = consdata->vars;
6854  assert(vars != NULL);
6855 
6856  applicable = TRUE;
6857  offset = 0.0;
6858  scale = 1.0;
6859 
6860  for( v = 0; v < nvars && applicable; ++v )
6861  {
6862  negated = FALSE;
6863  var = vars[v];
6864  assert(var != NULL);
6865 
6866  if( SCIPvarIsNegated(var) )
6867  {
6868  negated = TRUE;
6869  var = SCIPvarGetNegatedVar(var);
6870  assert(var != NULL);
6871  }
6872 
6873  objval = SCIPvarGetObj(var);
6874 
6875  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6876  if( SCIPisZero(scip, objval) )
6877  applicable = FALSE;
6878  else
6879  {
6880  SCIP_Real weight;
6881 
6882  weight = (SCIP_Real)consdata->weights[v];
6883 
6884  if( negated )
6885  {
6886  if( v == 0 )
6887  {
6888  /* the first variable defines the scale */
6889  scale = weight / -objval;
6890 
6891  offset += weight;
6892  }
6893  else if( SCIPisEQ(scip, -objval * scale, weight) )
6894  offset += weight;
6895  else
6896  applicable = FALSE;
6897  }
6898  else if( v == 0 )
6899  {
6900  /* the first variable define the scale */
6901  scale = weight / objval;
6902  }
6903  else if( !SCIPisEQ(scip, objval * scale, weight) )
6904  applicable = FALSE;
6905  }
6906  }
6907 
6908  if( applicable )
6909  {
6910  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6911  {
6912  SCIP_Real cutoffbound;
6913 
6914  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6915  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6916  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6917 
6918  cutoffbound = (consdata->capacity - offset) / scale;
6919 
6920  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6921  SCIPconsGetName(cons), cutoffbound);
6922 
6923  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6924  * still excepted
6925  */
6926  cutoffbound += SCIPcutoffbounddelta(scip);
6927 
6928  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6929  SCIPconsGetName(cons), cutoffbound);
6930 
6931  if( cutoffbound < SCIPgetCutoffbound(scip) )
6932  {
6933  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6934 
6935  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6936  }
6937  else
6938  {
6939  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6940  * propagation
6941  */
6942  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6943  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6944  }
6945  }
6946  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6947  {
6948  SCIP_Real lowerbound;
6949 
6950  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6951  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6952  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6953 
6954  lowerbound = (consdata->capacity - offset) / scale;
6955 
6956  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6957  SCIPconsGetName(cons), lowerbound);
6958 
6959  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6960  }
6961  }
6962 
6963  return SCIP_OKAY;
6964 }
6965 
6966 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6967  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
6968 static
6970  SCIP* scip, /**< SCIP data structure */
6971  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
6972  SCIP_VAR** vars, /**< array for sorted variables */
6973  SCIP_Longint* weights, /**< array for sorted weights */
6974  int* cliquestartposs, /**< starting position array for each clique */
6975  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
6976  )
6977 {
6978  SCIP_VAR** origvars;
6979  int norigvars;
6980  SCIP_Longint* origweights;
6981  int* cliquepartition;
6982  int ncliques;
6983 
6984  SCIP_VAR*** varpointers;
6985  SCIP_Longint** weightpointers;
6986  int* cliquecount;
6987 
6988  int nextpos;
6989  int c;
6990  int v;
6991 
6992  assert(scip != NULL);
6993  assert(consdata != NULL);
6994  assert(vars != NULL);
6995  assert(weights != NULL);
6996  assert(cliquestartposs != NULL);
6997 
6998  origweights = consdata->weights;
6999  origvars = consdata->vars;
7000  norigvars = consdata->nvars;
7001 
7002  assert(origvars != NULL || norigvars == 0);
7003  assert(origweights != NULL || norigvars == 0);
7004 
7005  if( norigvars == 0 )
7006  return SCIP_OKAY;
7007 
7008  if( usenegatedclique )
7009  {
7010  assert(consdata->negcliquepartitioned);
7011 
7012  cliquepartition = consdata->negcliquepartition;
7013  ncliques = consdata->nnegcliques;
7014  }
7015  else
7016  {
7017  assert(consdata->cliquepartitioned);
7018 
7019  cliquepartition = consdata->cliquepartition;
7020  ncliques = consdata->ncliques;
7021  }
7022 
7023  assert(cliquepartition != NULL);
7024  assert(ncliques > 0);
7025 
7026  /* we first count all clique items and alloc temporary memory for a bucket sort */
7027  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7028  BMSclearMemoryArray(cliquecount, ncliques);
7029 
7030  /* first we count for each clique the number of elements */
7031  for( v = norigvars - 1; v >= 0; --v )
7032  {
7033  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7034  ++(cliquecount[cliquepartition[v]]);
7035  }
7036 
7037  /*@todo: maybe it is better to put largest cliques up front */
7038 
7039 #ifndef NDEBUG
7040  BMSclearMemoryArray(vars, norigvars);
7041  BMSclearMemoryArray(weights, norigvars);
7042 #endif
7043  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7044  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7045 
7046  nextpos = 0;
7047  /* now we initialize all start pointers for each clique, so they will be ordered */
7048  for( c = 0; c < ncliques; ++c )
7049  {
7050  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7051  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7052  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7053  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7054  * vars[7]
7055  *
7056  */
7057  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7058  cliquestartposs[c] = nextpos;
7059  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7060  assert(cliquecount[c] > 0);
7061  nextpos += cliquecount[c];
7062  assert(nextpos > 0);
7063  }
7064  assert(nextpos == norigvars);
7065  cliquestartposs[c] = nextpos;
7066 
7067  /* now we copy all variable and weights to the right order */
7068  for( v = 0; v < norigvars; ++v )
7069  {
7070  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7071  ++(varpointers[cliquepartition[v]]);
7072  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7073  ++(weightpointers[cliquepartition[v]]);
7074  }
7075 #ifndef NDEBUG
7076  for( v = 0; v < norigvars; ++v )
7077  {
7078  assert(vars[v] != NULL);
7079  assert(weights[v] > 0);
7080  }
7081 #endif
7082 
7083  /* free temporary memory */
7084  SCIPfreeBufferArray(scip, &weightpointers);
7085  SCIPfreeBufferArray(scip, &varpointers);
7086  SCIPfreeBufferArray(scip, &cliquecount);
7087 
7088  return SCIP_OKAY;
7089 }
7090 
7091 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7092 static
7094  SCIP* scip, /**< SCIP data structure */
7095  SCIP_CONS* cons, /**< knapsack constraint */
7096  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7097  * information is not needed; in this case, we apply all fixings
7098  * instead of stopping after the first infeasible one */
7099  )
7100 {
7101  SCIP_CONSDATA* consdata;
7102  int v;
7103 
7104  assert(scip != NULL);
7105  assert(cons != NULL);
7106 
7107  consdata = SCIPconsGetData(cons);
7108  assert(consdata != NULL);
7109  assert(consdata->nvars == 0 || consdata->vars != NULL);
7110 
7111  if( cutoff != NULL )
7112  *cutoff = FALSE;
7113 
7114  SCIPdebugMsg(scip, "apply fixings:\n");
7115  SCIPdebugPrintCons(scip, cons, NULL);
7116 
7117  /* check infeasibility */
7118  if ( consdata->onesweightsum > consdata->capacity )
7119  {
7120  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7121 
7122  if( cutoff != NULL )
7123  *cutoff = TRUE;
7124 
7125  return SCIP_OKAY;
7126  }
7127 
7128  /* all multi-aggregations should be resolved */
7129  consdata->existmultaggr = FALSE;
7130 
7131  v = 0;
7132  while( v < consdata->nvars )
7133  {
7134  SCIP_VAR* var;
7135 
7136  var = consdata->vars[v];
7137  assert(SCIPvarIsBinary(var));
7138 
7139  if( SCIPvarGetLbGlobal(var) > 0.5 )
7140  {
7141  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7142  consdata->capacity -= consdata->weights[v];
7143  SCIP_CALL( delCoefPos(scip, cons, v) );
7144  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7145  }
7146  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7147  {
7148  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7149  SCIP_CALL( delCoefPos(scip, cons, v) );
7150  }
7151  else
7152  {
7153  SCIP_VAR* repvar;
7154  SCIP_VAR* negvar;
7155  SCIP_VAR* workvar;
7156  SCIP_Longint weight;
7157  SCIP_Bool negated;
7158 
7159  weight = consdata->weights[v];
7160 
7161  /* get binary representative of variable */
7162  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7163  assert(repvar != NULL);
7164 
7165  /* check for multi-aggregation */
7166  if( SCIPvarIsNegated(repvar) )
7167  {
7168  workvar = SCIPvarGetNegatedVar(repvar);
7169  assert(workvar != NULL);
7170  negated = TRUE;
7171  }
7172  else
7173  {
7174  workvar = repvar;
7175  negated = FALSE;
7176  }
7177 
7178  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7179  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7180  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7181  *
7182  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7183  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7184  *
7185  * The explanation for the following block:
7186  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7187  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7188  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7189  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7190  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7191  * 2) For all replacement variable we check:
7192  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7193  * capacity -= weight * a_i caused by the negation of y_i.
7194  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7195  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7196  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7197  * weight in this case.
7198  */
7199  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7200  {
7201  SCIP_VAR** aggrvars;
7202  SCIP_Real* aggrscalars;
7203  SCIP_Real aggrconst;
7204  int naggrvars;
7205  int i;
7206 
7207  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7208  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7209  aggrvars = SCIPvarGetMultaggrVars(workvar);
7210  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7211  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7212  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7213 
7214  if( !SCIPisIntegral(scip, weight * aggrconst) )
7215  {
7216  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7217  return SCIP_ERROR;
7218  }
7219 
7220  /* if workvar was negated, we have to flip the weight */
7221  if( negated )
7222  weight *= -1;
7223 
7224  for( i = naggrvars - 1; i >= 0; --i )
7225  {
7226  assert(aggrvars != NULL);
7227  assert(aggrscalars != NULL);
7228 
7229  if( !SCIPvarIsBinary(aggrvars[i]) )
7230  {
7231  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7232  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7233  return SCIP_ERROR;
7234  }
7235  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7236  {
7237  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7238  return SCIP_ERROR;
7239  }
7240  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7241  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7242  {
7243  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7244  assert(negvar != NULL);
7245  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7246  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7247  }
7248  else
7249  {
7250  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7251  }
7252  }
7253  /* delete old coefficient */
7254  SCIP_CALL( delCoefPos(scip, cons, v) );
7255 
7256  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7257  if( negated )
7258  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7259  else
7260  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7261 
7262  if( consdata->capacity < 0 )
7263  {
7264  if( cutoff != NULL )
7265  {
7266  *cutoff = TRUE;
7267  break;
7268  }
7269  }
7270  }
7271  /* check, if the variable should be replaced with the representative */
7272  else if( repvar != var )
7273  {
7274  /* delete old (aggregated) variable */
7275  SCIP_CALL( delCoefPos(scip, cons, v) );
7276 
7277  /* add representative instead */
7278  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7279  }
7280  else
7281  ++v;
7282  }
7283  }
7284  assert(consdata->onesweightsum == 0);
7285 
7286  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7287  SCIPdebugPrintCons(scip, cons, NULL);
7288 
7289  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7290  * clean up the constraint
7291  */
7292  if( cutoff != NULL && !(*cutoff) )
7293  {
7294  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7295  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7296  SCIPdebugPrintCons(scip, cons, NULL);
7297  }
7298 
7299  return SCIP_OKAY;
7300 }
7301 
7302 
7303 /** propagation method for knapsack constraints */
7304 static
7306  SCIP* scip, /**< SCIP data structure */
7307  SCIP_CONS* cons, /**< knapsack constraint */
7308  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7309  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7310  int* nfixedvars, /**< pointer to count number of fixings */
7311  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7312  )
7314  SCIP_CONSDATA* consdata;
7315  SCIP_Bool infeasible;
7316  SCIP_Bool tightened;
7317  SCIP_Longint* secondmaxweights;
7318  SCIP_Longint minweightsum;
7319  SCIP_Longint residualcapacity;
7320 
7321  int nvars;
7322  int i;
7323  int nnegcliques;
7324 
7325  SCIP_VAR** myvars;
7326  SCIP_Longint* myweights;
7327  int* cliquestartposs;
7328  int* cliqueendposs;
7329  SCIP_Longint localminweightsum;
7330  SCIP_Bool foundmax;
7331  int c;
7332 
7333  assert(scip != NULL);
7334  assert(cons != NULL);
7335  assert(cutoff != NULL);
7336  assert(redundant != NULL);
7337  assert(nfixedvars != NULL);
7338 
7339  consdata = SCIPconsGetData(cons);
7340  assert(consdata != NULL);
7341 
7342  *cutoff = FALSE;
7343  *redundant = FALSE;
7344 
7345  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7346 
7347  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7348  if( !SCIPinRepropagation(scip) )
7349  {
7350  SCIP_CALL( SCIPincConsAge(scip, cons) );
7351  }
7352 
7353 #ifndef NDEBUG
7354  /* assert that only active or negated variables are present */
7355  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7356  {
7357  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7358  }
7359 #endif
7360 
7361  usenegatedclique = usenegatedclique && consdata->merged;
7362 
7363  /* init for debugging */
7364  myvars = NULL;
7365  myweights = NULL;
7366  cliquestartposs = NULL;
7367  secondmaxweights = NULL;
7368  minweightsum = 0;
7369  nvars = consdata->nvars;
7370  /* make sure, the items are sorted by non-increasing weight */
7371  sortItems(consdata);
7372 
7373  do
7374  {
7375  localminweightsum = 0;
7376 
7377  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7378  * a negated clique means, that at most one of the clique variables can be zero
7379  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7380  *
7381  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7382  * since replacing i with the element of maximal weight leads to infeasibility
7383  */
7384  if( usenegatedclique && nvars > 0 )
7385  {
7386  SCIP_CONSHDLRDATA* conshdlrdata;
7387  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7388  assert(conshdlrdata != NULL);
7389 
7390  /* compute clique partitions */
7391  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7392  nnegcliques = consdata->nnegcliques;
7393 
7394  /* if we have no real negated cliques we can stop here */
7395  if( nnegcliques == nvars )
7396  {
7397  /* run the standard algorithm that does not involve cliques */
7398  usenegatedclique = FALSE;
7399  break;
7400  }
7401 
7402  /* allocate temporary memory and initialize it */
7403  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7404  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7405  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7406  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7407  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7408  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7409 
7410  /* resort variables to avoid quadratic algorithm later on */
7411  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7412 
7413  /* save the end positions of the cliques because start positions are moved in the following loop */
7414  for( c = 0; c < nnegcliques; ++c )
7415  {
7416  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7417  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7418  }
7419 
7420  c = 0;
7421  foundmax = FALSE;
7422  i = 0;
7423 
7424  while( i < nvars )
7425  {
7426  /* ignore variables of the negated clique which are fixed to one since these are counted in
7427  * consdata->onesweightsum
7428  */
7429 
7430  /* if there are only one variable negated cliques left we can stop */
7431  if( nnegcliques - c == nvars - i )
7432  {
7433  minweightsum += localminweightsum;
7434  localminweightsum = 0;
7435  break;
7436  }
7437 
7438  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7439  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7440  * other clique variables to one
7441  */
7442  if( cliquestartposs[c] == i )
7443  {
7444  assert(myweights[i] > 0);
7445  ++c;
7446  minweightsum += localminweightsum;
7447  localminweightsum = 0;
7448  foundmax = TRUE;
7449 
7450  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7451  foundmax = FALSE;
7452 
7453  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7454  {
7455  ++i;
7456  continue;
7457  }
7458  }
7459 
7460  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7461  {
7462  assert(myweights[i] > 0);
7463 
7464  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7465  {
7466  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7467 
7468  if( !foundmax )
7469  {
7470  foundmax = TRUE;
7471 
7472  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7473  cliquestartposs[c - 1] = i;
7474  ++i;
7475 
7476  continue;
7477  }
7478  /* memorize second max weight for each clique */
7479  if( secondmaxweights[c - 1] == 0 )
7480  secondmaxweights[c - 1] = myweights[i];
7481 
7482  localminweightsum += myweights[i];
7483  }
7484  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7485  else
7486  {
7487  int v;
7488  /* fix all other variables of the negated clique to 1 */
7489  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7490  {
7491  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7492  {
7493  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7494  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7495 
7496  if( infeasible )
7497  {
7498  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7499 
7500  /* analyze the infeasibility if conflict analysis is applicable */
7502  {
7503  /* conflict analysis can only be applied in solving stage */
7504  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7505 
7506  /* initialize the conflict analysis */
7508 
7509  /* add the two variables which are fixed to zero within a negated clique */
7510  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7511  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7512 
7513  /* start the conflict analysis */
7514  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7515  }
7516  *cutoff = TRUE;
7517  break;
7518  }
7519  assert(tightened);
7520  ++(*nfixedvars);
7521  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7522  }
7523  }
7524 
7525  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7526  localminweightsum = 0;
7527  /* we can jump to the end of this clique */
7528  i = cliqueendposs[c - 1];
7529 
7530  if( *cutoff )
7531  break;
7532  }
7533  }
7534  ++i;
7535  }
7536  /* add last clique minweightsum */
7537  minweightsum += localminweightsum;
7538 
7539  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7540  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7541 
7542  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7543  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7544  {
7545  SCIP_Longint maxcliqueweight = -1LL;
7546 
7547  /* loop over cliques */
7548  for( c = 0; c < nnegcliques; ++c )
7549  {
7550  SCIP_VAR* maxvar;
7551  SCIP_Bool maxvarfixed;
7552  int endvarposclique;
7553  int startvarposclique;
7554 
7555  assert(myvars != NULL);
7556  assert(nnegcliques == consdata->nnegcliques);
7557  assert(myweights != NULL);
7558  assert(secondmaxweights != NULL);
7559  assert(cliquestartposs != NULL);
7560 
7561  endvarposclique = cliqueendposs[c];
7562  startvarposclique = cliquestartposs[c];
7563 
7564  maxvar = myvars[startvarposclique];
7565 
7566  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7567  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7568  continue;
7569 
7570  maxcliqueweight = myweights[startvarposclique];
7571  maxvarfixed = FALSE;
7572  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7573  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7574  * exceeds the capacity the maximum weight variable can be fixed to zero.
7575  */
7576  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7577  {
7578 #ifndef NDEBUG
7579  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7580 #endif
7581  assert(maxcliqueweight >= secondmaxweights[c]);
7582  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7583 
7584  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7585  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7586  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7587  assert(consdata->onesweightsum == oldonesweightsum);
7588  assert(!infeasible);
7589  assert(tightened);
7590  (*nfixedvars)++;
7591  maxvarfixed = TRUE;
7592  }
7593  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7594  * fits into the knapsack
7595  */
7596  else if( nnegcliques - c == nvars - startvarposclique )
7597  break;
7598  /* early termination of the remaining loop because no further variable fixings are possible:
7599  *
7600  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7601  * largest was set to 0) does not suffice to infer additional variable fixings because
7602  *
7603  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7604  * - their second largest elements are at least as large as the smallest weight of the knapsack
7605  */
7606  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7607  break;
7608 
7609  /* loop over items with non-maximal weight (omitting the first position) */
7610  for( i = endvarposclique; i > startvarposclique; --i )
7611  {
7612  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7613  * messed up the clique preprocessing in the previous loop to filter those variables out */
7614  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7615 
7616  /* only check variables of negated cliques for which no variable is locally fixed */
7617  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7618  {
7619  assert(maxcliqueweight >= myweights[i]);
7620  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7621 
7622  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7623  *
7624  * the maxvar was already fixed to 0 because it has a huge gain.
7625  *
7626  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7627  * since replacing i with the element of maximal weight leads to infeasibility */
7628  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7629  {
7630 #ifndef NDEBUG
7631  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7632 #endif
7633  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7634  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7635  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7636  assert(!infeasible);
7637  assert(tightened);
7638  ++(*nfixedvars);
7639  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7640 
7641  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7642  * consdata->onesweightsum
7643  */
7644  minweightsum -= myweights[i];
7645  assert(minweightsum >= 0);
7646  }
7647  else
7648  break;
7649  }
7650  }
7651 #ifndef NDEBUG
7652  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7653  for( ; i > startvarposclique; --i )
7654  {
7655  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7656  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7657 
7658  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7659  assert(varisfixed || !exceedscapacity);
7660  }
7661 #endif
7662  }
7663  }
7664  SCIPfreeBufferArray(scip, &secondmaxweights);
7665  SCIPfreeBufferArray(scip, &cliqueendposs);
7666  SCIPfreeBufferArray(scip, &cliquestartposs);
7667  SCIPfreeBufferArray(scip, &myweights);
7668  SCIPfreeBufferArray(scip, &myvars);
7669  }
7670 
7671  assert(consdata->negcliquepartitioned || minweightsum == 0);
7672  }
7673  while( FALSE );
7674 
7675  assert(usenegatedclique || minweightsum == 0);
7676  /* check, if weights of fixed variables already exceed knapsack capacity */
7677  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7678  {
7679  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7680  consdata->onesweightsum, consdata->capacity);
7681 
7682  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7683  *cutoff = TRUE;
7684 
7685  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7687  {
7688  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7689  SCIP_Longint weight;
7690 
7691  weight = 0;
7692 
7694 
7695  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7696  {
7697  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7698  {
7699  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7700  weight += consdata->weights[i];
7701  }
7702  }
7703 
7704  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7705  }
7706 
7707  return SCIP_OKAY;
7708  }
7709 
7710  /* the algorithm below is a special case of propagation involving negated cliques */
7711  if( !usenegatedclique )
7712  {
7713  assert(consdata->sorted);
7714  residualcapacity = consdata->capacity - consdata->onesweightsum;
7715 
7716  /* fix all variables to zero, that don't fit into the knapsack anymore */
7717  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7718  {
7719  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7720  * to zero
7721  */
7722  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7723  {
7724  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7725  {
7726  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7727  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7728  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7729  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7730  assert(!infeasible);
7731  assert(tightened);
7732  (*nfixedvars)++;
7733  }
7734  }
7735  }
7736  }
7737 
7738  /* check if the knapsack is now redundant */
7739  if( !SCIPconsIsModifiable(cons) )
7740  {
7741  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7742 
7743  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7744  for( i = 0; i < nvars; ++i )
7745  {
7746  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7747  {
7748  unfixedweightsum += consdata->weights[i];
7749 
7750  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7751  if( unfixedweightsum > consdata->capacity )
7752  return SCIP_OKAY;
7753  }
7754  }
7755  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7756  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7757  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7758  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7759  *redundant = TRUE;
7760  }
7761 
7762  return SCIP_OKAY;
7763 }
7764 
7765 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7766  * containing all negated variables of this knapsack constraint
7767  */
7768 static
7770  SCIP* scip, /**< SCIP data structure */
7771  SCIP_CONS* cons, /**< knapsack constraint */
7772  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7773  int* naddconss /**< pointer to count number of added constraints */
7774  )
7775 {
7776  SCIP_CONS* newcons;
7777  SCIP_CONSDATA* consdata;
7778 
7779  assert(scip != NULL);
7780  assert(cons != NULL);
7781  assert(ndelconss != NULL);
7782  assert(naddconss != NULL);
7783 
7784  consdata = SCIPconsGetData(cons);
7785  assert(consdata != NULL);
7786  assert(consdata->nvars > 1);
7787 
7788  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7789  if( consdata->nvars == 2 )
7790  {
7791  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7792 
7793  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7797  SCIPconsIsStickingAtNode(cons)) );
7798  }
7799  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7800  * containing all negated variables of the knapsack
7801  */
7802  else
7803  {
7804  SCIP_VAR** consvars;
7805 
7806  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7807 
7808  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7809  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7810 
7811  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7815  SCIPconsIsStickingAtNode(cons)) );
7816 
7817  SCIPfreeBufferArray(scip, &consvars);
7818  }
7819 
7820  SCIP_CALL( SCIPaddCons(scip, newcons) );
7821  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7822  ++(*naddconss);
7823 
7824  SCIP_CALL( SCIPdelCons(scip, cons) );
7825  ++(*ndelconss);
7826 
7827  return SCIP_OKAY;
7828 }
7829 
7830 /** delete redundant variables
7831  *
7832  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7833  *
7834  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7835  * => x4, x5 always fits into the knapsack, so we can delete them
7836  *
7837  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7838  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7839  */
7840 static
7842  SCIP* scip, /**< SCIP data structure */
7843  SCIP_CONS* cons, /**< knapsack constraint */
7844  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7845  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7846  * first which did not fit */
7847  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7848  int* nchgsides, /**< pointer to store the amount of changed sides */
7849  int* naddconss /**< pointer to count number of added constraints */
7850  )
7851 {
7852  SCIP_CONSHDLRDATA* conshdlrdata;
7853  SCIP_CONSDATA* consdata;
7854  SCIP_VAR** vars;
7855  SCIP_Longint* weights;
7856  SCIP_Longint capacity;
7857  SCIP_Longint gcd;
7858  int nvars;
7859  int w;
7860 
7861  assert(scip != NULL);
7862  assert(cons != NULL);
7863  assert(nchgcoefs != NULL);
7864  assert(nchgsides != NULL);
7865  assert(naddconss != NULL);
7866 
7867  consdata = SCIPconsGetData(cons);
7868  assert(consdata != NULL);
7869  assert(0 < frontsum && frontsum < consdata->weightsum);
7870  assert(0 < splitpos && splitpos < consdata->nvars);
7871 
7872  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7873  assert(conshdlrdata != NULL);
7874 
7875  vars = consdata->vars;
7876  weights = consdata->weights;
7877  nvars = consdata->nvars;
7878  capacity = consdata->capacity;
7879 
7880  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7881  * weight must not be sorted by their index
7882  */
7883 #ifndef NDEBUG
7884  for( w = nvars - 1; w > 0; --w )
7885  assert(weights[w] <= weights[w-1]);
7886 #endif
7887 
7888  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7889  if( consdata->nvars - 1 == splitpos )
7890  return SCIP_OKAY;
7891 
7892  assert(frontsum + weights[splitpos] > capacity);
7893 
7894  /* detect redundant variables */
7895  if( consdata->weightsum - weights[splitpos] <= capacity )
7896  {
7897  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7898  * fit
7899  */
7900  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7901 
7902  /* delete items and update capacity */
7903  for( w = nvars - 1; w > splitpos; --w )
7904  {
7905  consdata->capacity -= weights[w];
7906  SCIP_CALL( delCoefPos(scip, cons, w) );
7907  }
7908  assert(w == splitpos);
7909 
7910  ++(*nchgsides);
7911  *nchgcoefs += (nvars - splitpos);
7912 
7913  /* division by greatest common divisor */
7914  gcd = weights[w];
7915  for( ; w >= 0 && gcd > 1; --w )
7916  {
7917  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7918  }
7919 
7920  /* normalize if possible */
7921  if( gcd > 1 )
7922  {
7923  for( w = splitpos; w >= 0; --w )
7924  {
7925  consdataChgWeight(consdata, w, weights[w]/gcd);
7926  }
7927  (*nchgcoefs) += nvars;
7928 
7929  consdata->capacity /= gcd;
7930  ++(*nchgsides);
7931  }
7932 
7933  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7934  * weight must not be sorted by their index
7935  */
7936 #ifndef NDEBUG
7937  for( w = consdata->nvars - 1; w > 0; --w )
7938  assert(weights[w] <= weights[w - 1]);
7939 #endif
7940  }
7941  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7942  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7943  * splitpos and needs to fit into the knapsack
7944  */
7945  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7946  {
7947  int* clqpart;
7948  int nclq;
7949  int len;
7950 
7951  len = nvars - (splitpos + 1);
7952  /* allocate temporary memory */
7953  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7954 
7955  /* calculate clique partition */
7956  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7957 
7958  /* check if we found at least one clique */
7959  if( nclq < len )
7960  {
7961  SCIP_Longint maxactduetoclq;
7962  int cliquenum;
7963 
7964  maxactduetoclq = 0;
7965  cliquenum = 0;
7966 
7967  /* calculate maximum activity due to cliques */
7968  for( w = 0; w < len; ++w )
7969  {
7970  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7971  if( clqpart[w] == cliquenum )
7972  {
7973  maxactduetoclq += weights[w + splitpos + 1];
7974  ++cliquenum;
7975  }
7976  }
7977 
7978  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
7979  * so delete them and create for all clique the corresponding clique constraints and update the capacity
7980  */
7981  if( frontsum + maxactduetoclq <= capacity )
7982  {
7983  SCIP_VAR** clqvars;
7984  int nclqvars;
7985  int c;
7986 
7987  assert(maxactduetoclq < weights[splitpos]);
7988 
7989  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
7990 
7991  /* allocate temporary memory */
7992  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
7993 
7994  for( c = 0; c < nclq; ++c )
7995  {
7996  nclqvars = 0;
7997  for( w = 0; w < len; ++w )
7998  {
7999  if( clqpart[w] == c )
8000  {
8001  clqvars[nclqvars] = vars[w + splitpos + 1];
8002  ++nclqvars;
8003  }
8004  }
8005 
8006  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8007  if( nclqvars > 1 )
8008  {
8009  SCIP_CONS* cliquecons;
8010  char name[SCIP_MAXSTRLEN];
8011 
8012  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8013  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8017  SCIPconsIsStickingAtNode(cons)) );
8018  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8019  SCIPdebugPrintCons(scip, cliquecons, NULL);
8020  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8021  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8022  ++(*naddconss);
8023  }
8024  }
8025 
8026  /* delete items and update capacity */
8027  for( w = nvars - 1; w > splitpos; --w )
8028  {
8029  SCIP_CALL( delCoefPos(scip, cons, w) );
8030  ++(*nchgcoefs);
8031  }
8032  consdata->capacity -= maxactduetoclq;
8033  assert(frontsum <= consdata->capacity);
8034  ++(*nchgsides);
8035 
8036  assert(w == splitpos);
8037 
8038  /* renew weights pointer */
8039  weights = consdata->weights;
8040 
8041  /* division by greatest common divisor */
8042  gcd = weights[w];
8043  for( ; w >= 0 && gcd > 1; --w )
8044  {
8045  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8046  }
8047 
8048  /* normalize if possible */
8049  if( gcd > 1 )
8050  {
8051  for( w = splitpos; w >= 0; --w )
8052  {
8053  consdataChgWeight(consdata, w, weights[w]/gcd);
8054  }
8055  (*nchgcoefs) += nvars;
8056 
8057  consdata->capacity /= gcd;
8058  ++(*nchgsides);
8059  }
8060 
8061  /* free temporary memory */
8062  SCIPfreeBufferArray(scip, &clqvars);
8063 
8064  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8065  * weight must not be sorted by their index
8066  */
8067 #ifndef NDEBUG
8068  for( w = consdata->nvars - 1; w > 0; --w )
8069  assert(weights[w] <= weights[w - 1]);
8070 #endif
8071  }
8072  }
8073 
8074  /* free temporary memory */
8075  SCIPfreeBufferArray(scip, &clqpart);
8076  }
8077 
8078  return SCIP_OKAY;
8079 }
8080 
8081 /* detect redundant variables which always fits into the knapsack
8082  *
8083  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8084  *
8085  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8086  * => x4, x5 always fits into the knapsack, so we can delete them
8087  *
8088  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8089  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8090  */
8091 static
8093  SCIP* scip, /**< SCIP data structure */
8094  SCIP_CONS* cons, /**< knapsack constraint */
8095  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8096  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8097  int* nchgsides, /**< pointer to store the amount of changed sides */
8098  int* naddconss /**< pointer to count number of added constraints */
8099  )
8101  SCIP_CONSHDLRDATA* conshdlrdata;
8102  SCIP_CONSDATA* consdata;
8103  SCIP_VAR** vars;
8104  SCIP_Longint* weights;
8105  SCIP_Longint capacity;
8106  SCIP_Longint sum;
8107  int noldchgcoefs;
8108  int nvars;
8109  int v;
8110  int w;
8111 
8112  assert(scip != NULL);
8113  assert(cons != NULL);
8114  assert(ndelconss != NULL);
8115  assert(nchgcoefs != NULL);
8116  assert(nchgsides != NULL);
8117  assert(naddconss != NULL);
8118 
8119  consdata = SCIPconsGetData(cons);
8120  assert(consdata != NULL);
8121  assert(consdata->nvars >= 2);
8122  assert(consdata->weightsum > consdata->capacity);
8123 
8124  noldchgcoefs = *nchgcoefs;
8125  vars = consdata->vars;
8126  weights = consdata->weights;
8127  nvars = consdata->nvars;
8128  capacity = consdata->capacity;
8129  sum = 0;
8130 
8131  /* search for maximal fitting items */
8132  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8133  sum += weights[v];
8134 
8135  assert(v < nvars);
8136 
8137  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8138  if( v == nvars - 1 )
8139  {
8140  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8141  assert(SCIPconsIsDeleted(cons));
8142 
8143  return SCIP_OKAY;
8144  }
8145 
8146  if( v < nvars - 1 )
8147  {
8148  /* try to delete variables */
8149  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8150  assert(consdata->nvars > 1);
8151 
8152  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8153  if( v == consdata->nvars - 1 )
8154  {
8155  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8156  assert(SCIPconsIsDeleted(cons));
8157  }
8158 
8159  return SCIP_OKAY;
8160  }
8161 
8162  /* if we already found some redundant variables, stop here */
8163  if( *nchgcoefs > noldchgcoefs )
8164  return SCIP_OKAY;
8165 
8166  assert(vars == consdata->vars);
8167  assert(weights == consdata->weights);
8168  assert(nvars == consdata->nvars);
8169  assert(capacity == consdata->capacity);
8170 
8171  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8172  assert(conshdlrdata != NULL);
8173  /* calculate clique partition */
8174  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8175 
8176  /* check for real existing cliques */
8177  if( consdata->cliquepartition[v] < v )
8178  {
8179  SCIP_Longint sumfront;
8180  SCIP_Longint maxactduetoclqfront;
8181  int* clqpart;
8182  int cliquenum;
8183 
8184  sumfront = 0;
8185  maxactduetoclqfront = 0;
8186 
8187  clqpart = consdata->cliquepartition;
8188  cliquenum = 0;
8189 
8190  /* calculate maximal activity due to cliques */
8191  for( w = 0; w < nvars; ++w )
8192  {
8193  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8194  if( clqpart[w] == cliquenum )
8195  {
8196  if( maxactduetoclqfront + weights[w] <= capacity )
8197  {
8198  maxactduetoclqfront += weights[w];
8199  ++cliquenum;
8200  }
8201  else
8202  break;
8203  }
8204  sumfront += weights[w];
8205  }
8206  assert(w >= v);
8207 
8208  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8209  * information
8210  */
8211  if( conshdlrdata->disaggregation && w == nvars )
8212  {
8213  SCIP_VAR** clqvars;
8214  int nclqvars;
8215  int c;
8216  int ncliques;
8217 
8218  assert(maxactduetoclqfront <= capacity);
8219 
8220  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8221 
8222  ncliques = consdata->ncliques;
8223 
8224  /* allocate temporary memory */
8225  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8226 
8227  for( c = 0; c < ncliques; ++c )
8228  {
8229  nclqvars = 0;
8230  for( w = 0; w < nvars; ++w )
8231  {
8232  if( clqpart[w] == c )
8233  {
8234  clqvars[nclqvars] = vars[w];
8235  ++nclqvars;
8236  }
8237  }
8238 
8239  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8240  if( nclqvars > 1 )
8241  {
8242  SCIP_CONS* cliquecons;
8243  char name[SCIP_MAXSTRLEN];
8244 
8245  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8246  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8250  SCIPconsIsStickingAtNode(cons)) );
8251  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8252  SCIPdebugPrintCons(scip, cliquecons, NULL);
8253  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8254  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8255  ++(*naddconss);
8256  }
8257  }
8258 
8259  /* delete old constraint */
8260  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8261  ++(*ndelconss);
8262 
8263  SCIPfreeBufferArray(scip, &clqvars);
8264 
8265  return SCIP_OKAY;
8266  }
8267 
8268  if( w > v && w < nvars - 1 )
8269  {
8270  /* try to delete variables */
8271  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8272  }
8273  }
8274 
8275  return SCIP_OKAY;
8276 }
8277 
8278 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8279 static
8280 void normalizeWeights(
8281  SCIP_CONS* cons, /**< knapsack constraint */
8282  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8283  int* nchgsides /**< pointer to count number of side changes */
8284  )
8285 {
8286  SCIP_CONSDATA* consdata;
8287  SCIP_Longint gcd;
8288  int i;
8289 
8290  assert(nchgcoefs != NULL);
8291  assert(nchgsides != NULL);
8292  assert(!SCIPconsIsModifiable(cons));
8293 
8294  consdata = SCIPconsGetData(cons);
8295  assert(consdata != NULL);
8296  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8297  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8298  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8299  assert(consdata->nvars >= 1);
8300 
8301  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8302  sortItems(consdata);
8303 
8304  gcd = consdata->weights[consdata->nvars-1];
8305  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8306  {
8307  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8308  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8309 
8310  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8311  }
8312 
8313  if( gcd >= 2 )
8314  {
8315  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8316 
8317  for( i = 0; i < consdata->nvars; ++i )
8318  {
8319  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8320  }
8321  consdata->capacity /= gcd;
8322  (*nchgcoefs) += consdata->nvars;
8323  (*nchgsides)++;
8324 
8325  /* weight should still be sorted, because the reduction preserves this */
8326 #ifndef NDEBUG
8327  for( i = consdata->nvars - 1; i > 0; --i )
8328  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8329 #endif
8330  consdata->sorted = TRUE;
8331  }
8332 }
8333 
8334 /** dual weights tightening for knapsack constraints
8335  *
8336  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8337  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8338  * constraint
8339  *
8340  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8341  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8342  *
8343  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8344  *
8345  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8346  *
8347  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8348  *
8349  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8350  *
8351  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8352  */
8353 static
8355  SCIP* scip, /**< SCIP data structure */
8356  SCIP_CONS* cons, /**< knapsack constraint */
8357  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8358  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8359  int* nchgsides, /**< pointer to store the amount of changed sides */
8360  int* naddconss /**< pointer to count number of added constraints */
8361  )
8363  SCIP_CONSDATA* consdata;
8364  SCIP_Longint* weights;
8365  SCIP_Longint dualcapacity;
8366  SCIP_Longint reductionsum;
8367  SCIP_Longint capacity;
8368  SCIP_Longint exceedsum;
8369  int oldnchgcoefs;
8370  int nvars;
8371  int vbig;
8372  int v;
8373  int w;
8374 #ifndef NDEBUG
8375  int oldnchgsides;
8376 #endif
8377 
8378  assert(scip != NULL);
8379  assert(cons != NULL);
8380  assert(ndelconss != NULL);
8381  assert(nchgcoefs != NULL);
8382  assert(nchgsides != NULL);
8383  assert(naddconss != NULL);
8384 
8385 #ifndef NDEBUG
8386  oldnchgsides = *nchgsides;
8387 #endif
8388 
8389  consdata = SCIPconsGetData(cons);
8390  assert(consdata != NULL);
8391  assert(consdata->weightsum > consdata->capacity);
8392  assert(consdata->nvars >= 2);
8393  assert(consdata->sorted);
8394 
8395  /* constraint should be merged */
8396  assert(consdata->merged);
8397 
8398  nvars = consdata->nvars;
8399  weights = consdata->weights;
8400  capacity = consdata->capacity;
8401 
8402  oldnchgcoefs = *nchgcoefs;
8403 
8404  /* case 1. */
8405  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8406  {
8407  SCIP_CONS* newcons;
8408 
8409  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8410  *
8411  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8412  */
8413  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8414 
8415  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8419  SCIPconsIsStickingAtNode(cons)) );
8420 
8421  SCIP_CALL( SCIPaddCons(scip, newcons) );
8422  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8423  ++(*naddconss);
8424 
8425  SCIP_CALL( SCIPdelCons(scip, cons) );
8426  ++(*ndelconss);
8427 
8428  return SCIP_OKAY;
8429  }
8430 
8431  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8432  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8433  {
8434  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8435  assert(SCIPconsIsDeleted(cons));
8436 
8437  return SCIP_OKAY;
8438  }
8439 
8440  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8441  /* @todo might be changed/removed when improving the coeffcients tightening */
8442  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8443  return SCIP_OKAY;
8444 
8445  /* case 2. */
8446 
8447  v = 0;
8448 
8449  /* @todo generalize the following algorithm for several parts of the knapsack
8450  *
8451  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8452  * variables each combination is a minimal cover, some examples
8453  *
8454  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8455  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8456  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8457  *
8458  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8459  *
8460  */
8461 
8462  /* determine big weights that fit only by itself */
8463  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8464  ++v;
8465 
8466  vbig = v;
8467  assert(vbig < nvars - 1);
8468  exceedsum = 0;
8469 
8470  /* determine the amount needed to exceed the capacity */
8471  while( v < nvars && exceedsum <= capacity )
8472  {
8473  exceedsum += weights[v];
8474  ++v;
8475  }
8476 
8477  /* if we exceeded the capacity we might reduce the weights */
8478  if( exceedsum > capacity )
8479  {
8480  assert(vbig > 0 || v < nvars);
8481 
8482  /* all small weights were needed to exceed the capacity */
8483  if( v == nvars )
8484  {
8485  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8486  assert(newweight > 0);
8487 
8488  /* reduce big weights */
8489  for( v = 0; v < vbig; ++v )
8490  {
8491  if( weights[v] > newweight )
8492  {
8493  consdataChgWeight(consdata, v, newweight);
8494  ++(*nchgcoefs);
8495  }
8496  }
8497 
8498  /* reduce small weights */
8499  for( ; v < nvars; ++v )
8500  {
8501  if( weights[v] > 1 )
8502  {
8503  consdataChgWeight(consdata, v, 1LL);
8504  ++(*nchgcoefs);
8505  }
8506  }
8507 
8508  consdata->capacity = newweight;
8509 
8510  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8511  * weight must not be sorted by their index
8512  */
8513 #ifndef NDEBUG
8514  for( v = nvars - 1; v > 0; --v )
8515  assert(weights[v] <= weights[v-1]);
8516 #endif
8517 
8518  return SCIP_OKAY;
8519  }
8520  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8521  * small weights
8522  */
8523  else
8524  {
8525  SCIP_Longint exceedsumback = 0;
8526  int nexceed = v - vbig;
8527 
8528  assert(nexceed > 1);
8529 
8530  /* determine weightsum of the same amount as before but of the smallest weight */
8531  for( w = nvars - 1; w >= nvars - nexceed; --w )
8532  exceedsumback += weights[w];
8533 
8534  assert(w >= 0);
8535 
8536  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8537  * combinations of all small weights
8538  */
8539  if( exceedsumback > capacity )
8540  {
8541  SCIP_Longint newweight = nexceed - 1;
8542 
8543  /* taking out the smallest element needs to fit */
8544  assert(exceedsumback - weights[nvars - 1] <= capacity);
8545 
8546  /* reduce big weights */
8547  for( v = 0; v < vbig; ++v )
8548  {
8549  if( weights[v] > newweight )
8550  {
8551  consdataChgWeight(consdata, v, newweight);
8552  ++(*nchgcoefs);
8553  }
8554  }
8555 
8556  /* reduce small weights */
8557  for( ; v < nvars; ++v )
8558  {
8559  if( weights[v] > 1 )
8560  {
8561  consdataChgWeight(consdata, v, 1LL);
8562  ++(*nchgcoefs);
8563  }
8564  }
8565 
8566  consdata->capacity = newweight;
8567 
8568  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8569  * weight must not be sorted by their index
8570  */
8571 #ifndef NDEBUG
8572  for( v = nvars - 1; v > 0; --v )
8573  assert(weights[v] <= weights[v-1]);
8574 #endif
8575  return SCIP_OKAY;
8576  }
8577  }
8578  }
8579  else
8580  {
8581  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8582  * not happen here
8583  */
8584  assert(vbig > 0 && vbig < nvars);
8585 
8586  /* either choose a big coefficients or all other variables
8587  *
8588  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8589  *
8590  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8591  * constraint to
8592  *
8593  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8594  */
8595 
8596  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8597  {
8598  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8599 #ifndef NDEBUG
8600  SCIP_Longint resweightsum = consdata->weightsum;
8601 
8602  for( v = 0; v < vbig; ++v )
8603  resweightsum -= weights[v];
8604 
8605  assert(exceedsum == resweightsum);
8606 #endif
8607  assert(newweight > 0);
8608 
8609  /* reduce big weights */
8610  for( v = 0; v < vbig; ++v )
8611  {
8612  if( weights[v] > newweight )
8613  {
8614  consdataChgWeight(consdata, v, newweight);
8615  ++(*nchgcoefs);
8616  }
8617  }
8618 
8619  /* reduce small weights */
8620  for( ; v < nvars; ++v )
8621  {
8622  if( weights[v] > 1 )
8623  {
8624  consdataChgWeight(consdata, v, 1LL);
8625  ++(*nchgcoefs);
8626  }
8627  }
8628 
8629  consdata->capacity = newweight;
8630 
8631  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8632  * weight must not be sorted by their index
8633  */
8634 #ifndef NDEBUG
8635  for( v = nvars - 1; v > 0; --v )
8636  assert(weights[v] <= weights[v-1]);
8637 #endif
8638  return SCIP_OKAY;
8639  }
8640  }
8641 
8642  /* case 3. */
8643 
8644  dualcapacity = consdata->weightsum - capacity;
8645  reductionsum = 0;
8646  v = 0;
8647 
8648  /* reduce big weights
8649  *
8650  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8651  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8652  * <=> x0 + x1 + x2 + x3 <= 3
8653  */
8654  while( weights[v] > dualcapacity )
8655  {
8656  reductionsum += (weights[v] - dualcapacity);
8657  consdataChgWeight(consdata, v, dualcapacity);
8658  ++v;
8659  assert(v < nvars);
8660  }
8661  (*nchgcoefs) += v;
8662 
8663  /* skip weights equal to the dualcapacity, because we cannot change them */
8664  while( v < nvars && weights[v] == dualcapacity )
8665  ++v;
8666 
8667  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8668  * after a possible removal of the last, redundant item
8669  *
8670  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8671  */
8672  if( v >= nvars - 1 )
8673  {
8674  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8675  if( v == nvars - 1 )
8676  {
8677  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8678  }
8679  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8680  assert(SCIPconsIsDeleted(cons));
8681 
8682  return SCIP_OKAY;
8683  }
8684  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8685  {
8686  /* @todo generalize the following algorithm for more than two variables */
8687 
8688  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8689  {
8690  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8691  * coefficients) of all or two variables of the rest
8692  *
8693  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8694  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8695  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8696  *
8697  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8698  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8699  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8700  *
8701  */
8702  if( v > 0 && weights[nvars - 2] > 1 )
8703  {
8704  int ncoefchg = 0;
8705 
8706  /* reduce all bigger weights */
8707  for( w = 0; w < v; ++w )
8708  {
8709  if( weights[w] > 2 )
8710  {
8711  consdataChgWeight(consdata, w, 2LL);
8712  ++ncoefchg;
8713  }
8714  else
8715  {
8716  assert(weights[0] == 2);
8717  assert(weights[v - 1] == 2);
8718  break;
8719  }
8720  }
8721 
8722  /* reduce all smaller weights */
8723  for( w = v; w < nvars; ++w )
8724  {
8725  if( weights[w] > 1 )
8726  {
8727  consdataChgWeight(consdata, w, 1LL);
8728  ++ncoefchg;
8729  }
8730  }
8731  assert(ncoefchg > 0);
8732 
8733  (*nchgcoefs) += ncoefchg;
8734 
8735  /* correct the capacity */
8736  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8737  assert(consdata->capacity > 0);
8738  assert(weights[0] <= consdata->capacity);
8739  assert(consdata->weightsum > consdata->capacity);
8740  /* reset the reductionsum */
8741  reductionsum = 0;
8742  }
8743  else if( v == 0 )
8744  {
8745  assert(weights[nvars - 2] == 1);
8746  }
8747  }
8748  else
8749  {
8750  SCIP_Longint minweight = weights[nvars - 1];
8751  SCIP_Longint newweight = dualcapacity - minweight;
8752  SCIP_Longint restsumweights = 0;
8753  SCIP_Longint sumcoef;
8754  SCIP_Bool sumcoefcase = FALSE;
8755  int startv = v;
8756  int end;
8757  int k;
8758 
8759  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8760 
8761  /* reduce big weights of pairs that exceed the dualcapacity
8762  *
8763  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8764  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8765  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8766  */
8767  while( weights[v] > newweight )
8768  {
8769  reductionsum += (weights[v] - newweight);
8770  consdataChgWeight(consdata, v, newweight);
8771  ++v;
8772  assert(v < nvars);
8773  }
8774  (*nchgcoefs) += (v - startv);
8775 
8776  /* skip equal weights */
8777  while( weights[v] == newweight )
8778  ++v;
8779 
8780  if( v > 0 )
8781  {
8782  for( w = v; w < nvars; ++w )
8783  restsumweights += weights[w];
8784  }
8785  else
8786  restsumweights = consdata->weightsum;
8787 
8788  if( restsumweights < dualcapacity )
8789  {
8790  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8791  *
8792  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8793  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8794  */
8795  if( startv == v )
8796  {
8797  /* remove redundant variables */
8798  for( w = nvars - 1; w >= v; --w )
8799  {
8800  SCIP_CALL( delCoefPos(scip, cons, v) );
8801  ++(*nchgcoefs);
8802  }
8803 
8804 #ifndef NDEBUG
8805  /* each coefficients should exceed the dualcapacity by itself */
8806  for( ; w >= 0; --w )
8807  assert(weights[w] == dualcapacity);
8808 #endif
8809  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8810  * upgrade this constraint
8811  */
8812  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8813  assert(SCIPconsIsDeleted(cons));
8814 
8815  return SCIP_OKAY;
8816  }
8817 
8818  /* special case where we have three different coefficient types
8819  *
8820  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8821  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8822  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8823  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8824  */
8825  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8826  {
8827  SCIP_Longint newcap;
8828 
8829  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8830  for( w = nvars - 1; w >= v; --w )
8831  {
8832  if( weights[w] > 1 )
8833  {
8834  consdataChgWeight(consdata, w, 1LL);
8835  ++(*nchgcoefs);
8836  }
8837  }
8838 
8839  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8840  * dualcapacity
8841  */
8842  newweight = (SCIP_Longint)nvars - v;
8843  assert(newweight > 1);
8844  for( ; w >= startv; --w )
8845  {
8846  if( weights[w] > newweight )
8847  {
8848  consdataChgWeight(consdata, w, newweight);
8849  ++(*nchgcoefs);
8850  }
8851  else
8852  assert(weights[w] == newweight);
8853  }
8854 
8855  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8856  ++newweight;
8857  assert(newweight > 2);
8858  for( ; w >= 0; --w )
8859  {
8860  if( weights[w] > newweight )
8861  {
8862  consdataChgWeight(consdata, w, newweight);
8863  ++(*nchgcoefs);
8864  }
8865  else
8866  assert(weights[w] == newweight);
8867  }
8868 
8869  /* update the capacity */
8870  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8871  if( consdata->capacity > newcap )
8872  {
8873  consdata->capacity = newcap;
8874  ++(*nchgsides);
8875  }
8876  else
8877  assert(consdata->capacity == newcap);
8878  }
8879  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8880 
8881  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8882  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8883 
8884  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8885  * weight must not be sorted by their index
8886  */
8887 #ifndef NDEBUG
8888  for( w = nvars - 1; w > 0; --w )
8889  assert(weights[w] <= weights[w - 1]);
8890 #endif
8891  return SCIP_OKAY;
8892  }
8893 
8894  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8895  end = nvars - 2;
8896  while( end >= 0 && weights[end] == weights[end + 1] )
8897  {
8898  assert(end >= v);
8899  --end;
8900  }
8901 
8902  if( v >= end )
8903  goto TERMINATE;
8904 
8905  end = nvars - 2;
8906 
8907  /* can we stop early, another special reduction case might exist */
8908  if( 2 * weights[end] > dualcapacity )
8909  {
8910  restsumweights = 0;
8911 
8912  /* determine capacity of the small items */
8913  for( w = end + 1; w < nvars; ++w )
8914  restsumweights += weights[w];
8915 
8916  if( restsumweights * 2 <= dualcapacity )
8917  {
8918  /* check for further posssible reductions in the middle */
8919  while( v < end && restsumweights + weights[v] >= dualcapacity )
8920  ++v;
8921 
8922  if( v >= end )
8923  goto TERMINATE;
8924 
8925  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8926  if( (dualcapacity & 1) == 0 )
8927  {
8928  newweight = dualcapacity / 2;
8929 
8930  /* set all middle coefficients */
8931  for( ; v <= end; ++v )
8932  {
8933  if( weights[v] > newweight )
8934  {
8935  reductionsum += (weights[v] - newweight);
8936  consdataChgWeight(consdata, v, newweight);
8937  ++(*nchgcoefs);
8938  }
8939  }
8940  }
8941  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8942  * other coefficients by 2
8943  */
8944  else
8945  {
8946  /* correct the reductionsum */
8947  reductionsum *= 2;
8948 
8949  /* multiply big coefficients by 2 */
8950  for( w = 0; w < v; ++w )
8951  {
8952  consdataChgWeight(consdata, w, weights[w] * 2);
8953  }
8954 
8955  newweight = dualcapacity;
8956  /* set all middle coefficients */
8957  for( ; v <= end; ++v )
8958  {
8959  reductionsum += (2 * weights[v] - newweight);
8960  consdataChgWeight(consdata, v, newweight);
8961  }
8962 
8963  /* multiply small coefficients by 2 */
8964  for( w = end + 1; w < nvars; ++w )
8965  {
8966  consdataChgWeight(consdata, w, weights[w] * 2);
8967  }
8968  (*nchgcoefs) += nvars;
8969 
8970  dualcapacity *= 2;
8971  consdata->capacity *= 2;
8972  ++(*nchgsides);
8973  }
8974  }
8975 
8976  goto TERMINATE;
8977  }
8978 
8979  /* further reductions using the next possible coefficient sum
8980  *
8981  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
8982  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
8983  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
8984  */
8985  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
8986  for( k = 0; k < 4; ++k )
8987  {
8988  /* determine next minimal coefficient sum */
8989  switch( k )
8990  {
8991  case 0:
8992  sumcoef = weights[nvars - 1] + weights[nvars - 2];
8993  break;
8994  case 1:
8995  assert(nvars >= 3);
8996  sumcoef = weights[nvars - 1] + weights[nvars - 3];
8997  break;
8998  case 2:
8999  assert(nvars >= 4);
9000  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9001  {
9002  sumcoefcase = TRUE;
9003  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9004  }
9005  else
9006  {
9007  sumcoefcase = FALSE;
9008  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9009  }
9010  break;
9011  case 3:
9012  assert(nvars >= 5);
9013  if( sumcoefcase )
9014  {
9015  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9016  }
9017  else
9018  {
9019  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9020  }
9021  break;
9022  default:
9023  return SCIP_ERROR;
9024  }
9025 
9026  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9027  minweight = weights[end];
9028  while( minweight <= sumcoef )
9029  {
9030  newweight = dualcapacity - minweight;
9031  startv = v;
9032  assert(v < nvars);
9033 
9034  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9035  /* shrink big coefficients */
9036  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9037  {
9038  reductionsum += (weights[v] - newweight);
9039  consdataChgWeight(consdata, v, newweight);
9040  ++v;
9041  assert(v < nvars);
9042  }
9043  (*nchgcoefs) += (v - startv);
9044 
9045  /* skip unchangable weights */
9046  while( weights[v] + minweight == dualcapacity )
9047  {
9048  assert(v < nvars);
9049  ++v;
9050  }
9051 
9052  --end;
9053  /* skip same end weights */
9054  while( end >= 0 && weights[end] == weights[end + 1] )
9055  --end;
9056 
9057  if( v >= end )
9058  goto TERMINATE;
9059 
9060  minweight = weights[end];
9061  }
9062 
9063  if( v >= end )
9064  goto TERMINATE;
9065 
9066  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9067  if( sumcoef < minweight )
9068  {
9069  minweight = sumcoef;
9070  newweight = dualcapacity - minweight;
9071  startv = v;
9072  assert(v < nvars);
9073 
9074  /* shrink big coefficients */
9075  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9076  {
9077  reductionsum += (weights[v] - newweight);
9078  consdataChgWeight(consdata, v, newweight);
9079  ++v;
9080  assert(v < nvars);
9081  }
9082  (*nchgcoefs) += (v - startv);
9083 
9084  /* skip unchangable weights */
9085  while( weights[v] + minweight == dualcapacity )
9086  {
9087  assert(v < nvars);
9088  ++v;
9089  }
9090  }
9091 
9092  if( v >= end )
9093  goto TERMINATE;
9094 
9095  /* can we stop early, another special reduction case might exist */
9096  if( 2 * weights[end] > dualcapacity )
9097  {
9098  restsumweights = 0;
9099 
9100  /* determine capacity of the small items */
9101  for( w = end + 1; w < nvars; ++w )
9102  restsumweights += weights[w];
9103 
9104  if( restsumweights * 2 <= dualcapacity )
9105  {
9106  /* check for further posssible reductions in the middle */
9107  while( v < end && restsumweights + weights[v] >= dualcapacity )
9108  ++v;
9109 
9110  if( v >= end )
9111  goto TERMINATE;
9112 
9113  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9114  if( (dualcapacity & 1) == 0 )
9115  {
9116  newweight = dualcapacity / 2;
9117 
9118  /* set all middle coefficients */
9119  for( ; v <= end; ++v )
9120  {
9121  if( weights[v] > newweight )
9122  {
9123  reductionsum += (weights[v] - newweight);
9124  consdataChgWeight(consdata, v, newweight);
9125  ++(*nchgcoefs);
9126  }
9127  }
9128  }
9129  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9130  * other coefficients by 2
9131  */
9132  else
9133  {
9134  /* correct the reductionsum */
9135  reductionsum *= 2;
9136 
9137  /* multiply big coefficients by 2 */
9138  for( w = 0; w < v; ++w )
9139  {
9140  consdataChgWeight(consdata, w, weights[w] * 2);
9141  }
9142 
9143  newweight = dualcapacity;
9144  /* set all middle coefficients */
9145  for( ; v <= end; ++v )
9146  {
9147  reductionsum += (2 * weights[v] - newweight);
9148  consdataChgWeight(consdata, v, newweight);
9149  }
9150 
9151  /* multiply small coefficients by 2 */
9152  for( w = end + 1; w < nvars; ++w )
9153  {
9154  consdataChgWeight(consdata, w, weights[w] * 2);
9155  }
9156  (*nchgcoefs) += nvars;
9157 
9158  dualcapacity *= 2;
9159  consdata->capacity *= 2;
9160  ++(*nchgsides);
9161  }
9162  }
9163 
9164  goto TERMINATE;
9165  }
9166 
9167  /* cannot tighten any further */
9168  if( 2 * sumcoef > dualcapacity )
9169  goto TERMINATE;
9170  }
9171  }
9172  }
9173 
9174  TERMINATE:
9175  /* correct capacity */
9176  if( reductionsum > 0 )
9177  {
9178  assert(v > 0);
9179 
9180  consdata->capacity -= reductionsum;
9181  ++(*nchgsides);
9182 
9183  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9184  }
9185  assert(weights[0] <= consdata->capacity);
9186 
9187  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9188  * weight must not be sorted by their index
9189  */
9190 #ifndef NDEBUG
9191  for( w = nvars - 1; w > 0; --w )
9192  assert(weights[w] <= weights[w - 1]);
9193 #endif
9194 
9195  if( oldnchgcoefs < *nchgcoefs )
9196  {
9197  assert(!SCIPconsIsDeleted(cons));
9198 
9199  /* it might be that we can divide the weights by their greatest common divisor */
9200  normalizeWeights(cons, nchgcoefs, nchgsides);
9201  }
9202  else
9203  {
9204  assert(oldnchgcoefs == *nchgcoefs);
9205  assert(oldnchgsides == *nchgsides);
9206  }
9207 
9208  return SCIP_OKAY;
9209 }
9210 
9211 
9212 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9213 static
9215  SCIP* scip, /**< SCIP data structure */
9216  SCIP_CONS* cons, /**< knapsack constraint */
9217  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9218  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9219  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9220  )
9221 {
9222  SCIP_VAR** vars;
9223  SCIP_CONSDATA* consdata;
9224  SCIP_Longint* weights;
9225  SCIP_Longint capacity;
9226  SCIP_Bool infeasible;
9227  SCIP_Bool fixed;
9228  int nvars;
9229  int v;
9230 
9231  assert(scip != NULL);
9232  assert(cons != NULL);
9233  assert(nfixedvars != NULL);
9234  assert(ndelconss != NULL);
9235  assert(nchgcoefs != NULL);
9236 
9237  consdata = SCIPconsGetData(cons);
9238  assert(consdata != NULL);
9239 
9240  nvars = consdata->nvars;
9241 
9242  /* no variables left, then delete constraint */
9243  if( nvars == 0 )
9244  {
9245  assert(consdata->capacity >= 0);
9246 
9247  SCIP_CALL( SCIPdelCons(scip, cons) );
9248  ++(*ndelconss);
9249 
9250  return SCIP_OKAY;
9251  }
9252 
9253  /* sort items */
9254  sortItems(consdata);
9255 
9256  vars = consdata->vars;
9257  weights = consdata->weights;
9258  capacity = consdata->capacity;
9259  v = 0;
9260 
9261  /* check for weights bigger than the capacity */
9262  while( v < nvars && weights[v] > capacity )
9263  {
9264  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9265  assert(!infeasible);
9266 
9267  if( fixed )
9268  ++(*nfixedvars);
9269 
9270  ++v;
9271  }
9272 
9273  /* if we fixed at least one variable we need to delete them from the constraint */
9274  if( v > 0 )
9275  {
9276  if( v == nvars )
9277  {
9278  SCIP_CALL( SCIPdelCons(scip, cons) );
9279  ++(*ndelconss);
9280 
9281  return SCIP_OKAY;
9282  }
9283 
9284  /* delete all position from back to front */
9285  for( --v; v >= 0; --v )
9286  {
9287  SCIP_CALL( delCoefPos(scip, cons, v) );
9288  ++(*nchgcoefs);
9289  }
9290 
9291  /* sort items again because of deletion */
9292  sortItems(consdata);
9293  assert(vars == consdata->vars);
9294  assert(weights == consdata->weights);
9295  }
9296  assert(consdata->sorted);
9297  assert(weights[0] <= capacity);
9298 
9299  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9300  {
9301  SCIP_CALL( SCIPdelCons(scip, cons) );
9302  ++(*ndelconss);
9303  }
9304 
9305  return SCIP_OKAY;
9306 }
9307 
9308 
9309 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9310  *
9311  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9312  *
9313  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9314  *
9315  * the above constraint can be changed to
9316  *
9317  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9318  *
9319  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9320  *
9321  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9322  *
9323  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9324  * constraint further, e.g.
9325  *
9326  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9327  * => 2x1 + x2 + x3 + x4 <= 2
9328  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9329  */
9330 static
9332  SCIP* scip, /**< SCIP data structure */
9333  SCIP_CONS* cons, /**< knapsack constraint */
9334  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9335  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9336  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9337  int* nchgsides, /**< pointer to store the amount of changed sides */
9338  int* naddconss, /**< pointer to count number of added constraints */
9339  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9340  )
9341 {
9342  SCIP_VAR** vars;
9343  SCIP_CONSDATA* consdata;
9344  SCIP_Longint* weights;
9345  SCIP_Longint restweight;
9346  SCIP_Longint newweight;
9347  SCIP_Longint weight;
9348  SCIP_Longint oldgcd;
9349  SCIP_Longint rest;
9350  SCIP_Longint gcd;
9351  int oldnchgcoefs;
9352  int oldnchgsides;
9353  int candpos;
9354  int candpos2;
9355  int offsetv;
9356  int nvars;
9357  int v;
9358 
9359  assert(scip != NULL);
9360  assert(cons != NULL);
9361  assert(nfixedvars != NULL);
9362  assert(ndelconss != NULL);
9363  assert(nchgcoefs != NULL);
9364  assert(nchgsides != NULL);
9365  assert(naddconss != NULL);
9366  assert(cutoff != NULL);
9367  assert(!SCIPconsIsModifiable(cons));
9368 
9369  consdata = SCIPconsGetData(cons);
9370  assert( consdata != NULL );
9371 
9372  *cutoff = FALSE;
9373 
9374  /* remove double enties and also combinations of active and negated variables */
9375  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9376  assert(consdata->merged);
9377  if( *cutoff )
9378  return SCIP_OKAY;
9379 
9380  assert(consdata->capacity >= 0);
9381 
9382  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9383  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9384 
9385  if( SCIPconsIsDeleted(cons) )
9386  return SCIP_OKAY;
9387 
9388  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9389  {
9390  /* 1. dual weights tightening */
9391  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9392 
9393  if( SCIPconsIsDeleted(cons) )
9394  return SCIP_OKAY;
9395  /* 2. delete redundant variables */
9396  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9397 
9398  if( SCIPconsIsDeleted(cons) )
9399  return SCIP_OKAY;
9400  }
9401 
9402  weights = consdata->weights;
9403  nvars = consdata->nvars;
9404 
9405 #ifndef NDEBUG
9406  /* constraint might not be sorted, but the weights are already sorted */
9407  for( v = nvars - 1; v > 0; --v )
9408  assert(weights[v] <= weights[v-1]);
9409 #endif
9410 
9411  /* determine greatest common divisor */
9412  gcd = weights[nvars - 1];
9413  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9414  {
9415  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9416  }
9417 
9418  /* divide the constraint by their greatest common divisor */
9419  if( gcd >= 2 )
9420  {
9421  for( v = nvars - 1; v >= 0; --v )
9422  {
9423  consdataChgWeight(consdata, v, weights[v]/gcd);
9424  }
9425  (*nchgcoefs) += nvars;
9426 
9427  consdata->capacity /= gcd;
9428  (*nchgsides)++;
9429  }
9430  assert(consdata->nvars == nvars);
9431 
9432  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9433  * must not be sorted by their index
9434  */
9435 #ifndef NDEBUG
9436  for( v = nvars - 1; v > 0; --v )
9437  assert(weights[v] <= weights[v-1]);
9438 #endif
9439 
9440  /* 3. start gcd procedure for all variables */
9441  do
9442  {
9443  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9444  SCIPdebug( oldnchgsides = *nchgsides; )
9445 
9446  vars = consdata->vars;
9447  weights = consdata->weights;
9448  nvars = consdata->nvars;
9449 
9450  /* stop if we have two coefficients which are one in absolute value */
9451  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9452  return SCIP_OKAY;
9453 
9454  v = 0;
9455  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9456  * gcd
9457  */
9458  while( weights[v] == consdata->capacity )
9459  {
9460  ++v;
9461  assert(v < nvars);
9462  }
9463 
9464  /* all but one variable are as big as the capacity, this is handled elsewhere */
9465  if( v == nvars - 1 )
9466  return SCIP_OKAY;
9467 
9468  offsetv = v;
9469 
9470  gcd = -1;
9471  candpos = -1;
9472  candpos2 = -1;
9473 
9474  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9475  * change the coefficient
9476  */
9477  for( v = nvars - 1; v >= offsetv; --v )
9478  {
9479  weight = weights[v];
9480  assert(weight >= 1);
9481 
9482  oldgcd = gcd;
9483 
9484  if( gcd == -1 )
9485  {
9486  gcd = weights[v];
9487  assert(gcd >= 1);
9488  }
9489  else
9490  {
9491  /* calculate greatest common divisor for all variables */
9492  gcd = SCIPcalcGreComDiv(gcd, weight);
9493  }
9494 
9495  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9496  * can terminate
9497  */
9498  if( gcd == 1 )
9499  {
9500  /* found candidate */
9501  if( candpos == -1 )
9502  {
9503  gcd = oldgcd;
9504  candpos = v;
9505 
9506  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9507  if( v == nvars - 2 )
9508  candpos2 = v + 1;
9509  }
9510  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9511  else
9512  {
9513  if( candpos == v + 1 && candpos2 == v + 2 )
9514  {
9515  assert(candpos2 == nvars - 1);
9516 
9517  /* take new candidates */
9518  candpos = candpos2;
9519 
9520  /* recalculate gcd from scratch */
9521  gcd = weights[v+1];
9522  assert(gcd >= 1);
9523 
9524  /* calculate greatest common divisor for variables */
9525  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9526  if( gcd == 1 )
9527  return SCIP_OKAY;
9528  }
9529  else
9530  /* cannot determine a possible coefficient for reduction */
9531  return SCIP_OKAY;
9532  }
9533  }
9534  }
9535  assert(gcd >= 2);
9536 
9537  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9538  * further
9539  */
9540  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9541 
9542  /* determine the remainder of the capacity and the gcd */
9543  rest = consdata->capacity % gcd;
9544  assert(rest >= 0);
9545  assert(rest < gcd);
9546 
9547  if( candpos == -1 )
9548  {
9549  /* we assume that the constraint was normalized */
9550  assert(rest > 0);
9551 
9552  /* replace old with new capacity */
9553  consdata->capacity -= rest;
9554  ++(*nchgsides);
9555 
9556  /* replace old big coefficients with new capacity */
9557  for( v = 0; v < offsetv; ++v )
9558  {
9559  consdataChgWeight(consdata, v, consdata->capacity);
9560  }
9561 
9562  *nchgcoefs += offsetv;
9563  goto CONTINUE;
9564  }
9565 
9566  /* determine the remainder of the coefficient candidate and the gcd */
9567  restweight = weights[candpos] % gcd;
9568  assert(restweight >= 1);
9569  assert(restweight < gcd);
9570 
9571  /* calculate new coefficient */
9572  if( restweight > rest )
9573  newweight = weights[candpos] - restweight + gcd;
9574  else
9575  newweight = weights[candpos] - restweight;
9576 
9577  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9578 
9579  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);
9580 
9581  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9582  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9583  */
9584  if( newweight == 0 && offsetv > 0 )
9585  return SCIP_OKAY;
9586 
9587  if( rest > 0 )
9588  {
9589  /* replace old with new capacity */
9590  consdata->capacity -= rest;
9591  ++(*nchgsides);
9592 
9593  /* replace old big coefficients with new capacity */
9594  for( v = 0; v < offsetv; ++v )
9595  {
9596  consdataChgWeight(consdata, v, consdata->capacity);
9597  }
9598 
9599  *nchgcoefs += offsetv;
9600  }
9601 
9602  if( newweight == 0 )
9603  {
9604  /* delete redundant coefficient */
9605  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9606  assert(consdata->nvars == nvars - 1);
9607  --nvars;
9608  }
9609  else
9610  {
9611  /* replace old with new coefficient */
9612  consdataChgWeight(consdata, candpos, newweight);
9613  }
9614  ++(*nchgcoefs);
9615 
9616  assert(consdata->vars == vars);
9617  assert(consdata->nvars == nvars);
9618  assert(consdata->weights == weights);
9619 
9620  CONTINUE:
9621  /* now constraint can be normalized, dividing it by the gcd */
9622  for( v = nvars - 1; v >= 0; --v )
9623  {
9624  consdataChgWeight(consdata, v, weights[v]/gcd);
9625  }
9626  (*nchgcoefs) += nvars;
9627 
9628  consdata->capacity /= gcd;
9629  ++(*nchgsides);
9630 
9631  SCIPdebugPrintCons(scip, cons, NULL);
9632 
9633  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));
9634  }
9635  while( nvars >= 2 );
9636 
9637  return SCIP_OKAY;
9638 }
9639 
9640 
9641 /** inserts an element into the list of binary zero implications */
9642 static
9644  SCIP* scip, /**< SCIP data structure */
9645  int** liftcands, /**< array of the lifting candidates */
9646  int* nliftcands, /**< number of lifting candidates */
9647  int** firstidxs, /**< array of first zeroitems indices */
9648  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9649  int** zeroitems, /**< pointer to zero items array */
9650  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9651  int* zeroitemssize, /**< pointer to size of zero items array */
9652  int* nzeroitems, /**< pointer to length of zero items array */
9653  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9654  SCIP_Bool value, /**< value v of variable y in implication */
9655  int knapsackidx, /**< index of variable x in knapsack */
9656  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9657  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9658  )
9659 {
9660  int nzeros;
9661 
9662  assert(liftcands != NULL);
9663  assert(liftcands[value] != NULL);
9664  assert(nliftcands != NULL);
9665  assert(firstidxs != NULL);
9666  assert(firstidxs[value] != NULL);
9667  assert(zeroweightsums != NULL);
9668  assert(zeroweightsums[value] != NULL);
9669  assert(zeroitems != NULL);
9670  assert(nextidxs != NULL);
9671  assert(zeroitemssize != NULL);
9672  assert(nzeroitems != NULL);
9673  assert(*nzeroitems <= *zeroitemssize);
9674  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9675  assert(memlimitreached != NULL);
9676 
9677  nzeros = *nzeroitems;
9678 
9679  /* allocate enough memory */
9680  if( nzeros == *zeroitemssize )
9681  {
9682  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9683  * this can be too huge - abort on memory limit
9684  */
9685  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9686  {
9687  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9688  *zeroitemssize);
9689  *memlimitreached = TRUE;
9690  return SCIP_OKAY;
9691  }
9692  *zeroitemssize *= 2;
9693  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9694  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9695  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9696  }
9697  assert(nzeros < *zeroitemssize);
9698 
9699  if( *memlimitreached )
9700  *memlimitreached = FALSE;
9701 
9702  /* insert element */
9703  (*zeroitems)[nzeros] = knapsackidx;
9704  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9705  if( firstidxs[value][probindex] == 0 )
9706  {
9707  liftcands[value][nliftcands[value]] = probindex;
9708  ++nliftcands[value];
9709  }
9710  firstidxs[value][probindex] = nzeros;
9711  ++(*nzeroitems);
9712  zeroweightsums[value][probindex] += knapsackweight;
9713 
9714  return SCIP_OKAY;
9715 }
9716 
9717 #define MAX_CLIQUELENGTH 50
9718 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9719  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9720  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9721  * if cliqueweightsum(xi == v) < capacity:
9722  * - fixing variable xi to v would make the knapsack constraint redundant
9723  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9724  * redundancy effect:
9725  * wi' := capacity - cliqueweightsum(xi == v)
9726  * this rule can also be applied to binary variables not in the knapsack!
9727  */
9728 static
9730  SCIP* scip, /**< SCIP data structure */
9731  SCIP_CONS* cons, /**< knapsack constraint */
9732  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9733  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9734  )
9735 {
9736  SCIP_CONSDATA* consdata;
9737  SCIP_VAR** binvars;
9738  int nbinvars;
9739  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9740  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9741  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9742  int* zeroitems; /* item number in knapsack that is implied to zero */
9743  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9744  int zeroitemssize;
9745  int nzeroitems;
9746  SCIP_Bool* zeroiteminserted[2];
9747  SCIP_Bool memlimitreached;
9748  int nliftcands[2];
9749  SCIP_Bool* cliqueused;
9750  SCIP_Bool* itemremoved;
9751  SCIP_Longint maxcliqueweightsum;
9752  SCIP_VAR** addvars;
9753  SCIP_Longint* addweights;
9754  SCIP_Longint addweightsum;
9755  int nvars;
9756  int cliquenum;
9757  int naddvars;
9758  int val;
9759  int i;
9760 
9761  int* tmpindices;
9762  SCIP_Bool* tmpboolindices;
9763  int* tmpindices2;
9764  SCIP_Bool* tmpboolindices2;
9765  int* tmpindices3;
9766  SCIP_Bool* tmpboolindices3;
9767  int tmp;
9768  int tmp2;
9769  int tmp3;
9770  SCIP_CONSHDLR* conshdlr;
9771  SCIP_CONSHDLRDATA* conshdlrdata;
9772 
9773  assert(nchgcoefs != NULL);
9774  assert(!SCIPconsIsModifiable(cons));
9775 
9776  consdata = SCIPconsGetData(cons);
9777  assert(consdata != NULL);
9778  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9779  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9780  assert(consdata->nvars > 0);
9781  assert(consdata->merged);
9782 
9783  nvars = consdata->nvars;
9784 
9785  /* check if the knapsack has too many items/cliques for applying this costly method */
9786  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9787  return SCIP_OKAY;
9788 
9789  /* sort items, s.t. the heaviest one is in the first position */
9790  sortItems(consdata);
9791 
9792  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9793  return SCIP_OKAY;
9794 
9795  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9796  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9797  assert(nbinvars > 0);
9798  binvars = SCIPgetVars(scip);
9799 
9800  /* get conshdlrdata to use cleared memory */
9801  conshdlr = SCIPconsGetHdlr(cons);
9802  assert(conshdlr != NULL);
9803  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9804  assert(conshdlrdata != NULL);
9805 
9806  /* allocate temporary memory for the list of implied to zero variables */
9807  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9808  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9809  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9810 
9811  assert(conshdlrdata->ints1size > 0);
9812  assert(conshdlrdata->ints2size > 0);
9813  assert(conshdlrdata->longints1size > 0);
9814  assert(conshdlrdata->longints2size > 0);
9815 
9816  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9817  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9818  * transform all integers into their binary representation then it maybe happens
9819  */
9820  if( conshdlrdata->ints1size < nbinvars )
9821  {
9822  int oldsize = conshdlrdata->ints1size;
9823 
9824  conshdlrdata->ints1size = nbinvars;
9825  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9826  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9827  }
9828  if( conshdlrdata->ints2size < nbinvars )
9829  {
9830  int oldsize = conshdlrdata->ints2size;
9831 
9832  conshdlrdata->ints2size = nbinvars;
9833  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9834  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9835  }
9836  if( conshdlrdata->longints1size < nbinvars )
9837  {
9838  int oldsize = conshdlrdata->longints1size;
9839 
9840  conshdlrdata->longints1size = nbinvars;
9841  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9842  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9843  }
9844  if( conshdlrdata->longints2size < nbinvars )
9845  {
9846  int oldsize = conshdlrdata->longints2size;
9847 
9848  conshdlrdata->longints2size = nbinvars;
9849  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9850  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9851  }
9852 
9853  firstidxs[0] = conshdlrdata->ints1;
9854  firstidxs[1] = conshdlrdata->ints2;
9855  zeroweightsums[0] = conshdlrdata->longints1;
9856  zeroweightsums[1] = conshdlrdata->longints2;
9857 
9858  /* check for cleared arrays, all entries are zero */
9859 #ifndef NDEBUG
9860  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9861  {
9862  assert(firstidxs[0][tmp] == 0);
9863  assert(firstidxs[1][tmp] == 0);
9864  assert(zeroweightsums[0][tmp] == 0);
9865  assert(zeroweightsums[1][tmp] == 0);
9866  }
9867 #endif
9868 
9869  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9870  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9871 
9872  zeroitems[0] = -1; /* dummy element */
9873  nextidxs[0] = -1;
9874  nzeroitems = 1;
9875  nliftcands[0] = 0;
9876  nliftcands[1] = 0;
9877 
9878  assert(conshdlrdata->bools1size > 0);
9879  assert(conshdlrdata->bools2size > 0);
9880 
9881  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9882  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9883  * transform all integers into their binary representation then it maybe happens
9884  */
9885  if( conshdlrdata->bools1size < nbinvars )
9886  {
9887  int oldsize = conshdlrdata->bools1size;
9888 
9889  conshdlrdata->bools1size = nbinvars;
9890  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9891  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9892  }
9893  if( conshdlrdata->bools2size < nbinvars )
9894  {
9895  int oldsize = conshdlrdata->bools2size;
9896 
9897  conshdlrdata->bools2size = nbinvars;
9898  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9899  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9900  }
9901 
9902  zeroiteminserted[0] = conshdlrdata->bools1;
9903  zeroiteminserted[1] = conshdlrdata->bools2;
9904 
9905  /* check for cleared arrays, all entries are zero */
9906 #ifndef NDEBUG
9907  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9908  {
9909  assert(zeroiteminserted[0][tmp] == 0);
9910  assert(zeroiteminserted[1][tmp] == 0);
9911  }
9912 #endif
9913 
9914  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9915  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9916  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9917  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9918  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9919  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9920 
9921  tmp2 = 0;
9922  tmp3 = 0;
9923 
9924  memlimitreached = FALSE;
9925  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9926  {
9927  SCIP_CLIQUE** cliques;
9928  SCIP_VAR* var;
9929  SCIP_Longint weight;
9930  SCIP_Bool value;
9931  int varprobindex;
9932  int ncliques;
9933  int j;
9934 
9935  tmp = 0;
9936 
9937  /* get corresponding active problem variable */
9938  var = consdata->vars[i];
9939  weight = consdata->weights[i];
9940  value = TRUE;
9941  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9942  varprobindex = SCIPvarGetProbindex(var);
9943  assert(0 <= varprobindex && varprobindex < nbinvars);
9944 
9945  /* update the zeroweightsum */
9946  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9947  tmpboolindices3[tmp3] = !value;
9948  tmpindices3[tmp3] = varprobindex;
9949  ++tmp3;
9950 
9951  /* initialize the arrays of inserted zero items */
9952  /* first add the implications (~x == 1 -> x == 0) */
9953  {
9954  SCIP_Bool implvalue;
9955  int probindex;
9956 
9957  probindex = SCIPvarGetProbindex(var);
9958  assert(0 <= probindex && probindex < nbinvars);
9959 
9960  implvalue = !value;
9961 
9962  /* insert the item into the list of the implied variable/value */
9963  assert( !zeroiteminserted[implvalue][probindex] );
9964 
9965  if( firstidxs[implvalue][probindex] == 0 )
9966  {
9967  tmpboolindices2[tmp2] = implvalue;
9968  tmpindices2[tmp2] = probindex;
9969  ++tmp2;
9970  }
9971  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
9972  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
9973  &memlimitreached) );
9974  zeroiteminserted[implvalue][probindex] = TRUE;
9975  tmpboolindices[tmp] = implvalue;
9976  tmpindices[tmp] = probindex;
9977  ++tmp;
9978  }
9979 
9980  /* get the cliques where the knapsack item is member of with value 1 */
9981  ncliques = SCIPvarGetNCliques(var, value);
9982  cliques = SCIPvarGetCliques(var, value);
9983  for( j = 0; j < ncliques && !memlimitreached; ++j )
9984  {
9985  SCIP_VAR** cliquevars;
9986  SCIP_Bool* cliquevalues;
9987  int ncliquevars;
9988  int k;
9989 
9990  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
9991 
9992  /* discard big cliques */
9993  if( ncliquevars > MAX_CLIQUELENGTH )
9994  continue;
9995 
9996  cliquevars = SCIPcliqueGetVars(cliques[j]);
9997  cliquevalues = SCIPcliqueGetValues(cliques[j]);
9998 
9999  for( k = ncliquevars - 1; k >= 0; --k )
10000  {
10001  SCIP_Bool implvalue;
10002  int probindex;
10003 
10004  if( var == cliquevars[k] )
10005  continue;
10006 
10007  probindex = SCIPvarGetProbindex(cliquevars[k]);
10008  if( probindex == -1 )
10009  continue;
10010 
10011  assert(0 <= probindex && probindex < nbinvars);
10012  implvalue = cliquevalues[k];
10013 
10014  /* insert the item into the list of the clique variable/value */
10015  if( !zeroiteminserted[implvalue][probindex] )
10016  {
10017  if( firstidxs[implvalue][probindex] == 0 )
10018  {
10019  tmpboolindices2[tmp2] = implvalue;
10020  tmpindices2[tmp2] = probindex;
10021  ++tmp2;
10022  }
10023 
10024  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10025  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10026  &memlimitreached) );
10027  zeroiteminserted[implvalue][probindex] = TRUE;
10028  tmpboolindices[tmp] = implvalue;
10029  tmpindices[tmp] = probindex;
10030  ++tmp;
10031 
10032  if( memlimitreached )
10033  break;
10034  }
10035  }
10036  }
10037  /* clear zeroiteminserted */
10038  for( --tmp; tmp >= 0; --tmp)
10039  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10040  }
10041  SCIPfreeBufferArray(scip, &tmpboolindices);
10042 
10043  /* calculate the clique partition and the maximal sum of weights using the clique information */
10044  assert(consdata->sorted);
10045  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10046 
10047  assert(conshdlrdata->bools3size > 0);
10048 
10049  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10050  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10051  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10052  */
10053  if( conshdlrdata->bools3size < consdata->nvars )
10054  {
10055  int oldsize = conshdlrdata->bools3size;
10056 
10057  conshdlrdata->bools3size = consdata->nvars;;
10058  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10059  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10060  }
10061 
10062  cliqueused = conshdlrdata->bools3;
10063 
10064  /* check for cleared array, all entries are zero */
10065 #ifndef NDEBUG
10066  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10067  assert(cliqueused[tmp] == 0);
10068 #endif
10069 
10070  maxcliqueweightsum = 0;
10071  tmp = 0;
10072 
10073  /* calculates maximal weight of cliques */
10074  for( i = 0; i < consdata->nvars; ++i )
10075  {
10076  cliquenum = consdata->cliquepartition[i];
10077  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10078 
10079  if( !cliqueused[cliquenum] )
10080  {
10081  maxcliqueweightsum += consdata->weights[i];
10082  cliqueused[cliquenum] = TRUE;
10083  tmpindices[tmp] = cliquenum;
10084  ++tmp;
10085  }
10086  }
10087  /* clear cliqueused */
10088  for( --tmp; tmp >= 0; --tmp)
10089  cliqueused[tmp] = FALSE;
10090 
10091  assert(conshdlrdata->bools4size > 0);
10092 
10093  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10094  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10095  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10096  */
10097  if( conshdlrdata->bools4size < consdata->nvars )
10098  {
10099  int oldsize = conshdlrdata->bools4size;
10100 
10101  conshdlrdata->bools4size = consdata->nvars;
10102  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10103  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10104  }
10105 
10106  itemremoved = conshdlrdata->bools4;
10107 
10108  /* check for cleared array, all entries are zero */
10109 #ifndef NDEBUG
10110  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10111  assert(itemremoved[tmp] == 0);
10112 #endif
10113 
10114  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10115  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10116  * included in subsequent cliqueweightsum calculations)
10117  */
10118  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10119  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10120  naddvars = 0;
10121  addweightsum = 0;
10122  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10123  {
10124  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10125  {
10126  SCIP_Longint cliqueweightsum;
10127  int probindex;
10128  int idx;
10129  int j;
10130 
10131  tmp = 0;
10132 
10133  probindex = liftcands[val][i];
10134  assert(0 <= probindex && probindex < nbinvars);
10135 
10136  /* ignore empty zero lists and variables that cannot be lifted anyways */
10137  if( firstidxs[val][probindex] == 0
10138  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10139  continue;
10140 
10141  /* mark the items that are implied to zero by setting the current variable to the current value */
10142  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10143  {
10144  assert(0 < idx && idx < nzeroitems);
10145  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10146  itemremoved[zeroitems[idx]] = TRUE;
10147  }
10148 
10149  /* calculate the residual cliqueweight sum */
10150  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10151  for( j = 0; j < consdata->nvars; ++j )
10152  {
10153  cliquenum = consdata->cliquepartition[j];
10154  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10155  if( !itemremoved[j] )
10156  {
10157  if( !cliqueused[cliquenum] )
10158  {
10159  cliqueweightsum += consdata->weights[j];
10160  cliqueused[cliquenum] = TRUE;
10161  tmpindices[tmp] = cliquenum;
10162  ++tmp;
10163  }
10164 
10165  if( cliqueweightsum >= consdata->capacity )
10166  break;
10167  }
10168  }
10169 
10170  /* check if the weight of the variable/value can be increased */
10171  if( cliqueweightsum < consdata->capacity )
10172  {
10173  SCIP_VAR* var;
10174  SCIP_Longint weight;
10175 
10176  /* insert the variable (with value TRUE) in the list of additional items */
10177  assert(naddvars < 2*nbinvars);
10178  var = binvars[probindex];
10179  if( val == FALSE )
10180  {
10181  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10182  }
10183  weight = consdata->capacity - cliqueweightsum;
10184  addvars[naddvars] = var;
10185  addweights[naddvars] = weight;
10186  addweightsum += weight;
10187  naddvars++;
10188 
10189  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10190  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10191  }
10192 
10193  /* clear itemremoved */
10194  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10195  {
10196  assert(0 < idx && idx < nzeroitems);
10197  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10198  itemremoved[zeroitems[idx]] = FALSE;
10199  }
10200  /* clear cliqueused */
10201  for( --tmp; tmp >= 0; --tmp)
10202  cliqueused[tmpindices[tmp]] = FALSE;
10203  }
10204  }
10205 
10206  /* clear part of zeroweightsums */
10207  for( --tmp3; tmp3 >= 0; --tmp3)
10208  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10209 
10210  /* clear rest of zeroweightsums and firstidxs */
10211  for( --tmp2; tmp2 >= 0; --tmp2)
10212  {
10213  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10214  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10215  }
10216 
10217  /* add all additional item weights */
10218  for( i = 0; i < naddvars; ++i )
10219  {
10220  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10221  }
10222  *nchgcoefs += naddvars;
10223 
10224  if( naddvars > 0 )
10225  {
10226  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10227  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10228  }
10229 
10230  /* free temporary memory */
10231  SCIPfreeBufferArray(scip, &addweights);
10232  SCIPfreeBufferArray(scip, &addvars);
10233  SCIPfreeBufferArray(scip, &tmpindices);
10234  SCIPfreeBufferArray(scip, &tmpindices2);
10235  SCIPfreeBufferArray(scip, &tmpindices3);
10236  SCIPfreeBufferArray(scip, &tmpboolindices2);
10237  SCIPfreeBufferArray(scip, &tmpboolindices3);
10238  SCIPfreeBufferArray(scip, &nextidxs);
10239  SCIPfreeBufferArray(scip, &zeroitems);
10240  SCIPfreeBufferArray(scip, &liftcands[1]);
10241  SCIPfreeBufferArray(scip, &liftcands[0]);
10242 
10243  return SCIP_OKAY;
10244 }
10245 
10246 /** tightens item weights and capacity in presolving:
10247  * given a knapsack sum(wi*xi) <= capacity
10248  * (1) let weightsum := sum(wi)
10249  * if weightsum - wi < capacity:
10250  * - not using item i would make the knapsack constraint redundant
10251  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10252  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10253  * - change coefficients:
10254  * wi' := weightsum - capacity
10255  * capacity' := capacity - (wi - wi')
10256  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10257  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10258  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10259  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10260  * can be multiple times the same weight, this can be improved
10261  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10262  * weight, to capacity - lastmininmalweightsum, e.g. :
10263  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10264  * -> minimal weightsums: 5, 5, 10, 10
10265  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10266  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10267  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10268  * (3) let W(C) be the maximal weight of clique C,
10269  * cliqueweightsum := sum(W(C))
10270  * if cliqueweightsum - W(C) < capacity:
10271  * - not using any item of C would make the knapsack constraint redundant
10272  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10273  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10274  * - change coefficients:
10275  * delta := capacity - (cliqueweightsum - W(C))
10276  * wi' := max(wi - delta, 0)
10277  * capacity' := capacity - delta
10278  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10279  * introduce infeasible solutions.
10280  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10281  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10282  * if cliqueweightsum(xi == v) < capacity:
10283  * - fixing variable xi to v would make the knapsack constraint redundant
10284  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10285  * redundancy effect:
10286  * wi' := capacity - cliqueweightsum(xi == v)
10287  * This rule can also be applied to binary variables not in the knapsack!
10288  * (5) if min{w} + wi > capacity:
10289  * - using item i would force to fix other items to zero
10290  * - wi can be increased to the capacity
10291  */
10292 static
10294  SCIP* scip, /**< SCIP data structure */
10295  SCIP_CONS* cons, /**< knapsack constraint */
10296  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10297  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10298  int* nchgsides, /**< pointer to count number of side changes */
10299  int* naddconss, /**< pointer to count number of added constraints */
10300  int* ndelconss, /**< pointer to count number of deleted constraints */
10301  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10302  )
10303 {
10304  SCIP_CONSHDLRDATA* conshdlrdata;
10305  SCIP_CONSDATA* consdata;
10306  SCIP_Longint* weights;
10307  SCIP_Longint sumcoef;
10308  SCIP_Longint capacity;
10309  SCIP_Longint newweight;
10310  SCIP_Longint maxweight;
10311  SCIP_Longint minweight;
10312  SCIP_Bool sumcoefcase = FALSE;
10313  int startpos;
10314  int backpos;
10315  int nvars;
10316  int pos;
10317  int k;
10318  int i;
10319 
10320  assert(nchgcoefs != NULL);
10321  assert(nchgsides != NULL);
10322  assert(!SCIPconsIsModifiable(cons));
10323 
10324  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10325  assert(conshdlrdata != NULL);
10326 
10327  consdata = SCIPconsGetData(cons);
10328  assert(consdata != NULL);
10329  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10330  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10331  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10332  assert(consdata->nvars > 0);
10333 
10334  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10335  if( *cutoff )
10336  return SCIP_OKAY;
10337 
10338  /* apply rule (1) */
10339  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10340  {
10341  do
10342  {
10343  assert(consdata->merged);
10344 
10345  /* sort items, s.t. the heaviest one is in the first position */
10346  sortItems(consdata);
10347 
10348  for( i = 0; i < consdata->nvars; ++i )
10349  {
10350  SCIP_Longint weight;
10351 
10352  weight = consdata->weights[i];
10353  if( consdata->weightsum - weight < consdata->capacity )
10354  {
10355  newweight = consdata->weightsum - consdata->capacity;
10356  consdataChgWeight(consdata, i, newweight);
10357  consdata->capacity -= (weight - newweight);
10358  (*nchgcoefs)++;
10359  (*nchgsides)++;
10360  assert(!consdata->sorted);
10361  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",
10362  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10363  consdata->capacity + (weight-newweight), consdata->capacity);
10364  }
10365  else
10366  break;
10367  }
10368  }
10369  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10370  }
10371 
10372  /* check for redundancy */
10373  if( consdata->weightsum <= consdata->capacity )
10374  return SCIP_OKAY;
10375 
10376  pos = 0;
10377  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10378  ++pos;
10379 
10380  sumcoef = 0;
10381  weights = consdata->weights;
10382  nvars = consdata->nvars;
10383  capacity = consdata->capacity;
10384 
10385  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10386  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10387  {
10388  /* further reductions using the next possible coefficient sum
10389  *
10390  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10391  */
10392  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10393  for( k = 0; k < 4; ++k )
10394  {
10395  newweight = capacity - sumcoef;
10396 
10397  /* determine next minimal coefficient sum */
10398  switch( k )
10399  {
10400  case 0:
10401  sumcoef = weights[nvars - 1];
10402  backpos = nvars - 1;
10403  break;
10404  case 1:
10405  sumcoef = weights[nvars - 2];
10406  backpos = nvars - 2;
10407  break;
10408  case 2:
10409  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10410  {
10411  sumcoefcase = TRUE;
10412  sumcoef = weights[nvars - 3];
10413  backpos = nvars - 3;
10414  }
10415  else
10416  {
10417  sumcoefcase = FALSE;
10418  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10419  backpos = nvars - 2;
10420  }
10421  break;
10422  default:
10423  assert(k == 3);
10424  if( sumcoefcase )
10425  {
10426  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10427  {
10428  sumcoef = weights[nvars - 4];
10429  backpos = nvars - 4;
10430  }
10431  else
10432  {
10433  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10434  backpos = nvars - 2;
10435  }
10436  }
10437  else
10438  {
10439  sumcoef = weights[nvars - 3];
10440  backpos = nvars - 3;
10441  }
10442  break;
10443  }
10444 
10445  if( backpos <= pos )
10446  break;
10447 
10448  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10449  maxweight = weights[pos];
10450  startpos = pos;
10451  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10452  {
10453  assert(newweight > weights[pos]);
10454 
10455  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10456  SCIPconsGetName(cons), maxweight, newweight);
10457 
10458  consdataChgWeight(consdata, pos, newweight);
10459 
10460  ++pos;
10461  assert(pos < nvars);
10462 
10463  maxweight = weights[pos];
10464 
10465  if( backpos <= pos )
10466  break;
10467  }
10468  (*nchgcoefs) += (pos - startpos);
10469 
10470  /* skip unchangable weights */
10471  while( pos < nvars && weights[pos] + sumcoef == capacity )
10472  ++pos;
10473 
10474  /* check special case were there is only one weight left to tighten
10475  *
10476  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10477  *
10478  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10479  *
10480  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10481  */
10482  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10483  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10484  {
10485  newweight = capacity - sumcoef;
10486  assert(newweight > weights[pos]);
10487 
10488  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10489  SCIPconsGetName(cons), maxweight, newweight);
10490 
10491  consdataChgWeight(consdata, pos, newweight);
10492 
10493  break;
10494  }
10495 
10496  if( backpos <= pos )
10497  break;
10498  }
10499  }
10500 
10501  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10502  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10503  {
10504  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10505  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10506  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10507  {
10508  SCIP_VAR** clqvars;
10509  SCIP_CONS* cliquecons;
10510  char name[SCIP_MAXSTRLEN];
10511  int* clqpart;
10512  int nclqvars;
10513  int nclq;
10514  int len;
10515  int c;
10516  int w;
10517 
10518  assert(!SCIPconsIsDeleted(cons));
10519 
10520  if( pos == consdata->nvars )
10521  {
10522  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10523 
10524  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10528  SCIPconsIsStickingAtNode(cons)) );
10529 
10530  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10531  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10532  ++(*naddconss);
10533 
10534  /* delete old constraint */
10535  SCIP_CALL( SCIPdelCons(scip, cons) );
10536  ++(*ndelconss);
10537 
10538  return SCIP_OKAY;
10539  }
10540 
10541  len = consdata->nvars - pos;
10542 
10543  /* allocate temporary memory */
10544  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10545 
10546  /* calculate clique partition */
10547  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10548  assert(nclq <= len);
10549 
10550 #ifndef NDEBUG
10551  /* clique numbers must be at least as high as the index */
10552  for( w = 0; w < nclq; ++w )
10553  assert(clqpart[w] <= w);
10554 #endif
10555 
10556  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10557 
10558  /* allocate temporary memory */
10559  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10560 
10561  /* copy corresponding variables with big coefficients */
10562  for( w = pos - 1; w >= 0; --w )
10563  clqvars[w] = consdata->vars[w];
10564 
10565  /* create for each clique a set-packing constraint */
10566  for( c = 0; c < nclq; ++c )
10567  {
10568  nclqvars = pos;
10569 
10570  for( w = c; w < len; ++w )
10571  {
10572  if( clqpart[w] == c )
10573  {
10574  assert(nclqvars < pos + len - nclq + 1);
10575  clqvars[nclqvars] = consdata->vars[w + pos];
10576  ++nclqvars;
10577  }
10578  }
10579 
10580  assert(nclqvars > 1);
10581 
10582  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10583  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10587  SCIPconsIsStickingAtNode(cons)) );
10588  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10589  SCIPdebugPrintCons(scip, cliquecons, NULL);
10590  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10591  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10592  ++(*naddconss);
10593  }
10594 
10595  /* delete old constraint */
10596  SCIP_CALL( SCIPdelCons(scip, cons) );
10597  ++(*ndelconss);
10598 
10599  SCIPfreeBufferArray(scip, &clqvars);
10600  SCIPfreeBufferArray(scip, &clqpart);
10601 
10602  return SCIP_OKAY;
10603  }
10604  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10605  {
10606  SCIP_Longint* maxcliqueweights;
10607  SCIP_Longint* newweightvals;
10608  int* newweightidxs;
10609  SCIP_Longint cliqueweightsum;
10610 
10611  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10612  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10613  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10614 
10615  /* repeat as long as changes have been applied */
10616  do
10617  {
10618  int ncliques;
10619  int cliquenum;
10620  SCIP_Bool zeroweights;
10621 
10622  assert(consdata->merged);
10623 
10624  /* sort items, s.t. the heaviest one is in the first position */
10625  sortItems(consdata);
10626 
10627  /* calculate a clique partition */
10628  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10629 
10630  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10631  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10632  break;
10633 
10634  /* calculate the maximal weight of the cliques and store the clique type */
10635  cliqueweightsum = 0;
10636  ncliques = 0;
10637 
10638  for( i = 0; i < consdata->nvars; ++i )
10639  {
10640  SCIP_Longint weight;
10641 
10642  cliquenum = consdata->cliquepartition[i];
10643  assert(0 <= cliquenum && cliquenum <= ncliques);
10644 
10645  weight = consdata->weights[i];
10646  assert(weight > 0);
10647 
10648  if( cliquenum == ncliques )
10649  {
10650  maxcliqueweights[ncliques] = weight;
10651  cliqueweightsum += weight;
10652  ++ncliques;
10653  }
10654 
10655  assert(maxcliqueweights[cliquenum] >= weight);
10656  }
10657 
10658  /* apply rule on every clique */
10659  zeroweights = FALSE;
10660  for( i = 0; i < ncliques; ++i )
10661  {
10662  SCIP_Longint delta;
10663 
10664  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10665  if( delta > 0 )
10666  {
10667  SCIP_Longint newcapacity;
10668 #ifndef NDEBUG
10669  SCIP_Longint newmincliqueweight;
10670 #endif
10671  SCIP_Longint newminweightsuminclique;
10672  SCIP_Bool forceclique;
10673  int nnewweights;
10674  int j;
10675 
10676  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",
10677  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10678  newcapacity = consdata->capacity - delta;
10679  forceclique = FALSE;
10680  nnewweights = 0;
10681 #ifndef NDEBUG
10682  newmincliqueweight = newcapacity + 1;
10683  for( j = 0; j < i; ++j )
10684  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10685 #endif
10686  for( j = i; j < consdata->nvars; ++j )
10687  {
10688  if( consdata->cliquepartition[j] == i )
10689  {
10690  newweight = consdata->weights[j] - delta;
10691  newweight = MAX(newweight, 0);
10692 
10693  /* cache the new weight */
10694  assert(nnewweights < consdata->nvars);
10695  newweightvals[nnewweights] = newweight;
10696  newweightidxs[nnewweights] = j;
10697  nnewweights++;
10698 
10699 #ifndef NDEBUG
10700  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10701  newmincliqueweight = newweight;
10702 #endif
10703  }
10704  }
10705 
10706  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10707  if( nnewweights > 1 )
10708  {
10709 #ifndef NDEBUG
10710  j = newweightidxs[nnewweights - 2];
10711  assert(0 <= j && j < consdata->nvars);
10712  assert(consdata->cliquepartition[j] == i);
10713  j = newweightidxs[nnewweights - 1];
10714  assert(0 <= j && j < consdata->nvars);
10715  assert(consdata->cliquepartition[j] == i);
10716 #endif
10717 
10718  newminweightsuminclique = newweightvals[nnewweights - 2];
10719  newminweightsuminclique += newweightvals[nnewweights - 1];
10720 
10721  /* check if these new two minimal weights both fit into the knapsack;
10722  * if this is true, we have to add a clique constraint in order to enforce the clique
10723  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10724  * reduction might be infeasible, i.e., allows additional solutions)
10725  */
10726  if( newminweightsuminclique <= newcapacity )
10727  forceclique = TRUE;
10728  }
10729 
10730  /* check if we really want to apply the change */
10731  if( conshdlrdata->disaggregation || !forceclique )
10732  {
10733  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10734  consdata->capacity, newcapacity, forceclique);
10735  consdata->capacity = newcapacity;
10736  (*nchgsides)++;
10737 
10738  for( k = 0; k < nnewweights; ++k )
10739  {
10740  j = newweightidxs[k];
10741  assert(0 <= j && j < consdata->nvars);
10742  assert(consdata->cliquepartition[j] == i);
10743 
10744  /* apply the weight change */
10745  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10746  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10747  consdataChgWeight(consdata, j, newweightvals[k]);
10748  (*nchgcoefs)++;
10749  assert(!consdata->sorted);
10750  zeroweights = zeroweights || (newweightvals[k] == 0);
10751  }
10752  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10753  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10754  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10755  * knapsack constraint
10756  */
10757  if( forceclique )
10758  {
10759  SCIP_CONS* cliquecons;
10760  char name[SCIP_MAXSTRLEN];
10761  SCIP_VAR** cliquevars;
10762 
10763  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10764  for( k = 0; k < nnewweights; ++k )
10765  cliquevars[k] = consdata->vars[newweightidxs[k]];
10766 
10767  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10768  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10772  SCIPconsIsStickingAtNode(cons)) );
10773  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10774  SCIPdebugPrintCons(scip, cliquecons, NULL);
10775  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10776  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10777  SCIPfreeBufferArray(scip, &cliquevars);
10778  (*naddconss)++;
10779  }
10780  }
10781  }
10782  }
10783  if( zeroweights )
10784  {
10785  SCIP_CALL( removeZeroWeights(scip, cons) );
10786  }
10787  }
10788  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10789 
10790  /* free temporary memory */
10791  SCIPfreeBufferArray(scip, &newweightidxs);
10792  SCIPfreeBufferArray(scip, &newweightvals);
10793  SCIPfreeBufferArray(scip, &maxcliqueweights);
10794 
10795  /* check for redundancy */
10796  if( consdata->weightsum <= consdata->capacity )
10797  return SCIP_OKAY;
10798  }
10799  }
10800 
10801  /* apply rule (3) */
10802  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10803  {
10804  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10805  }
10806 
10807  /* check for redundancy */
10808  if( consdata->weightsum <= consdata->capacity )
10809  return SCIP_OKAY;
10810 
10811  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10812  {
10813  /* apply rule (4) (all but smallest weight) */
10814  assert(consdata->merged);
10815  sortItems(consdata);
10816  minweight = consdata->weights[consdata->nvars-1];
10817  for( i = 0; i < consdata->nvars-1; ++i )
10818  {
10819  SCIP_Longint weight;
10820 
10821  weight = consdata->weights[i];
10822  assert(weight >= minweight);
10823  if( minweight + weight > consdata->capacity )
10824  {
10825  if( weight < consdata->capacity )
10826  {
10827  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10828  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10829  assert(consdata->sorted);
10830  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10831  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10832  consdata->sorted = TRUE;
10833  (*nchgcoefs)++;
10834  }
10835  }
10836  else
10837  break;
10838  }
10839 
10840  /* apply rule (5) (smallest weight) */
10841  if( consdata->nvars >= 2 )
10842  {
10843  SCIP_Longint weight;
10844 
10845  minweight = consdata->weights[consdata->nvars-2];
10846  weight = consdata->weights[consdata->nvars-1];
10847  assert(minweight >= weight);
10848  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10849  {
10850  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10851  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10852  assert(consdata->sorted);
10853  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10854  assert(minweight >= consdata->weights[consdata->nvars-1]);
10855  consdata->sorted = TRUE;
10856  (*nchgcoefs)++;
10857  }
10858  }
10859  }
10860 
10861  return SCIP_OKAY;
10862 }
10863 
10864 
10865 #ifdef SCIP_DEBUG
10866 static
10867 void printClique(
10868  SCIP_VAR** cliquevars,
10869  int ncliquevars
10870  )
10871 {
10872  int b;
10873  SCIPdebugMessage("adding new Clique: ");
10874  for( b = 0; b < ncliquevars; ++b )
10875  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10876  SCIPdebugPrintf("\n");
10877 }
10878 #endif
10879 
10880 /** adds negated cliques of the knapsack constraint to the global clique table */
10881 static
10883  SCIP*const scip, /**< SCIP data structure */
10884  SCIP_CONS*const cons, /**< knapsack constraint */
10885  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10886  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10887  )
10888 {
10889  SCIP_CONSDATA* consdata;
10890  SCIP_CONSHDLRDATA* conshdlrdata;
10891  SCIP_VAR** poscliquevars;
10892  SCIP_VAR** cliquevars;
10893  SCIP_Longint* maxweights;
10894  SCIP_Longint* gainweights;
10895  int* gaincliquepartition;
10896  SCIP_Bool* cliqueused;
10897  SCIP_Longint minactduetonegcliques;
10898  SCIP_Longint freecapacity;
10899  SCIP_Longint lastweight;
10900  SCIP_Longint beforelastweight;
10901  int nposcliquevars;
10902  int ncliquevars;
10903  int nvars;
10904  int nnegcliques;
10905  int lastcliqueused;
10906  int thisnbdchgs;
10907  int v;
10908  int w;
10909 
10910  assert(scip != NULL);
10911  assert(cons != NULL);
10912  assert(cutoff != NULL);
10913  assert(nbdchgs != NULL);
10914 
10915  *cutoff = FALSE;
10916 
10917  consdata = SCIPconsGetData(cons);
10918  assert(consdata != NULL);
10919 
10920  nvars = consdata->nvars;
10921 
10922  /* check whether the cliques have already been added */
10923  if( consdata->cliquesadded || nvars == 0 )
10924  return SCIP_OKAY;
10925 
10926  /* make sure, the items are merged */
10927  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10928  if( *cutoff )
10929  return SCIP_OKAY;
10930 
10931  /* make sure, items are sorted by non-increasing weight */
10932  sortItems(consdata);
10933 
10934  assert(consdata->merged);
10935 
10936  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10937  assert(conshdlrdata != NULL);
10938 
10939  /* calculate a clique partition */
10940  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10941  nnegcliques = consdata->nnegcliques;
10942 
10943  /* if we have no negated cliques, stop */
10944  if( nnegcliques == nvars )
10945  return SCIP_OKAY;
10946 
10947  /* get temporary memory */
10948  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10949  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10950  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
10951  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10952  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10953  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
10954 
10955  nnegcliques = 0;
10956  minactduetonegcliques = 0;
10957 
10958  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10959  for( v = 0; v < nvars; ++v )
10960  {
10961  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10962  assert(consdata->weights[v] > 0);
10963 
10964  if( consdata->negcliquepartition[v] == nnegcliques )
10965  {
10966  nnegcliques++;
10967  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
10968  }
10969  else
10970  minactduetonegcliques += consdata->weights[v];
10971  }
10972 
10973  nposcliquevars = 0;
10974 
10975  /* add cliques, using negated cliques information */
10976  if( minactduetonegcliques > 0 )
10977  {
10978  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
10979  freecapacity = consdata->capacity - minactduetonegcliques;
10980 
10981  SCIPdebugPrintCons(scip, cons, NULL);
10982  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",
10983  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
10984 
10985  /* calculate possible gain by switching chosen items in negated cliques */
10986  for( v = 0; v < nvars; ++v )
10987  {
10988  if( !cliqueused[consdata->negcliquepartition[v]] )
10989  {
10990  cliqueused[consdata->negcliquepartition[v]] = TRUE;
10991  for( w = v + 1; w < nvars; ++w )
10992  {
10993  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
10994  * weight[w] (which are both in a negated clique) */
10995  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
10996  && consdata->weights[v] > consdata->weights[w] )
10997  {
10998  poscliquevars[nposcliquevars] = consdata->vars[w];
10999  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11000  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11001  ++nposcliquevars;
11002  }
11003  }
11004  }
11005  }
11006 
11007  /* try to create negated cliques */
11008  if( nposcliquevars > 0 )
11009  {
11010  /* sort possible gain per substitution of the clique members */
11011  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11012 
11013  for( v = 0; v < nposcliquevars; ++v )
11014  {
11015  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11016  ncliquevars = 1;
11017  lastweight = gainweights[v];
11018  beforelastweight = -1;
11019  lastcliqueused = gaincliquepartition[v];
11020  /* clear cliqueused to get an unused array */
11021  BMSclearMemoryArray(cliqueused, nnegcliques);
11022  cliqueused[gaincliquepartition[v]] = TRUE;
11023 
11024  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11025  * in the same negated clique and by taking two of them would exceed the free capacity */
11026  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11027  {
11028  beforelastweight = lastweight;
11029  lastweight = gainweights[w];
11030  lastcliqueused = gaincliquepartition[w];
11031  cliqueused[gaincliquepartition[w]] = TRUE;
11032  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11033  ++ncliquevars;
11034  }
11035 
11036  if( ncliquevars > 1 )
11037  {
11038  SCIPdebug( printClique(cliquevars, ncliquevars) );
11039  assert(beforelastweight > 0);
11040  /* add the clique to the clique table */
11041  /* this really happens, e.g., on enigma.mps from the short test set */
11042  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11043  if( *cutoff )
11044  goto TERMINATE;
11045  *nbdchgs += thisnbdchgs;
11046 
11047  /* reset last used clique to get slightly different cliques */
11048  cliqueused[lastcliqueused] = FALSE;
11049 
11050  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11051  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11052  {
11053  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11054  SCIPdebug( printClique(cliquevars, ncliquevars) );
11055  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11056  if( *cutoff )
11057  goto TERMINATE;
11058  *nbdchgs += thisnbdchgs;
11059  }
11060  }
11061  }
11062  }
11063  }
11064 
11065  TERMINATE:
11066  /* free temporary memory */
11067  SCIPfreeBufferArray(scip, &cliqueused);
11068  SCIPfreeBufferArray(scip, &maxweights);
11069  SCIPfreeBufferArray(scip, &gaincliquepartition);
11070  SCIPfreeBufferArray(scip, &gainweights);
11071  SCIPfreeBufferArray(scip, &cliquevars);
11072  SCIPfreeBufferArray(scip, &poscliquevars);
11073 
11074  return SCIP_OKAY;
11075 }
11076 
11077 /** greedy clique detection by considering weights and capacity
11078  *
11079  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11080  * 1) neighboring items which exceed the capacity together => one clique
11081  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11082  */
11083 static
11085  SCIP*const scip, /**< SCIP data structure */
11086  SCIP_VAR** items, /**< array of variable items */
11087  SCIP_Longint* weights, /**< weights of the items */
11088  int nitems, /**< the number of items */
11089  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11090  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11091  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11092  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11093  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11094  )
11095 {
11096  SCIP_Longint lastweight;
11097  int ncliquevars;
11098  int i;
11099  int thisnbdchgs;
11100 
11101  if( nitems <= 1 )
11102  return SCIP_OKAY;
11103 
11104  /* sort possible gain per substitution of the clique members */
11105  if( ! sorteditems )
11106  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11107 
11108  ncliquevars = 1;
11109  lastweight = weights[0];
11110 
11111  /* taking these two weights together violates the knapsack => include into clique */
11112  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11113  {
11114  lastweight = weights[i];
11115  ++ncliquevars;
11116  }
11117 
11118  if( ncliquevars > 1 )
11119  {
11120  SCIP_Longint compareweight;
11121  SCIP_VAR** cliquevars;
11122  int compareweightidx;
11123  int minclqsize;
11124  int nnzadded;
11125 
11126  /* add the clique to the clique table */
11127  SCIPdebug( printClique(items, ncliquevars) );
11128  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11129 
11130  if( *cutoff )
11131  return SCIP_OKAY;
11132 
11133  *nbdchgs += thisnbdchgs;
11134  nnzadded = ncliquevars;
11135 
11136  /* 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)*/
11137  if( ncliquevars == nitems )
11138  return SCIP_OKAY;
11139 
11140  /* copy items in order into buffer array and deduce more cliques */
11141  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11142 
11143  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11144  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11145  compareweightidx = ncliquevars - 2;
11146  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11147 
11148  /* determine minimum clique size for the following loop */
11149  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11150  minclqsize = MAX(minclqsize, 2);
11151 
11152  /* loop over the remaining variables and the larger items of the first clique until we
11153  * find another clique or reach the size limit */
11154  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11155  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11156  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11157  )
11158  {
11159  compareweight = weights[compareweightidx];
11160  assert(compareweight > 0);
11161 
11162  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11163  if( compareweight + weights[i] > capacity )
11164  {
11165  assert(compareweightidx == ncliquevars -2);
11166  cliquevars[ncliquevars - 1] = items[i];
11167  SCIPdebug( printClique(cliquevars, ncliquevars) );
11168  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11169 
11170  nnzadded += ncliquevars;
11171 
11172  /* stop when there is a cutoff */
11173  if( ! (*cutoff) )
11174  *nbdchgs += thisnbdchgs;
11175 
11176  /* go to next smaller item */
11177  ++i;
11178  }
11179  else
11180  {
11181  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11182  compareweightidx--;
11183  ncliquevars --;
11184  }
11185  }
11186 
11187  SCIPfreeBufferArray(scip, &cliquevars);
11188  }
11189 
11190  return SCIP_OKAY;
11191 }
11192 
11193 /** adds cliques of the knapsack constraint to the global clique table */
11194 static
11196  SCIP*const scip, /**< SCIP data structure */
11197  SCIP_CONS*const cons, /**< knapsack constraint */
11198  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11199  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11200  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11201  )
11202 {
11203  SCIP_CONSDATA* consdata;
11204  SCIP_CONSHDLRDATA* conshdlrdata;
11205  int i;
11206  SCIP_Longint minactduetonegcliques;
11207  SCIP_Longint freecapacity;
11208  int nnegcliques;
11209  int cliquenum;
11210  SCIP_VAR** poscliquevars;
11211  SCIP_Longint* gainweights;
11212  int nposcliquevars;
11213  SCIP_Longint* secondmaxweights;
11214  int nvars;
11215 
11216  assert(scip != NULL);
11217  assert(cons != NULL);
11218  assert(cutoff != NULL);
11219  assert(nbdchgs != NULL);
11220 
11221  *cutoff = FALSE;
11222 
11223  consdata = SCIPconsGetData(cons);
11224  assert(consdata != NULL);
11225 
11226  nvars = consdata->nvars;
11227 
11228  /* check whether the cliques have already been added */
11229  if( consdata->cliquesadded || nvars == 0 )
11230  return SCIP_OKAY;
11231 
11232  /* make sure, the items are merged */
11233  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11234  if( *cutoff )
11235  return SCIP_OKAY;
11236 
11237  /* make sure, the items are sorted by non-increasing weight */
11238  sortItems(consdata);
11239 
11240  assert(consdata->merged);
11241 
11242  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11243  assert(conshdlrdata != NULL);
11244 
11245  /* calculate a clique partition */
11246  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11247  nnegcliques = consdata->nnegcliques;
11248  assert(nnegcliques <= nvars);
11249 
11250  /* get temporary memory */
11251  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11252  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11253  BMSclearMemoryArray(gainweights, nvars);
11254  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11255  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11256 
11257  minactduetonegcliques = 0;
11258 
11259  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11260  if( nnegcliques < nvars )
11261  {
11262  nnegcliques = 0;
11263 
11264  for( i = 0; i < nvars; ++i )
11265  {
11266  SCIP_Longint weight;
11267 
11268  cliquenum = consdata->negcliquepartition[i];
11269  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11270 
11271  weight = consdata->weights[i];
11272  assert(weight > 0);
11273 
11274  if( cliquenum == nnegcliques )
11275  nnegcliques++;
11276  else
11277  {
11278  minactduetonegcliques += weight;
11279  if( secondmaxweights[cliquenum] == 0 )
11280  secondmaxweights[cliquenum] = weight;
11281  }
11282  }
11283  }
11284 
11285  /* add cliques, using negated cliques information */
11286  if( minactduetonegcliques > 0 )
11287  {
11288  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11289  freecapacity = consdata->capacity - minactduetonegcliques;
11290 
11291  SCIPdebugPrintCons(scip, cons, NULL);
11292  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",
11293  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11294 
11295  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11296  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11297 
11298  if( *cutoff )
11299  goto TERMINATE;
11300 
11301  nposcliquevars = 0;
11302 
11303  for( i = nvars - 1; i >= 0; --i )
11304  {
11305  /* if we would take the biggest weight instead of the second biggest */
11306  cliquenum = consdata->negcliquepartition[i];
11307  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11308  {
11309  poscliquevars[nposcliquevars] = consdata->vars[i];
11310  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11311  ++nposcliquevars;
11312  }
11313  }
11314 
11315  /* use the gain weights and free capacity to derive greedily cliques */
11316  if( nposcliquevars > 1 )
11317  {
11318  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11319 
11320  if( *cutoff )
11321  goto TERMINATE;
11322  }
11323  }
11324 
11325  /* build cliques by using the items with the maximal weights */
11326  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11327 
11328  TERMINATE:
11329  /* free temporary memory and mark the constraint */
11330  SCIPfreeBufferArray(scip, &secondmaxweights);
11331  SCIPfreeBufferArray(scip, &gainweights);
11332  SCIPfreeBufferArray(scip, &poscliquevars);
11333  consdata->cliquesadded = TRUE;
11334 
11335  return SCIP_OKAY;
11336 }
11337 
11338 
11339 /** gets the key of the given element */
11340 static
11341 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11342 { /*lint --e{715}*/
11343  /* the key is the element itself */
11344  return elem;
11345 }
11346 
11347 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11348  * same coefficients
11349  */
11350 static
11351 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11352 {
11353 #ifndef NDEBUG
11354  SCIP* scip;
11355 #endif
11356  SCIP_CONSDATA* consdata1;
11357  SCIP_CONSDATA* consdata2;
11358  int i;
11360  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11361  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11362  assert(consdata1->sorted);
11363  assert(consdata2->sorted);
11364 #ifndef NDEBUG
11365  scip = (SCIP*)userptr;
11366  assert(scip != NULL);
11367 #endif
11368 
11369  /* checks trivial case */
11370  if( consdata1->nvars != consdata2->nvars )
11371  return FALSE;
11372 
11373  for( i = consdata1->nvars - 1; i >= 0; --i )
11374  {
11375  /* tests if variables are equal */
11376  if( consdata1->vars[i] != consdata2->vars[i] )
11377  {
11378  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11379  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11380  return FALSE;
11381  }
11382  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11383 
11384  /* tests if weights are equal too */
11385  if( consdata1->weights[i] != consdata2->weights[i] )
11386  return FALSE;
11387  }
11388 
11389  return TRUE;
11390 }
11391 
11392 /** returns the hash value of the key */
11393 static
11394 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11395 {
11396 #ifndef NDEBUG
11397  SCIP* scip;
11398 #endif
11399  SCIP_CONSDATA* consdata;
11400  uint64_t firstweight;
11401  int minidx;
11402  int mididx;
11403  int maxidx;
11404 
11405  consdata = SCIPconsGetData((SCIP_CONS*)key);
11406  assert(consdata != NULL);
11407  assert(consdata->nvars > 0);
11408 
11409 #ifndef NDEBUG
11410  scip = (SCIP*)userptr;
11411  assert(scip != NULL);
11412 #endif
11413 
11414  /* sorts the constraints */
11415  sortItems(consdata);
11416 
11417  minidx = SCIPvarGetIndex(consdata->vars[0]);
11418  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11419  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11420  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11421 
11422  /* hash value depends on vectors of variable indices */
11423  firstweight = (uint64_t)consdata->weights[0];
11424  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11425 }
11426 
11427 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11428  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11429  */
11430 static
11432  SCIP* scip, /**< SCIP data structure */
11433  BMS_BLKMEM* blkmem, /**< block memory */
11434  SCIP_CONS** conss, /**< constraint set */
11435  int nconss, /**< number of constraints in constraint set */
11436  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11437  int* ndelconss /**< pointer to count number of deleted constraints */
11438  )
11440  SCIP_HASHTABLE* hashtable;
11441  int hashtablesize;
11442  int c;
11443 
11444  assert(scip != NULL);
11445  assert(blkmem != NULL);
11446  assert(conss != NULL);
11447  assert(ndelconss != NULL);
11448 
11449  /* create a hash table for the constraint set */
11450  hashtablesize = nconss;
11451  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11452  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11453  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11454 
11455  /* check all constraints in the given set for redundancy */
11456  for( c = nconss - 1; c >= 0; --c )
11457  {
11458  SCIP_CONS* cons0;
11459  SCIP_CONS* cons1;
11460  SCIP_CONSDATA* consdata0;
11461 
11462  cons0 = conss[c];
11463 
11464  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11465  continue;
11466 
11467  consdata0 = SCIPconsGetData(cons0);
11468  assert(consdata0 != NULL);
11469  if( consdata0->nvars == 0 )
11470  {
11471  if( consdata0->capacity < 0 )
11472  {
11473  *cutoff = TRUE;
11474  goto TERMINATE;
11475  }
11476  else
11477  {
11478  SCIP_CALL( SCIPdelCons(scip, cons0) );
11479  ++(*ndelconss);
11480  continue;
11481  }
11482  }
11483 
11484  /* get constraint from current hash table with same variables and same weights as cons0 */
11485  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11486 
11487  if( cons1 != NULL )
11488  {
11489  SCIP_CONS* consstay;
11490  SCIP_CONS* consdel;
11491  SCIP_CONSDATA* consdata1;
11492 
11493  assert(SCIPconsIsActive(cons1));
11494  assert(!SCIPconsIsModifiable(cons1));
11495 
11496  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11497  * delete old constraints afterwards
11498  */
11499  consdata1 = SCIPconsGetData(cons1);
11500 
11501  assert(consdata1 != NULL);
11502  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11503 
11504  assert(consdata0->sorted && consdata1->sorted);
11505  assert(consdata0->vars[0] == consdata1->vars[0]);
11506  assert(consdata0->weights[0] == consdata1->weights[0]);
11507 
11508  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11509  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11510 
11511  /* check which constraint has to stay; */
11512  if( consdata0->capacity < consdata1->capacity )
11513  {
11514  consstay = cons0;
11515  consdel = cons1;
11516 
11517  /* exchange consdel with consstay in hashtable */
11518  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11519  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11520  }
11521  else
11522  {
11523  consstay = cons1;
11524  consdel = cons0;
11525  }
11526 
11527  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11528  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11529 
11530  /* delete consdel */
11531  SCIP_CALL( SCIPdelCons(scip, consdel) );
11532  ++(*ndelconss);
11533 
11534  assert(SCIPconsIsActive(consstay));
11535  }
11536  else
11537  {
11538  /* no such constraint in current hash table: insert cons0 into hash table */
11539  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11540  }
11541  }
11542 
11543  TERMINATE:
11544  /* free hash table */
11545  SCIPhashtableFree(&hashtable);
11546 
11547  return SCIP_OKAY;
11548 }
11549 
11550 
11551 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11552  * and removes or changes constraint accordingly
11553  */
11554 static
11556  SCIP* scip, /**< SCIP data structure */
11557  SCIP_CONS** conss, /**< constraint set */
11558  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11559  int chkind, /**< index of constraint to check against all prior indices upto startind */
11560  int* ndelconss /**< pointer to count number of deleted constraints */
11561  )
11562 {
11563  SCIP_CONS* cons0;
11564  SCIP_CONSDATA* consdata0;
11565  int c;
11566 
11567  assert(scip != NULL);
11568  assert(conss != NULL);
11569  assert(firstchange <= chkind);
11570  assert(ndelconss != NULL);
11571 
11572  /* get the constraint to be checked against all prior constraints */
11573  cons0 = conss[chkind];
11574  assert(cons0 != NULL);
11575  assert(SCIPconsIsActive(cons0));
11576  assert(!SCIPconsIsModifiable(cons0));
11577 
11578  consdata0 = SCIPconsGetData(cons0);
11579  assert(consdata0 != NULL);
11580  assert(consdata0->nvars >= 1);
11581  assert(consdata0->merged);
11582 
11583  /* sort the constraint */
11584  sortItems(consdata0);
11585 
11586  /* see #2970 */
11587  if( consdata0->capacity == 0 )
11588  return SCIP_OKAY;
11589 
11590  /* check constraint against all prior constraints */
11591  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11592  {
11593  SCIP_CONS* cons1;
11594  SCIP_CONSDATA* consdata1;
11595  SCIP_Bool iscons0incons1contained;
11596  SCIP_Bool iscons1incons0contained;
11597  SCIP_Real quotient;
11598  int v;
11599  int v0;
11600  int v1;
11601 
11602  cons1 = conss[c];
11603  assert(cons1 != NULL);
11604  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11605  continue;
11606 
11607  consdata1 = SCIPconsGetData(cons1);
11608  assert(consdata1 != NULL);
11609 
11610  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11611  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11612  continue;
11613 
11614  assert(consdata1->nvars >= 1);
11615  assert(consdata1->merged);
11616 
11617  /* sort the constraint */
11618  sortItems(consdata1);
11619 
11620  /* see #2970 */
11621  if( consdata1->capacity == 0 )
11622  continue;
11623 
11624  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11625 
11626  if( consdata0->nvars > consdata1->nvars )
11627  {
11628  iscons0incons1contained = FALSE;
11629  iscons1incons0contained = TRUE;
11630  v = consdata1->nvars - 1;
11631  }
11632  else if( consdata0->nvars < consdata1->nvars )
11633  {
11634  iscons0incons1contained = TRUE;
11635  iscons1incons0contained = FALSE;
11636  v = consdata0->nvars - 1;
11637  }
11638  else
11639  {
11640  iscons0incons1contained = TRUE;
11641  iscons1incons0contained = TRUE;
11642  v = consdata0->nvars - 1;
11643  }
11644 
11645  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11646 
11647  /* check consdata0 against consdata1:
11648  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11649  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11650  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11651  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11652  */
11653  v0 = consdata0->nvars - 1;
11654  v1 = consdata1->nvars - 1;
11655 
11656  while( v >= 0 )
11657  {
11658  assert(iscons0incons1contained || iscons1incons0contained);
11659 
11660  /* now there are more variables in cons1 left */
11661  if( v1 > v0 )
11662  {
11663  iscons1incons0contained = FALSE;
11664  if( !iscons0incons1contained )
11665  break;
11666  }
11667  /* now there are more variables in cons0 left */
11668  else if( v1 < v0 )
11669  {
11670  iscons0incons1contained = FALSE;
11671  if( !iscons1incons0contained )
11672  break;
11673  }
11674 
11675  assert(v == v0 || v == v1);
11676  assert(v0 >= 0);
11677  assert(v1 >= 0);
11678 
11679  /* both variables are the same */
11680  if( consdata0->vars[v0] == consdata1->vars[v1] )
11681  {
11682  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11683  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11684  {
11685  iscons1incons0contained = FALSE;
11686  if( !iscons0incons1contained )
11687  break;
11688  }
11689  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11690  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11691  {
11692  iscons0incons1contained = FALSE;
11693  if( !iscons1incons0contained )
11694  break;
11695  }
11696  --v0;
11697  --v1;
11698  --v;
11699  }
11700  else
11701  {
11702  /* both constraints have a variables which is not part of the other constraint, so stop */
11703  if( iscons0incons1contained && iscons1incons0contained )
11704  {
11705  iscons0incons1contained = FALSE;
11706  iscons1incons0contained = FALSE;
11707  break;
11708  }
11709  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11710  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11711  /* continue to the next variable */
11712  if( iscons0incons1contained )
11713  --v1;
11714  else
11715  --v0;
11716  }
11717  }
11718  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11719  * other
11720  */
11721  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11722 
11723  if( iscons1incons0contained )
11724  {
11725  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11726  SCIPdebugPrintCons(scip, cons1, NULL);
11727 
11728  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11729  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11730 
11731  SCIP_CALL( SCIPdelCons(scip, cons1) );
11732  ++(*ndelconss);
11733  }
11734  else if( iscons0incons1contained )
11735  {
11736  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11737  SCIPdebugPrintCons(scip, cons0, NULL);
11738 
11739  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11740  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11741 
11742  SCIP_CALL( SCIPdelCons(scip, cons0) );
11743  ++(*ndelconss);
11744  break;
11745  }
11746  }
11747 
11748  return SCIP_OKAY;
11749 }
11750 
11751 /** helper function to enforce constraints */
11752 static
11754  SCIP* scip, /**< SCIP data structure */
11755  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11756  SCIP_CONS** conss, /**< constraints to process */
11757  int nconss, /**< number of constraints */
11758  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11759  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11760  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11761  )
11762 {
11763  SCIP_CONSHDLRDATA* conshdlrdata;
11764  SCIP_Bool violated;
11765  SCIP_Bool cutoff = FALSE;
11766  int maxncuts;
11767  int ncuts = 0;
11768  int i;
11769 
11770  *result = SCIP_FEASIBLE;
11771 
11772  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11773  sol == NULL ? "LP" : "relaxation");
11774 
11775  /* get maximal number of cuts per round */
11776  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11777  assert(conshdlrdata != NULL);
11778  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11779 
11780  /* search for violated useful knapsack constraints */
11781  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11782  {
11783  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11784  if( violated )
11785  {
11786  /* add knapsack constraint as LP row to the relaxation */
11787  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11788  ncuts++;
11789  }
11790  }
11791 
11792  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11793  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11794  {
11795  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11796  if( violated )
11797  {
11798  /* add knapsack constraint as LP row to the relaxation */
11799  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11800  ncuts++;
11801  }
11802  }
11803 
11804  /* adjust the result code */
11805  if ( cutoff )
11806  *result = SCIP_CUTOFF;
11807  else if ( ncuts > 0 )
11808  *result = SCIP_SEPARATED;
11809 
11810  return SCIP_OKAY;
11811 }
11812 
11813 /*
11814  * Linear constraint upgrading
11815  */
11816 
11817 /** creates and captures a knapsack constraint out of a linear inequality */
11818 static
11820  SCIP* scip, /**< SCIP data structure */
11821  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11822  const char* name, /**< name of constraint */
11823  int nvars, /**< number of variables in the constraint */
11824  SCIP_VAR** vars, /**< array with variables of constraint entries */
11825  SCIP_Real* vals, /**< array with inequality coefficients */
11826  SCIP_Real lhs, /**< left hand side of inequality */
11827  SCIP_Real rhs, /**< right hand side of inequality */
11828  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11829  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11830  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11831  * Usually set to TRUE. */
11832  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11833  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11834  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11835  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11836  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11837  * Usually set to TRUE. */
11838  SCIP_Bool local, /**< is constraint only valid locally?
11839  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11840  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11841  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11842  * adds coefficients to this constraint. */
11843  SCIP_Bool dynamic, /**< is constraint subject to aging?
11844  * Usually set to FALSE. Set to TRUE for own cuts which
11845  * are separated as constraints. */
11846  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11847  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11848  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11849  * if it may be moved to a more global node?
11850  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11851  )
11852 {
11853  SCIP_VAR** transvars;
11854  SCIP_Longint* weights;
11855  SCIP_Longint capacity;
11856  SCIP_Longint weight;
11857  int mult;
11858  int v;
11859 
11860  assert(nvars == 0 || vars != NULL);
11861  assert(nvars == 0 || vals != NULL);
11862  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11863 
11864  /* get temporary memory */
11865  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11866  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11867 
11868  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11869  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11870  */
11871  if( SCIPisInfinity(scip, rhs) )
11872  {
11873  mult = -1;
11874  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11875  }
11876  else
11877  {
11878  mult = +1;
11879  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11880  }
11881 
11882  /* negate positive or negative variables */
11883  for( v = 0; v < nvars; ++v )
11884  {
11885  assert(SCIPisFeasIntegral(scip, vals[v]));
11886  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11887  if( weight > 0 )
11888  {
11889  transvars[v] = vars[v];
11890  weights[v] = weight;
11891  }
11892  else
11893  {
11894  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11895  weights[v] = -weight; /*lint !e2704*/
11896  capacity -= weight;
11897  }
11898  assert(transvars[v] != NULL);
11899  }
11900 
11901  /* create the constraint */
11902  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11903  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11904 
11905  /* free temporary memory */
11906  SCIPfreeBufferArray(scip, &weights);
11907  SCIPfreeBufferArray(scip, &transvars);
11908 
11909  return SCIP_OKAY;
11910 }
11911 
11912 /** tries to upgrade a linear constraint into a knapsack constraint */
11913 static
11914 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11915 { /*lint --e{715}*/
11916  SCIP_Bool upgrade;
11917 
11918  assert(upgdcons != NULL);
11919 
11920  /* check, if linear constraint can be upgraded to a knapsack constraint
11921  * - all variables must be binary
11922  * - all coefficients must be integral
11923  * - exactly one of the sides must be infinite
11924  */
11925  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11926  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11927  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11928 
11929  if( upgrade )
11930  {
11931  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11932 
11933  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11934  assert(!SCIPconsIsModifiable(cons));
11935  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11940  }
11941 
11942  return SCIP_OKAY;
11943 }
11944 
11945 
11946 /*
11947  * Callback methods of constraint handler
11948  */
11949 
11950 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11951 /**! [SnippetConsCopyKnapsack] */
11952 static
11953 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11954 { /*lint --e{715}*/
11955  assert(scip != NULL);
11956  assert(conshdlr != NULL);
11957  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11958 
11959  /* call inclusion method of constraint handler */
11962  *valid = TRUE;
11963 
11964  return SCIP_OKAY;
11965 }
11966 /**! [SnippetConsCopyKnapsack] */
11967 
11968 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11969 /**! [SnippetConsFreeKnapsack] */
11970 static
11971 SCIP_DECL_CONSFREE(consFreeKnapsack)
11972 { /*lint --e{715}*/
11973  SCIP_CONSHDLRDATA* conshdlrdata;
11974 
11975  /* free constraint handler data */
11976  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11977  assert(conshdlrdata != NULL);
11978 
11979  SCIPfreeBlockMemory(scip, &conshdlrdata);
11980 
11981  SCIPconshdlrSetData(conshdlr, NULL);
11982 
11983  return SCIP_OKAY;
11984 }
11985 /**! [SnippetConsFreeKnapsack] */
11986 
11987 
11988 /** initialization method of constraint handler (called after problem was transformed) */
11989 static
11990 SCIP_DECL_CONSINIT(consInitKnapsack)
11991 { /*lint --e{715}*/
11992  SCIP_CONSHDLRDATA* conshdlrdata;
11993  int nvars;
11994 
11995  assert( scip != NULL );
11996  assert( conshdlr != NULL );
11997 
11998  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11999  assert(conshdlrdata != NULL);
12000 
12001  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12002  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12003 
12004  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12005  conshdlrdata->reals1size = nvars;
12006 
12007  return SCIP_OKAY;
12008 }
12009 
12010 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12011 static
12012 SCIP_DECL_CONSEXIT(consExitKnapsack)
12013 { /*lint --e{715}*/
12014  SCIP_CONSHDLRDATA* conshdlrdata;
12015 
12016  assert( scip != NULL );
12017  assert( conshdlr != NULL );
12018 
12019  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12020  assert(conshdlrdata != NULL);
12021 
12022  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12023  conshdlrdata->reals1size = 0;
12024 
12025  return SCIP_OKAY;
12026 }
12027 
12028 
12029 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12030 static
12031 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12032 { /*lint --e{715}*/
12033  SCIP_CONSHDLRDATA* conshdlrdata;
12034  int nvars;
12035 
12036  assert(scip != NULL);
12037  assert(conshdlr != NULL);
12038  assert(nconss == 0 || conss != NULL);
12040  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12041  assert(conshdlrdata != NULL);
12042 
12043  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12044  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12045 
12046  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12047  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12048  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12049  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12050  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12051  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12052  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12053  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12054 
12055  conshdlrdata->ints1size = nvars;
12056  conshdlrdata->ints2size = nvars;
12057  conshdlrdata->longints1size = nvars;
12058  conshdlrdata->longints2size = nvars;
12059  conshdlrdata->bools1size = nvars;
12060  conshdlrdata->bools2size = nvars;
12061  conshdlrdata->bools3size = nvars;
12062  conshdlrdata->bools4size = nvars;
12063 
12064 #ifdef WITH_CARDINALITY_UPGRADE
12065  conshdlrdata->upgradedcard = FALSE;
12066 #endif
12067 
12068  return SCIP_OKAY;
12069 }
12070 
12071 
12072 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12073 static
12074 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12075 { /*lint --e{715}*/
12076  SCIP_CONSHDLRDATA* conshdlrdata;
12077  int c;
12078 
12079  assert(scip != NULL);
12080  assert(conshdlr != NULL);
12081 
12082  for( c = 0; c < nconss; ++c )
12083  {
12084  if( !SCIPconsIsDeleted(conss[c]) )
12085  {
12086  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12087  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12088  }
12089  }
12090 
12091  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12092  assert(conshdlrdata != NULL);
12093 
12094  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12095  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12096  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12097  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12098  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12099  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12100  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12101  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12102 
12103  conshdlrdata->ints1size = 0;
12104  conshdlrdata->ints2size = 0;
12105  conshdlrdata->longints1size = 0;
12106  conshdlrdata->longints2size = 0;
12107  conshdlrdata->bools1size = 0;
12108  conshdlrdata->bools2size = 0;
12109  conshdlrdata->bools3size = 0;
12110  conshdlrdata->bools4size = 0;
12111 
12112  return SCIP_OKAY;
12113 }
12114 
12115 
12116 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12117 static
12118 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12119 { /*lint --e{715}*/
12120  SCIP_CONSDATA* consdata;
12121  int c;
12122 
12123  assert( scip != NULL );
12124 
12125  /* release the rows of all constraints */
12126  for( c = 0; c < nconss; ++c )
12127  {
12128  consdata = SCIPconsGetData(conss[c]);
12129  assert(consdata != NULL);
12130 
12131  if( consdata->row != NULL )
12132  {
12133  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12134  }
12135  }
12136 
12137  return SCIP_OKAY;
12138 }
12139 
12140 /** frees specific constraint data */
12141 static
12142 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12143 { /*lint --e{715}*/
12144  SCIP_CONSHDLRDATA* conshdlrdata;
12145 
12146  assert(conshdlr != NULL);
12147  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12148 
12149  /* get event handler */
12150  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12151  assert(conshdlrdata != NULL);
12152  assert(conshdlrdata->eventhdlr != NULL);
12153 
12154  /* free knapsack constraint */
12155  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12156 
12157  return SCIP_OKAY;
12158 }
12159 
12160 /** transforms constraint data into data belonging to the transformed problem */
12161 /**! [SnippetConsTransKnapsack]*/
12162 static
12163 SCIP_DECL_CONSTRANS(consTransKnapsack)
12164 { /*lint --e{715}*/
12165  SCIP_CONSHDLRDATA* conshdlrdata;
12166  SCIP_CONSDATA* sourcedata;
12167  SCIP_CONSDATA* targetdata;
12168 
12169  assert(conshdlr != NULL);
12170  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12172  assert(sourcecons != NULL);
12173  assert(targetcons != NULL);
12174 
12175  sourcedata = SCIPconsGetData(sourcecons);
12176  assert(sourcedata != NULL);
12177  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12178 
12179  /* get event handler */
12180  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12181  assert(conshdlrdata != NULL);
12182  assert(conshdlrdata->eventhdlr != NULL);
12183 
12184  /* create target constraint data */
12185  SCIP_CALL( consdataCreate(scip, &targetdata,
12186  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12187 
12188  /* create target constraint */
12189  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12190  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12191  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12192  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12193  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12194 
12195  /* catch events for variables */
12196  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12197 
12198  return SCIP_OKAY;
12199 }
12200 /**! [SnippetConsTransKnapsack]*/
12201 
12202 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12203 static
12204 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12205 { /*lint --e{715}*/
12206  int i;
12207 
12208  *infeasible = FALSE;
12209 
12210  for( i = 0; i < nconss && !(*infeasible); i++ )
12211  {
12212  assert(SCIPconsIsInitial(conss[i]));
12213  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12214  }
12215 
12216  return SCIP_OKAY;
12217 }
12218 
12219 /** separation method of constraint handler for LP solutions */
12220 static
12221 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12222 { /*lint --e{715}*/
12223  SCIP_CONSHDLRDATA* conshdlrdata;
12224  SCIP_Bool sepacardinality;
12225  SCIP_Bool cutoff;
12226 
12227  SCIP_Real loclowerbound;
12228  SCIP_Real glblowerbound;
12229  SCIP_Real cutoffbound;
12230  SCIP_Real maxbound;
12231 
12232  int depth;
12233  int nrounds;
12234  int sepafreq;
12235  int sepacardfreq;
12236  int ncuts;
12237  int maxsepacuts;
12238  int i;
12239 
12240  *result = SCIP_DIDNOTRUN;
12241 
12242  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12243  assert(conshdlrdata != NULL);
12244 
12245  depth = SCIPgetDepth(scip);
12246  nrounds = SCIPgetNSepaRounds(scip);
12247 
12248  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12249  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12250 
12251  /* only call the separator a given number of times at each node */
12252  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12253  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12254  return SCIP_OKAY;
12255 
12256  /* check, if we should additionally separate knapsack cuts */
12257  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12258  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12259  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12260  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12261 
12262  /* check dual bound to see if we want to produce knapsack cuts at this node */
12263  loclowerbound = SCIPgetLocalLowerbound(scip);
12264  glblowerbound = SCIPgetLowerbound(scip);
12265  cutoffbound = SCIPgetCutoffbound(scip);
12266  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12267  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12268  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12269 
12270  /* get the maximal number of cuts allowed in a separation round */
12271  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12272 
12273  *result = SCIP_DIDNOTFIND;
12274  ncuts = 0;
12275  cutoff = FALSE;
12276 
12277  /* separate useful constraints */
12278  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12279  {
12280  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12281  }
12282 
12283  /* adjust return value */
12284  if ( cutoff )
12285  *result = SCIP_CUTOFF;
12286  else if ( ncuts > 0 )
12287  *result = SCIP_SEPARATED;
12288 
12289  return SCIP_OKAY;
12290 }
12291 
12292 
12293 /** separation method of constraint handler for arbitrary primal solutions */
12294 static
12295 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12296 { /*lint --e{715}*/
12297  SCIP_CONSHDLRDATA* conshdlrdata;
12298  SCIP_Bool sepacardinality;
12299  SCIP_Bool cutoff;
12300 
12301  int depth;
12302  int nrounds;
12303  int sepafreq;
12304  int sepacardfreq;
12305  int ncuts;
12306  int maxsepacuts;
12307  int i;
12308 
12309  *result = SCIP_DIDNOTRUN;
12310 
12311  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12312  assert(conshdlrdata != NULL);
12313 
12314  depth = SCIPgetDepth(scip);
12315  nrounds = SCIPgetNSepaRounds(scip);
12316 
12317  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12318  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12319 
12320  /* only call the separator a given number of times at each node */
12321  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12322  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12323  return SCIP_OKAY;
12324 
12325  /* check, if we should additionally separate knapsack cuts */
12326  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12327  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12328  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12329  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12330 
12331  /* get the maximal number of cuts allowed in a separation round */
12332  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12333 
12334  *result = SCIP_DIDNOTFIND;
12335  ncuts = 0;
12336  cutoff = FALSE;
12337 
12338  /* separate useful constraints */
12339  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12340  {
12341  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12342  }
12343 
12344  /* adjust return value */
12345  if ( cutoff )
12346  *result = SCIP_CUTOFF;
12347  else if( ncuts > 0 )
12348  *result = SCIP_SEPARATED;
12349 
12350  return SCIP_OKAY;
12351 }
12352 
12353 /** constraint enforcing method of constraint handler for LP solutions */
12354 static
12355 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12356 { /*lint --e{715}*/
12357  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12358 
12359  return SCIP_OKAY;
12360 }
12361 
12362 /** constraint enforcing method of constraint handler for relaxation solutions */
12363 static
12364 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12365 { /*lint --e{715}*/
12366  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12367 
12368  return SCIP_OKAY;
12369 }
12370 
12371 /** constraint enforcing method of constraint handler for pseudo solutions */
12372 static
12373 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12374 { /*lint --e{715}*/
12375  SCIP_Bool violated;
12376  int i;
12377 
12378  for( i = 0; i < nconss; i++ )
12379  {
12380  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12381  if( violated )
12382  {
12383  *result = SCIP_INFEASIBLE;
12384  return SCIP_OKAY;
12385  }
12386  }
12387  *result = SCIP_FEASIBLE;
12388 
12389  return SCIP_OKAY;
12390 }
12391 
12392 /** feasibility check method of constraint handler for integral solutions */
12393 static
12394 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12395 { /*lint --e{715}*/
12396  SCIP_Bool violated;
12397  int i;
12398 
12399  *result = SCIP_FEASIBLE;
12400 
12401  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12402  {
12403  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12404  if( violated )
12405  *result = SCIP_INFEASIBLE;
12406  }
12407 
12408  return SCIP_OKAY;
12409 }
12410 
12411 /** domain propagation method of constraint handler */
12412 static
12413 SCIP_DECL_CONSPROP(consPropKnapsack)
12414 { /*lint --e{715}*/
12415  SCIP_CONSHDLRDATA* conshdlrdata;
12416  SCIP_Bool cutoff;
12417  SCIP_Bool redundant;
12418  SCIP_Bool inpresolve;
12419  int nfixedvars;
12420  int i;
12422  cutoff = FALSE;
12423  nfixedvars = 0;
12424 
12425  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12426  assert(conshdlrdata != NULL);
12427 
12428  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12429  assert(!inpresolve || SCIPinProbing(scip));
12430 
12431  /* process useful constraints */
12432  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12433  {
12434  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12435  * otherwise the multi-aggregation should be resolved
12436  */
12437  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12438  continue;
12439 #ifndef NDEBUG
12440  else
12441  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12442 #endif
12443 
12444  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12445 
12446  /* unmark the constraint to be propagated */
12447  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12448  }
12449 
12450  /* adjust result code */
12451  if( cutoff )
12452  *result = SCIP_CUTOFF;
12453  else if( nfixedvars > 0 )
12454  *result = SCIP_REDUCEDDOM;
12455  else
12456  *result = SCIP_DIDNOTFIND;
12457 
12458  return SCIP_OKAY; /*lint !e438*/
12459 }
12460 
12461 /** presolving method of constraint handler */
12462 static
12463 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12464 { /*lint --e{574,715}*/
12465  SCIP_CONSHDLRDATA* conshdlrdata;
12466  SCIP_CONSDATA* consdata;
12467  SCIP_CONS* cons;
12468  SCIP_Bool cutoff;
12469  SCIP_Bool redundant;
12470  SCIP_Bool success;
12471  int oldnfixedvars;
12472  int oldnchgbds;
12473  int oldndelconss;
12474  int oldnaddconss;
12475  int oldnchgcoefs;
12476  int oldnchgsides;
12477  int firstchange;
12478  int c;
12479  SCIP_Bool newchanges;
12480 
12481  /* remember old preprocessing counters */
12482  cutoff = FALSE;
12483  oldnfixedvars = *nfixedvars;
12484  oldnchgbds = *nchgbds;
12485  oldndelconss = *ndelconss;
12486  oldnaddconss = *naddconss;
12487  oldnchgcoefs = *nchgcoefs;
12488  oldnchgsides = *nchgsides;
12489  firstchange = INT_MAX;
12490 
12491  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12492 
12493  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12494  assert(conshdlrdata != NULL);
12495 
12496  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12497  {
12498  int thisnfixedvars;
12499  int thisnchgbds;
12500 
12501  cons = conss[c];
12502  consdata = SCIPconsGetData(cons);
12503  assert(consdata != NULL);
12504 
12505  /* update data structures */
12506  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12507  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12508  {
12509  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12510  if( cutoff )
12511  break;
12512  }
12513 
12514  /* force presolving the constraint in the initial round */
12515  if( nrounds == 0 )
12516  consdata->presolvedtiming = 0;
12517  else if( consdata->presolvedtiming >= presoltiming )
12518  continue;
12519 
12520  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12521  SCIPdebugPrintCons(scip, cons, NULL);
12522  consdata->presolvedtiming = presoltiming;
12523 
12524  thisnfixedvars = *nfixedvars;
12525  thisnchgbds = *nchgbds;
12526 
12527  /* merge constraint, so propagation works better */
12528  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12529  if( cutoff )
12530  break;
12531 
12532  /* add cliques in the knapsack to the clique table */
12533  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12534  {
12535  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12536  if( cutoff )
12537  break;
12538  }
12539 
12540  /* propagate constraint */
12541  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12542  {
12543  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12544 
12545  if( cutoff )
12546  break;
12547  if( redundant )
12548  {
12549  (*ndelconss)++;
12550  continue;
12551  }
12552  }
12553 
12554  /* remove again all fixed variables, if further fixings were found */
12555  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12556  {
12557  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12558  if( cutoff )
12559  break;
12560 
12561  thisnfixedvars = *nfixedvars;
12562  }
12563 
12564  if( !SCIPconsIsModifiable(cons) )
12565  {
12566  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12567  if( consdata->weightsum <= consdata->capacity )
12568  {
12569  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12570  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12571  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12572  continue;
12573  }
12574 
12575  /* divide weights by their greatest common divisor */
12576  normalizeWeights(cons, nchgcoefs, nchgsides);
12577 
12578  /* try to simplify inequalities */
12579  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12580  {
12581  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12582  if( cutoff )
12583  break;
12584 
12585  if( SCIPconsIsDeleted(cons) )
12586  continue;
12587 
12588  /* remove again all fixed variables, if further fixings were found */
12589  if( *nfixedvars > thisnfixedvars )
12590  {
12591  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12592  if( cutoff )
12593  break;
12594  }
12595  }
12596 
12597  /* tighten capacity and weights */
12598  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12599  if( cutoff )
12600  break;
12601 
12602  if( SCIPconsIsActive(cons) )
12603  {
12604  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12605  {
12606  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12607  * dual reduction
12608  */
12609  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12610  if( redundant )
12611  continue;
12612  }
12613 
12614  /* check if knapsack constraint is parallel to objective function */
12615  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12616  }
12617  }
12618  /* remember the first changed constraint to begin the next aggregation round with */
12619  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12620  firstchange = c;
12621  }
12622 
12623  /* preprocess pairs of knapsack constraints */
12624  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12625  {
12626  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12627  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12628  }
12629 
12630  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12631  success = TRUE;
12632  else
12633  success = FALSE;
12634 
12635  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12636  {
12637  SCIP_Longint npaircomparisons;
12638 
12639  npaircomparisons = 0;
12640  oldndelconss = *ndelconss;
12641  oldnchgsides = *nchgsides;
12642  oldnchgcoefs = *nchgcoefs;
12643 
12644  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12645  {
12646  cons = conss[c];
12647  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12648  continue;
12649 
12650  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12651 
12652  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12653 
12654  if( npaircomparisons > NMINCOMPARISONS )
12655  {
12656  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12657  success = TRUE;
12658  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12659  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12660  break;
12661  oldndelconss = *ndelconss;
12662  oldnchgsides = *nchgsides;
12663  oldnchgcoefs = *nchgcoefs;
12664  npaircomparisons = 0;
12665  }
12666  }
12667  }
12668 #ifdef WITH_CARDINALITY_UPGRADE
12669  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12670  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12671  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12672  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12673  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12674  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12675  * as well, we better keep this code disabled. */
12676  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12677  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12678  {
12679  SCIP_HASHMAP* varhash;
12680  SCIP_VAR** cardvars;
12681  SCIP_Real* cardweights;
12682  int noldupgdconss;
12683  int nscipvars;
12684  int makeupgrade;
12685 
12686  noldupgdconss = *nupgdconss;
12687  nscipvars = SCIPgetNVars(scip);
12688  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12689  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12690 
12691  /* set up hash map */
12692  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12693 
12694  /* We loop through all cardinality constraints twice:
12695  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12696  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12697  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12698  * - Second, upgrade knapsack constraints to cardinality constraints. */
12699  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12700  {
12701  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12702  {
12703  SCIP_CONS* cardcons;
12704  SCIP_VAR** vars;
12705  SCIP_Longint* weights;
12706  int nvars;
12707  int v;
12708 
12709  cons = conss[c];
12710  assert( cons != NULL );
12711  consdata = SCIPconsGetData(cons);
12712  assert( consdata != NULL );
12713 
12714  nvars = consdata->nvars;
12715  vars = consdata->vars;
12716  weights = consdata->weights;
12717 
12718  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12719  * - all variables must be binary (always true)
12720  * - all coefficients must be 1.0
12721  * - the right hand side must be smaller than nvars
12722  */
12723  if ( consdata->capacity >= nvars )
12724  continue;
12725 
12726  /* the weights are sorted: check first and last weight */
12727  assert( consdata->sorted );
12728  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12729  continue;
12730 
12731  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12732  for (v = 0; v < nvars; ++v)
12733  {
12734  SCIP_BOUNDTYPE* impltypes;
12735  SCIP_Real* implbounds;
12736  SCIP_VAR** implvars;
12737  SCIP_VAR* var;
12738  int nimpls;
12739  int j;
12740 
12741  var = consdata->vars[v];
12742  assert( var != NULL );
12743  assert( SCIPvarIsBinary(var) );
12744 
12745  /* ignore non-active variables */
12746  if ( ! SCIPvarIsActive(var) )
12747  break;
12748 
12749  /* be sure that implication variable has zero objective */
12750  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12751  break;
12752 
12753  nimpls = SCIPvarGetNImpls(var, FALSE);
12754  implvars = SCIPvarGetImplVars(var, FALSE);
12755  implbounds = SCIPvarGetImplBounds(var, FALSE);
12756  impltypes = SCIPvarGetImplTypes(var, FALSE);
12757 
12758  for (j = 0; j < nimpls; ++j)
12759  {
12760  /* be sure that continuous variable is fixed to 0 */
12761  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12762  continue;
12763 
12764  /* cannot currently deal with nonzero fixings */
12765  if ( ! SCIPisZero(scip, implbounds[j]) )
12766  continue;
12767 
12768  /* number of down locks should be one */
12769  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12770  continue;
12771 
12772  cardvars[v] = implvars[j];
12773  cardweights[v] = (SCIP_Real) v;
12774 
12775  break;
12776  }
12777 
12778  /* found no variable upper bound candidate -> exit */
12779  if ( j >= nimpls )
12780  break;
12781  }
12782 
12783  /* did not find fitting variable upper bound for some variable -> exit */
12784  if ( v < nvars )
12785  break;
12786 
12787  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12788  * in which the binary variable is involved in */
12789  if ( makeupgrade == 0 )
12790  {
12791  for (v = 0; v < nvars; ++v)
12792  {
12793  if ( SCIPhashmapExists(varhash, vars[v]) )
12794  {
12795  int image;
12796 
12797  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12798  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12799  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12800  }
12801  else
12802  {
12803  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12804  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12805  assert( SCIPhashmapExists(varhash, vars[v]) );
12806  }
12807  }
12808  }
12809  else
12810  {
12811  SCIP_CONS* origcons;
12812 
12813  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12814  * knapsack constraint coincides with the number of variable up locks */
12815  for (v = 0; v < nvars; ++v)
12816  {
12817  assert( SCIPhashmapExists(varhash, vars[v]) );
12818  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12819  break;
12820  }
12821  if ( v < nvars )
12822  break;
12823 
12824  /* store that we have upgraded */
12825  conshdlrdata->upgradedcard = TRUE;
12826 
12827  /* at this point we found suitable variable upper bounds */
12828  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12829 
12830  /* create cardinality constraint */
12831  assert( ! SCIPconsIsModifiable(cons) );
12832  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12836 #ifdef SCIP_DEBUG
12837  SCIPprintCons(scip, cons, NULL);
12838  SCIPinfoMessage(scip, NULL, "\n");
12839  SCIPprintCons(scip, cardcons, NULL);
12840  SCIPinfoMessage(scip, NULL, "\n");
12841 #endif
12842  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12843  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12844  ++(*nupgdconss);
12845 
12846  /* delete oknapsack constraint */
12847  SCIP_CALL( SCIPdelCons(scip, cons) );
12848  ++(*ndelconss);
12849 
12850  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12851  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12852  * although the cardinality constraint is satisfied. */
12853  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12854  assert( origcons != NULL );
12855  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12856 
12857  for (v = 0; v < nvars; ++v)
12858  {
12859  int image;
12860 
12861  assert ( SCIPhashmapExists(varhash, vars[v]) );
12862  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12863  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12864  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12865  }
12866  }
12867  }
12868  }
12869  SCIPhashmapFree(&varhash);
12870  SCIPfreeBufferArray(scip, &cardweights);
12871  SCIPfreeBufferArray(scip, &cardvars);
12872 
12873  if ( *nupgdconss > noldupgdconss )
12874  success = TRUE;
12875  }
12876 #endif
12877 
12878  if( cutoff )
12879  *result = SCIP_CUTOFF;
12880  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12881  *result = SCIP_SUCCESS;
12882  else
12883  *result = SCIP_DIDNOTFIND;
12884 
12885  return SCIP_OKAY;
12886 }
12887 
12888 /** propagation conflict resolving method of constraint handler */
12889 static
12890 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12891 { /*lint --e{715}*/
12892  SCIP_CONSDATA* consdata;
12893  SCIP_Longint capsum;
12894  int i;
12895 
12896  assert(result != NULL);
12897 
12898  consdata = SCIPconsGetData(cons);
12899  assert(consdata != NULL);
12900 
12901  /* check if we fixed a binary variable to one (due to negated clique) */
12902  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12903  {
12904  for( i = 0; i < consdata->nvars; ++i )
12905  {
12906  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12907  {
12908  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12909  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12910  break;
12911  }
12912  }
12913  assert(i < consdata->nvars);
12914  }
12915  else
12916  {
12917  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12918  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12919  * knapsack constraint, see one above call of SCIPinferBinvarCons
12920  */
12921  if( inferinfo < 0 )
12922  capsum = 0;
12923  else
12924  {
12925  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12926  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12927  */
12928  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12929  capsum = consdata->weights[inferinfo];
12930  else
12931  {
12932  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12933  {}
12934  assert(i < consdata->nvars);
12935  capsum = consdata->weights[i];
12936  }
12937  }
12938 
12939  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12940  * the capacity
12941  */
12942  if( capsum <= consdata->capacity )
12943  {
12944  for( i = 0; i < consdata->nvars; i++ )
12945  {
12946  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12947  {
12948  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12949  capsum += consdata->weights[i];
12950  if( capsum > consdata->capacity )
12951  break;
12952  }
12953  }
12954  }
12955  }
12956 
12957  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12958  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12959  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12960  * used to fix variables to zero.
12961  *
12962  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12963  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12964  * one.
12965  */
12966  *result = SCIP_SUCCESS;
12967 
12968  return SCIP_OKAY;
12969 }
12970 
12971 /** variable rounding lock method of constraint handler */
12972 /**! [SnippetConsLockKnapsack] */
12973 static
12974 SCIP_DECL_CONSLOCK(consLockKnapsack)
12975 { /*lint --e{715}*/
12976  SCIP_CONSDATA* consdata;
12977  int i;
12978 
12979  consdata = SCIPconsGetData(cons);
12980  assert(consdata != NULL);
12981 
12982  for( i = 0; i < consdata->nvars; i++)
12983  {
12984  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
12985  }
12986 
12987  return SCIP_OKAY;
12988 }
12989 /**! [SnippetConsLockKnapsack] */
12990 
12991 
12992 /** variable deletion method of constraint handler */
12993 static
12994 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
12995 {
12996  assert(scip != NULL);
12997  assert(conshdlr != NULL);
12998  assert(conss != NULL || nconss == 0);
12999 
13000  if( nconss > 0 )
13001  {
13002  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13003  }
13004 
13005  return SCIP_OKAY;
13006 }
13007 
13008 /** constraint display method of constraint handler */
13009 static
13010 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13011 { /*lint --e{715}*/
13012  SCIP_CONSDATA* consdata;
13013  int i;
13014 
13015  assert( scip != NULL );
13016  assert( conshdlr != NULL );
13017  assert( cons != NULL );
13019  consdata = SCIPconsGetData(cons);
13020  assert(consdata != NULL);
13021 
13022  for( i = 0; i < consdata->nvars; ++i )
13023  {
13024  if( i > 0 )
13025  SCIPinfoMessage(scip, file, " ");
13026  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13027  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13028  }
13029  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13030 
13031  return SCIP_OKAY;
13032 }
13033 
13034 /** constraint copying method of constraint handler */
13035 static
13036 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13037 { /*lint --e{715}*/
13038  SCIP_VAR** sourcevars;
13039  SCIP_Longint* weights;
13040  SCIP_Real* coefs;
13041  const char* consname;
13042  int nvars;
13043  int v;
13045  /* get variables and coefficients of the source constraint */
13046  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13047  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13048  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13049 
13050  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13051  for( v = 0; v < nvars; ++v )
13052  coefs[v] = (SCIP_Real) weights[v];
13053 
13054  if( name != NULL )
13055  consname = name;
13056  else
13057  consname = SCIPconsGetName(sourcecons);
13058 
13059  /* copy the logic using the linear constraint copy method */
13060  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13061  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13062  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13063  assert(cons != NULL);
13064 
13065  SCIPfreeBufferArray(scip, &coefs);
13066 
13067  return SCIP_OKAY;
13068 }
13069 
13070 /** constraint parsing method of constraint handler */
13071 static
13072 SCIP_DECL_CONSPARSE(consParseKnapsack)
13073 { /*lint --e{715}*/
13074  SCIP_VAR* var;
13075  SCIP_Longint weight;
13076  SCIP_VAR** vars;
13077  SCIP_Longint* weights;
13078  SCIP_Longint capacity;
13079  char* endptr;
13080  int nread;
13081  int nvars;
13082  int varssize;
13083 
13084  assert(scip != NULL);
13085  assert(success != NULL);
13086  assert(str != NULL);
13087  assert(name != NULL);
13088  assert(cons != NULL);
13089 
13090  *success = TRUE;
13091 
13092  nvars = 0;
13093  varssize = 5;
13094  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13095  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13096 
13097  while( *str != '\0' )
13098  {
13099  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13100  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13101  break;
13102 
13103  str += nread;
13104 
13105  /* skip whitespace */
13106  while( isspace((int)*str) )
13107  ++str;
13108 
13109  /* parse variable name */
13110  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13111  if( var == NULL )
13112  {
13113  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13114  *success = FALSE;
13115  break;
13116  }
13117 
13118  str = endptr;
13119 
13120  /* store weight and variable */
13121  if( varssize <= nvars )
13122  {
13123  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13124  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13125  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13126  }
13127 
13128  vars[nvars] = var;
13129  weights[nvars] = weight;
13130  ++nvars;
13131 
13132  /* skip whitespace */
13133  while( isspace((int)*str) )
13134  ++str;
13135  }
13136 
13137  if( *success )
13138  {
13139  if( strncmp(str, "<= ", 3) != 0 )
13140  {
13141  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13142  *success = FALSE;
13143  }
13144  else
13145  {
13146  str += 3;
13147  }
13148  }
13149 
13150  if( *success )
13151  {
13152  /* coverity[secure_coding] */
13153  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13154  {
13155  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13156  *success = FALSE;
13157  }
13158  else
13159  {
13160  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13161  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13162  }
13163  }
13164 
13165  SCIPfreeBufferArray(scip, &vars);
13166  SCIPfreeBufferArray(scip, &weights);
13167 
13168  return SCIP_OKAY;
13169 }
13170 
13171 /** constraint method of constraint handler which returns the variables (if possible) */
13172 static
13173 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13174 { /*lint --e{715}*/
13175  SCIP_CONSDATA* consdata;
13176 
13177  consdata = SCIPconsGetData(cons);
13178  assert(consdata != NULL);
13179 
13180  if( varssize < consdata->nvars )
13181  (*success) = FALSE;
13182  else
13183  {
13184  assert(vars != NULL);
13185 
13186  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13187  (*success) = TRUE;
13188  }
13189 
13190  return SCIP_OKAY;
13191 }
13192 
13193 /** constraint method of constraint handler which returns the number of variables (if possible) */
13194 static
13195 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13196 { /*lint --e{715}*/
13197  SCIP_CONSDATA* consdata;
13198 
13199  consdata = SCIPconsGetData(cons);
13200  assert(consdata != NULL);
13201 
13202  (*nvars) = consdata->nvars;
13203  (*success) = TRUE;
13204 
13205  return SCIP_OKAY;
13206 }
13207 
13208 /*
13209  * Event handler
13210  */
13211 
13212 /** execution method of bound change event handler */
13213 static
13214 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13215 { /*lint --e{715}*/
13216  SCIP_CONSDATA* consdata;
13217 
13218  assert(eventdata != NULL);
13219  assert(eventdata->cons != NULL);
13220 
13221  consdata = SCIPconsGetData(eventdata->cons);
13222  assert(consdata != NULL);
13223 
13224  switch( SCIPeventGetType(event) )
13225  {
13227  consdata->onesweightsum += eventdata->weight;
13228  consdata->presolvedtiming = 0;
13229  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13230  break;
13232  consdata->onesweightsum -= eventdata->weight;
13233  break;
13235  consdata->presolvedtiming = 0;
13236  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13237  break;
13238  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13239  if( !consdata->existmultaggr )
13240  {
13241  SCIP_VAR* var;
13242  var = SCIPeventGetVar(event);
13243  assert(var != NULL);
13244 
13245  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13247  {
13248  consdata->existmultaggr = TRUE;
13249  consdata->merged = FALSE;
13250  }
13251  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13253  consdata->merged = FALSE;
13254  }
13255  /*lint -fallthrough*/
13256  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13257  consdata->presolvedtiming = 0;
13258  break;
13260  consdata->varsdeleted = TRUE;
13261  break;
13262  default:
13263  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
13264  return SCIP_INVALIDDATA;
13265  }
13266 
13267  return SCIP_OKAY;
13268 }
13269 
13270 
13271 /*
13272  * constraint specific interface methods
13273  */
13274 
13275 /** creates the handler for knapsack constraints and includes it in SCIP */
13277  SCIP* scip /**< SCIP data structure */
13278  )
13279 {
13280  SCIP_EVENTHDLRDATA* eventhdlrdata;
13281  SCIP_CONSHDLRDATA* conshdlrdata;
13282  SCIP_CONSHDLR* conshdlr;
13283 
13284  /* create knapsack constraint handler data */
13285  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13286 
13287  /* include event handler for bound change events */
13288  eventhdlrdata = NULL;
13289  conshdlrdata->eventhdlr = NULL;
13290  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13291  eventExecKnapsack, eventhdlrdata) );
13292 
13293  /* get event handler for bound change events */
13294  if( conshdlrdata->eventhdlr == NULL )
13295  {
13296  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13297  return SCIP_PLUGINNOTFOUND;
13298  }
13299 
13300  /* include constraint handler */
13303  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13304  conshdlrdata) );
13305 
13306  assert(conshdlr != NULL);
13307 
13308  /* set non-fundamental callbacks via specific setter functions */
13309  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13310  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13311  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13312  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13313  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13314  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13315  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13316  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13317  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13318  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13319  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13320  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13321  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13322  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13323  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13324  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13326  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13327  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13329  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13330  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13331 
13332  if( SCIPfindConshdlr(scip,"linear") != NULL )
13333  {
13334  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13336  }
13337 
13338  /* add knapsack constraint handler parameters */
13339  SCIP_CALL( SCIPaddIntParam(scip,
13340  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13341  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13342  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13344  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13345  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13346  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13348  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13349  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13350  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13351  SCIP_CALL( SCIPaddIntParam(scip,
13352  "constraints/" CONSHDLR_NAME "/maxrounds",
13353  "maximal number of separation rounds per node (-1: unlimited)",
13354  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13355  SCIP_CALL( SCIPaddIntParam(scip,
13356  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13357  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13358  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13359  SCIP_CALL( SCIPaddIntParam(scip,
13360  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13361  "maximal number of cuts separated per separation round",
13362  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13363  SCIP_CALL( SCIPaddIntParam(scip,
13364  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13365  "maximal number of cuts separated per separation round in the root node",
13366  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13368  "constraints/" CONSHDLR_NAME "/disaggregation",
13369  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13370  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13372  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13373  "should presolving try to simplify knapsacks",
13374  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13376  "constraints/" CONSHDLR_NAME "/negatedclique",
13377  "should negated clique information be used in solving process",
13378  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13380  "constraints/" CONSHDLR_NAME "/presolpairwise",
13381  "should pairwise constraint comparison be performed in presolving?",
13382  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13384  "constraints/" CONSHDLR_NAME "/presolusehashing",
13385  "should hash table be used for detecting redundant constraints in advance",
13386  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13388  "constraints/" CONSHDLR_NAME "/dualpresolving",
13389  "should dual presolving steps be performed?",
13390  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13392  "constraints/" CONSHDLR_NAME "/usegubs",
13393  "should GUB information be used for separation?",
13394  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13396  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13397  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13398  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13400  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13401  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13402  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13404  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13405  "should clique partition information be updated when old partition seems outdated?",
13406  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13408  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13409  "factor on the growth of global cliques to decide when to update a previous "
13410  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13411  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13412 #ifdef WITH_CARDINALITY_UPGRADE
13414  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13415  "if TRUE then try to update knapsack constraints to cardinality constraints",
13416  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13417 #endif
13418  return SCIP_OKAY;
13419 }
13420 
13421 /** creates and captures a knapsack constraint
13422  *
13423  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13424  */
13425 /**! [SnippetConsCreationKnapsack] */
13427  SCIP* scip, /**< SCIP data structure */
13428  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13429  const char* name, /**< name of constraint */
13430  int nvars, /**< number of items in the knapsack */
13431  SCIP_VAR** vars, /**< array with item variables */
13432  SCIP_Longint* weights, /**< array with item weights */
13433  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13434  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13435  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13436  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13437  * Usually set to TRUE. */
13438  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13439  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13440  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13441  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13442  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13443  * Usually set to TRUE. */
13444  SCIP_Bool local, /**< is constraint only valid locally?
13445  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13446  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13447  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13448  * adds coefficients to this constraint. */
13449  SCIP_Bool dynamic, /**< is constraint subject to aging?
13450  * Usually set to FALSE. Set to TRUE for own cuts which
13451  * are separated as constraints. */
13452  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13453  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13454  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13455  * if it may be moved to a more global node?
13456  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13457  )
13458 {
13459  SCIP_CONSHDLRDATA* conshdlrdata;
13460  SCIP_CONSHDLR* conshdlr;
13461  SCIP_CONSDATA* consdata;
13462 
13463  /* find the knapsack constraint handler */
13464  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13465  if( conshdlr == NULL )
13466  {
13467  SCIPerrorMessage("knapsack constraint handler not found\n");
13468  return SCIP_PLUGINNOTFOUND;
13469  }
13470 
13471  /* get event handler */
13472  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13473  assert(conshdlrdata != NULL);
13474  assert(conshdlrdata->eventhdlr != NULL);
13475 
13476  /* create constraint data */
13477  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13478 
13479  /* create constraint */
13480  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13481  local, modifiable, dynamic, removable, stickingatnode) );
13482 
13483  /* catch events for variables */
13484  if( SCIPisTransformed(scip) )
13485  {
13486  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13487  }
13488 
13489  return SCIP_OKAY;
13490 }
13491 /**! [SnippetConsCreationKnapsack] */
13492 
13493 /** creates and captures a knapsack constraint
13494  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13495  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13496  *
13497  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13498  *
13499  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13500  */
13502  SCIP* scip, /**< SCIP data structure */
13503  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13504  const char* name, /**< name of constraint */
13505  int nvars, /**< number of items in the knapsack */
13506  SCIP_VAR** vars, /**< array with item variables */
13507  SCIP_Longint* weights, /**< array with item weights */
13508  SCIP_Longint capacity /**< capacity of knapsack */
13509  )
13510 {
13511  assert(scip != NULL);
13512 
13513  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13514  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13515 
13516  return SCIP_OKAY;
13517 }
13518 
13519 /** adds new item to knapsack constraint */
13521  SCIP* scip, /**< SCIP data structure */
13522  SCIP_CONS* cons, /**< constraint data */
13523  SCIP_VAR* var, /**< item variable */
13524  SCIP_Longint weight /**< item weight */
13525  )
13526 {
13527  assert(var != NULL);
13528  assert(scip != NULL);
13529 
13530  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13531  {
13532  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13533  return SCIP_INVALIDDATA;
13534  }
13535 
13536  SCIP_CALL( addCoef(scip, cons, var, weight) );
13537 
13538  return SCIP_OKAY;
13539 }
13540 
13541 /** gets the capacity of the knapsack constraint */
13543  SCIP* scip, /**< SCIP data structure */
13544  SCIP_CONS* cons /**< constraint data */
13545  )
13546 {
13547  SCIP_CONSDATA* consdata;
13548 
13549  assert(scip != NULL);
13551  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13552  {
13553  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13554  SCIPABORT();
13555  return 0; /*lint !e527*/
13556  }
13557 
13558  consdata = SCIPconsGetData(cons);
13559  assert(consdata != NULL);
13560 
13561  return consdata->capacity;
13562 }
13563 
13564 /** changes capacity of the knapsack constraint
13565  *
13566  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13567  */
13569  SCIP* scip, /**< SCIP data structure */
13570  SCIP_CONS* cons, /**< constraint data */
13571  SCIP_Longint capacity /**< new capacity of knapsack */
13572  )
13573 {
13574  SCIP_CONSDATA* consdata;
13575 
13576  assert(scip != NULL);
13577 
13578  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13579  {
13580  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13581  return SCIP_INVALIDDATA;
13582  }
13583 
13584  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13585  {
13586  SCIPerrorMessage("method can only be called during problem creation stage\n");
13587  return SCIP_INVALIDDATA;
13588  }
13589 
13590  consdata = SCIPconsGetData(cons);
13591  assert(consdata != NULL);
13592 
13593  consdata->capacity = capacity;
13594 
13595  return SCIP_OKAY;
13596 }
13597 
13598 /** gets the number of items in the knapsack constraint */
13600  SCIP* scip, /**< SCIP data structure */
13601  SCIP_CONS* cons /**< constraint data */
13602  )
13603 {
13604  SCIP_CONSDATA* consdata;
13605 
13606  assert(scip != NULL);
13608  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13609  {
13610  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13611  SCIPABORT();
13612  return -1; /*lint !e527*/
13613  }
13614 
13615  consdata = SCIPconsGetData(cons);
13616  assert(consdata != NULL);
13617 
13618  return consdata->nvars;
13619 }
13620 
13621 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13623  SCIP* scip, /**< SCIP data structure */
13624  SCIP_CONS* cons /**< constraint data */
13625  )
13626 {
13627  SCIP_CONSDATA* consdata;
13628 
13629  assert(scip != NULL);
13631  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13632  {
13633  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13634  SCIPABORT();
13635  return NULL; /*lint !e527*/
13636  }
13637 
13638  consdata = SCIPconsGetData(cons);
13639  assert(consdata != NULL);
13640 
13641  return consdata->vars;
13642 }
13643 
13644 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13646  SCIP* scip, /**< SCIP data structure */
13647  SCIP_CONS* cons /**< constraint data */
13648  )
13649 {
13650  SCIP_CONSDATA* consdata;
13651 
13652  assert(scip != NULL);
13654  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13655  {
13656  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13657  SCIPABORT();
13658  return NULL; /*lint !e527*/
13659  }
13660 
13661  consdata = SCIPconsGetData(cons);
13662  assert(consdata != NULL);
13663 
13664  return consdata->weights;
13665 }
13666 
13667 /** gets the dual solution of the knapsack constraint in the current LP */
13669  SCIP* scip, /**< SCIP data structure */
13670  SCIP_CONS* cons /**< constraint data */
13671  )
13672 {
13673  SCIP_CONSDATA* consdata;
13674 
13675  assert(scip != NULL);
13677  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13678  {
13679  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13680  SCIPABORT();
13681  return SCIP_INVALID; /*lint !e527*/
13682  }
13683 
13684  consdata = SCIPconsGetData(cons);
13685  assert(consdata != NULL);
13686 
13687  if( consdata->row != NULL )
13688  return SCIProwGetDualsol(consdata->row);
13689  else
13690  return 0.0;
13691 }
13692 
13693 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13695  SCIP* scip, /**< SCIP data structure */
13696  SCIP_CONS* cons /**< constraint data */
13697  )
13698 {
13699  SCIP_CONSDATA* consdata;
13700 
13701  assert(scip != NULL);
13703  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13704  {
13705  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13706  SCIPABORT();
13707  return SCIP_INVALID; /*lint !e527*/
13708  }
13709 
13710  consdata = SCIPconsGetData(cons);
13711  assert(consdata != NULL);
13712 
13713  if( consdata->row != NULL )
13714  return SCIProwGetDualfarkas(consdata->row);
13715  else
13716  return 0.0;
13717 }
13718 
13719 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13720  * the user must not modify the row!
13721  */
13723  SCIP* scip, /**< SCIP data structure */
13724  SCIP_CONS* cons /**< constraint data */
13725  )
13726 {
13727  SCIP_CONSDATA* consdata;
13728 
13729  assert(scip != NULL);
13731  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13732  {
13733  SCIPerrorMessage("constraint is not a knapsack\n");
13734  SCIPABORT();
13735  return NULL; /*lint !e527*/
13736  }
13737 
13738  consdata = SCIPconsGetData(cons);
13739  assert(consdata != NULL);
13740 
13741  return consdata->row;
13742 }
13743 
13744 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13746  SCIP* scip, /**< SCIP data structure */
13747  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13748  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13749  )
13750 {
13751  SCIP_CONSHDLR* conshdlr;
13752  SCIP_CONS** conss;
13753  int nconss;
13754  int i;
13755 
13756  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13757  if( conshdlr == NULL )
13758  return SCIP_OKAY;
13759 
13760  assert(infeasible != NULL);
13761  *infeasible = FALSE;
13762 
13763  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13764  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13765 
13766  for( i = 0; i < nconss; ++i )
13767  {
13768  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13769 
13770  if( *infeasible )
13771  break;
13772  }
13773 
13774  return SCIP_OKAY;
13775 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define KNAPSACKRELAX_MAXSCALE
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int * gubconssidx
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7237
#define DEFAULT_DETECTCUTOFFBOUND
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4209
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4614
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2166
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17154
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)
SCIP_Real SCIPepsilon(SCIP *scip)
GUBVarstatus
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:687
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
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 SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3351
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2486
SCIP_EXPORT SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17167
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17161
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)
#define CONSHDLR_DESC
Definition: cons_knapsack.c:70
public methods for SCIP parameter handling
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:85
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:63
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1996
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip_prob.c:2892
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:221
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:453
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5184
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
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_cons.c:934
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8328
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3250
public methods for memory management
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:308
static SCIP_DECL_CONSINIT(consInitKnapsack)
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:113
#define DEFAULT_CLQPARTUPDATEFAC
public methods for implications, variable bounds, and cliques
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8288
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1951
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_cons.c:166
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4263
GUBCONSSTATUS * gubconsstatus
#define SCIP_MAXSTRLEN
Definition: def.h:273
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1484
public methods for conflict handler plugins and conflict analysis
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip_var.c:1564
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:72
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5704
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2547
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1601
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1218
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1353
SCIP_EXPORT void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5301
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)
SCIP_EXPORT SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:844
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)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2152
#define LINCONSUPGD_PRIORITY
Definition: cons_knapsack.c:95
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9008
#define DEFAULT_CLIQUEEXTRACTFACTOR
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
SCIP_GUBCONS ** gubconss
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:146
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:419
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_EXPORT void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
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)
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip_cons.c:747
GUBConsstatus
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3131
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:74
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
SCIP_EXPORT SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17192
SCIP_EXPORT SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17957
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1986
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8150
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:216
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1368
#define FALSE
Definition: def.h:73
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)
#define MAX_CLIQUELENGTH
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17510
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:79
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 TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
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 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_lp.c:1428
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:76
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3468
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:524
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8258
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip_prob.c:3579
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:277
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17335
public methods for problem variables
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:521
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_param.c:48
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3690
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_EXPORT SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17986
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2616
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:87
#define SCIPdebugMessage
Definition: pub_message.h:87
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17131
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1233
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:119
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
#define SCIP_LONGINT_MAX
Definition: def.h:149
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:381
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:136
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1258
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
public methods for SCIP variables
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 SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:501
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:84
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
#define DEFAULT_PRESOLUSEHASHING
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4354
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
SCIP_EXPORT void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17866
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:559
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1461
SCIP_EXPORT void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
public methods for numerical tolerances
SCIP_EXPORT SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17454
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:2235
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2837
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
public methods for querying solving statistics
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17372
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define DEFAULT_SEPACARDFREQ
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:69
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3220
public methods for the branch-and-bound tree
static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1531
static SCIP_DECL_CONSPARSE(consParseKnapsack)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
#define DEFAULT_MAXROUNDS
#define DEFAULT_DISAGGREGATION
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3362
SCIP_VAR * w
Definition: circlepacking.c:58
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
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:71
public methods for managing constraints
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10898
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:405
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17012
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(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_lp.c:1337
SCIP_EXPORT void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
enum GUBVarstatus GUBVARSTATUS
SCIP_EXPORT SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17203
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:55
SCIP_EXPORT SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12044
#define SCIPdebugPrintf
Definition: pub_message.h:90
SCIP_EXPORT void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
SCIP_EXPORT SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17478
SCIP_EXPORT int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17940
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
public methods for event handler plugins and event handlers
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2214
#define DEFAULT_PRESOLPAIRWISE
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:596
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1941
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:109
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
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)
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4571
SCIP_EXPORT SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17918
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
SCIP_EXPORT void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:76
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7556
#define NULL
Definition: lpi_spx1.cpp:155
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:187
#define DEFAULT_NEGATEDCLIQUE
SCIP_EXPORT void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
public methods for problem copies
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip_copy.c:646
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:477
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8119
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
#define SCIP_CALL(x)
Definition: def.h:364
SCIP_EXPORT int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17896
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:68
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:632
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1021
SCIP_VAR * h
Definition: circlepacking.c:59
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
GUBVARSTATUS * gubvarsstatus
SCIP_EXPORT const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:697
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
Definition: grphload.c:88
#define KNAPSACKRELAX_MAXDNOM
#define DEFAULT_MAXSEPACUTSROOT
static SCIP_DECL_CONSFREE(consFreeKnapsack)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7456
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)
public methods for constraint handler plugins and constraints
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5088
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1749
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8358
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible)
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17174
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)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_Real SCIPinfinity(SCIP *scip)
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_cons.c:220
public data structures and miscellaneous methods
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4439
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2285
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:638
SCIP_EXPORT void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define SCIP_Bool
Definition: def.h:70
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
SCIP_EXPORT SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17466
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1208
#define MINGAINPERNMINCOMPARISONS
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3013
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
SCIP_EXPORT void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
static SCIP_DECL_CONSPROP(consPropKnapsack)
SCIP_EXPORT SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11984
#define MAXABSVBCOEF
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:80
#define DEFAULT_MAXSEPACUTS
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17672
#define DEFAULT_MAXCARDBOUNDDIST
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
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_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4199
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
#define MAX(x, y)
Definition: tclique_def.h:83
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_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3363
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1308
public methods for LP management
#define DEFAULT_USEGUBS
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8398
#define KNAPSACKRELAX_MAXDELTA
public methods for cuts and aggregation rows
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:98
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:88
#define CONSHDLR_NAME
Definition: cons_knapsack.c:69
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4628
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:88
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8268
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:81
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8255
int SCIPgetNSepaRounds(SCIP *scip)
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_EXPORT SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17233
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:70
Constraint handler for linear constraints in their most general form, .
#define IDX(j, d)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_EXPORT SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18025
int * gubvarsidx
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)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8348
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17718
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define SCIP_MAXTREEDEPTH
Definition: def.h:300
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:95
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_param.c:130
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1979
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
public methods for the LP relaxation, rows and columns
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2132
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3193
SCIP_EXPORT void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17728
methods for sorting joint arrays of various types
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1390
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)
public methods for branching rule plugins and branching
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)
SCIP_VAR ** b
Definition: circlepacking.c:56
static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:221
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
public methods for managing events
general public methods
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:121
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
static SCIP_DECL_CONSLOCK(consLockKnapsack)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
public methods for solutions
SCIP_EXPORT void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8278
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17662
public methods for the probing mode
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
constraint handler for cardinality constraints
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17876
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1641
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
SCIP_EXPORT int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17430
#define DEFAULT_DETECTLOWERBOUND
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4551
public methods for message output
#define HASHSIZE_KNAPSACKCONS
enum GUBConsstatus GUBCONSSTATUS
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17886
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:97
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6902
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10590
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_param.c:74
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3047
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8089
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1252
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8218
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:163
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8109
#define GUBCONSGROWVALUE
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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:89
#define SCIP_INVALID
Definition: def.h:183
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:75
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 CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:82
SCIP_EXPORT SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17972
#define SCIP_Longint
Definition: def.h:148
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8368
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4179
SCIP_EXPORT SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:11244
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1044
SCIP_EXPORT int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17355
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2764
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
SCIP_EXPORT SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:12076
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1721
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3341
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)
public methods for separators
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8595
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
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:9113
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
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
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:429
SCIP_EXPORT int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18014
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1697
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:266
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:9444
#define SCIPABORT()
Definition: def.h:336
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
public methods for global and local (sub)problems
#define MAXCOVERSIZEITERLEWI
SCIP_EXPORT SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17928
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:106
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8308
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17908
#define DEFAULT_UPDATECLIQUEPARTITIONS
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:73
SCIP_EXPORT SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17442
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:62
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:609
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17854
SCIP_EXPORT int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17345
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_lp.c:1399
#define DEFAULT_SIMPLIFYINEQUALITIES
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8338
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4858
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
methods for selecting (weighted) k-medians
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11708
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1283
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3296
memory allocation routines