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-2022 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_nlp.h"
54 #include "scip/scip_numerics.h"
55 #include "scip/scip_param.h"
56 #include "scip/scip_prob.h"
57 #include "scip/scip_probing.h"
58 #include "scip/scip_sol.h"
59 #include "scip/scip_solvingstats.h"
60 #include "scip/scip_tree.h"
61 #include "scip/scip_var.h"
62 #include <ctype.h>
63 #include <string.h>
64 
65 #ifdef WITH_CARDINALITY_UPGRADE
66 #include "scip/cons_cardinality.h"
67 #endif
68 
69 /* constraint handler properties */
70 #define CONSHDLR_NAME "knapsack"
71 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
72 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
73 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
74 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
75 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
76 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
77 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
78  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
79 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
80 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
81 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
82 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
83 
84 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
85 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
86 
87 #define EVENTHDLR_NAME "knapsack"
88 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
89 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
90  | SCIP_EVENTTYPE_UBTIGHTENED \
91  | SCIP_EVENTTYPE_VARFIXED \
92  | SCIP_EVENTTYPE_VARDELETED \
93  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
94 
95 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
96 
97 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
98 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
99 
100 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
101 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
102 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
104 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
105 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
106 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
107 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
108 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
109 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
110  * to best node's dual bound for separating knapsack cuts */
111 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
112 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
113 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
115 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
116 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
118 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
119 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
121 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
122 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
123 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
124  * comparison round */
125 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
126 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
127  * function defining an upper bound and prevent these constraints from
128  * entering the LP */
129 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
130  * function defining a lower bound and prevent these constraints from
131  * entering the LP */
132 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
133 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
135 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
136 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
137 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
138 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
139  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
140 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
141 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
142 #ifdef WITH_CARDINALITY_UPGRADE
143 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
144 #endif
146 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
147 
148 /*
149  * Data structures
150  */
151 
152 /** constraint handler data */
153 struct SCIP_ConshdlrData
154 {
155  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
156  * you have to clear it at the end, exists only in presolving stage */
157  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
158  * you have to clear it at the end, exists only in presolving stage */
159  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
160  * you have to clear it at the end, exists only in presolving stage */
161  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
162  * you have to clear it at the end, exists only in presolving stage */
163  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
164  * you have to clear it at the end, exists only in presolving stage */
165  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
166  * you have to clear it at the end, exists only in presolving stage */
167  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
168  * you have to clear it at the end, exists only in presolving stage */
169  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
170  * you have to clear it at the end, exists only in presolving stage */
171  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
172  * you have to clear it at the end */
173  int ints1size; /**< size of ints1 array */
174  int ints2size; /**< size of ints2 array */
175  int longints1size; /**< size of longints1 array */
176  int longints2size; /**< size of longints2 array */
177  int bools1size; /**< size of bools1 array */
178  int bools2size; /**< size of bools2 array */
179  int bools3size; /**< size of bools3 array */
180  int bools4size; /**< size of bools4 array */
181  int reals1size; /**< size of reals1 array */
182  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
183  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
184  * to best node's dual bound for separating knapsack cuts */
185  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
186  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
187  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
188  int maxsepacuts; /**< maximal number of cuts separated per separation round */
189  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
190  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
191  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
192  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
193  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
194  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
195  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
196  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
197  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
198  * function defining an upper bound and prevent these constraints from
199  * entering the LP */
200  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
201  * function defining a lower bound and prevent these constraints from
202  * entering the LP */
203  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
204  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
205  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
206  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
207 #ifdef WITH_CARDINALITY_UPGRADE
208  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
209  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
210 #endif
211 };
212 
213 
214 /** constraint data for knapsack constraints */
215 struct SCIP_ConsData
216 {
217  SCIP_VAR** vars; /**< variables in knapsack constraint */
218  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
219  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
220  int* cliquepartition; /**< clique indices of the clique partition */
221  int* negcliquepartition; /**< clique indices of the negated clique partition */
222  SCIP_ROW* row; /**< corresponding LP row */
223  SCIP_NLROW* nlrow; /**< corresponding NLP row */
224  int nvars; /**< number of variables in knapsack constraint */
225  int varssize; /**< size of vars, weights, and eventdata arrays */
226  int ncliques; /**< number of cliques in the clique partition */
227  int nnegcliques; /**< number of cliques in the negated clique partition */
228  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
229  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
230  SCIP_Longint capacity; /**< capacity of knapsack */
231  SCIP_Longint weightsum; /**< sum of all weights */
232  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
233  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
234  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
235  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
236  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
237  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
238  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
239  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
240  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
241 };
242 
243 /** event data for bound changes events */
244 struct SCIP_EventData
245 {
246  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
247  SCIP_Longint weight; /**< weight of variable */
248  int filterpos; /**< position of event in variable's event filter */
249 };
250 
251 
252 /** data structure to combine two sorting key values */
253 struct sortkeypair
254 {
255  SCIP_Real key1; /**< first sort key value */
256  SCIP_Real key2; /**< second sort key value */
257 };
258 typedef struct sortkeypair SORTKEYPAIR;
259 
260 /** status of GUB constraint */
261 enum GUBVarstatus
262 {
263  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
264  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
265  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
266  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
267  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
268  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
269 };
270 typedef enum GUBVarstatus GUBVARSTATUS;
272 /** status of variable in GUB constraint */
274 {
275  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
276  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
277  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
278  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
279  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
280  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
281 };
282 typedef enum GUBConsstatus GUBCONSSTATUS;
284 /** data structure of GUB constraints */
286 {
287  int* gubvars; /**< indices of GUB variables in knapsack constraint */
288  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
289  int ngubvars; /**< number of GUB variables */
290  int gubvarssize; /**< size of gubvars array */
291 };
292 typedef struct SCIP_GUBCons SCIP_GUBCONS;
294 /** data structure of a set of GUB constraints */
296 {
297  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
298  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
299  int ngubconss; /**< number of GUB constraints */
300  int nvars; /**< number of variables in knapsack constraint */
301  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
302  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
303 };
304 typedef struct SCIP_GUBSet SCIP_GUBSET;
306 /*
307  * Local methods
308  */
310 /** comparison method for two sorting key pairs */
311 static
312 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
313 {
314  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
315  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
316 
317  if( sortkeypair1->key1 < sortkeypair2->key1 )
318  return -1;
319  else if( sortkeypair1->key1 > sortkeypair2->key1 )
320  return +1;
321  else if( sortkeypair1->key2 < sortkeypair2->key2 )
322  return -1;
323  else if( sortkeypair1->key2 > sortkeypair2->key2 )
324  return +1;
325  else
326  return 0;
327 }
328 
329 /** creates event data */
330 static
332  SCIP* scip, /**< SCIP data structure */
333  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
334  SCIP_CONS* cons, /**< constraint */
335  SCIP_Longint weight /**< weight of variable */
336  )
337 {
338  assert(eventdata != NULL);
340  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
341  (*eventdata)->cons = cons;
342  (*eventdata)->weight = weight;
343 
344  return SCIP_OKAY;
345 }
346 
347 /** frees event data */
348 static
350  SCIP* scip, /**< SCIP data structure */
351  SCIP_EVENTDATA** eventdata /**< pointer to event data */
352  )
353 {
354  assert(eventdata != NULL);
355 
356  SCIPfreeBlockMemory(scip, eventdata);
358  return SCIP_OKAY;
359 }
360 
361 /** sorts items in knapsack with nonincreasing weights */
362 static
363 void sortItems(
364  SCIP_CONSDATA* consdata /**< constraint data */
365  )
366 {
367  assert(consdata != NULL);
368  assert(consdata->nvars == 0 || consdata->vars != NULL);
369  assert(consdata->nvars == 0 || consdata->weights != NULL);
370  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
371  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
372 
373  if( !consdata->sorted )
374  {
375  int pos;
376  int lastcliquenum;
377  int v;
378 
379  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
380  * sorted by first array in non-increasing order via sort template */
382  consdata->weights,
383  (void**)consdata->vars,
384  (void**)consdata->eventdata,
385  consdata->cliquepartition,
386  consdata->negcliquepartition,
387  consdata->nvars);
388 
389  v = consdata->nvars - 1;
390  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
391  while( v >= 0 )
392  {
393  int w = v - 1;
394 
395  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
396  --w;
397 
398  if( v - w > 1 )
399  {
400  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
402  (void**)(&(consdata->vars[w+1])),
403  (void**)(&(consdata->eventdata[w+1])),
404  &(consdata->cliquepartition[w+1]),
405  &(consdata->negcliquepartition[w+1]),
406  SCIPvarComp,
407  v - w);
408  }
409  v = w;
410  }
411 
412  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
413  if( consdata->cliquepartitioned )
414  {
415  lastcliquenum = 0;
416 
417  for( pos = 0; pos < consdata->nvars; ++pos )
418  {
419  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
420  * partition is invalid */
421  if( consdata->cliquepartition[pos] > lastcliquenum )
422  {
423  consdata->cliquepartitioned = FALSE;
424  break;
425  }
426  else if( consdata->cliquepartition[pos] == lastcliquenum )
427  ++lastcliquenum;
428  }
429  }
430  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
431  if( consdata->negcliquepartitioned )
432  {
433  lastcliquenum = 0;
434 
435  for( pos = 0; pos < consdata->nvars; ++pos )
436  {
437  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
438  * partition is invalid */
439  if( consdata->negcliquepartition[pos] > lastcliquenum )
440  {
441  consdata->negcliquepartitioned = FALSE;
442  break;
443  }
444  else if( consdata->negcliquepartition[pos] == lastcliquenum )
445  ++lastcliquenum;
446  }
447  }
448 
449  consdata->sorted = TRUE;
450  }
451 #ifndef NDEBUG
452  {
453  /* check if the weight array is sorted in a non-increasing way */
454  int i;
455  for( i = 0; i < consdata->nvars-1; ++i )
456  assert(consdata->weights[i] >= consdata->weights[i+1]);
457  }
458 #endif
459 }
460 
461 /** calculates a partition of the variables into cliques */
462 static
464  SCIP* scip, /**< SCIP data structure */
465  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
466  SCIP_CONSDATA* consdata, /**< constraint data */
467  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
468  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
469  )
470 {
471  SCIP_Bool ispartitionoutdated;
472  SCIP_Bool isnegpartitionoutdated;
473  assert(consdata != NULL);
474  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
475 
476  /* rerun eventually if number of global cliques increased considerably since last partition */
477  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
478  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
479 
480  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
481  {
482  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
483  consdata->cliquepartitioned = TRUE;
484  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
485  }
486 
487  /* rerun eventually if number of global cliques increased considerably since last negated partition */
488  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
489  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
490 
491  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
492  {
493  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
494  consdata->negcliquepartitioned = TRUE;
495  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
496  }
497  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
498  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
499 
500  return SCIP_OKAY;
501 }
502 
503 /** installs rounding locks for the given variable in the given knapsack constraint */
504 static
506  SCIP* scip, /**< SCIP data structure */
507  SCIP_CONS* cons, /**< knapsack constraint */
508  SCIP_VAR* var /**< variable of constraint entry */
509  )
510 {
511  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
512 
513  return SCIP_OKAY;
514 }
515 
516 /** removes rounding locks for the given variable in the given knapsack constraint */
517 static
519  SCIP* scip, /**< SCIP data structure */
520  SCIP_CONS* cons, /**< knapsack constraint */
521  SCIP_VAR* var /**< variable of constraint entry */
522  )
523 {
524  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
525 
526  return SCIP_OKAY;
527 }
528 
529 /** catches bound change events for variables in knapsack */
530 static
532  SCIP* scip, /**< SCIP data structure */
533  SCIP_CONS* cons, /**< constraint */
534  SCIP_CONSDATA* consdata, /**< constraint data */
535  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
536  )
537 {
538  int i;
540  assert(cons != NULL);
541  assert(consdata != NULL);
542  assert(consdata->nvars == 0 || consdata->vars != NULL);
543  assert(consdata->nvars == 0 || consdata->weights != NULL);
544  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
545 
546  for( i = 0; i < consdata->nvars; i++)
547  {
548  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
549  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
550  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
551  }
552 
553  return SCIP_OKAY;
554 }
555 
556 /** drops bound change events for variables in knapsack */
557 static
559  SCIP* scip, /**< SCIP data structure */
560  SCIP_CONSDATA* consdata, /**< constraint data */
561  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
562  )
563 {
564  int i;
565 
566  assert(consdata != NULL);
567  assert(consdata->nvars == 0 || consdata->vars != NULL);
568  assert(consdata->nvars == 0 || consdata->weights != NULL);
569  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
570 
571  for( i = 0; i < consdata->nvars; i++)
572  {
573  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
574  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
575  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
576  }
577 
578  return SCIP_OKAY;
579 }
580 
581 /** ensures, that vars and vals arrays can store at least num entries */
582 static
584  SCIP* scip, /**< SCIP data structure */
585  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
586  int num, /**< minimum number of entries to store */
587  SCIP_Bool transformed /**< is constraint from transformed problem? */
588  )
589 {
590  assert(consdata != NULL);
591  assert(consdata->nvars <= consdata->varssize);
592 
593  if( num > consdata->varssize )
594  {
595  int newsize;
596 
597  newsize = SCIPcalcMemGrowSize(scip, num);
598  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
599  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
600  if( transformed )
601  {
602  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
603  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
604  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
605  }
606  else
607  {
608  assert(consdata->eventdata == NULL);
609  assert(consdata->cliquepartition == NULL);
610  assert(consdata->negcliquepartition == NULL);
611  }
612  consdata->varssize = newsize;
613  }
614  assert(num <= consdata->varssize);
615 
616  return SCIP_OKAY;
617 }
618 
619 /** updates all weight sums for fixed and unfixed variables */
620 static
621 void updateWeightSums(
622  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
623  SCIP_VAR* var, /**< variable for this weight */
624  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
625  )
626 {
627  assert(consdata != NULL);
628  assert(var != NULL);
630  consdata->weightsum += weightdelta;
631 
632  if( SCIPvarGetLbLocal(var) > 0.5 )
633  consdata->onesweightsum += weightdelta;
634 
635  assert(consdata->weightsum >= 0);
636  assert(consdata->onesweightsum >= 0);
637 }
638 
639 /** creates knapsack constraint data */
640 static
642  SCIP* scip, /**< SCIP data structure */
643  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
644  int nvars, /**< number of variables in knapsack */
645  SCIP_VAR** vars, /**< variables of knapsack */
646  SCIP_Longint* weights, /**< weights of knapsack items */
647  SCIP_Longint capacity /**< capacity of knapsack */
648  )
649 {
650  int v;
651  SCIP_Longint constant;
652 
653  assert(consdata != NULL);
654 
655  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
656 
657  constant = 0L;
658  (*consdata)->vars = NULL;
659  (*consdata)->weights = NULL;
660  (*consdata)->nvars = 0;
661  if( nvars > 0 )
662  {
663  SCIP_VAR** varsbuffer;
664  SCIP_Longint* weightsbuffer;
665  int k;
666 
667  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
668  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
669 
670  k = 0;
671  for( v = 0; v < nvars; ++v )
672  {
673  assert(vars[v] != NULL);
674  assert(SCIPvarIsBinary(vars[v]));
675 
676  /* all weight have to be non negative */
677  assert( weights[v] >= 0 );
678 
679  if( weights[v] > 0 )
680  {
681  /* treat fixed variables as constants if problem compression is enabled */
682  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
683  {
684  /* only if the variable is fixed to 1, we add its weight to the constant */
685  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
686  constant += weights[v];
687  }
688  else
689  {
690  varsbuffer[k] = vars[v];
691  weightsbuffer[k] = weights[v];
692  ++k;
693  }
694  }
695  }
696  assert(k >= 0);
697  assert(constant >= 0);
698 
699  (*consdata)->nvars = k;
700 
701  /* copy the active variables and weights into the constraint data structure */
702  if( k > 0 )
703  {
704  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
705  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
706  }
707 
708  /* free buffer storage */
709  SCIPfreeBufferArray(scip, &weightsbuffer);
710  SCIPfreeBufferArray(scip, &varsbuffer);
711  }
712 
713  (*consdata)->varssize = (*consdata)->nvars;
714  (*consdata)->capacity = capacity - constant;
715  (*consdata)->eventdata = NULL;
716  (*consdata)->cliquepartition = NULL;
717  (*consdata)->negcliquepartition = NULL;
718  (*consdata)->row = NULL;
719  (*consdata)->nlrow = 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)->nlrow != NULL )
781  {
782  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
783  }
784  if( (*consdata)->eventdata != NULL )
785  {
786  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
787  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
788  }
789  if( (*consdata)->negcliquepartition != NULL )
790  {
791  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
792  }
793  if( (*consdata)->cliquepartition != NULL )
794  {
795  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
796  }
797  if( (*consdata)->vars != NULL )
798  {
799  int v;
800 
801  /* release variables */
802  for( v = 0; v < (*consdata)->nvars; v++ )
803  {
804  assert((*consdata)->vars[v] != NULL);
805  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
806  }
807 
808  assert( (*consdata)->weights != NULL );
809  assert( (*consdata)->varssize > 0 );
810  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
811  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
812  }
813 
814  SCIPfreeBlockMemory(scip, consdata);
815 
816  return SCIP_OKAY;
817 }
818 
819 /** changes a single weight in knapsack constraint data */
820 static
821 void consdataChgWeight(
822  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
823  int item, /**< item number */
824  SCIP_Longint newweight /**< new weight of item */
825  )
826 {
827  SCIP_Longint oldweight;
828  SCIP_Longint weightdiff;
830  assert(consdata != NULL);
831  assert(0 <= item && item < consdata->nvars);
832 
833  oldweight = consdata->weights[item];
834  weightdiff = newweight - oldweight;
835  consdata->weights[item] = newweight;
836 
837  /* update weight sums for all and fixed variables */
838  updateWeightSums(consdata, consdata->vars[item], weightdiff);
839 
840  if( consdata->eventdata != NULL )
841  {
842  assert(consdata->eventdata[item] != NULL);
843  assert(consdata->eventdata[item]->weight == oldweight);
844  consdata->eventdata[item]->weight = newweight;
845  }
846 
847  consdata->presolvedtiming = 0;
848  consdata->sorted = FALSE;
849 
850  /* recalculate cliques extraction after a weight was increased */
851  if( oldweight < newweight )
852  {
853  consdata->cliquesadded = FALSE;
854  }
855 }
856 
857 /** creates LP row corresponding to knapsack constraint */
858 static
860  SCIP* scip, /**< SCIP data structure */
861  SCIP_CONS* cons /**< knapsack constraint */
862  )
863 {
864  SCIP_CONSDATA* consdata;
865  int i;
866 
867  consdata = SCIPconsGetData(cons);
868  assert(consdata != NULL);
869  assert(consdata->row == NULL);
870 
871  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
872  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
874 
875  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
876  for( i = 0; i < consdata->nvars; ++i )
877  {
878  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
879  }
880  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
881 
882  return SCIP_OKAY;
883 }
884 
885 /** adds linear relaxation of knapsack constraint to the LP */
886 static
888  SCIP* scip, /**< SCIP data structure */
889  SCIP_CONS* cons, /**< knapsack constraint */
890  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
891  )
892 {
893  SCIP_CONSDATA* consdata;
894 
895  assert( cutoff != NULL );
896  *cutoff = FALSE;
897 
898  consdata = SCIPconsGetData(cons);
899  assert(consdata != NULL);
900 
901  if( consdata->row == NULL )
902  {
903  SCIP_CALL( createRelaxation(scip, cons) );
904  }
905  assert(consdata->row != NULL);
906 
907  /* insert LP row as cut */
908  if( !SCIProwIsInLP(consdata->row) )
909  {
910  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
911  SCIPconsGetName(cons), consdata->capacity);
912  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
913  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
914  }
915 
916  return SCIP_OKAY;
917 }
918 
919 /** adds knapsack constraint as row to the NLP, if not added yet */
920 static
922  SCIP* scip, /**< SCIP data structure */
923  SCIP_CONS* cons /**< knapsack constraint */
924  )
925 {
926  SCIP_CONSDATA* consdata;
927 
928  assert(SCIPisNLPConstructed(scip));
930  /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
931  if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
932  return SCIP_OKAY;
933 
934  consdata = SCIPconsGetData(cons);
935  assert(consdata != NULL);
936 
937  if( consdata->nlrow == NULL )
938  {
939  SCIP_Real* coefs;
940  int i;
941 
942  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
943  for( i = 0; i < consdata->nvars; ++i )
944  coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
945 
946  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
947  consdata->nvars, consdata->vars, coefs, NULL,
948  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
949 
950  assert(consdata->nlrow != NULL);
951 
952  SCIPfreeBufferArray(scip, &coefs);
953  }
954 
955  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
956  {
957  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
958  }
959 
960  return SCIP_OKAY;
961 }
962 
963 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
964 static
966  SCIP* scip, /**< SCIP data structure */
967  SCIP_CONS* cons, /**< constraint to check */
968  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
969  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
970  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
971  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
972  )
973 {
974  SCIP_CONSDATA* consdata;
975 
976  assert(violated != NULL);
977 
978  consdata = SCIPconsGetData(cons);
979  assert(consdata != NULL);
980 
981  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
982  SCIPconsGetName(cons), (void*)sol, checklprows);
983 
984  *violated = FALSE;
985 
986  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
987  {
988  SCIP_Real sum;
989  SCIP_Longint integralsum;
990  SCIP_Bool ishuge;
991  SCIP_Real absviol;
992  SCIP_Real relviol;
993  int v;
994 
995  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
996  * enforcement
997  */
998  if( sol == NULL )
999  {
1000  SCIP_CALL( SCIPincConsAge(scip, cons) );
1001  }
1002 
1003  sum = 0.0;
1004  integralsum = 0;
1005  /* we perform a more exact comparison if the capacity does not exceed the huge value */
1006  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1007  {
1008  ishuge = TRUE;
1009 
1010  /* sum over all weight times the corresponding solution value */
1011  for( v = consdata->nvars - 1; v >= 0; --v )
1012  {
1013  assert(SCIPvarIsBinary(consdata->vars[v]));
1014  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1015  }
1016  }
1017  else
1018  {
1019  ishuge = FALSE;
1020 
1021  /* sum over all weight for which the variable has a solution value of 1 in feastol */
1022  for( v = consdata->nvars - 1; v >= 0; --v )
1023  {
1024  assert(SCIPvarIsBinary(consdata->vars[v]));
1025 
1026  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1027  integralsum += consdata->weights[v];
1028  }
1029  }
1030 
1031  /* calculate constraint violation and update it in solution */
1032  absviol = ishuge ? sum : (SCIP_Real)integralsum;
1033  absviol -= consdata->capacity;
1034  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1035  if( sol != NULL )
1036  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1037 
1038  if( SCIPisFeasPositive(scip, absviol) )
1039  {
1040  *violated = TRUE;
1041 
1042  /* only reset constraint age if we are in enforcement */
1043  if( sol == NULL )
1044  {
1045  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1046  }
1047 
1048  if( printreason )
1049  {
1050  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1051 
1052  SCIPinfoMessage(scip, NULL, ";\n");
1053  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1054  }
1055  }
1056  }
1057 
1058  return SCIP_OKAY;
1059 }
1060 
1061 /* IDX computes the integer index for the optimal solution array */
1062 #define IDX(j,d) ((j)*(intcap)+(d))
1063 
1064 /** solves knapsack problem in maximization form exactly using dynamic programming;
1065  * if needed, one can provide arrays to store all selected items and all not selected items
1066  *
1067  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1068  *
1069  * @note the algorithm will first compute a greedy solution and terminate
1070  * if the greedy solution is proven to be optimal.
1071  * The dynamic programming algorithm runs with a time and space complexity
1072  * of O(nitems * capacity).
1073  *
1074  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1075  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1076  * to be checked whether they are faster and whether they can reconstruct the solution.
1077  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1078  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1079  * This could be implemented, however, it would be technically a bit cumbersome,
1080  * since one needs the greedy solution and the LP-value for this.
1081  * This is currently only available after the redundant items have already been sorted out.
1082  */
1084  SCIP* scip, /**< SCIP data structure */
1085  int nitems, /**< number of available items */
1086  SCIP_Longint* weights, /**< item weights */
1087  SCIP_Real* profits, /**< item profits */
1088  SCIP_Longint capacity, /**< capacity of knapsack */
1089  int* items, /**< item numbers */
1090  int* solitems, /**< array to store items in solution, or NULL */
1091  int* nonsolitems, /**< array to store items not in solution, or NULL */
1092  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1093  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1094  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1095  SCIP_Bool* success /**< pointer to store if an error occured during solving
1096  * (normally a memory problem) */
1097  )
1098 {
1099  SCIP_RETCODE retcode;
1100  SCIP_Real* tempsort;
1101  SCIP_Real* optvalues;
1102  int intcap;
1103  int d;
1104  int j;
1105  int greedymedianpos;
1106  SCIP_Longint weightsum;
1107  int* myitems;
1108  SCIP_Longint* myweights;
1109  SCIP_Real* realweights;
1110  int* allcurrminweight;
1111  SCIP_Real* myprofits;
1112  int nmyitems;
1113  SCIP_Longint gcd;
1114  SCIP_Longint minweight;
1115  SCIP_Longint maxweight;
1116  int currminweight;
1117  SCIP_Longint greedysolweight;
1118  SCIP_Real greedysolvalue;
1119  SCIP_Real greedyupperbound;
1120  SCIP_Bool eqweights;
1121  SCIP_Bool intprofits;
1122 
1123  assert(weights != NULL);
1124  assert(profits != NULL);
1125  assert(capacity >= 0);
1126  assert(items != NULL);
1127  assert(nitems >= 0);
1128  assert(success != NULL);
1129 
1130  *success = TRUE;
1131 
1132 #ifndef NDEBUG
1133  for( j = nitems - 1; j >= 0; --j )
1134  assert(weights[j] >= 0);
1135 #endif
1136 
1137  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1138 
1139  /* initializing solution value */
1140  if( solval != NULL )
1141  *solval = 0.0;
1142 
1143  /* init solution information */
1144  if( solitems != NULL )
1145  {
1146  assert(items != NULL);
1147  assert(nsolitems != NULL);
1148  assert(nonsolitems != NULL);
1149  assert(nnonsolitems != NULL);
1150 
1151  *nnonsolitems = 0;
1152  *nsolitems = 0;
1153  }
1154 
1155  /* allocate temporary memory */
1156  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1157  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1158  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1159  nmyitems = 0;
1160  weightsum = 0;
1161  minweight = SCIP_LONGINT_MAX;
1162  maxweight = 0;
1163 
1164  /* remove unnecessary items */
1165  for( j = 0; j < nitems; ++j )
1166  {
1167  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1168 
1169  /* item does not fit */
1170  if( weights[j] > capacity )
1171  {
1172  if( solitems != NULL )
1173  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1174  }
1175  /* item is not profitable */
1176  else if( profits[j] <= 0.0 )
1177  {
1178  if( solitems != NULL )
1179  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1180  }
1181  /* item always fits */
1182  else if( weights[j] == 0 )
1183  {
1184  if( solitems != NULL )
1185  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1186 
1187  if( solval != NULL )
1188  *solval += profits[j];
1189  }
1190  /* all important items */
1191  else
1192  {
1193  myweights[nmyitems] = weights[j];
1194  myprofits[nmyitems] = profits[j];
1195  myitems[nmyitems] = items[j];
1196 
1197  /* remember smallest item */
1198  if( myweights[nmyitems] < minweight )
1199  minweight = myweights[nmyitems];
1200 
1201  /* remember bigest item */
1202  if( myweights[nmyitems] > maxweight )
1203  maxweight = myweights[nmyitems];
1204 
1205  weightsum += myweights[nmyitems];
1206  ++nmyitems;
1207  }
1208  }
1209 
1210  intprofits = TRUE;
1211  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1212  for( j = 0; j < nmyitems && intprofits; ++j )
1213  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1214 
1215  /* if no item is left then goto end */
1216  if( nmyitems == 0 )
1217  {
1218  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1219 
1220  goto TERMINATE;
1221  }
1222 
1223  /* if all items fit, we also do not need to do the expensive stuff later on */
1224  if( weightsum > 0 && weightsum <= capacity )
1225  {
1226  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1227 
1228  for( j = nmyitems - 1; j >= 0; --j )
1229  {
1230  if( solitems != NULL )
1231  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1232 
1233  if( solval != NULL )
1234  *solval += myprofits[j];
1235  }
1236 
1237  goto TERMINATE;
1238  }
1239 
1240  assert(0 < minweight && minweight <= capacity );
1241  assert(0 < maxweight && maxweight <= capacity);
1242 
1243  /* make weights relatively prime */
1244  eqweights = TRUE;
1245  if( maxweight > 1 )
1246  {
1247  /* determine greatest common divisor */
1248  gcd = myweights[nmyitems - 1];
1249  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1250  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1251 
1252  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1253 
1254  /* divide by greatest common divisor */
1255  if( gcd > 1 )
1256  {
1257  for( j = nmyitems - 1; j >= 0; --j )
1258  {
1259  myweights[j] /= gcd;
1260  eqweights = eqweights && (myweights[j] == 1);
1261  }
1262  capacity /= gcd;
1263  minweight /= gcd;
1264  }
1265  else
1266  eqweights = FALSE;
1267  }
1268  assert(minweight <= capacity);
1269 
1270  /* if only one item fits, then take the best */
1271  if( minweight > capacity / 2 )
1272  {
1273  int p;
1274 
1275  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1276 
1277  p = nmyitems - 1;
1278 
1279  /* find best item */
1280  for( j = nmyitems - 2; j >= 0; --j )
1281  {
1282  if( myprofits[j] > myprofits[p] )
1283  p = j;
1284  }
1285 
1286  /* update solution information */
1287  if( solitems != NULL )
1288  {
1289  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1290 
1291  solitems[(*nsolitems)++] = myitems[p];
1292  for( j = nmyitems - 1; j >= 0; --j )
1293  {
1294  if( j != p )
1295  nonsolitems[(*nnonsolitems)++] = myitems[j];
1296  }
1297  }
1298  /* update solution value */
1299  if( solval != NULL )
1300  *solval += myprofits[p];
1301 
1302  goto TERMINATE;
1303  }
1304 
1305  /* if all items have the same weight, then take the best */
1306  if( eqweights )
1307  {
1308  SCIP_Real addval = 0.0;
1309 
1310  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1311 
1312  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1313 
1314  /* update solution information */
1315  if( solitems != NULL || solval != NULL )
1316  {
1317  SCIP_Longint i;
1318 
1319  /* if all items would fit we had handled this case before */
1320  assert((SCIP_Longint) nmyitems > capacity);
1321  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1322 
1323  /* take the first best items into the solution */
1324  for( i = capacity - 1; i >= 0; --i )
1325  {
1326  if( solitems != NULL )
1327  solitems[(*nsolitems)++] = myitems[i];
1328  addval += myprofits[i];
1329  }
1330 
1331  if( solitems != NULL )
1332  {
1333  /* the rest are not in the solution */
1334  for( i = nmyitems - 1; i >= capacity; --i )
1335  nonsolitems[(*nnonsolitems)++] = myitems[i];
1336  }
1337  }
1338  /* update solution value */
1339  if( solval != NULL )
1340  {
1341  assert(addval > 0.0);
1342  *solval += addval;
1343  }
1344 
1345  goto TERMINATE;
1346  }
1347 
1348  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1349 
1350  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1351  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1352  */
1353  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1354  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1355 
1356  for( j = 0; j < nmyitems; ++j )
1357  {
1358  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1359  realweights[j] = (SCIP_Real)myweights[j];
1360  }
1361 
1362  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1363  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1364 
1365  SCIPfreeBufferArray(scip, &realweights);
1366  SCIPfreeBufferArray(scip, &tempsort);
1367 
1368  /* initialize values for greedy solution information */
1369  greedysolweight = 0;
1370  greedysolvalue = 0.0;
1371 
1372  /* determine greedy solution */
1373  for( j = 0; j < greedymedianpos; ++j )
1374  {
1375  assert(myweights[j] <= capacity);
1376 
1377  /* update greedy solution weight and value */
1378  greedysolweight += myweights[j];
1379  greedysolvalue += myprofits[j];
1380  }
1381 
1382  assert(0 < greedysolweight && greedysolweight <= capacity);
1383  assert(greedysolvalue > 0.0);
1384 
1385  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1386  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1387  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1388  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1389  if( intprofits )
1390  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1391  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1392  {
1393  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1394 
1395  /* update solution information */
1396  if( solitems != NULL )
1397  {
1398  int l;
1399 
1400  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1401 
1402  /* collect items */
1403  for( l = 0; l < j; ++l )
1404  solitems[(*nsolitems)++] = myitems[l];
1405  for ( ; l < nmyitems; ++l )
1406  nonsolitems[(*nnonsolitems)++] = myitems[l];
1407  }
1408  /* update solution value */
1409  if( solval != NULL )
1410  {
1411  assert(greedysolvalue > 0.0);
1412  *solval += greedysolvalue;
1413  }
1414 
1415  goto TERMINATE;
1416  }
1417 
1418  /* in the following table we do not need the first minweight columns */
1419  capacity -= (minweight - 1);
1420 
1421  /* we can only handle integers */
1422  if( capacity >= INT_MAX )
1423  {
1424  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1425 
1426  *success = FALSE;
1427  goto TERMINATE;
1428  }
1429  assert(capacity < INT_MAX);
1430 
1431  intcap = (int)capacity;
1432  assert(intcap >= 0);
1433  assert(nmyitems > 0);
1434  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1435 
1436  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1437  * computing the size for the allocation
1438  */
1439  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*/
1440  {
1441  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1442 
1443  *success = FALSE;
1444  goto TERMINATE;
1445  }
1446 
1447  /* allocate temporary memory and check for memory exceedance */
1448  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1449  if( retcode == SCIP_NOMEMORY )
1450  {
1451  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1452 
1453  *success = FALSE;
1454  goto TERMINATE;
1455  }
1456  else
1457  {
1458  SCIP_CALL( retcode );
1459  }
1460 
1461  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1462 
1463  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1464  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1465  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1466  * 'nmyitem' values
1467  */
1468  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1469  assert(myweights[0] - minweight < INT_MAX);
1470  currminweight = (int) (myweights[0] - minweight);
1471  allcurrminweight[0] = currminweight;
1472 
1473  /* fills first row of dynamic programming table with optimal values */
1474  for( d = currminweight; d < intcap; ++d )
1475  optvalues[d] = myprofits[0];
1476 
1477  /* fills dynamic programming table with optimal values */
1478  for( j = 1; j < nmyitems; ++j )
1479  {
1480  int intweight;
1481 
1482  /* compute important part of weight, which will be represented in the table */
1483  intweight = (int)(myweights[j] - minweight);
1484  assert(0 <= intweight && intweight < intcap);
1485 
1486  /* copy all nonzeros from row above */
1487  for( d = currminweight; d < intweight && d < intcap; ++d )
1488  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1489 
1490  /* update corresponding row */
1491  for( d = intweight; d < intcap; ++d )
1492  {
1493  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1494  if( d < currminweight )
1495  optvalues[IDX(j,d)] = myprofits[j];
1496  else
1497  {
1498  SCIP_Real sumprofit;
1499 
1500  if( d - myweights[j] < currminweight )
1501  sumprofit = myprofits[j];
1502  else
1503  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1504 
1505  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1506  }
1507  }
1508 
1509  /* update currminweight */
1510  if( intweight < currminweight )
1511  currminweight = intweight;
1512 
1513  allcurrminweight[j] = currminweight;
1514  }
1515 
1516  /* update optimal solution by following the table */
1517  if( solitems != NULL )
1518  {
1519  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1520  d = intcap - 1;
1521 
1522  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1523 
1524  /* insert all items in (non-) solution vector */
1525  for( j = nmyitems - 1; j > 0; --j )
1526  {
1527  /* if the following condition holds this means all remaining items does not fit anymore */
1528  if( d < allcurrminweight[j] )
1529  {
1530  /* we cannot have exceeded our capacity */
1531  assert((SCIP_Longint) d >= -minweight);
1532  break;
1533  }
1534 
1535  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1536  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1537  {
1538  solitems[(*nsolitems)++] = myitems[j];
1539 
1540  /* check that we do not have an underflow */
1541  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1542  d = (int)(d - myweights[j]);
1543  }
1544  /* collect non-solution items */
1545  else
1546  nonsolitems[(*nnonsolitems)++] = myitems[j];
1547  }
1548 
1549  /* insert remaining items */
1550  if( d >= allcurrminweight[j] )
1551  {
1552  assert(j == 0);
1553  solitems[(*nsolitems)++] = myitems[j];
1554  }
1555  else
1556  {
1557  assert(j >= 0);
1558  assert(d < allcurrminweight[j]);
1559 
1560  for( ; j >= 0; --j )
1561  nonsolitems[(*nnonsolitems)++] = myitems[j];
1562  }
1563 
1564  assert(*nsolitems + *nnonsolitems == nitems);
1565  }
1566 
1567  /* update solution value */
1568  if( solval != NULL )
1569  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1570  SCIPfreeBufferArray(scip, &allcurrminweight);
1571 
1572  /* free all temporary memory */
1573  SCIPfreeBufferArray(scip, &optvalues);
1574 
1575  TERMINATE:
1576  SCIPfreeBufferArray(scip, &myitems);
1577  SCIPfreeBufferArray(scip, &myprofits);
1578  SCIPfreeBufferArray(scip, &myweights);
1579 
1580  return SCIP_OKAY;
1581 }
1582 
1583 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1584  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1585  * selected items
1586  */
1588  SCIP* scip, /**< SCIP data structure */
1589  int nitems, /**< number of available items */
1590  SCIP_Longint* weights, /**< item weights */
1591  SCIP_Real* profits, /**< item profits */
1592  SCIP_Longint capacity, /**< capacity of knapsack */
1593  int* items, /**< item numbers */
1594  int* solitems, /**< array to store items in solution, or NULL */
1595  int* nonsolitems, /**< array to store items not in solution, or NULL */
1596  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1597  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1598  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1599  )
1600 {
1601  SCIP_Real* tempsort;
1602  SCIP_Longint solitemsweight;
1603  SCIP_Real* realweights;
1604  int j;
1605  int criticalindex;
1606 
1607  assert(weights != NULL);
1608  assert(profits != NULL);
1609  assert(capacity >= 0);
1610  assert(items != NULL);
1611  assert(nitems >= 0);
1612 
1613  if( solitems != NULL )
1614  {
1615  *nsolitems = 0;
1616  *nnonsolitems = 0;
1617  }
1618  if( solval != NULL )
1619  *solval = 0.0;
1620 
1621  /* initialize data for median search */
1622  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1623  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1624  for( j = nitems - 1; j >= 0; --j )
1625  {
1626  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1627  realweights[j] = (SCIP_Real)weights[j];
1628  }
1629 
1630  /* partially sort indices such that all elements that are larger than the break item appear first */
1631  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1632 
1633  /* selects items as long as they fit into the knapsack */
1634  solitemsweight = 0;
1635  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1636  {
1637  if( solitems != NULL )
1638  solitems[(*nsolitems)++] = items[j];
1639 
1640  if( solval != NULL )
1641  (*solval) += profits[j];
1642  solitemsweight += weights[j];
1643  }
1644  if ( solitems != NULL )
1645  {
1646  for( ; j < nitems; j++ )
1647  nonsolitems[(*nnonsolitems)++] = items[j];
1648  }
1649 
1650  SCIPfreeBufferArray(scip, &realweights);
1651  SCIPfreeBufferArray(scip, &tempsort);
1652 
1653  return SCIP_OKAY;
1654 }
1655 
1656 #ifdef SCIP_DEBUG
1657 /** prints all nontrivial GUB constraints and their LP solution values */
1658 static
1659 void GUBsetPrint(
1660  SCIP* scip, /**< SCIP data structure */
1661  SCIP_GUBSET* gubset, /**< GUB set data structure */
1662  SCIP_VAR** vars, /**< variables in knapsack constraint */
1663  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1664  )
1665 {
1666  int nnontrivialgubconss;
1667  int c;
1668 
1669  nnontrivialgubconss = 0;
1670 
1671  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1672 
1673  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1674  for( c = 0; c < gubset->ngubconss; c++ )
1675  {
1676  SCIP_Real gubsolval;
1677 
1678  assert(gubset->gubconss[c]->ngubvars >= 0);
1679 
1680  /* nontrivial GUB */
1681  if( gubset->gubconss[c]->ngubvars > 1 )
1682  {
1683  int v;
1684 
1685  gubsolval = 0.0;
1686  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1687 
1688  /* print GUB var */
1689  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1690  {
1691  int currentvar;
1692 
1693  currentvar = gubset->gubconss[c]->gubvars[v];
1694  if( solvals != NULL )
1695  {
1696  gubsolval += solvals[currentvar];
1697  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1698  }
1699  else
1700  {
1701  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1702  }
1703  }
1704 
1705  /* check whether LP solution satisfies the GUB constraint */
1706  if( solvals != NULL )
1707  {
1708  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1709  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1710  }
1711  else
1712  {
1713  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1714  }
1715  nnontrivialgubconss++;
1716  }
1717  }
1718 
1719  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1720 }
1721 #endif
1722 
1723 /** creates an empty GUB constraint */
1724 static
1726  SCIP* scip, /**< SCIP data structure */
1727  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1728  )
1729 {
1730  assert(scip != NULL);
1731  assert(gubcons != NULL);
1732 
1733  /* allocate memory for GUB constraint data structures */
1734  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1735  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1736  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1737  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1738 
1739  (*gubcons)->ngubvars = 0;
1740 
1741  return SCIP_OKAY;
1742 }
1743 
1744 /** frees GUB constraint */
1745 static
1746 void GUBconsFree(
1747  SCIP* scip, /**< SCIP data structure */
1748  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1749  )
1750 {
1751  assert(scip != NULL);
1752  assert(gubcons != NULL);
1753  assert((*gubcons)->gubvars != NULL);
1754  assert((*gubcons)->gubvarsstatus != NULL);
1755 
1756  /* free allocated memory */
1757  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1758  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1759  SCIPfreeBuffer(scip, gubcons);
1760 }
1761 
1762 /** adds variable to given GUB constraint */
1763 static
1765  SCIP* scip, /**< SCIP data structure */
1766  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1767  int var /**< index of given variable in knapsack constraint */
1768  )
1769 {
1770  assert(scip != NULL);
1771  assert(gubcons != NULL);
1772  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1773  assert(gubcons->gubvars != NULL);
1774  assert(gubcons->gubvarsstatus != NULL);
1775  assert(var >= 0);
1776 
1777  /* add variable to GUB constraint */
1778  gubcons->gubvars[gubcons->ngubvars] = var;
1779  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1780  gubcons->ngubvars++;
1781 
1782  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1783  if( gubcons->ngubvars == gubcons->gubvarssize )
1784  {
1785  int newlen;
1786 
1787  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1788  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1789  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1790 
1791  gubcons->gubvarssize = newlen;
1792  }
1793 
1794  return SCIP_OKAY;
1795 }
1796 
1797 /** deletes variable from its current GUB constraint */
1798 static
1800  SCIP* scip, /**< SCIP data structure */
1801  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1802  int var, /**< index of given variable in knapsack constraint */
1803  int gubvarsidx /**< index of the variable in its current GUB constraint */
1804  )
1805 {
1806  assert(scip != NULL);
1807  assert(gubcons != NULL);
1808  assert(var >= 0);
1809  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1810  assert(gubcons->ngubvars >= gubvarsidx+1);
1811  assert(gubcons->gubvars[gubvarsidx] == var);
1812 
1813  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1814  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1815  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1816  gubcons->ngubvars--;
1817 
1818  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1819  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1820  {
1821  int newlen;
1822 
1823  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1824 
1825  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1826  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1827 
1828  gubcons->gubvarssize = newlen;
1829  }
1830 
1831  return SCIP_OKAY;
1832 }
1833 
1834 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1835 static
1837  SCIP* scip, /**< SCIP data structure */
1838  SCIP_GUBSET* gubset, /**< GUB set data structure */
1839  SCIP_VAR** vars, /**< variables in knapsack constraint */
1840  int var, /**< index of given variable in knapsack constraint */
1841  int oldgubcons, /**< index of old GUB constraint of given variable */
1842  int newgubcons /**< index of new GUB constraint of given variable */
1843  )
1845  int oldgubvaridx;
1846  int replacevar;
1847  int j;
1848 
1849  assert(scip != NULL);
1850  assert(gubset != NULL);
1851  assert(var >= 0);
1852  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1853  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1854  assert(oldgubcons != newgubcons);
1855  assert(gubset->gubconssidx[var] == oldgubcons);
1856  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1857  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1858 
1859  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1860 
1861  oldgubvaridx = gubset->gubvarsidx[var];
1862 
1863  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1864  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1865 
1866  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1867  * replacement variable is given by old position of the deleted variable
1868  */
1869  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1870  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1871  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1872 
1873  /* add variable to the end of new GUB constraint */
1874  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1875  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1876 
1877  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1878  gubset->gubconssidx[var] = newgubcons;
1879  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1880 
1881  /* delete old GUB constraint if it became empty */
1882  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1883  {
1884  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1885 #ifdef SCIP_DEBUG
1886  GUBsetPrint(scip, gubset, vars, NULL);
1887 #endif
1888 
1889  /* free old GUB constraint */
1890  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1891 
1892  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1893  if( oldgubcons != gubset->ngubconss-1 )
1894  {
1895  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1896  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1897 
1898  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1899  * replacement GUB is given by old position of the deleted GUB
1900  */
1901  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1902  {
1903  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1904  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1905  }
1906  }
1907 
1908  /* update number of GUB constraints */
1909  gubset->ngubconss--;
1910 
1911  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1912  * (because it was at the end of the GUB constraint array)
1913  */
1914  assert(gubset->gubconssidx[var] == newgubcons
1915  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1916  }
1917 #ifndef NDEBUG
1918  else
1919  assert(gubset->gubconssidx[var] == newgubcons);
1920 #endif
1921 
1922  return SCIP_OKAY;
1923 }
1924 
1925 /** swaps two variables in the same GUB constraint */
1926 static
1927 void GUBsetSwapVars(
1928  SCIP* scip, /**< SCIP data structure */
1929  SCIP_GUBSET* gubset, /**< GUB set data structure */
1930  int var1, /**< first variable to be swapped */
1931  int var2 /**< second variable to be swapped */
1932  )
1933 {
1934  int gubcons;
1935  int var1idx;
1936  GUBVARSTATUS var1status;
1937  int var2idx;
1938  GUBVARSTATUS var2status;
1939 
1940  assert(scip != NULL);
1941  assert(gubset != NULL);
1942 
1943  gubcons = gubset->gubconssidx[var1];
1944  assert(gubcons == gubset->gubconssidx[var2]);
1945 
1946  /* nothing to be done if both variables are the same */
1947  if( var1 == var2 )
1948  return;
1949 
1950  /* swap index and status of variables in GUB constraint */
1951  var1idx = gubset->gubvarsidx[var1];
1952  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1953  var2idx = gubset->gubvarsidx[var2];
1954  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1955 
1956  gubset->gubvarsidx[var1] = var2idx;
1957  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1958  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1959 
1960  gubset->gubvarsidx[var2] = var1idx;
1961  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1962  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1963 }
1964 
1965 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1966 static
1968  SCIP* scip, /**< SCIP data structure */
1969  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1970  int nvars, /**< number of variables in the knapsack constraint */
1971  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1972  SCIP_Longint capacity /**< capacity of knapsack */
1973  )
1974 {
1975  int i;
1976 
1977  assert(scip != NULL);
1978  assert(gubset != NULL);
1979  assert(nvars > 0);
1980  assert(weights != NULL);
1981  assert(capacity >= 0);
1982 
1983  /* allocate memory for GUB set data structures */
1984  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1985  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1986  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1987  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1988  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1989  (*gubset)->ngubconss = nvars;
1990  (*gubset)->nvars = nvars;
1991 
1992  /* initialize the set of GUB constraints */
1993  for( i = 0; i < nvars; i++ )
1994  {
1995  /* assign each variable to a new (trivial) GUB constraint */
1996  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1997  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1998 
1999  /* set status of GUB constraint to initial */
2000  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2001 
2002  (*gubset)->gubconssidx[i] = i;
2003  (*gubset)->gubvarsidx[i] = 0;
2004  assert((*gubset)->gubconss[i]->ngubvars == 1);
2005 
2006  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2007  if( weights[i] > capacity )
2008  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2009  }
2010 
2011  return SCIP_OKAY;
2012 }
2013 
2014 /** frees GUB set data structure */
2015 static
2016 void GUBsetFree(
2017  SCIP* scip, /**< SCIP data structure */
2018  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2019  )
2020 {
2021  int i;
2022 
2023  assert(scip != NULL);
2024  assert(gubset != NULL);
2025  assert((*gubset)->gubconss != NULL);
2026  assert((*gubset)->gubconsstatus != NULL);
2027  assert((*gubset)->gubconssidx != NULL);
2028  assert((*gubset)->gubvarsidx != NULL);
2029 
2030  /* free all GUB constraints */
2031  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2032  {
2033  assert((*gubset)->gubconss[i] != NULL);
2034  GUBconsFree(scip, &(*gubset)->gubconss[i]);
2035  }
2036 
2037  /* free allocated memory */
2038  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2039  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2040  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2041  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2042  SCIPfreeBuffer(scip, gubset);
2043 }
2044 
2045 #ifndef NDEBUG
2046 /** checks whether GUB set data structure is consistent */
2047 static
2049  SCIP* scip, /**< SCIP data structure */
2050  SCIP_GUBSET* gubset, /**< GUB set data structure */
2051  SCIP_VAR** vars /**< variables in the knapsack constraint */
2052  )
2053 {
2054  int i;
2055  int gubconsidx;
2056  int gubvaridx;
2057  SCIP_VAR* var1;
2058  SCIP_VAR* var2;
2059  SCIP_Bool var1negated;
2060  SCIP_Bool var2negated;
2061 
2062  assert(scip != NULL);
2063  assert(gubset != NULL);
2064 
2065  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2066 
2067  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2068  for( i = 0; i < gubset->nvars; i++ )
2069  {
2070  gubconsidx = gubset->gubconssidx[i];
2071  gubvaridx = gubset->gubvarsidx[i];
2072 
2073  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2074  {
2075  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2076  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2077  }
2078  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2079  }
2080 
2081  /* checks for each GUB whether all pairs of its variables have a common clique */
2082  for( i = 0; i < gubset->ngubconss; i++ )
2083  {
2084  int j;
2085 
2086  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2087  {
2088  int k;
2089 
2090  /* get corresponding active problem variable */
2091  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2092  var1negated = FALSE;
2093  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2094 
2095  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2096  {
2097  /* get corresponding active problem variable */
2098  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2099  var2negated = FALSE;
2100  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2101 
2102  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2103  {
2104  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2105  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2106  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2107  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2108  SCIPvarGetName(var1), k,
2109  SCIPvarGetName(var2));
2110  }
2111 
2112  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2113  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2114  }
2115  }
2116  }
2117  SCIPdebugMsg(scip, " --> successful\n");
2118 
2119  return SCIP_OKAY;
2120 }
2121 #endif
2122 
2123 /** calculates a partition of the given set of binary variables into cliques;
2124  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2125  * were assigned to the same clique;
2126  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2127  * the preceding variables was assigned to clique i-1;
2128  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2129  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2130  */
2131 
2132 static
2134  SCIP*const scip, /**< SCIP data structure */
2135  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2136  int const nvars, /**< number of variables in the clique */
2137  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2138  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2139  SCIP_Real* solvals /**< solution values of all given binary variables */
2140  )
2142  SCIP_VAR** tmpvars;
2143  SCIP_VAR** cliquevars;
2144  SCIP_Bool* cliquevalues;
2145  SCIP_Bool* tmpvalues;
2146  int* varseq;
2147  int* sortkeys;
2148  int ncliquevars;
2149  int maxncliquevarscomp;
2150  int nignorevars;
2151  int nvarsused;
2152  int i;
2153 
2154  assert(scip != NULL);
2155  assert(nvars == 0 || vars != NULL);
2156  assert(nvars == 0 || cliquepartition != NULL);
2157  assert(ncliques != NULL);
2158 
2159  if( nvars == 0 )
2160  {
2161  *ncliques = 0;
2162  return SCIP_OKAY;
2163  }
2164 
2165  /* allocate temporary memory for storing the variables of the current clique */
2166  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2167  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2168  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2169  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2170  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2171  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2172 
2173  /* initialize the cliquepartition array with -1 */
2174  /* initialize the tmpvalues array */
2175  for( i = nvars - 1; i >= 0; --i )
2176  {
2177  tmpvalues[i] = TRUE;
2178  cliquepartition[i] = -1;
2179  }
2180 
2181  /* get corresponding active problem variables */
2182  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2183 
2184  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2185  * by nondecreasing number of cliques the variables are in
2186  */
2187  nignorevars = 0;
2188  nvarsused = 0;
2189  for( i = 0; i < nvars; i++ )
2190  {
2191  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2192  {
2193  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2194  varseq[nvars-1-nignorevars] = i;
2195  nignorevars++;
2196  }
2197  else
2198  {
2199  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2200  varseq[nvarsused] = i;
2201  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2202  nvarsused++;
2203  }
2204  }
2205  assert(nvarsused + nignorevars == nvars);
2206 
2207  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2208  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2209 
2210  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2211 
2212  /* calculate the clique partition */
2213  *ncliques = 0;
2214  for( i = 0; i < nvars; ++i )
2215  {
2216  if( cliquepartition[varseq[i]] == -1 )
2217  {
2218  int j;
2219 
2220  /* variable starts a new clique */
2221  cliquepartition[varseq[i]] = *ncliques;
2222  cliquevars[0] = tmpvars[varseq[i]];
2223  cliquevalues[0] = tmpvalues[varseq[i]];
2224  ncliquevars = 1;
2225 
2226  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2227  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2228  */
2229  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2230  {
2231  /* greedily fill up the clique */
2232  for( j = i + 1; j < nvarsused; ++j )
2233  {
2234  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2235  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2236  {
2237  int k;
2238 
2239  /* check if every variable in the actual clique is in clique with the new variable */
2240  for( k = ncliquevars - 1; k >= 0; --k )
2241  {
2242  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2243  cliquevalues[k], TRUE) )
2244  break;
2245  }
2246 
2247  if( k == -1 )
2248  {
2249  /* put the variable into the same clique */
2250  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2251  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2252  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2253  ++ncliquevars;
2254  }
2255  }
2256  }
2257  }
2258 
2259  /* this clique is finished */
2260  ++(*ncliques);
2261  }
2262  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2263 
2264  /* break if we reached the maximal number of comparisons */
2265  if( i * nvars > maxncliquevarscomp )
2266  break;
2267  }
2268  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2269  for( ; i < nvars; ++i )
2270  {
2271  if( cliquepartition[varseq[i]] == -1 )
2272  {
2273  cliquepartition[varseq[i]] = *ncliques;
2274  ++(*ncliques);
2275  }
2276  }
2277 
2278  /* free temporary memory */
2279  SCIPfreeBufferArray(scip, &sortkeys);
2280  SCIPfreeBufferArray(scip, &varseq);
2281  SCIPfreeBufferArray(scip, &tmpvars);
2282  SCIPfreeBufferArray(scip, &tmpvalues);
2283  SCIPfreeBufferArray(scip, &cliquevalues);
2284  SCIPfreeBufferArray(scip, &cliquevars);
2285 
2286  return SCIP_OKAY;
2287 }
2288 
2289 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2290 static
2292  SCIP* scip, /**< SCIP data structure */
2293  SCIP_GUBSET* gubset, /**< GUB set data structure */
2294  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2295  SCIP_Real* solvals /**< solution values of all knapsack variables */
2296  )
2297 {
2298  int* cliquepartition;
2299  int* gubfirstvar;
2300  int ncliques;
2301  int currentgubconsidx;
2302  int newgubconsidx;
2303  int cliqueidx;
2304  int nvars;
2305  int i;
2306 
2307  assert(scip != NULL);
2308  assert(gubset != NULL);
2309  assert(vars != NULL);
2310 
2311  nvars = gubset->nvars;
2312  assert(nvars >= 0);
2313 
2314  /* allocate temporary memory for clique partition */
2315  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2316 
2317  /* compute sophisticated clique partition */
2318  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2319 
2320  /* allocate temporary memory for GUB set data structure */
2321  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2322 
2323  /* translate GUB partition into GUB set data structure */
2324  for( i = 0; i < ncliques; i++ )
2325  {
2326  /* initialize first variable for every GUB */
2327  gubfirstvar[i] = -1;
2328  }
2329  /* move every knapsack variable into GUB defined by clique partition */
2330  for( i = 0; i < nvars; i++ )
2331  {
2332  assert(cliquepartition[i] >= 0);
2333 
2334  cliqueidx = cliquepartition[i];
2335  currentgubconsidx = gubset->gubconssidx[i];
2336  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2337 
2338  /* variable is first element in GUB constraint defined by clique partition */
2339  if( gubfirstvar[cliqueidx] == -1 )
2340  {
2341  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2342  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2343  */
2344  assert(gubset->gubvarsidx[i] == 0);
2345  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2346 
2347  /* remember the first variable found for the current GUB */
2348  gubfirstvar[cliqueidx] = i;
2349  }
2350  /* variable is additional element of GUB constraint defined by clique partition */
2351  else
2352  {
2353  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2354 
2355  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2356  * first variable of this GUB constraint
2357  */
2358  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2359  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2360  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2361 
2362  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2363  }
2364  }
2365 
2366 #ifdef SCIP_DEBUG
2367  /* prints GUB set data structure */
2368  GUBsetPrint(scip, gubset, vars, solvals);
2369 #endif
2370 
2371 #ifndef NDEBUG
2372  /* checks consistency of GUB set data structure */
2373  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2374 #endif
2375 
2376  /* free temporary memory */
2377  SCIPfreeBufferArray(scip, &gubfirstvar);
2378  SCIPfreeBufferArray(scip, &cliquepartition);
2379 
2380  return SCIP_OKAY;
2381 }
2382 
2383 /** 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$
2384  * 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
2385  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2386  */
2387 static
2389  SCIP* scip, /**< SCIP data structure */
2390  SCIP_VAR** vars, /**< variables in knapsack constraint */
2391  int nvars, /**< number of variables in knapsack constraint */
2392  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2393  SCIP_Longint capacity, /**< capacity of knapsack */
2394  SCIP_Real* solvals, /**< solution values of all problem variables */
2395  int* covervars, /**< pointer to store cover variables */
2396  int* noncovervars, /**< pointer to store noncover variables */
2397  int* ncovervars, /**< pointer to store number of cover variables */
2398  int* nnoncovervars, /**< pointer to store number of noncover variables */
2399  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2400  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2401  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2402  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2403  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2404  )
2405 {
2406  SCIP_Longint* transweights;
2407  SCIP_Real* transprofits;
2408  SCIP_Longint transcapacity;
2409  SCIP_Longint fixedonesweight;
2410  SCIP_Longint itemsweight;
2411  SCIP_Bool infeasible;
2412  int* fixedones;
2413  int* fixedzeros;
2414  int* items;
2415  int nfixedones;
2416  int nfixedzeros;
2417  int nitems;
2418  int j;
2419 
2420  assert(scip != NULL);
2421  assert(vars != NULL);
2422  assert(nvars > 0);
2423  assert(weights != NULL);
2424  assert(capacity >= 0);
2425  assert(solvals != NULL);
2426  assert(covervars != NULL);
2427  assert(noncovervars != NULL);
2428  assert(ncovervars != NULL);
2429  assert(nnoncovervars != NULL);
2430  assert(coverweight != NULL);
2431  assert(found != NULL);
2432  assert(ntightened != NULL);
2433  assert(fractional != NULL);
2434 
2435  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2436 
2437  /* allocates temporary memory */
2438  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2439  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2440  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2441  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2442  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2443 
2444  *found = FALSE;
2445  *ncovervars = 0;
2446  *nnoncovervars = 0;
2447  *coverweight = 0;
2448  *fractional = TRUE;
2449 
2450  /* gets the following sets
2451  * N_1 = {j in N : x*_j = 1} (fixedones),
2452  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2453  * N\(N_0 & N_1) (items),
2454  * where x*_j is the solution value of variable x_j
2455  */
2456  nfixedones = 0;
2457  nfixedzeros = 0;
2458  nitems = 0;
2459  fixedonesweight = 0;
2460  itemsweight = 0;
2461  *ntightened = 0;
2462  for( j = 0; j < nvars; j++ )
2463  {
2464  assert(SCIPvarIsBinary(vars[j]));
2465 
2466  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2467  if( weights[j] > capacity )
2468  {
2469  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2470  assert(!infeasible);
2471  (*ntightened)++;
2472  continue;
2473  }
2474 
2475  /* variable x_j has solution value one */
2476  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2477  {
2478  fixedones[nfixedones] = j;
2479  nfixedones++;
2480  fixedonesweight += weights[j];
2481  }
2482  /* variable x_j has solution value zero */
2483  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2484  {
2485  fixedzeros[nfixedzeros] = j;
2486  nfixedzeros++;
2487  }
2488  /* variable x_j has fractional solution value */
2489  else
2490  {
2491  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2492  items[nitems] = j;
2493  nitems++;
2494  itemsweight += weights[j];
2495  }
2496  }
2497  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2498 
2499  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2500  * the separation routine
2501  */
2502  assert(nitems >= 0);
2503  if( nitems == 0 )
2504  {
2505  *fractional = FALSE;
2506  goto TERMINATE;
2507  }
2508  assert(*fractional);
2509 
2510  /* transforms the traditional separation problem (under consideration of the following fixing:
2511  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2512  *
2513  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2514  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2515  * z_j in {0,1}, j in N\(N_0 & N_1)
2516  *
2517  * to a knapsack problem in maximization form by complementing the variables
2518  *
2519  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2520  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2521  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2522  * z_j in {0,1}, j in N\(N_0 & N_1)
2523  */
2524 
2525  /* gets weight and profit of variables in transformed knapsack problem */
2526  for( j = 0; j < nitems; j++ )
2527  {
2528  transweights[j] = weights[items[j]];
2529  transprofits[j] = 1.0 - solvals[items[j]];
2530  }
2531  /* gets capacity of transformed knapsack problem */
2532  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2533 
2534  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2535  * (when variables fixed to zero are not used)
2536  */
2537  if( transcapacity < 0 )
2538  {
2539  assert(!(*found));
2540  goto TERMINATE;
2541  }
2542 
2543  if( modtransused )
2544  {
2545  /* transforms the modified separation problem (under consideration of the following fixing:
2546  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2547  *
2548  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2549  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2550  * z_j in {0,1}, j in N\(N_0 & N_1)
2551  *
2552  * to a knapsack problem in maximization form by complementing the variables
2553  *
2554  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2555  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2556  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2557  * z_j in {0,1}, j in N\(N_0 & N_1)
2558  */
2559 
2560  /* gets weight and profit of variables in modified transformed knapsack problem */
2561  for( j = 0; j < nitems; j++ )
2562  {
2563  transprofits[j] *= weights[items[j]];
2564  assert(SCIPisFeasPositive(scip, transprofits[j]));
2565  }
2566  }
2567 
2568  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2569  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2570  * let z* be the solution, then
2571  * j in C, if z*_j = 0 and
2572  * i in N\C, if z*_j = 1.
2573  */
2574  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2575  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2576  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2577 
2578  /* constructs cover C (sum_{j in C} a_j > a_0) */
2579  for( j = 0; j < *ncovervars; j++ )
2580  {
2581  (*coverweight) += weights[covervars[j]];
2582  }
2583 
2584  /* adds all variables from N_1 to C */
2585  for( j = 0; j < nfixedones; j++ )
2586  {
2587  covervars[*ncovervars] = fixedones[j];
2588  (*ncovervars)++;
2589  (*coverweight) += weights[fixedones[j]];
2590  }
2591 
2592  /* adds all variables from N_0 to N\C */
2593  for( j = 0; j < nfixedzeros; j++ )
2594  {
2595  noncovervars[*nnoncovervars] = fixedzeros[j];
2596  (*nnoncovervars)++;
2597  }
2598  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2599  assert((*coverweight) > capacity);
2600  *found = TRUE;
2601 
2602  TERMINATE:
2603  /* frees temporary memory */
2604  SCIPfreeBufferArray(scip, &items);
2605  SCIPfreeBufferArray(scip, &fixedzeros);
2606  SCIPfreeBufferArray(scip, &fixedones);
2607  SCIPfreeBufferArray(scip, &transprofits);
2608  SCIPfreeBufferArray(scip, &transweights);
2609 
2610  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2611 
2612  return SCIP_OKAY;
2613 }
2614 
2615 #ifndef NDEBUG
2616 /** checks if minweightidx is set correctly
2617  */
2618 static
2620  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2621  SCIP_Longint capacity, /**< capacity of knapsack */
2622  int* covervars, /**< pointer to store cover variables */
2623  int ncovervars, /**< pointer to store number of cover variables */
2624  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2625  int minweightidx, /**< index of variable in cover variables with minimum weight */
2626  int j /**< current index in cover variables */
2627  )
2628 {
2629  SCIP_Longint minweight;
2630  int i;
2631 
2632  assert(weights != NULL);
2633  assert(covervars != NULL);
2634  assert(ncovervars > 0);
2635 
2636  minweight = weights[covervars[minweightidx]];
2637 
2638  /* checks if all cover variables before index j have weight greater than minweight */
2639  for( i = 0; i < j; i++ )
2640  {
2641  assert(weights[covervars[i]] > minweight);
2642  if( weights[covervars[i]] <= minweight )
2643  return FALSE;
2644  }
2645 
2646  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2647  for( i = 0; i < j; i++ )
2648  {
2649  assert(coverweight - weights[covervars[i]] <= capacity);
2650  if( coverweight - weights[covervars[i]] > capacity )
2651  return FALSE;
2652  }
2653  return TRUE;
2654 }
2655 #endif
2656 
2657 
2658 /** 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$,
2659  * 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$
2660  */
2661 static
2663  SCIP* scip, /**< SCIP data structure */
2664  SCIP_Real* solvals, /**< solution values of all problem variables */
2665  int* covervars, /**< cover variables */
2666  int ncovervars, /**< number of cover variables */
2667  int* varsC1, /**< pointer to store variables in C1 */
2668  int* varsC2, /**< pointer to store variables in C2 */
2669  int* nvarsC1, /**< pointer to store number of variables in C1 */
2670  int* nvarsC2 /**< pointer to store number of variables in C2 */
2671  )
2672 {
2673  int j;
2674 
2675  assert(scip != NULL);
2676  assert(ncovervars >= 0);
2677  assert(solvals != NULL);
2678  assert(covervars != NULL);
2679  assert(varsC1 != NULL);
2680  assert(varsC2 != NULL);
2681  assert(nvarsC1 != NULL);
2682  assert(nvarsC2 != NULL);
2683 
2684  *nvarsC1 = 0;
2685  *nvarsC2 = 0;
2686  for( j = 0; j < ncovervars; j++ )
2687  {
2688  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2689 
2690  /* variable has solution value one */
2691  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2692  {
2693  varsC2[*nvarsC2] = covervars[j];
2694  (*nvarsC2)++;
2695  }
2696  /* variable has solution value less than one */
2697  else
2698  {
2699  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2700  varsC1[*nvarsC1] = covervars[j];
2701  (*nvarsC1)++;
2702  }
2703  }
2704  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2705 }
2706 
2707 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2708  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2709  */
2710 static
2712  SCIP* scip, /**< SCIP data structure */
2713  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2714  int* varsC1, /**< pointer to store variables in C1 */
2715  int* varsC2, /**< pointer to store variables in C2 */
2716  int* nvarsC1, /**< pointer to store number of variables in C1 */
2717  int* nvarsC2 /**< pointer to store number of variables in C2 */
2718  )
2720  SCIP_Real* sortkeysC2;
2721  int j;
2722 
2723  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2724  assert(*nvarsC2 > 0);
2725 
2726  /* allocates temporary memory */
2727  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2728 
2729  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2730  for( j = 0; j < *nvarsC2; j++ )
2731  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2732  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2733 
2734  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2735  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2736  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2737  {
2738  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2739  (*nvarsC1)++;
2740  (*nvarsC2)--;
2741  }
2742 
2743  /* frees temporary memory */
2744  SCIPfreeBufferArray(scip, &sortkeysC2);
2745 
2746  return SCIP_OKAY;
2747 }
2748 
2749 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2750 static
2752  SCIP* scip, /**< SCIP data structure */
2753  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2754  int* varsC1, /**< pointer to store variables in C1 */
2755  int* varsC2, /**< pointer to store variables in C2 */
2756  int* nvarsC1, /**< pointer to store number of variables in C1 */
2757  int* nvarsC2 /**< pointer to store number of variables in C2 */
2758  )
2760  SCIP_Real* sortkeysC2;
2761  int j;
2762 
2763  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2764  assert(*nvarsC2 > 0);
2765 
2766  /* allocates temporary memory */
2767  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2768 
2769  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2770  for( j = 0; j < *nvarsC2; j++ )
2771  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2772  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2773 
2774  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2775  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2776  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2777  (*nvarsC1)++;
2778  (*nvarsC2)--;
2779 
2780  /* frees temporary memory */
2781  SCIPfreeBufferArray(scip, &sortkeysC2);
2782 
2783  return SCIP_OKAY;
2784 }
2785 
2786 
2787 /** 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$
2788  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2789  * \f$F = (N \setminus C) \setminus F\f$
2790  */
2791 static
2793  SCIP* scip, /**< SCIP data structure */
2794  SCIP_Real* solvals, /**< solution values of all problem variables */
2795  int* noncovervars, /**< noncover variables */
2796  int nnoncovervars, /**< number of noncover variables */
2797  int* varsF, /**< pointer to store variables in F */
2798  int* varsR, /**< pointer to store variables in R */
2799  int* nvarsF, /**< pointer to store number of variables in F */
2800  int* nvarsR /**< pointer to store number of variables in R */
2801  )
2802 {
2803  int j;
2804 
2805  assert(scip != NULL);
2806  assert(nnoncovervars >= 0);
2807  assert(solvals != NULL);
2808  assert(noncovervars != NULL);
2809  assert(varsF != NULL);
2810  assert(varsR != NULL);
2811  assert(nvarsF != NULL);
2812  assert(nvarsR != NULL);
2813 
2814  *nvarsF = 0;
2815  *nvarsR = 0;
2816 
2817  for( j = 0; j < nnoncovervars; j++ )
2818  {
2819  /* variable has solution value zero */
2820  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2821  {
2822  varsR[*nvarsR] = noncovervars[j];
2823  (*nvarsR)++;
2824  }
2825  /* variable has solution value greater than zero */
2826  else
2827  {
2828  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2829  varsF[*nvarsF] = noncovervars[j];
2830  (*nvarsF)++;
2831  }
2832  }
2833  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2834 }
2835 
2836 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2837  * lifting procedure
2838  */
2839 static
2841  SCIP* scip, /**< SCIP data structure */
2842  SCIP_Real* solvals, /**< solution values of all problem variables */
2843  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2844  int* varsF, /**< pointer to store variables in F */
2845  int* varsC2, /**< pointer to store variables in C2 */
2846  int* varsR, /**< pointer to store variables in R */
2847  int nvarsF, /**< number of variables in F */
2848  int nvarsC2, /**< number of variables in C2 */
2849  int nvarsR /**< number of variables in R */
2850  )
2851 {
2852  SORTKEYPAIR** sortkeypairsF;
2853  SORTKEYPAIR* sortkeypairsFstore;
2854  SCIP_Real* sortkeysC2;
2855  SCIP_Real* sortkeysR;
2856  int j;
2857 
2858  assert(scip != NULL);
2859  assert(solvals != NULL);
2860  assert(weights != NULL);
2861  assert(varsF != NULL);
2862  assert(varsC2 != NULL);
2863  assert(varsR != NULL);
2864  assert(nvarsF >= 0);
2865  assert(nvarsC2 >= 0);
2866  assert(nvarsR >= 0);
2867 
2868  /* allocates temporary memory */
2869  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2870  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2871  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2872  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2873 
2874  /* gets sorting key for variables in F corresponding to the following lifting sequence
2875  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2876  * x*_1 >= x*_2 >= ... >= x*_|F|
2877  * in case of equality uses
2878  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2879  */
2880  for( j = 0; j < nvarsF; j++ )
2881  {
2882  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2883  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2884  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2885  }
2886 
2887  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2888  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2889  */
2890  for( j = 0; j < nvarsC2; j++ )
2891  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2892 
2893  /* gets sorting key for variables in R corresponding to the following lifting sequence
2894  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2895  */
2896  for( j = 0; j < nvarsR; j++ )
2897  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2898 
2899  /* sorts F, C2 and R */
2900  if( nvarsF > 0 )
2901  {
2902  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2903  }
2904  if( nvarsC2 > 0 )
2905  {
2906  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2907  }
2908  if( nvarsR > 0)
2909  {
2910  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2911  }
2912 
2913  /* frees temporary memory */
2914  SCIPfreeBufferArray(scip, &sortkeysR);
2915  SCIPfreeBufferArray(scip, &sortkeysC2);
2916  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2917  SCIPfreeBufferArray(scip, &sortkeypairsF);
2918 
2919  return SCIP_OKAY;
2920 }
2921 
2922 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2923  * for the sequential GUB wise lifting procedure
2924  */
2925 static
2927  SCIP* scip, /**< SCIP data structure */
2928  SCIP_GUBSET* gubset, /**< GUB set data structure */
2929  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2930  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2931  int* varsC1, /**< variables in C1 */
2932  int* varsC2, /**< variables in C2 */
2933  int* varsF, /**< variables in F */
2934  int* varsR, /**< variables in R */
2935  int nvarsC1, /**< number of variables in C1 */
2936  int nvarsC2, /**< number of variables in C2 */
2937  int nvarsF, /**< number of variables in F */
2938  int nvarsR, /**< number of variables in R */
2939  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2940  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2941  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2942  int* gubconsGR, /**< pointer to store GUBs in GR */
2943  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2944  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2945  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2946  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2947  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2948  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2949  )
2950 {
2951  SORTKEYPAIR** sortkeypairsGFC1;
2952  SORTKEYPAIR* sortkeypairsGFC1store;
2953  SCIP_Real* sortkeysC1;
2954  SCIP_Real* sortkeysC2;
2955  SCIP_Real* sortkeysR;
2956  int* nC1varsingubcons;
2957  int var;
2958  int gubconsidx;
2959  int varidx;
2960  int ngubconss;
2961  int ngubconsGOC1;
2962  int targetvar;
2963  int nvarsprocessed;
2964  int i;
2965  int j;
2966 
2967 #if GUBSPLITGNC1GUBS
2968  SCIP_Bool gubconswithF;
2969  int origngubconss;
2970  origngubconss = gubset->ngubconss;
2971 #endif
2972 
2973  assert(scip != NULL);
2974  assert(gubset != NULL);
2975  assert(solvals != NULL);
2976  assert(weights != NULL);
2977  assert(varsC1 != NULL);
2978  assert(varsC2 != NULL);
2979  assert(varsF != NULL);
2980  assert(varsR != NULL);
2981  assert(nvarsC1 > 0);
2982  assert(nvarsC2 >= 0);
2983  assert(nvarsF >= 0);
2984  assert(nvarsR >= 0);
2985  assert(gubconsGC1 != NULL);
2986  assert(gubconsGC2 != NULL);
2987  assert(gubconsGFC1 != NULL);
2988  assert(gubconsGR != NULL);
2989  assert(ngubconsGC1 != NULL);
2990  assert(ngubconsGC2 != NULL);
2991  assert(ngubconsGFC1 != NULL);
2992  assert(ngubconsGR != NULL);
2993  assert(maxgubvarssize != NULL);
2994 
2995  ngubconss = gubset->ngubconss;
2996  nvarsprocessed = 0;
2997  ngubconsGOC1 = 0;
2998 
2999  /* GUBs are categorized into different types according to the variables in volved
3000  * - GOC1: involves variables in C1 only -- no C2, R, F
3001  * - GNC1: involves variables in C1 and F (and R) -- no C2
3002  * - GF: involves variables in F (and R) only -- no C1, C2
3003  * - GC2: involves variables in C2 only -- no C1, R, F
3004  * - GR: involves variables in R only -- no C1, C2, F
3005  * which requires splitting GUBs in case they include variable in F and R.
3006  *
3007  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3008  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3009  * - second ordering level is
3010  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3011  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3012  * GR: non-increasing max{ a_k : k in GR_j}
3013  *
3014  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3015  * - GC1: GUBs of category GOC1 and GNC1
3016  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3017  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3018  */
3019 
3020  /* allocates temporary memory */
3021  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3022  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3023  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3024 
3025  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3026  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3027  * - C2: non-increasing a_j
3028  * - R: non-increasing a_j
3029  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3030  */
3031 
3032  /* gets sorting key for variables in C1 corresponding to the following ordering
3033  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3034  */
3035  for( j = 0; j < nvarsC1; j++ )
3036  {
3037  /* gets sortkeys */
3038  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3039 
3040  /* update status of variable in its gub constraint */
3041  gubconsidx = gubset->gubconssidx[varsC1[j]];
3042  varidx = gubset->gubvarsidx[varsC1[j]];
3043  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3044  }
3045 
3046  /* gets sorting key for variables in F corresponding to the following ordering
3047  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3048  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3049  * and updates status of each variable in F in GUB set data structure
3050  */
3051  for( j = 0; j < nvarsF; j++ )
3052  {
3053  /* update status of variable in its gub constraint */
3054  gubconsidx = gubset->gubconssidx[varsF[j]];
3055  varidx = gubset->gubvarsidx[varsF[j]];
3056  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3057  }
3058 
3059  /* gets sorting key for variables in C2 corresponding to the following ordering
3060  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3061  * and updates status of each variable in F in GUB set data structure
3062  */
3063  for( j = 0; j < nvarsC2; j++ )
3064  {
3065  /* gets sortkeys */
3066  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3067 
3068  /* update status of variable in its gub constraint */
3069  gubconsidx = gubset->gubconssidx[varsC2[j]];
3070  varidx = gubset->gubvarsidx[varsC2[j]];
3071  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3072  }
3073 
3074  /* gets sorting key for variables in R corresponding to the following ordering
3075  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3076  * and updates status of each variable in F in GUB set data structure
3077  */
3078  for( j = 0; j < nvarsR; j++ )
3079  {
3080  /* gets sortkeys */
3081  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3082 
3083  /* update status of variable in its gub constraint */
3084  gubconsidx = gubset->gubconssidx[varsR[j]];
3085  varidx = gubset->gubvarsidx[varsR[j]];
3086  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3087  }
3088 
3089  /* sorts C1, F, C2 and R */
3090  assert(nvarsC1 > 0);
3091  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3092 
3093  if( nvarsC2 > 0 )
3094  {
3095  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3096  }
3097  if( nvarsR > 0)
3098  {
3099  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3100  }
3101 
3102  /* frees temporary memory */
3103  SCIPfreeBufferArray(scip, &sortkeysR);
3104  SCIPfreeBufferArray(scip, &sortkeysC2);
3105  SCIPfreeBufferArray(scip, &sortkeysC1);
3106 
3107  /* allocate and initialize temporary memory for sorting GUB constraints */
3108  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3109  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3110  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3111  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3112  for( i = 0; i < ngubconss; i++)
3113  {
3114  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3115  sortkeypairsGFC1[i]->key1 = 0.0;
3116  sortkeypairsGFC1[i]->key2 = 0.0;
3117  }
3118  *ngubconsGC1 = 0;
3119  *ngubconsGC2 = 0;
3120  *ngubconsGFC1 = 0;
3121  *ngubconsGR = 0;
3122  *ngubconscapexceed = 0;
3123  *maxgubvarssize = 0;
3124 
3125 #ifndef NDEBUG
3126  for( i = 0; i < gubset->ngubconss; i++ )
3127  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3128 #endif
3129 
3130  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3131  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3132  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3133  * non-increasing number of variables in F, and
3134  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3135  */
3136  for( i = 0; i < nvarsC1; i++ )
3137  {
3138  int nvarsC1capexceed;
3139 
3140  nvarsC1capexceed = 0;
3141 
3142  var = varsC1[i];
3143  gubconsidx = gubset->gubconssidx[var];
3144  varidx = gubset->gubvarsidx[var];
3145 
3146  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3147  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3148 
3149  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3150  * note that variables in C1 are already sorted by non-decreasing weigth
3151  */
3152  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3153  GUBsetSwapVars(scip, gubset, var, targetvar);
3154  nC1varsingubcons[gubconsidx]++;
3155 
3156  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3157  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3158  {
3159  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3160  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3161  continue;
3162  }
3163 
3164  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3165  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3166  */
3167 #if GUBSPLITGNC1GUBS
3168  gubconswithF = FALSE;
3169 #endif
3170  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3171  {
3172  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3173 
3174  /* C1-variable: update number of C1/capacity exceeding variables */
3175  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3176  {
3177  nvarsC1capexceed++;
3178  nvarsprocessed++;
3179  }
3180  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3181  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3182  {
3183 #if GUBSPLITGNC1GUBS
3184  gubconswithF = TRUE;
3185 #endif
3186  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3187 
3188  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3189  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3190  }
3191  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3192  {
3193  nvarsC1capexceed++;
3194  }
3195  else
3196  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3197  }
3198 
3199  /* update set of GC1 GUBs */
3200  gubconsGC1[*ngubconsGC1] = gubconsidx;
3201  (*ngubconsGC1)++;
3202 
3203  /* update maximum size of all GUB constraints */
3204  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3205  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3206 
3207  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3208  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3209  {
3210  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3211  ngubconsGOC1++;
3212  }
3213  else
3214  {
3215 #if GUBSPLITGNC1GUBS
3216  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3217  if( !gubconswithF )
3218  {
3219  GUBVARSTATUS movevarstatus;
3220 
3221  assert(gubset->ngubconss < gubset->nvars);
3222 
3223  /* create a new GUB for GR part of splitting */
3224  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3225  gubset->ngubconss++;
3226  ngubconss = gubset->ngubconss;
3227 
3228  /* fill GR with R variables in current GUB */
3229  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3230  {
3231  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3232  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3233  {
3234  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3235  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3236  gubconsidx, ngubconss-1) );
3237  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3238  movevarstatus;
3239  }
3240  }
3241 
3242  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3243  ngubconsGOC1++;
3244 
3245  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3246  gubconsGR[*ngubconsGR] = ngubconss-1;
3247  (*ngubconsGR)++;
3248  }
3249  /* variables in C1, F, and maybe R: GNC1 GUB */
3250  else
3251  {
3252  assert(gubconswithF);
3253 
3254  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3255  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3256  (*ngubconsGFC1)++;
3257  }
3258 #else
3259  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3260  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3261  (*ngubconsGFC1)++;
3262 #endif
3263  }
3264  }
3265 
3266  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3267  * are already sorted correctly
3268  */
3269  for( i = 0; i < nvarsC2; i++ )
3270  {
3271  var = varsC2[i];
3272  gubconsidx = gubset->gubconssidx[var];
3273  varidx = gubset->gubvarsidx[var];
3274 
3275  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3276  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3277  assert(varidx == 0);
3278  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3279  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3280 
3281  /* set status of GC2 GUB */
3282  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3283 
3284  /* update group of GC2 GUBs */
3285  gubconsGC2[*ngubconsGC2] = gubconsidx;
3286  (*ngubconsGC2)++;
3287 
3288  /* update maximum size of all GUB constraints */
3289  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3290  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3291 
3292  nvarsprocessed++;
3293  }
3294 
3295  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3296  * non-increasing number of variables in F, and
3297  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3298  */
3299  for( i = 0; i < nvarsF; i++ )
3300  {
3301  var = varsF[i];
3302  gubconsidx = gubset->gubconssidx[var];
3303  varidx = gubset->gubvarsidx[var];
3304 
3305  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3306  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3307 
3308  nvarsprocessed++;
3309 
3310  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3311  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3312  {
3313  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3314  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3315  continue;
3316  }
3317 
3318  /* set status of GF GUB */
3319  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3320 
3321  /* update sorting key of corresponding GFC1 GUB */
3322  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3323  {
3324  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3325  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3326 
3327  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3328  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3329  {
3330  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3331 
3332  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3333  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3334  }
3335  }
3336 
3337  /* update set of GFC1 GUBs */
3338  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3339  (*ngubconsGFC1)++;
3340 
3341  /* update maximum size of all GUB constraints */
3342  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3343  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3344  }
3345 
3346  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3347  * correctly
3348  */
3349  for( i = 0; i < nvarsR; i++ )
3350  {
3351  var = varsR[i];
3352  gubconsidx = gubset->gubconssidx[var];
3353  varidx = gubset->gubvarsidx[var];
3354 
3355  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3356  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3357 
3358  nvarsprocessed++;
3359 
3360  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3361  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3362  {
3363  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3364  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3365  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3366  continue;
3367  }
3368 
3369  /* set status of GR GUB */
3370  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3371 
3372  /* update set of GR GUBs */
3373  gubconsGR[*ngubconsGR] = gubconsidx;
3374  (*ngubconsGR)++;
3375 
3376  /* update maximum size of all GUB constraints */
3377  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3378  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3379  }
3380  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3381 
3382  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3383  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3384  assert(*ngubconscapexceed >= 0);
3385 #ifndef NDEBUG
3386  {
3387  int check;
3388 
3389  check = 0;
3390 
3391  /* remaining not handled GUBs should only contain capacity exceeding variables */
3392  for( i = 0; i < ngubconss; i++ )
3393  {
3394  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3395  check++;
3396  }
3397  assert(check == *ngubconscapexceed);
3398  }
3399 #endif
3400 
3401  /* sort GFCI GUBs according to computed sorting keys */
3402  if( (*ngubconsGFC1) > 0 )
3403  {
3404  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3405  }
3406 
3407  /* free temporary memory */
3408 #if GUBSPLITGNC1GUBS
3409  ngubconss = origngubconss;
3410 #endif
3411  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3412  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3413  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3414 
3415  return SCIP_OKAY;
3416 }
3417 
3418 /** enlarges minweight table to at least the given length */
3419 static
3421  SCIP* scip, /**< SCIP data structure */
3422  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3423  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3424  int* minweightssize, /**< pointer to current size of minweights table */
3425  int newlen /**< new length of minweights table */
3426  )
3427 {
3428  int j;
3429 
3430  assert(minweightsptr != NULL);
3431  assert(*minweightsptr != NULL);
3432  assert(minweightslen != NULL);
3433  assert(*minweightslen >= 0);
3434  assert(minweightssize != NULL);
3435  assert(*minweightssize >= 0);
3436 
3437  if( newlen > *minweightssize )
3438  {
3439  int newsize;
3440 
3441  /* reallocate table memory */
3442  newsize = SCIPcalcMemGrowSize(scip, newlen);
3443  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3444  *minweightssize = newsize;
3445  }
3446  assert(newlen <= *minweightssize);
3447 
3448  /* initialize new elements */
3449  for( j = *minweightslen; j < newlen; ++j )
3450  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3451  *minweightslen = newlen;
3452 
3453  return SCIP_OKAY;
3454 }
3455 
3456 /** lifts given inequality
3457  * sum_{j in M_1} x_j <= alpha_0
3458  * valid for
3459  * 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 }
3460  * to a valid inequality
3461  * 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
3462  * <= alpha_0 + sum_{j in M_2} alpha_j
3463  * for
3464  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3465  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3466  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3467  * extended weight inequalities.
3468  */
3469 static
3471  SCIP* scip, /**< SCIP data structure */
3472  SCIP_VAR** vars, /**< variables in knapsack constraint */
3473  int nvars, /**< number of variables in knapsack constraint */
3474  int ntightened, /**< number of variables with tightened upper bound */
3475  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3476  SCIP_Longint capacity, /**< capacity of knapsack */
3477  SCIP_Real* solvals, /**< solution values of all problem variables */
3478  int* varsM1, /**< variables in M_1 */
3479  int* varsM2, /**< variables in M_2 */
3480  int* varsF, /**< variables in F */
3481  int* varsR, /**< variables in R */
3482  int nvarsM1, /**< number of variables in M_1 */
3483  int nvarsM2, /**< number of variables in M_2 */
3484  int nvarsF, /**< number of variables in F */
3485  int nvarsR, /**< number of variables in R */
3486  int alpha0, /**< rights hand side of given valid inequality */
3487  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3488  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3489  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3490  )
3491 {
3492  SCIP_Longint* minweights;
3493  SCIP_Real* sortkeys;
3494  SCIP_Longint fixedonesweight;
3495  int minweightssize;
3496  int minweightslen;
3497  int j;
3498  int w;
3499 
3500  assert(scip != NULL);
3501  assert(vars != NULL);
3502  assert(nvars >= 0);
3503  assert(weights != NULL);
3504  assert(capacity >= 0);
3505  assert(solvals != NULL);
3506  assert(varsM1 != NULL);
3507  assert(varsM2 != NULL);
3508  assert(varsF != NULL);
3509  assert(varsR != NULL);
3510  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3511  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3512  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3513  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3514  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3515  assert(alpha0 >= 0);
3516  assert(liftcoefs != NULL);
3517  assert(cutact != NULL);
3518  assert(liftrhs != NULL);
3519 
3520  /* allocates temporary memory */
3521  minweightssize = nvarsM1 + 1;
3522  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3523  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3524 
3525  /* initializes data structures */
3526  BMSclearMemoryArray(liftcoefs, nvars);
3527  *cutact = 0.0;
3528 
3529  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3530  * and calculates activity of the current valid inequality
3531  */
3532  for( j = 0; j < nvarsM1; j++ )
3533  {
3534  assert(liftcoefs[varsM1[j]] == 0);
3535  liftcoefs[varsM1[j]] = 1;
3536  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3537  (*cutact) += solvals[varsM1[j]];
3538  }
3539 
3540  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3541 
3542  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3543  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3544  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3545  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3546  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3547  */
3548  minweights[0] = 0;
3549  for( w = 1; w <= nvarsM1; w++ )
3550  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3551  minweightslen = nvarsM1 + 1;
3552 
3553  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3554  fixedonesweight = 0;
3555  for( j = 0; j < nvarsM2; j++ )
3556  fixedonesweight += weights[varsM2[j]];
3557  assert(fixedonesweight >= 0);
3558 
3559  /* initializes right hand side of lifted valid inequality */
3560  *liftrhs = alpha0;
3561 
3562  /* sequentially up-lifts all variables in F: */
3563  for( j = 0; j < nvarsF; j++ )
3564  {
3565  SCIP_Longint weight;
3566  int liftvar;
3567  int liftcoef;
3568  int z;
3569 
3570  liftvar = varsF[j];
3571  weight = weights[liftvar];
3572  assert(liftvar >= 0 && liftvar < nvars);
3573  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3574  assert(weight > 0);
3575 
3576  /* knapsack problem is infeasible:
3577  * sets z = 0
3578  */
3579  if( capacity - fixedonesweight - weight < 0 )
3580  {
3581  z = 0;
3582  }
3583  /* knapsack problem is feasible:
3584  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3585  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3586  */
3587  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3588  {
3589  z = *liftrhs;
3590  }
3591  /* knapsack problem is feasible:
3592  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3593  */
3594  else
3595  {
3596  int left;
3597  int right;
3598  int middle;
3599 
3600  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3601  left = 0;
3602  right = (*liftrhs) + 1;
3603  while( left < right - 1 )
3604  {
3605  middle = (left + right) / 2;
3606  assert(0 <= middle && middle < minweightslen);
3607  if( minweights[middle] <= capacity - fixedonesweight - weight )
3608  left = middle;
3609  else
3610  right = middle;
3611  }
3612  assert(left == right - 1);
3613  assert(0 <= left && left < minweightslen);
3614  assert(minweights[left] <= capacity - fixedonesweight - weight );
3615  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3616 
3617  /* now z = left */
3618  z = left;
3619  assert(z <= *liftrhs);
3620  }
3621 
3622  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3623  liftcoef = (*liftrhs) - z;
3624  liftcoefs[liftvar] = liftcoef;
3625  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3626 
3627  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3628  if( liftcoef == 0 )
3629  continue;
3630 
3631  /* updates activity of current valid inequality */
3632  (*cutact) += liftcoef * solvals[liftvar];
3633 
3634  /* enlarges current minweight table:
3635  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3636  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3637  * and sets minweights_i[w] = infinity for
3638  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3639  */
3640  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3641 
3642  /* updates minweight table: minweight_i+1[w] =
3643  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3644  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3645  */
3646  for( w = minweightslen - 1; w >= 0; w-- )
3647  {
3648  SCIP_Longint min;
3649  if( w < liftcoef )
3650  {
3651  min = MIN(minweights[w], weight);
3652  minweights[w] = min;
3653  }
3654  else
3655  {
3656  assert(w >= liftcoef);
3657  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3658  minweights[w] = min;
3659  }
3660  }
3661  }
3662  assert(minweights[0] == 0);
3663 
3664  /* sequentially down-lifts all variables in M_2: */
3665  for( j = 0; j < nvarsM2; j++ )
3666  {
3667  SCIP_Longint weight;
3668  int liftvar;
3669  int liftcoef;
3670  int left;
3671  int right;
3672  int middle;
3673  int z;
3674 
3675  liftvar = varsM2[j];
3676  weight = weights[liftvar];
3677  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3678  assert(liftvar >= 0 && liftvar < nvars);
3679  assert(weight > 0);
3680 
3681  /* uses binary search to find
3682  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3683  */
3684  left = 0;
3685  right = minweightslen;
3686  while( left < right - 1 )
3687  {
3688  middle = (left + right) / 2;
3689  assert(0 <= middle && middle < minweightslen);
3690  if( minweights[middle] <= capacity - fixedonesweight + weight )
3691  left = middle;
3692  else
3693  right = middle;
3694  }
3695  assert(left == right - 1);
3696  assert(0 <= left && left < minweightslen);
3697  assert(minweights[left] <= capacity - fixedonesweight + weight );
3698  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3699 
3700  /* now z = left */
3701  z = left;
3702  assert(z >= *liftrhs);
3703 
3704  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3705  liftcoef = z - (*liftrhs);
3706  liftcoefs[liftvar] = liftcoef;
3707  assert(liftcoef >= 0);
3708 
3709  /* updates sum of weights of variables fixed to one */
3710  fixedonesweight -= weight;
3711 
3712  /* updates right-hand side of current valid inequality */
3713  (*liftrhs) += liftcoef;
3714  assert(*liftrhs >= alpha0);
3715 
3716  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3717  if( liftcoef == 0 )
3718  continue;
3719 
3720  /* updates activity of current valid inequality */
3721  (*cutact) += liftcoef * solvals[liftvar];
3722 
3723  /* enlarges current minweight table:
3724  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3725  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3726  * and sets minweights_i[w] = infinity for
3727  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3728  */
3729  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3730 
3731  /* updates minweight table: minweight_i+1[w] =
3732  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3733  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3734  */
3735  for( w = minweightslen - 1; w >= 0; w-- )
3736  {
3737  SCIP_Longint min;
3738  if( w < liftcoef )
3739  {
3740  min = MIN(minweights[w], weight);
3741  minweights[w] = min;
3742  }
3743  else
3744  {
3745  assert(w >= liftcoef);
3746  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3747  minweights[w] = min;
3748  }
3749  }
3750  }
3751  assert(fixedonesweight == 0);
3752  assert(*liftrhs >= alpha0);
3753 
3754  /* sequentially up-lifts all variables in R: */
3755  for( j = 0; j < nvarsR; j++ )
3756  {
3757  SCIP_Longint weight;
3758  int liftvar;
3759  int liftcoef;
3760  int z;
3761 
3762  liftvar = varsR[j];
3763  weight = weights[liftvar];
3764  assert(liftvar >= 0 && liftvar < nvars);
3765  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3766  assert(weight > 0);
3767  assert(capacity - weight >= 0);
3768  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3769 
3770  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3771  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3772  */
3773  if( minweights[*liftrhs] <= capacity - weight )
3774  {
3775  z = *liftrhs;
3776  }
3777  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3778  */
3779  else
3780  {
3781  int left;
3782  int right;
3783  int middle;
3784 
3785  left = 0;
3786  right = (*liftrhs) + 1;
3787  while( left < right - 1)
3788  {
3789  middle = (left + right) / 2;
3790  assert(0 <= middle && middle < minweightslen);
3791  if( minweights[middle] <= capacity - weight )
3792  left = middle;
3793  else
3794  right = middle;
3795  }
3796  assert(left == right - 1);
3797  assert(0 <= left && left < minweightslen);
3798  assert(minweights[left] <= capacity - weight );
3799  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3800 
3801  /* now z = left */
3802  z = left;
3803  assert(z <= *liftrhs);
3804  }
3805 
3806  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3807  liftcoef = (*liftrhs) - z;
3808  liftcoefs[liftvar] = liftcoef;
3809  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3810 
3811  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3812  if( liftcoef == 0 )
3813  continue;
3814 
3815  /* updates activity of current valid inequality */
3816  (*cutact) += liftcoef * solvals[liftvar];
3817 
3818  /* updates minweight table: minweight_i+1[w] =
3819  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3820  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3821  */
3822  for( w = *liftrhs; w >= 0; w-- )
3823  {
3824  SCIP_Longint min;
3825  if( w < liftcoef )
3826  {
3827  min = MIN(minweights[w], weight);
3828  minweights[w] = min;
3829  }
3830  else
3831  {
3832  assert(w >= liftcoef);
3833  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3834  minweights[w] = min;
3835  }
3836  }
3837  }
3838 
3839  /* frees temporary memory */
3840  SCIPfreeBufferArray(scip, &sortkeys);
3841  SCIPfreeBufferArray(scip, &minweights);
3842 
3843  return SCIP_OKAY;
3844 }
3845 
3846 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3847 static
3849  SCIP_Longint val1, /**< first value to add */
3850  SCIP_Longint val2 /**< second value to add */
3851  )
3852 {
3853  assert(val1 >= 0);
3854  assert(val2 >= 0);
3855 
3856  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3857  return SCIP_LONGINT_MAX;
3858  else
3859  {
3860  assert(val1 <= SCIP_LONGINT_MAX - val2);
3861  return (val1 + val2);
3862  }
3863 }
3864 
3865 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3866 static
3868  SCIP_Longint* minweights, /**< minweight table to compute */
3869  SCIP_Longint* finished, /**< given finished table */
3870  SCIP_Longint* unfinished, /**< given unfinished table */
3871  int minweightslen /**< length of minweight, finished, and unfinished tables */
3872  )
3873 {
3874  int w1;
3875  int w2;
3876 
3877  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3878  * note that finished and unfished arrays sorted by non-decreasing weight
3879  */
3880 
3881  /* initialize minweight with w2 = 0 */
3882  w2 = 0;
3883  assert(unfinished[w2] == 0);
3884  for( w1 = 0; w1 < minweightslen; w1++ )
3885  minweights[w1] = finished[w1];
3886 
3887  /* consider w2 = 1, ..., minweightslen-1 */
3888  for( w2 = 1; w2 < minweightslen; w2++ )
3889  {
3890  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3891  break;
3892 
3893  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3894  {
3895  SCIP_Longint temp;
3896 
3897  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3898  if( temp <= minweights[w1+w2] )
3899  minweights[w1+w2] = temp;
3900  }
3901  }
3902 }
3903 
3904 /** lifts given inequality
3905  * sum_{j in C_1} x_j <= alpha_0
3906  * valid for
3907  * 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;
3908  * sum_{j in Q_i} x_j <= 1, forall i in I }
3909  * to a valid inequality
3910  * 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
3911  * <= alpha_0 + sum_{j in C_2} alpha_j
3912  * for
3913  * 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 };
3914  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3915  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3916  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3917  */
3918 static
3920  SCIP* scip, /**< SCIP data structure */
3921  SCIP_GUBSET* gubset, /**< GUB set data structure */
3922  SCIP_VAR** vars, /**< variables in knapsack constraint */
3923  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3924  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3925  SCIP_Longint capacity, /**< capacity of knapsack */
3926  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3927  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3928  int* gubconsGC2, /**< GUBs in GC2 */
3929  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3930  int* gubconsGR, /**< GUBs in GR */
3931  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3932  int ngubconsGC2, /**< number of GUBs in GC2 */
3933  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3934  int ngubconsGR, /**< number of GUBs in GR */
3935  int alpha0, /**< rights hand side of given valid inequality */
3936  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3937  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3938  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3939  int maxgubvarssize /**< maximal size of GUB constraints */
3940  )
3941 {
3942  SCIP_Longint* minweights;
3943  SCIP_Longint* finished;
3944  SCIP_Longint* unfinished;
3945  int* gubconsGOC1;
3946  int* gubconsGNC1;
3947  int* liftgubvars;
3948  SCIP_Longint fixedonesweight;
3949  SCIP_Longint weight;
3950  SCIP_Longint weightdiff1;
3951  SCIP_Longint weightdiff2;
3952  SCIP_Longint min;
3953  int minweightssize;
3954  int minweightslen;
3955  int nvars;
3956  int varidx;
3957  int liftgubconsidx;
3958  int liftvar;
3959  int sumliftcoef;
3960  int liftcoef;
3961  int ngubconsGOC1;
3962  int ngubconsGNC1;
3963  int left;
3964  int right;
3965  int middle;
3966  int nliftgubvars;
3967  int tmplen;
3968  int tmpsize;
3969  int j;
3970  int k;
3971  int w;
3972  int z;
3973 #ifndef NDEBUG
3974  int ngubconss;
3975  int nliftgubC1;
3976 
3977  assert(gubset != NULL);
3978  ngubconss = gubset->ngubconss;
3979 #else
3980  assert(gubset != NULL);
3981 #endif
3982 
3983  nvars = gubset->nvars;
3984 
3985  assert(scip != NULL);
3986  assert(vars != NULL);
3987  assert(nvars >= 0);
3988  assert(weights != NULL);
3989  assert(capacity >= 0);
3990  assert(solvals != NULL);
3991  assert(gubconsGC1 != NULL);
3992  assert(gubconsGC2 != NULL);
3993  assert(gubconsGFC1 != NULL);
3994  assert(gubconsGR != NULL);
3995  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3996  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3997  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3998  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3999  assert(alpha0 >= 0);
4000  assert(liftcoefs != NULL);
4001  assert(cutact != NULL);
4002  assert(liftrhs != NULL);
4003 
4004  minweightssize = ngubconsGC1+1;
4005 
4006  /* allocates temporary memory */
4007  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4008  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4009  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4010  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4011  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4012  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4013 
4014  /* initializes data structures */
4015  BMSclearMemoryArray(liftcoefs, nvars);
4016  *cutact = 0.0;
4017 
4018  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4019  * valid inequality
4020  */
4021  ngubconsGOC1 = 0;
4022  ngubconsGNC1 = 0;
4023  for( j = 0; j < ngubconsGC1; j++ )
4024  {
4025  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4026  {
4027  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4028  ngubconsGOC1++;
4029  }
4030  else
4031  {
4032  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4033  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4034  ngubconsGNC1++;
4035  }
4036  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4037  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4038  {
4039  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4040  assert(varidx >= 0 && varidx < nvars);
4041  assert(liftcoefs[varidx] == 0);
4042 
4043  liftcoefs[varidx] = 1;
4044  (*cutact) += solvals[varidx];
4045  }
4046  assert(k >= 1);
4047  }
4048  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4049  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4050 
4051  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4052  * - finished_i[w] =
4053  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4054  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4055  * sum_{j in Q_k} x_j <= 1
4056  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4057  * - unfinished_i[w] =
4058  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4059  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4060  * sum_{j in Q_k} x_j <= 1
4061  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4062  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4063  */
4064 
4065  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4066  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4067  * 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
4068  * comes from the first variable in the GUB
4069  */
4070  assert(ngubconsGOC1 <= ngubconsGC1);
4071  finished[0] = 0;
4072  for( w = 1; w <= ngubconsGOC1; w++ )
4073  {
4074  liftgubconsidx = gubconsGOC1[w-1];
4075 
4076  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4077  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4078 
4079  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4080 
4081  assert(varidx >= 0 && varidx < nvars);
4082  assert(liftcoefs[varidx] == 1);
4083 
4084  min = weights[varidx];
4085  finished[w] = finished[w-1] + min;
4086 
4087 #ifndef NDEBUG
4088  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4089  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4090  {
4091  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4092  assert(varidx >= 0 && varidx < nvars);
4093  assert(liftcoefs[varidx] == 1);
4094  assert(weights[varidx] >= min);
4095  }
4096 #endif
4097  }
4098  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4099  finished[w] = SCIP_LONGINT_MAX;
4100 
4101  /* initialize unfinished table; note that variables in GNC1 GUBs
4102  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4103  * 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
4104  * comes from the first variable in the GUB
4105  */
4106  assert(ngubconsGNC1 <= ngubconsGC1);
4107  unfinished[0] = 0;
4108  for( w = 1; w <= ngubconsGNC1; w++ )
4109  {
4110  liftgubconsidx = gubconsGNC1[w-1];
4111 
4112  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4113  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4114 
4115  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4116 
4117  assert(varidx >= 0 && varidx < nvars);
4118  assert(liftcoefs[varidx] == 1);
4119 
4120  min = weights[varidx];
4121  unfinished[w] = unfinished[w-1] + min;
4122 
4123 #ifndef NDEBUG
4124  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4125  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4126  {
4127  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4128  assert(varidx >= 0 && varidx < nvars);
4129  assert(liftcoefs[varidx] == 1);
4130  assert(weights[varidx] >= min );
4131  }
4132 #endif
4133  }
4134  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4135  unfinished[w] = SCIP_LONGINT_MAX;
4136 
4137  /* initialize minweights table; note that variables in GC1 GUBs
4138  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4139  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4140  * consuming) because is it has to be build using weights from C1 only.
4141  */
4142  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4143  minweights[0] = 0;
4144  for( w = 1; w <= ngubconsGC1; w++ )
4145  {
4146  liftgubconsidx = gubconsGC1[w-1];
4147 
4148  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4149  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4150  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4151 
4152  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4153 
4154  assert(varidx >= 0 && varidx < nvars);
4155  assert(liftcoefs[varidx] == 1);
4156 
4157  min = weights[varidx];
4158  minweights[w] = minweights[w-1] + min;
4159 
4160 #ifndef NDEBUG
4161  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4162  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4163  {
4164  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4165  assert(varidx >= 0 && varidx < nvars);
4166  assert(liftcoefs[varidx] == 1);
4167  assert(weights[varidx] >= min);
4168  }
4169 #endif
4170  }
4171  minweightslen = ngubconsGC1 + 1;
4172 
4173  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4174  fixedonesweight = 0;
4175  for( j = 0; j < ngubconsGC2; j++ )
4176  {
4177  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4178 
4179  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4180  assert(varidx >= 0 && varidx < nvars);
4181  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4182 
4183  fixedonesweight += weights[varidx];
4184  }
4185  assert(fixedonesweight >= 0);
4186 
4187  /* initializes right hand side of lifted valid inequality */
4188  *liftrhs = alpha0;
4189 
4190  /* sequentially up-lifts all variables in GFC1 GUBs */
4191  for( j = 0; j < ngubconsGFC1; j++ )
4192  {
4193  liftgubconsidx = gubconsGFC1[j];
4194  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4195 
4196  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4197  * compute minweight table via updated unfinished table and aleady upto date finished table;
4198  */
4199  k = 0;
4200  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4201  {
4202  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4203  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4204  assert(ngubconsGNC1 > 0);
4205 
4206  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4207  * are considered for the lifting, i.e., not capacity exceeding
4208  */
4209  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4210  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4211  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4212  assert(k >= 1);
4213 
4214  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4215  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4216  */
4217  weight = weights[liftgubvars[0]];
4218 
4219  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4220  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4221  for( w = ngubconsGNC1-1; w >= 1; w-- )
4222  {
4223  weightdiff1 = weightdiff2;
4224  weightdiff2 = unfinished[w] - weight;
4225 
4226  if( unfinished[w] < weightdiff1 )
4227  unfinished[w] = weightdiff1;
4228  else
4229  break;
4230  }
4231  ngubconsGNC1--;
4232 
4233  /* computes minweights table by combining unfished and fished tables */
4234  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4235  assert(minweights[0] == 0);
4236  }
4237  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4238  * are therefore not in the unfinished table
4239  */
4240  else
4241  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4242 
4243 #ifndef NDEBUG
4244  nliftgubC1 = k;
4245 #endif
4246  nliftgubvars = k;
4247  sumliftcoef = 0;
4248 
4249  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4250  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4251  {
4252  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4253  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4254  {
4255  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4256  weight = weights[liftvar];
4257  assert(weight > 0);
4258  assert(liftvar >= 0 && liftvar < nvars);
4259  assert(capacity - weight >= 0);
4260 
4261  /* put variable into array of variables in GUB that are considered for the lifting,
4262  * i.e., not capacity exceeding
4263  */
4264  liftgubvars[nliftgubvars] = liftvar;
4265  nliftgubvars++;
4266 
4267  /* knapsack problem is infeasible:
4268  * sets z = 0
4269  */
4270  if( capacity - fixedonesweight - weight < 0 )
4271  {
4272  z = 0;
4273  }
4274  /* knapsack problem is feasible:
4275  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4276  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4277  */
4278  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4279  {
4280  z = *liftrhs;
4281  }
4282  /* knapsack problem is feasible:
4283  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4284  */
4285  else
4286  {
4287  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4288  left = 0;
4289  right = (*liftrhs) + 1;
4290  while( left < right - 1 )
4291  {
4292  middle = (left + right) / 2;
4293  assert(0 <= middle && middle < minweightslen);
4294  if( minweights[middle] <= capacity - fixedonesweight - weight )
4295  left = middle;
4296  else
4297  right = middle;
4298  }
4299  assert(left == right - 1);
4300  assert(0 <= left && left < minweightslen);
4301  assert(minweights[left] <= capacity - fixedonesweight - weight);
4302  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4303 
4304  /* now z = left */
4305  z = left;
4306  assert(z <= *liftrhs);
4307  }
4308 
4309  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4310  liftcoef = (*liftrhs) - z;
4311  liftcoefs[liftvar] = liftcoef;
4312  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4313 
4314  /* updates activity of current valid inequality */
4315  (*cutact) += liftcoef * solvals[liftvar];
4316 
4317  /* updates sum of all lifting coefficients in GUB */
4318  sumliftcoef += liftcoefs[liftvar];
4319  }
4320  else
4321  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4322  }
4323  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4324  assert(nliftgubvars > nliftgubC1);
4325 
4326  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4327  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4328  * not needed for GF GUBs
4329  */
4330  if( sumliftcoef == 0 )
4331  {
4332  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4333  {
4334  weight = weights[liftgubvars[0]];
4335  /* update finished table and minweights table by applying special case of
4336  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4337  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4338  */
4339  for( w = minweightslen-1; w >= 1; w-- )
4340  {
4341  SCIP_Longint tmpval;
4342 
4343  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4344  finished[w] = MIN(finished[w], tmpval);
4345 
4346  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4347  minweights[w] = MIN(minweights[w], tmpval);
4348  }
4349  }
4350  else
4351  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4352 
4353  continue;
4354  }
4355 
4356  /* enlarges current minweights tables(finished, unfinished, minweights):
4357  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4358  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4359  * and sets minweights_i[w] = infinity for
4360  * 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
4361  */
4362  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4363  tmpsize = minweightssize;
4364  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4365  tmplen = minweightslen;
4366  tmpsize = minweightssize;
4367  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4368  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4369 
4370  /* update finished table and minweight table;
4371  * note that instead of computing minweight table from updated finished and updated unfinished table again
4372  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4373  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4374  * not needed because only finished table changed at this point and the change was "adding" one weight)
4375  *
4376  * update formular for minweight table is: minweight_i+1[w] =
4377  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4378  * formular for finished table has the same pattern.
4379  */
4380  for( w = minweightslen-1; w >= 0; w-- )
4381  {
4382  SCIP_Longint minminweight;
4383  SCIP_Longint minfinished;
4384 
4385  for( k = 0; k < nliftgubvars; k++ )
4386  {
4387  liftcoef = liftcoefs[liftgubvars[k]];
4388  weight = weights[liftgubvars[k]];
4389 
4390  if( w < liftcoef )
4391  {
4392  minfinished = MIN(finished[w], weight);
4393  minminweight = MIN(minweights[w], weight);
4394 
4395  finished[w] = minfinished;
4396  minweights[w] = minminweight;
4397  }
4398  else
4399  {
4400  SCIP_Longint tmpval;
4401 
4402  assert(w >= liftcoef);
4403 
4404  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4405  minfinished = MIN(finished[w], tmpval);
4406 
4407  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4408  minminweight = MIN(minweights[w], tmpval);
4409 
4410  finished[w] = minfinished;
4411  minweights[w] = minminweight;
4412  }
4413  }
4414  }
4415  assert(minweights[0] == 0);
4416  }
4417  assert(ngubconsGNC1 == 0);
4418 
4419  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4420  * therefore, only work with minweight table from here on
4421  */
4422 
4423  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4424  for( j = 0; j < ngubconsGC2; j++ )
4425  {
4426  liftgubconsidx = gubconsGC2[j];
4427 
4428  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4429  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4430  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4431  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4432 
4433  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4434  weight = weights[liftvar];
4435 
4436  assert(liftvar >= 0 && liftvar < nvars);
4437  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4438  assert(weight > 0);
4439 
4440  /* uses binary search to find
4441  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4442  */
4443  left = 0;
4444  right = minweightslen;
4445  while( left < right - 1 )
4446  {
4447  middle = (left + right) / 2;
4448  assert(0 <= middle && middle < minweightslen);
4449  if( minweights[middle] <= capacity - fixedonesweight + weight )
4450  left = middle;
4451  else
4452  right = middle;
4453  }
4454  assert(left == right - 1);
4455  assert(0 <= left && left < minweightslen);
4456  assert(minweights[left] <= capacity - fixedonesweight + weight);
4457  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4458 
4459  /* now z = left */
4460  z = left;
4461  assert(z >= *liftrhs);
4462 
4463  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4464  liftcoef = z - (*liftrhs);
4465  liftcoefs[liftvar] = liftcoef;
4466  assert(liftcoef >= 0);
4467 
4468  /* updates sum of weights of variables fixed to one */
4469  fixedonesweight -= weight;
4470 
4471  /* updates right-hand side of current valid inequality */
4472  (*liftrhs) += liftcoef;
4473  assert(*liftrhs >= alpha0);
4474 
4475  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4476  if( liftcoef == 0 )
4477  continue;
4478 
4479  /* updates activity of current valid inequality */
4480  (*cutact) += liftcoef * solvals[liftvar];
4481 
4482  /* enlarges current minweight table:
4483  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4484  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4485  * and sets minweights_i[w] = infinity for
4486  * 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
4487  */
4488  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4489 
4490  /* updates minweight table: minweight_i+1[w] =
4491  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4492  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4493  */
4494  for( w = minweightslen - 1; w >= 0; w-- )
4495  {
4496  if( w < liftcoef )
4497  {
4498  min = MIN(minweights[w], weight);
4499  minweights[w] = min;
4500  }
4501  else
4502  {
4503  SCIP_Longint tmpval;
4504 
4505  assert(w >= liftcoef);
4506 
4507  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4508  min = MIN(minweights[w], tmpval);
4509  minweights[w] = min;
4510  }
4511  }
4512  }
4513  assert(fixedonesweight == 0);
4514  assert(*liftrhs >= alpha0);
4515 
4516  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4517  for( j = 0; j < ngubconsGR; j++ )
4518  {
4519  liftgubconsidx = gubconsGR[j];
4520 
4521  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4522  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4523 
4524  sumliftcoef = 0;
4525  nliftgubvars = 0;
4526  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4527  {
4528  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4529  {
4530  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4531  weight = weights[liftvar];
4532  assert(weight > 0);
4533  assert(liftvar >= 0 && liftvar < nvars);
4534  assert(capacity - weight >= 0);
4535  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4536 
4537  /* put variable into array of variables in GUB that are considered for the lifting,
4538  * i.e., not capacity exceeding
4539  */
4540  liftgubvars[nliftgubvars] = liftvar;
4541  nliftgubvars++;
4542 
4543  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4544  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4545  */
4546  if( minweights[*liftrhs] <= capacity - weight )
4547  {
4548  z = *liftrhs;
4549  }
4550  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4551  */
4552  else
4553  {
4554  left = 0;
4555  right = (*liftrhs) + 1;
4556  while( left < right - 1 )
4557  {
4558  middle = (left + right) / 2;
4559  assert(0 <= middle && middle < minweightslen);
4560  if( minweights[middle] <= capacity - weight )
4561  left = middle;
4562  else
4563  right = middle;
4564  }
4565  assert(left == right - 1);
4566  assert(0 <= left && left < minweightslen);
4567  assert(minweights[left] <= capacity - weight);
4568  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4569 
4570  /* now z = left */
4571  z = left;
4572  assert(z <= *liftrhs);
4573  }
4574  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4575  liftcoef = (*liftrhs) - z;
4576  liftcoefs[liftvar] = liftcoef;
4577  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4578 
4579  /* updates activity of current valid inequality */
4580  (*cutact) += liftcoef * solvals[liftvar];
4581 
4582  /* updates sum of all lifting coefficients in GUB */
4583  sumliftcoef += liftcoefs[liftvar];
4584  }
4585  else
4586  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4587  }
4588  assert(nliftgubvars >= 1); /* at least one variable is in R */
4589 
4590  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4591  if( sumliftcoef == 0 )
4592  continue;
4593 
4594  /* updates minweight table: minweight_i+1[w] =
4595  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4596  */
4597  for( w = *liftrhs; w >= 0; w-- )
4598  {
4599  for( k = 0; k < nliftgubvars; k++ )
4600  {
4601  liftcoef = liftcoefs[liftgubvars[k]];
4602  weight = weights[liftgubvars[k]];
4603 
4604  if( w < liftcoef )
4605  {
4606  min = MIN(minweights[w], weight);
4607  minweights[w] = min;
4608  }
4609  else
4610  {
4611  SCIP_Longint tmpval;
4612 
4613  assert(w >= liftcoef);
4614 
4615  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4616  min = MIN(minweights[w], tmpval);
4617  minweights[w] = min;
4618  }
4619  }
4620  }
4621  assert(minweights[0] == 0);
4622  }
4623 
4624  /* frees temporary memory */
4625  SCIPfreeBufferArray(scip, &minweights);
4626  SCIPfreeBufferArray(scip, &finished);
4627  SCIPfreeBufferArray(scip, &unfinished);
4628  SCIPfreeBufferArray(scip, &liftgubvars);
4629  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4630  SCIPfreeBufferArray(scip, &gubconsGNC1);
4631 
4632  return SCIP_OKAY;
4633 }
4634 
4635 /** lifts given minimal cover inequality
4636  * \f[
4637  * \sum_{j \in C} x_j \leq |C| - 1
4638  * \f]
4639  * valid for
4640  * \f[
4641  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4642  * \f]
4643  * to a valid inequality
4644  * \f[
4645  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4646  * \f]
4647  * for
4648  * \f[
4649  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4650  * \f]
4651  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4652  */
4653 static
4655  SCIP* scip, /**< SCIP data structure */
4656  SCIP_VAR** vars, /**< variables in knapsack constraint */
4657  int nvars, /**< number of variables in knapsack constraint */
4658  int ntightened, /**< number of variables with tightened upper bound */
4659  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4660  SCIP_Longint capacity, /**< capacity of knapsack */
4661  SCIP_Real* solvals, /**< solution values of all problem variables */
4662  int* covervars, /**< cover variables */
4663  int* noncovervars, /**< noncover variables */
4664  int ncovervars, /**< number of cover variables */
4665  int nnoncovervars, /**< number of noncover variables */
4666  SCIP_Longint coverweight, /**< weight of cover */
4667  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4668  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4669  )
4670 {
4671  SCIP_Longint* maxweightsums;
4672  SCIP_Longint* intervalends;
4673  SCIP_Longint* rhos;
4674  SCIP_Real* sortkeys;
4675  SCIP_Longint lambda;
4676  int j;
4677  int h;
4678 
4679  assert(scip != NULL);
4680  assert(vars != NULL);
4681  assert(nvars >= 0);
4682  assert(weights != NULL);
4683  assert(capacity >= 0);
4684  assert(solvals != NULL);
4685  assert(covervars != NULL);
4686  assert(noncovervars != NULL);
4687  assert(ncovervars > 0 && ncovervars <= nvars);
4688  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4689  assert(ncovervars + nnoncovervars == nvars - ntightened);
4690  assert(liftcoefs != NULL);
4691  assert(cutact != NULL);
4692 
4693  /* allocates temporary memory */
4694  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4695  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4696  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4697  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4698 
4699  /* initializes data structures */
4700  BMSclearMemoryArray(liftcoefs, nvars);
4701  *cutact = 0.0;
4702 
4703  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4704  * and calculates activity of current valid inequality
4705  */
4706  for( j = 0; j < ncovervars; j++ )
4707  {
4708  assert(liftcoefs[covervars[j]] == 0.0);
4709  liftcoefs[covervars[j]] = 1.0;
4710  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4711  (*cutact) += solvals[covervars[j]];
4712  }
4713  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4714 
4715  /* calculates weight excess of cover C */
4716  lambda = coverweight - capacity;
4717  assert(lambda > 0);
4718 
4719  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4720  maxweightsums[0] = 0;
4721  for( h = 1; h <= ncovervars; h++ )
4722  {
4723  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4724  intervalends[h-1] = maxweightsums[h] - lambda;
4725  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4726  }
4727 
4728  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4729  for( j = 0; j < nnoncovervars; j++ )
4730  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4731  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4732 
4733  /* calculates lifting coefficient for all variables in N\C */
4734  h = 0;
4735  for( j = 0; j < nnoncovervars; j++ )
4736  {
4737  int liftvar;
4738  SCIP_Longint weight;
4739  SCIP_Real liftcoef;
4740 
4741  liftvar = noncovervars[j];
4742  weight = weights[liftvar];
4743 
4744  while( intervalends[h] < weight )
4745  h++;
4746 
4747  if( h == 0 )
4748  liftcoef = h;
4749  else
4750  {
4751  if( weight <= intervalends[h-1] + rhos[h] )
4752  {
4753  SCIP_Real tmp1;
4754  SCIP_Real tmp2;
4755  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4756  tmp2 = (SCIP_Real) rhos[1];
4757  liftcoef = h - ( tmp1 / tmp2 );
4758  }
4759  else
4760  liftcoef = h;
4761  }
4762 
4763  /* sets lifting coefficient */
4764  assert(liftcoefs[liftvar] == 0.0);
4765  liftcoefs[liftvar] = liftcoef;
4766 
4767  /* updates activity of current valid inequality */
4768  (*cutact) += liftcoef * solvals[liftvar];
4769  }
4770 
4771  /* frees temporary memory */
4772  SCIPfreeBufferArray(scip, &rhos);
4773  SCIPfreeBufferArray(scip, &intervalends);
4774  SCIPfreeBufferArray(scip, &maxweightsums);
4775  SCIPfreeBufferArray(scip, &sortkeys);
4776 
4777  return SCIP_OKAY;
4778 }
4779 
4780 
4781 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4782  * given knapsack problem
4783 */
4784 static
4786  SCIP* scip, /**< SCIP data structure */
4787  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4788  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4789  SCIP_VAR** vars, /**< variables in knapsack constraint */
4790  int nvars, /**< number of variables in knapsack constraint */
4791  int ntightened, /**< number of variables with tightened upper bound */
4792  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4793  SCIP_Longint capacity, /**< capacity of knapsack */
4794  SCIP_Real* solvals, /**< solution values of all problem variables */
4795  int* mincovervars, /**< mincover variables */
4796  int* nonmincovervars, /**< nonmincover variables */
4797  int nmincovervars, /**< number of mincover variables */
4798  int nnonmincovervars, /**< number of nonmincover variables */
4799  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4800  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4801  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4802  int* ncuts /**< pointer to add up the number of found cuts */
4803  )
4804 {
4805  int* varsC1;
4806  int* varsC2;
4807  int* varsF;
4808  int* varsR;
4809  int nvarsC1;
4810  int nvarsC2;
4811  int nvarsF;
4812  int nvarsR;
4813  SCIP_Real cutact;
4814  int* liftcoefs;
4815  int liftrhs;
4816 
4817  assert( cutoff != NULL );
4818  *cutoff = FALSE;
4819 
4820  /* allocates temporary memory */
4821  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4822  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4823  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4824  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4825  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4826 
4827  /* 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
4828  * as follows
4829  * C_2 = { j in C : x*_j = 1 } and
4830  * C_1 = C\C_2
4831  */
4832  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4833  assert(nvarsC1 + nvarsC2 == nmincovervars);
4834  assert(nmincovervars > 0);
4835  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4836 
4837  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4838  if( nvarsC1 < 2 && nvarsC2 > 0)
4839  {
4840  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4841  assert(nvarsC1 >= 1);
4842  }
4843  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4844 
4845  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4846  * R = { j in N\C : x*_j = 0 } and
4847  * F = (N\C)\F
4848  */
4849  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4850  assert(nvarsF + nvarsR == nnonmincovervars);
4851  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4852 
4853  /* lift cuts without GUB information */
4854  if( gubset == NULL )
4855  {
4856  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4857  * lifting procedure
4858  */
4859  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4860 
4861  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4862  *
4863  * 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 }
4864  *
4865  * 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
4866  *
4867  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4868  *
4869  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4870  * up-lifting for the variables in R according to the second level lifting sequence
4871  */
4872  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4873  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4874  }
4875  /* lift cuts with GUB information */
4876  else
4877  {
4878  int* gubconsGC1;
4879  int* gubconsGC2;
4880  int* gubconsGFC1;
4881  int* gubconsGR;
4882  int ngubconsGC1;
4883  int ngubconsGC2;
4884  int ngubconsGFC1;
4885  int ngubconsGR;
4886  int ngubconss;
4887  int nconstightened;
4888  int maxgubvarssize;
4889 
4890  assert(nvars == gubset->nvars);
4891 
4892  ngubconsGC1 = 0;
4893  ngubconsGC2 = 0;
4894  ngubconsGFC1 = 0;
4895  ngubconsGR = 0;
4896  ngubconss = gubset->ngubconss;
4897  nconstightened = 0;
4898  maxgubvarssize = 0;
4899 
4900  /* allocates temporary memory */
4901  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4902  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4903  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4904  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4905 
4906  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4907  * the GUBs for the sequential GUB wise lifting procedure
4908  */
4909  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4910  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4911  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4912 
4913  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4914  *
4915  * 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,
4916  * sum_{j in Q_i} x_j <= 1, forall i in I }
4917  *
4918  * 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
4919  *
4920  * 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 },
4921  *
4922  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4923  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4924  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4925  */
4926  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4927  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4928  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4929 
4930  /* frees temporary memory */
4931  SCIPfreeBufferArray(scip, &gubconsGR);
4932  SCIPfreeBufferArray(scip, &gubconsGFC1);
4933  SCIPfreeBufferArray(scip, &gubconsGC2);
4934  SCIPfreeBufferArray(scip, &gubconsGC1);
4935  }
4936 
4937  /* checks, if lifting yielded a violated cut */
4938  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4939  {
4940  SCIP_ROW* row;
4941  char name[SCIP_MAXSTRLEN];
4942  int j;
4943 
4944  /* creates LP row */
4945  assert( cons == NULL || sepa == NULL );
4946  if ( cons != NULL )
4947  {
4948  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4949  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4950  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4951  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4952  }
4953  else if ( sepa != NULL )
4954  {
4955  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4956  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4957  }
4958  else
4959  {
4960  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4961  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4962  }
4963 
4964  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4965  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4966  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4967  for( j = 0; j < nvarsC1; j++ )
4968  {
4969  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4970  }
4971  for( j = 0; j < nvarsC2; j++ )
4972  {
4973  if( liftcoefs[varsC2[j]] > 0 )
4974  {
4975  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4976  }
4977  }
4978  for( j = 0; j < nvarsF; j++ )
4979  {
4980  if( liftcoefs[varsF[j]] > 0 )
4981  {
4982  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4983  }
4984  }
4985  for( j = 0; j < nvarsR; j++ )
4986  {
4987  if( liftcoefs[varsR[j]] > 0 )
4988  {
4989  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4990  }
4991  }
4992  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4993 
4994  /* checks, if cut is violated enough */
4995  if( SCIPisCutEfficacious(scip, sol, row) )
4996  {
4997  if( cons != NULL )
4998  {
4999  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5000  }
5001  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5002  (*ncuts)++;
5003  }
5004  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5005  }
5006 
5007  /* frees temporary memory */
5008  SCIPfreeBufferArray(scip, &liftcoefs);
5009  SCIPfreeBufferArray(scip, &varsR);
5010  SCIPfreeBufferArray(scip, &varsF);
5011  SCIPfreeBufferArray(scip, &varsC2);
5012  SCIPfreeBufferArray(scip, &varsC1);
5013 
5014  return SCIP_OKAY;
5015 }
5016 
5017 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5018 static
5020  SCIP* scip, /**< SCIP data structure */
5021  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5022  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5023  SCIP_VAR** vars, /**< variables in knapsack constraint */
5024  int nvars, /**< number of variables in knapsack constraint */
5025  int ntightened, /**< number of variables with tightened upper bound */
5026  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5027  SCIP_Longint capacity, /**< capacity of knapsack */
5028  SCIP_Real* solvals, /**< solution values of all problem variables */
5029  int* feassetvars, /**< variables in feasible set */
5030  int* nonfeassetvars, /**< variables not in feasible set */
5031  int nfeassetvars, /**< number of variables in feasible set */
5032  int nnonfeassetvars, /**< number of variables not in feasible set */
5033  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5034  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5035  int* ncuts /**< pointer to add up the number of found cuts */
5036  )
5037 {
5038  int* varsT1;
5039  int* varsT2;
5040  int* varsF;
5041  int* varsR;
5042  int* liftcoefs;
5043  SCIP_Real cutact;
5044  int nvarsT1;
5045  int nvarsT2;
5046  int nvarsF;
5047  int nvarsR;
5048  int liftrhs;
5049  int j;
5050 
5051  assert( cutoff != NULL );
5052  *cutoff = FALSE;
5053 
5054  /* allocates temporary memory */
5055  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5056  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5057  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5058  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5059  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5060 
5061  /* 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
5062  * as follows
5063  * T_2 = { j in T : x*_j = 1 } and
5064  * T_1 = T\T_2
5065  */
5066  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5067  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5068 
5069  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5070  if( nvarsT1 == 0 && nvarsT2 > 0)
5071  {
5072  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5073  assert(nvarsT1 == 1);
5074  }
5075  assert(nvarsT2 == 0 || nvarsT1 > 0);
5076 
5077  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5078  * R = { j in N\T : x*_j = 0 } and
5079  * F = (N\T)\F
5080  */
5081  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5082  assert(nvarsF + nvarsR == nnonfeassetvars);
5083  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5084 
5085  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5086  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5087  * is included in the sorting routine)
5088  */
5089  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5090 
5091  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5092  *
5093  * 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 }
5094  *
5095  * 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
5096  *
5097  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5098  *
5099  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5100  * up-lifting for the variabels in R according to the second level lifting sequence
5101  */
5102  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5103  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5104 
5105  /* checks, if lifting yielded a violated cut */
5106  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5107  {
5108  SCIP_ROW* row;
5109  char name[SCIP_MAXSTRLEN];
5110 
5111  /* creates LP row */
5112  assert( cons == NULL || sepa == NULL );
5113  if( cons != NULL )
5114  {
5115  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5116  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5117  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5118  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5119  }
5120  else if ( sepa != NULL )
5121  {
5122  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5123  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5124  }
5125  else
5126  {
5127  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5128  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5129  }
5130 
5131  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5132  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5133  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5134  for( j = 0; j < nvarsT1; j++ )
5135  {
5136  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5137  }
5138  for( j = 0; j < nvarsT2; j++ )
5139  {
5140  if( liftcoefs[varsT2[j]] > 0 )
5141  {
5142  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5143  }
5144  }
5145  for( j = 0; j < nvarsF; j++ )
5146  {
5147  if( liftcoefs[varsF[j]] > 0 )
5148  {
5149  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5150  }
5151  }
5152  for( j = 0; j < nvarsR; j++ )
5153  {
5154  if( liftcoefs[varsR[j]] > 0 )
5155  {
5156  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5157  }
5158  }
5159  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5160 
5161  /* checks, if cut is violated enough */
5162  if( SCIPisCutEfficacious(scip, sol, row) )
5163  {
5164  if( cons != NULL )
5165  {
5166  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5167  }
5168  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5169  (*ncuts)++;
5170  }
5171  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5172  }
5173 
5174  /* frees temporary memory */
5175  SCIPfreeBufferArray(scip, &liftcoefs);
5176  SCIPfreeBufferArray(scip, &varsR);
5177  SCIPfreeBufferArray(scip, &varsF);
5178  SCIPfreeBufferArray(scip, &varsT2);
5179  SCIPfreeBufferArray(scip, &varsT1);
5180 
5181  return SCIP_OKAY;
5182 }
5183 
5184 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5185 static
5187  SCIP* scip, /**< SCIP data structure */
5188  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5189  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5190  SCIP_VAR** vars, /**< variables in knapsack constraint */
5191  int nvars, /**< number of variables in knapsack constraint */
5192  int ntightened, /**< number of variables with tightened upper bound */
5193  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5194  SCIP_Longint capacity, /**< capacity of knapsack */
5195  SCIP_Real* solvals, /**< solution values of all problem variables */
5196  int* mincovervars, /**< mincover variables */
5197  int* nonmincovervars, /**< nonmincover variables */
5198  int nmincovervars, /**< number of mincover variables */
5199  int nnonmincovervars, /**< number of nonmincover variables */
5200  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5201  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5202  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5203  int* ncuts /**< pointer to add up the number of found cuts */
5204  )
5205 {
5206  SCIP_Real* realliftcoefs;
5207  SCIP_Real cutact;
5208  int liftrhs;
5209 
5210  assert( cutoff != NULL );
5211  *cutoff = FALSE;
5212  cutact = 0.0;
5213 
5214  /* allocates temporary memory */
5215  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5216 
5217  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5218  *
5219  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5220  *
5221  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5222  *
5223  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5224  *
5225  * uses superadditive up-lifting for the variables in N\C.
5226  */
5227  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5228  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5229  liftrhs = nmincovervars - 1;
5230 
5231  /* checks, if lifting yielded a violated cut */
5232  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5233  {
5234  SCIP_ROW* row;
5235  char name[SCIP_MAXSTRLEN];
5236  int j;
5237 
5238  /* creates LP row */
5239  assert( cons == NULL || sepa == NULL );
5240  if ( cons != NULL )
5241  {
5242  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5243  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5244  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5245  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5246  }
5247  else if ( sepa != NULL )
5248  {
5249  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5250  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5251  }
5252  else
5253  {
5254  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5255  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5256  }
5257 
5258  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5259  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5260  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5261  for( j = 0; j < nmincovervars; j++ )
5262  {
5263  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5264  }
5265  for( j = 0; j < nnonmincovervars; j++ )
5266  {
5267  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5268  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5269  {
5270  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5271  }
5272  }
5273  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5274 
5275  /* checks, if cut is violated enough */
5276  if( SCIPisCutEfficacious(scip, sol, row) )
5277  {
5278  if( cons != NULL )
5279  {
5280  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5281  }
5282  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5283  (*ncuts)++;
5284  }
5285  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5286  }
5287 
5288  /* frees temporary memory */
5289  SCIPfreeBufferArray(scip, &realliftcoefs);
5290 
5291  return SCIP_OKAY;
5292 }
5293 
5294 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5295  * 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
5296  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5297  * note that all variables with x*_j = 1 will be removed last
5298  */
5299 static
5301  SCIP* scip, /**< SCIP data structure */
5302  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5303  SCIP_Longint capacity, /**< capacity of knapsack */
5304  SCIP_Real* solvals, /**< solution values of all problem variables */
5305  int* covervars, /**< pointer to store cover variables */
5306  int* noncovervars, /**< pointer to store noncover variables */
5307  int* ncovervars, /**< pointer to store number of cover variables */
5308  int* nnoncovervars, /**< pointer to store number of noncover variables */
5309  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5310  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5311  )
5312 {
5313  SORTKEYPAIR** sortkeypairs;
5314  SORTKEYPAIR** sortkeypairssorted;
5315  SCIP_Longint minweight;
5316  int nsortkeypairs;
5317  int minweightidx;
5318  int j;
5319  int k;
5320 
5321  assert(scip != NULL);
5322  assert(covervars != NULL);
5323  assert(noncovervars != NULL);
5324  assert(ncovervars != NULL);
5325  assert(*ncovervars > 0);
5326  assert(nnoncovervars != NULL);
5327  assert(*nnoncovervars >= 0);
5328  assert(coverweight != NULL);
5329  assert(*coverweight > 0);
5330  assert(*coverweight > capacity);
5331 
5332  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5333  * order */
5334  nsortkeypairs = *ncovervars;
5335  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5336  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5337 
5338  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5339  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5340  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5341  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5342  */
5343  assert(*ncovervars == nsortkeypairs);
5344  if( modtransused )
5345  {
5346  for( j = 0; j < *ncovervars; j++ )
5347  {
5348  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5349  sortkeypairssorted[j] = sortkeypairs[j];
5350 
5351  sortkeypairs[j]->key1 = solvals[covervars[j]];
5352  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5353  }
5354  }
5355  else
5356  {
5357  for( j = 0; j < *ncovervars; j++ )
5358  {
5359  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5360  sortkeypairssorted[j] = sortkeypairs[j];
5361 
5362  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5363  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5364  }
5365  }
5366  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5367 
5368  /* gets j' with a_j' = min{ a_j : j in C } */
5369  minweightidx = 0;
5370  minweight = weights[covervars[minweightidx]];
5371  for( j = 1; j < *ncovervars; j++ )
5372  {
5373  if( weights[covervars[j]] <= minweight )
5374  {
5375  minweightidx = j;
5376  minweight = weights[covervars[minweightidx]];
5377  }
5378  }
5379  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5380  assert(minweight > 0 && minweight <= *coverweight);
5381 
5382  j = 0;
5383  /* removes variables from C until the remaining variables form a minimal cover */
5384  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5385  {
5386  assert(minweightidx >= j);
5387  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5388 
5389  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5390  if( (*coverweight) - weights[covervars[j]] <= capacity )
5391  {
5392  ++j;
5393  continue;
5394  }
5395 
5396  /* adds j to N\C */
5397  noncovervars[*nnoncovervars] = covervars[j];
5398  (*nnoncovervars)++;
5399 
5400  /* removes j from C */
5401  (*coverweight) -= weights[covervars[j]];
5402  for( k = j; k < (*ncovervars) - 1; k++ )
5403  covervars[k] = covervars[k+1];
5404  (*ncovervars)--;
5405 
5406  /* updates j' with a_j' = min{ a_j : j in C } */
5407  if( j == minweightidx )
5408  {
5409  minweightidx = 0;
5410  minweight = weights[covervars[minweightidx]];
5411  for( k = 1; k < *ncovervars; k++ )
5412  {
5413  if( weights[covervars[k]] <= minweight )
5414  {
5415  minweightidx = k;
5416  minweight = weights[covervars[minweightidx]];
5417  }
5418  }
5419  assert(minweight > 0 && minweight <= *coverweight);
5420  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5421  }
5422  else
5423  {
5424  assert(minweightidx > j);
5425  minweightidx--;
5426  }
5427  /* j needs to stay the same */
5428  }
5429  assert((*coverweight) > capacity);
5430  assert((*coverweight) - minweight <= capacity);
5431 
5432  /* frees temporary memory */
5433  for( j = nsortkeypairs-1; j >= 0; j-- )
5434  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5435  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5436  SCIPfreeBufferArray(scip, &sortkeypairs);
5437 
5438  return SCIP_OKAY;
5439 }
5440 
5441 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5442  * they were chosen to be in C_init:
5443  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5444  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5445  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5446  * and all subsequent feasible sets.
5447  */
5448 static
5450  SCIP* scip, /**< SCIP data structure */
5451  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5452  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5453  SCIP_VAR** vars, /**< variables in knapsack constraint */
5454  int nvars, /**< number of variables in knapsack constraint */
5455  int ntightened, /**< number of variables with tightened upper bound */
5456  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5457  SCIP_Longint capacity, /**< capacity of knapsack */
5458  SCIP_Real* solvals, /**< solution values of all problem variables */
5459  int* covervars, /**< pointer to store cover variables */
5460  int* noncovervars, /**< pointer to store noncover variables */
5461  int* ncovervars, /**< pointer to store number of cover variables */
5462  int* nnoncovervars, /**< pointer to store number of noncover variables */
5463  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5464  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5465  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5466  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5467  int* ncuts /**< pointer to add up the number of found cuts */
5468  )
5469 {
5470  SCIP_Real* sortkeys;
5471  int j;
5472  int k;
5473 
5474  assert(scip != NULL);
5475  assert(covervars != NULL);
5476  assert(noncovervars != NULL);
5477  assert(ncovervars != NULL);
5478  assert(*ncovervars > 0);
5479  assert(nnoncovervars != NULL);
5480  assert(*nnoncovervars >= 0);
5481  assert(coverweight != NULL);
5482  assert(*coverweight > 0);
5483  assert(*coverweight > capacity);
5484  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5485  assert(cutoff != NULL);
5486 
5487  *cutoff = FALSE;
5488 
5489  /* allocates temporary memory */
5490  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5491 
5492  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5493  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5494  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5495  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5496  */
5497  if( modtransused )
5498  {
5499  for( j = 0; j < *ncovervars; j++ )
5500  {
5501  sortkeys[j] = solvals[covervars[j]];
5502  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5503  }
5504  }
5505  else
5506  {
5507  for( j = 0; j < *ncovervars; j++ )
5508  {
5509  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5510  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5511  }
5512  }
5513  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5514 
5515  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5516  * in addition to an extended weight inequality this gives cardinality inequalities */
5517  while( *ncovervars >= 2 )
5518  {
5519  /* adds first element of C_init to N\C_init */
5520  noncovervars[*nnoncovervars] = covervars[0];
5521  (*nnoncovervars)++;
5522 
5523  /* removes first element from C_init */
5524  (*coverweight) -= weights[covervars[0]];
5525  for( k = 0; k < (*ncovervars) - 1; k++ )
5526  covervars[k] = covervars[k+1];
5527  (*ncovervars)--;
5528 
5529  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5530  if( (*coverweight) <= capacity )
5531  {
5532  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5533  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5534  }
5535 
5536  /* stop if cover is too large */
5537  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5538  break;
5539  }
5540 
5541  /* frees temporary memory */
5542  SCIPfreeBufferArray(scip, &sortkeys);
5543 
5544  return SCIP_OKAY;
5545 }
5546 
5547 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5549  SCIP* scip, /**< SCIP data structure */
5550  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5551  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5552  SCIP_VAR** vars, /**< variables in knapsack constraint */
5553  int nvars, /**< number of variables in knapsack constraint */
5554  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5555  SCIP_Longint capacity, /**< capacity of knapsack */
5556  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5557  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5558  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5559  int* ncuts /**< pointer to add up the number of found cuts */
5560  )
5561 {
5562  SCIP_Real* solvals;
5563  int* covervars;
5564  int* noncovervars;
5565  SCIP_Bool coverfound;
5566  SCIP_Bool fractional;
5567  SCIP_Bool modtransused;
5568  SCIP_Longint coverweight;
5569  int ncovervars;
5570  int nnoncovervars;
5571  int ntightened;
5572 
5573  assert(scip != NULL);
5574  assert(capacity >= 0);
5575  assert(cutoff != NULL);
5576  assert(ncuts != NULL);
5577 
5578  *cutoff = FALSE;
5579 
5580  if( nvars == 0 )
5581  return SCIP_OKAY;
5582 
5583  assert(vars != NULL);
5584  assert(nvars > 0);
5585  assert(weights != NULL);
5586 
5587  /* increase age of constraint (age is reset to zero, if a cut was found) */
5588  if( cons != NULL )
5589  {
5590  SCIP_CALL( SCIPincConsAge(scip, cons) );
5591  }
5592 
5593  /* allocates temporary memory */
5594  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5595  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5596  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5597 
5598  /* gets solution values of all problem variables */
5599  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5600 
5601 #ifdef SCIP_DEBUG
5602  {
5603  int i;
5604 
5605  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5606  cons == NULL ? "-" : SCIPconsGetName(cons));
5607  for( i = 0; i < nvars; ++i )
5608  {
5609  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5610  }
5611  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5612  }
5613 #endif
5614 
5615  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5616  */
5617  if( usegubs )
5618  {
5619  SCIP_GUBSET* gubset;
5620 
5621  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5622 
5623  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5624  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5625 
5626  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5627  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5628  assert(gubset->ngubconss <= nvars);
5629 
5630  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5631  * MODIFIED transformed separation problem and taking into account the following fixing:
5632  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5633  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5634  * if one exists
5635  */
5636  modtransused = TRUE;
5637  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5638  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5639 
5640  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5641 
5642  /* if x* is not fractional we stop the separation routine */
5643  if( !fractional )
5644  {
5645  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5646 
5647  /* frees memory for GUB set data structure */
5648  GUBsetFree(scip, &gubset);
5649 
5650  goto TERMINATE;
5651  }
5652 
5653  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5654  if( coverfound )
5655  {
5656  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5657  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5658  */
5659  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5660  &nnoncovervars, &coverweight, modtransused) );
5661 
5662  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5663  if( gubset->ngubconss < nvars )
5664  {
5665  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5666  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5667  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5668  }
5669  else
5670  {
5671  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5672  * GUB information
5673  */
5674  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5675  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5676  }
5677  }
5678 
5679  /* frees memory for GUB set data structure */
5680  GUBsetFree(scip, &gubset);
5681  }
5682  else
5683  {
5684  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5685  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5686  */
5687 
5688  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5689  * MODIFIED transformed separation problem and taking into account the following fixing:
5690  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5691  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5692  * if one exists
5693  */
5694  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5695  modtransused = TRUE;
5696  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5697  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5698  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5699 
5700  /* if x* is not fractional we stop the separation routine */
5701  if( !fractional )
5702  goto TERMINATE;
5703 
5704  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5705  if( coverfound )
5706  {
5707  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5708  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5709  */
5710  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5711  &nnoncovervars, &coverweight, modtransused) );
5712 
5713  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5714  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5715  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5716 
5717  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5718  {
5719  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5720  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5721  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5722  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5723  }
5724  }
5725  }
5726 
5727  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5728  if ( ! (*cutoff) )
5729  {
5730  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5731  * transformed separation problem and taking into account the following fixing:
5732  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5733  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5734  * if one exists
5735  */
5736  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5737  modtransused = FALSE;
5738  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5739  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5740  assert(fractional);
5741  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5742 
5743  /* if no cover was found we stop the separation routine */
5744  if( coverfound )
5745  {
5746  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5747  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5748  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5749  */
5750  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5751  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5752  }
5753  }
5754 
5755  TERMINATE:
5756  /* frees temporary memory */
5757  SCIPfreeBufferArray(scip, &noncovervars);
5758  SCIPfreeBufferArray(scip, &covervars);
5759  SCIPfreeBufferArray(scip, &solvals);
5760 
5761  return SCIP_OKAY;
5762 }
5763 
5764 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5766  SCIP* scip, /**< SCIP data structure */
5767  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5768  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5769  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5770  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5771  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5772  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5773  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5774  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5775  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5776  int* ncuts /**< pointer to add up the number of found cuts */
5777  )
5778 {
5779  SCIP_VAR** binvars;
5780  SCIP_VAR** consvars;
5781  SCIP_Real* binvals;
5782  SCIP_Longint* consvals;
5783  SCIP_Longint minact;
5784  SCIP_Longint maxact;
5785  SCIP_Real intscalar;
5786  SCIP_Bool success;
5787  int nbinvars;
5788  int nconsvars;
5789  int i;
5790 
5791  int* tmpindices;
5792  int tmp;
5793  SCIP_CONSHDLR* conshdlr;
5794  SCIP_CONSHDLRDATA* conshdlrdata;
5795  SCIP_Bool noknapsackconshdlr;
5796  SCIP_Bool usegubs;
5797 
5798  assert(nknapvars > 0);
5799  assert(knapvars != NULL);
5800  assert(cutoff != NULL);
5801 
5802  tmpindices = NULL;
5803 
5804  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5805  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5806 
5807  binvars = SCIPgetVars(scip);
5808 
5809  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5810  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5811 
5812  *cutoff = FALSE;
5813 
5814  if( nbinvars == 0 )
5815  return SCIP_OKAY;
5816 
5817  /* set up data structures */
5818  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5819  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5820 
5821  /* get conshdlrdata to use cleared memory */
5822  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5823  if( conshdlr == NULL )
5824  {
5825  noknapsackconshdlr = TRUE;
5826  usegubs = DEFAULT_USEGUBS;
5827 
5828  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5829  BMSclearMemoryArray(binvals, nbinvars);
5830  }
5831  else
5832  {
5833  noknapsackconshdlr = FALSE;
5834  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5835  assert(conshdlrdata != NULL);
5836  usegubs = conshdlrdata->usegubs;
5837 
5838  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5839 
5840  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5841  * change their types to SCIP_VARTYPE_BINARY during presolving
5842  */
5843  if( conshdlrdata->reals1size == 0 )
5844  {
5845  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5846  conshdlrdata->reals1size = 1;
5847  conshdlrdata->reals1[0] = 0.0;
5848  }
5849 
5850  assert(conshdlrdata->reals1size > 0);
5851 
5852  /* next if condition should normally not be true, because it means that presolving has created more binary
5853  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5854  * transform all integers into their binary representation then it maybe happens
5855  */
5856  if( conshdlrdata->reals1size < nbinvars )
5857  {
5858  int oldsize = conshdlrdata->reals1size;
5859 
5860  conshdlrdata->reals1size = nbinvars;
5861  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5862  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5863  }
5864  binvals = conshdlrdata->reals1;
5865 
5866  /* check for cleared array, all entries have to be zero */
5867 #ifndef NDEBUG
5868  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5869  {
5870  assert(binvals[tmp] == 0);
5871  }
5872 #endif
5873  }
5874 
5875  tmp = 0;
5876 
5877  /* relax continuous knapsack constraint:
5878  * 1. make all variables binary:
5879  * if x_j is continuous or integer variable substitute:
5880  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5881  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5882  * 2. convert coefficients of all variables to positive integers:
5883  * - scale all coefficients a_j to a~_j integral
5884  * - substitute x~_j = 1 - x_j if a~_j < 0
5885  */
5886 
5887  /* replace integer and continuous variables with binary variables */
5888  for( i = 0; i < nknapvars; i++ )
5889  {
5890  SCIP_VAR* var;
5891 
5892  var = knapvars[i];
5893 
5894  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5895  {
5896  SCIP_Real solval;
5897  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5898 
5899  solval = SCIPgetSolVal(scip, sol, var);
5900 
5901  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5902  if( SCIPisFeasLT(scip, solval, 0.0 )
5903  || SCIPisFeasGT(scip, solval, 1.0) )
5904  {
5905  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5906  solval, SCIPvarGetName(var));
5907  goto TERMINATE;
5908  }
5909 
5910  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5911  if( !noknapsackconshdlr )
5912  {
5913  assert(tmpindices != NULL);
5914 
5915  tmpindices[tmp] = SCIPvarGetProbindex(var);
5916  ++tmp;
5917  }
5918  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5919  }
5920  else if( valscale * knapvals[i] > 0.0 )
5921  {
5922  SCIP_VAR** zvlb;
5923  SCIP_Real* bvlb;
5924  SCIP_Real* dvlb;
5925  SCIP_Real bestlbsol;
5926  int bestlbtype;
5927  int nvlb;
5928  int j;
5929 
5930  /* a_j > 0: substitution with lb or vlb */
5931  nvlb = SCIPvarGetNVlbs(var);
5932  zvlb = SCIPvarGetVlbVars(var);
5933  bvlb = SCIPvarGetVlbCoefs(var);
5934  dvlb = SCIPvarGetVlbConstants(var);
5935 
5936  /* search for lb or vlb with maximal bound value */
5937  bestlbsol = SCIPvarGetLbGlobal(var);
5938  bestlbtype = -1;
5939  for( j = 0; j < nvlb; j++ )
5940  {
5941  /* use only numerical stable vlb with binary variable z */
5942  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5943  {
5944  SCIP_Real vlbsol;
5945 
5946  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5947  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5948  {
5949  *cutoff = TRUE;
5950  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5952  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5953  goto TERMINATE;
5954  }
5955 
5956  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5957  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5958  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5959  {
5960  bestlbsol = vlbsol;
5961  bestlbtype = j;
5962  }
5963  }
5964  }
5965 
5966  /* if no lb or vlb with binary variable was found, we have to abort */
5967  if( SCIPisInfinity(scip, -bestlbsol) )
5968  goto TERMINATE;
5969 
5970  if( bestlbtype == -1 )
5971  {
5972  rhs -= valscale * knapvals[i] * bestlbsol;
5973  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5974  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5975  }
5976  else
5977  {
5978  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5979  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5980  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5981 
5982  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5983  goto TERMINATE;
5984 
5985  if( !noknapsackconshdlr )
5986  {
5987  assert(tmpindices != NULL);
5988 
5989  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5990  ++tmp;
5991  }
5992  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5993  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5994  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5995  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5996  }
5997  }
5998  else
5999  {
6000  SCIP_VAR** zvub;
6001  SCIP_Real* bvub;
6002  SCIP_Real* dvub;
6003  SCIP_Real bestubsol;
6004  int bestubtype;
6005  int nvub;
6006  int j;
6007 
6008  assert(valscale * knapvals[i] < 0.0);
6009 
6010  /* a_j < 0: substitution with ub or vub */
6011  nvub = SCIPvarGetNVubs(var);
6012  zvub = SCIPvarGetVubVars(var);
6013  bvub = SCIPvarGetVubCoefs(var);
6014  dvub = SCIPvarGetVubConstants(var);
6015 
6016  /* search for ub or vub with minimal bound value */
6017  bestubsol = SCIPvarGetUbGlobal(var);
6018  bestubtype = -1;
6019  for( j = 0; j < nvub; j++ )
6020  {
6021  /* use only numerical stable vub with active binary variable z */
6022  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6023  {
6024  SCIP_Real vubsol;
6025 
6026  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6027  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6028  {
6029  *cutoff = TRUE;
6030  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6032  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6033  goto TERMINATE;
6034  }
6035 
6036  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6037  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6038  if( SCIPisLE(scip, vubsol, bestubsol) )
6039  {
6040  bestubsol = vubsol;
6041  bestubtype = j;
6042  }
6043  }
6044  }
6045 
6046  /* if no ub or vub with binary variable was found, we have to abort */
6047  if( SCIPisInfinity(scip, bestubsol) )
6048  goto TERMINATE;
6049 
6050  if( bestubtype == -1 )
6051  {
6052  rhs -= valscale * knapvals[i] * bestubsol;
6053  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6054  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6055  }
6056  else
6057  {
6058  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6059  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6060  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6061 
6062  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6063  goto TERMINATE;
6064 
6065  if( !noknapsackconshdlr )
6066  {
6067  assert(tmpindices != NULL);
6068 
6069  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6070  ++tmp;
6071  }
6072  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6073  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6074  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6075  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6076  }
6077  }
6078  }
6079 
6080  /* convert coefficients of all (now binary) variables to positive integers:
6081  * - make all coefficients integral
6082  * - make all coefficients positive (substitute negated variable)
6083  */
6084  nconsvars = 0;
6085 
6086  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6087  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6088  */
6090  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6091  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6092 
6093  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6094  if( !success )
6095  intscalar = 1.0;
6096 
6097  /* make all coefficients integral and positive:
6098  * - scale a~_j = a_j * intscalar
6099  * - substitute x~_j = 1 - x_j if a~_j < 0
6100  */
6101  rhs = rhs * intscalar;
6102 
6103  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6104  minact = 0;
6105  maxact = 0;
6106  for( i = 0; i < nbinvars; i++ )
6107  {
6108  SCIP_VAR* var;
6109  SCIP_Longint val;
6110 
6111  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6112  if( val == 0 )
6113  continue;
6114 
6115  if( val > 0 )
6116  {
6117  var = binvars[i];
6118  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6119  val, SCIPvarGetName(var), binvals[i], rhs);
6120  }
6121  else
6122  {
6123  assert(val < 0);
6124 
6125  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6126  val = -val; /*lint !e2704*/
6127  rhs += val;
6128  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6129  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6130  }
6131 
6132  if( SCIPvarGetLbLocal(var) > 0.5 )
6133  minact += val;
6134  if( SCIPvarGetUbLocal(var) > 0.5 )
6135  maxact += val;
6136  consvals[nconsvars] = val;
6137  consvars[nconsvars] = var;
6138  nconsvars++;
6139  }
6140 
6141  if( nconsvars > 0 )
6142  {
6143  SCIP_Longint capacity;
6144 
6145  assert(consvars != NULL);
6146  assert(consvals != NULL);
6147  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6148 
6149 #ifdef SCIP_DEBUG
6150  {
6151  SCIP_Real act;
6152 
6153  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6154  act = 0.0;
6155  for( i = 0; i < nconsvars; ++i )
6156  {
6157  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6158  SCIPgetSolVal(scip, sol, consvars[i]));
6159  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6160  }
6161  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6162  capacity, rhs, act, minact, maxact);
6163  }
6164 #endif
6165 
6166  if( minact > capacity )
6167  {
6168  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6169  *cutoff = TRUE;
6170  goto TERMINATE;
6171  }
6172 
6173  if( maxact > capacity )
6174  {
6175  /* separate lifted cut from relaxed knapsack constraint */
6176  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6177  }
6178  }
6179 
6180  TERMINATE:
6181  /* free data structures */
6182  if( noknapsackconshdlr)
6183  {
6184  SCIPfreeBufferArray(scip, &binvals);
6185  }
6186  else
6187  {
6188  /* clear binvals */
6189  for( --tmp; tmp >= 0; --tmp)
6190  {
6191  assert(tmpindices != NULL);
6192  binvals[tmpindices[tmp]] = 0;
6193  }
6194  SCIPfreeBufferArray(scip, &tmpindices);
6195  }
6196  SCIPfreeBufferArray(scip, &consvals);
6197  SCIPfreeBufferArray(scip, &consvars);
6198 
6199  return SCIP_OKAY;
6200 }
6201 
6202 /** separates given knapsack constraint */
6203 static
6205  SCIP* scip, /**< SCIP data structure */
6206  SCIP_CONS* cons, /**< knapsack constraint */
6207  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6208  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6209  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6210  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6211  int* ncuts /**< pointer to add up the number of found cuts */
6212  )
6213 {
6214  SCIP_CONSDATA* consdata;
6215  SCIP_Bool violated;
6216 
6217  assert(ncuts != NULL);
6218  assert(cutoff != NULL);
6219  *cutoff = FALSE;
6220 
6221  consdata = SCIPconsGetData(cons);
6222  assert(consdata != NULL);
6223 
6224  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6225 
6226  /* check knapsack constraint itself for feasibility */
6227  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6228 
6229  if( violated )
6230  {
6231  /* add knapsack constraint as LP row to the LP */
6232  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6233  (*ncuts)++;
6234  }
6235  else if( sepacuts )
6236  {
6237  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6238  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6239  }
6240 
6241  return SCIP_OKAY;
6242 }
6243 
6244 /** adds coefficient to constraint data */
6245 static
6247  SCIP* scip, /**< SCIP data structure */
6248  SCIP_CONS* cons, /**< knapsack constraint */
6249  SCIP_VAR* var, /**< variable to add to knapsack */
6250  SCIP_Longint weight /**< weight of variable in knapsack */
6251  )
6252 {
6253  SCIP_CONSDATA* consdata;
6255  consdata = SCIPconsGetData(cons);
6256  assert(consdata != NULL);
6257  assert(SCIPvarIsBinary(var));
6258  assert(weight > 0);
6259 
6260  /* add the new coefficient to the LP row */
6261  if( consdata->row != NULL )
6262  {
6263  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6264  }
6265 
6266  /* check for fixed variable */
6267  if( SCIPvarGetLbGlobal(var) > 0.5 )
6268  {
6269  /* variable is fixed to one: reduce capacity */
6270  consdata->capacity -= weight;
6271  }
6272  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6273  {
6274  SCIP_Bool negated;
6275 
6276  /* get binary representative of variable */
6277  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6278 
6279  /* insert coefficient */
6280  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6281  consdata->vars[consdata->nvars] = var;
6282  consdata->weights[consdata->nvars] = weight;
6283  consdata->nvars++;
6284 
6285  /* capture variable */
6286  SCIP_CALL( SCIPcaptureVar(scip, var) );
6287 
6288  /* install the rounding locks of variable */
6289  SCIP_CALL( lockRounding(scip, cons, var) );
6290 
6291  /* catch events */
6292  if( SCIPconsIsTransformed(cons) )
6293  {
6294  SCIP_CONSHDLRDATA* conshdlrdata;
6295 
6296  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6297  assert(conshdlrdata != NULL);
6298  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6300  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6301  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6302 
6303  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6304  consdata->existmultaggr = TRUE;
6305 
6306  /* mark constraint to be propagated and presolved */
6307  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6308  consdata->presolvedtiming = 0;
6309  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6310  }
6311 
6312  /* update weight sums */
6313  updateWeightSums(consdata, var, weight);
6314 
6315  consdata->sorted = FALSE;
6316  consdata->cliquepartitioned = FALSE;
6317  consdata->negcliquepartitioned = FALSE;
6318  consdata->merged = FALSE;
6319  }
6320 
6321  return SCIP_OKAY;
6322 }
6323 
6324 /** deletes coefficient at given position from constraint data */
6325 static
6327  SCIP* scip, /**< SCIP data structure */
6328  SCIP_CONS* cons, /**< knapsack constraint */
6329  int pos /**< position of coefficient to delete */
6330  )
6331 {
6332  SCIP_CONSDATA* consdata;
6333  SCIP_VAR* var;
6335  consdata = SCIPconsGetData(cons);
6336  assert(consdata != NULL);
6337  assert(0 <= pos && pos < consdata->nvars);
6338 
6339  var = consdata->vars[pos];
6340  assert(var != NULL);
6341  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6342 
6343  /* delete the coefficient from the LP row */
6344  if( consdata->row != NULL )
6345  {
6346  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6347  }
6348 
6349  /* remove the rounding locks of variable */
6350  SCIP_CALL( unlockRounding(scip, cons, var) );
6351 
6352  /* drop events and mark constraint to be propagated and presolved */
6353  if( SCIPconsIsTransformed(cons) )
6354  {
6355  SCIP_CONSHDLRDATA* conshdlrdata;
6356 
6357  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6358  assert(conshdlrdata != NULL);
6360  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6361  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6362 
6363  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6364  consdata->presolvedtiming = 0;
6365  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6366  }
6367 
6368  /* decrease weight sums */
6369  updateWeightSums(consdata, var, -consdata->weights[pos]);
6370 
6371  /* move the last variable to the free slot */
6372  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6373  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6374  if( consdata->eventdata != NULL )
6375  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6376 
6377  /* release variable */
6378  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6379 
6380  /* try to use old clique partitions */
6381  if( consdata->cliquepartitioned )
6382  {
6383  assert(consdata->cliquepartition != NULL);
6384  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6385  * change the clique number */
6386  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6387  {
6388  int oldcliqenum;
6389 
6390  oldcliqenum = consdata->cliquepartition[pos];
6391  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6392 
6393  /* the following if and else cases assure that we have increasing clique numbers */
6394  if( consdata->cliquepartition[pos] > pos )
6395  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6396  else
6397  {
6398  int i;
6399  int cliquenumbefore;
6400 
6401  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6402  * occurs the same as the old one is still in the cliquepartition */
6403  if( oldcliqenum > consdata->cliquepartition[pos] )
6404  {
6405  for( i = 0; i < consdata->nvars; ++i )
6406  if( oldcliqenum == consdata->cliquepartition[i] )
6407  break;
6408  else if( oldcliqenum < consdata->cliquepartition[i] )
6409  {
6410  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6411  break;
6412  }
6413  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6414  * the biggest index, so decrease the number of cliques
6415  */
6416  if( i == consdata->nvars )
6417  --(consdata->ncliques);
6418  }
6419  /* if the old clique number was smaller than the new one we have to check the front for an element with
6420  * clique number minus 1 */
6421  else if( oldcliqenum < consdata->cliquepartition[pos] )
6422  {
6423  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6424  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6425 
6426  if( i < cliquenumbefore )
6427  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6428  }
6429  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6430  else if( pos == consdata->nvars - 1)
6431  {
6432  cliquenumbefore = consdata->cliquepartition[pos];
6433  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6434 
6435  if( i < cliquenumbefore )
6436  --(consdata->ncliques);
6437  }
6438  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6439  }
6440  }
6441  else
6442  --(consdata->ncliques);
6443  }
6444 
6445  if( consdata->negcliquepartitioned )
6446  {
6447  assert(consdata->negcliquepartition != NULL);
6448  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6449  * change the clique number */
6450  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6451  {
6452  int oldcliqenum;
6453 
6454  oldcliqenum = consdata->negcliquepartition[pos];
6455  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6456 
6457  /* the following if and else cases assure that we have increasing clique numbers */
6458  if( consdata->negcliquepartition[pos] > pos )
6459  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6460  else
6461  {
6462  int i;
6463  int cliquenumbefore;
6464 
6465  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6466  * occurs, the same as the old one occurs */
6467  if( oldcliqenum > consdata->negcliquepartition[pos] )
6468  {
6469  for( i = 0; i < consdata->nvars; ++i )
6470  if( oldcliqenum == consdata->negcliquepartition[i] )
6471  break;
6472  else if( oldcliqenum < consdata->negcliquepartition[i] )
6473  {
6474  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6475  break;
6476  }
6477  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6478  * the biggest index, so decrease the number of negated cliques
6479  */
6480  if( i == consdata->nvars )
6481  --(consdata->nnegcliques);
6482  }
6483  /* if the old clique number was smaller than the new one we have to check the front for an element with
6484  * clique number minus 1 */
6485  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6486  {
6487  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6488  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6489 
6490  if( i < cliquenumbefore )
6491  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6492  }
6493  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6494  else if( pos == consdata->nvars - 1)
6495  {
6496  cliquenumbefore = consdata->negcliquepartition[pos];
6497  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6498 
6499  if( i < cliquenumbefore )
6500  --(consdata->nnegcliques);
6501  }
6502  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6503  }
6504  }
6505  else
6506  --(consdata->nnegcliques);
6507  }
6508 
6509  --(consdata->nvars);
6510 
6511  return SCIP_OKAY;
6512 }
6513 
6514 /** removes all items with weight zero from knapsack constraint */
6515 static
6517  SCIP* scip, /**< SCIP data structure */
6518  SCIP_CONS* cons /**< knapsack constraint */
6519  )
6520 {
6521  SCIP_CONSDATA* consdata;
6522  int v;
6523 
6524  consdata = SCIPconsGetData(cons);
6525  assert(consdata != NULL);
6526 
6527  for( v = consdata->nvars-1; v >= 0; --v )
6528  {
6529  if( consdata->weights[v] == 0 )
6530  {
6531  SCIP_CALL( delCoefPos(scip, cons, v) );
6532  }
6533  }
6534 
6535  return SCIP_OKAY;
6536 }
6537 
6538 /* perform deletion of variables in all constraints of the constraint handler */
6539 static
6541  SCIP* scip, /**< SCIP data structure */
6542  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6543  SCIP_CONS** conss, /**< array of constraints */
6544  int nconss /**< number of constraints */
6545  )
6546 {
6547  SCIP_CONSDATA* consdata;
6548  int i;
6549  int v;
6550 
6551  assert(scip != NULL);
6552  assert(conshdlr != NULL);
6553  assert(conss != NULL);
6554  assert(nconss >= 0);
6555  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6556 
6557  /* iterate over all constraints */
6558  for( i = 0; i < nconss; i++ )
6559  {
6560  consdata = SCIPconsGetData(conss[i]);
6561 
6562  /* constraint is marked, that some of its variables were deleted */
6563  if( consdata->varsdeleted )
6564  {
6565  /* iterate over all variables of the constraint and delete them from the constraint */
6566  for( v = consdata->nvars - 1; v >= 0; --v )
6567  {
6568  if( SCIPvarIsDeleted(consdata->vars[v]) )
6569  {
6570  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6571  }
6572  }
6573  consdata->varsdeleted = FALSE;
6574  }
6575  }
6576 
6577  return SCIP_OKAY;
6578 }
6579 
6580 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6581 static
6583  SCIP* scip, /**< SCIP data structure */
6584  SCIP_CONS* cons, /**< knapsack constraint */
6585  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6586  )
6587 {
6588  SCIP_CONSDATA* consdata;
6589  int v;
6590  int prev;
6591 
6592  assert(scip != NULL);
6593  assert(cons != NULL);
6594  assert(cutoff != NULL);
6595 
6596  consdata = SCIPconsGetData(cons);
6597  assert(consdata != NULL);
6598 
6599  *cutoff = FALSE;
6600 
6601  if( consdata->merged )
6602  return SCIP_OKAY;
6603 
6604  if( consdata->nvars <= 1 )
6605  {
6606  consdata->merged = TRUE;
6607  return SCIP_OKAY;
6608  }
6609 
6610  assert(consdata->vars != NULL || consdata->nvars == 0);
6611 
6612  /* sorting array after indices of variables, that's only for faster merging */
6613  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6614  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6615 
6616  /* knapsack-sorting (decreasing weights) now lost */
6617  consdata->sorted = FALSE;
6618 
6619  v = consdata->nvars - 1;
6620  prev = v - 1;
6621  /* loop backwards through the items: deletion only affects rear items */
6622  while( prev >= 0 )
6623  {
6624  SCIP_VAR* var1;
6625  SCIP_VAR* var2;
6626  SCIP_Bool negated1;
6627  SCIP_Bool negated2;
6628 
6629  negated1 = FALSE;
6630  negated2 = FALSE;
6631 
6632  var1 = consdata->vars[v];
6633  assert(SCIPvarIsBinary(var1));
6634  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6636  {
6637  var1 = SCIPvarGetNegatedVar(var1);
6638  negated1 = TRUE;
6639  }
6640  assert(var1 != NULL);
6641 
6642  var2 = consdata->vars[prev];
6643  assert(SCIPvarIsBinary(var2));
6644  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6646  {
6647  var2 = SCIPvarGetNegatedVar(var2);
6648  negated2 = TRUE;
6649  }
6650  assert(var2 != NULL);
6651 
6652  if( var1 == var2 )
6653  {
6654  /* both variables are either active or negated */
6655  if( negated1 == negated2 )
6656  {
6657  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6658  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6659  SCIP_CALL( delCoefPos(scip, cons, v) );
6660  }
6661  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6662  * and delete item of smaller weight
6663  */
6664  else if( consdata->weights[v] == consdata->weights[prev] )
6665  {
6666  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6667  consdata->capacity -= consdata->weights[v];
6668  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6669  SCIP_CALL( delCoefPos(scip, cons, prev) );
6670 
6671  --prev;
6672  }
6673  else if( consdata->weights[v] < consdata->weights[prev] )
6674  {
6675  consdata->capacity -= consdata->weights[v];
6676  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6677  assert(consdata->weights[prev] > 0);
6678  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6679  }
6680  else
6681  {
6682  consdata->capacity -= consdata->weights[prev];
6683  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6684  assert(consdata->weights[v] > 0);
6685  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6686  /* restore order iff necessary */
6687  if( consdata->nvars != v ) /* otherwise the order still stands */
6688  {
6689  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6690  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6691  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6692  --prev;
6693  else /* we need to let v at the same position*/
6694  {
6695  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6696  /* don't decrease v, the same variable may exist up front */
6697  --prev;
6698  continue;
6699  }
6700  }
6701  }
6702  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6703  }
6704  v = prev;
6705  --prev;
6706  }
6707 
6708  consdata->merged = TRUE;
6709 
6710  /* check infeasibility */
6711  if( consdata->onesweightsum > consdata->capacity )
6712  {
6713  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6714  *cutoff = TRUE;
6715  return SCIP_OKAY;
6716  }
6717 
6718  return SCIP_OKAY;
6719 }
6720 
6721 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6722  * fixings (dual reductions)
6723  */
6724 static
6726  SCIP* scip, /**< SCIP data structure */
6727  SCIP_CONS* cons, /**< knapsack constraint */
6728  int* nfixedvars, /**< pointer to count number of fixings */
6729  int* ndelconss, /**< pointer to count number of deleted constraints */
6730  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6731  )
6732 {
6733  SCIP_CONSDATA* consdata;
6734  SCIP_VAR** vars;
6735  SCIP_Real* profits;
6736  int* solitems;
6737  int* nonsolitems;
6738  int* items;
6739  SCIP_Real solval;
6740  SCIP_Bool infeasible;
6741  SCIP_Bool tightened;
6742  SCIP_Bool applicable;
6743  int nsolitems;
6744  int nnonsolitems;
6745  int nvars;
6746  int v;
6747 
6748  assert(!SCIPconsIsModifiable(cons));
6749 
6750  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6751  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6752  * added to the problems have the check flag set to FALSE
6753  */
6754  if( !SCIPconsIsChecked(cons) )
6755  return SCIP_OKAY;
6756 
6757  consdata = SCIPconsGetData(cons);
6758  assert(consdata != NULL);
6759 
6760  nvars = consdata->nvars;
6761  vars = consdata->vars;
6762 
6763  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6764  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6765  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6766  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6767 
6768  applicable = TRUE;
6769 
6770  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6771  * collect object values which are the profits of the knapsack problem
6772  */
6773  for( v = 0; v < nvars; ++v )
6774  {
6775  SCIP_VAR* var;
6776  SCIP_Bool negated;
6777 
6778  var = vars[v];
6779  assert(var != NULL);
6780 
6781  /* the variable should not be (globally) fixed */
6782  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6783 
6786  {
6787  applicable = FALSE;
6788  break;
6789  }
6790 
6791  negated = FALSE;
6792 
6793  /* get the active variable */
6794  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6795  assert(SCIPvarIsActive(var));
6796 
6797  if( negated )
6798  profits[v] = SCIPvarGetObj(var);
6799  else
6800  profits[v] = -SCIPvarGetObj(var);
6801 
6802  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6803  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6804  items[v] = v;
6805  }
6806 
6807  if( applicable )
6808  {
6809  SCIP_Bool success;
6810 
6811  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6812  SCIPdebugPrintCons(scip, cons, NULL);
6813 
6814  /* solve knapsack problem exactly */
6815  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6816  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6817 
6818  if( success )
6819  {
6820  SCIP_VAR* var;
6821 
6822  /* apply solution of the knapsack as dual reductions */
6823  for( v = 0; v < nsolitems; ++v )
6824  {
6825  var = vars[solitems[v]];
6826  assert(var != NULL);
6827 
6828  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6830  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6831  assert(!infeasible);
6832  assert(tightened);
6833  (*nfixedvars)++;
6834  }
6835 
6836  for( v = 0; v < nnonsolitems; ++v )
6837  {
6838  var = vars[nonsolitems[v]];
6839  assert(var != NULL);
6840 
6841  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6843  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6844  assert(!infeasible);
6845  assert(tightened);
6846  (*nfixedvars)++;
6847  }
6848 
6849  SCIP_CALL( SCIPdelCons(scip, cons) );
6850  (*ndelconss)++;
6851  (*deleted) = TRUE;
6852  }
6853  }
6854 
6855  SCIPfreeBufferArray(scip, &nonsolitems);
6856  SCIPfreeBufferArray(scip, &solitems);
6857  SCIPfreeBufferArray(scip, &items);
6858  SCIPfreeBufferArray(scip, &profits);
6859 
6860  return SCIP_OKAY;
6861 }
6862 
6863 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6864  * constraint enters the LP by setting the initial and separated flag to FALSE
6865  */
6866 static
6868  SCIP* scip, /**< SCIP data structure */
6869  SCIP_CONS* cons, /**< knapsack constraint */
6870  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6871  )
6872 {
6873  SCIP_CONSDATA* consdata;
6874  SCIP_VAR** vars;
6875  SCIP_VAR* var;
6876  SCIP_Real offset;
6877  SCIP_Real scale;
6878  SCIP_Real objval;
6879  SCIP_Bool applicable;
6880  SCIP_Bool negated;
6881  int nobjvars;
6882  int nvars;
6883  int v;
6884 
6885  assert(scip != NULL);
6886  assert(cons != NULL);
6887  assert(conshdlrdata != NULL);
6888 
6889  consdata = SCIPconsGetData(cons);
6890  assert(consdata != NULL);
6891 
6892  nvars = consdata->nvars;
6893  nobjvars = SCIPgetNObjVars(scip);
6894 
6895  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6896  * and/or separated flag is set to FALSE
6897  */
6898  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6899  return SCIP_OKAY;
6900 
6901  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6902  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6903  */
6904  if( nobjvars == 0 )
6905  return SCIP_OKAY;
6906 
6907  vars = consdata->vars;
6908  assert(vars != NULL);
6909 
6910  applicable = TRUE;
6911  offset = 0.0;
6912  scale = 1.0;
6913 
6914  for( v = 0; v < nvars && applicable; ++v )
6915  {
6916  negated = FALSE;
6917  var = vars[v];
6918  assert(var != NULL);
6919 
6920  if( SCIPvarIsNegated(var) )
6921  {
6922  negated = TRUE;
6923  var = SCIPvarGetNegatedVar(var);
6924  assert(var != NULL);
6925  }
6926 
6927  objval = SCIPvarGetObj(var);
6928 
6929  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6930  if( SCIPisZero(scip, objval) )
6931  applicable = FALSE;
6932  else
6933  {
6934  SCIP_Real weight;
6935 
6936  weight = (SCIP_Real)consdata->weights[v];
6937 
6938  if( negated )
6939  {
6940  if( v == 0 )
6941  {
6942  /* the first variable defines the scale */
6943  scale = weight / -objval;
6944 
6945  offset += weight;
6946  }
6947  else if( SCIPisEQ(scip, -objval * scale, weight) )
6948  offset += weight;
6949  else
6950  applicable = FALSE;
6951  }
6952  else if( v == 0 )
6953  {
6954  /* the first variable define the scale */
6955  scale = weight / objval;
6956  }
6957  else if( !SCIPisEQ(scip, objval * scale, weight) )
6958  applicable = FALSE;
6959  }
6960  }
6961 
6962  if( applicable )
6963  {
6964  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6965  {
6966  SCIP_Real cutoffbound;
6967 
6968  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6969  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6970  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6971 
6972  cutoffbound = (consdata->capacity - offset) / scale;
6973 
6974  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6975  SCIPconsGetName(cons), cutoffbound);
6976 
6977  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6978  * still excepted
6979  */
6980  cutoffbound += SCIPcutoffbounddelta(scip);
6981 
6982  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6983  SCIPconsGetName(cons), cutoffbound);
6984 
6985  if( cutoffbound < SCIPgetCutoffbound(scip) )
6986  {
6987  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6988 
6989  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6990  }
6991  else
6992  {
6993  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6994  * propagation
6995  */
6996  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6997  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6998  }
6999  }
7000  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7001  {
7002  SCIP_Real lowerbound;
7003 
7004  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7005  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
7006  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
7007 
7008  lowerbound = (consdata->capacity - offset) / scale;
7009 
7010  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7011  SCIPconsGetName(cons), lowerbound);
7012 
7013  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
7014  }
7015  }
7016 
7017  return SCIP_OKAY;
7018 }
7019 
7020 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7021  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7022 static
7024  SCIP* scip, /**< SCIP data structure */
7025  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7026  SCIP_VAR** vars, /**< array for sorted variables */
7027  SCIP_Longint* weights, /**< array for sorted weights */
7028  int* cliquestartposs, /**< starting position array for each clique */
7029  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7030  )
7031 {
7032  SCIP_VAR** origvars;
7033  int norigvars;
7034  SCIP_Longint* origweights;
7035  int* cliquepartition;
7036  int ncliques;
7037 
7038  SCIP_VAR*** varpointers;
7039  SCIP_Longint** weightpointers;
7040  int* cliquecount;
7041 
7042  int nextpos;
7043  int c;
7044  int v;
7045 
7046  assert(scip != NULL);
7047  assert(consdata != NULL);
7048  assert(vars != NULL);
7049  assert(weights != NULL);
7050  assert(cliquestartposs != NULL);
7051 
7052  origweights = consdata->weights;
7053  origvars = consdata->vars;
7054  norigvars = consdata->nvars;
7055 
7056  assert(origvars != NULL || norigvars == 0);
7057  assert(origweights != NULL || norigvars == 0);
7058 
7059  if( norigvars == 0 )
7060  return SCIP_OKAY;
7061 
7062  if( usenegatedclique )
7063  {
7064  assert(consdata->negcliquepartitioned);
7065 
7066  cliquepartition = consdata->negcliquepartition;
7067  ncliques = consdata->nnegcliques;
7068  }
7069  else
7070  {
7071  assert(consdata->cliquepartitioned);
7072 
7073  cliquepartition = consdata->cliquepartition;
7074  ncliques = consdata->ncliques;
7075  }
7076 
7077  assert(cliquepartition != NULL);
7078  assert(ncliques > 0);
7079 
7080  /* we first count all clique items and alloc temporary memory for a bucket sort */
7081  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7082  BMSclearMemoryArray(cliquecount, ncliques);
7083 
7084  /* first we count for each clique the number of elements */
7085  for( v = norigvars - 1; v >= 0; --v )
7086  {
7087  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7088  ++(cliquecount[cliquepartition[v]]);
7089  }
7090 
7091  /*@todo: maybe it is better to put largest cliques up front */
7092 
7093 #ifndef NDEBUG
7094  BMSclearMemoryArray(vars, norigvars);
7095  BMSclearMemoryArray(weights, norigvars);
7096 #endif
7097  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7098  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7099 
7100  nextpos = 0;
7101  /* now we initialize all start pointers for each clique, so they will be ordered */
7102  for( c = 0; c < ncliques; ++c )
7103  {
7104  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7105  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7106  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7107  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7108  * vars[7]
7109  *
7110  */
7111  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7112  cliquestartposs[c] = nextpos;
7113  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7114  assert(cliquecount[c] > 0);
7115  nextpos += cliquecount[c];
7116  assert(nextpos > 0);
7117  }
7118  assert(nextpos == norigvars);
7119  cliquestartposs[c] = nextpos;
7120 
7121  /* now we copy all variable and weights to the right order */
7122  for( v = 0; v < norigvars; ++v )
7123  {
7124  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7125  ++(varpointers[cliquepartition[v]]);
7126  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7127  ++(weightpointers[cliquepartition[v]]);
7128  }
7129 #ifndef NDEBUG
7130  for( v = 0; v < norigvars; ++v )
7131  {
7132  assert(vars[v] != NULL);
7133  assert(weights[v] > 0);
7134  }
7135 #endif
7136 
7137  /* free temporary memory */
7138  SCIPfreeBufferArray(scip, &weightpointers);
7139  SCIPfreeBufferArray(scip, &varpointers);
7140  SCIPfreeBufferArray(scip, &cliquecount);
7141 
7142  return SCIP_OKAY;
7143 }
7144 
7145 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7146 static
7148  SCIP* scip, /**< SCIP data structure */
7149  SCIP_CONS* cons, /**< knapsack constraint */
7150  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7151  * information is not needed; in this case, we apply all fixings
7152  * instead of stopping after the first infeasible one */
7153  )
7154 {
7155  SCIP_CONSDATA* consdata;
7156  int v;
7157 
7158  assert(scip != NULL);
7159  assert(cons != NULL);
7160 
7161  consdata = SCIPconsGetData(cons);
7162  assert(consdata != NULL);
7163  assert(consdata->nvars == 0 || consdata->vars != NULL);
7164 
7165  if( cutoff != NULL )
7166  *cutoff = FALSE;
7167 
7168  SCIPdebugMsg(scip, "apply fixings:\n");
7169  SCIPdebugPrintCons(scip, cons, NULL);
7170 
7171  /* check infeasibility */
7172  if ( consdata->onesweightsum > consdata->capacity )
7173  {
7174  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7175 
7176  if( cutoff != NULL )
7177  *cutoff = TRUE;
7178 
7179  return SCIP_OKAY;
7180  }
7181 
7182  /* all multi-aggregations should be resolved */
7183  consdata->existmultaggr = FALSE;
7184 
7185  v = 0;
7186  while( v < consdata->nvars )
7187  {
7188  SCIP_VAR* var;
7189 
7190  var = consdata->vars[v];
7191  assert(SCIPvarIsBinary(var));
7192 
7193  if( SCIPvarGetLbGlobal(var) > 0.5 )
7194  {
7195  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7196  consdata->capacity -= consdata->weights[v];
7197  SCIP_CALL( delCoefPos(scip, cons, v) );
7198  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7199  }
7200  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7201  {
7202  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7203  SCIP_CALL( delCoefPos(scip, cons, v) );
7204  }
7205  else
7206  {
7207  SCIP_VAR* repvar;
7208  SCIP_VAR* negvar;
7209  SCIP_VAR* workvar;
7210  SCIP_Longint weight;
7211  SCIP_Bool negated;
7212 
7213  weight = consdata->weights[v];
7214 
7215  /* get binary representative of variable */
7216  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7217  assert(repvar != NULL);
7218 
7219  /* check for multi-aggregation */
7220  if( SCIPvarIsNegated(repvar) )
7221  {
7222  workvar = SCIPvarGetNegatedVar(repvar);
7223  assert(workvar != NULL);
7224  negated = TRUE;
7225  }
7226  else
7227  {
7228  workvar = repvar;
7229  negated = FALSE;
7230  }
7231 
7232  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7233  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7234  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7235  *
7236  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7237  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7238  *
7239  * The explanation for the following block:
7240  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7241  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7242  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7243  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7244  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7245  * 2) For all replacement variable we check:
7246  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7247  * capacity -= weight * a_i caused by the negation of y_i.
7248  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7249  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7250  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7251  * weight in this case.
7252  */
7253  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7254  {
7255  SCIP_VAR** aggrvars;
7256  SCIP_Real* aggrscalars;
7257  SCIP_Real aggrconst;
7258  int naggrvars;
7259  int i;
7260 
7261  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7262  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7263  aggrvars = SCIPvarGetMultaggrVars(workvar);
7264  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7265  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7266  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7267 
7268  if( !SCIPisIntegral(scip, weight * aggrconst) )
7269  {
7270  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7271  return SCIP_ERROR;
7272  }
7273 
7274  /* if workvar was negated, we have to flip the weight */
7275  if( negated )
7276  weight *= -1;
7277 
7278  for( i = naggrvars - 1; i >= 0; --i )
7279  {
7280  assert(aggrvars != NULL);
7281  assert(aggrscalars != NULL);
7282 
7283  if( !SCIPvarIsBinary(aggrvars[i]) )
7284  {
7285  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7286  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7287  return SCIP_ERROR;
7288  }
7289  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7290  {
7291  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7292  return SCIP_ERROR;
7293  }
7294  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7295  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7296  {
7297  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7298  assert(negvar != NULL);
7299  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7300  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7301  }
7302  else
7303  {
7304  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7305  }
7306  }
7307  /* delete old coefficient */
7308  SCIP_CALL( delCoefPos(scip, cons, v) );
7309 
7310  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7311  if( negated )
7312  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7313  else
7314  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7315 
7316  if( consdata->capacity < 0 )
7317  {
7318  if( cutoff != NULL )
7319  {
7320  *cutoff = TRUE;
7321  break;
7322  }
7323  }
7324  }
7325  /* check, if the variable should be replaced with the representative */
7326  else if( repvar != var )
7327  {
7328  /* delete old (aggregated) variable */
7329  SCIP_CALL( delCoefPos(scip, cons, v) );
7330 
7331  /* add representative instead */
7332  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7333  }
7334  else
7335  ++v;
7336  }
7337  }
7338  assert(consdata->onesweightsum == 0);
7339 
7340  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7341  SCIPdebugPrintCons(scip, cons, NULL);
7342 
7343  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7344  * clean up the constraint
7345  */
7346  if( cutoff != NULL && !(*cutoff) )
7347  {
7348  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7349  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7350  SCIPdebugPrintCons(scip, cons, NULL);
7351  }
7352 
7353  return SCIP_OKAY;
7354 }
7355 
7356 
7357 /** propagation method for knapsack constraints */
7358 static
7360  SCIP* scip, /**< SCIP data structure */
7361  SCIP_CONS* cons, /**< knapsack constraint */
7362  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7363  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7364  int* nfixedvars, /**< pointer to count number of fixings */
7365  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7366  )
7368  SCIP_CONSDATA* consdata;
7369  SCIP_Bool infeasible;
7370  SCIP_Bool tightened;
7371  SCIP_Longint* secondmaxweights;
7372  SCIP_Longint minweightsum;
7373  SCIP_Longint residualcapacity;
7374 
7375  int nvars;
7376  int i;
7377  int nnegcliques;
7378 
7379  SCIP_VAR** myvars;
7380  SCIP_Longint* myweights;
7381  int* cliquestartposs;
7382  int* cliqueendposs;
7383  SCIP_Longint localminweightsum;
7384  SCIP_Bool foundmax;
7385  int c;
7386 
7387  assert(scip != NULL);
7388  assert(cons != NULL);
7389  assert(cutoff != NULL);
7390  assert(redundant != NULL);
7391  assert(nfixedvars != NULL);
7392 
7393  consdata = SCIPconsGetData(cons);
7394  assert(consdata != NULL);
7395 
7396  *cutoff = FALSE;
7397  *redundant = FALSE;
7398 
7399  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7400 
7401  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7402  if( !SCIPinRepropagation(scip) )
7403  {
7404  SCIP_CALL( SCIPincConsAge(scip, cons) );
7405  }
7406 
7407 #ifndef NDEBUG
7408  /* assert that only active or negated variables are present */
7409  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7410  {
7411  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7412  }
7413 #endif
7414 
7415  usenegatedclique = usenegatedclique && consdata->merged;
7416 
7417  /* init for debugging */
7418  myvars = NULL;
7419  myweights = NULL;
7420  cliquestartposs = NULL;
7421  secondmaxweights = NULL;
7422  minweightsum = 0;
7423  nvars = consdata->nvars;
7424  /* make sure, the items are sorted by non-increasing weight */
7425  sortItems(consdata);
7426 
7427  do
7428  {
7429  localminweightsum = 0;
7430 
7431  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7432  * a negated clique means, that at most one of the clique variables can be zero
7433  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7434  *
7435  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7436  * since replacing i with the element of maximal weight leads to infeasibility
7437  */
7438  if( usenegatedclique && nvars > 0 )
7439  {
7440  SCIP_CONSHDLRDATA* conshdlrdata;
7441  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7442  assert(conshdlrdata != NULL);
7443 
7444  /* compute clique partitions */
7445  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7446  nnegcliques = consdata->nnegcliques;
7447 
7448  /* if we have no real negated cliques we can stop here */
7449  if( nnegcliques == nvars )
7450  {
7451  /* run the standard algorithm that does not involve cliques */
7452  usenegatedclique = FALSE;
7453  break;
7454  }
7455 
7456  /* allocate temporary memory and initialize it */
7457  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7458  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7459  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7460  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7461  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7462  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7463 
7464  /* resort variables to avoid quadratic algorithm later on */
7465  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7466 
7467  /* save the end positions of the cliques because start positions are moved in the following loop */
7468  for( c = 0; c < nnegcliques; ++c )
7469  {
7470  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7471  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7472  }
7473 
7474  c = 0;
7475  foundmax = FALSE;
7476  i = 0;
7477 
7478  while( i < nvars )
7479  {
7480  /* ignore variables of the negated clique which are fixed to one since these are counted in
7481  * consdata->onesweightsum
7482  */
7483 
7484  /* if there are only one variable negated cliques left we can stop */
7485  if( nnegcliques - c == nvars - i )
7486  {
7487  minweightsum += localminweightsum;
7488  localminweightsum = 0;
7489  break;
7490  }
7491 
7492  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7493  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7494  * other clique variables to one
7495  */
7496  if( cliquestartposs[c] == i )
7497  {
7498  assert(myweights[i] > 0);
7499  ++c;
7500  minweightsum += localminweightsum;
7501  localminweightsum = 0;
7502  foundmax = TRUE;
7503 
7504  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7505  foundmax = FALSE;
7506 
7507  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7508  {
7509  ++i;
7510  continue;
7511  }
7512  }
7513 
7514  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7515  {
7516  assert(myweights[i] > 0);
7517 
7518  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7519  {
7520  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7521 
7522  if( !foundmax )
7523  {
7524  foundmax = TRUE;
7525 
7526  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7527  cliquestartposs[c - 1] = i;
7528  ++i;
7529 
7530  continue;
7531  }
7532  /* memorize second max weight for each clique */
7533  if( secondmaxweights[c - 1] == 0 )
7534  secondmaxweights[c - 1] = myweights[i];
7535 
7536  localminweightsum += myweights[i];
7537  }
7538  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7539  else
7540  {
7541  int v;
7542  /* fix all other variables of the negated clique to 1 */
7543  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7544  {
7545  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7546  {
7547  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7548  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7549 
7550  if( infeasible )
7551  {
7552  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7553 
7554  /* analyze the infeasibility if conflict analysis is applicable */
7556  {
7557  /* conflict analysis can only be applied in solving stage */
7558  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7559 
7560  /* initialize the conflict analysis */
7562 
7563  /* add the two variables which are fixed to zero within a negated clique */
7564  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7565  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7566 
7567  /* start the conflict analysis */
7568  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7569  }
7570  *cutoff = TRUE;
7571  break;
7572  }
7573  assert(tightened);
7574  ++(*nfixedvars);
7575  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7576  }
7577  }
7578 
7579  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7580  localminweightsum = 0;
7581  /* we can jump to the end of this clique */
7582  i = cliqueendposs[c - 1];
7583 
7584  if( *cutoff )
7585  break;
7586  }
7587  }
7588  ++i;
7589  }
7590  /* add last clique minweightsum */
7591  minweightsum += localminweightsum;
7592 
7593  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7594  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7595 
7596  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7597  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7598  {
7599  SCIP_Longint maxcliqueweight = -1LL;
7600 
7601  /* loop over cliques */
7602  for( c = 0; c < nnegcliques; ++c )
7603  {
7604  SCIP_VAR* maxvar;
7605  SCIP_Bool maxvarfixed;
7606  int endvarposclique;
7607  int startvarposclique;
7608 
7609  assert(myvars != NULL);
7610  assert(nnegcliques == consdata->nnegcliques);
7611  assert(myweights != NULL);
7612  assert(secondmaxweights != NULL);
7613  assert(cliquestartposs != NULL);
7614 
7615  endvarposclique = cliqueendposs[c];
7616  startvarposclique = cliquestartposs[c];
7617 
7618  maxvar = myvars[startvarposclique];
7619 
7620  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7621  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7622  continue;
7623 
7624  maxcliqueweight = myweights[startvarposclique];
7625  maxvarfixed = FALSE;
7626  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7627  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7628  * exceeds the capacity the maximum weight variable can be fixed to zero.
7629  */
7630  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7631  {
7632 #ifndef NDEBUG
7633  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7634 #endif
7635  assert(maxcliqueweight >= secondmaxweights[c]);
7636  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7637 
7638  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7639  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7640  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7641  assert(consdata->onesweightsum == oldonesweightsum);
7642  assert(!infeasible);
7643  assert(tightened);
7644  (*nfixedvars)++;
7645  maxvarfixed = TRUE;
7646  }
7647  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7648  * fits into the knapsack
7649  */
7650  else if( nnegcliques - c == nvars - startvarposclique )
7651  break;
7652  /* early termination of the remaining loop because no further variable fixings are possible:
7653  *
7654  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7655  * largest was set to 0) does not suffice to infer additional variable fixings because
7656  *
7657  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7658  * - their second largest elements are at least as large as the smallest weight of the knapsack
7659  */
7660  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7661  break;
7662 
7663  /* loop over items with non-maximal weight (omitting the first position) */
7664  for( i = endvarposclique; i > startvarposclique; --i )
7665  {
7666  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7667  * messed up the clique preprocessing in the previous loop to filter those variables out */
7668  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7669 
7670  /* only check variables of negated cliques for which no variable is locally fixed */
7671  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7672  {
7673  assert(maxcliqueweight >= myweights[i]);
7674  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7675 
7676  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7677  *
7678  * the maxvar was already fixed to 0 because it has a huge gain.
7679  *
7680  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7681  * since replacing i with the element of maximal weight leads to infeasibility */
7682  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7683  {
7684 #ifndef NDEBUG
7685  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7686 #endif
7687  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7688  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7689  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7690  assert(!infeasible);
7691  assert(tightened);
7692  ++(*nfixedvars);
7693  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7694 
7695  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7696  * consdata->onesweightsum
7697  */
7698  minweightsum -= myweights[i];
7699  assert(minweightsum >= 0);
7700  }
7701  else
7702  break;
7703  }
7704  }
7705 #ifndef NDEBUG
7706  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7707  for( ; i > startvarposclique; --i )
7708  {
7709  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7710  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7711 
7712  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7713  assert(varisfixed || !exceedscapacity);
7714  }
7715 #endif
7716  }
7717  }
7718  SCIPfreeBufferArray(scip, &secondmaxweights);
7719  SCIPfreeBufferArray(scip, &cliqueendposs);
7720  SCIPfreeBufferArray(scip, &cliquestartposs);
7721  SCIPfreeBufferArray(scip, &myweights);
7722  SCIPfreeBufferArray(scip, &myvars);
7723  }
7724 
7725  assert(consdata->negcliquepartitioned || minweightsum == 0);
7726  }
7727  while( FALSE );
7728 
7729  assert(usenegatedclique || minweightsum == 0);
7730  /* check, if weights of fixed variables already exceed knapsack capacity */
7731  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7732  {
7733  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7734  consdata->onesweightsum, consdata->capacity);
7735 
7736  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7737  *cutoff = TRUE;
7738 
7739  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7741  {
7742  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7743  SCIP_Longint weight;
7744 
7745  weight = 0;
7746 
7748 
7749  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7750  {
7751  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7752  {
7753  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7754  weight += consdata->weights[i];
7755  }
7756  }
7757 
7758  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7759  }
7760 
7761  return SCIP_OKAY;
7762  }
7763 
7764  /* the algorithm below is a special case of propagation involving negated cliques */
7765  if( !usenegatedclique )
7766  {
7767  assert(consdata->sorted);
7768  residualcapacity = consdata->capacity - consdata->onesweightsum;
7769 
7770  /* fix all variables to zero, that don't fit into the knapsack anymore */
7771  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7772  {
7773  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7774  * to zero
7775  */
7776  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7777  {
7778  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7779  {
7780  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7781  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7782  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7783  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7784  assert(!infeasible);
7785  assert(tightened);
7786  (*nfixedvars)++;
7787  }
7788  }
7789  }
7790  }
7791 
7792  /* check if the knapsack is now redundant */
7793  if( !SCIPconsIsModifiable(cons) )
7794  {
7795  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7796 
7797  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7798  for( i = 0; i < nvars; ++i )
7799  {
7800  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7801  {
7802  unfixedweightsum += consdata->weights[i];
7803 
7804  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7805  if( unfixedweightsum > consdata->capacity )
7806  return SCIP_OKAY;
7807  }
7808  }
7809  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7810  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7811  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7812  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7813  *redundant = TRUE;
7814  }
7815 
7816  return SCIP_OKAY;
7817 }
7818 
7819 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7820  * containing all negated variables of this knapsack constraint
7821  */
7822 static
7824  SCIP* scip, /**< SCIP data structure */
7825  SCIP_CONS* cons, /**< knapsack constraint */
7826  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7827  int* naddconss /**< pointer to count number of added constraints */
7828  )
7829 {
7830  SCIP_CONS* newcons;
7831  SCIP_CONSDATA* consdata;
7832 
7833  assert(scip != NULL);
7834  assert(cons != NULL);
7835  assert(ndelconss != NULL);
7836  assert(naddconss != NULL);
7837 
7838  consdata = SCIPconsGetData(cons);
7839  assert(consdata != NULL);
7840  assert(consdata->nvars > 1);
7841 
7842  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7843  if( consdata->nvars == 2 )
7844  {
7845  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7846 
7847  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7851  SCIPconsIsStickingAtNode(cons)) );
7852  }
7853  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7854  * containing all negated variables of the knapsack
7855  */
7856  else
7857  {
7858  SCIP_VAR** consvars;
7859 
7860  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7861 
7862  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7863  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7864 
7865  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7869  SCIPconsIsStickingAtNode(cons)) );
7870 
7871  SCIPfreeBufferArray(scip, &consvars);
7872  }
7873 
7874  SCIP_CALL( SCIPaddCons(scip, newcons) );
7875  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7876  ++(*naddconss);
7877 
7878  SCIP_CALL( SCIPdelCons(scip, cons) );
7879  ++(*ndelconss);
7880 
7881  return SCIP_OKAY;
7882 }
7883 
7884 /** delete redundant variables
7885  *
7886  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7887  *
7888  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7889  * => x4, x5 always fits into the knapsack, so we can delete them
7890  *
7891  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7892  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7893  */
7894 static
7896  SCIP* scip, /**< SCIP data structure */
7897  SCIP_CONS* cons, /**< knapsack constraint */
7898  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7899  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7900  * first which did not fit */
7901  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7902  int* nchgsides, /**< pointer to store the amount of changed sides */
7903  int* naddconss /**< pointer to count number of added constraints */
7904  )
7905 {
7906  SCIP_CONSHDLRDATA* conshdlrdata;
7907  SCIP_CONSDATA* consdata;
7908  SCIP_VAR** vars;
7909  SCIP_Longint* weights;
7910  SCIP_Longint capacity;
7911  SCIP_Longint gcd;
7912  int nvars;
7913  int w;
7914 
7915  assert(scip != NULL);
7916  assert(cons != NULL);
7917  assert(nchgcoefs != NULL);
7918  assert(nchgsides != NULL);
7919  assert(naddconss != NULL);
7920 
7921  consdata = SCIPconsGetData(cons);
7922  assert(consdata != NULL);
7923  assert(0 < frontsum && frontsum < consdata->weightsum);
7924  assert(0 < splitpos && splitpos < consdata->nvars);
7925 
7926  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7927  assert(conshdlrdata != NULL);
7928 
7929  vars = consdata->vars;
7930  weights = consdata->weights;
7931  nvars = consdata->nvars;
7932  capacity = consdata->capacity;
7933 
7934  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7935  * weight must not be sorted by their index
7936  */
7937 #ifndef NDEBUG
7938  for( w = nvars - 1; w > 0; --w )
7939  assert(weights[w] <= weights[w-1]);
7940 #endif
7941 
7942  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7943  if( consdata->nvars - 1 == splitpos )
7944  return SCIP_OKAY;
7945 
7946  assert(frontsum + weights[splitpos] > capacity);
7947 
7948  /* detect redundant variables */
7949  if( consdata->weightsum - weights[splitpos] <= capacity )
7950  {
7951  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7952  * fit
7953  */
7954  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7955 
7956  /* delete items and update capacity */
7957  for( w = nvars - 1; w > splitpos; --w )
7958  {
7959  consdata->capacity -= weights[w];
7960  SCIP_CALL( delCoefPos(scip, cons, w) );
7961  }
7962  assert(w == splitpos);
7963 
7964  ++(*nchgsides);
7965  *nchgcoefs += (nvars - splitpos);
7966 
7967  /* division by greatest common divisor */
7968  gcd = weights[w];
7969  for( ; w >= 0 && gcd > 1; --w )
7970  {
7971  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7972  }
7973 
7974  /* normalize if possible */
7975  if( gcd > 1 )
7976  {
7977  for( w = splitpos; w >= 0; --w )
7978  {
7979  consdataChgWeight(consdata, w, weights[w]/gcd);
7980  }
7981  (*nchgcoefs) += nvars;
7982 
7983  consdata->capacity /= gcd;
7984  ++(*nchgsides);
7985  }
7986 
7987  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7988  * weight must not be sorted by their index
7989  */
7990 #ifndef NDEBUG
7991  for( w = consdata->nvars - 1; w > 0; --w )
7992  assert(weights[w] <= weights[w - 1]);
7993 #endif
7994  }
7995  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7996  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7997  * splitpos and needs to fit into the knapsack
7998  */
7999  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8000  {
8001  int* clqpart;
8002  int nclq;
8003  int len;
8004 
8005  len = nvars - (splitpos + 1);
8006  /* allocate temporary memory */
8007  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8008 
8009  /* calculate clique partition */
8010  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8011 
8012  /* check if we found at least one clique */
8013  if( nclq < len )
8014  {
8015  SCIP_Longint maxactduetoclq;
8016  int cliquenum;
8017 
8018  maxactduetoclq = 0;
8019  cliquenum = 0;
8020 
8021  /* calculate maximum activity due to cliques */
8022  for( w = 0; w < len; ++w )
8023  {
8024  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8025  if( clqpart[w] == cliquenum )
8026  {
8027  maxactduetoclq += weights[w + splitpos + 1];
8028  ++cliquenum;
8029  }
8030  }
8031 
8032  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8033  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8034  */
8035  if( frontsum + maxactduetoclq <= capacity )
8036  {
8037  SCIP_VAR** clqvars;
8038  int nclqvars;
8039  int c;
8040 
8041  assert(maxactduetoclq < weights[splitpos]);
8042 
8043  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8044 
8045  /* allocate temporary memory */
8046  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8047 
8048  for( c = 0; c < nclq; ++c )
8049  {
8050  nclqvars = 0;
8051  for( w = 0; w < len; ++w )
8052  {
8053  if( clqpart[w] == c )
8054  {
8055  clqvars[nclqvars] = vars[w + splitpos + 1];
8056  ++nclqvars;
8057  }
8058  }
8059 
8060  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8061  if( nclqvars > 1 )
8062  {
8063  SCIP_CONS* cliquecons;
8064  char name[SCIP_MAXSTRLEN];
8065 
8066  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8067  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8071  SCIPconsIsStickingAtNode(cons)) );
8072  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8073  SCIPdebugPrintCons(scip, cliquecons, NULL);
8074  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8075  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8076  ++(*naddconss);
8077  }
8078  }
8079 
8080  /* delete items and update capacity */
8081  for( w = nvars - 1; w > splitpos; --w )
8082  {
8083  SCIP_CALL( delCoefPos(scip, cons, w) );
8084  ++(*nchgcoefs);
8085  }
8086  consdata->capacity -= maxactduetoclq;
8087  assert(frontsum <= consdata->capacity);
8088  ++(*nchgsides);
8089 
8090  assert(w == splitpos);
8091 
8092  /* renew weights pointer */
8093  weights = consdata->weights;
8094 
8095  /* division by greatest common divisor */
8096  gcd = weights[w];
8097  for( ; w >= 0 && gcd > 1; --w )
8098  {
8099  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8100  }
8101 
8102  /* normalize if possible */
8103  if( gcd > 1 )
8104  {
8105  for( w = splitpos; w >= 0; --w )
8106  {
8107  consdataChgWeight(consdata, w, weights[w]/gcd);
8108  }
8109  (*nchgcoefs) += nvars;
8110 
8111  consdata->capacity /= gcd;
8112  ++(*nchgsides);
8113  }
8114 
8115  /* free temporary memory */
8116  SCIPfreeBufferArray(scip, &clqvars);
8117 
8118  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8119  * weight must not be sorted by their index
8120  */
8121 #ifndef NDEBUG
8122  for( w = consdata->nvars - 1; w > 0; --w )
8123  assert(weights[w] <= weights[w - 1]);
8124 #endif
8125  }
8126  }
8127 
8128  /* free temporary memory */
8129  SCIPfreeBufferArray(scip, &clqpart);
8130  }
8131 
8132  return SCIP_OKAY;
8133 }
8134 
8135 /* detect redundant variables which always fits into the knapsack
8136  *
8137  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8138  *
8139  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8140  * => x4, x5 always fits into the knapsack, so we can delete them
8141  *
8142  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8143  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8144  */
8145 static
8147  SCIP* scip, /**< SCIP data structure */
8148  SCIP_CONS* cons, /**< knapsack constraint */
8149  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8150  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8151  int* nchgsides, /**< pointer to store the amount of changed sides */
8152  int* naddconss /**< pointer to count number of added constraints */
8153  )
8155  SCIP_CONSHDLRDATA* conshdlrdata;
8156  SCIP_CONSDATA* consdata;
8157  SCIP_VAR** vars;
8158  SCIP_Longint* weights;
8159  SCIP_Longint capacity;
8160  SCIP_Longint sum;
8161  int noldchgcoefs;
8162  int nvars;
8163  int v;
8164  int w;
8165 
8166  assert(scip != NULL);
8167  assert(cons != NULL);
8168  assert(ndelconss != NULL);
8169  assert(nchgcoefs != NULL);
8170  assert(nchgsides != NULL);
8171  assert(naddconss != NULL);
8172 
8173  consdata = SCIPconsGetData(cons);
8174  assert(consdata != NULL);
8175  assert(consdata->nvars >= 2);
8176  assert(consdata->weightsum > consdata->capacity);
8177 
8178  noldchgcoefs = *nchgcoefs;
8179  vars = consdata->vars;
8180  weights = consdata->weights;
8181  nvars = consdata->nvars;
8182  capacity = consdata->capacity;
8183  sum = 0;
8184 
8185  /* search for maximal fitting items */
8186  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8187  sum += weights[v];
8188 
8189  assert(v < nvars);
8190 
8191  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8192  if( v == nvars - 1 )
8193  {
8194  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8195  assert(SCIPconsIsDeleted(cons));
8196 
8197  return SCIP_OKAY;
8198  }
8199 
8200  if( v < nvars - 1 )
8201  {
8202  /* try to delete variables */
8203  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8204  assert(consdata->nvars > 1);
8205 
8206  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8207  if( v == consdata->nvars - 1 )
8208  {
8209  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8210  assert(SCIPconsIsDeleted(cons));
8211  }
8212 
8213  return SCIP_OKAY;
8214  }
8215 
8216  /* if we already found some redundant variables, stop here */
8217  if( *nchgcoefs > noldchgcoefs )
8218  return SCIP_OKAY;
8219 
8220  assert(vars == consdata->vars);
8221  assert(weights == consdata->weights);
8222  assert(nvars == consdata->nvars);
8223  assert(capacity == consdata->capacity);
8224 
8225  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8226  assert(conshdlrdata != NULL);
8227  /* calculate clique partition */
8228  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8229 
8230  /* check for real existing cliques */
8231  if( consdata->cliquepartition[v] < v )
8232  {
8233  SCIP_Longint sumfront;
8234  SCIP_Longint maxactduetoclqfront;
8235  int* clqpart;
8236  int cliquenum;
8237 
8238  sumfront = 0;
8239  maxactduetoclqfront = 0;
8240 
8241  clqpart = consdata->cliquepartition;
8242  cliquenum = 0;
8243 
8244  /* calculate maximal activity due to cliques */
8245  for( w = 0; w < nvars; ++w )
8246  {
8247  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8248  if( clqpart[w] == cliquenum )
8249  {
8250  if( maxactduetoclqfront + weights[w] <= capacity )
8251  {
8252  maxactduetoclqfront += weights[w];
8253  ++cliquenum;
8254  }
8255  else
8256  break;
8257  }
8258  sumfront += weights[w];
8259  }
8260  assert(w >= v);
8261 
8262  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8263  * information
8264  */
8265  if( conshdlrdata->disaggregation && w == nvars )
8266  {
8267  SCIP_VAR** clqvars;
8268  int nclqvars;
8269  int c;
8270  int ncliques;
8271 
8272  assert(maxactduetoclqfront <= capacity);
8273 
8274  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8275 
8276  ncliques = consdata->ncliques;
8277 
8278  /* allocate temporary memory */
8279  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8280 
8281  for( c = 0; c < ncliques; ++c )
8282  {
8283  nclqvars = 0;
8284  for( w = 0; w < nvars; ++w )
8285  {
8286  if( clqpart[w] == c )
8287  {
8288  clqvars[nclqvars] = vars[w];
8289  ++nclqvars;
8290  }
8291  }
8292 
8293  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8294  if( nclqvars > 1 )
8295  {
8296  SCIP_CONS* cliquecons;
8297  char name[SCIP_MAXSTRLEN];
8298 
8299  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8300  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8304  SCIPconsIsStickingAtNode(cons)) );
8305  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8306  SCIPdebugPrintCons(scip, cliquecons, NULL);
8307  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8308  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8309  ++(*naddconss);
8310  }
8311  }
8312 
8313  /* delete old constraint */
8314  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8315  ++(*ndelconss);
8316 
8317  SCIPfreeBufferArray(scip, &clqvars);
8318 
8319  return SCIP_OKAY;
8320  }
8321 
8322  if( w > v && w < nvars - 1 )
8323  {
8324  /* try to delete variables */
8325  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8326  }
8327  }
8328 
8329  return SCIP_OKAY;
8330 }
8331 
8332 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8333 static
8334 void normalizeWeights(
8335  SCIP_CONS* cons, /**< knapsack constraint */
8336  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8337  int* nchgsides /**< pointer to count number of side changes */
8338  )
8339 {
8340  SCIP_CONSDATA* consdata;
8341  SCIP_Longint gcd;
8342  int i;
8343 
8344  assert(nchgcoefs != NULL);
8345  assert(nchgsides != NULL);
8346  assert(!SCIPconsIsModifiable(cons));
8347 
8348  consdata = SCIPconsGetData(cons);
8349  assert(consdata != NULL);
8350  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8351  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8352  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8353  assert(consdata->nvars >= 1);
8354 
8355  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8356  sortItems(consdata);
8357 
8358  gcd = consdata->weights[consdata->nvars-1];
8359  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8360  {
8361  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8362  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8363 
8364  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8365  }
8366 
8367  if( gcd >= 2 )
8368  {
8369  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8370 
8371  for( i = 0; i < consdata->nvars; ++i )
8372  {
8373  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8374  }
8375  consdata->capacity /= gcd;
8376  (*nchgcoefs) += consdata->nvars;
8377  (*nchgsides)++;
8378 
8379  /* weight should still be sorted, because the reduction preserves this */
8380 #ifndef NDEBUG
8381  for( i = consdata->nvars - 1; i > 0; --i )
8382  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8383 #endif
8384  consdata->sorted = TRUE;
8385  }
8386 }
8387 
8388 /** dual weights tightening for knapsack constraints
8389  *
8390  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8391  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8392  * constraint
8393  *
8394  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8395  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8396  *
8397  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8398  *
8399  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8400  *
8401  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8402  *
8403  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8404  *
8405  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8406  */
8407 static
8409  SCIP* scip, /**< SCIP data structure */
8410  SCIP_CONS* cons, /**< knapsack constraint */
8411  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8412  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8413  int* nchgsides, /**< pointer to store the amount of changed sides */
8414  int* naddconss /**< pointer to count number of added constraints */
8415  )
8417  SCIP_CONSDATA* consdata;
8418  SCIP_Longint* weights;
8419  SCIP_Longint dualcapacity;
8420  SCIP_Longint reductionsum;
8421  SCIP_Longint capacity;
8422  SCIP_Longint exceedsum;
8423  int oldnchgcoefs;
8424  int nvars;
8425  int vbig;
8426  int v;
8427  int w;
8428 #ifndef NDEBUG
8429  int oldnchgsides;
8430 #endif
8431 
8432  assert(scip != NULL);
8433  assert(cons != NULL);
8434  assert(ndelconss != NULL);
8435  assert(nchgcoefs != NULL);
8436  assert(nchgsides != NULL);
8437  assert(naddconss != NULL);
8438 
8439 #ifndef NDEBUG
8440  oldnchgsides = *nchgsides;
8441 #endif
8442 
8443  consdata = SCIPconsGetData(cons);
8444  assert(consdata != NULL);
8445  assert(consdata->weightsum > consdata->capacity);
8446  assert(consdata->nvars >= 2);
8447  assert(consdata->sorted);
8448 
8449  /* constraint should be merged */
8450  assert(consdata->merged);
8451 
8452  nvars = consdata->nvars;
8453  weights = consdata->weights;
8454  capacity = consdata->capacity;
8455 
8456  oldnchgcoefs = *nchgcoefs;
8457 
8458  /* case 1. */
8459  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8460  {
8461  SCIP_CONS* newcons;
8462 
8463  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8464  *
8465  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8466  */
8467  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8468 
8469  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8473  SCIPconsIsStickingAtNode(cons)) );
8474 
8475  SCIP_CALL( SCIPaddCons(scip, newcons) );
8476  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8477  ++(*naddconss);
8478 
8479  SCIP_CALL( SCIPdelCons(scip, cons) );
8480  ++(*ndelconss);
8481 
8482  return SCIP_OKAY;
8483  }
8484 
8485  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8486  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8487  {
8488  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8489  assert(SCIPconsIsDeleted(cons));
8490 
8491  return SCIP_OKAY;
8492  }
8493 
8494  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8495  /* @todo might be changed/removed when improving the coeffcients tightening */
8496  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8497  return SCIP_OKAY;
8498 
8499  /* case 2. */
8500 
8501  v = 0;
8502 
8503  /* @todo generalize the following algorithm for several parts of the knapsack
8504  *
8505  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8506  * variables each combination is a minimal cover, some examples
8507  *
8508  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8509  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8510  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8511  *
8512  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8513  *
8514  */
8515 
8516  /* determine big weights that fit only by itself */
8517  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8518  ++v;
8519 
8520  vbig = v;
8521  assert(vbig < nvars - 1);
8522  exceedsum = 0;
8523 
8524  /* determine the amount needed to exceed the capacity */
8525  while( v < nvars && exceedsum <= capacity )
8526  {
8527  exceedsum += weights[v];
8528  ++v;
8529  }
8530 
8531  /* if we exceeded the capacity we might reduce the weights */
8532  if( exceedsum > capacity )
8533  {
8534  assert(vbig > 0 || v < nvars);
8535 
8536  /* all small weights were needed to exceed the capacity */
8537  if( v == nvars )
8538  {
8539  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8540  assert(newweight > 0);
8541 
8542  /* reduce big weights */
8543  for( v = 0; v < vbig; ++v )
8544  {
8545  if( weights[v] > newweight )
8546  {
8547  consdataChgWeight(consdata, v, newweight);
8548  ++(*nchgcoefs);
8549  }
8550  }
8551 
8552  /* reduce small weights */
8553  for( ; v < nvars; ++v )
8554  {
8555  if( weights[v] > 1 )
8556  {
8557  consdataChgWeight(consdata, v, 1LL);
8558  ++(*nchgcoefs);
8559  }
8560  }
8561 
8562  consdata->capacity = newweight;
8563 
8564  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8565  * weight must not be sorted by their index
8566  */
8567 #ifndef NDEBUG
8568  for( v = nvars - 1; v > 0; --v )
8569  assert(weights[v] <= weights[v-1]);
8570 #endif
8571 
8572  return SCIP_OKAY;
8573  }
8574  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8575  * small weights
8576  */
8577  else
8578  {
8579  SCIP_Longint exceedsumback = 0;
8580  int nexceed = v - vbig;
8581 
8582  assert(nexceed > 1);
8583 
8584  /* determine weightsum of the same amount as before but of the smallest weight */
8585  for( w = nvars - 1; w >= nvars - nexceed; --w )
8586  exceedsumback += weights[w];
8587 
8588  assert(w >= 0);
8589 
8590  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8591  * combinations of all small weights
8592  */
8593  if( exceedsumback > capacity )
8594  {
8595  SCIP_Longint newweight = nexceed - 1;
8596 
8597  /* taking out the smallest element needs to fit */
8598  assert(exceedsumback - weights[nvars - 1] <= capacity);
8599 
8600  /* reduce big weights */
8601  for( v = 0; v < vbig; ++v )
8602  {
8603  if( weights[v] > newweight )
8604  {
8605  consdataChgWeight(consdata, v, newweight);
8606  ++(*nchgcoefs);
8607  }
8608  }
8609 
8610  /* reduce small weights */
8611  for( ; v < nvars; ++v )
8612  {
8613  if( weights[v] > 1 )
8614  {
8615  consdataChgWeight(consdata, v, 1LL);
8616  ++(*nchgcoefs);
8617  }
8618  }
8619 
8620  consdata->capacity = newweight;
8621 
8622  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8623  * weight must not be sorted by their index
8624  */
8625 #ifndef NDEBUG
8626  for( v = nvars - 1; v > 0; --v )
8627  assert(weights[v] <= weights[v-1]);
8628 #endif
8629  return SCIP_OKAY;
8630  }
8631  }
8632  }
8633  else
8634  {
8635  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8636  * not happen here
8637  */
8638  assert(vbig > 0 && vbig < nvars);
8639 
8640  /* either choose a big coefficients or all other variables
8641  *
8642  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8643  *
8644  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8645  * constraint to
8646  *
8647  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8648  */
8649 
8650  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8651  {
8652  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8653 #ifndef NDEBUG
8654  SCIP_Longint resweightsum = consdata->weightsum;
8655 
8656  for( v = 0; v < vbig; ++v )
8657  resweightsum -= weights[v];
8658 
8659  assert(exceedsum == resweightsum);
8660 #endif
8661  assert(newweight > 0);
8662 
8663  /* reduce big weights */
8664  for( v = 0; v < vbig; ++v )
8665  {
8666  if( weights[v] > newweight )
8667  {
8668  consdataChgWeight(consdata, v, newweight);
8669  ++(*nchgcoefs);
8670  }
8671  }
8672 
8673  /* reduce small weights */
8674  for( ; v < nvars; ++v )
8675  {
8676  if( weights[v] > 1 )
8677  {
8678  consdataChgWeight(consdata, v, 1LL);
8679  ++(*nchgcoefs);
8680  }
8681  }
8682 
8683  consdata->capacity = newweight;
8684 
8685  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8686  * weight must not be sorted by their index
8687  */
8688 #ifndef NDEBUG
8689  for( v = nvars - 1; v > 0; --v )
8690  assert(weights[v] <= weights[v-1]);
8691 #endif
8692  return SCIP_OKAY;
8693  }
8694  }
8695 
8696  /* case 3. */
8697 
8698  dualcapacity = consdata->weightsum - capacity;
8699  reductionsum = 0;
8700  v = 0;
8701 
8702  /* reduce big weights
8703  *
8704  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8705  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8706  * <=> x0 + x1 + x2 + x3 <= 3
8707  */
8708  while( weights[v] > dualcapacity )
8709  {
8710  reductionsum += (weights[v] - dualcapacity);
8711  consdataChgWeight(consdata, v, dualcapacity);
8712  ++v;
8713  assert(v < nvars);
8714  }
8715  (*nchgcoefs) += v;
8716 
8717  /* skip weights equal to the dualcapacity, because we cannot change them */
8718  while( v < nvars && weights[v] == dualcapacity )
8719  ++v;
8720 
8721  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8722  * after a possible removal of the last, redundant item
8723  *
8724  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8725  */
8726  if( v >= nvars - 1 )
8727  {
8728  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8729  if( v == nvars - 1 )
8730  {
8731  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8732  }
8733  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8734  assert(SCIPconsIsDeleted(cons));
8735 
8736  return SCIP_OKAY;
8737  }
8738  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8739  {
8740  /* @todo generalize the following algorithm for more than two variables */
8741 
8742  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8743  {
8744  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8745  * coefficients) of all or two variables of the rest
8746  *
8747  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8748  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8749  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8750  *
8751  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8752  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8753  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8754  *
8755  */
8756  if( v > 0 && weights[nvars - 2] > 1 )
8757  {
8758  int ncoefchg = 0;
8759 
8760  /* reduce all bigger weights */
8761  for( w = 0; w < v; ++w )
8762  {
8763  if( weights[w] > 2 )
8764  {
8765  consdataChgWeight(consdata, w, 2LL);
8766  ++ncoefchg;
8767  }
8768  else
8769  {
8770  assert(weights[0] == 2);
8771  assert(weights[v - 1] == 2);
8772  break;
8773  }
8774  }
8775 
8776  /* reduce all smaller weights */
8777  for( w = v; w < nvars; ++w )
8778  {
8779  if( weights[w] > 1 )
8780  {
8781  consdataChgWeight(consdata, w, 1LL);
8782  ++ncoefchg;
8783  }
8784  }
8785  assert(ncoefchg > 0);
8786 
8787  (*nchgcoefs) += ncoefchg;
8788 
8789  /* correct the capacity */
8790  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8791  assert(consdata->capacity > 0);
8792  assert(weights[0] <= consdata->capacity);
8793  assert(consdata->weightsum > consdata->capacity);
8794  /* reset the reductionsum */
8795  reductionsum = 0;
8796  }
8797  else if( v == 0 )
8798  {
8799  assert(weights[nvars - 2] == 1);
8800  }
8801  }
8802  else
8803  {
8804  SCIP_Longint minweight = weights[nvars - 1];
8805  SCIP_Longint newweight = dualcapacity - minweight;
8806  SCIP_Longint restsumweights = 0;
8807  SCIP_Longint sumcoef;
8808  SCIP_Bool sumcoefcase = FALSE;
8809  int startv = v;
8810  int end;
8811  int k;
8812 
8813  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8814 
8815  /* reduce big weights of pairs that exceed the dualcapacity
8816  *
8817  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8818  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8819  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8820  */
8821  while( weights[v] > newweight )
8822  {
8823  reductionsum += (weights[v] - newweight);
8824  consdataChgWeight(consdata, v, newweight);
8825  ++v;
8826  assert(v < nvars);
8827  }
8828  (*nchgcoefs) += (v - startv);
8829 
8830  /* skip equal weights */
8831  while( weights[v] == newweight )
8832  ++v;
8833 
8834  if( v > 0 )
8835  {
8836  for( w = v; w < nvars; ++w )
8837  restsumweights += weights[w];
8838  }
8839  else
8840  restsumweights = consdata->weightsum;
8841 
8842  if( restsumweights < dualcapacity )
8843  {
8844  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8845  *
8846  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8847  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8848  */
8849  if( startv == v )
8850  {
8851  /* remove redundant variables */
8852  for( w = nvars - 1; w >= v; --w )
8853  {
8854  SCIP_CALL( delCoefPos(scip, cons, v) );
8855  ++(*nchgcoefs);
8856  }
8857 
8858 #ifndef NDEBUG
8859  /* each coefficients should exceed the dualcapacity by itself */
8860  for( ; w >= 0; --w )
8861  assert(weights[w] == dualcapacity);
8862 #endif
8863  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8864  * upgrade this constraint
8865  */
8866  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8867  assert(SCIPconsIsDeleted(cons));
8868 
8869  return SCIP_OKAY;
8870  }
8871 
8872  /* special case where we have three different coefficient types
8873  *
8874  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8875  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8876  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8877  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8878  */
8879  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8880  {
8881  SCIP_Longint newcap;
8882 
8883  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8884  for( w = nvars - 1; w >= v; --w )
8885  {
8886  if( weights[w] > 1 )
8887  {
8888  consdataChgWeight(consdata, w, 1LL);
8889  ++(*nchgcoefs);
8890  }
8891  }
8892 
8893  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8894  * dualcapacity
8895  */
8896  newweight = (SCIP_Longint)nvars - v;
8897  assert(newweight > 1);
8898  for( ; w >= startv; --w )
8899  {
8900  if( weights[w] > newweight )
8901  {
8902  consdataChgWeight(consdata, w, newweight);
8903  ++(*nchgcoefs);
8904  }
8905  else
8906  assert(weights[w] == newweight);
8907  }
8908 
8909  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8910  ++newweight;
8911  assert(newweight > 2);
8912  for( ; w >= 0; --w )
8913  {
8914  if( weights[w] > newweight )
8915  {
8916  consdataChgWeight(consdata, w, newweight);
8917  ++(*nchgcoefs);
8918  }
8919  else
8920  assert(weights[w] == newweight);
8921  }
8922 
8923  /* update the capacity */
8924  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8925  if( consdata->capacity > newcap )
8926  {
8927  consdata->capacity = newcap;
8928  ++(*nchgsides);
8929  }
8930  else
8931  assert(consdata->capacity == newcap);
8932  }
8933  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8934 
8935  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8936  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8937 
8938  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8939  * weight must not be sorted by their index
8940  */
8941 #ifndef NDEBUG
8942  for( w = nvars - 1; w > 0; --w )
8943  assert(weights[w] <= weights[w - 1]);
8944 #endif
8945  return SCIP_OKAY;
8946  }
8947 
8948  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8949  end = nvars - 2;
8950  while( end >= 0 && weights[end] == weights[end + 1] )
8951  {
8952  assert(end >= v);
8953  --end;
8954  }
8955 
8956  if( v >= end )
8957  goto TERMINATE;
8958 
8959  end = nvars - 2;
8960 
8961  /* can we stop early, another special reduction case might exist */
8962  if( 2 * weights[end] > dualcapacity )
8963  {
8964  restsumweights = 0;
8965 
8966  /* determine capacity of the small items */
8967  for( w = end + 1; w < nvars; ++w )
8968  restsumweights += weights[w];
8969 
8970  if( restsumweights * 2 <= dualcapacity )
8971  {
8972  /* check for further posssible reductions in the middle */
8973  while( v < end && restsumweights + weights[v] >= dualcapacity )
8974  ++v;
8975 
8976  if( v >= end )
8977  goto TERMINATE;
8978 
8979  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8980  if( (dualcapacity & 1) == 0 )
8981  {
8982  newweight = dualcapacity / 2;
8983 
8984  /* set all middle coefficients */
8985  for( ; v <= end; ++v )
8986  {
8987  if( weights[v] > newweight )
8988  {
8989  reductionsum += (weights[v] - newweight);
8990  consdataChgWeight(consdata, v, newweight);
8991  ++(*nchgcoefs);
8992  }
8993  }
8994  }
8995  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8996  * other coefficients by 2
8997  */
8998  else
8999  {
9000  /* correct the reductionsum */
9001  reductionsum *= 2;
9002 
9003  /* multiply big coefficients by 2 */
9004  for( w = 0; w < v; ++w )
9005  {
9006  consdataChgWeight(consdata, w, weights[w] * 2);
9007  }
9008 
9009  newweight = dualcapacity;
9010  /* set all middle coefficients */
9011  for( ; v <= end; ++v )
9012  {
9013  reductionsum += (2 * weights[v] - newweight);
9014  consdataChgWeight(consdata, v, newweight);
9015  }
9016 
9017  /* multiply small coefficients by 2 */
9018  for( w = end + 1; w < nvars; ++w )
9019  {
9020  consdataChgWeight(consdata, w, weights[w] * 2);
9021  }
9022  (*nchgcoefs) += nvars;
9023 
9024  dualcapacity *= 2;
9025  consdata->capacity *= 2;
9026  ++(*nchgsides);
9027  }
9028  }
9029 
9030  goto TERMINATE;
9031  }
9032 
9033  /* further reductions using the next possible coefficient sum
9034  *
9035  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9036  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9037  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9038  */
9039  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9040  for( k = 0; k < 4; ++k )
9041  {
9042  /* determine next minimal coefficient sum */
9043  switch( k )
9044  {
9045  case 0:
9046  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9047  break;
9048  case 1:
9049  assert(nvars >= 3);
9050  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9051  break;
9052  case 2:
9053  assert(nvars >= 4);
9054  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9055  {
9056  sumcoefcase = TRUE;
9057  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9058  }
9059  else
9060  {
9061  sumcoefcase = FALSE;
9062  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9063  }
9064  break;
9065  case 3:
9066  assert(nvars >= 5);
9067  if( sumcoefcase )
9068  {
9069  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9070  }
9071  else
9072  {
9073  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9074  }
9075  break;
9076  default:
9077  return SCIP_ERROR;
9078  }
9079 
9080  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9081  minweight = weights[end];
9082  while( minweight <= sumcoef )
9083  {
9084  newweight = dualcapacity - minweight;
9085  startv = v;
9086  assert(v < nvars);
9087 
9088  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9089  /* shrink big coefficients */
9090  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9091  {
9092  reductionsum += (weights[v] - newweight);
9093  consdataChgWeight(consdata, v, newweight);
9094  ++v;
9095  assert(v < nvars);
9096  }
9097  (*nchgcoefs) += (v - startv);
9098 
9099  /* skip unchangable weights */
9100  while( weights[v] + minweight == dualcapacity )
9101  {
9102  assert(v < nvars);
9103  ++v;
9104  }
9105 
9106  --end;
9107  /* skip same end weights */
9108  while( end >= 0 && weights[end] == weights[end + 1] )
9109  --end;
9110 
9111  if( v >= end )
9112  goto TERMINATE;
9113 
9114  minweight = weights[end];
9115  }
9116 
9117  if( v >= end )
9118  goto TERMINATE;
9119 
9120  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9121  if( sumcoef < minweight )
9122  {
9123  minweight = sumcoef;
9124  newweight = dualcapacity - minweight;
9125  startv = v;
9126  assert(v < nvars);
9127 
9128  /* shrink big coefficients */
9129  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9130  {
9131  reductionsum += (weights[v] - newweight);
9132  consdataChgWeight(consdata, v, newweight);
9133  ++v;
9134  assert(v < nvars);
9135  }
9136  (*nchgcoefs) += (v - startv);
9137 
9138  /* skip unchangable weights */
9139  while( weights[v] + minweight == dualcapacity )
9140  {
9141  assert(v < nvars);
9142  ++v;
9143  }
9144  }
9145 
9146  if( v >= end )
9147  goto TERMINATE;
9148 
9149  /* can we stop early, another special reduction case might exist */
9150  if( 2 * weights[end] > dualcapacity )
9151  {
9152  restsumweights = 0;
9153 
9154  /* determine capacity of the small items */
9155  for( w = end + 1; w < nvars; ++w )
9156  restsumweights += weights[w];
9157 
9158  if( restsumweights * 2 <= dualcapacity )
9159  {
9160  /* check for further posssible reductions in the middle */
9161  while( v < end && restsumweights + weights[v] >= dualcapacity )
9162  ++v;
9163 
9164  if( v >= end )
9165  goto TERMINATE;
9166 
9167  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9168  if( (dualcapacity & 1) == 0 )
9169  {
9170  newweight = dualcapacity / 2;
9171 
9172  /* set all middle coefficients */
9173  for( ; v <= end; ++v )
9174  {
9175  if( weights[v] > newweight )
9176  {
9177  reductionsum += (weights[v] - newweight);
9178  consdataChgWeight(consdata, v, newweight);
9179  ++(*nchgcoefs);
9180  }
9181  }
9182  }
9183  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9184  * other coefficients by 2
9185  */
9186  else
9187  {
9188  /* correct the reductionsum */
9189  reductionsum *= 2;
9190 
9191  /* multiply big coefficients by 2 */
9192  for( w = 0; w < v; ++w )
9193  {
9194  consdataChgWeight(consdata, w, weights[w] * 2);
9195  }
9196 
9197  newweight = dualcapacity;
9198  /* set all middle coefficients */
9199  for( ; v <= end; ++v )
9200  {
9201  reductionsum += (2 * weights[v] - newweight);
9202  consdataChgWeight(consdata, v, newweight);
9203  }
9204 
9205  /* multiply small coefficients by 2 */
9206  for( w = end + 1; w < nvars; ++w )
9207  {
9208  consdataChgWeight(consdata, w, weights[w] * 2);
9209  }
9210  (*nchgcoefs) += nvars;
9211 
9212  dualcapacity *= 2;
9213  consdata->capacity *= 2;
9214  ++(*nchgsides);
9215  }
9216  }
9217 
9218  goto TERMINATE;
9219  }
9220 
9221  /* cannot tighten any further */
9222  if( 2 * sumcoef > dualcapacity )
9223  goto TERMINATE;
9224  }
9225  }
9226  }
9227 
9228  TERMINATE:
9229  /* correct capacity */
9230  if( reductionsum > 0 )
9231  {
9232  assert(v > 0);
9233 
9234  consdata->capacity -= reductionsum;
9235  ++(*nchgsides);
9236 
9237  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9238  }
9239  assert(weights[0] <= consdata->capacity);
9240 
9241  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9242  * weight must not be sorted by their index
9243  */
9244 #ifndef NDEBUG
9245  for( w = nvars - 1; w > 0; --w )
9246  assert(weights[w] <= weights[w - 1]);
9247 #endif
9248 
9249  if( oldnchgcoefs < *nchgcoefs )
9250  {
9251  assert(!SCIPconsIsDeleted(cons));
9252 
9253  /* it might be that we can divide the weights by their greatest common divisor */
9254  normalizeWeights(cons, nchgcoefs, nchgsides);
9255  }
9256  else
9257  {
9258  assert(oldnchgcoefs == *nchgcoefs);
9259  assert(oldnchgsides == *nchgsides);
9260  }
9261 
9262  return SCIP_OKAY;
9263 }
9264 
9265 
9266 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9267 static
9269  SCIP* scip, /**< SCIP data structure */
9270  SCIP_CONS* cons, /**< knapsack constraint */
9271  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9272  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9273  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9274  )
9275 {
9276  SCIP_VAR** vars;
9277  SCIP_CONSDATA* consdata;
9278  SCIP_Longint* weights;
9279  SCIP_Longint capacity;
9280  SCIP_Bool infeasible;
9281  SCIP_Bool fixed;
9282  int nvars;
9283  int v;
9284 
9285  assert(scip != NULL);
9286  assert(cons != NULL);
9287  assert(nfixedvars != NULL);
9288  assert(ndelconss != NULL);
9289  assert(nchgcoefs != NULL);
9290 
9291  consdata = SCIPconsGetData(cons);
9292  assert(consdata != NULL);
9293 
9294  nvars = consdata->nvars;
9295 
9296  /* no variables left, then delete constraint */
9297  if( nvars == 0 )
9298  {
9299  assert(consdata->capacity >= 0);
9300 
9301  SCIP_CALL( SCIPdelCons(scip, cons) );
9302  ++(*ndelconss);
9303 
9304  return SCIP_OKAY;
9305  }
9306 
9307  /* sort items */
9308  sortItems(consdata);
9309 
9310  vars = consdata->vars;
9311  weights = consdata->weights;
9312  capacity = consdata->capacity;
9313  v = 0;
9314 
9315  /* check for weights bigger than the capacity */
9316  while( v < nvars && weights[v] > capacity )
9317  {
9318  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9319  assert(!infeasible);
9320 
9321  if( fixed )
9322  ++(*nfixedvars);
9323 
9324  ++v;
9325  }
9326 
9327  /* if we fixed at least one variable we need to delete them from the constraint */
9328  if( v > 0 )
9329  {
9330  if( v == nvars )
9331  {
9332  SCIP_CALL( SCIPdelCons(scip, cons) );
9333  ++(*ndelconss);
9334 
9335  return SCIP_OKAY;
9336  }
9337 
9338  /* delete all position from back to front */
9339  for( --v; v >= 0; --v )
9340  {
9341  SCIP_CALL( delCoefPos(scip, cons, v) );
9342  ++(*nchgcoefs);
9343  }
9344 
9345  /* sort items again because of deletion */
9346  sortItems(consdata);
9347  assert(vars == consdata->vars);
9348  assert(weights == consdata->weights);
9349  }
9350  assert(consdata->sorted);
9351  assert(weights[0] <= capacity);
9352 
9353  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9354  {
9355  SCIP_CALL( SCIPdelCons(scip, cons) );
9356  ++(*ndelconss);
9357  }
9358 
9359  return SCIP_OKAY;
9360 }
9361 
9362 
9363 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9364  *
9365  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9366  *
9367  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9368  *
9369  * the above constraint can be changed to
9370  *
9371  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9372  *
9373  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9374  *
9375  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9376  *
9377  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9378  * constraint further, e.g.
9379  *
9380  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9381  * => 2x1 + x2 + x3 + x4 <= 2
9382  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9383  */
9384 static
9386  SCIP* scip, /**< SCIP data structure */
9387  SCIP_CONS* cons, /**< knapsack constraint */
9388  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9389  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9390  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9391  int* nchgsides, /**< pointer to store the amount of changed sides */
9392  int* naddconss, /**< pointer to count number of added constraints */
9393  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9394  )
9395 {
9396  SCIP_VAR** vars;
9397  SCIP_CONSDATA* consdata;
9398  SCIP_Longint* weights;
9399  SCIP_Longint restweight;
9400  SCIP_Longint newweight;
9401  SCIP_Longint weight;
9402  SCIP_Longint oldgcd;
9403  SCIP_Longint rest;
9404  SCIP_Longint gcd;
9405  int oldnchgcoefs;
9406  int oldnchgsides;
9407  int candpos;
9408  int candpos2;
9409  int offsetv;
9410  int nvars;
9411  int v;
9412 
9413  assert(scip != NULL);
9414  assert(cons != NULL);
9415  assert(nfixedvars != NULL);
9416  assert(ndelconss != NULL);
9417  assert(nchgcoefs != NULL);
9418  assert(nchgsides != NULL);
9419  assert(naddconss != NULL);
9420  assert(cutoff != NULL);
9421  assert(!SCIPconsIsModifiable(cons));
9422 
9423  consdata = SCIPconsGetData(cons);
9424  assert( consdata != NULL );
9425 
9426  *cutoff = FALSE;
9427 
9428  /* remove double enties and also combinations of active and negated variables */
9429  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9430  assert(consdata->merged);
9431  if( *cutoff )
9432  return SCIP_OKAY;
9433 
9434  assert(consdata->capacity >= 0);
9435 
9436  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9437  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9438 
9439  if( SCIPconsIsDeleted(cons) )
9440  return SCIP_OKAY;
9441 
9442  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9443  {
9444  /* 1. dual weights tightening */
9445  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9446 
9447  if( SCIPconsIsDeleted(cons) )
9448  return SCIP_OKAY;
9449  /* 2. delete redundant variables */
9450  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9451 
9452  if( SCIPconsIsDeleted(cons) )
9453  return SCIP_OKAY;
9454  }
9455 
9456  weights = consdata->weights;
9457  nvars = consdata->nvars;
9458 
9459 #ifndef NDEBUG
9460  /* constraint might not be sorted, but the weights are already sorted */
9461  for( v = nvars - 1; v > 0; --v )
9462  assert(weights[v] <= weights[v-1]);
9463 #endif
9464 
9465  /* determine greatest common divisor */
9466  gcd = weights[nvars - 1];
9467  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9468  {
9469  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9470  }
9471 
9472  /* divide the constraint by their greatest common divisor */
9473  if( gcd >= 2 )
9474  {
9475  for( v = nvars - 1; v >= 0; --v )
9476  {
9477  consdataChgWeight(consdata, v, weights[v]/gcd);
9478  }
9479  (*nchgcoefs) += nvars;
9480 
9481  consdata->capacity /= gcd;
9482  (*nchgsides)++;
9483  }
9484  assert(consdata->nvars == nvars);
9485 
9486  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9487  * must not be sorted by their index
9488  */
9489 #ifndef NDEBUG
9490  for( v = nvars - 1; v > 0; --v )
9491  assert(weights[v] <= weights[v-1]);
9492 #endif
9493 
9494  /* 3. start gcd procedure for all variables */
9495  do
9496  {
9497  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9498  SCIPdebug( oldnchgsides = *nchgsides; )
9499 
9500  vars = consdata->vars;
9501  weights = consdata->weights;
9502  nvars = consdata->nvars;
9503 
9504  /* stop if we have two coefficients which are one in absolute value */
9505  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9506  return SCIP_OKAY;
9507 
9508  v = 0;
9509  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9510  * gcd
9511  */
9512  while( weights[v] == consdata->capacity )
9513  {
9514  ++v;
9515  assert(v < nvars);
9516  }
9517 
9518  /* all but one variable are as big as the capacity, this is handled elsewhere */
9519  if( v == nvars - 1 )
9520  return SCIP_OKAY;
9521 
9522  offsetv = v;
9523 
9524  gcd = -1;
9525  candpos = -1;
9526  candpos2 = -1;
9527 
9528  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9529  * change the coefficient
9530  */
9531  for( v = nvars - 1; v >= offsetv; --v )
9532  {
9533  weight = weights[v];
9534  assert(weight >= 1);
9535 
9536  oldgcd = gcd;
9537 
9538  if( gcd == -1 )
9539  {
9540  gcd = weights[v];
9541  assert(gcd >= 1);
9542  }
9543  else
9544  {
9545  /* calculate greatest common divisor for all variables */
9546  gcd = SCIPcalcGreComDiv(gcd, weight);
9547  }
9548 
9549  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9550  * can terminate
9551  */
9552  if( gcd == 1 )
9553  {
9554  /* found candidate */
9555  if( candpos == -1 )
9556  {
9557  gcd = oldgcd;
9558  candpos = v;
9559 
9560  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9561  if( v == nvars - 2 )
9562  candpos2 = v + 1;
9563  }
9564  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9565  else
9566  {
9567  if( candpos == v + 1 && candpos2 == v + 2 )
9568  {
9569  assert(candpos2 == nvars - 1);
9570 
9571  /* take new candidates */
9572  candpos = candpos2;
9573 
9574  /* recalculate gcd from scratch */
9575  gcd = weights[v+1];
9576  assert(gcd >= 1);
9577 
9578  /* calculate greatest common divisor for variables */
9579  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9580  if( gcd == 1 )
9581  return SCIP_OKAY;
9582  }
9583  else
9584  /* cannot determine a possible coefficient for reduction */
9585  return SCIP_OKAY;
9586  }
9587  }
9588  }
9589  assert(gcd >= 2);
9590 
9591  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9592  * further
9593  */
9594  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9595 
9596  /* determine the remainder of the capacity and the gcd */
9597  rest = consdata->capacity % gcd;
9598  assert(rest >= 0);
9599  assert(rest < gcd);
9600 
9601  if( candpos == -1 )
9602  {
9603  /* we assume that the constraint was normalized */
9604  assert(rest > 0);
9605 
9606  /* replace old with new capacity */
9607  consdata->capacity -= rest;
9608  ++(*nchgsides);
9609 
9610  /* replace old big coefficients with new capacity */
9611  for( v = 0; v < offsetv; ++v )
9612  {
9613  consdataChgWeight(consdata, v, consdata->capacity);
9614  }
9615 
9616  *nchgcoefs += offsetv;
9617  goto CONTINUE;
9618  }
9619 
9620  /* determine the remainder of the coefficient candidate and the gcd */
9621  restweight = weights[candpos] % gcd;
9622  assert(restweight >= 1);
9623  assert(restweight < gcd);
9624 
9625  /* calculate new coefficient */
9626  if( restweight > rest )
9627  newweight = weights[candpos] - restweight + gcd;
9628  else
9629  newweight = weights[candpos] - restweight;
9630 
9631  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9632 
9633  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);
9634 
9635  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9636  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9637  */
9638  if( newweight == 0 && offsetv > 0 )
9639  return SCIP_OKAY;
9640 
9641  if( rest > 0 )
9642  {
9643  /* replace old with new capacity */
9644  consdata->capacity -= rest;
9645  ++(*nchgsides);
9646 
9647  /* replace old big coefficients with new capacity */
9648  for( v = 0; v < offsetv; ++v )
9649  {
9650  consdataChgWeight(consdata, v, consdata->capacity);
9651  }
9652 
9653  *nchgcoefs += offsetv;
9654  }
9655 
9656  if( newweight == 0 )
9657  {
9658  /* delete redundant coefficient */
9659  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9660  assert(consdata->nvars == nvars - 1);
9661  --nvars;
9662  }
9663  else
9664  {
9665  /* replace old with new coefficient */
9666  consdataChgWeight(consdata, candpos, newweight);
9667  }
9668  ++(*nchgcoefs);
9669 
9670  assert(consdata->vars == vars);
9671  assert(consdata->nvars == nvars);
9672  assert(consdata->weights == weights);
9673 
9674  CONTINUE:
9675  /* now constraint can be normalized, dividing it by the gcd */
9676  for( v = nvars - 1; v >= 0; --v )
9677  {
9678  consdataChgWeight(consdata, v, weights[v]/gcd);
9679  }
9680  (*nchgcoefs) += nvars;
9681 
9682  consdata->capacity /= gcd;
9683  ++(*nchgsides);
9684 
9685  SCIPdebugPrintCons(scip, cons, NULL);
9686 
9687  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));
9688  }
9689  while( nvars >= 2 );
9690 
9691  return SCIP_OKAY;
9692 }
9693 
9694 
9695 /** inserts an element into the list of binary zero implications */
9696 static
9698  SCIP* scip, /**< SCIP data structure */
9699  int** liftcands, /**< array of the lifting candidates */
9700  int* nliftcands, /**< number of lifting candidates */
9701  int** firstidxs, /**< array of first zeroitems indices */
9702  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9703  int** zeroitems, /**< pointer to zero items array */
9704  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9705  int* zeroitemssize, /**< pointer to size of zero items array */
9706  int* nzeroitems, /**< pointer to length of zero items array */
9707  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9708  SCIP_Bool value, /**< value v of variable y in implication */
9709  int knapsackidx, /**< index of variable x in knapsack */
9710  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9711  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9712  )
9713 {
9714  int nzeros;
9715 
9716  assert(liftcands != NULL);
9717  assert(liftcands[value] != NULL);
9718  assert(nliftcands != NULL);
9719  assert(firstidxs != NULL);
9720  assert(firstidxs[value] != NULL);
9721  assert(zeroweightsums != NULL);
9722  assert(zeroweightsums[value] != NULL);
9723  assert(zeroitems != NULL);
9724  assert(nextidxs != NULL);
9725  assert(zeroitemssize != NULL);
9726  assert(nzeroitems != NULL);
9727  assert(*nzeroitems <= *zeroitemssize);
9728  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9729  assert(memlimitreached != NULL);
9730 
9731  nzeros = *nzeroitems;
9732 
9733  /* allocate enough memory */
9734  if( nzeros == *zeroitemssize )
9735  {
9736  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9737  * this can be too huge - abort on memory limit
9738  */
9739  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9740  {
9741  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9742  *zeroitemssize);
9743  *memlimitreached = TRUE;
9744  return SCIP_OKAY;
9745  }
9746  *zeroitemssize *= 2;
9747  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9748  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9749  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9750  }
9751  assert(nzeros < *zeroitemssize);
9752 
9753  if( *memlimitreached )
9754  *memlimitreached = FALSE;
9755 
9756  /* insert element */
9757  (*zeroitems)[nzeros] = knapsackidx;
9758  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9759  if( firstidxs[value][probindex] == 0 )
9760  {
9761  liftcands[value][nliftcands[value]] = probindex;
9762  ++nliftcands[value];
9763  }
9764  firstidxs[value][probindex] = nzeros;
9765  ++(*nzeroitems);
9766  zeroweightsums[value][probindex] += knapsackweight;
9767 
9768  return SCIP_OKAY;
9769 }
9770 
9771 #define MAX_CLIQUELENGTH 50
9772 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9773  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9774  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9775  * if cliqueweightsum(xi == v) < capacity:
9776  * - fixing variable xi to v would make the knapsack constraint redundant
9777  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9778  * redundancy effect:
9779  * wi' := capacity - cliqueweightsum(xi == v)
9780  * this rule can also be applied to binary variables not in the knapsack!
9781  */
9782 static
9784  SCIP* scip, /**< SCIP data structure */
9785  SCIP_CONS* cons, /**< knapsack constraint */
9786  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9787  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9788  )
9789 {
9790  SCIP_CONSDATA* consdata;
9791  SCIP_VAR** binvars;
9792  int nbinvars;
9793  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9794  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9795  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9796  int* zeroitems; /* item number in knapsack that is implied to zero */
9797  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9798  int zeroitemssize;
9799  int nzeroitems;
9800  SCIP_Bool* zeroiteminserted[2];
9801  SCIP_Bool memlimitreached;
9802  int nliftcands[2];
9803  SCIP_Bool* cliqueused;
9804  SCIP_Bool* itemremoved;
9805  SCIP_Longint maxcliqueweightsum;
9806  SCIP_VAR** addvars;
9807  SCIP_Longint* addweights;
9808  SCIP_Longint addweightsum;
9809  int nvars;
9810  int cliquenum;
9811  int naddvars;
9812  int val;
9813  int i;
9814 
9815  int* tmpindices;
9816  SCIP_Bool* tmpboolindices;
9817  int* tmpindices2;
9818  SCIP_Bool* tmpboolindices2;
9819  int* tmpindices3;
9820  SCIP_Bool* tmpboolindices3;
9821  int tmp;
9822  int tmp2;
9823  int tmp3;
9824  SCIP_CONSHDLR* conshdlr;
9825  SCIP_CONSHDLRDATA* conshdlrdata;
9826 
9827  assert(nchgcoefs != NULL);
9828  assert(!SCIPconsIsModifiable(cons));
9829 
9830  consdata = SCIPconsGetData(cons);
9831  assert(consdata != NULL);
9832  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9833  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9834  assert(consdata->nvars > 0);
9835  assert(consdata->merged);
9836 
9837  nvars = consdata->nvars;
9838 
9839  /* check if the knapsack has too many items/cliques for applying this costly method */
9840  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9841  return SCIP_OKAY;
9842 
9843  /* sort items, s.t. the heaviest one is in the first position */
9844  sortItems(consdata);
9845 
9846  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9847  return SCIP_OKAY;
9848 
9849  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9850  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9851  assert(nbinvars > 0);
9852  binvars = SCIPgetVars(scip);
9853 
9854  /* get conshdlrdata to use cleared memory */
9855  conshdlr = SCIPconsGetHdlr(cons);
9856  assert(conshdlr != NULL);
9857  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9858  assert(conshdlrdata != NULL);
9859 
9860  /* allocate temporary memory for the list of implied to zero variables */
9861  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9862  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9863  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9864 
9865  assert(conshdlrdata->ints1size > 0);
9866  assert(conshdlrdata->ints2size > 0);
9867  assert(conshdlrdata->longints1size > 0);
9868  assert(conshdlrdata->longints2size > 0);
9869 
9870  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9871  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9872  * transform all integers into their binary representation then it maybe happens
9873  */
9874  if( conshdlrdata->ints1size < nbinvars )
9875  {
9876  int oldsize = conshdlrdata->ints1size;
9877 
9878  conshdlrdata->ints1size = nbinvars;
9879  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9880  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9881  }
9882  if( conshdlrdata->ints2size < nbinvars )
9883  {
9884  int oldsize = conshdlrdata->ints2size;
9885 
9886  conshdlrdata->ints2size = nbinvars;
9887  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9888  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9889  }
9890  if( conshdlrdata->longints1size < nbinvars )
9891  {
9892  int oldsize = conshdlrdata->longints1size;
9893 
9894  conshdlrdata->longints1size = nbinvars;
9895  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9896  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9897  }
9898  if( conshdlrdata->longints2size < nbinvars )
9899  {
9900  int oldsize = conshdlrdata->longints2size;
9901 
9902  conshdlrdata->longints2size = nbinvars;
9903  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9904  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9905  }
9906 
9907  firstidxs[0] = conshdlrdata->ints1;
9908  firstidxs[1] = conshdlrdata->ints2;
9909  zeroweightsums[0] = conshdlrdata->longints1;
9910  zeroweightsums[1] = conshdlrdata->longints2;
9911 
9912  /* check for cleared arrays, all entries are zero */
9913 #ifndef NDEBUG
9914  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9915  {
9916  assert(firstidxs[0][tmp] == 0);
9917  assert(firstidxs[1][tmp] == 0);
9918  assert(zeroweightsums[0][tmp] == 0);
9919  assert(zeroweightsums[1][tmp] == 0);
9920  }
9921 #endif
9922 
9923  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9924  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9925 
9926  zeroitems[0] = -1; /* dummy element */
9927  nextidxs[0] = -1;
9928  nzeroitems = 1;
9929  nliftcands[0] = 0;
9930  nliftcands[1] = 0;
9931 
9932  assert(conshdlrdata->bools1size > 0);
9933  assert(conshdlrdata->bools2size > 0);
9934 
9935  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9936  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9937  * transform all integers into their binary representation then it maybe happens
9938  */
9939  if( conshdlrdata->bools1size < nbinvars )
9940  {
9941  int oldsize = conshdlrdata->bools1size;
9942 
9943  conshdlrdata->bools1size = nbinvars;
9944  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9945  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9946  }
9947  if( conshdlrdata->bools2size < nbinvars )
9948  {
9949  int oldsize = conshdlrdata->bools2size;
9950 
9951  conshdlrdata->bools2size = nbinvars;
9952  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9953  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9954  }
9955 
9956  zeroiteminserted[0] = conshdlrdata->bools1;
9957  zeroiteminserted[1] = conshdlrdata->bools2;
9958 
9959  /* check for cleared arrays, all entries are zero */
9960 #ifndef NDEBUG
9961  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9962  {
9963  assert(zeroiteminserted[0][tmp] == 0);
9964  assert(zeroiteminserted[1][tmp] == 0);
9965  }
9966 #endif
9967 
9968  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9969  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9970  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9971  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9972  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9973  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9974 
9975  tmp2 = 0;
9976  tmp3 = 0;
9977 
9978  memlimitreached = FALSE;
9979  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9980  {
9981  SCIP_CLIQUE** cliques;
9982  SCIP_VAR* var;
9983  SCIP_Longint weight;
9984  SCIP_Bool value;
9985  int varprobindex;
9986  int ncliques;
9987  int j;
9988 
9989  tmp = 0;
9990 
9991  /* get corresponding active problem variable */
9992  var = consdata->vars[i];
9993  weight = consdata->weights[i];
9994  value = TRUE;
9995  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9996  varprobindex = SCIPvarGetProbindex(var);
9997  assert(0 <= varprobindex && varprobindex < nbinvars);
9998 
9999  /* update the zeroweightsum */
10000  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10001  tmpboolindices3[tmp3] = !value;
10002  tmpindices3[tmp3] = varprobindex;
10003  ++tmp3;
10004 
10005  /* initialize the arrays of inserted zero items */
10006  /* first add the implications (~x == 1 -> x == 0) */
10007  {
10008  SCIP_Bool implvalue;
10009  int probindex;
10010 
10011  probindex = SCIPvarGetProbindex(var);
10012  assert(0 <= probindex && probindex < nbinvars);
10013 
10014  implvalue = !value;
10015 
10016  /* insert the item into the list of the implied variable/value */
10017  assert( !zeroiteminserted[implvalue][probindex] );
10018 
10019  if( firstidxs[implvalue][probindex] == 0 )
10020  {
10021  tmpboolindices2[tmp2] = implvalue;
10022  tmpindices2[tmp2] = probindex;
10023  ++tmp2;
10024  }
10025  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10026  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10027  &memlimitreached) );
10028  zeroiteminserted[implvalue][probindex] = TRUE;
10029  tmpboolindices[tmp] = implvalue;
10030  tmpindices[tmp] = probindex;
10031  ++tmp;
10032  }
10033 
10034  /* get the cliques where the knapsack item is member of with value 1 */
10035  ncliques = SCIPvarGetNCliques(var, value);
10036  cliques = SCIPvarGetCliques(var, value);
10037  for( j = 0; j < ncliques && !memlimitreached; ++j )
10038  {
10039  SCIP_VAR** cliquevars;
10040  SCIP_Bool* cliquevalues;
10041  int ncliquevars;
10042  int k;
10043 
10044  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10045 
10046  /* discard big cliques */
10047  if( ncliquevars > MAX_CLIQUELENGTH )
10048  continue;
10049 
10050  cliquevars = SCIPcliqueGetVars(cliques[j]);
10051  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10052 
10053  for( k = ncliquevars - 1; k >= 0; --k )
10054  {
10055  SCIP_Bool implvalue;
10056  int probindex;
10057 
10058  if( var == cliquevars[k] )
10059  continue;
10060 
10061  probindex = SCIPvarGetProbindex(cliquevars[k]);
10062  if( probindex == -1 )
10063  continue;
10064 
10065  assert(0 <= probindex && probindex < nbinvars);
10066  implvalue = cliquevalues[k];
10067 
10068  /* insert the item into the list of the clique variable/value */
10069  if( !zeroiteminserted[implvalue][probindex] )
10070  {
10071  if( firstidxs[implvalue][probindex] == 0 )
10072  {
10073  tmpboolindices2[tmp2] = implvalue;
10074  tmpindices2[tmp2] = probindex;
10075  ++tmp2;
10076  }
10077 
10078  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10079  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10080  &memlimitreached) );
10081  zeroiteminserted[implvalue][probindex] = TRUE;
10082  tmpboolindices[tmp] = implvalue;
10083  tmpindices[tmp] = probindex;
10084  ++tmp;
10085 
10086  if( memlimitreached )
10087  break;
10088  }
10089  }
10090  }
10091  /* clear zeroiteminserted */
10092  for( --tmp; tmp >= 0; --tmp)
10093  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10094  }
10095  SCIPfreeBufferArray(scip, &tmpboolindices);
10096 
10097  /* calculate the clique partition and the maximal sum of weights using the clique information */
10098  assert(consdata->sorted);
10099  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10100 
10101  assert(conshdlrdata->bools3size > 0);
10102 
10103  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10104  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10105  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10106  */
10107  if( conshdlrdata->bools3size < consdata->nvars )
10108  {
10109  int oldsize = conshdlrdata->bools3size;
10110 
10111  conshdlrdata->bools3size = consdata->nvars;;
10112  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10113  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10114  }
10115 
10116  cliqueused = conshdlrdata->bools3;
10117 
10118  /* check for cleared array, all entries are zero */
10119 #ifndef NDEBUG
10120  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10121  assert(cliqueused[tmp] == 0);
10122 #endif
10123 
10124  maxcliqueweightsum = 0;
10125  tmp = 0;
10126 
10127  /* calculates maximal weight of cliques */
10128  for( i = 0; i < consdata->nvars; ++i )
10129  {
10130  cliquenum = consdata->cliquepartition[i];
10131  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10132 
10133  if( !cliqueused[cliquenum] )
10134  {
10135  maxcliqueweightsum += consdata->weights[i];
10136  cliqueused[cliquenum] = TRUE;
10137  tmpindices[tmp] = cliquenum;
10138  ++tmp;
10139  }
10140  }
10141  /* clear cliqueused */
10142  for( --tmp; tmp >= 0; --tmp)
10143  cliqueused[tmp] = FALSE;
10144 
10145  assert(conshdlrdata->bools4size > 0);
10146 
10147  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10148  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10149  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10150  */
10151  if( conshdlrdata->bools4size < consdata->nvars )
10152  {
10153  int oldsize = conshdlrdata->bools4size;
10154 
10155  conshdlrdata->bools4size = consdata->nvars;
10156  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10157  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10158  }
10159 
10160  itemremoved = conshdlrdata->bools4;
10161 
10162  /* check for cleared array, all entries are zero */
10163 #ifndef NDEBUG
10164  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10165  assert(itemremoved[tmp] == 0);
10166 #endif
10167 
10168  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10169  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10170  * included in subsequent cliqueweightsum calculations)
10171  */
10172  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10173  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10174  naddvars = 0;
10175  addweightsum = 0;
10176  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10177  {
10178  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10179  {
10180  SCIP_Longint cliqueweightsum;
10181  int probindex;
10182  int idx;
10183  int j;
10184 
10185  tmp = 0;
10186 
10187  probindex = liftcands[val][i];
10188  assert(0 <= probindex && probindex < nbinvars);
10189 
10190  /* ignore empty zero lists and variables that cannot be lifted anyways */
10191  if( firstidxs[val][probindex] == 0
10192  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10193  continue;
10194 
10195  /* mark the items that are implied to zero by setting the current variable to the current value */
10196  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10197  {
10198  assert(0 < idx && idx < nzeroitems);
10199  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10200  itemremoved[zeroitems[idx]] = TRUE;
10201  }
10202 
10203  /* calculate the residual cliqueweight sum */
10204  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10205  for( j = 0; j < consdata->nvars; ++j )
10206  {
10207  cliquenum = consdata->cliquepartition[j];
10208  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10209  if( !itemremoved[j] )
10210  {
10211  if( !cliqueused[cliquenum] )
10212  {
10213  cliqueweightsum += consdata->weights[j];
10214  cliqueused[cliquenum] = TRUE;
10215  tmpindices[tmp] = cliquenum;
10216  ++tmp;
10217  }
10218 
10219  if( cliqueweightsum >= consdata->capacity )
10220  break;
10221  }
10222  }
10223 
10224  /* check if the weight of the variable/value can be increased */
10225  if( cliqueweightsum < consdata->capacity )
10226  {
10227  SCIP_VAR* var;
10228  SCIP_Longint weight;
10229 
10230  /* insert the variable (with value TRUE) in the list of additional items */
10231  assert(naddvars < 2*nbinvars);
10232  var = binvars[probindex];
10233  if( val == FALSE )
10234  {
10235  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10236  }
10237  weight = consdata->capacity - cliqueweightsum;
10238  addvars[naddvars] = var;
10239  addweights[naddvars] = weight;
10240  addweightsum += weight;
10241  naddvars++;
10242 
10243  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10244  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10245  }
10246 
10247  /* clear itemremoved */
10248  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10249  {
10250  assert(0 < idx && idx < nzeroitems);
10251  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10252  itemremoved[zeroitems[idx]] = FALSE;
10253  }
10254  /* clear cliqueused */
10255  for( --tmp; tmp >= 0; --tmp)
10256  cliqueused[tmpindices[tmp]] = FALSE;
10257  }
10258  }
10259 
10260  /* clear part of zeroweightsums */
10261  for( --tmp3; tmp3 >= 0; --tmp3)
10262  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10263 
10264  /* clear rest of zeroweightsums and firstidxs */
10265  for( --tmp2; tmp2 >= 0; --tmp2)
10266  {
10267  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10268  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10269  }
10270 
10271  /* add all additional item weights */
10272  for( i = 0; i < naddvars; ++i )
10273  {
10274  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10275  }
10276  *nchgcoefs += naddvars;
10277 
10278  if( naddvars > 0 )
10279  {
10280  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10281  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10282  }
10283 
10284  /* free temporary memory */
10285  SCIPfreeBufferArray(scip, &addweights);
10286  SCIPfreeBufferArray(scip, &addvars);
10287  SCIPfreeBufferArray(scip, &tmpindices);
10288  SCIPfreeBufferArray(scip, &tmpindices2);
10289  SCIPfreeBufferArray(scip, &tmpindices3);
10290  SCIPfreeBufferArray(scip, &tmpboolindices2);
10291  SCIPfreeBufferArray(scip, &tmpboolindices3);
10292  SCIPfreeBufferArray(scip, &nextidxs);
10293  SCIPfreeBufferArray(scip, &zeroitems);
10294  SCIPfreeBufferArray(scip, &liftcands[1]);
10295  SCIPfreeBufferArray(scip, &liftcands[0]);
10296 
10297  return SCIP_OKAY;
10298 }
10299 
10300 /** tightens item weights and capacity in presolving:
10301  * given a knapsack sum(wi*xi) <= capacity
10302  * (1) let weightsum := sum(wi)
10303  * if weightsum - wi < capacity:
10304  * - not using item i would make the knapsack constraint redundant
10305  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10306  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10307  * - change coefficients:
10308  * wi' := weightsum - capacity
10309  * capacity' := capacity - (wi - wi')
10310  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10311  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10312  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10313  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10314  * can be multiple times the same weight, this can be improved
10315  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10316  * weight, to capacity - lastmininmalweightsum, e.g. :
10317  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10318  * -> minimal weightsums: 5, 5, 10, 10
10319  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10320  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10321  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10322  * (3) let W(C) be the maximal weight of clique C,
10323  * cliqueweightsum := sum(W(C))
10324  * if cliqueweightsum - W(C) < capacity:
10325  * - not using any item of C would make the knapsack constraint redundant
10326  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10327  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10328  * - change coefficients:
10329  * delta := capacity - (cliqueweightsum - W(C))
10330  * wi' := max(wi - delta, 0)
10331  * capacity' := capacity - delta
10332  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10333  * introduce infeasible solutions.
10334  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10335  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10336  * if cliqueweightsum(xi == v) < capacity:
10337  * - fixing variable xi to v would make the knapsack constraint redundant
10338  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10339  * redundancy effect:
10340  * wi' := capacity - cliqueweightsum(xi == v)
10341  * This rule can also be applied to binary variables not in the knapsack!
10342  * (5) if min{w} + wi > capacity:
10343  * - using item i would force to fix other items to zero
10344  * - wi can be increased to the capacity
10345  */
10346 static
10348  SCIP* scip, /**< SCIP data structure */
10349  SCIP_CONS* cons, /**< knapsack constraint */
10350  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10351  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10352  int* nchgsides, /**< pointer to count number of side changes */
10353  int* naddconss, /**< pointer to count number of added constraints */
10354  int* ndelconss, /**< pointer to count number of deleted constraints */
10355  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10356  )
10357 {
10358  SCIP_CONSHDLRDATA* conshdlrdata;
10359  SCIP_CONSDATA* consdata;
10360  SCIP_Longint* weights;
10361  SCIP_Longint sumcoef;
10362  SCIP_Longint capacity;
10363  SCIP_Longint newweight;
10364  SCIP_Longint maxweight;
10365  SCIP_Longint minweight;
10366  SCIP_Bool sumcoefcase = FALSE;
10367  int startpos;
10368  int backpos;
10369  int nvars;
10370  int pos;
10371  int k;
10372  int i;
10373 
10374  assert(nchgcoefs != NULL);
10375  assert(nchgsides != NULL);
10376  assert(!SCIPconsIsModifiable(cons));
10377 
10378  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10379  assert(conshdlrdata != NULL);
10380 
10381  consdata = SCIPconsGetData(cons);
10382  assert(consdata != NULL);
10383  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10384  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10385  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10386  assert(consdata->nvars > 0);
10387 
10388  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10389  if( *cutoff )
10390  return SCIP_OKAY;
10391 
10392  /* apply rule (1) */
10393  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10394  {
10395  do
10396  {
10397  assert(consdata->merged);
10398 
10399  /* sort items, s.t. the heaviest one is in the first position */
10400  sortItems(consdata);
10401 
10402  for( i = 0; i < consdata->nvars; ++i )
10403  {
10404  SCIP_Longint weight;
10405 
10406  weight = consdata->weights[i];
10407  if( consdata->weightsum - weight < consdata->capacity )
10408  {
10409  newweight = consdata->weightsum - consdata->capacity;
10410  consdataChgWeight(consdata, i, newweight);
10411  consdata->capacity -= (weight - newweight);
10412  (*nchgcoefs)++;
10413  (*nchgsides)++;
10414  assert(!consdata->sorted);
10415  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",
10416  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10417  consdata->capacity + (weight-newweight), consdata->capacity);
10418  }
10419  else
10420  break;
10421  }
10422  }
10423  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10424  }
10425 
10426  /* check for redundancy */
10427  if( consdata->weightsum <= consdata->capacity )
10428  return SCIP_OKAY;
10429 
10430  pos = 0;
10431  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10432  ++pos;
10433 
10434  sumcoef = 0;
10435  weights = consdata->weights;
10436  nvars = consdata->nvars;
10437  capacity = consdata->capacity;
10438 
10439  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10440  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10441  {
10442  /* further reductions using the next possible coefficient sum
10443  *
10444  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10445  */
10446  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10447  for( k = 0; k < 4; ++k )
10448  {
10449  newweight = capacity - sumcoef;
10450 
10451  /* determine next minimal coefficient sum */
10452  switch( k )
10453  {
10454  case 0:
10455  sumcoef = weights[nvars - 1];
10456  backpos = nvars - 1;
10457  break;
10458  case 1:
10459  sumcoef = weights[nvars - 2];
10460  backpos = nvars - 2;
10461  break;
10462  case 2:
10463  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10464  {
10465  sumcoefcase = TRUE;
10466  sumcoef = weights[nvars - 3];
10467  backpos = nvars - 3;
10468  }
10469  else
10470  {
10471  sumcoefcase = FALSE;
10472  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10473  backpos = nvars - 2;
10474  }
10475  break;
10476  default:
10477  assert(k == 3);
10478  if( sumcoefcase )
10479  {
10480  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10481  {
10482  sumcoef = weights[nvars - 4];
10483  backpos = nvars - 4;
10484  }
10485  else
10486  {
10487  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10488  backpos = nvars - 2;
10489  }
10490  }
10491  else
10492  {
10493  sumcoef = weights[nvars - 3];
10494  backpos = nvars - 3;
10495  }
10496  break;
10497  }
10498 
10499  if( backpos <= pos )
10500  break;
10501 
10502  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10503  maxweight = weights[pos];
10504  startpos = pos;
10505  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10506  {
10507  assert(newweight > weights[pos]);
10508 
10509  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10510  SCIPconsGetName(cons), maxweight, newweight);
10511 
10512  consdataChgWeight(consdata, pos, newweight);
10513 
10514  ++pos;
10515  assert(pos < nvars);
10516 
10517  maxweight = weights[pos];
10518 
10519  if( backpos <= pos )
10520  break;
10521  }
10522  (*nchgcoefs) += (pos - startpos);
10523 
10524  /* skip unchangable weights */
10525  while( pos < nvars && weights[pos] + sumcoef == capacity )
10526  ++pos;
10527 
10528  /* check special case were there is only one weight left to tighten
10529  *
10530  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10531  *
10532  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10533  *
10534  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10535  */
10536  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10537  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10538  {
10539  newweight = capacity - sumcoef;
10540  assert(newweight > weights[pos]);
10541 
10542  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10543  SCIPconsGetName(cons), maxweight, newweight);
10544 
10545  consdataChgWeight(consdata, pos, newweight);
10546 
10547  break;
10548  }
10549 
10550  if( backpos <= pos )
10551  break;
10552  }
10553  }
10554 
10555  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10556  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10557  {
10558  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10559  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10560  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10561  {
10562  SCIP_VAR** clqvars;
10563  SCIP_CONS* cliquecons;
10564  char name[SCIP_MAXSTRLEN];
10565  int* clqpart;
10566  int nclqvars;
10567  int nclq;
10568  int len;
10569  int c;
10570  int w;
10571 
10572  assert(!SCIPconsIsDeleted(cons));
10573 
10574  if( pos == consdata->nvars )
10575  {
10576  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10577 
10578  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10582  SCIPconsIsStickingAtNode(cons)) );
10583 
10584  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10585  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10586  ++(*naddconss);
10587 
10588  /* delete old constraint */
10589  SCIP_CALL( SCIPdelCons(scip, cons) );
10590  ++(*ndelconss);
10591 
10592  return SCIP_OKAY;
10593  }
10594 
10595  len = consdata->nvars - pos;
10596 
10597  /* allocate temporary memory */
10598  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10599 
10600  /* calculate clique partition */
10601  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10602  assert(nclq <= len);
10603 
10604 #ifndef NDEBUG
10605  /* clique numbers must be at least as high as the index */
10606  for( w = 0; w < nclq; ++w )
10607  assert(clqpart[w] <= w);
10608 #endif
10609 
10610  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10611 
10612  /* allocate temporary memory */
10613  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10614 
10615  /* copy corresponding variables with big coefficients */
10616  for( w = pos - 1; w >= 0; --w )
10617  clqvars[w] = consdata->vars[w];
10618 
10619  /* create for each clique a set-packing constraint */
10620  for( c = 0; c < nclq; ++c )
10621  {
10622  nclqvars = pos;
10623 
10624  for( w = c; w < len; ++w )
10625  {
10626  if( clqpart[w] == c )
10627  {
10628  assert(nclqvars < pos + len - nclq + 1);
10629  clqvars[nclqvars] = consdata->vars[w + pos];
10630  ++nclqvars;
10631  }
10632  }
10633 
10634  assert(nclqvars > 1);
10635 
10636  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10637  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10641  SCIPconsIsStickingAtNode(cons)) );
10642  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10643  SCIPdebugPrintCons(scip, cliquecons, NULL);
10644  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10645  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10646  ++(*naddconss);
10647  }
10648 
10649  /* delete old constraint */
10650  SCIP_CALL( SCIPdelCons(scip, cons) );
10651  ++(*ndelconss);
10652 
10653  SCIPfreeBufferArray(scip, &clqvars);
10654  SCIPfreeBufferArray(scip, &clqpart);
10655 
10656  return SCIP_OKAY;
10657  }
10658  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10659  {
10660  SCIP_Longint* maxcliqueweights;
10661  SCIP_Longint* newweightvals;
10662  int* newweightidxs;
10663  SCIP_Longint cliqueweightsum;
10664 
10665  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10666  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10667  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10668 
10669  /* repeat as long as changes have been applied */
10670  do
10671  {
10672  int ncliques;
10673  int cliquenum;
10674  SCIP_Bool zeroweights;
10675 
10676  assert(consdata->merged);
10677 
10678  /* sort items, s.t. the heaviest one is in the first position */
10679  sortItems(consdata);
10680 
10681  /* calculate a clique partition */
10682  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10683 
10684  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10685  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10686  break;
10687 
10688  /* calculate the maximal weight of the cliques and store the clique type */
10689  cliqueweightsum = 0;
10690  ncliques = 0;
10691 
10692  for( i = 0; i < consdata->nvars; ++i )
10693  {
10694  SCIP_Longint weight;
10695 
10696  cliquenum = consdata->cliquepartition[i];
10697  assert(0 <= cliquenum && cliquenum <= ncliques);
10698 
10699  weight = consdata->weights[i];
10700  assert(weight > 0);
10701 
10702  if( cliquenum == ncliques )
10703  {
10704  maxcliqueweights[ncliques] = weight;
10705  cliqueweightsum += weight;
10706  ++ncliques;
10707  }
10708 
10709  assert(maxcliqueweights[cliquenum] >= weight);
10710  }
10711 
10712  /* apply rule on every clique */
10713  zeroweights = FALSE;
10714  for( i = 0; i < ncliques; ++i )
10715  {
10716  SCIP_Longint delta;
10717 
10718  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10719  if( delta > 0 )
10720  {
10721  SCIP_Longint newcapacity;
10722 #ifndef NDEBUG
10723  SCIP_Longint newmincliqueweight;
10724 #endif
10725  SCIP_Longint newminweightsuminclique;
10726  SCIP_Bool forceclique;
10727  int nnewweights;
10728  int j;
10729 
10730  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",
10731  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10732  newcapacity = consdata->capacity - delta;
10733  forceclique = FALSE;
10734  nnewweights = 0;
10735 #ifndef NDEBUG
10736  newmincliqueweight = newcapacity + 1;
10737  for( j = 0; j < i; ++j )
10738  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10739 #endif
10740  for( j = i; j < consdata->nvars; ++j )
10741  {
10742  if( consdata->cliquepartition[j] == i )
10743  {
10744  newweight = consdata->weights[j] - delta;
10745  newweight = MAX(newweight, 0);
10746 
10747  /* cache the new weight */
10748  assert(nnewweights < consdata->nvars);
10749  newweightvals[nnewweights] = newweight;
10750  newweightidxs[nnewweights] = j;
10751  nnewweights++;
10752 
10753 #ifndef NDEBUG
10754  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10755  newmincliqueweight = newweight;
10756 #endif
10757  }
10758  }
10759 
10760  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10761  if( nnewweights > 1 )
10762  {
10763 #ifndef NDEBUG
10764  j = newweightidxs[nnewweights - 2];
10765  assert(0 <= j && j < consdata->nvars);
10766  assert(consdata->cliquepartition[j] == i);
10767  j = newweightidxs[nnewweights - 1];
10768  assert(0 <= j && j < consdata->nvars);
10769  assert(consdata->cliquepartition[j] == i);
10770 #endif
10771 
10772  newminweightsuminclique = newweightvals[nnewweights - 2];
10773  newminweightsuminclique += newweightvals[nnewweights - 1];
10774 
10775  /* check if these new two minimal weights both fit into the knapsack;
10776  * if this is true, we have to add a clique constraint in order to enforce the clique
10777  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10778  * reduction might be infeasible, i.e., allows additional solutions)
10779  */
10780  if( newminweightsuminclique <= newcapacity )
10781  forceclique = TRUE;
10782  }
10783 
10784  /* check if we really want to apply the change */
10785  if( conshdlrdata->disaggregation || !forceclique )
10786  {
10787  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10788  consdata->capacity, newcapacity, forceclique);
10789  consdata->capacity = newcapacity;
10790  (*nchgsides)++;
10791 
10792  for( k = 0; k < nnewweights; ++k )
10793  {
10794  j = newweightidxs[k];
10795  assert(0 <= j && j < consdata->nvars);
10796  assert(consdata->cliquepartition[j] == i);
10797 
10798  /* apply the weight change */
10799  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10800  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10801  consdataChgWeight(consdata, j, newweightvals[k]);
10802  (*nchgcoefs)++;
10803  assert(!consdata->sorted);
10804  zeroweights = zeroweights || (newweightvals[k] == 0);
10805  }
10806  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10807  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10808  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10809  * knapsack constraint
10810  */
10811  if( forceclique )
10812  {
10813  SCIP_CONS* cliquecons;
10814  char name[SCIP_MAXSTRLEN];
10815  SCIP_VAR** cliquevars;
10816 
10817  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10818  for( k = 0; k < nnewweights; ++k )
10819  cliquevars[k] = consdata->vars[newweightidxs[k]];
10820 
10821  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10822  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10826  SCIPconsIsStickingAtNode(cons)) );
10827  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10828  SCIPdebugPrintCons(scip, cliquecons, NULL);
10829  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10830  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10831  SCIPfreeBufferArray(scip, &cliquevars);
10832  (*naddconss)++;
10833  }
10834  }
10835  }
10836  }
10837  if( zeroweights )
10838  {
10839  SCIP_CALL( removeZeroWeights(scip, cons) );
10840  }
10841  }
10842  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10843 
10844  /* free temporary memory */
10845  SCIPfreeBufferArray(scip, &newweightidxs);
10846  SCIPfreeBufferArray(scip, &newweightvals);
10847  SCIPfreeBufferArray(scip, &maxcliqueweights);
10848 
10849  /* check for redundancy */
10850  if( consdata->weightsum <= consdata->capacity )
10851  return SCIP_OKAY;
10852  }
10853  }
10854 
10855  /* apply rule (3) */
10856  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10857  {
10858  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10859  }
10860 
10861  /* check for redundancy */
10862  if( consdata->weightsum <= consdata->capacity )
10863  return SCIP_OKAY;
10864 
10865  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10866  {
10867  /* apply rule (4) (all but smallest weight) */
10868  assert(consdata->merged);
10869  sortItems(consdata);
10870  minweight = consdata->weights[consdata->nvars-1];
10871  for( i = 0; i < consdata->nvars-1; ++i )
10872  {
10873  SCIP_Longint weight;
10874 
10875  weight = consdata->weights[i];
10876  assert(weight >= minweight);
10877  if( minweight + weight > consdata->capacity )
10878  {
10879  if( weight < consdata->capacity )
10880  {
10881  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10882  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10883  assert(consdata->sorted);
10884  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10885  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10886  consdata->sorted = TRUE;
10887  (*nchgcoefs)++;
10888  }
10889  }
10890  else
10891  break;
10892  }
10893 
10894  /* apply rule (5) (smallest weight) */
10895  if( consdata->nvars >= 2 )
10896  {
10897  SCIP_Longint weight;
10898 
10899  minweight = consdata->weights[consdata->nvars-2];
10900  weight = consdata->weights[consdata->nvars-1];
10901  assert(minweight >= weight);
10902  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10903  {
10904  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10905  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10906  assert(consdata->sorted);
10907  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10908  assert(minweight >= consdata->weights[consdata->nvars-1]);
10909  consdata->sorted = TRUE;
10910  (*nchgcoefs)++;
10911  }
10912  }
10913  }
10914 
10915  return SCIP_OKAY;
10916 }
10917 
10918 
10919 #ifdef SCIP_DEBUG
10920 static
10921 void printClique(
10922  SCIP_VAR** cliquevars,
10923  int ncliquevars
10924  )
10925 {
10926  int b;
10927  SCIPdebugMessage("adding new Clique: ");
10928  for( b = 0; b < ncliquevars; ++b )
10929  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10930  SCIPdebugPrintf("\n");
10931 }
10932 #endif
10933 
10934 /** adds negated cliques of the knapsack constraint to the global clique table */
10935 static
10937  SCIP*const scip, /**< SCIP data structure */
10938  SCIP_CONS*const cons, /**< knapsack constraint */
10939  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10940  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10941  )
10942 {
10943  SCIP_CONSDATA* consdata;
10944  SCIP_CONSHDLRDATA* conshdlrdata;
10945  SCIP_VAR** poscliquevars;
10946  SCIP_VAR** cliquevars;
10947  SCIP_Longint* maxweights;
10948  SCIP_Longint* gainweights;
10949  int* gaincliquepartition;
10950  SCIP_Bool* cliqueused;
10951  SCIP_Longint minactduetonegcliques;
10952  SCIP_Longint freecapacity;
10953  SCIP_Longint lastweight;
10954  SCIP_Longint beforelastweight;
10955  int nposcliquevars;
10956  int ncliquevars;
10957  int nvars;
10958  int nnegcliques;
10959  int lastcliqueused;
10960  int thisnbdchgs;
10961  int v;
10962  int w;
10963 
10964  assert(scip != NULL);
10965  assert(cons != NULL);
10966  assert(cutoff != NULL);
10967  assert(nbdchgs != NULL);
10968 
10969  *cutoff = FALSE;
10970 
10971  consdata = SCIPconsGetData(cons);
10972  assert(consdata != NULL);
10973 
10974  nvars = consdata->nvars;
10975 
10976  /* check whether the cliques have already been added */
10977  if( consdata->cliquesadded || nvars == 0 )
10978  return SCIP_OKAY;
10979 
10980  /* make sure, the items are merged */
10981  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10982  if( *cutoff )
10983  return SCIP_OKAY;
10984 
10985  /* make sure, items are sorted by non-increasing weight */
10986  sortItems(consdata);
10987 
10988  assert(consdata->merged);
10989 
10990  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10991  assert(conshdlrdata != NULL);
10992 
10993  /* calculate a clique partition */
10994  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10995  nnegcliques = consdata->nnegcliques;
10996 
10997  /* if we have no negated cliques, stop */
10998  if( nnegcliques == nvars )
10999  return SCIP_OKAY;
11000 
11001  /* get temporary memory */
11002  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11003  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11004  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11005  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11006  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11007  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11008 
11009  nnegcliques = 0;
11010  minactduetonegcliques = 0;
11011 
11012  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11013  for( v = 0; v < nvars; ++v )
11014  {
11015  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11016  assert(consdata->weights[v] > 0);
11017 
11018  if( consdata->negcliquepartition[v] == nnegcliques )
11019  {
11020  nnegcliques++;
11021  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11022  }
11023  else
11024  minactduetonegcliques += consdata->weights[v];
11025  }
11026 
11027  nposcliquevars = 0;
11028 
11029  /* add cliques, using negated cliques information */
11030  if( minactduetonegcliques > 0 )
11031  {
11032  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11033  freecapacity = consdata->capacity - minactduetonegcliques;
11034 
11035  SCIPdebugPrintCons(scip, cons, NULL);
11036  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",
11037  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11038 
11039  /* calculate possible gain by switching chosen items in negated cliques */
11040  for( v = 0; v < nvars; ++v )
11041  {
11042  if( !cliqueused[consdata->negcliquepartition[v]] )
11043  {
11044  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11045  for( w = v + 1; w < nvars; ++w )
11046  {
11047  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11048  * weight[w] (which are both in a negated clique) */
11049  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11050  && consdata->weights[v] > consdata->weights[w] )
11051  {
11052  poscliquevars[nposcliquevars] = consdata->vars[w];
11053  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11054  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11055  ++nposcliquevars;
11056  }
11057  }
11058  }
11059  }
11060 
11061  /* try to create negated cliques */
11062  if( nposcliquevars > 0 )
11063  {
11064  /* sort possible gain per substitution of the clique members */
11065  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11066 
11067  for( v = 0; v < nposcliquevars; ++v )
11068  {
11069  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11070  ncliquevars = 1;
11071  lastweight = gainweights[v];
11072  beforelastweight = -1;
11073  lastcliqueused = gaincliquepartition[v];
11074  /* clear cliqueused to get an unused array */
11075  BMSclearMemoryArray(cliqueused, nnegcliques);
11076  cliqueused[gaincliquepartition[v]] = TRUE;
11077 
11078  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11079  * in the same negated clique and by taking two of them would exceed the free capacity */
11080  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11081  {
11082  beforelastweight = lastweight;
11083  lastweight = gainweights[w];
11084  lastcliqueused = gaincliquepartition[w];
11085  cliqueused[gaincliquepartition[w]] = TRUE;
11086  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11087  ++ncliquevars;
11088  }
11089 
11090  if( ncliquevars > 1 )
11091  {
11092  SCIPdebug( printClique(cliquevars, ncliquevars) );
11093  assert(beforelastweight > 0);
11094  /* add the clique to the clique table */
11095  /* this really happens, e.g., on enigma.mps from the short test set */
11096  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11097  if( *cutoff )
11098  goto TERMINATE;
11099  *nbdchgs += thisnbdchgs;
11100 
11101  /* reset last used clique to get slightly different cliques */
11102  cliqueused[lastcliqueused] = FALSE;
11103 
11104  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11105  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11106  {
11107  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11108  SCIPdebug( printClique(cliquevars, ncliquevars) );
11109  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11110  if( *cutoff )
11111  goto TERMINATE;
11112  *nbdchgs += thisnbdchgs;
11113  }
11114  }
11115  }
11116  }
11117  }
11118 
11119  TERMINATE:
11120  /* free temporary memory */
11121  SCIPfreeBufferArray(scip, &cliqueused);
11122  SCIPfreeBufferArray(scip, &maxweights);
11123  SCIPfreeBufferArray(scip, &gaincliquepartition);
11124  SCIPfreeBufferArray(scip, &gainweights);
11125  SCIPfreeBufferArray(scip, &cliquevars);
11126  SCIPfreeBufferArray(scip, &poscliquevars);
11127 
11128  return SCIP_OKAY;
11129 }
11130 
11131 /** greedy clique detection by considering weights and capacity
11132  *
11133  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11134  * 1) neighboring items which exceed the capacity together => one clique
11135  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11136  */
11137 static
11139  SCIP*const scip, /**< SCIP data structure */
11140  SCIP_VAR** items, /**< array of variable items */
11141  SCIP_Longint* weights, /**< weights of the items */
11142  int nitems, /**< the number of items */
11143  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11144  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11145  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11146  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11147  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11148  )
11149 {
11150  SCIP_Longint lastweight;
11151  int ncliquevars;
11152  int i;
11153  int thisnbdchgs;
11154 
11155  if( nitems <= 1 )
11156  return SCIP_OKAY;
11157 
11158  /* sort possible gain per substitution of the clique members */
11159  if( ! sorteditems )
11160  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11161 
11162  ncliquevars = 1;
11163  lastweight = weights[0];
11164 
11165  /* taking these two weights together violates the knapsack => include into clique */
11166  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11167  {
11168  lastweight = weights[i];
11169  ++ncliquevars;
11170  }
11171 
11172  if( ncliquevars > 1 )
11173  {
11174  SCIP_Longint compareweight;
11175  SCIP_VAR** cliquevars;
11176  int compareweightidx;
11177  int minclqsize;
11178  int nnzadded;
11179 
11180  /* add the clique to the clique table */
11181  SCIPdebug( printClique(items, ncliquevars) );
11182  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11183 
11184  if( *cutoff )
11185  return SCIP_OKAY;
11186 
11187  *nbdchgs += thisnbdchgs;
11188  nnzadded = ncliquevars;
11189 
11190  /* 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)*/
11191  if( ncliquevars == nitems )
11192  return SCIP_OKAY;
11193 
11194  /* copy items in order into buffer array and deduce more cliques */
11195  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11196 
11197  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11198  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11199  compareweightidx = ncliquevars - 2;
11200  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11201 
11202  /* determine minimum clique size for the following loop */
11203  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11204  minclqsize = MAX(minclqsize, 2);
11205 
11206  /* loop over the remaining variables and the larger items of the first clique until we
11207  * find another clique or reach the size limit */
11208  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11209  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11210  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11211  )
11212  {
11213  compareweight = weights[compareweightidx];
11214  assert(compareweight > 0);
11215 
11216  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11217  if( compareweight + weights[i] > capacity )
11218  {
11219  assert(compareweightidx == ncliquevars -2);
11220  cliquevars[ncliquevars - 1] = items[i];
11221  SCIPdebug( printClique(cliquevars, ncliquevars) );
11222  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11223 
11224  nnzadded += ncliquevars;
11225 
11226  /* stop when there is a cutoff */
11227  if( ! (*cutoff) )
11228  *nbdchgs += thisnbdchgs;
11229 
11230  /* go to next smaller item */
11231  ++i;
11232  }
11233  else
11234  {
11235  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11236  compareweightidx--;
11237  ncliquevars --;
11238  }
11239  }
11240 
11241  SCIPfreeBufferArray(scip, &cliquevars);
11242  }
11243 
11244  return SCIP_OKAY;
11245 }
11246 
11247 /** adds cliques of the knapsack constraint to the global clique table */
11248 static
11250  SCIP*const scip, /**< SCIP data structure */
11251  SCIP_CONS*const cons, /**< knapsack constraint */
11252  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11253  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11254  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11255  )
11256 {
11257  SCIP_CONSDATA* consdata;
11258  SCIP_CONSHDLRDATA* conshdlrdata;
11259  int i;
11260  SCIP_Longint minactduetonegcliques;
11261  SCIP_Longint freecapacity;
11262  int nnegcliques;
11263  int cliquenum;
11264  SCIP_VAR** poscliquevars;
11265  SCIP_Longint* gainweights;
11266  int nposcliquevars;
11267  SCIP_Longint* secondmaxweights;
11268  int nvars;
11269 
11270  assert(scip != NULL);
11271  assert(cons != NULL);
11272  assert(cutoff != NULL);
11273  assert(nbdchgs != NULL);
11274 
11275  *cutoff = FALSE;
11276 
11277  consdata = SCIPconsGetData(cons);
11278  assert(consdata != NULL);
11279 
11280  nvars = consdata->nvars;
11281 
11282  /* check whether the cliques have already been added */
11283  if( consdata->cliquesadded || nvars == 0 )
11284  return SCIP_OKAY;
11285 
11286  /* make sure, the items are merged */
11287  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11288  if( *cutoff )
11289  return SCIP_OKAY;
11290 
11291  /* make sure, the items are sorted by non-increasing weight */
11292  sortItems(consdata);
11293 
11294  assert(consdata->merged);
11295 
11296  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11297  assert(conshdlrdata != NULL);
11298 
11299  /* calculate a clique partition */
11300  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11301  nnegcliques = consdata->nnegcliques;
11302  assert(nnegcliques <= nvars);
11303 
11304  /* get temporary memory */
11305  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11306  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11307  BMSclearMemoryArray(gainweights, nvars);
11308  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11309  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11310 
11311  minactduetonegcliques = 0;
11312 
11313  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11314  if( nnegcliques < nvars )
11315  {
11316  nnegcliques = 0;
11317 
11318  for( i = 0; i < nvars; ++i )
11319  {
11320  SCIP_Longint weight;
11321 
11322  cliquenum = consdata->negcliquepartition[i];
11323  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11324 
11325  weight = consdata->weights[i];
11326  assert(weight > 0);
11327 
11328  if( cliquenum == nnegcliques )
11329  nnegcliques++;
11330  else
11331  {
11332  minactduetonegcliques += weight;
11333  if( secondmaxweights[cliquenum] == 0 )
11334  secondmaxweights[cliquenum] = weight;
11335  }
11336  }
11337  }
11338 
11339  /* add cliques, using negated cliques information */
11340  if( minactduetonegcliques > 0 )
11341  {
11342  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11343  freecapacity = consdata->capacity - minactduetonegcliques;
11344 
11345  SCIPdebugPrintCons(scip, cons, NULL);
11346  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",
11347  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11348 
11349  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11350  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11351 
11352  if( *cutoff )
11353  goto TERMINATE;
11354 
11355  nposcliquevars = 0;
11356 
11357  for( i = nvars - 1; i >= 0; --i )
11358  {
11359  /* if we would take the biggest weight instead of the second biggest */
11360  cliquenum = consdata->negcliquepartition[i];
11361  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11362  {
11363  poscliquevars[nposcliquevars] = consdata->vars[i];
11364  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11365  ++nposcliquevars;
11366  }
11367  }
11368 
11369  /* use the gain weights and free capacity to derive greedily cliques */
11370  if( nposcliquevars > 1 )
11371  {
11372  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11373 
11374  if( *cutoff )
11375  goto TERMINATE;
11376  }
11377  }
11378 
11379  /* build cliques by using the items with the maximal weights */
11380  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11381 
11382  TERMINATE:
11383  /* free temporary memory and mark the constraint */
11384  SCIPfreeBufferArray(scip, &secondmaxweights);
11385  SCIPfreeBufferArray(scip, &gainweights);
11386  SCIPfreeBufferArray(scip, &poscliquevars);
11387  consdata->cliquesadded = TRUE;
11388 
11389  return SCIP_OKAY;
11390 }
11391 
11392 
11393 /** gets the key of the given element */
11394 static
11395 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11396 { /*lint --e{715}*/
11397  /* the key is the element itself */
11398  return elem;
11399 }
11400 
11401 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11402  * same coefficients
11403  */
11404 static
11405 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11406 {
11407 #ifndef NDEBUG
11408  SCIP* scip;
11409 #endif
11410  SCIP_CONSDATA* consdata1;
11411  SCIP_CONSDATA* consdata2;
11412  int i;
11414  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11415  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11416  assert(consdata1->sorted);
11417  assert(consdata2->sorted);
11418 #ifndef NDEBUG
11419  scip = (SCIP*)userptr;
11420  assert(scip != NULL);
11421 #endif
11422 
11423  /* checks trivial case */
11424  if( consdata1->nvars != consdata2->nvars )
11425  return FALSE;
11426 
11427  for( i = consdata1->nvars - 1; i >= 0; --i )
11428  {
11429  /* tests if variables are equal */
11430  if( consdata1->vars[i] != consdata2->vars[i] )
11431  {
11432  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11433  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11434  return FALSE;
11435  }
11436  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11437 
11438  /* tests if weights are equal too */
11439  if( consdata1->weights[i] != consdata2->weights[i] )
11440  return FALSE;
11441  }
11442 
11443  return TRUE;
11444 }
11445 
11446 /** returns the hash value of the key */
11447 static
11448 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11449 {
11450 #ifndef NDEBUG
11451  SCIP* scip;
11452 #endif
11453  SCIP_CONSDATA* consdata;
11454  uint64_t firstweight;
11455  int minidx;
11456  int mididx;
11457  int maxidx;
11458 
11459  consdata = SCIPconsGetData((SCIP_CONS*)key);
11460  assert(consdata != NULL);
11461  assert(consdata->nvars > 0);
11462 
11463 #ifndef NDEBUG
11464  scip = (SCIP*)userptr;
11465  assert(scip != NULL);
11466 #endif
11467 
11468  /* sorts the constraints */
11469  sortItems(consdata);
11470 
11471  minidx = SCIPvarGetIndex(consdata->vars[0]);
11472  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11473  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11474  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11475 
11476  /* hash value depends on vectors of variable indices */
11477  firstweight = (uint64_t)consdata->weights[0];
11478  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11479 }
11480 
11481 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11482  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11483  */
11484 static
11486  SCIP* scip, /**< SCIP data structure */
11487  BMS_BLKMEM* blkmem, /**< block memory */
11488  SCIP_CONS** conss, /**< constraint set */
11489  int nconss, /**< number of constraints in constraint set */
11490  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11491  int* ndelconss /**< pointer to count number of deleted constraints */
11492  )
11494  SCIP_HASHTABLE* hashtable;
11495  int hashtablesize;
11496  int c;
11497 
11498  assert(scip != NULL);
11499  assert(blkmem != NULL);
11500  assert(conss != NULL);
11501  assert(ndelconss != NULL);
11502 
11503  /* create a hash table for the constraint set */
11504  hashtablesize = nconss;
11505  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11506  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11507  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11508 
11509  /* check all constraints in the given set for redundancy */
11510  for( c = nconss - 1; c >= 0; --c )
11511  {
11512  SCIP_CONS* cons0;
11513  SCIP_CONS* cons1;
11514  SCIP_CONSDATA* consdata0;
11515 
11516  cons0 = conss[c];
11517 
11518  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11519  continue;
11520 
11521  consdata0 = SCIPconsGetData(cons0);
11522  assert(consdata0 != NULL);
11523  if( consdata0->nvars == 0 )
11524  {
11525  if( consdata0->capacity < 0 )
11526  {
11527  *cutoff = TRUE;
11528  goto TERMINATE;
11529  }
11530  else
11531  {
11532  SCIP_CALL( SCIPdelCons(scip, cons0) );
11533  ++(*ndelconss);
11534  continue;
11535  }
11536  }
11537 
11538  /* get constraint from current hash table with same variables and same weights as cons0 */
11539  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11540 
11541  if( cons1 != NULL )
11542  {
11543  SCIP_CONS* consstay;
11544  SCIP_CONS* consdel;
11545  SCIP_CONSDATA* consdata1;
11546 
11547  assert(SCIPconsIsActive(cons1));
11548  assert(!SCIPconsIsModifiable(cons1));
11549 
11550  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11551  * delete old constraints afterwards
11552  */
11553  consdata1 = SCIPconsGetData(cons1);
11554 
11555  assert(consdata1 != NULL);
11556  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11557 
11558  assert(consdata0->sorted && consdata1->sorted);
11559  assert(consdata0->vars[0] == consdata1->vars[0]);
11560  assert(consdata0->weights[0] == consdata1->weights[0]);
11561 
11562  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11563  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11564 
11565  /* check which constraint has to stay; */
11566  if( consdata0->capacity < consdata1->capacity )
11567  {
11568  consstay = cons0;
11569  consdel = cons1;
11570 
11571  /* exchange consdel with consstay in hashtable */
11572  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11573  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11574  }
11575  else
11576  {
11577  consstay = cons1;
11578  consdel = cons0;
11579  }
11580 
11581  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11582  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11583 
11584  /* delete consdel */
11585  SCIP_CALL( SCIPdelCons(scip, consdel) );
11586  ++(*ndelconss);
11587 
11588  assert(SCIPconsIsActive(consstay));
11589  }
11590  else
11591  {
11592  /* no such constraint in current hash table: insert cons0 into hash table */
11593  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11594  }
11595  }
11596 
11597  TERMINATE:
11598  /* free hash table */
11599  SCIPhashtableFree(&hashtable);
11600 
11601  return SCIP_OKAY;
11602 }
11603 
11604 
11605 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11606  * and removes or changes constraint accordingly
11607  */
11608 static
11610  SCIP* scip, /**< SCIP data structure */
11611  SCIP_CONS** conss, /**< constraint set */
11612  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11613  int chkind, /**< index of constraint to check against all prior indices upto startind */
11614  int* ndelconss /**< pointer to count number of deleted constraints */
11615  )
11616 {
11617  SCIP_CONS* cons0;
11618  SCIP_CONSDATA* consdata0;
11619  int c;
11620 
11621  assert(scip != NULL);
11622  assert(conss != NULL);
11623  assert(firstchange <= chkind);
11624  assert(ndelconss != NULL);
11625 
11626  /* get the constraint to be checked against all prior constraints */
11627  cons0 = conss[chkind];
11628  assert(cons0 != NULL);
11629  assert(SCIPconsIsActive(cons0));
11630  assert(!SCIPconsIsModifiable(cons0));
11631 
11632  consdata0 = SCIPconsGetData(cons0);
11633  assert(consdata0 != NULL);
11634  assert(consdata0->nvars >= 1);
11635  assert(consdata0->merged);
11636 
11637  /* sort the constraint */
11638  sortItems(consdata0);
11639 
11640  /* see #2970 */
11641  if( consdata0->capacity == 0 )
11642  return SCIP_OKAY;
11643 
11644  /* check constraint against all prior constraints */
11645  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11646  {
11647  SCIP_CONS* cons1;
11648  SCIP_CONSDATA* consdata1;
11649  SCIP_Bool iscons0incons1contained;
11650  SCIP_Bool iscons1incons0contained;
11651  SCIP_Real quotient;
11652  int v;
11653  int v0;
11654  int v1;
11655 
11656  cons1 = conss[c];
11657  assert(cons1 != NULL);
11658  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11659  continue;
11660 
11661  consdata1 = SCIPconsGetData(cons1);
11662  assert(consdata1 != NULL);
11663 
11664  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11665  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11666  continue;
11667 
11668  assert(consdata1->nvars >= 1);
11669  assert(consdata1->merged);
11670 
11671  /* sort the constraint */
11672  sortItems(consdata1);
11673 
11674  /* see #2970 */
11675  if( consdata1->capacity == 0 )
11676  continue;
11677 
11678  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11679 
11680  if( consdata0->nvars > consdata1->nvars )
11681  {
11682  iscons0incons1contained = FALSE;
11683  iscons1incons0contained = TRUE;
11684  v = consdata1->nvars - 1;
11685  }
11686  else if( consdata0->nvars < consdata1->nvars )
11687  {
11688  iscons0incons1contained = TRUE;
11689  iscons1incons0contained = FALSE;
11690  v = consdata0->nvars - 1;
11691  }
11692  else
11693  {
11694  iscons0incons1contained = TRUE;
11695  iscons1incons0contained = TRUE;
11696  v = consdata0->nvars - 1;
11697  }
11698 
11699  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11700 
11701  /* check consdata0 against consdata1:
11702  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11703  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11704  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11705  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11706  */
11707  v0 = consdata0->nvars - 1;
11708  v1 = consdata1->nvars - 1;
11709 
11710  while( v >= 0 )
11711  {
11712  assert(iscons0incons1contained || iscons1incons0contained);
11713 
11714  /* now there are more variables in cons1 left */
11715  if( v1 > v0 )
11716  {
11717  iscons1incons0contained = FALSE;
11718  if( !iscons0incons1contained )
11719  break;
11720  }
11721  /* now there are more variables in cons0 left */
11722  else if( v1 < v0 )
11723  {
11724  iscons0incons1contained = FALSE;
11725  if( !iscons1incons0contained )
11726  break;
11727  }
11728 
11729  assert(v == v0 || v == v1);
11730  assert(v0 >= 0);
11731  assert(v1 >= 0);
11732 
11733  /* both variables are the same */
11734  if( consdata0->vars[v0] == consdata1->vars[v1] )
11735  {
11736  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11737  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11738  {
11739  iscons1incons0contained = FALSE;
11740  if( !iscons0incons1contained )
11741  break;
11742  }
11743  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11744  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11745  {
11746  iscons0incons1contained = FALSE;
11747  if( !iscons1incons0contained )
11748  break;
11749  }
11750  --v0;
11751  --v1;
11752  --v;
11753  }
11754  else
11755  {
11756  /* both constraints have a variables which is not part of the other constraint, so stop */
11757  if( iscons0incons1contained && iscons1incons0contained )
11758  {
11759  iscons0incons1contained = FALSE;
11760  iscons1incons0contained = FALSE;
11761  break;
11762  }
11763  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11764  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11765  /* continue to the next variable */
11766  if( iscons0incons1contained )
11767  --v1;
11768  else
11769  --v0;
11770  }
11771  }
11772  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11773  * other
11774  */
11775  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11776 
11777  if( iscons1incons0contained )
11778  {
11779  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11780  SCIPdebugPrintCons(scip, cons1, NULL);
11781 
11782  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11783  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11784 
11785  SCIP_CALL( SCIPdelCons(scip, cons1) );
11786  ++(*ndelconss);
11787  }
11788  else if( iscons0incons1contained )
11789  {
11790  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11791  SCIPdebugPrintCons(scip, cons0, NULL);
11792 
11793  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11794  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11795 
11796  SCIP_CALL( SCIPdelCons(scip, cons0) );
11797  ++(*ndelconss);
11798  break;
11799  }
11800  }
11801 
11802  return SCIP_OKAY;
11803 }
11804 
11805 /** helper function to enforce constraints */
11806 static
11808  SCIP* scip, /**< SCIP data structure */
11809  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11810  SCIP_CONS** conss, /**< constraints to process */
11811  int nconss, /**< number of constraints */
11812  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11813  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11814  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11815  )
11816 {
11817  SCIP_CONSHDLRDATA* conshdlrdata;
11818  SCIP_Bool violated;
11819  SCIP_Bool cutoff = FALSE;
11820  int maxncuts;
11821  int ncuts = 0;
11822  int i;
11823 
11824  *result = SCIP_FEASIBLE;
11825 
11826  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11827  sol == NULL ? "LP" : "relaxation");
11828 
11829  /* get maximal number of cuts per round */
11830  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11831  assert(conshdlrdata != NULL);
11832  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11833 
11834  /* search for violated useful knapsack constraints */
11835  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11836  {
11837  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11838  if( violated )
11839  {
11840  /* add knapsack constraint as LP row to the relaxation */
11841  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11842  ncuts++;
11843  }
11844  }
11845 
11846  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11847  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11848  {
11849  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11850  if( violated )
11851  {
11852  /* add knapsack constraint as LP row to the relaxation */
11853  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11854  ncuts++;
11855  }
11856  }
11857 
11858  /* adjust the result code */
11859  if ( cutoff )
11860  *result = SCIP_CUTOFF;
11861  else if ( ncuts > 0 )
11862  *result = SCIP_SEPARATED;
11863 
11864  return SCIP_OKAY;
11865 }
11866 
11867 /*
11868  * Linear constraint upgrading
11869  */
11870 
11871 /** creates and captures a knapsack constraint out of a linear inequality */
11872 static
11874  SCIP* scip, /**< SCIP data structure */
11875  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11876  const char* name, /**< name of constraint */
11877  int nvars, /**< number of variables in the constraint */
11878  SCIP_VAR** vars, /**< array with variables of constraint entries */
11879  SCIP_Real* vals, /**< array with inequality coefficients */
11880  SCIP_Real lhs, /**< left hand side of inequality */
11881  SCIP_Real rhs, /**< right hand side of inequality */
11882  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11883  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11884  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11885  * Usually set to TRUE. */
11886  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11887  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11888  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11889  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11890  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11891  * Usually set to TRUE. */
11892  SCIP_Bool local, /**< is constraint only valid locally?
11893  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11894  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11895  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11896  * adds coefficients to this constraint. */
11897  SCIP_Bool dynamic, /**< is constraint subject to aging?
11898  * Usually set to FALSE. Set to TRUE for own cuts which
11899  * are separated as constraints. */
11900  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11901  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11902  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11903  * if it may be moved to a more global node?
11904  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11905  )
11906 {
11907  SCIP_VAR** transvars;
11908  SCIP_Longint* weights;
11909  SCIP_Longint capacity;
11910  SCIP_Longint weight;
11911  int mult;
11912  int v;
11913 
11914  assert(nvars == 0 || vars != NULL);
11915  assert(nvars == 0 || vals != NULL);
11916  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11917 
11918  /* get temporary memory */
11919  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11920  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11921 
11922  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11923  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11924  */
11925  if( SCIPisInfinity(scip, rhs) )
11926  {
11927  mult = -1;
11928  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11929  }
11930  else
11931  {
11932  mult = +1;
11933  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11934  }
11935 
11936  /* negate positive or negative variables */
11937  for( v = 0; v < nvars; ++v )
11938  {
11939  assert(SCIPisFeasIntegral(scip, vals[v]));
11940  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11941  if( weight > 0 )
11942  {
11943  transvars[v] = vars[v];
11944  weights[v] = weight;
11945  }
11946  else
11947  {
11948  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11949  weights[v] = -weight; /*lint !e2704*/
11950  capacity -= weight;
11951  }
11952  assert(transvars[v] != NULL);
11953  }
11954 
11955  /* create the constraint */
11956  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11957  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11958 
11959  /* free temporary memory */
11960  SCIPfreeBufferArray(scip, &weights);
11961  SCIPfreeBufferArray(scip, &transvars);
11962 
11963  return SCIP_OKAY;
11964 }
11965 
11966 /** tries to upgrade a linear constraint into a knapsack constraint */
11967 static
11968 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11969 { /*lint --e{715}*/
11970  SCIP_Bool upgrade;
11971 
11972  assert(upgdcons != NULL);
11973 
11974  /* check, if linear constraint can be upgraded to a knapsack constraint
11975  * - all variables must be binary
11976  * - all coefficients must be integral
11977  * - exactly one of the sides must be infinite
11978  * note that this includes the case of negative capacity, which has been
11979  * observed to occur, e.g., when upgrading a conflict constraint
11980  */
11981  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11982  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11983  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11984 
11985  if( upgrade )
11986  {
11987  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11988 
11989  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11990  assert(!SCIPconsIsModifiable(cons));
11991  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11996  }
11997 
11998  return SCIP_OKAY;
11999 }
12000 
12001 
12002 /*
12003  * Callback methods of constraint handler
12004  */
12005 
12006 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12007 /**! [SnippetConsCopyKnapsack] */
12008 static
12009 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12010 { /*lint --e{715}*/
12011  assert(scip != NULL);
12012  assert(conshdlr != NULL);
12013  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12014 
12015  /* call inclusion method of constraint handler */
12018  *valid = TRUE;
12019 
12020  return SCIP_OKAY;
12021 }
12022 /**! [SnippetConsCopyKnapsack] */
12023 
12024 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12025 /**! [SnippetConsFreeKnapsack] */
12026 static
12027 SCIP_DECL_CONSFREE(consFreeKnapsack)
12028 { /*lint --e{715}*/
12029  SCIP_CONSHDLRDATA* conshdlrdata;
12030 
12031  /* free constraint handler data */
12032  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12033  assert(conshdlrdata != NULL);
12034 
12035  SCIPfreeBlockMemory(scip, &conshdlrdata);
12036 
12037  SCIPconshdlrSetData(conshdlr, NULL);
12038 
12039  return SCIP_OKAY;
12040 }
12041 /**! [SnippetConsFreeKnapsack] */
12042 
12043 
12044 /** initialization method of constraint handler (called after problem was transformed) */
12045 static
12046 SCIP_DECL_CONSINIT(consInitKnapsack)
12047 { /*lint --e{715}*/
12048  SCIP_CONSHDLRDATA* conshdlrdata;
12049  int nvars;
12050 
12051  assert( scip != NULL );
12052  assert( conshdlr != NULL );
12053 
12054  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12055  assert(conshdlrdata != NULL);
12056 
12057  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12058  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12059 
12060  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12061  conshdlrdata->reals1size = nvars;
12062 
12063  return SCIP_OKAY;
12064 }
12065 
12066 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12067 static
12068 SCIP_DECL_CONSEXIT(consExitKnapsack)
12069 { /*lint --e{715}*/
12070  SCIP_CONSHDLRDATA* conshdlrdata;
12071 
12072  assert( scip != NULL );
12073  assert( conshdlr != NULL );
12074 
12075  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12076  assert(conshdlrdata != NULL);
12077 
12078  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12079  conshdlrdata->reals1size = 0;
12080 
12081  return SCIP_OKAY;
12082 }
12083 
12084 
12085 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12086 static
12087 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12088 { /*lint --e{715}*/
12089  SCIP_CONSHDLRDATA* conshdlrdata;
12090  int nvars;
12091 
12092  assert(scip != NULL);
12093  assert(conshdlr != NULL);
12094  assert(nconss == 0 || conss != NULL);
12096  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12097  assert(conshdlrdata != NULL);
12098 
12099  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12100  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12101 
12102  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12103  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12104  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12105  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12106  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12107  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12108  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12109  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12110 
12111  conshdlrdata->ints1size = nvars;
12112  conshdlrdata->ints2size = nvars;
12113  conshdlrdata->longints1size = nvars;
12114  conshdlrdata->longints2size = nvars;
12115  conshdlrdata->bools1size = nvars;
12116  conshdlrdata->bools2size = nvars;
12117  conshdlrdata->bools3size = nvars;
12118  conshdlrdata->bools4size = nvars;
12119 
12120 #ifdef WITH_CARDINALITY_UPGRADE
12121  conshdlrdata->upgradedcard = FALSE;
12122 #endif
12123 
12124  return SCIP_OKAY;
12125 }
12126 
12127 
12128 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12129 static
12130 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12131 { /*lint --e{715}*/
12132  SCIP_CONSHDLRDATA* conshdlrdata;
12133  int c;
12134 
12135  assert(scip != NULL);
12136  assert(conshdlr != NULL);
12137 
12138  for( c = 0; c < nconss; ++c )
12139  {
12140  if( !SCIPconsIsDeleted(conss[c]) )
12141  {
12142  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12143  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12144  }
12145  }
12146 
12147  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12148  assert(conshdlrdata != NULL);
12149 
12150  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12151  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12152  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12153  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12154  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12155  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12156  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12157  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12158 
12159  conshdlrdata->ints1size = 0;
12160  conshdlrdata->ints2size = 0;
12161  conshdlrdata->longints1size = 0;
12162  conshdlrdata->longints2size = 0;
12163  conshdlrdata->bools1size = 0;
12164  conshdlrdata->bools2size = 0;
12165  conshdlrdata->bools3size = 0;
12166  conshdlrdata->bools4size = 0;
12167 
12168  return SCIP_OKAY;
12169 }
12170 
12171 /** solving process initialization method of constraint handler */
12172 static
12173 SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12174 { /*lint --e{715}*/
12175 
12176  /* add nlrow representation to NLP, if NLP had been constructed */
12177  if( SCIPisNLPConstructed(scip) )
12178  {
12179  int c;
12180  for( c = 0; c < nconss; ++c )
12181  {
12182  SCIP_CALL( addNlrow(scip, conss[c]) );
12183  }
12184  }
12185 
12186  return SCIP_OKAY;
12187 }
12188 
12189 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12190 static
12191 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12192 { /*lint --e{715}*/
12193  SCIP_CONSDATA* consdata;
12194  int c;
12195 
12196  assert( scip != NULL );
12197 
12198  /* release the rows and nlrows of all constraints */
12199  for( c = 0; c < nconss; ++c )
12200  {
12201  consdata = SCIPconsGetData(conss[c]);
12202  assert(consdata != NULL);
12203 
12204  if( consdata->row != NULL )
12205  {
12206  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12207  }
12208 
12209  if( consdata->nlrow != NULL )
12210  {
12211  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12212  }
12213  }
12214 
12215  return SCIP_OKAY;
12216 }
12217 
12218 /** frees specific constraint data */
12219 static
12220 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12221 { /*lint --e{715}*/
12222  SCIP_CONSHDLRDATA* conshdlrdata;
12223 
12224  assert(conshdlr != NULL);
12225  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12226 
12227  /* get event handler */
12228  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12229  assert(conshdlrdata != NULL);
12230  assert(conshdlrdata->eventhdlr != NULL);
12231 
12232  /* free knapsack constraint */
12233  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12234 
12235  return SCIP_OKAY;
12236 }
12237 
12238 /** transforms constraint data into data belonging to the transformed problem */
12239 /**! [SnippetConsTransKnapsack]*/
12240 static
12241 SCIP_DECL_CONSTRANS(consTransKnapsack)
12242 { /*lint --e{715}*/
12243  SCIP_CONSHDLRDATA* conshdlrdata;
12244  SCIP_CONSDATA* sourcedata;
12245  SCIP_CONSDATA* targetdata;
12246 
12247  assert(conshdlr != NULL);
12248  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12250  assert(sourcecons != NULL);
12251  assert(targetcons != NULL);
12252 
12253  sourcedata = SCIPconsGetData(sourcecons);
12254  assert(sourcedata != NULL);
12255  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12256 
12257  /* get event handler */
12258  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12259  assert(conshdlrdata != NULL);
12260  assert(conshdlrdata->eventhdlr != NULL);
12261 
12262  /* create target constraint data */
12263  SCIP_CALL( consdataCreate(scip, &targetdata,
12264  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12265 
12266  /* create target constraint */
12267  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12268  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12269  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12270  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12271  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12272 
12273  /* catch events for variables */
12274  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12275 
12276  return SCIP_OKAY;
12277 }
12278 /**! [SnippetConsTransKnapsack]*/
12279 
12280 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12281 static
12282 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12283 { /*lint --e{715}*/
12284  int i;
12285 
12286  *infeasible = FALSE;
12287 
12288  for( i = 0; i < nconss && !(*infeasible); i++ )
12289  {
12290  assert(SCIPconsIsInitial(conss[i]));
12291  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12292  }
12293 
12294  return SCIP_OKAY;
12295 }
12296 
12297 /** separation method of constraint handler for LP solutions */
12298 static
12299 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12300 { /*lint --e{715}*/
12301  SCIP_CONSHDLRDATA* conshdlrdata;
12302  SCIP_Bool sepacardinality;
12303  SCIP_Bool cutoff;
12304 
12305  SCIP_Real loclowerbound;
12306  SCIP_Real glblowerbound;
12307  SCIP_Real cutoffbound;
12308  SCIP_Real maxbound;
12309 
12310  int depth;
12311  int nrounds;
12312  int sepafreq;
12313  int sepacardfreq;
12314  int ncuts;
12315  int maxsepacuts;
12316  int i;
12317 
12318  *result = SCIP_DIDNOTRUN;
12319 
12320  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12321  assert(conshdlrdata != NULL);
12322 
12323  depth = SCIPgetDepth(scip);
12324  nrounds = SCIPgetNSepaRounds(scip);
12325 
12326  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12327  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12328 
12329  /* only call the separator a given number of times at each node */
12330  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12331  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12332  return SCIP_OKAY;
12333 
12334  /* check, if we should additionally separate knapsack cuts */
12335  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12336  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12337  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12338  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12339 
12340  /* check dual bound to see if we want to produce knapsack cuts at this node */
12341  loclowerbound = SCIPgetLocalLowerbound(scip);
12342  glblowerbound = SCIPgetLowerbound(scip);
12343  cutoffbound = SCIPgetCutoffbound(scip);
12344  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12345  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12346  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12347 
12348  /* get the maximal number of cuts allowed in a separation round */
12349  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12350 
12351  *result = SCIP_DIDNOTFIND;
12352  ncuts = 0;
12353  cutoff = FALSE;
12354 
12355  /* separate useful constraints */
12356  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12357  {
12358  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12359  }
12360 
12361  /* adjust return value */
12362  if ( cutoff )
12363  *result = SCIP_CUTOFF;
12364  else if ( ncuts > 0 )
12365  *result = SCIP_SEPARATED;
12366 
12367  return SCIP_OKAY;
12368 }
12369 
12370 
12371 /** separation method of constraint handler for arbitrary primal solutions */
12372 static
12373 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12374 { /*lint --e{715}*/
12375  SCIP_CONSHDLRDATA* conshdlrdata;
12376  SCIP_Bool sepacardinality;
12377  SCIP_Bool cutoff;
12378 
12379  int depth;
12380  int nrounds;
12381  int sepafreq;
12382  int sepacardfreq;
12383  int ncuts;
12384  int maxsepacuts;
12385  int i;
12386 
12387  *result = SCIP_DIDNOTRUN;
12388 
12389  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12390  assert(conshdlrdata != NULL);
12391 
12392  depth = SCIPgetDepth(scip);
12393  nrounds = SCIPgetNSepaRounds(scip);
12394 
12395  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12396  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12397 
12398  /* only call the separator a given number of times at each node */
12399  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12400  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12401  return SCIP_OKAY;
12402 
12403  /* check, if we should additionally separate knapsack cuts */
12404  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12405  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12406  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12407  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12408 
12409  /* get the maximal number of cuts allowed in a separation round */
12410  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12411 
12412  *result = SCIP_DIDNOTFIND;
12413  ncuts = 0;
12414  cutoff = FALSE;
12415 
12416  /* separate useful constraints */
12417  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12418  {
12419  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12420  }
12421 
12422  /* adjust return value */
12423  if ( cutoff )
12424  *result = SCIP_CUTOFF;
12425  else if( ncuts > 0 )
12426  *result = SCIP_SEPARATED;
12427 
12428  return SCIP_OKAY;
12429 }
12430 
12431 /** constraint enforcing method of constraint handler for LP solutions */
12432 static
12433 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12434 { /*lint --e{715}*/
12435  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12436 
12437  return SCIP_OKAY;
12438 }
12439 
12440 /** constraint enforcing method of constraint handler for relaxation solutions */
12441 static
12442 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12443 { /*lint --e{715}*/
12444  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12445 
12446  return SCIP_OKAY;
12447 }
12448 
12449 /** constraint enforcing method of constraint handler for pseudo solutions */
12450 static
12451 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12452 { /*lint --e{715}*/
12453  SCIP_Bool violated;
12454  int i;
12455 
12456  for( i = 0; i < nconss; i++ )
12457  {
12458  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12459  if( violated )
12460  {
12461  *result = SCIP_INFEASIBLE;
12462  return SCIP_OKAY;
12463  }
12464  }
12465  *result = SCIP_FEASIBLE;
12466 
12467  return SCIP_OKAY;
12468 }
12469 
12470 /** feasibility check method of constraint handler for integral solutions */
12471 static
12472 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12473 { /*lint --e{715}*/
12474  SCIP_Bool violated;
12475  int i;
12476 
12477  *result = SCIP_FEASIBLE;
12478 
12479  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12480  {
12481  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12482  if( violated )
12483  *result = SCIP_INFEASIBLE;
12484  }
12485 
12486  return SCIP_OKAY;
12487 }
12488 
12489 /** domain propagation method of constraint handler */
12490 static
12491 SCIP_DECL_CONSPROP(consPropKnapsack)
12492 { /*lint --e{715}*/
12493  SCIP_CONSHDLRDATA* conshdlrdata;
12494  SCIP_Bool cutoff;
12495  SCIP_Bool redundant;
12496  SCIP_Bool inpresolve;
12497  int nfixedvars;
12498  int i;
12500  cutoff = FALSE;
12501  nfixedvars = 0;
12502 
12503  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12504  assert(conshdlrdata != NULL);
12505 
12506  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12507  assert(!inpresolve || SCIPinProbing(scip));
12508 
12509  /* process useful constraints */
12510  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12511  {
12512  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12513  * otherwise the multi-aggregation should be resolved
12514  */
12515  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12516  continue;
12517 #ifndef NDEBUG
12518  else
12519  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12520 #endif
12521 
12522  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12523 
12524  /* unmark the constraint to be propagated */
12525  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12526  }
12527 
12528  /* adjust result code */
12529  if( cutoff )
12530  *result = SCIP_CUTOFF;
12531  else if( nfixedvars > 0 )
12532  *result = SCIP_REDUCEDDOM;
12533  else
12534  *result = SCIP_DIDNOTFIND;
12535 
12536  return SCIP_OKAY; /*lint !e438*/
12537 }
12538 
12539 /** presolving method of constraint handler */
12540 static
12541 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12542 { /*lint --e{574,715}*/
12543  SCIP_CONSHDLRDATA* conshdlrdata;
12544  SCIP_CONSDATA* consdata;
12545  SCIP_CONS* cons;
12546  SCIP_Bool cutoff;
12547  SCIP_Bool redundant;
12548  SCIP_Bool success;
12549  int oldnfixedvars;
12550  int oldnchgbds;
12551  int oldndelconss;
12552  int oldnaddconss;
12553  int oldnchgcoefs;
12554  int oldnchgsides;
12555  int firstchange;
12556  int c;
12557  SCIP_Bool newchanges;
12558 
12559  /* remember old preprocessing counters */
12560  cutoff = FALSE;
12561  oldnfixedvars = *nfixedvars;
12562  oldnchgbds = *nchgbds;
12563  oldndelconss = *ndelconss;
12564  oldnaddconss = *naddconss;
12565  oldnchgcoefs = *nchgcoefs;
12566  oldnchgsides = *nchgsides;
12567  firstchange = INT_MAX;
12568 
12569  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12570 
12571  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12572  assert(conshdlrdata != NULL);
12573 
12574  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12575  {
12576  int thisnfixedvars;
12577  int thisnchgbds;
12578 
12579  cons = conss[c];
12580  consdata = SCIPconsGetData(cons);
12581  assert(consdata != NULL);
12582 
12583  /* update data structures */
12584  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12585  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12586  {
12587  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12588  if( cutoff )
12589  break;
12590  }
12591 
12592  /* force presolving the constraint in the initial round */
12593  if( nrounds == 0 )
12594  consdata->presolvedtiming = 0;
12595  else if( consdata->presolvedtiming >= presoltiming )
12596  continue;
12597 
12598  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12599  SCIPdebugPrintCons(scip, cons, NULL);
12600  consdata->presolvedtiming = presoltiming;
12601 
12602  thisnfixedvars = *nfixedvars;
12603  thisnchgbds = *nchgbds;
12604 
12605  /* merge constraint, so propagation works better */
12606  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12607  if( cutoff )
12608  break;
12609 
12610  /* add cliques in the knapsack to the clique table */
12611  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12612  {
12613  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12614  if( cutoff )
12615  break;
12616  }
12617 
12618  /* propagate constraint */
12619  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12620  {
12621  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12622 
12623  if( cutoff )
12624  break;
12625  if( redundant )
12626  {
12627  (*ndelconss)++;
12628  continue;
12629  }
12630  }
12631 
12632  /* remove again all fixed variables, if further fixings were found */
12633  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12634  {
12635  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12636  if( cutoff )
12637  break;
12638 
12639  thisnfixedvars = *nfixedvars;
12640  }
12641 
12642  if( !SCIPconsIsModifiable(cons) )
12643  {
12644  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12645  if( consdata->weightsum <= consdata->capacity )
12646  {
12647  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12648  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12649  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12650  continue;
12651  }
12652 
12653  /* divide weights by their greatest common divisor */
12654  normalizeWeights(cons, nchgcoefs, nchgsides);
12655 
12656  /* try to simplify inequalities */
12657  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12658  {
12659  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12660  if( cutoff )
12661  break;
12662 
12663  if( SCIPconsIsDeleted(cons) )
12664  continue;
12665 
12666  /* remove again all fixed variables, if further fixings were found */
12667  if( *nfixedvars > thisnfixedvars )
12668  {
12669  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12670  if( cutoff )
12671  break;
12672  }
12673  }
12674 
12675  /* tighten capacity and weights */
12676  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12677  if( cutoff )
12678  break;
12679 
12680  if( SCIPconsIsActive(cons) )
12681  {
12682  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12683  {
12684  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12685  * dual reduction
12686  */
12687  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12688  if( redundant )
12689  continue;
12690  }
12691 
12692  /* check if knapsack constraint is parallel to objective function */
12693  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12694  }
12695  }
12696  /* remember the first changed constraint to begin the next aggregation round with */
12697  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12698  firstchange = c;
12699  }
12700 
12701  /* preprocess pairs of knapsack constraints */
12702  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12703  {
12704  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12705  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12706  }
12707 
12708  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12709  success = TRUE;
12710  else
12711  success = FALSE;
12712 
12713  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12714  {
12715  SCIP_Longint npaircomparisons;
12716 
12717  npaircomparisons = 0;
12718  oldndelconss = *ndelconss;
12719  oldnchgsides = *nchgsides;
12720  oldnchgcoefs = *nchgcoefs;
12721 
12722  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12723  {
12724  cons = conss[c];
12725  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12726  continue;
12727 
12728  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12729 
12730  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12731 
12732  if( npaircomparisons > NMINCOMPARISONS )
12733  {
12734  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12735  success = TRUE;
12736  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12737  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12738  break;
12739  oldndelconss = *ndelconss;
12740  oldnchgsides = *nchgsides;
12741  oldnchgcoefs = *nchgcoefs;
12742  npaircomparisons = 0;
12743  }
12744  }
12745  }
12746 #ifdef WITH_CARDINALITY_UPGRADE
12747  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12748  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12749  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12750  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12751  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12752  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12753  * as well, we better keep this code disabled. */
12754  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12755  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12756  {
12757  SCIP_HASHMAP* varhash;
12758  SCIP_VAR** cardvars;
12759  SCIP_Real* cardweights;
12760  int noldupgdconss;
12761  int nscipvars;
12762  int makeupgrade;
12763 
12764  noldupgdconss = *nupgdconss;
12765  nscipvars = SCIPgetNVars(scip);
12766  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12767  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12768 
12769  /* set up hash map */
12770  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12771 
12772  /* We loop through all cardinality constraints twice:
12773  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12774  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12775  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12776  * - Second, upgrade knapsack constraints to cardinality constraints. */
12777  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12778  {
12779  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12780  {
12781  SCIP_CONS* cardcons;
12782  SCIP_VAR** vars;
12783  SCIP_Longint* weights;
12784  int nvars;
12785  int v;
12786 
12787  cons = conss[c];
12788  assert( cons != NULL );
12789  consdata = SCIPconsGetData(cons);
12790  assert( consdata != NULL );
12791 
12792  nvars = consdata->nvars;
12793  vars = consdata->vars;
12794  weights = consdata->weights;
12795 
12796  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12797  * - all variables must be binary (always true)
12798  * - all coefficients must be 1.0
12799  * - the right hand side must be smaller than nvars
12800  */
12801  if ( consdata->capacity >= nvars )
12802  continue;
12803 
12804  /* the weights are sorted: check first and last weight */
12805  assert( consdata->sorted );
12806  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12807  continue;
12808 
12809  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12810  for (v = 0; v < nvars; ++v)
12811  {
12812  SCIP_BOUNDTYPE* impltypes;
12813  SCIP_Real* implbounds;
12814  SCIP_VAR** implvars;
12815  SCIP_VAR* var;
12816  int nimpls;
12817  int j;
12818 
12819  var = consdata->vars[v];
12820  assert( var != NULL );
12821  assert( SCIPvarIsBinary(var) );
12822 
12823  /* ignore non-active variables */
12824  if ( ! SCIPvarIsActive(var) )
12825  break;
12826 
12827  /* be sure that implication variable has zero objective */
12828  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12829  break;
12830 
12831  nimpls = SCIPvarGetNImpls(var, FALSE);
12832  implvars = SCIPvarGetImplVars(var, FALSE);
12833  implbounds = SCIPvarGetImplBounds(var, FALSE);
12834  impltypes = SCIPvarGetImplTypes(var, FALSE);
12835 
12836  for (j = 0; j < nimpls; ++j)
12837  {
12838  /* be sure that continuous variable is fixed to 0 */
12839  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12840  continue;
12841 
12842  /* cannot currently deal with nonzero fixings */
12843  if ( ! SCIPisZero(scip, implbounds[j]) )
12844  continue;
12845 
12846  /* number of down locks should be one */
12847  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12848  continue;
12849 
12850  cardvars[v] = implvars[j];
12851  cardweights[v] = (SCIP_Real) v;
12852 
12853  break;
12854  }
12855 
12856  /* found no variable upper bound candidate -> exit */
12857  if ( j >= nimpls )
12858  break;
12859  }
12860 
12861  /* did not find fitting variable upper bound for some variable -> exit */
12862  if ( v < nvars )
12863  break;
12864 
12865  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12866  * in which the binary variable is involved in */
12867  if ( makeupgrade == 0 )
12868  {
12869  for (v = 0; v < nvars; ++v)
12870  {
12871  if ( SCIPhashmapExists(varhash, vars[v]) )
12872  {
12873  int image;
12874 
12875  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12876  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12877  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12878  }
12879  else
12880  {
12881  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12882  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12883  assert( SCIPhashmapExists(varhash, vars[v]) );
12884  }
12885  }
12886  }
12887  else
12888  {
12889  SCIP_CONS* origcons;
12890 
12891  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12892  * knapsack constraint coincides with the number of variable up locks */
12893  for (v = 0; v < nvars; ++v)
12894  {
12895  assert( SCIPhashmapExists(varhash, vars[v]) );
12896  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12897  break;
12898  }
12899  if ( v < nvars )
12900  break;
12901 
12902  /* store that we have upgraded */
12903  conshdlrdata->upgradedcard = TRUE;
12904 
12905  /* at this point we found suitable variable upper bounds */
12906  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12907 
12908  /* create cardinality constraint */
12909  assert( ! SCIPconsIsModifiable(cons) );
12910  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12914 #ifdef SCIP_DEBUG
12915  SCIPprintCons(scip, cons, NULL);
12916  SCIPinfoMessage(scip, NULL, "\n");
12917  SCIPprintCons(scip, cardcons, NULL);
12918  SCIPinfoMessage(scip, NULL, "\n");
12919 #endif
12920  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12921  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12922  ++(*nupgdconss);
12923 
12924  /* delete oknapsack constraint */
12925  SCIP_CALL( SCIPdelCons(scip, cons) );
12926  ++(*ndelconss);
12927 
12928  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12929  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12930  * although the cardinality constraint is satisfied. */
12931  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12932  assert( origcons != NULL );
12933  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12934 
12935  for (v = 0; v < nvars; ++v)
12936  {
12937  int image;
12938 
12939  assert ( SCIPhashmapExists(varhash, vars[v]) );
12940  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12941  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12942  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12943  }
12944  }
12945  }
12946  }
12947  SCIPhashmapFree(&varhash);
12948  SCIPfreeBufferArray(scip, &cardweights);
12949  SCIPfreeBufferArray(scip, &cardvars);
12950 
12951  if ( *nupgdconss > noldupgdconss )
12952  success = TRUE;
12953  }
12954 #endif
12955 
12956  if( cutoff )
12957  *result = SCIP_CUTOFF;
12958  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12959  *result = SCIP_SUCCESS;
12960  else
12961  *result = SCIP_DIDNOTFIND;
12962 
12963  return SCIP_OKAY;
12964 }
12965 
12966 /** propagation conflict resolving method of constraint handler */
12967 static
12968 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12969 { /*lint --e{715}*/
12970  SCIP_CONSDATA* consdata;
12971  SCIP_Longint capsum;
12972  int i;
12973 
12974  assert(result != NULL);
12975 
12976  consdata = SCIPconsGetData(cons);
12977  assert(consdata != NULL);
12978 
12979  /* check if we fixed a binary variable to one (due to negated clique) */
12980  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12981  {
12982  for( i = 0; i < consdata->nvars; ++i )
12983  {
12984  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12985  {
12986  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12987  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12988  break;
12989  }
12990  }
12991  assert(i < consdata->nvars);
12992  }
12993  else
12994  {
12995  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12996  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12997  * knapsack constraint, see one above call of SCIPinferBinvarCons
12998  */
12999  if( inferinfo < 0 )
13000  capsum = 0;
13001  else
13002  {
13003  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13004  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13005  */
13006  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13007  capsum = consdata->weights[inferinfo];
13008  else
13009  {
13010  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13011  {}
13012  assert(i < consdata->nvars);
13013  capsum = consdata->weights[i];
13014  }
13015  }
13016 
13017  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13018  * the capacity
13019  */
13020  if( capsum <= consdata->capacity )
13021  {
13022  for( i = 0; i < consdata->nvars; i++ )
13023  {
13024  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13025  {
13026  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13027  capsum += consdata->weights[i];
13028  if( capsum > consdata->capacity )
13029  break;
13030  }
13031  }
13032  }
13033  }
13034 
13035  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13036  * to zero can included negated clique information. A negated clique means, that at most one of the clique
13037  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13038  * used to fix variables to zero.
13039  *
13040  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13041  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13042  * one.
13043  */
13044  *result = SCIP_SUCCESS;
13045 
13046  return SCIP_OKAY;
13047 }
13048 
13049 /** variable rounding lock method of constraint handler */
13050 /**! [SnippetConsLockKnapsack] */
13051 static
13052 SCIP_DECL_CONSLOCK(consLockKnapsack)
13053 { /*lint --e{715}*/
13054  SCIP_CONSDATA* consdata;
13055  int i;
13056 
13057  consdata = SCIPconsGetData(cons);
13058  assert(consdata != NULL);
13059 
13060  for( i = 0; i < consdata->nvars; i++)
13061  {
13062  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13063  }
13064 
13065  return SCIP_OKAY;
13066 }
13067 /**! [SnippetConsLockKnapsack] */
13068 
13069 /** constraint activation notification method of constraint handler */
13070 static
13071 SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13072 { /*lint --e{715}*/
13073 
13074  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) )
13075  {
13076  SCIP_CALL( addNlrow(scip, cons) );
13077  }
13078 
13079  return SCIP_OKAY;
13080 }
13081 
13082 /** constraint deactivation notification method of constraint handler */
13083 static
13084 SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13085 { /*lint --e{715}*/
13086  SCIP_CONSDATA* consdata;
13087 
13088  assert(cons != NULL);
13089 
13090  consdata = SCIPconsGetData(cons);
13091  assert(consdata != NULL);
13093  /* remove row from NLP, if still in solving
13094  * if we are in exitsolve, the whole NLP will be freed anyway
13095  */
13096  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13097  {
13098  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13099  }
13100 
13101  return SCIP_OKAY;
13102 }
13103 
13104 /** variable deletion method of constraint handler */
13105 static
13106 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13107 {
13108  assert(scip != NULL);
13109  assert(conshdlr != NULL);
13110  assert(conss != NULL || nconss == 0);
13111 
13112  if( nconss > 0 )
13113  {
13114  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13115  }
13116 
13117  return SCIP_OKAY;
13118 }
13119 
13120 /** constraint display method of constraint handler */
13121 static
13122 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13123 { /*lint --e{715}*/
13124  SCIP_CONSDATA* consdata;
13125  int i;
13126 
13127  assert( scip != NULL );
13128  assert( conshdlr != NULL );
13129  assert( cons != NULL );
13131  consdata = SCIPconsGetData(cons);
13132  assert(consdata != NULL);
13133 
13134  for( i = 0; i < consdata->nvars; ++i )
13135  {
13136  if( i > 0 )
13137  SCIPinfoMessage(scip, file, " ");
13138  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13139  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13140  }
13141  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13142 
13143  return SCIP_OKAY;
13144 }
13145 
13146 /** constraint copying method of constraint handler */
13147 static
13148 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13149 { /*lint --e{715}*/
13150  SCIP_VAR** sourcevars;
13151  SCIP_Longint* weights;
13152  SCIP_Real* coefs;
13153  const char* consname;
13154  int nvars;
13155  int v;
13157  /* get variables and coefficients of the source constraint */
13158  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13159  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13160  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13161 
13162  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13163  for( v = 0; v < nvars; ++v )
13164  coefs[v] = (SCIP_Real) weights[v];
13165 
13166  if( name != NULL )
13167  consname = name;
13168  else
13169  consname = SCIPconsGetName(sourcecons);
13170 
13171  /* copy the logic using the linear constraint copy method */
13172  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13173  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13174  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13175  assert(cons != NULL);
13176 
13177  SCIPfreeBufferArray(scip, &coefs);
13178 
13179  return SCIP_OKAY;
13180 }
13181 
13182 /** constraint parsing method of constraint handler */
13183 static
13184 SCIP_DECL_CONSPARSE(consParseKnapsack)
13185 { /*lint --e{715}*/
13186  SCIP_VAR* var;
13187  SCIP_Longint weight;
13188  SCIP_VAR** vars;
13189  SCIP_Longint* weights;
13190  SCIP_Longint capacity;
13191  char* endptr;
13192  int nread;
13193  int nvars;
13194  int varssize;
13195 
13196  assert(scip != NULL);
13197  assert(success != NULL);
13198  assert(str != NULL);
13199  assert(name != NULL);
13200  assert(cons != NULL);
13201 
13202  *success = TRUE;
13203 
13204  nvars = 0;
13205  varssize = 5;
13206  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13207  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13208 
13209  while( *str != '\0' )
13210  {
13211  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13212  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13213  break;
13214 
13215  str += nread;
13216 
13217  /* skip whitespace */
13218  while( isspace((int)*str) )
13219  ++str;
13220 
13221  /* parse variable name */
13222  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13223  if( var == NULL )
13224  {
13225  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13226  *success = FALSE;
13227  break;
13228  }
13229 
13230  str = endptr;
13231 
13232  /* store weight and variable */
13233  if( varssize <= nvars )
13234  {
13235  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13236  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13237  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13238  }
13239 
13240  vars[nvars] = var;
13241  weights[nvars] = weight;
13242  ++nvars;
13243 
13244  /* skip whitespace */
13245  while( isspace((int)*str) )
13246  ++str;
13247  }
13248 
13249  if( *success )
13250  {
13251  if( strncmp(str, "<= ", 3) != 0 )
13252  {
13253  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13254  *success = FALSE;
13255  }
13256  else
13257  {
13258  str += 3;
13259  }
13260  }
13261 
13262  if( *success )
13263  {
13264  /* coverity[secure_coding] */
13265  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13266  {
13267  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13268  *success = FALSE;
13269  }
13270  else
13271  {
13272  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13273  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13274  }
13275  }
13276 
13277  SCIPfreeBufferArray(scip, &vars);
13278  SCIPfreeBufferArray(scip, &weights);
13279 
13280  return SCIP_OKAY;
13281 }
13282 
13283 /** constraint method of constraint handler which returns the variables (if possible) */
13284 static
13285 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13286 { /*lint --e{715}*/
13287  SCIP_CONSDATA* consdata;
13288 
13289  consdata = SCIPconsGetData(cons);
13290  assert(consdata != NULL);
13291 
13292  if( varssize < consdata->nvars )
13293  (*success) = FALSE;
13294  else
13295  {
13296  assert(vars != NULL);
13297 
13298  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13299  (*success) = TRUE;
13300  }
13301 
13302  return SCIP_OKAY;
13303 }
13304 
13305 /** constraint method of constraint handler which returns the number of variables (if possible) */
13306 static
13307 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13308 { /*lint --e{715}*/
13309  SCIP_CONSDATA* consdata;
13310 
13311  consdata = SCIPconsGetData(cons);
13312  assert(consdata != NULL);
13313 
13314  (*nvars) = consdata->nvars;
13315  (*success) = TRUE;
13316 
13317  return SCIP_OKAY;
13318 }
13319 
13320 /*
13321  * Event handler
13322  */
13323 
13324 /** execution method of bound change event handler */
13325 static
13326 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13327 { /*lint --e{715}*/
13328  SCIP_CONSDATA* consdata;
13329 
13330  assert(eventdata != NULL);
13331  assert(eventdata->cons != NULL);
13332 
13333  consdata = SCIPconsGetData(eventdata->cons);
13334  assert(consdata != NULL);
13335 
13336  switch( SCIPeventGetType(event) )
13337  {
13339  consdata->onesweightsum += eventdata->weight;
13340  consdata->presolvedtiming = 0;
13341  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13342  break;
13344  consdata->onesweightsum -= eventdata->weight;
13345  break;
13347  consdata->presolvedtiming = 0;
13348  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13349  break;
13350  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13351  if( !consdata->existmultaggr )
13352  {
13353  SCIP_VAR* var;
13354  var = SCIPeventGetVar(event);
13355  assert(var != NULL);
13356 
13357  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13359  {
13360  consdata->existmultaggr = TRUE;
13361  consdata->merged = FALSE;
13362  }
13363  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13365  consdata->merged = FALSE;
13366  }
13367  /*lint -fallthrough*/
13368  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13369  consdata->presolvedtiming = 0;
13370  break;
13372  consdata->varsdeleted = TRUE;
13373  break;
13374  default:
13375  SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13376  return SCIP_INVALIDDATA;
13377  }
13378 
13379  return SCIP_OKAY;
13380 }
13381 
13382 
13383 /*
13384  * constraint specific interface methods
13385  */
13386 
13387 /** creates the handler for knapsack constraints and includes it in SCIP */
13389  SCIP* scip /**< SCIP data structure */
13390  )
13391 {
13392  SCIP_EVENTHDLRDATA* eventhdlrdata;
13393  SCIP_CONSHDLRDATA* conshdlrdata;
13394  SCIP_CONSHDLR* conshdlr;
13395 
13396  /* create knapsack constraint handler data */
13397  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13398 
13399  /* include event handler for bound change events */
13400  eventhdlrdata = NULL;
13401  conshdlrdata->eventhdlr = NULL;
13402  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13403  eventExecKnapsack, eventhdlrdata) );
13404 
13405  /* get event handler for bound change events */
13406  if( conshdlrdata->eventhdlr == NULL )
13407  {
13408  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13409  return SCIP_PLUGINNOTFOUND;
13410  }
13411 
13412  /* include constraint handler */
13415  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13416  conshdlrdata) );
13417 
13418  assert(conshdlr != NULL);
13419 
13420  /* set non-fundamental callbacks via specific setter functions */
13421  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13422  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13423  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13424  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13425  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13426  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13427  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13428  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13429  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13430  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13431  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13432  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13433  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13434  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13435  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13436  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13437  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13438  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13439  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13441  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13442  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13444  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13445  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13446 
13447  if( SCIPfindConshdlr(scip,"linear") != NULL )
13448  {
13449  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13451  }
13452 
13453  /* add knapsack constraint handler parameters */
13454  SCIP_CALL( SCIPaddIntParam(scip,
13455  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13456  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13457  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13459  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13460  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13461  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13463  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13464  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13465  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13466  SCIP_CALL( SCIPaddIntParam(scip,
13467  "constraints/" CONSHDLR_NAME "/maxrounds",
13468  "maximal number of separation rounds per node (-1: unlimited)",
13469  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13470  SCIP_CALL( SCIPaddIntParam(scip,
13471  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13472  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13473  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13474  SCIP_CALL( SCIPaddIntParam(scip,
13475  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13476  "maximal number of cuts separated per separation round",
13477  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13478  SCIP_CALL( SCIPaddIntParam(scip,
13479  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13480  "maximal number of cuts separated per separation round in the root node",
13481  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13483  "constraints/" CONSHDLR_NAME "/disaggregation",
13484  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13485  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13487  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13488  "should presolving try to simplify knapsacks",
13489  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13491  "constraints/" CONSHDLR_NAME "/negatedclique",
13492  "should negated clique information be used in solving process",
13493  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13495  "constraints/" CONSHDLR_NAME "/presolpairwise",
13496  "should pairwise constraint comparison be performed in presolving?",
13497  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13499  "constraints/" CONSHDLR_NAME "/presolusehashing",
13500  "should hash table be used for detecting redundant constraints in advance",
13501  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13503  "constraints/" CONSHDLR_NAME "/dualpresolving",
13504  "should dual presolving steps be performed?",
13505  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13507  "constraints/" CONSHDLR_NAME "/usegubs",
13508  "should GUB information be used for separation?",
13509  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13511  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13512  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13513  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13515  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13516  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13517  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13519  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13520  "should clique partition information be updated when old partition seems outdated?",
13521  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13523  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13524  "factor on the growth of global cliques to decide when to update a previous "
13525  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13526  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13527 #ifdef WITH_CARDINALITY_UPGRADE
13529  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13530  "if TRUE then try to update knapsack constraints to cardinality constraints",
13531  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13532 #endif
13533  return SCIP_OKAY;
13534 }
13535 
13536 /** creates and captures a knapsack constraint
13537  *
13538  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13539  */
13540 /**! [SnippetConsCreationKnapsack] */
13542  SCIP* scip, /**< SCIP data structure */
13543  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13544  const char* name, /**< name of constraint */
13545  int nvars, /**< number of items in the knapsack */
13546  SCIP_VAR** vars, /**< array with item variables */
13547  SCIP_Longint* weights, /**< array with item weights */
13548  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13549  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13550  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13551  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13552  * Usually set to TRUE. */
13553  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13554  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13555  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13556  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13557  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13558  * Usually set to TRUE. */
13559  SCIP_Bool local, /**< is constraint only valid locally?
13560  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13561  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13562  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13563  * adds coefficients to this constraint. */
13564  SCIP_Bool dynamic, /**< is constraint subject to aging?
13565  * Usually set to FALSE. Set to TRUE for own cuts which
13566  * are separated as constraints. */
13567  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13568  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13569  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13570  * if it may be moved to a more global node?
13571  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13572  )
13573 {
13574  SCIP_CONSHDLRDATA* conshdlrdata;
13575  SCIP_CONSHDLR* conshdlr;
13576  SCIP_CONSDATA* consdata;
13577 
13578  /* find the knapsack constraint handler */
13579  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13580  if( conshdlr == NULL )
13581  {
13582  SCIPerrorMessage("knapsack constraint handler not found\n");
13583  return SCIP_PLUGINNOTFOUND;
13584  }
13585 
13586  /* get event handler */
13587  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13588  assert(conshdlrdata != NULL);
13589  assert(conshdlrdata->eventhdlr != NULL);
13590 
13591  /* create constraint data */
13592  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13593 
13594  /* create constraint */
13595  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13596  local, modifiable, dynamic, removable, stickingatnode) );
13597 
13598  /* catch events for variables */
13599  if( SCIPisTransformed(scip) )
13600  {
13601  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13602  }
13603 
13604  return SCIP_OKAY;
13605 }
13606 /**! [SnippetConsCreationKnapsack] */
13607 
13608 /** creates and captures a knapsack constraint
13609  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13610  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13611  *
13612  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13613  *
13614  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13615  */
13617  SCIP* scip, /**< SCIP data structure */
13618  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13619  const char* name, /**< name of constraint */
13620  int nvars, /**< number of items in the knapsack */
13621  SCIP_VAR** vars, /**< array with item variables */
13622  SCIP_Longint* weights, /**< array with item weights */
13623  SCIP_Longint capacity /**< capacity of knapsack */
13624  )
13625 {
13626  assert(scip != NULL);
13627 
13628  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13629  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13630 
13631  return SCIP_OKAY;
13632 }
13633 
13634 /** adds new item to knapsack constraint */
13636  SCIP* scip, /**< SCIP data structure */
13637  SCIP_CONS* cons, /**< constraint data */
13638  SCIP_VAR* var, /**< item variable */
13639  SCIP_Longint weight /**< item weight */
13640  )
13641 {
13642  assert(var != NULL);
13643  assert(scip != NULL);
13644 
13645  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13646  {
13647  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13648  return SCIP_INVALIDDATA;
13649  }
13650 
13651  SCIP_CALL( addCoef(scip, cons, var, weight) );
13652 
13653  return SCIP_OKAY;
13654 }
13655 
13656 /** gets the capacity of the knapsack constraint */
13658  SCIP* scip, /**< SCIP data structure */
13659  SCIP_CONS* cons /**< constraint data */
13660  )
13661 {
13662  SCIP_CONSDATA* consdata;
13663 
13664  assert(scip != NULL);
13666  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13667  {
13668  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13669  SCIPABORT();
13670  return 0; /*lint !e527*/
13671  }
13672 
13673  consdata = SCIPconsGetData(cons);
13674  assert(consdata != NULL);
13675 
13676  return consdata->capacity;
13677 }
13678 
13679 /** changes capacity of the knapsack constraint
13680  *
13681  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13682  */
13684  SCIP* scip, /**< SCIP data structure */
13685  SCIP_CONS* cons, /**< constraint data */
13686  SCIP_Longint capacity /**< new capacity of knapsack */
13687  )
13688 {
13689  SCIP_CONSDATA* consdata;
13690 
13691  assert(scip != NULL);
13692 
13693  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13694  {
13695  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13696  return SCIP_INVALIDDATA;
13697  }
13698 
13699  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13700  {
13701  SCIPerrorMessage("method can only be called during problem creation stage\n");
13702  return SCIP_INVALIDDATA;
13703  }
13704 
13705  consdata = SCIPconsGetData(cons);
13706  assert(consdata != NULL);
13707 
13708  consdata->capacity = capacity;
13709 
13710  return SCIP_OKAY;
13711 }
13712 
13713 /** gets the number of items in the knapsack constraint */
13715  SCIP* scip, /**< SCIP data structure */
13716  SCIP_CONS* cons /**< constraint data */
13717  )
13718 {
13719  SCIP_CONSDATA* consdata;
13720 
13721  assert(scip != NULL);
13723  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13724  {
13725  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13726  SCIPABORT();
13727  return -1; /*lint !e527*/
13728  }
13729 
13730  consdata = SCIPconsGetData(cons);
13731  assert(consdata != NULL);
13732 
13733  return consdata->nvars;
13734 }
13735 
13736 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13738  SCIP* scip, /**< SCIP data structure */
13739  SCIP_CONS* cons /**< constraint data */
13740  )
13741 {
13742  SCIP_CONSDATA* consdata;
13743 
13744  assert(scip != NULL);
13746  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13747  {
13748  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13749  SCIPABORT();
13750  return NULL; /*lint !e527*/
13751  }
13752 
13753  consdata = SCIPconsGetData(cons);
13754  assert(consdata != NULL);
13755 
13756  return consdata->vars;
13757 }
13758 
13759 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13761  SCIP* scip, /**< SCIP data structure */
13762  SCIP_CONS* cons /**< constraint data */
13763  )
13764 {
13765  SCIP_CONSDATA* consdata;
13766 
13767  assert(scip != NULL);
13769  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13770  {
13771  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13772  SCIPABORT();
13773  return NULL; /*lint !e527*/
13774  }
13775 
13776  consdata = SCIPconsGetData(cons);
13777  assert(consdata != NULL);
13778 
13779  return consdata->weights;
13780 }
13781 
13782 /** gets the dual solution of the knapsack constraint in the current LP */
13784  SCIP* scip, /**< SCIP data structure */
13785  SCIP_CONS* cons /**< constraint data */
13786  )
13787 {
13788  SCIP_CONSDATA* consdata;
13789 
13790  assert(scip != NULL);
13792  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13793  {
13794  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13795  SCIPABORT();
13796  return SCIP_INVALID; /*lint !e527*/
13797  }
13798 
13799  consdata = SCIPconsGetData(cons);
13800  assert(consdata != NULL);
13801 
13802  if( consdata->row != NULL )
13803  return SCIProwGetDualsol(consdata->row);
13804  else
13805  return 0.0;
13806 }
13807 
13808 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13810  SCIP* scip, /**< SCIP data structure */
13811  SCIP_CONS* cons /**< constraint data */
13812  )
13813 {
13814  SCIP_CONSDATA* consdata;
13815 
13816  assert(scip != NULL);
13818  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13819  {
13820  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13821  SCIPABORT();
13822  return SCIP_INVALID; /*lint !e527*/
13823  }
13824 
13825  consdata = SCIPconsGetData(cons);
13826  assert(consdata != NULL);
13827 
13828  if( consdata->row != NULL )
13829  return SCIProwGetDualfarkas(consdata->row);
13830  else
13831  return 0.0;
13832 }
13833 
13834 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13835  * the user must not modify the row!
13836  */
13838  SCIP* scip, /**< SCIP data structure */
13839  SCIP_CONS* cons /**< constraint data */
13840  )
13841 {
13842  SCIP_CONSDATA* consdata;
13843 
13844  assert(scip != NULL);
13846  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13847  {
13848  SCIPerrorMessage("constraint is not a knapsack\n");
13849  SCIPABORT();
13850  return NULL; /*lint !e527*/
13851  }
13852 
13853  consdata = SCIPconsGetData(cons);
13854  assert(consdata != NULL);
13855 
13856  return consdata->row;
13857 }
13858 
13859 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13861  SCIP* scip, /**< SCIP data structure */
13862  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13863  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13864  )
13865 {
13866  SCIP_CONSHDLR* conshdlr;
13867  SCIP_CONS** conss;
13868  int nconss;
13869  int i;
13870 
13871  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13872  if( conshdlr == NULL )
13873  return SCIP_OKAY;
13874 
13875  assert(infeasible != NULL);
13876  *infeasible = FALSE;
13877 
13878  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13879  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13880 
13881  for( i = 0; i < nconss; ++i )
13882  {
13883  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13884 
13885  if( *infeasible )
13886  break;
13887  }
13888 
13889  return SCIP_OKAY;
13890 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define KNAPSACKRELAX_MAXSCALE
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int * gubconssidx
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4205
#define DEFAULT_DETECTCUTOFFBOUND
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1721
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:1413
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:90
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1690
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:137
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
GUBVarstatus
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18124
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:11474
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3368
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:101
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5200
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1626
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2125
#define CONSHDLR_DESC
Definition: cons_knapsack.c:71
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for SCIP parameter handling
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3289
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:86
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:63
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8344
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17702
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1594
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1473
SCIP_Bool SCIPisFeasLT(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 SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3297
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1989
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2487
public methods for memory management
static SCIP_DECL_CONSINIT(consInitKnapsack)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1649
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:117
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18102
#define DEFAULT_CLQPARTUPDATEFAC
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
public methods for implications, variable bounds, and cliques
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17910
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
GUBCONSSTATUS * gubconsstatus
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:12309
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define SCIP_MAXSTRLEN
Definition: def.h:293
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3347
public methods for conflict handler plugins and conflict analysis
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:73
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:308
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:88
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1749
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2842
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17690
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1686
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1308
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip_var.c:1557
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18273
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_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip_cons.c:678
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
#define LINCONSUPGD_PRIORITY
Definition: cons_knapsack.c:96
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
#define DEFAULT_CLIQUEEXTRACTFACTOR
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
SCIP_GUBCONS ** gubconss
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1461
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:524
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1245
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17431
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:146
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:477
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
GUBConsstatus
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define CONSHDLR_SEPAFREQ
Definition: cons_knapsack.c:75
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4547
#define FALSE
Definition: def.h:87
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3014
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11063
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
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:80
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10755
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:86
#define SCIPdebug(x)
Definition: pub_message.h:84
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:734
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1979
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)
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip_prob.c:3584
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:77
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8364
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18144
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3132
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17600
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:891
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4854
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8394
public methods for problem variables
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:522
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5317
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:88
#define SCIPdebugMessage
Definition: pub_message.h:87
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
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18114
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:123
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5084
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_LONGINT_MAX
Definition: def.h:163
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:566
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:419
public methods for SCIP variables
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip_cons.c:747
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8354
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:609
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17278
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
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
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1477
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:85
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
#define DEFAULT_PRESOLUSEHASHING
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8146
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18262
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2171
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_Real SCIPepsilon(SCIP *scip)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
public methods for numerical tolerances
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:2236
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
public methods for querying solving statistics
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17726
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17489
#define DEFAULT_SEPACARDFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3363
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4256
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:69
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
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)
static SCIP_DECL_CONSPARSE(consParseKnapsack)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1233
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:6918
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_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17920
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:12217
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:429
SCIP_VAR * w
Definition: circlepacking.c:58
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:96
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:72
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:108
public methods for managing constraints
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:603
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:1863
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
enum GUBVarstatus GUBVARSTATUS
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:55
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4175
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2769
#define SCIPdebugPrintf
Definition: pub_message.h:90
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:354
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3473
public methods for event handler plugins and event handlers
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1389
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
#define DEFAULT_PRESOLPAIRWISE
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:113
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1016
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define DEFAULT_DUALPRESOLVING
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip_prob.c:2897
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:126
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4434
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1283
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8085
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18176
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8304
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:76
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
static SCIP_DECL_CONSACTIVE(consActiveKnapsack)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4195
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1951
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:201
#define DEFAULT_NEGATEDCLIQUE
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)
public methods for problem copies
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
#define SCIP_CALL(x)
Definition: def.h:384
SCIP_Real SCIPgetLowerbound(SCIP *scip)
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:68
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18134
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17714
SCIP_VAR * h
Definition: circlepacking.c:59
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2617
GUBVARSTATUS * gubvarsstatus
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:276
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:216
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18166
Definition: graph_load.c:93
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8324
#define KNAPSACKRELAX_MAXDNOM
#define DEFAULT_MAXSEPACUTSROOT
static SCIP_DECL_CONSFREE(consFreeKnapsack)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:632
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
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
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9259
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
public data structures and miscellaneous methods
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18220
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1044
#define SCIP_Bool
Definition: def.h:84
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1021
#define MINGAINPERNMINCOMPARISONS
static SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_DECL_CONSPROP(consPropKnapsack)
#define MAXABSVBCOEF
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:81
#define DEFAULT_MAXSEPACUTS
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
#define DEFAULT_MAXCARDBOUNDDIST
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:661
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18188
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
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_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7253
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8105
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11941
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3380
public methods for LP management
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:1444
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8214
#define DEFAULT_USEGUBS
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
#define KNAPSACKRELAX_MAXDELTA
public methods for cuts and aggregation rows
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8284
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8254
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17758
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:99
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:89
#define CONSHDLR_NAME
Definition: cons_knapsack.c:70
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:912
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8273
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:127
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:82
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17291
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4348
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:70
Constraint handler for linear constraints in their most general form, .
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2219
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2548
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17678
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18234
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define SCIP_MAXTREEDEPTH
Definition: def.h:320
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4624
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
public methods for the LP relaxation, rows and columns
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2286
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1991
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:382
public methods for nonlinear relaxation
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3695
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
methods for sorting joint arrays of various types
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18205
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:501
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)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
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:125
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_DECL_CONSLOCK(consLockKnapsack)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
public methods for solutions
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8115
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:381
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4567
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1258
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:405
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:143
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip_copy.c:651
public methods for the probing mode
constraint handler for cardinality constraints
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
#define DEFAULT_DETECTLOWERBOUND
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
public methods for message output
#define HASHSIZE_KNAPSACKCONS
enum GUBConsstatus GUBCONSSTATUS
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7572
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:98
static SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1946
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17370
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7472
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1211
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:177
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8334
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:694
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12277
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
#define GUBCONSGROWVALUE
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4610
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8274
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:90
#define SCIP_INVALID
Definition: def.h:197
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8264
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2197
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18156
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:76
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:83
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
#define SCIP_Longint
Definition: def.h:162
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:9458
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17590
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:102
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3358
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17393
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
public methods for separators
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
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)
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip_cons.c:655
#define USESUPADDLIFT
SCIPallocBlockMemory(scip, subsol))
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:430
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3221
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:1382
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:453
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:356
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:221
public methods for global and local (sub)problems
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17442
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9022
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17472
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
#define DEFAULT_UPDATECLIQUEPARTITIONS
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8626
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 SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5720
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:74
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:62
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1524
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48
int SCIPgetNSepaRounds(SCIP *scip)
#define DEFAULT_SIMPLIFYINEQUALITIES
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17580
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17406
methods for selecting (weighted) k-medians
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:119
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 SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1208
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
memory allocation routines