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-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_knapsack.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
19  * @author Tobias Achterberg
20  * @author Xin Liu
21  * @author Kati Wolter
22  * @author Michael Winkler
23  * @author Tobias Fischer
24  */
25 
26 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
27 
28 #include "blockmemshell/memory.h"
29 #include "scip/cons_knapsack.h"
30 #include "scip/cons_linear.h"
31 #include "scip/cons_logicor.h"
32 #include "scip/cons_setppc.h"
33 #include "scip/pub_cons.h"
34 #include "scip/pub_event.h"
35 #include "scip/pub_implics.h"
36 #include "scip/pub_lp.h"
37 #include "scip/pub_message.h"
38 #include "scip/pub_misc.h"
39 #include "scip/pub_misc_select.h"
40 #include "scip/pub_misc_sort.h"
41 #include "scip/pub_sepa.h"
42 #include "scip/pub_var.h"
43 #include "scip/scip_branch.h"
44 #include "scip/scip_conflict.h"
45 #include "scip/scip_cons.h"
46 #include "scip/scip_copy.h"
47 #include "scip/scip_cut.h"
48 #include "scip/scip_event.h"
49 #include "scip/scip_general.h"
50 #include "scip/scip_lp.h"
51 #include "scip/scip_mem.h"
52 #include "scip/scip_message.h"
53 #include "scip/scip_numerics.h"
54 #include "scip/scip_param.h"
55 #include "scip/scip_prob.h"
56 #include "scip/scip_probing.h"
57 #include "scip/scip_sol.h"
58 #include "scip/scip_solvingstats.h"
59 #include "scip/scip_tree.h"
60 #include "scip/scip_var.h"
61 #include <ctype.h>
62 #include <string.h>
63 
64 #ifdef WITH_CARDINALITY_UPGRADE
65 #include "scip/cons_cardinality.h"
66 #endif
67 
68 /* constraint handler properties */
69 #define CONSHDLR_NAME "knapsack"
70 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
71 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
72 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
73 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
74 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
75 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
76 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
77  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
78 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
79 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
80 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
81 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
82 
83 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
84 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
85 
86 #define EVENTHDLR_NAME "knapsack"
87 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
88 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
89  | SCIP_EVENTTYPE_UBTIGHTENED \
90  | SCIP_EVENTTYPE_VARFIXED \
91  | SCIP_EVENTTYPE_VARDELETED \
92  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
93 
94 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
95 
96 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
97 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
98 
99 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
100 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
101 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
103 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
104 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
105 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
106 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
107 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
108 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
109  * to best node's dual bound for separating knapsack cuts */
110 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
111 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
112 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
114 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
115 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
117 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
118 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
120 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
121 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
122 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
123  * comparison round */
124 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
125 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
126  * function defining an upper bound and prevent these constraints from
127  * entering the LP */
128 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
129  * function defining a lower bound and prevent these constraints from
130  * entering the LP */
131 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
132 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
134 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
135 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
136 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
137 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
138  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
139 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
140 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
141 #ifdef WITH_CARDINALITY_UPGRADE
142 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
143 #endif
145 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
146 
147 /*
148  * Data structures
149  */
150 
151 /** constraint handler data */
152 struct SCIP_ConshdlrData
153 {
154  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
155  * you have to clear it at the end, exists only in presolving stage */
156  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
157  * you have to clear it at the end, exists only in presolving stage */
158  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
159  * you have to clear it at the end, exists only in presolving stage */
160  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
161  * you have to clear it at the end, exists only in presolving stage */
162  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
163  * you have to clear it at the end, exists only in presolving stage */
164  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
165  * you have to clear it at the end, exists only in presolving stage */
166  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167  * you have to clear it at the end, exists only in presolving stage */
168  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169  * you have to clear it at the end, exists only in presolving stage */
170  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
171  * you have to clear it at the end */
172  int ints1size; /**< size of ints1 array */
173  int ints2size; /**< size of ints2 array */
174  int longints1size; /**< size of longints1 array */
175  int longints2size; /**< size of longints2 array */
176  int bools1size; /**< size of bools1 array */
177  int bools2size; /**< size of bools2 array */
178  int bools3size; /**< size of bools3 array */
179  int bools4size; /**< size of bools4 array */
180  int reals1size; /**< size of reals1 array */
181  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
182  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
183  * to best node's dual bound for separating knapsack cuts */
184  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
185  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
186  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
187  int maxsepacuts; /**< maximal number of cuts separated per separation round */
188  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
189  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
190  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
191  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
192  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
193  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
194  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
195  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
196  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
197  * function defining an upper bound and prevent these constraints from
198  * entering the LP */
199  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
200  * function defining a lower bound and prevent these constraints from
201  * entering the LP */
202  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
203  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
204  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
205  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
206 #ifdef WITH_CARDINALITY_UPGRADE
207  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
208  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
209 #endif
210 };
211 
212 
213 /** constraint data for knapsack constraints */
214 struct SCIP_ConsData
215 {
216  SCIP_VAR** vars; /**< variables in knapsack constraint */
217  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
218  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
219  int* cliquepartition; /**< clique indices of the clique partition */
220  int* negcliquepartition; /**< clique indices of the negated clique partition */
221  SCIP_ROW* row; /**< corresponding LP row */
222  int nvars; /**< number of variables in knapsack constraint */
223  int varssize; /**< size of vars, weights, and eventdata arrays */
224  int ncliques; /**< number of cliques in the clique partition */
225  int nnegcliques; /**< number of cliques in the negated clique partition */
226  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
227  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
228  SCIP_Longint capacity; /**< capacity of knapsack */
229  SCIP_Longint weightsum; /**< sum of all weights */
230  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
231  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
232  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
233  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
234  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
235  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
236  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
237  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
238  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
239 };
240 
241 /** event data for bound changes events */
242 struct SCIP_EventData
243 {
244  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
245  SCIP_Longint weight; /**< weight of variable */
246  int filterpos; /**< position of event in variable's event filter */
247 };
248 
249 
250 /** data structure to combine two sorting key values */
251 struct sortkeypair
252 {
253  SCIP_Real key1; /**< first sort key value */
254  SCIP_Real key2; /**< second sort key value */
255 };
256 typedef struct sortkeypair SORTKEYPAIR;
257 
258 /** status of GUB constraint */
259 enum GUBVarstatus
260 {
261  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
262  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
263  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
264  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
265  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
266  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
267 };
268 typedef enum GUBVarstatus GUBVARSTATUS;
270 /** status of variable in GUB constraint */
272 {
273  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
274  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
275  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
276  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
277  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
278  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
279 };
280 typedef enum GUBConsstatus GUBCONSSTATUS;
282 /** data structure of GUB constraints */
284 {
285  int* gubvars; /**< indices of GUB variables in knapsack constraint */
286  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
287  int ngubvars; /**< number of GUB variables */
288  int gubvarssize; /**< size of gubvars array */
289 };
290 typedef struct SCIP_GUBCons SCIP_GUBCONS;
292 /** data structure of a set of GUB constraints */
294 {
295  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
296  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
297  int ngubconss; /**< number of GUB constraints */
298  int nvars; /**< number of variables in knapsack constraint */
299  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
300  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
301 };
302 typedef struct SCIP_GUBSet SCIP_GUBSET;
304 /*
305  * Local methods
306  */
308 /** comparison method for two sorting key pairs */
309 static
310 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
311 {
312  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
313  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
314 
315  if( sortkeypair1->key1 < sortkeypair2->key1 )
316  return -1;
317  else if( sortkeypair1->key1 > sortkeypair2->key1 )
318  return +1;
319  else if( sortkeypair1->key2 < sortkeypair2->key2 )
320  return -1;
321  else if( sortkeypair1->key2 > sortkeypair2->key2 )
322  return +1;
323  else
324  return 0;
325 }
326 
327 /** creates event data */
328 static
330  SCIP* scip, /**< SCIP data structure */
331  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
332  SCIP_CONS* cons, /**< constraint */
333  SCIP_Longint weight /**< weight of variable */
334  )
335 {
336  assert(eventdata != NULL);
338  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
339  (*eventdata)->cons = cons;
340  (*eventdata)->weight = weight;
341 
342  return SCIP_OKAY;
343 }
344 
345 /** frees event data */
346 static
348  SCIP* scip, /**< SCIP data structure */
349  SCIP_EVENTDATA** eventdata /**< pointer to event data */
350  )
351 {
352  assert(eventdata != NULL);
353 
354  SCIPfreeBlockMemory(scip, eventdata);
356  return SCIP_OKAY;
357 }
358 
359 /** sorts items in knapsack with nonincreasing weights */
360 static
361 void sortItems(
362  SCIP_CONSDATA* consdata /**< constraint data */
363  )
364 {
365  assert(consdata != NULL);
366  assert(consdata->nvars == 0 || consdata->vars != NULL);
367  assert(consdata->nvars == 0 || consdata->weights != NULL);
368  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
369  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
370 
371  if( !consdata->sorted )
372  {
373  int pos;
374  int lastcliquenum;
375  int v;
376 
377  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
378  * sorted by first array in non-increasing order via sort template */
380  consdata->weights,
381  (void**)consdata->vars,
382  (void**)consdata->eventdata,
383  consdata->cliquepartition,
384  consdata->negcliquepartition,
385  consdata->nvars);
386 
387  v = consdata->nvars - 1;
388  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
389  while( v >= 0 )
390  {
391  int w = v - 1;
392 
393  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
394  --w;
395 
396  if( v - w > 1 )
397  {
398  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
400  (void**)(&(consdata->vars[w+1])),
401  (void**)(&(consdata->eventdata[w+1])),
402  &(consdata->cliquepartition[w+1]),
403  &(consdata->negcliquepartition[w+1]),
404  SCIPvarComp,
405  v - w);
406  }
407  v = w;
408  }
409 
410  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
411  if( consdata->cliquepartitioned )
412  {
413  lastcliquenum = 0;
414 
415  for( pos = 0; pos < consdata->nvars; ++pos )
416  {
417  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
418  * partition is invalid */
419  if( consdata->cliquepartition[pos] > lastcliquenum )
420  {
421  consdata->cliquepartitioned = FALSE;
422  break;
423  }
424  else if( consdata->cliquepartition[pos] == lastcliquenum )
425  ++lastcliquenum;
426  }
427  }
428  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
429  if( consdata->negcliquepartitioned )
430  {
431  lastcliquenum = 0;
432 
433  for( pos = 0; pos < consdata->nvars; ++pos )
434  {
435  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
436  * partition is invalid */
437  if( consdata->negcliquepartition[pos] > lastcliquenum )
438  {
439  consdata->negcliquepartitioned = FALSE;
440  break;
441  }
442  else if( consdata->negcliquepartition[pos] == lastcliquenum )
443  ++lastcliquenum;
444  }
445  }
446 
447  consdata->sorted = TRUE;
448  }
449 #ifndef NDEBUG
450  {
451  /* check if the weight array is sorted in a non-increasing way */
452  int i;
453  for( i = 0; i < consdata->nvars-1; ++i )
454  assert(consdata->weights[i] >= consdata->weights[i+1]);
455  }
456 #endif
457 }
458 
459 /** calculates a partition of the variables into cliques */
460 static
462  SCIP* scip, /**< SCIP data structure */
463  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
464  SCIP_CONSDATA* consdata, /**< constraint data */
465  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
466  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
467  )
468 {
469  SCIP_Bool ispartitionoutdated;
470  SCIP_Bool isnegpartitionoutdated;
471  assert(consdata != NULL);
472  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
473 
474  /* rerun eventually if number of global cliques increased considerably since last partition */
475  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
476  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
477 
478  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
479  {
480  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
481  consdata->cliquepartitioned = TRUE;
482  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
483  }
484 
485  /* rerun eventually if number of global cliques increased considerably since last negated partition */
486  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
487  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
488 
489  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
490  {
491  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
492  consdata->negcliquepartitioned = TRUE;
493  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
494  }
495  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
496  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
497 
498  return SCIP_OKAY;
499 }
500 
501 /** installs rounding locks for the given variable in the given knapsack constraint */
502 static
504  SCIP* scip, /**< SCIP data structure */
505  SCIP_CONS* cons, /**< knapsack constraint */
506  SCIP_VAR* var /**< variable of constraint entry */
507  )
508 {
509  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
510 
511  return SCIP_OKAY;
512 }
513 
514 /** removes rounding locks for the given variable in the given knapsack constraint */
515 static
517  SCIP* scip, /**< SCIP data structure */
518  SCIP_CONS* cons, /**< knapsack constraint */
519  SCIP_VAR* var /**< variable of constraint entry */
520  )
521 {
522  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
523 
524  return SCIP_OKAY;
525 }
526 
527 /** catches bound change events for variables in knapsack */
528 static
530  SCIP* scip, /**< SCIP data structure */
531  SCIP_CONS* cons, /**< constraint */
532  SCIP_CONSDATA* consdata, /**< constraint data */
533  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
534  )
535 {
536  int i;
538  assert(cons != NULL);
539  assert(consdata != NULL);
540  assert(consdata->nvars == 0 || consdata->vars != NULL);
541  assert(consdata->nvars == 0 || consdata->weights != NULL);
542  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
543 
544  for( i = 0; i < consdata->nvars; i++)
545  {
546  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
547  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
548  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
549  }
550 
551  return SCIP_OKAY;
552 }
553 
554 /** drops bound change events for variables in knapsack */
555 static
557  SCIP* scip, /**< SCIP data structure */
558  SCIP_CONSDATA* consdata, /**< constraint data */
559  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
560  )
561 {
562  int i;
563 
564  assert(consdata != NULL);
565  assert(consdata->nvars == 0 || consdata->vars != NULL);
566  assert(consdata->nvars == 0 || consdata->weights != NULL);
567  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
568 
569  for( i = 0; i < consdata->nvars; i++)
570  {
571  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
572  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
573  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
574  }
575 
576  return SCIP_OKAY;
577 }
578 
579 /** ensures, that vars and vals arrays can store at least num entries */
580 static
582  SCIP* scip, /**< SCIP data structure */
583  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
584  int num, /**< minimum number of entries to store */
585  SCIP_Bool transformed /**< is constraint from transformed problem? */
586  )
587 {
588  assert(consdata != NULL);
589  assert(consdata->nvars <= consdata->varssize);
590 
591  if( num > consdata->varssize )
592  {
593  int newsize;
594 
595  newsize = SCIPcalcMemGrowSize(scip, num);
596  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
597  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
598  if( transformed )
599  {
600  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
601  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
602  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
603  }
604  else
605  {
606  assert(consdata->eventdata == NULL);
607  assert(consdata->cliquepartition == NULL);
608  assert(consdata->negcliquepartition == NULL);
609  }
610  consdata->varssize = newsize;
611  }
612  assert(num <= consdata->varssize);
613 
614  return SCIP_OKAY;
615 }
616 
617 /** updates all weight sums for fixed and unfixed variables */
618 static
619 void updateWeightSums(
620  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
621  SCIP_VAR* var, /**< variable for this weight */
622  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
623  )
624 {
625  assert(consdata != NULL);
626  assert(var != NULL);
628  consdata->weightsum += weightdelta;
629 
630  if( SCIPvarGetLbLocal(var) > 0.5 )
631  consdata->onesweightsum += weightdelta;
632 
633  assert(consdata->weightsum >= 0);
634  assert(consdata->onesweightsum >= 0);
635 }
636 
637 /** creates knapsack constraint data */
638 static
640  SCIP* scip, /**< SCIP data structure */
641  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
642  int nvars, /**< number of variables in knapsack */
643  SCIP_VAR** vars, /**< variables of knapsack */
644  SCIP_Longint* weights, /**< weights of knapsack items */
645  SCIP_Longint capacity /**< capacity of knapsack */
646  )
647 {
648  int v;
649  SCIP_Longint constant;
650 
651  assert(consdata != NULL);
652 
653  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
654 
655  constant = 0L;
656  (*consdata)->vars = NULL;
657  (*consdata)->weights = NULL;
658  (*consdata)->nvars = 0;
659  if( nvars > 0 )
660  {
661  SCIP_VAR** varsbuffer;
662  SCIP_Longint* weightsbuffer;
663  int k;
664 
665  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
666  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
667 
668  k = 0;
669  for( v = 0; v < nvars; ++v )
670  {
671  assert(vars[v] != NULL);
672  assert(SCIPvarIsBinary(vars[v]));
673 
674  /* all weight have to be non negative */
675  assert( weights[v] >= 0 );
676 
677  if( weights[v] > 0 )
678  {
679  /* treat fixed variables as constants if problem compression is enabled */
680  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
681  {
682  /* only if the variable is fixed to 1, we add its weight to the constant */
683  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
684  constant += weights[v];
685  }
686  else
687  {
688  varsbuffer[k] = vars[v];
689  weightsbuffer[k] = weights[v];
690  ++k;
691  }
692  }
693  }
694  assert(k >= 0);
695 
696  (*consdata)->nvars = k;
697 
698  /* copy the active variables and weights into the constraint data structure */
699  if( k > 0 )
700  {
701  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
702  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
703  }
704 
705  /* free buffer storage */
706  SCIPfreeBufferArray(scip, &weightsbuffer);
707  SCIPfreeBufferArray(scip, &varsbuffer);
708  }
709 
710  /* capacity has to be greater or equal to zero */
711  assert(capacity >= 0);
712  assert(constant >= 0);
713 
714  (*consdata)->varssize = (*consdata)->nvars;
715  (*consdata)->capacity = capacity - constant;
716  (*consdata)->eventdata = NULL;
717  (*consdata)->cliquepartition = NULL;
718  (*consdata)->negcliquepartition = NULL;
719  (*consdata)->row = NULL;
720  (*consdata)->weightsum = 0;
721  (*consdata)->onesweightsum = 0;
722  (*consdata)->ncliques = 0;
723  (*consdata)->nnegcliques = 0;
724  (*consdata)->presolvedtiming = 0;
725  (*consdata)->sorted = FALSE;
726  (*consdata)->cliquepartitioned = FALSE;
727  (*consdata)->negcliquepartitioned = FALSE;
728  (*consdata)->ncliqueslastpart = -1;
729  (*consdata)->ncliqueslastnegpart = -1;
730  (*consdata)->merged = FALSE;
731  (*consdata)->cliquesadded = FALSE;
732  (*consdata)->varsdeleted = FALSE;
733  (*consdata)->existmultaggr = FALSE;
734 
735  /* get transformed variables, if we are in the transformed problem */
736  if( SCIPisTransformed(scip) )
737  {
738  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
739 
740  for( v = 0; v < (*consdata)->nvars; v++ )
741  {
742  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
743  assert(var != NULL);
744  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
745  }
746 
747  /* allocate memory for additional data structures */
748  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
749  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
750  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
751  }
752 
753  /* calculate sum of weights and capture variables */
754  for( v = 0; v < (*consdata)->nvars; ++v )
755  {
756  /* calculate sum of weights */
757  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
758 
759  /* capture variables */
760  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
761  }
762  return SCIP_OKAY;
763 }
764 
765 /** frees knapsack constraint data */
766 static
768  SCIP* scip, /**< SCIP data structure */
769  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
770  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
771  )
772 {
773  assert(consdata != NULL);
774  assert(*consdata != NULL);
776  if( (*consdata)->row != NULL )
777  {
778  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
779  }
780  if( (*consdata)->eventdata != NULL )
781  {
782  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
783  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
784  }
785  if( (*consdata)->negcliquepartition != NULL )
786  {
787  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
788  }
789  if( (*consdata)->cliquepartition != NULL )
790  {
791  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
792  }
793  if( (*consdata)->vars != NULL )
794  {
795  int v;
796 
797  /* release variables */
798  for( v = 0; v < (*consdata)->nvars; v++ )
799  {
800  assert((*consdata)->vars[v] != NULL);
801  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
802  }
803 
804  assert( (*consdata)->weights != NULL );
805  assert( (*consdata)->varssize > 0 );
806  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
807  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
808  }
809 
810  SCIPfreeBlockMemory(scip, consdata);
811 
812  return SCIP_OKAY;
813 }
814 
815 /** changes a single weight in knapsack constraint data */
816 static
817 void consdataChgWeight(
818  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
819  int item, /**< item number */
820  SCIP_Longint newweight /**< new weight of item */
821  )
822 {
823  SCIP_Longint oldweight;
824  SCIP_Longint weightdiff;
826  assert(consdata != NULL);
827  assert(0 <= item && item < consdata->nvars);
828 
829  oldweight = consdata->weights[item];
830  weightdiff = newweight - oldweight;
831  consdata->weights[item] = newweight;
832 
833  /* update weight sums for all and fixed variables */
834  updateWeightSums(consdata, consdata->vars[item], weightdiff);
835 
836  if( consdata->eventdata != NULL )
837  {
838  assert(consdata->eventdata[item] != NULL);
839  assert(consdata->eventdata[item]->weight == oldweight);
840  consdata->eventdata[item]->weight = newweight;
841  }
842 
843  consdata->presolvedtiming = 0;
844  consdata->sorted = FALSE;
845 
846  /* recalculate cliques extraction after a weight was increased */
847  if( oldweight < newweight )
848  {
849  consdata->cliquesadded = FALSE;
850  }
851 }
852 
853 /** creates LP row corresponding to knapsack constraint */
854 static
856  SCIP* scip, /**< SCIP data structure */
857  SCIP_CONS* cons /**< knapsack constraint */
858  )
859 {
860  SCIP_CONSDATA* consdata;
861  int i;
862 
863  consdata = SCIPconsGetData(cons);
864  assert(consdata != NULL);
865  assert(consdata->row == NULL);
866 
867  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
868  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
870 
871  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
872  for( i = 0; i < consdata->nvars; ++i )
873  {
874  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
875  }
876  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
877 
878  return SCIP_OKAY;
879 }
880 
881 /** adds linear relaxation of knapsack constraint to the LP */
882 static
884  SCIP* scip, /**< SCIP data structure */
885  SCIP_CONS* cons, /**< knapsack constraint */
886  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
887  )
888 {
889  SCIP_CONSDATA* consdata;
890 
891  assert( cutoff != NULL );
892  *cutoff = FALSE;
893 
894  consdata = SCIPconsGetData(cons);
895  assert(consdata != NULL);
896 
897  if( consdata->row == NULL )
898  {
899  SCIP_CALL( createRelaxation(scip, cons) );
900  }
901  assert(consdata->row != NULL);
902 
903  /* insert LP row as cut */
904  if( !SCIProwIsInLP(consdata->row) )
905  {
906  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
907  SCIPconsGetName(cons), consdata->capacity);
908  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
909  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
910  }
911 
912  return SCIP_OKAY;
913 }
914 
915 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
916 static
918  SCIP* scip, /**< SCIP data structure */
919  SCIP_CONS* cons, /**< constraint to check */
920  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
921  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
922  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
923  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
924  )
925 {
926  SCIP_CONSDATA* consdata;
927 
928  assert(violated != NULL);
929 
930  consdata = SCIPconsGetData(cons);
931  assert(consdata != NULL);
932 
933  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
934  SCIPconsGetName(cons), (void*)sol, checklprows);
935 
936  *violated = FALSE;
937 
938  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
939  {
940  SCIP_Real sum;
941  SCIP_Longint integralsum;
942  SCIP_Bool ishuge;
943  SCIP_Real absviol;
944  SCIP_Real relviol;
945  int v;
946 
947  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
948  * enforcement
949  */
950  if( sol == NULL )
951  {
952  SCIP_CALL( SCIPincConsAge(scip, cons) );
953  }
954 
955  sum = 0.0;
956  integralsum = 0;
957  /* we perform a more exact comparison if the capacity does not exceed the huge value */
958  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
959  {
960  ishuge = TRUE;
961 
962  /* sum over all weight times the corresponding solution value */
963  for( v = consdata->nvars - 1; v >= 0; --v )
964  {
965  assert(SCIPvarIsBinary(consdata->vars[v]));
966  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
967  }
968  }
969  else
970  {
971  ishuge = FALSE;
972 
973  /* sum over all weight for which the variable has a solution value of 1 in feastol */
974  for( v = consdata->nvars - 1; v >= 0; --v )
975  {
976  assert(SCIPvarIsBinary(consdata->vars[v]));
977 
978  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
979  integralsum += consdata->weights[v];
980  }
981  }
982 
983  /* calculate constraint violation and update it in solution */
984  absviol = ishuge ? sum : (SCIP_Real)integralsum;
985  absviol -= consdata->capacity;
986  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
987  if( sol != NULL )
988  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
989 
990  if( SCIPisFeasPositive(scip, absviol) )
991  {
992  *violated = TRUE;
993 
994  /* only reset constraint age if we are in enforcement */
995  if( sol == NULL )
996  {
997  SCIP_CALL( SCIPresetConsAge(scip, cons) );
998  }
999 
1000  if( printreason )
1001  {
1002  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1003 
1004  SCIPinfoMessage(scip, NULL, ";\n");
1005  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1006  }
1007  }
1008  }
1009 
1010  return SCIP_OKAY;
1011 }
1012 
1013 /* IDX computes the integer index for the optimal solution array */
1014 #define IDX(j,d) ((j)*(intcap)+(d))
1015 
1016 /** solves knapsack problem in maximization form exactly using dynamic programming;
1017  * if needed, one can provide arrays to store all selected items and all not selected items
1018  *
1019  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1020  *
1021  * @note the algorithm will first compute a greedy solution and terminate
1022  * if the greedy solution is proven to be optimal.
1023  * The dynamic programming algorithm runs with a time and space complexity
1024  * of O(nitems * capacity).
1025  *
1026  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1027  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1028  * to be checked whether they are faster and whether they can reconstruct the solution.
1029  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1030  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1031  * This could be implemented, however, it would be technically a bit cumbersome,
1032  * since one needs the greedy solution and the LP-value for this.
1033  * This is currently only available after the redundant items have already been sorted out.
1034  */
1036  SCIP* scip, /**< SCIP data structure */
1037  int nitems, /**< number of available items */
1038  SCIP_Longint* weights, /**< item weights */
1039  SCIP_Real* profits, /**< item profits */
1040  SCIP_Longint capacity, /**< capacity of knapsack */
1041  int* items, /**< item numbers */
1042  int* solitems, /**< array to store items in solution, or NULL */
1043  int* nonsolitems, /**< array to store items not in solution, or NULL */
1044  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1045  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1046  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1047  SCIP_Bool* success /**< pointer to store if an error occured during solving
1048  * (normally a memory problem) */
1049  )
1050 {
1051  SCIP_RETCODE retcode;
1052  SCIP_Real* tempsort;
1053  SCIP_Real* optvalues;
1054  int intcap;
1055  int d;
1056  int j;
1057  int greedymedianpos;
1058  SCIP_Longint weightsum;
1059  int* myitems;
1060  SCIP_Longint* myweights;
1061  SCIP_Real* realweights;
1062  int* allcurrminweight;
1063  SCIP_Real* myprofits;
1064  int nmyitems;
1065  SCIP_Longint gcd;
1066  SCIP_Longint minweight;
1067  SCIP_Longint maxweight;
1068  int currminweight;
1069  SCIP_Longint greedysolweight;
1070  SCIP_Real greedysolvalue;
1071  SCIP_Real greedyupperbound;
1072  SCIP_Bool eqweights;
1073  SCIP_Bool intprofits;
1074 
1075  assert(weights != NULL);
1076  assert(profits != NULL);
1077  assert(capacity >= 0);
1078  assert(items != NULL);
1079  assert(nitems >= 0);
1080  assert(success != NULL);
1081 
1082  *success = TRUE;
1083 
1084 #ifndef NDEBUG
1085  for( j = nitems - 1; j >= 0; --j )
1086  assert(weights[j] >= 0);
1087 #endif
1088 
1089  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1090 
1091  /* initializing solution value */
1092  if( solval != NULL )
1093  *solval = 0.0;
1094 
1095  /* init solution information */
1096  if( solitems != NULL )
1097  {
1098  assert(items != NULL);
1099  assert(nsolitems != NULL);
1100  assert(nonsolitems != NULL);
1101  assert(nnonsolitems != NULL);
1102 
1103  *nnonsolitems = 0;
1104  *nsolitems = 0;
1105  }
1106 
1107  /* allocate temporary memory */
1108  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1109  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1110  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1111  nmyitems = 0;
1112  weightsum = 0;
1113  minweight = SCIP_LONGINT_MAX;
1114  maxweight = 0;
1115 
1116  /* remove unnecessary items */
1117  for( j = 0; j < nitems; ++j )
1118  {
1119  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1120 
1121  /* item does not fit */
1122  if( weights[j] > capacity )
1123  {
1124  if( solitems != NULL )
1125  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1126  }
1127  /* item is not profitable */
1128  else if( profits[j] <= 0.0 )
1129  {
1130  if( solitems != NULL )
1131  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1132  }
1133  /* item always fits */
1134  else if( weights[j] == 0 )
1135  {
1136  if( solitems != NULL )
1137  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1138 
1139  if( solval != NULL )
1140  *solval += profits[j];
1141  }
1142  /* all important items */
1143  else
1144  {
1145  myweights[nmyitems] = weights[j];
1146  myprofits[nmyitems] = profits[j];
1147  myitems[nmyitems] = items[j];
1148 
1149  /* remember smallest item */
1150  if( myweights[nmyitems] < minweight )
1151  minweight = myweights[nmyitems];
1152 
1153  /* remember bigest item */
1154  if( myweights[nmyitems] > maxweight )
1155  maxweight = myweights[nmyitems];
1156 
1157  weightsum += myweights[nmyitems];
1158  ++nmyitems;
1159  }
1160  }
1161 
1162  intprofits = TRUE;
1163  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1164  for( j = 0; j < nmyitems && intprofits; ++j )
1165  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1166 
1167  /* if no item is left then goto end */
1168  if( nmyitems == 0 )
1169  {
1170  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1171 
1172  goto TERMINATE;
1173  }
1174 
1175  /* if all items fit, we also do not need to do the expensive stuff later on */
1176  if( weightsum > 0 && weightsum <= capacity )
1177  {
1178  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1179 
1180  for( j = nmyitems - 1; j >= 0; --j )
1181  {
1182  if( solitems != NULL )
1183  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1184 
1185  if( solval != NULL )
1186  *solval += myprofits[j];
1187  }
1188 
1189  goto TERMINATE;
1190  }
1191 
1192  assert(0 < minweight && minweight <= capacity );
1193  assert(0 < maxweight && maxweight <= capacity);
1194 
1195  /* make weights relatively prime */
1196  eqweights = TRUE;
1197  if( maxweight > 1 )
1198  {
1199  /* determine greatest common divisor */
1200  gcd = myweights[nmyitems - 1];
1201  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1202  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1203 
1204  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1205 
1206  /* divide by greatest common divisor */
1207  if( gcd > 1 )
1208  {
1209  for( j = nmyitems - 1; j >= 0; --j )
1210  {
1211  myweights[j] /= gcd;
1212  eqweights = eqweights && (myweights[j] == 1);
1213  }
1214  capacity /= gcd;
1215  minweight /= gcd;
1216  }
1217  else
1218  eqweights = FALSE;
1219  }
1220  assert(minweight <= capacity);
1221 
1222  /* if only one item fits, then take the best */
1223  if( minweight > capacity / 2 )
1224  {
1225  int p;
1226 
1227  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1228 
1229  p = nmyitems - 1;
1230 
1231  /* find best item */
1232  for( j = nmyitems - 2; j >= 0; --j )
1233  {
1234  if( myprofits[j] > myprofits[p] )
1235  p = j;
1236  }
1237 
1238  /* update solution information */
1239  if( solitems != NULL )
1240  {
1241  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1242 
1243  solitems[(*nsolitems)++] = myitems[p];
1244  for( j = nmyitems - 1; j >= 0; --j )
1245  {
1246  if( j != p )
1247  nonsolitems[(*nnonsolitems)++] = myitems[j];
1248  }
1249  }
1250  /* update solution value */
1251  if( solval != NULL )
1252  *solval += myprofits[p];
1253 
1254  goto TERMINATE;
1255  }
1256 
1257  /* if all items have the same weight, then take the best */
1258  if( eqweights )
1259  {
1260  SCIP_Real addval = 0.0;
1261 
1262  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1263 
1264  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1265 
1266  /* update solution information */
1267  if( solitems != NULL || solval != NULL )
1268  {
1269  SCIP_Longint i;
1270 
1271  /* if all items would fit we had handled this case before */
1272  assert((SCIP_Longint) nmyitems > capacity);
1273  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1274 
1275  /* take the first best items into the solution */
1276  for( i = capacity - 1; i >= 0; --i )
1277  {
1278  if( solitems != NULL )
1279  solitems[(*nsolitems)++] = myitems[i];
1280  addval += myprofits[i];
1281  }
1282 
1283  if( solitems != NULL )
1284  {
1285  /* the rest are not in the solution */
1286  for( i = nmyitems - 1; i >= capacity; --i )
1287  nonsolitems[(*nnonsolitems)++] = myitems[i];
1288  }
1289  }
1290  /* update solution value */
1291  if( solval != NULL )
1292  {
1293  assert(addval > 0.0);
1294  *solval += addval;
1295  }
1296 
1297  goto TERMINATE;
1298  }
1299 
1300  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1301 
1302  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1303  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1304  */
1305  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1306  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1307 
1308  for( j = 0; j < nmyitems; ++j )
1309  {
1310  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1311  realweights[j] = (SCIP_Real)myweights[j];
1312  }
1313 
1314  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1315  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1316 
1317  SCIPfreeBufferArray(scip, &realweights);
1318  SCIPfreeBufferArray(scip, &tempsort);
1319 
1320  /* initialize values for greedy solution information */
1321  greedysolweight = 0;
1322  greedysolvalue = 0.0;
1323 
1324  /* determine greedy solution */
1325  for( j = 0; j < greedymedianpos; ++j )
1326  {
1327  assert(myweights[j] <= capacity);
1328 
1329  /* update greedy solution weight and value */
1330  greedysolweight += myweights[j];
1331  greedysolvalue += myprofits[j];
1332  }
1333 
1334  assert(0 < greedysolweight && greedysolweight <= capacity);
1335  assert(greedysolvalue > 0.0);
1336 
1337  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1338  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1339  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1340  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1341  if( intprofits )
1342  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1343  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1344  {
1345  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1346 
1347  /* update solution information */
1348  if( solitems != NULL )
1349  {
1350  int l;
1351 
1352  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1353 
1354  /* collect items */
1355  for( l = 0; l < j; ++l )
1356  solitems[(*nsolitems)++] = myitems[l];
1357  for ( ; l < nmyitems; ++l )
1358  nonsolitems[(*nnonsolitems)++] = myitems[l];
1359  }
1360  /* update solution value */
1361  if( solval != NULL )
1362  {
1363  assert(greedysolvalue > 0.0);
1364  *solval += greedysolvalue;
1365  }
1366 
1367  goto TERMINATE;
1368  }
1369 
1370  /* in the following table we do not need the first minweight columns */
1371  capacity -= (minweight - 1);
1372 
1373  /* we can only handle integers */
1374  if( capacity >= INT_MAX )
1375  {
1376  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1377 
1378  *success = FALSE;
1379  goto TERMINATE;
1380  }
1381  assert(capacity < INT_MAX);
1382 
1383  intcap = (int)capacity;
1384  assert(intcap >= 0);
1385  assert(nmyitems > 0);
1386  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1387 
1388  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1389  * computing the size for the allocation
1390  */
1391  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*/
1392  {
1393  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1394 
1395  *success = FALSE;
1396  goto TERMINATE;
1397  }
1398 
1399  /* allocate temporary memory and check for memory exceedance */
1400  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1401  if( retcode == SCIP_NOMEMORY )
1402  {
1403  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1404 
1405  *success = FALSE;
1406  goto TERMINATE;
1407  }
1408  else
1409  {
1410  SCIP_CALL( retcode );
1411  }
1412 
1413  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1414 
1415  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1416  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1417  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1418  * 'nmyitem' values
1419  */
1420  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1421  assert(myweights[0] - minweight < INT_MAX);
1422  currminweight = (int) (myweights[0] - minweight);
1423  allcurrminweight[0] = currminweight;
1424 
1425  /* fills first row of dynamic programming table with optimal values */
1426  for( d = currminweight; d < intcap; ++d )
1427  optvalues[d] = myprofits[0];
1428 
1429  /* fills dynamic programming table with optimal values */
1430  for( j = 1; j < nmyitems; ++j )
1431  {
1432  int intweight;
1433 
1434  /* compute important part of weight, which will be represented in the table */
1435  intweight = (int)(myweights[j] - minweight);
1436  assert(0 <= intweight && intweight < intcap);
1437 
1438  /* copy all nonzeros from row above */
1439  for( d = currminweight; d < intweight && d < intcap; ++d )
1440  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1441 
1442  /* update corresponding row */
1443  for( d = intweight; d < intcap; ++d )
1444  {
1445  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1446  if( d < currminweight )
1447  optvalues[IDX(j,d)] = myprofits[j];
1448  else
1449  {
1450  SCIP_Real sumprofit;
1451 
1452  if( d - myweights[j] < currminweight )
1453  sumprofit = myprofits[j];
1454  else
1455  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1456 
1457  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1458  }
1459  }
1460 
1461  /* update currminweight */
1462  if( intweight < currminweight )
1463  currminweight = intweight;
1464 
1465  allcurrminweight[j] = currminweight;
1466  }
1467 
1468  /* update optimal solution by following the table */
1469  if( solitems != NULL )
1470  {
1471  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1472  d = intcap - 1;
1473 
1474  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1475 
1476  /* insert all items in (non-) solution vector */
1477  for( j = nmyitems - 1; j > 0; --j )
1478  {
1479  /* if the following condition holds this means all remaining items does not fit anymore */
1480  if( d < allcurrminweight[j] )
1481  {
1482  /* we cannot have exceeded our capacity */
1483  assert((SCIP_Longint) d >= -minweight);
1484  break;
1485  }
1486 
1487  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1488  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1489  {
1490  solitems[(*nsolitems)++] = myitems[j];
1491 
1492  /* check that we do not have an underflow */
1493  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1494  d = (int)(d - myweights[j]);
1495  }
1496  /* collect non-solution items */
1497  else
1498  nonsolitems[(*nnonsolitems)++] = myitems[j];
1499  }
1500 
1501  /* insert remaining items */
1502  if( d >= allcurrminweight[j] )
1503  {
1504  assert(j == 0);
1505  solitems[(*nsolitems)++] = myitems[j];
1506  }
1507  else
1508  {
1509  assert(j >= 0);
1510  assert(d < allcurrminweight[j]);
1511 
1512  for( ; j >= 0; --j )
1513  nonsolitems[(*nnonsolitems)++] = myitems[j];
1514  }
1515 
1516  assert(*nsolitems + *nnonsolitems == nitems);
1517  }
1518 
1519  /* update solution value */
1520  if( solval != NULL )
1521  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1522  SCIPfreeBufferArray(scip, &allcurrminweight);
1523 
1524  /* free all temporary memory */
1525  SCIPfreeBufferArray(scip, &optvalues);
1526 
1527  TERMINATE:
1528  SCIPfreeBufferArray(scip, &myitems);
1529  SCIPfreeBufferArray(scip, &myprofits);
1530  SCIPfreeBufferArray(scip, &myweights);
1531 
1532  return SCIP_OKAY;
1533 }
1534 
1535 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1536  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1537  * selected items
1538  */
1540  SCIP* scip, /**< SCIP data structure */
1541  int nitems, /**< number of available items */
1542  SCIP_Longint* weights, /**< item weights */
1543  SCIP_Real* profits, /**< item profits */
1544  SCIP_Longint capacity, /**< capacity of knapsack */
1545  int* items, /**< item numbers */
1546  int* solitems, /**< array to store items in solution, or NULL */
1547  int* nonsolitems, /**< array to store items not in solution, or NULL */
1548  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1549  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1550  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1551  )
1552 {
1553  SCIP_Real* tempsort;
1554  SCIP_Longint solitemsweight;
1555  SCIP_Real* realweights;
1556  int j;
1557  int criticalindex;
1558 
1559  assert(weights != NULL);
1560  assert(profits != NULL);
1561  assert(capacity >= 0);
1562  assert(items != NULL);
1563  assert(nitems >= 0);
1564 
1565  if( solitems != NULL )
1566  {
1567  *nsolitems = 0;
1568  *nnonsolitems = 0;
1569  }
1570  if( solval != NULL )
1571  *solval = 0.0;
1572 
1573  /* initialize data for median search */
1574  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1575  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1576  for( j = nitems - 1; j >= 0; --j )
1577  {
1578  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1579  realweights[j] = (SCIP_Real)weights[j];
1580  }
1581 
1582  /* partially sort indices such that all elements that are larger than the break item appear first */
1583  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1584 
1585  /* selects items as long as they fit into the knapsack */
1586  solitemsweight = 0;
1587  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1588  {
1589  if( solitems != NULL )
1590  solitems[(*nsolitems)++] = items[j];
1591 
1592  if( solval != NULL )
1593  (*solval) += profits[j];
1594  solitemsweight += weights[j];
1595  }
1596  if ( solitems != NULL )
1597  {
1598  for( ; j < nitems; j++ )
1599  nonsolitems[(*nnonsolitems)++] = items[j];
1600  }
1601 
1602  SCIPfreeBufferArray(scip, &realweights);
1603  SCIPfreeBufferArray(scip, &tempsort);
1604 
1605  return SCIP_OKAY;
1606 }
1607 
1608 #ifdef SCIP_DEBUG
1609 /** prints all nontrivial GUB constraints and their LP solution values */
1610 static
1611 void GUBsetPrint(
1612  SCIP* scip, /**< SCIP data structure */
1613  SCIP_GUBSET* gubset, /**< GUB set data structure */
1614  SCIP_VAR** vars, /**< variables in knapsack constraint */
1615  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1616  )
1617 {
1618  int nnontrivialgubconss;
1619  int c;
1620 
1621  nnontrivialgubconss = 0;
1622 
1623  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1624 
1625  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1626  for( c = 0; c < gubset->ngubconss; c++ )
1627  {
1628  SCIP_Real gubsolval;
1629 
1630  assert(gubset->gubconss[c]->ngubvars >= 0);
1631 
1632  /* nontrivial GUB */
1633  if( gubset->gubconss[c]->ngubvars > 1 )
1634  {
1635  int v;
1636 
1637  gubsolval = 0.0;
1638  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1639 
1640  /* print GUB var */
1641  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1642  {
1643  int currentvar;
1644 
1645  currentvar = gubset->gubconss[c]->gubvars[v];
1646  if( solvals != NULL )
1647  {
1648  gubsolval += solvals[currentvar];
1649  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1650  }
1651  else
1652  {
1653  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1654  }
1655  }
1656 
1657  /* check whether LP solution satisfies the GUB constraint */
1658  if( solvals != NULL )
1659  {
1660  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1661  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1662  }
1663  else
1664  {
1665  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1666  }
1667  nnontrivialgubconss++;
1668  }
1669  }
1670 
1671  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1672 }
1673 #endif
1674 
1675 /** creates an empty GUB constraint */
1676 static
1678  SCIP* scip, /**< SCIP data structure */
1679  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1680  )
1681 {
1682  assert(scip != NULL);
1683  assert(gubcons != NULL);
1684 
1685  /* allocate memory for GUB constraint data structures */
1686  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1687  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1688  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1689  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1690 
1691  (*gubcons)->ngubvars = 0;
1692 
1693  return SCIP_OKAY;
1694 }
1695 
1696 /** frees GUB constraint */
1697 static
1698 void GUBconsFree(
1699  SCIP* scip, /**< SCIP data structure */
1700  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1701  )
1702 {
1703  assert(scip != NULL);
1704  assert(gubcons != NULL);
1705  assert((*gubcons)->gubvars != NULL);
1706  assert((*gubcons)->gubvarsstatus != NULL);
1707 
1708  /* free allocated memory */
1709  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1710  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1711  SCIPfreeBuffer(scip, gubcons);
1712 }
1713 
1714 /** adds variable to given GUB constraint */
1715 static
1717  SCIP* scip, /**< SCIP data structure */
1718  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1719  int var /**< index of given variable in knapsack constraint */
1720  )
1721 {
1722  assert(scip != NULL);
1723  assert(gubcons != NULL);
1724  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1725  assert(gubcons->gubvars != NULL);
1726  assert(gubcons->gubvarsstatus != NULL);
1727  assert(var >= 0);
1728 
1729  /* add variable to GUB constraint */
1730  gubcons->gubvars[gubcons->ngubvars] = var;
1731  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1732  gubcons->ngubvars++;
1733 
1734  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1735  if( gubcons->ngubvars == gubcons->gubvarssize )
1736  {
1737  int newlen;
1738 
1739  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1740  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1741  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1742 
1743  gubcons->gubvarssize = newlen;
1744  }
1745 
1746  return SCIP_OKAY;
1747 }
1748 
1749 /** deletes variable from its current GUB constraint */
1750 static
1752  SCIP* scip, /**< SCIP data structure */
1753  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1754  int var, /**< index of given variable in knapsack constraint */
1755  int gubvarsidx /**< index of the variable in its current GUB constraint */
1756  )
1757 {
1758  assert(scip != NULL);
1759  assert(gubcons != NULL);
1760  assert(var >= 0);
1761  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1762  assert(gubcons->ngubvars >= gubvarsidx+1);
1763  assert(gubcons->gubvars[gubvarsidx] == var);
1764 
1765  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1766  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1767  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1768  gubcons->ngubvars--;
1769 
1770  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1771  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1772  {
1773  int newlen;
1774 
1775  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1776 
1777  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1778  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1779 
1780  gubcons->gubvarssize = newlen;
1781  }
1782 
1783  return SCIP_OKAY;
1784 }
1785 
1786 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1787 static
1789  SCIP* scip, /**< SCIP data structure */
1790  SCIP_GUBSET* gubset, /**< GUB set data structure */
1791  SCIP_VAR** vars, /**< variables in knapsack constraint */
1792  int var, /**< index of given variable in knapsack constraint */
1793  int oldgubcons, /**< index of old GUB constraint of given variable */
1794  int newgubcons /**< index of new GUB constraint of given variable */
1795  )
1797  int oldgubvaridx;
1798  int replacevar;
1799  int j;
1800 
1801  assert(scip != NULL);
1802  assert(gubset != NULL);
1803  assert(var >= 0);
1804  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1805  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1806  assert(oldgubcons != newgubcons);
1807  assert(gubset->gubconssidx[var] == oldgubcons);
1808  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1809  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1810 
1811  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1812 
1813  oldgubvaridx = gubset->gubvarsidx[var];
1814 
1815  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1816  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1817 
1818  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1819  * replacement variable is given by old position of the deleted variable
1820  */
1821  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1822  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1823  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1824 
1825  /* add variable to the end of new GUB constraint */
1826  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1827  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1828 
1829  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1830  gubset->gubconssidx[var] = newgubcons;
1831  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1832 
1833  /* delete old GUB constraint if it became empty */
1834  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1835  {
1836  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1837 #ifdef SCIP_DEBUG
1838  GUBsetPrint(scip, gubset, vars, NULL);
1839 #endif
1840 
1841  /* free old GUB constraint */
1842  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1843 
1844  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1845  if( oldgubcons != gubset->ngubconss-1 )
1846  {
1847  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1848  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1849 
1850  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1851  * replacement GUB is given by old position of the deleted GUB
1852  */
1853  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1854  {
1855  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1856  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1857  }
1858  }
1859 
1860  /* update number of GUB constraints */
1861  gubset->ngubconss--;
1862 
1863  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1864  * (because it was at the end of the GUB constraint array)
1865  */
1866  assert(gubset->gubconssidx[var] == newgubcons
1867  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1868  }
1869 #ifndef NDEBUG
1870  else
1871  assert(gubset->gubconssidx[var] == newgubcons);
1872 #endif
1873 
1874  return SCIP_OKAY;
1875 }
1876 
1877 /** swaps two variables in the same GUB constraint */
1878 static
1879 void GUBsetSwapVars(
1880  SCIP* scip, /**< SCIP data structure */
1881  SCIP_GUBSET* gubset, /**< GUB set data structure */
1882  int var1, /**< first variable to be swapped */
1883  int var2 /**< second variable to be swapped */
1884  )
1885 {
1886  int gubcons;
1887  int var1idx;
1888  GUBVARSTATUS var1status;
1889  int var2idx;
1890  GUBVARSTATUS var2status;
1891 
1892  assert(scip != NULL);
1893  assert(gubset != NULL);
1894 
1895  gubcons = gubset->gubconssidx[var1];
1896  assert(gubcons == gubset->gubconssidx[var2]);
1897 
1898  /* nothing to be done if both variables are the same */
1899  if( var1 == var2 )
1900  return;
1901 
1902  /* swap index and status of variables in GUB constraint */
1903  var1idx = gubset->gubvarsidx[var1];
1904  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1905  var2idx = gubset->gubvarsidx[var2];
1906  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1907 
1908  gubset->gubvarsidx[var1] = var2idx;
1909  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1910  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1911 
1912  gubset->gubvarsidx[var2] = var1idx;
1913  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1914  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1915 }
1916 
1917 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1918 static
1920  SCIP* scip, /**< SCIP data structure */
1921  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1922  int nvars, /**< number of variables in the knapsack constraint */
1923  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1924  SCIP_Longint capacity /**< capacity of knapsack */
1925  )
1926 {
1927  int i;
1928 
1929  assert(scip != NULL);
1930  assert(gubset != NULL);
1931  assert(nvars > 0);
1932  assert(weights != NULL);
1933  assert(capacity >= 0);
1934 
1935  /* allocate memory for GUB set data structures */
1936  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1937  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1938  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1939  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1940  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1941  (*gubset)->ngubconss = nvars;
1942  (*gubset)->nvars = nvars;
1943 
1944  /* initialize the set of GUB constraints */
1945  for( i = 0; i < nvars; i++ )
1946  {
1947  /* assign each variable to a new (trivial) GUB constraint */
1948  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1949  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1950 
1951  /* set status of GUB constraint to initial */
1952  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1953 
1954  (*gubset)->gubconssidx[i] = i;
1955  (*gubset)->gubvarsidx[i] = 0;
1956  assert((*gubset)->gubconss[i]->ngubvars == 1);
1957 
1958  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1959  if( weights[i] > capacity )
1960  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1961  }
1962 
1963  return SCIP_OKAY;
1964 }
1965 
1966 /** frees GUB set data structure */
1967 static
1968 void GUBsetFree(
1969  SCIP* scip, /**< SCIP data structure */
1970  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1971  )
1972 {
1973  int i;
1974 
1975  assert(scip != NULL);
1976  assert(gubset != NULL);
1977  assert((*gubset)->gubconss != NULL);
1978  assert((*gubset)->gubconsstatus != NULL);
1979  assert((*gubset)->gubconssidx != NULL);
1980  assert((*gubset)->gubvarsidx != NULL);
1981 
1982  /* free all GUB constraints */
1983  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1984  {
1985  assert((*gubset)->gubconss[i] != NULL);
1986  GUBconsFree(scip, &(*gubset)->gubconss[i]);
1987  }
1988 
1989  /* free allocated memory */
1990  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1991  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1992  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1993  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
1994  SCIPfreeBuffer(scip, gubset);
1995 }
1996 
1997 #ifndef NDEBUG
1998 /** checks whether GUB set data structure is consistent */
1999 static
2001  SCIP* scip, /**< SCIP data structure */
2002  SCIP_GUBSET* gubset, /**< GUB set data structure */
2003  SCIP_VAR** vars /**< variables in the knapsack constraint */
2004  )
2005 {
2006  int i;
2007  int gubconsidx;
2008  int gubvaridx;
2009  SCIP_VAR* var1;
2010  SCIP_VAR* var2;
2011  SCIP_Bool var1negated;
2012  SCIP_Bool var2negated;
2013 
2014  assert(scip != NULL);
2015  assert(gubset != NULL);
2016 
2017  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2018 
2019  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2020  for( i = 0; i < gubset->nvars; i++ )
2021  {
2022  gubconsidx = gubset->gubconssidx[i];
2023  gubvaridx = gubset->gubvarsidx[i];
2024 
2025  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2026  {
2027  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2028  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2029  }
2030  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2031  }
2032 
2033  /* checks for each GUB whether all pairs of its variables have a common clique */
2034  for( i = 0; i < gubset->ngubconss; i++ )
2035  {
2036  int j;
2037 
2038  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2039  {
2040  int k;
2041 
2042  /* get corresponding active problem variable */
2043  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2044  var1negated = FALSE;
2045  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2046 
2047  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2048  {
2049  /* get corresponding active problem variable */
2050  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2051  var2negated = FALSE;
2052  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2053 
2054  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2055  {
2056  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2057  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2058  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2059  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2060  SCIPvarGetName(var1), k,
2061  SCIPvarGetName(var2));
2062  }
2063 
2064  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2065  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2066  }
2067  }
2068  }
2069  SCIPdebugMsg(scip, " --> successful\n");
2070 
2071  return SCIP_OKAY;
2072 }
2073 #endif
2074 
2075 /** calculates a partition of the given set of binary variables into cliques;
2076  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2077  * were assigned to the same clique;
2078  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2079  * the preceding variables was assigned to clique i-1;
2080  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2081  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2082  */
2083 
2084 static
2086  SCIP*const scip, /**< SCIP data structure */
2087  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2088  int const nvars, /**< number of variables in the clique */
2089  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2090  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2091  SCIP_Real* solvals /**< solution values of all given binary variables */
2092  )
2094  SCIP_VAR** tmpvars;
2095  SCIP_VAR** cliquevars;
2096  SCIP_Bool* cliquevalues;
2097  SCIP_Bool* tmpvalues;
2098  int* varseq;
2099  int* sortkeys;
2100  int ncliquevars;
2101  int maxncliquevarscomp;
2102  int nignorevars;
2103  int nvarsused;
2104  int i;
2105 
2106  assert(scip != NULL);
2107  assert(nvars == 0 || vars != NULL);
2108  assert(nvars == 0 || cliquepartition != NULL);
2109  assert(ncliques != NULL);
2110 
2111  if( nvars == 0 )
2112  {
2113  *ncliques = 0;
2114  return SCIP_OKAY;
2115  }
2116 
2117  /* allocate temporary memory for storing the variables of the current clique */
2118  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2119  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2120  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2121  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2122  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2123  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2124 
2125  /* initialize the cliquepartition array with -1 */
2126  /* initialize the tmpvalues array */
2127  for( i = nvars - 1; i >= 0; --i )
2128  {
2129  tmpvalues[i] = TRUE;
2130  cliquepartition[i] = -1;
2131  }
2132 
2133  /* get corresponding active problem variables */
2134  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2135 
2136  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2137  * by nondecreasing number of cliques the variables are in
2138  */
2139  nignorevars = 0;
2140  nvarsused = 0;
2141  for( i = 0; i < nvars; i++ )
2142  {
2143  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2144  {
2145  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2146  varseq[nvars-1-nignorevars] = i;
2147  nignorevars++;
2148  }
2149  else
2150  {
2151  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2152  varseq[nvarsused] = i;
2153  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2154  nvarsused++;
2155  }
2156  }
2157  assert(nvarsused + nignorevars == nvars);
2158 
2159  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2160  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2161 
2162  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2163 
2164  /* calculate the clique partition */
2165  *ncliques = 0;
2166  for( i = 0; i < nvars; ++i )
2167  {
2168  if( cliquepartition[varseq[i]] == -1 )
2169  {
2170  int j;
2171 
2172  /* variable starts a new clique */
2173  cliquepartition[varseq[i]] = *ncliques;
2174  cliquevars[0] = tmpvars[varseq[i]];
2175  cliquevalues[0] = tmpvalues[varseq[i]];
2176  ncliquevars = 1;
2177 
2178  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2179  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2180  */
2181  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2182  {
2183  /* greedily fill up the clique */
2184  for( j = i + 1; j < nvarsused; ++j )
2185  {
2186  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2187  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2188  {
2189  int k;
2190 
2191  /* check if every variable in the actual clique is in clique with the new variable */
2192  for( k = ncliquevars - 1; k >= 0; --k )
2193  {
2194  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2195  cliquevalues[k], TRUE) )
2196  break;
2197  }
2198 
2199  if( k == -1 )
2200  {
2201  /* put the variable into the same clique */
2202  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2203  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2204  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2205  ++ncliquevars;
2206  }
2207  }
2208  }
2209  }
2210 
2211  /* this clique is finished */
2212  ++(*ncliques);
2213  }
2214  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2215 
2216  /* break if we reached the maximal number of comparisons */
2217  if( i * nvars > maxncliquevarscomp )
2218  break;
2219  }
2220  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2221  for( ; i < nvars; ++i )
2222  {
2223  if( cliquepartition[varseq[i]] == -1 )
2224  {
2225  cliquepartition[varseq[i]] = *ncliques;
2226  ++(*ncliques);
2227  }
2228  }
2229 
2230  /* free temporary memory */
2231  SCIPfreeBufferArray(scip, &sortkeys);
2232  SCIPfreeBufferArray(scip, &varseq);
2233  SCIPfreeBufferArray(scip, &tmpvars);
2234  SCIPfreeBufferArray(scip, &tmpvalues);
2235  SCIPfreeBufferArray(scip, &cliquevalues);
2236  SCIPfreeBufferArray(scip, &cliquevars);
2237 
2238  return SCIP_OKAY;
2239 }
2240 
2241 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2242 static
2244  SCIP* scip, /**< SCIP data structure */
2245  SCIP_GUBSET* gubset, /**< GUB set data structure */
2246  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2247  SCIP_Real* solvals /**< solution values of all knapsack variables */
2248  )
2249 {
2250  int* cliquepartition;
2251  int* gubfirstvar;
2252  int ncliques;
2253  int currentgubconsidx;
2254  int newgubconsidx;
2255  int cliqueidx;
2256  int nvars;
2257  int i;
2258 
2259  assert(scip != NULL);
2260  assert(gubset != NULL);
2261  assert(vars != NULL);
2262 
2263  nvars = gubset->nvars;
2264  assert(nvars >= 0);
2265 
2266  /* allocate temporary memory for clique partition */
2267  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2268 
2269  /* compute sophisticated clique partition */
2270  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2271 
2272  /* allocate temporary memory for GUB set data structure */
2273  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2274 
2275  /* translate GUB partition into GUB set data structure */
2276  for( i = 0; i < ncliques; i++ )
2277  {
2278  /* initialize first variable for every GUB */
2279  gubfirstvar[i] = -1;
2280  }
2281  /* move every knapsack variable into GUB defined by clique partition */
2282  for( i = 0; i < nvars; i++ )
2283  {
2284  assert(cliquepartition[i] >= 0);
2285 
2286  cliqueidx = cliquepartition[i];
2287  currentgubconsidx = gubset->gubconssidx[i];
2288  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2289 
2290  /* variable is first element in GUB constraint defined by clique partition */
2291  if( gubfirstvar[cliqueidx] == -1 )
2292  {
2293  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2294  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2295  */
2296  assert(gubset->gubvarsidx[i] == 0);
2297  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2298 
2299  /* remember the first variable found for the current GUB */
2300  gubfirstvar[cliqueidx] = i;
2301  }
2302  /* variable is additional element of GUB constraint defined by clique partition */
2303  else
2304  {
2305  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2306 
2307  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2308  * first variable of this GUB constraint
2309  */
2310  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2311  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2312  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2313 
2314  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2315  }
2316  }
2317 
2318 #ifdef SCIP_DEBUG
2319  /* prints GUB set data structure */
2320  GUBsetPrint(scip, gubset, vars, solvals);
2321 #endif
2322 
2323 #ifndef NDEBUG
2324  /* checks consistency of GUB set data structure */
2325  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2326 #endif
2327 
2328  /* free temporary memory */
2329  SCIPfreeBufferArray(scip, &gubfirstvar);
2330  SCIPfreeBufferArray(scip, &cliquepartition);
2331 
2332  return SCIP_OKAY;
2333 }
2334 
2335 /** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
2336  * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
2337  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2338  */
2339 static
2341  SCIP* scip, /**< SCIP data structure */
2342  SCIP_VAR** vars, /**< variables in knapsack constraint */
2343  int nvars, /**< number of variables in knapsack constraint */
2344  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2345  SCIP_Longint capacity, /**< capacity of knapsack */
2346  SCIP_Real* solvals, /**< solution values of all problem variables */
2347  int* covervars, /**< pointer to store cover variables */
2348  int* noncovervars, /**< pointer to store noncover variables */
2349  int* ncovervars, /**< pointer to store number of cover variables */
2350  int* nnoncovervars, /**< pointer to store number of noncover variables */
2351  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2352  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2353  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2354  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2355  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2356  )
2357 {
2358  SCIP_Longint* transweights;
2359  SCIP_Real* transprofits;
2360  SCIP_Longint transcapacity;
2361  SCIP_Longint fixedonesweight;
2362  SCIP_Longint itemsweight;
2363  SCIP_Bool infeasible;
2364  int* fixedones;
2365  int* fixedzeros;
2366  int* items;
2367  int nfixedones;
2368  int nfixedzeros;
2369  int nitems;
2370  int j;
2371 
2372  assert(scip != NULL);
2373  assert(vars != NULL);
2374  assert(nvars > 0);
2375  assert(weights != NULL);
2376  assert(capacity >= 0);
2377  assert(solvals != NULL);
2378  assert(covervars != NULL);
2379  assert(noncovervars != NULL);
2380  assert(ncovervars != NULL);
2381  assert(nnoncovervars != NULL);
2382  assert(coverweight != NULL);
2383  assert(found != NULL);
2384  assert(ntightened != NULL);
2385  assert(fractional != NULL);
2386 
2387  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2388 
2389  /* allocates temporary memory */
2390  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2391  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2392  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2393  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2394  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2395 
2396  *found = FALSE;
2397  *ncovervars = 0;
2398  *nnoncovervars = 0;
2399  *coverweight = 0;
2400  *fractional = TRUE;
2401 
2402  /* gets the following sets
2403  * N_1 = {j in N : x*_j = 1} (fixedones),
2404  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2405  * N\(N_0 & N_1) (items),
2406  * where x*_j is the solution value of variable x_j
2407  */
2408  nfixedones = 0;
2409  nfixedzeros = 0;
2410  nitems = 0;
2411  fixedonesweight = 0;
2412  itemsweight = 0;
2413  *ntightened = 0;
2414  for( j = 0; j < nvars; j++ )
2415  {
2416  assert(SCIPvarIsBinary(vars[j]));
2417 
2418  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2419  if( weights[j] > capacity )
2420  {
2421  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2422  assert(!infeasible);
2423  (*ntightened)++;
2424  continue;
2425  }
2426 
2427  /* variable x_j has solution value one */
2428  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2429  {
2430  fixedones[nfixedones] = j;
2431  nfixedones++;
2432  fixedonesweight += weights[j];
2433  }
2434  /* variable x_j has solution value zero */
2435  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2436  {
2437  fixedzeros[nfixedzeros] = j;
2438  nfixedzeros++;
2439  }
2440  /* variable x_j has fractional solution value */
2441  else
2442  {
2443  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2444  items[nitems] = j;
2445  nitems++;
2446  itemsweight += weights[j];
2447  }
2448  }
2449  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2450 
2451  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2452  * the separation routine
2453  */
2454  assert(nitems >= 0);
2455  if( nitems == 0 )
2456  {
2457  *fractional = FALSE;
2458  goto TERMINATE;
2459  }
2460  assert(*fractional);
2461 
2462  /* transforms the traditional separation problem (under consideration of the following fixing:
2463  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2464  *
2465  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2466  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2467  * z_j in {0,1}, j in N\(N_0 & N_1)
2468  *
2469  * to a knapsack problem in maximization form by complementing the variables
2470  *
2471  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2472  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2473  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2474  * z_j in {0,1}, j in N\(N_0 & N_1)
2475  */
2476 
2477  /* gets weight and profit of variables in transformed knapsack problem */
2478  for( j = 0; j < nitems; j++ )
2479  {
2480  transweights[j] = weights[items[j]];
2481  transprofits[j] = 1.0 - solvals[items[j]];
2482  }
2483  /* gets capacity of transformed knapsack problem */
2484  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2485 
2486  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2487  * (when variables fixed to zero are not used)
2488  */
2489  if( transcapacity < 0 )
2490  {
2491  assert(!(*found));
2492  goto TERMINATE;
2493  }
2494 
2495  if( modtransused )
2496  {
2497  /* transforms the modified separation problem (under consideration of the following fixing:
2498  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2499  *
2500  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2501  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2502  * z_j in {0,1}, j in N\(N_0 & N_1)
2503  *
2504  * to a knapsack problem in maximization form by complementing the variables
2505  *
2506  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2507  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2508  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2509  * z_j in {0,1}, j in N\(N_0 & N_1)
2510  */
2511 
2512  /* gets weight and profit of variables in modified transformed knapsack problem */
2513  for( j = 0; j < nitems; j++ )
2514  {
2515  transprofits[j] *= weights[items[j]];
2516  assert(SCIPisFeasPositive(scip, transprofits[j]));
2517  }
2518  }
2519 
2520  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2521  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2522  * let z* be the solution, then
2523  * j in C, if z*_j = 0 and
2524  * i in N\C, if z*_j = 1.
2525  */
2526  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2527  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2528  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2529 
2530  /* constructs cover C (sum_{j in C} a_j > a_0) */
2531  for( j = 0; j < *ncovervars; j++ )
2532  {
2533  (*coverweight) += weights[covervars[j]];
2534  }
2535 
2536  /* adds all variables from N_1 to C */
2537  for( j = 0; j < nfixedones; j++ )
2538  {
2539  covervars[*ncovervars] = fixedones[j];
2540  (*ncovervars)++;
2541  (*coverweight) += weights[fixedones[j]];
2542  }
2543 
2544  /* adds all variables from N_0 to N\C */
2545  for( j = 0; j < nfixedzeros; j++ )
2546  {
2547  noncovervars[*nnoncovervars] = fixedzeros[j];
2548  (*nnoncovervars)++;
2549  }
2550  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2551  assert((*coverweight) > capacity);
2552  *found = TRUE;
2553 
2554  TERMINATE:
2555  /* frees temporary memory */
2556  SCIPfreeBufferArray(scip, &items);
2557  SCIPfreeBufferArray(scip, &fixedzeros);
2558  SCIPfreeBufferArray(scip, &fixedones);
2559  SCIPfreeBufferArray(scip, &transprofits);
2560  SCIPfreeBufferArray(scip, &transweights);
2561 
2562  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2563 
2564  return SCIP_OKAY;
2565 }
2566 
2567 #ifndef NDEBUG
2568 /** checks if minweightidx is set correctly
2569  */
2570 static
2572  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2573  SCIP_Longint capacity, /**< capacity of knapsack */
2574  int* covervars, /**< pointer to store cover variables */
2575  int ncovervars, /**< pointer to store number of cover variables */
2576  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2577  int minweightidx, /**< index of variable in cover variables with minimum weight */
2578  int j /**< current index in cover variables */
2579  )
2580 {
2581  SCIP_Longint minweight;
2582  int i;
2583 
2584  assert(weights != NULL);
2585  assert(covervars != NULL);
2586  assert(ncovervars > 0);
2587 
2588  minweight = weights[covervars[minweightidx]];
2589 
2590  /* checks if all cover variables before index j have weight greater than minweight */
2591  for( i = 0; i < j; i++ )
2592  {
2593  assert(weights[covervars[i]] > minweight);
2594  if( weights[covervars[i]] <= minweight )
2595  return FALSE;
2596  }
2597 
2598  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2599  for( i = 0; i < j; i++ )
2600  {
2601  assert(coverweight - weights[covervars[i]] <= capacity);
2602  if( coverweight - weights[covervars[i]] > capacity )
2603  return FALSE;
2604  }
2605  return TRUE;
2606 }
2607 #endif
2608 
2609 
2610 /** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
2611  * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
2612  */
2613 static
2615  SCIP* scip, /**< SCIP data structure */
2616  SCIP_Real* solvals, /**< solution values of all problem variables */
2617  int* covervars, /**< cover variables */
2618  int ncovervars, /**< number of cover variables */
2619  int* varsC1, /**< pointer to store variables in C1 */
2620  int* varsC2, /**< pointer to store variables in C2 */
2621  int* nvarsC1, /**< pointer to store number of variables in C1 */
2622  int* nvarsC2 /**< pointer to store number of variables in C2 */
2623  )
2624 {
2625  int j;
2626 
2627  assert(scip != NULL);
2628  assert(ncovervars >= 0);
2629  assert(solvals != NULL);
2630  assert(covervars != NULL);
2631  assert(varsC1 != NULL);
2632  assert(varsC2 != NULL);
2633  assert(nvarsC1 != NULL);
2634  assert(nvarsC2 != NULL);
2635 
2636  *nvarsC1 = 0;
2637  *nvarsC2 = 0;
2638  for( j = 0; j < ncovervars; j++ )
2639  {
2640  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2641 
2642  /* variable has solution value one */
2643  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2644  {
2645  varsC2[*nvarsC2] = covervars[j];
2646  (*nvarsC2)++;
2647  }
2648  /* variable has solution value less than one */
2649  else
2650  {
2651  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2652  varsC1[*nvarsC1] = covervars[j];
2653  (*nvarsC1)++;
2654  }
2655  }
2656  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2657 }
2658 
2659 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2660  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2661  */
2662 static
2664  SCIP* scip, /**< SCIP data structure */
2665  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2666  int* varsC1, /**< pointer to store variables in C1 */
2667  int* varsC2, /**< pointer to store variables in C2 */
2668  int* nvarsC1, /**< pointer to store number of variables in C1 */
2669  int* nvarsC2 /**< pointer to store number of variables in C2 */
2670  )
2672  SCIP_Real* sortkeysC2;
2673  int j;
2674 
2675  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2676  assert(*nvarsC2 > 0);
2677 
2678  /* allocates temporary memory */
2679  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2680 
2681  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2682  for( j = 0; j < *nvarsC2; j++ )
2683  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2684  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2685 
2686  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2687  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2688  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2689  {
2690  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2691  (*nvarsC1)++;
2692  (*nvarsC2)--;
2693  }
2694 
2695  /* frees temporary memory */
2696  SCIPfreeBufferArray(scip, &sortkeysC2);
2697 
2698  return SCIP_OKAY;
2699 }
2700 
2701 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2702 static
2704  SCIP* scip, /**< SCIP data structure */
2705  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2706  int* varsC1, /**< pointer to store variables in C1 */
2707  int* varsC2, /**< pointer to store variables in C2 */
2708  int* nvarsC1, /**< pointer to store number of variables in C1 */
2709  int* nvarsC2 /**< pointer to store number of variables in C2 */
2710  )
2712  SCIP_Real* sortkeysC2;
2713  int j;
2714 
2715  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2716  assert(*nvarsC2 > 0);
2717 
2718  /* allocates temporary memory */
2719  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2720 
2721  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2722  for( j = 0; j < *nvarsC2; j++ )
2723  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2724  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2725 
2726  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2727  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2728  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2729  (*nvarsC1)++;
2730  (*nvarsC2)--;
2731 
2732  /* frees temporary memory */
2733  SCIPfreeBufferArray(scip, &sortkeysC2);
2734 
2735  return SCIP_OKAY;
2736 }
2737 
2738 
2739 /** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
2740  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2741  * \f$F = (N \setminus C) \setminus F\f$
2742  */
2743 static
2745  SCIP* scip, /**< SCIP data structure */
2746  SCIP_Real* solvals, /**< solution values of all problem variables */
2747  int* noncovervars, /**< noncover variables */
2748  int nnoncovervars, /**< number of noncover variables */
2749  int* varsF, /**< pointer to store variables in F */
2750  int* varsR, /**< pointer to store variables in R */
2751  int* nvarsF, /**< pointer to store number of variables in F */
2752  int* nvarsR /**< pointer to store number of variables in R */
2753  )
2754 {
2755  int j;
2756 
2757  assert(scip != NULL);
2758  assert(nnoncovervars >= 0);
2759  assert(solvals != NULL);
2760  assert(noncovervars != NULL);
2761  assert(varsF != NULL);
2762  assert(varsR != NULL);
2763  assert(nvarsF != NULL);
2764  assert(nvarsR != NULL);
2765 
2766  *nvarsF = 0;
2767  *nvarsR = 0;
2768 
2769  for( j = 0; j < nnoncovervars; j++ )
2770  {
2771  /* variable has solution value zero */
2772  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2773  {
2774  varsR[*nvarsR] = noncovervars[j];
2775  (*nvarsR)++;
2776  }
2777  /* variable has solution value greater than zero */
2778  else
2779  {
2780  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2781  varsF[*nvarsF] = noncovervars[j];
2782  (*nvarsF)++;
2783  }
2784  }
2785  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2786 }
2787 
2788 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2789  * lifting procedure
2790  */
2791 static
2793  SCIP* scip, /**< SCIP data structure */
2794  SCIP_Real* solvals, /**< solution values of all problem variables */
2795  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2796  int* varsF, /**< pointer to store variables in F */
2797  int* varsC2, /**< pointer to store variables in C2 */
2798  int* varsR, /**< pointer to store variables in R */
2799  int nvarsF, /**< number of variables in F */
2800  int nvarsC2, /**< number of variables in C2 */
2801  int nvarsR /**< number of variables in R */
2802  )
2803 {
2804  SORTKEYPAIR** sortkeypairsF;
2805  SORTKEYPAIR* sortkeypairsFstore;
2806  SCIP_Real* sortkeysC2;
2807  SCIP_Real* sortkeysR;
2808  int j;
2809 
2810  assert(scip != NULL);
2811  assert(solvals != NULL);
2812  assert(weights != NULL);
2813  assert(varsF != NULL);
2814  assert(varsC2 != NULL);
2815  assert(varsR != NULL);
2816  assert(nvarsF >= 0);
2817  assert(nvarsC2 >= 0);
2818  assert(nvarsR >= 0);
2819 
2820  /* allocates temporary memory */
2821  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2822  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2823  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2824  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2825 
2826  /* gets sorting key for variables in F corresponding to the following lifting sequence
2827  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2828  * x*_1 >= x*_2 >= ... >= x*_|F|
2829  * in case of equality uses
2830  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2831  */
2832  for( j = 0; j < nvarsF; j++ )
2833  {
2834  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2835  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2836  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2837  }
2838 
2839  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2840  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2841  */
2842  for( j = 0; j < nvarsC2; j++ )
2843  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2844 
2845  /* gets sorting key for variables in R corresponding to the following lifting sequence
2846  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2847  */
2848  for( j = 0; j < nvarsR; j++ )
2849  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2850 
2851  /* sorts F, C2 and R */
2852  if( nvarsF > 0 )
2853  {
2854  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2855  }
2856  if( nvarsC2 > 0 )
2857  {
2858  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2859  }
2860  if( nvarsR > 0)
2861  {
2862  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2863  }
2864 
2865  /* frees temporary memory */
2866  SCIPfreeBufferArray(scip, &sortkeysR);
2867  SCIPfreeBufferArray(scip, &sortkeysC2);
2868  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2869  SCIPfreeBufferArray(scip, &sortkeypairsF);
2870 
2871  return SCIP_OKAY;
2872 }
2873 
2874 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2875  * for the sequential GUB wise lifting procedure
2876  */
2877 static
2879  SCIP* scip, /**< SCIP data structure */
2880  SCIP_GUBSET* gubset, /**< GUB set data structure */
2881  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2882  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2883  int* varsC1, /**< variables in C1 */
2884  int* varsC2, /**< variables in C2 */
2885  int* varsF, /**< variables in F */
2886  int* varsR, /**< variables in R */
2887  int nvarsC1, /**< number of variables in C1 */
2888  int nvarsC2, /**< number of variables in C2 */
2889  int nvarsF, /**< number of variables in F */
2890  int nvarsR, /**< number of variables in R */
2891  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2892  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2893  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2894  int* gubconsGR, /**< pointer to store GUBs in GR */
2895  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2896  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2897  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2898  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2899  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2900  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2901  )
2902 {
2903  SORTKEYPAIR** sortkeypairsGFC1;
2904  SORTKEYPAIR* sortkeypairsGFC1store;
2905  SCIP_Real* sortkeysC1;
2906  SCIP_Real* sortkeysC2;
2907  SCIP_Real* sortkeysR;
2908  int* nC1varsingubcons;
2909  int var;
2910  int gubconsidx;
2911  int varidx;
2912  int ngubconss;
2913  int ngubconsGOC1;
2914  int targetvar;
2915  int nvarsprocessed;
2916  int i;
2917  int j;
2918 
2919 #if GUBSPLITGNC1GUBS
2920  SCIP_Bool gubconswithF;
2921  int origngubconss;
2922  origngubconss = gubset->ngubconss;
2923 #endif
2924 
2925  assert(scip != NULL);
2926  assert(gubset != NULL);
2927  assert(solvals != NULL);
2928  assert(weights != NULL);
2929  assert(varsC1 != NULL);
2930  assert(varsC2 != NULL);
2931  assert(varsF != NULL);
2932  assert(varsR != NULL);
2933  assert(nvarsC1 > 0);
2934  assert(nvarsC2 >= 0);
2935  assert(nvarsF >= 0);
2936  assert(nvarsR >= 0);
2937  assert(gubconsGC1 != NULL);
2938  assert(gubconsGC2 != NULL);
2939  assert(gubconsGFC1 != NULL);
2940  assert(gubconsGR != NULL);
2941  assert(ngubconsGC1 != NULL);
2942  assert(ngubconsGC2 != NULL);
2943  assert(ngubconsGFC1 != NULL);
2944  assert(ngubconsGR != NULL);
2945  assert(maxgubvarssize != NULL);
2946 
2947  ngubconss = gubset->ngubconss;
2948  nvarsprocessed = 0;
2949  ngubconsGOC1 = 0;
2950 
2951  /* GUBs are categorized into different types according to the variables in volved
2952  * - GOC1: involves variables in C1 only -- no C2, R, F
2953  * - GNC1: involves variables in C1 and F (and R) -- no C2
2954  * - GF: involves variables in F (and R) only -- no C1, C2
2955  * - GC2: involves variables in C2 only -- no C1, R, F
2956  * - GR: involves variables in R only -- no C1, C2, F
2957  * which requires splitting GUBs in case they include variable in F and R.
2958  *
2959  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2960  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2961  * - second ordering level is
2962  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2963  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2964  * GR: non-increasing max{ a_k : k in GR_j}
2965  *
2966  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2967  * - GC1: GUBs of category GOC1 and GNC1
2968  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2969  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2970  */
2971 
2972  /* allocates temporary memory */
2973  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2974  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2975  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2976 
2977  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2978  * - F: non-increasing x*_j and non-increasing a_j in case of equality
2979  * - C2: non-increasing a_j
2980  * - R: non-increasing a_j
2981  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2982  */
2983 
2984  /* gets sorting key for variables in C1 corresponding to the following ordering
2985  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
2986  */
2987  for( j = 0; j < nvarsC1; j++ )
2988  {
2989  /* gets sortkeys */
2990  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
2991 
2992  /* update status of variable in its gub constraint */
2993  gubconsidx = gubset->gubconssidx[varsC1[j]];
2994  varidx = gubset->gubvarsidx[varsC1[j]];
2995  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
2996  }
2997 
2998  /* gets sorting key for variables in F corresponding to the following ordering
2999  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3000  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3001  * and updates status of each variable in F in GUB set data structure
3002  */
3003  for( j = 0; j < nvarsF; j++ )
3004  {
3005  /* update status of variable in its gub constraint */
3006  gubconsidx = gubset->gubconssidx[varsF[j]];
3007  varidx = gubset->gubvarsidx[varsF[j]];
3008  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3009  }
3010 
3011  /* gets sorting key for variables in C2 corresponding to the following ordering
3012  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3013  * and updates status of each variable in F in GUB set data structure
3014  */
3015  for( j = 0; j < nvarsC2; j++ )
3016  {
3017  /* gets sortkeys */
3018  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3019 
3020  /* update status of variable in its gub constraint */
3021  gubconsidx = gubset->gubconssidx[varsC2[j]];
3022  varidx = gubset->gubvarsidx[varsC2[j]];
3023  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3024  }
3025 
3026  /* gets sorting key for variables in R corresponding to the following ordering
3027  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3028  * and updates status of each variable in F in GUB set data structure
3029  */
3030  for( j = 0; j < nvarsR; j++ )
3031  {
3032  /* gets sortkeys */
3033  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3034 
3035  /* update status of variable in its gub constraint */
3036  gubconsidx = gubset->gubconssidx[varsR[j]];
3037  varidx = gubset->gubvarsidx[varsR[j]];
3038  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3039  }
3040 
3041  /* sorts C1, F, C2 and R */
3042  assert(nvarsC1 > 0);
3043  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3044 
3045  if( nvarsC2 > 0 )
3046  {
3047  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3048  }
3049  if( nvarsR > 0)
3050  {
3051  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3052  }
3053 
3054  /* frees temporary memory */
3055  SCIPfreeBufferArray(scip, &sortkeysR);
3056  SCIPfreeBufferArray(scip, &sortkeysC2);
3057  SCIPfreeBufferArray(scip, &sortkeysC1);
3058 
3059  /* allocate and initialize temporary memory for sorting GUB constraints */
3060  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3061  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3062  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3063  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3064  for( i = 0; i < ngubconss; i++)
3065  {
3066  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3067  sortkeypairsGFC1[i]->key1 = 0.0;
3068  sortkeypairsGFC1[i]->key2 = 0.0;
3069  }
3070  *ngubconsGC1 = 0;
3071  *ngubconsGC2 = 0;
3072  *ngubconsGFC1 = 0;
3073  *ngubconsGR = 0;
3074  *ngubconscapexceed = 0;
3075  *maxgubvarssize = 0;
3076 
3077 #ifndef NDEBUG
3078  for( i = 0; i < gubset->ngubconss; i++ )
3079  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3080 #endif
3081 
3082  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3083  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3084  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3085  * non-increasing number of variables in F, and
3086  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3087  */
3088  for( i = 0; i < nvarsC1; i++ )
3089  {
3090  int nvarsC1capexceed;
3091 
3092  nvarsC1capexceed = 0;
3093 
3094  var = varsC1[i];
3095  gubconsidx = gubset->gubconssidx[var];
3096  varidx = gubset->gubvarsidx[var];
3097 
3098  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3099  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3100 
3101  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3102  * note that variables in C1 are already sorted by non-decreasing weigth
3103  */
3104  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3105  GUBsetSwapVars(scip, gubset, var, targetvar);
3106  nC1varsingubcons[gubconsidx]++;
3107 
3108  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3109  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3110  {
3111  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3112  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3113  continue;
3114  }
3115 
3116  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3117  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3118  */
3119 #if GUBSPLITGNC1GUBS
3120  gubconswithF = FALSE;
3121 #endif
3122  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3123  {
3124  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3125 
3126  /* C1-variable: update number of C1/capacity exceeding variables */
3127  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3128  {
3129  nvarsC1capexceed++;
3130  nvarsprocessed++;
3131  }
3132  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3133  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3134  {
3135 #if GUBSPLITGNC1GUBS
3136  gubconswithF = TRUE;
3137 #endif
3138  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3139 
3140  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3141  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3142  }
3143  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3144  {
3145  nvarsC1capexceed++;
3146  }
3147  else
3148  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3149  }
3150 
3151  /* update set of GC1 GUBs */
3152  gubconsGC1[*ngubconsGC1] = gubconsidx;
3153  (*ngubconsGC1)++;
3154 
3155  /* update maximum size of all GUB constraints */
3156  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3157  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3158 
3159  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3160  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3161  {
3162  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3163  ngubconsGOC1++;
3164  }
3165  else
3166  {
3167 #if GUBSPLITGNC1GUBS
3168  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3169  if( !gubconswithF )
3170  {
3171  GUBVARSTATUS movevarstatus;
3172 
3173  assert(gubset->ngubconss < gubset->nvars);
3174 
3175  /* create a new GUB for GR part of splitting */
3176  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3177  gubset->ngubconss++;
3178  ngubconss = gubset->ngubconss;
3179 
3180  /* fill GR with R variables in current GUB */
3181  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3182  {
3183  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3184  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3185  {
3186  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3187  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3188  gubconsidx, ngubconss-1) );
3189  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3190  movevarstatus;
3191  }
3192  }
3193 
3194  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3195  ngubconsGOC1++;
3196 
3197  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3198  gubconsGR[*ngubconsGR] = ngubconss-1;
3199  (*ngubconsGR)++;
3200  }
3201  /* variables in C1, F, and maybe R: GNC1 GUB */
3202  else
3203  {
3204  assert(gubconswithF);
3205 
3206  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3207  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3208  (*ngubconsGFC1)++;
3209  }
3210 #else
3211  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3212  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3213  (*ngubconsGFC1)++;
3214 #endif
3215  }
3216  }
3217 
3218  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3219  * are already sorted correctly
3220  */
3221  for( i = 0; i < nvarsC2; i++ )
3222  {
3223  var = varsC2[i];
3224  gubconsidx = gubset->gubconssidx[var];
3225  varidx = gubset->gubvarsidx[var];
3226 
3227  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3228  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3229  assert(varidx == 0);
3230  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3231  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3232 
3233  /* set status of GC2 GUB */
3234  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3235 
3236  /* update group of GC2 GUBs */
3237  gubconsGC2[*ngubconsGC2] = gubconsidx;
3238  (*ngubconsGC2)++;
3239 
3240  /* update maximum size of all GUB constraints */
3241  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3242  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3243 
3244  nvarsprocessed++;
3245  }
3246 
3247  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3248  * non-increasing number of variables in F, and
3249  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3250  */
3251  for( i = 0; i < nvarsF; i++ )
3252  {
3253  var = varsF[i];
3254  gubconsidx = gubset->gubconssidx[var];
3255  varidx = gubset->gubvarsidx[var];
3256 
3257  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3258  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3259 
3260  nvarsprocessed++;
3261 
3262  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3263  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3264  {
3265  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3266  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3267  continue;
3268  }
3269 
3270  /* set status of GF GUB */
3271  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3272 
3273  /* update sorting key of corresponding GFC1 GUB */
3274  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3275  {
3276  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3277  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3278 
3279  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3280  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3281  {
3282  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3283 
3284  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3285  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3286  }
3287  }
3288 
3289  /* update set of GFC1 GUBs */
3290  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3291  (*ngubconsGFC1)++;
3292 
3293  /* update maximum size of all GUB constraints */
3294  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3295  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3296  }
3297 
3298  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3299  * correctly
3300  */
3301  for( i = 0; i < nvarsR; i++ )
3302  {
3303  var = varsR[i];
3304  gubconsidx = gubset->gubconssidx[var];
3305  varidx = gubset->gubvarsidx[var];
3306 
3307  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3308  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3309 
3310  nvarsprocessed++;
3311 
3312  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3313  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3314  {
3315  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3316  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3317  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3318  continue;
3319  }
3320 
3321  /* set status of GR GUB */
3322  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3323 
3324  /* update set of GR GUBs */
3325  gubconsGR[*ngubconsGR] = gubconsidx;
3326  (*ngubconsGR)++;
3327 
3328  /* update maximum size of all GUB constraints */
3329  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3330  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3331  }
3332  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3333 
3334  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3335  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3336  assert(*ngubconscapexceed >= 0);
3337 #ifndef NDEBUG
3338  {
3339  int check;
3340 
3341  check = 0;
3342 
3343  /* remaining not handled GUBs should only contain capacity exceeding variables */
3344  for( i = 0; i < ngubconss; i++ )
3345  {
3346  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3347  check++;
3348  }
3349  assert(check == *ngubconscapexceed);
3350  }
3351 #endif
3352 
3353  /* sort GFCI GUBs according to computed sorting keys */
3354  if( (*ngubconsGFC1) > 0 )
3355  {
3356  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3357  }
3358 
3359  /* free temporary memory */
3360 #if GUBSPLITGNC1GUBS
3361  ngubconss = origngubconss;
3362 #endif
3363  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3364  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3365  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3366 
3367  return SCIP_OKAY;
3368 }
3369 
3370 /** enlarges minweight table to at least the given length */
3371 static
3373  SCIP* scip, /**< SCIP data structure */
3374  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3375  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3376  int* minweightssize, /**< pointer to current size of minweights table */
3377  int newlen /**< new length of minweights table */
3378  )
3379 {
3380  int j;
3381 
3382  assert(minweightsptr != NULL);
3383  assert(*minweightsptr != NULL);
3384  assert(minweightslen != NULL);
3385  assert(*minweightslen >= 0);
3386  assert(minweightssize != NULL);
3387  assert(*minweightssize >= 0);
3388 
3389  if( newlen > *minweightssize )
3390  {
3391  int newsize;
3392 
3393  /* reallocate table memory */
3394  newsize = SCIPcalcMemGrowSize(scip, newlen);
3395  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3396  *minweightssize = newsize;
3397  }
3398  assert(newlen <= *minweightssize);
3399 
3400  /* initialize new elements */
3401  for( j = *minweightslen; j < newlen; ++j )
3402  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3403  *minweightslen = newlen;
3404 
3405  return SCIP_OKAY;
3406 }
3407 
3408 /** lifts given inequality
3409  * sum_{j in M_1} x_j <= alpha_0
3410  * valid for
3411  * 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 }
3412  * to a valid inequality
3413  * 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
3414  * <= alpha_0 + sum_{j in M_2} alpha_j
3415  * for
3416  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3417  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3418  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3419  * extended weight inequalities.
3420  */
3421 static
3423  SCIP* scip, /**< SCIP data structure */
3424  SCIP_VAR** vars, /**< variables in knapsack constraint */
3425  int nvars, /**< number of variables in knapsack constraint */
3426  int ntightened, /**< number of variables with tightened upper bound */
3427  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3428  SCIP_Longint capacity, /**< capacity of knapsack */
3429  SCIP_Real* solvals, /**< solution values of all problem variables */
3430  int* varsM1, /**< variables in M_1 */
3431  int* varsM2, /**< variables in M_2 */
3432  int* varsF, /**< variables in F */
3433  int* varsR, /**< variables in R */
3434  int nvarsM1, /**< number of variables in M_1 */
3435  int nvarsM2, /**< number of variables in M_2 */
3436  int nvarsF, /**< number of variables in F */
3437  int nvarsR, /**< number of variables in R */
3438  int alpha0, /**< rights hand side of given valid inequality */
3439  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3440  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3441  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3442  )
3443 {
3444  SCIP_Longint* minweights;
3445  SCIP_Real* sortkeys;
3446  SCIP_Longint fixedonesweight;
3447  int minweightssize;
3448  int minweightslen;
3449  int j;
3450  int w;
3451 
3452  assert(scip != NULL);
3453  assert(vars != NULL);
3454  assert(nvars >= 0);
3455  assert(weights != NULL);
3456  assert(capacity >= 0);
3457  assert(solvals != NULL);
3458  assert(varsM1 != NULL);
3459  assert(varsM2 != NULL);
3460  assert(varsF != NULL);
3461  assert(varsR != NULL);
3462  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3463  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3464  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3465  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3466  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3467  assert(alpha0 >= 0);
3468  assert(liftcoefs != NULL);
3469  assert(cutact != NULL);
3470  assert(liftrhs != NULL);
3471 
3472  /* allocates temporary memory */
3473  minweightssize = nvarsM1 + 1;
3474  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3475  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3476 
3477  /* initializes data structures */
3478  BMSclearMemoryArray(liftcoefs, nvars);
3479  *cutact = 0.0;
3480 
3481  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3482  * and calculates activity of the current valid inequality
3483  */
3484  for( j = 0; j < nvarsM1; j++ )
3485  {
3486  assert(liftcoefs[varsM1[j]] == 0);
3487  liftcoefs[varsM1[j]] = 1;
3488  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3489  (*cutact) += solvals[varsM1[j]];
3490  }
3491 
3492  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3493 
3494  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3495  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3496  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3497  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3498  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3499  */
3500  minweights[0] = 0;
3501  for( w = 1; w <= nvarsM1; w++ )
3502  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3503  minweightslen = nvarsM1 + 1;
3504 
3505  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3506  fixedonesweight = 0;
3507  for( j = 0; j < nvarsM2; j++ )
3508  fixedonesweight += weights[varsM2[j]];
3509  assert(fixedonesweight >= 0);
3510 
3511  /* initializes right hand side of lifted valid inequality */
3512  *liftrhs = alpha0;
3513 
3514  /* sequentially up-lifts all variables in F: */
3515  for( j = 0; j < nvarsF; j++ )
3516  {
3517  SCIP_Longint weight;
3518  int liftvar;
3519  int liftcoef;
3520  int z;
3521 
3522  liftvar = varsF[j];
3523  weight = weights[liftvar];
3524  assert(liftvar >= 0 && liftvar < nvars);
3525  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3526  assert(weight > 0);
3527 
3528  /* knapsack problem is infeasible:
3529  * sets z = 0
3530  */
3531  if( capacity - fixedonesweight - weight < 0 )
3532  {
3533  z = 0;
3534  }
3535  /* knapsack problem is feasible:
3536  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3537  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3538  */
3539  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3540  {
3541  z = *liftrhs;
3542  }
3543  /* knapsack problem is feasible:
3544  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3545  */
3546  else
3547  {
3548  int left;
3549  int right;
3550  int middle;
3551 
3552  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3553  left = 0;
3554  right = (*liftrhs) + 1;
3555  while( left < right - 1 )
3556  {
3557  middle = (left + right) / 2;
3558  assert(0 <= middle && middle < minweightslen);
3559  if( minweights[middle] <= capacity - fixedonesweight - weight )
3560  left = middle;
3561  else
3562  right = middle;
3563  }
3564  assert(left == right - 1);
3565  assert(0 <= left && left < minweightslen);
3566  assert(minweights[left] <= capacity - fixedonesweight - weight );
3567  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3568 
3569  /* now z = left */
3570  z = left;
3571  assert(z <= *liftrhs);
3572  }
3573 
3574  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3575  liftcoef = (*liftrhs) - z;
3576  liftcoefs[liftvar] = liftcoef;
3577  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3578 
3579  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3580  if( liftcoef == 0 )
3581  continue;
3582 
3583  /* updates activity of current valid inequality */
3584  (*cutact) += liftcoef * solvals[liftvar];
3585 
3586  /* enlarges current minweight table:
3587  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3588  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3589  * and sets minweights_i[w] = infinity for
3590  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3591  */
3592  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3593 
3594  /* updates minweight table: minweight_i+1[w] =
3595  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3596  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3597  */
3598  for( w = minweightslen - 1; w >= 0; w-- )
3599  {
3600  SCIP_Longint min;
3601  if( w < liftcoef )
3602  {
3603  min = MIN(minweights[w], weight);
3604  minweights[w] = min;
3605  }
3606  else
3607  {
3608  assert(w >= liftcoef);
3609  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3610  minweights[w] = min;
3611  }
3612  }
3613  }
3614  assert(minweights[0] == 0);
3615 
3616  /* sequentially down-lifts all variables in M_2: */
3617  for( j = 0; j < nvarsM2; j++ )
3618  {
3619  SCIP_Longint weight;
3620  int liftvar;
3621  int liftcoef;
3622  int left;
3623  int right;
3624  int middle;
3625  int z;
3626 
3627  liftvar = varsM2[j];
3628  weight = weights[liftvar];
3629  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3630  assert(liftvar >= 0 && liftvar < nvars);
3631  assert(weight > 0);
3632 
3633  /* uses binary search to find
3634  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3635  */
3636  left = 0;
3637  right = minweightslen;
3638  while( left < right - 1 )
3639  {
3640  middle = (left + right) / 2;
3641  assert(0 <= middle && middle < minweightslen);
3642  if( minweights[middle] <= capacity - fixedonesweight + weight )
3643  left = middle;
3644  else
3645  right = middle;
3646  }
3647  assert(left == right - 1);
3648  assert(0 <= left && left < minweightslen);
3649  assert(minweights[left] <= capacity - fixedonesweight + weight );
3650  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3651 
3652  /* now z = left */
3653  z = left;
3654  assert(z >= *liftrhs);
3655 
3656  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3657  liftcoef = z - (*liftrhs);
3658  liftcoefs[liftvar] = liftcoef;
3659  assert(liftcoef >= 0);
3660 
3661  /* updates sum of weights of variables fixed to one */
3662  fixedonesweight -= weight;
3663 
3664  /* updates right-hand side of current valid inequality */
3665  (*liftrhs) += liftcoef;
3666  assert(*liftrhs >= alpha0);
3667 
3668  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3669  if( liftcoef == 0 )
3670  continue;
3671 
3672  /* updates activity of current valid inequality */
3673  (*cutact) += liftcoef * solvals[liftvar];
3674 
3675  /* enlarges current minweight table:
3676  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3677  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3678  * and sets minweights_i[w] = infinity for
3679  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3680  */
3681  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3682 
3683  /* updates minweight table: minweight_i+1[w] =
3684  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3685  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3686  */
3687  for( w = minweightslen - 1; w >= 0; w-- )
3688  {
3689  SCIP_Longint min;
3690  if( w < liftcoef )
3691  {
3692  min = MIN(minweights[w], weight);
3693  minweights[w] = min;
3694  }
3695  else
3696  {
3697  assert(w >= liftcoef);
3698  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3699  minweights[w] = min;
3700  }
3701  }
3702  }
3703  assert(fixedonesweight == 0);
3704  assert(*liftrhs >= alpha0);
3705 
3706  /* sequentially up-lifts all variables in R: */
3707  for( j = 0; j < nvarsR; j++ )
3708  {
3709  SCIP_Longint weight;
3710  int liftvar;
3711  int liftcoef;
3712  int z;
3713 
3714  liftvar = varsR[j];
3715  weight = weights[liftvar];
3716  assert(liftvar >= 0 && liftvar < nvars);
3717  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3718  assert(weight > 0);
3719  assert(capacity - weight >= 0);
3720  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3721 
3722  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3723  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3724  */
3725  if( minweights[*liftrhs] <= capacity - weight )
3726  {
3727  z = *liftrhs;
3728  }
3729  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3730  */
3731  else
3732  {
3733  int left;
3734  int right;
3735  int middle;
3736 
3737  left = 0;
3738  right = (*liftrhs) + 1;
3739  while( left < right - 1)
3740  {
3741  middle = (left + right) / 2;
3742  assert(0 <= middle && middle < minweightslen);
3743  if( minweights[middle] <= capacity - weight )
3744  left = middle;
3745  else
3746  right = middle;
3747  }
3748  assert(left == right - 1);
3749  assert(0 <= left && left < minweightslen);
3750  assert(minweights[left] <= capacity - weight );
3751  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3752 
3753  /* now z = left */
3754  z = left;
3755  assert(z <= *liftrhs);
3756  }
3757 
3758  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3759  liftcoef = (*liftrhs) - z;
3760  liftcoefs[liftvar] = liftcoef;
3761  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3762 
3763  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3764  if( liftcoef == 0 )
3765  continue;
3766 
3767  /* updates activity of current valid inequality */
3768  (*cutact) += liftcoef * solvals[liftvar];
3769 
3770  /* updates minweight table: minweight_i+1[w] =
3771  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3772  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3773  */
3774  for( w = *liftrhs; w >= 0; w-- )
3775  {
3776  SCIP_Longint min;
3777  if( w < liftcoef )
3778  {
3779  min = MIN(minweights[w], weight);
3780  minweights[w] = min;
3781  }
3782  else
3783  {
3784  assert(w >= liftcoef);
3785  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3786  minweights[w] = min;
3787  }
3788  }
3789  }
3790 
3791  /* frees temporary memory */
3792  SCIPfreeBufferArray(scip, &sortkeys);
3793  SCIPfreeBufferArray(scip, &minweights);
3794 
3795  return SCIP_OKAY;
3796 }
3797 
3798 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3799 static
3801  SCIP_Longint val1, /**< first value to add */
3802  SCIP_Longint val2 /**< second value to add */
3803  )
3804 {
3805  assert(val1 >= 0);
3806  assert(val2 >= 0);
3807 
3808  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3809  return SCIP_LONGINT_MAX;
3810  else
3811  {
3812  assert(val1 <= SCIP_LONGINT_MAX - val2);
3813  return (val1 + val2);
3814  }
3815 }
3816 
3817 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3818 static
3820  SCIP_Longint* minweights, /**< minweight table to compute */
3821  SCIP_Longint* finished, /**< given finished table */
3822  SCIP_Longint* unfinished, /**< given unfinished table */
3823  int minweightslen /**< length of minweight, finished, and unfinished tables */
3824  )
3825 {
3826  int w1;
3827  int w2;
3828 
3829  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3830  * note that finished and unfished arrays sorted by non-decreasing weight
3831  */
3832 
3833  /* initialize minweight with w2 = 0 */
3834  w2 = 0;
3835  assert(unfinished[w2] == 0);
3836  for( w1 = 0; w1 < minweightslen; w1++ )
3837  minweights[w1] = finished[w1];
3838 
3839  /* consider w2 = 1, ..., minweightslen-1 */
3840  for( w2 = 1; w2 < minweightslen; w2++ )
3841  {
3842  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3843  break;
3844 
3845  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3846  {
3847  SCIP_Longint temp;
3848 
3849  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3850  if( temp <= minweights[w1+w2] )
3851  minweights[w1+w2] = temp;
3852  }
3853  }
3854 }
3855 
3856 /** lifts given inequality
3857  * sum_{j in C_1} x_j <= alpha_0
3858  * valid for
3859  * 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;
3860  * sum_{j in Q_i} x_j <= 1, forall i in I }
3861  * to a valid inequality
3862  * 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
3863  * <= alpha_0 + sum_{j in C_2} alpha_j
3864  * for
3865  * 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 };
3866  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3867  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3868  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3869  */
3870 static
3872  SCIP* scip, /**< SCIP data structure */
3873  SCIP_GUBSET* gubset, /**< GUB set data structure */
3874  SCIP_VAR** vars, /**< variables in knapsack constraint */
3875  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3876  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3877  SCIP_Longint capacity, /**< capacity of knapsack */
3878  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3879  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3880  int* gubconsGC2, /**< GUBs in GC2 */
3881  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3882  int* gubconsGR, /**< GUBs in GR */
3883  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3884  int ngubconsGC2, /**< number of GUBs in GC2 */
3885  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3886  int ngubconsGR, /**< number of GUBs in GR */
3887  int alpha0, /**< rights hand side of given valid inequality */
3888  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3889  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3890  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3891  int maxgubvarssize /**< maximal size of GUB constraints */
3892  )
3893 {
3894  SCIP_Longint* minweights;
3895  SCIP_Longint* finished;
3896  SCIP_Longint* unfinished;
3897  int* gubconsGOC1;
3898  int* gubconsGNC1;
3899  int* liftgubvars;
3900  SCIP_Longint fixedonesweight;
3901  SCIP_Longint weight;
3902  SCIP_Longint weightdiff1;
3903  SCIP_Longint weightdiff2;
3904  SCIP_Longint min;
3905  int minweightssize;
3906  int minweightslen;
3907  int nvars;
3908  int varidx;
3909  int liftgubconsidx;
3910  int liftvar;
3911  int sumliftcoef;
3912  int liftcoef;
3913  int ngubconsGOC1;
3914  int ngubconsGNC1;
3915  int left;
3916  int right;
3917  int middle;
3918  int nliftgubvars;
3919  int tmplen;
3920  int tmpsize;
3921  int j;
3922  int k;
3923  int w;
3924  int z;
3925 #ifndef NDEBUG
3926  int ngubconss;
3927  int nliftgubC1;
3928 
3929  assert(gubset != NULL);
3930  ngubconss = gubset->ngubconss;
3931 #else
3932  assert(gubset != NULL);
3933 #endif
3934 
3935  nvars = gubset->nvars;
3936 
3937  assert(scip != NULL);
3938  assert(vars != NULL);
3939  assert(nvars >= 0);
3940  assert(weights != NULL);
3941  assert(capacity >= 0);
3942  assert(solvals != NULL);
3943  assert(gubconsGC1 != NULL);
3944  assert(gubconsGC2 != NULL);
3945  assert(gubconsGFC1 != NULL);
3946  assert(gubconsGR != NULL);
3947  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3948  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3949  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3950  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3951  assert(alpha0 >= 0);
3952  assert(liftcoefs != NULL);
3953  assert(cutact != NULL);
3954  assert(liftrhs != NULL);
3955 
3956  minweightssize = ngubconsGC1+1;
3957 
3958  /* allocates temporary memory */
3959  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3960  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3961  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3962  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3963  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3964  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3965 
3966  /* initializes data structures */
3967  BMSclearMemoryArray(liftcoefs, nvars);
3968  *cutact = 0.0;
3969 
3970  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
3971  * valid inequality
3972  */
3973  ngubconsGOC1 = 0;
3974  ngubconsGNC1 = 0;
3975  for( j = 0; j < ngubconsGC1; j++ )
3976  {
3977  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
3978  {
3979  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
3980  ngubconsGOC1++;
3981  }
3982  else
3983  {
3984  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3985  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
3986  ngubconsGNC1++;
3987  }
3988  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
3989  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
3990  {
3991  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
3992  assert(varidx >= 0 && varidx < nvars);
3993  assert(liftcoefs[varidx] == 0);
3994 
3995  liftcoefs[varidx] = 1;
3996  (*cutact) += solvals[varidx];
3997  }
3998  assert(k >= 1);
3999  }
4000  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4001  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4002 
4003  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4004  * - finished_i[w] =
4005  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4006  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4007  * sum_{j in Q_k} x_j <= 1
4008  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4009  * - unfinished_i[w] =
4010  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4011  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4012  * sum_{j in Q_k} x_j <= 1
4013  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4014  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4015  */
4016 
4017  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4018  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4019  * 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
4020  * comes from the first variable in the GUB
4021  */
4022  assert(ngubconsGOC1 <= ngubconsGC1);
4023  finished[0] = 0;
4024  for( w = 1; w <= ngubconsGOC1; w++ )
4025  {
4026  liftgubconsidx = gubconsGOC1[w-1];
4027 
4028  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4029  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4030 
4031  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4032 
4033  assert(varidx >= 0 && varidx < nvars);
4034  assert(liftcoefs[varidx] == 1);
4035 
4036  min = weights[varidx];
4037  finished[w] = finished[w-1] + min;
4038 
4039 #ifndef NDEBUG
4040  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4041  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4042  {
4043  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4044  assert(varidx >= 0 && varidx < nvars);
4045  assert(liftcoefs[varidx] == 1);
4046  assert(weights[varidx] >= min);
4047  }
4048 #endif
4049  }
4050  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4051  finished[w] = SCIP_LONGINT_MAX;
4052 
4053  /* initialize unfinished table; note that variables in GNC1 GUBs
4054  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4055  * 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
4056  * comes from the first variable in the GUB
4057  */
4058  assert(ngubconsGNC1 <= ngubconsGC1);
4059  unfinished[0] = 0;
4060  for( w = 1; w <= ngubconsGNC1; w++ )
4061  {
4062  liftgubconsidx = gubconsGNC1[w-1];
4063 
4064  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4065  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4066 
4067  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4068 
4069  assert(varidx >= 0 && varidx < nvars);
4070  assert(liftcoefs[varidx] == 1);
4071 
4072  min = weights[varidx];
4073  unfinished[w] = unfinished[w-1] + min;
4074 
4075 #ifndef NDEBUG
4076  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4077  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4078  {
4079  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4080  assert(varidx >= 0 && varidx < nvars);
4081  assert(liftcoefs[varidx] == 1);
4082  assert(weights[varidx] >= min );
4083  }
4084 #endif
4085  }
4086  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4087  unfinished[w] = SCIP_LONGINT_MAX;
4088 
4089  /* initialize minweights table; note that variables in GC1 GUBs
4090  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4091  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4092  * consuming) because is it has to be build using weights from C1 only.
4093  */
4094  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4095  minweights[0] = 0;
4096  for( w = 1; w <= ngubconsGC1; w++ )
4097  {
4098  liftgubconsidx = gubconsGC1[w-1];
4099 
4100  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4101  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4102  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4103 
4104  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4105 
4106  assert(varidx >= 0 && varidx < nvars);
4107  assert(liftcoefs[varidx] == 1);
4108 
4109  min = weights[varidx];
4110  minweights[w] = minweights[w-1] + min;
4111 
4112 #ifndef NDEBUG
4113  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4114  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4115  {
4116  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4117  assert(varidx >= 0 && varidx < nvars);
4118  assert(liftcoefs[varidx] == 1);
4119  assert(weights[varidx] >= min);
4120  }
4121 #endif
4122  }
4123  minweightslen = ngubconsGC1 + 1;
4124 
4125  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4126  fixedonesweight = 0;
4127  for( j = 0; j < ngubconsGC2; j++ )
4128  {
4129  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4130 
4131  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4132  assert(varidx >= 0 && varidx < nvars);
4133  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4134 
4135  fixedonesweight += weights[varidx];
4136  }
4137  assert(fixedonesweight >= 0);
4138 
4139  /* initializes right hand side of lifted valid inequality */
4140  *liftrhs = alpha0;
4141 
4142  /* sequentially up-lifts all variables in GFC1 GUBs */
4143  for( j = 0; j < ngubconsGFC1; j++ )
4144  {
4145  liftgubconsidx = gubconsGFC1[j];
4146  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4147 
4148  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4149  * compute minweight table via updated unfinished table and aleady upto date finished table;
4150  */
4151  k = 0;
4152  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4153  {
4154  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4155  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4156  assert(ngubconsGNC1 > 0);
4157 
4158  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4159  * are considered for the lifting, i.e., not capacity exceeding
4160  */
4161  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4162  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4163  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4164  assert(k >= 1);
4165 
4166  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4167  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4168  */
4169  weight = weights[liftgubvars[0]];
4170 
4171  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4172  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4173  for( w = ngubconsGNC1-1; w >= 1; w-- )
4174  {
4175  weightdiff1 = weightdiff2;
4176  weightdiff2 = unfinished[w] - weight;
4177 
4178  if( unfinished[w] < weightdiff1 )
4179  unfinished[w] = weightdiff1;
4180  else
4181  break;
4182  }
4183  ngubconsGNC1--;
4184 
4185  /* computes minweights table by combining unfished and fished tables */
4186  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4187  assert(minweights[0] == 0);
4188  }
4189  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4190  * are therefore not in the unfinished table
4191  */
4192  else
4193  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4194 
4195 #ifndef NDEBUG
4196  nliftgubC1 = k;
4197 #endif
4198  nliftgubvars = k;
4199  sumliftcoef = 0;
4200 
4201  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4202  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4203  {
4204  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4205  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4206  {
4207  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4208  weight = weights[liftvar];
4209  assert(weight > 0);
4210  assert(liftvar >= 0 && liftvar < nvars);
4211  assert(capacity - weight >= 0);
4212 
4213  /* put variable into array of variables in GUB that are considered for the lifting,
4214  * i.e., not capacity exceeding
4215  */
4216  liftgubvars[nliftgubvars] = liftvar;
4217  nliftgubvars++;
4218 
4219  /* knapsack problem is infeasible:
4220  * sets z = 0
4221  */
4222  if( capacity - fixedonesweight - weight < 0 )
4223  {
4224  z = 0;
4225  }
4226  /* knapsack problem is feasible:
4227  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4228  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4229  */
4230  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4231  {
4232  z = *liftrhs;
4233  }
4234  /* knapsack problem is feasible:
4235  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4236  */
4237  else
4238  {
4239  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4240  left = 0;
4241  right = (*liftrhs) + 1;
4242  while( left < right - 1 )
4243  {
4244  middle = (left + right) / 2;
4245  assert(0 <= middle && middle < minweightslen);
4246  if( minweights[middle] <= capacity - fixedonesweight - weight )
4247  left = middle;
4248  else
4249  right = middle;
4250  }
4251  assert(left == right - 1);
4252  assert(0 <= left && left < minweightslen);
4253  assert(minweights[left] <= capacity - fixedonesweight - weight);
4254  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4255 
4256  /* now z = left */
4257  z = left;
4258  assert(z <= *liftrhs);
4259  }
4260 
4261  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4262  liftcoef = (*liftrhs) - z;
4263  liftcoefs[liftvar] = liftcoef;
4264  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4265 
4266  /* updates activity of current valid inequality */
4267  (*cutact) += liftcoef * solvals[liftvar];
4268 
4269  /* updates sum of all lifting coefficients in GUB */
4270  sumliftcoef += liftcoefs[liftvar];
4271  }
4272  else
4273  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4274  }
4275  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4276  assert(nliftgubvars > nliftgubC1);
4277 
4278  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4279  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4280  * not needed for GF GUBs
4281  */
4282  if( sumliftcoef == 0 )
4283  {
4284  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4285  {
4286  weight = weights[liftgubvars[0]];
4287  /* update finished table and minweights table by applying special case of
4288  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4289  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4290  */
4291  for( w = minweightslen-1; w >= 1; w-- )
4292  {
4293  SCIP_Longint tmpval;
4294 
4295  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4296  finished[w] = MIN(finished[w], tmpval);
4297 
4298  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4299  minweights[w] = MIN(minweights[w], tmpval);
4300  }
4301  }
4302  else
4303  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4304 
4305  continue;
4306  }
4307 
4308  /* enlarges current minweights tables(finished, unfinished, minweights):
4309  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4310  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4311  * and sets minweights_i[w] = infinity for
4312  * 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
4313  */
4314  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4315  tmpsize = minweightssize;
4316  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4317  tmplen = minweightslen;
4318  tmpsize = minweightssize;
4319  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4320  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4321 
4322  /* update finished table and minweight table;
4323  * note that instead of computing minweight table from updated finished and updated unfinished table again
4324  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4325  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4326  * not needed because only finished table changed at this point and the change was "adding" one weight)
4327  *
4328  * update formular for minweight table is: minweight_i+1[w] =
4329  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4330  * formular for finished table has the same pattern.
4331  */
4332  for( w = minweightslen-1; w >= 0; w-- )
4333  {
4334  SCIP_Longint minminweight;
4335  SCIP_Longint minfinished;
4336 
4337  for( k = 0; k < nliftgubvars; k++ )
4338  {
4339  liftcoef = liftcoefs[liftgubvars[k]];
4340  weight = weights[liftgubvars[k]];
4341 
4342  if( w < liftcoef )
4343  {
4344  minfinished = MIN(finished[w], weight);
4345  minminweight = MIN(minweights[w], weight);
4346 
4347  finished[w] = minfinished;
4348  minweights[w] = minminweight;
4349  }
4350  else
4351  {
4352  SCIP_Longint tmpval;
4353 
4354  assert(w >= liftcoef);
4355 
4356  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4357  minfinished = MIN(finished[w], tmpval);
4358 
4359  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4360  minminweight = MIN(minweights[w], tmpval);
4361 
4362  finished[w] = minfinished;
4363  minweights[w] = minminweight;
4364  }
4365  }
4366  }
4367  assert(minweights[0] == 0);
4368  }
4369  assert(ngubconsGNC1 == 0);
4370 
4371  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4372  * therefore, only work with minweight table from here on
4373  */
4374 
4375  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4376  for( j = 0; j < ngubconsGC2; j++ )
4377  {
4378  liftgubconsidx = gubconsGC2[j];
4379 
4380  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4381  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4382  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4383  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4384 
4385  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4386  weight = weights[liftvar];
4387 
4388  assert(liftvar >= 0 && liftvar < nvars);
4389  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4390  assert(weight > 0);
4391 
4392  /* uses binary search to find
4393  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4394  */
4395  left = 0;
4396  right = minweightslen;
4397  while( left < right - 1 )
4398  {
4399  middle = (left + right) / 2;
4400  assert(0 <= middle && middle < minweightslen);
4401  if( minweights[middle] <= capacity - fixedonesweight + weight )
4402  left = middle;
4403  else
4404  right = middle;
4405  }
4406  assert(left == right - 1);
4407  assert(0 <= left && left < minweightslen);
4408  assert(minweights[left] <= capacity - fixedonesweight + weight);
4409  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4410 
4411  /* now z = left */
4412  z = left;
4413  assert(z >= *liftrhs);
4414 
4415  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4416  liftcoef = z - (*liftrhs);
4417  liftcoefs[liftvar] = liftcoef;
4418  assert(liftcoef >= 0);
4419 
4420  /* updates sum of weights of variables fixed to one */
4421  fixedonesweight -= weight;
4422 
4423  /* updates right-hand side of current valid inequality */
4424  (*liftrhs) += liftcoef;
4425  assert(*liftrhs >= alpha0);
4426 
4427  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4428  if( liftcoef == 0 )
4429  continue;
4430 
4431  /* updates activity of current valid inequality */
4432  (*cutact) += liftcoef * solvals[liftvar];
4433 
4434  /* enlarges current minweight table:
4435  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4436  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4437  * and sets minweights_i[w] = infinity for
4438  * 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
4439  */
4440  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4441 
4442  /* updates minweight table: minweight_i+1[w] =
4443  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4444  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4445  */
4446  for( w = minweightslen - 1; w >= 0; w-- )
4447  {
4448  if( w < liftcoef )
4449  {
4450  min = MIN(minweights[w], weight);
4451  minweights[w] = min;
4452  }
4453  else
4454  {
4455  SCIP_Longint tmpval;
4456 
4457  assert(w >= liftcoef);
4458 
4459  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4460  min = MIN(minweights[w], tmpval);
4461  minweights[w] = min;
4462  }
4463  }
4464  }
4465  assert(fixedonesweight == 0);
4466  assert(*liftrhs >= alpha0);
4467 
4468  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4469  for( j = 0; j < ngubconsGR; j++ )
4470  {
4471  liftgubconsidx = gubconsGR[j];
4472 
4473  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4474  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4475 
4476  sumliftcoef = 0;
4477  nliftgubvars = 0;
4478  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4479  {
4480  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4481  {
4482  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4483  weight = weights[liftvar];
4484  assert(weight > 0);
4485  assert(liftvar >= 0 && liftvar < nvars);
4486  assert(capacity - weight >= 0);
4487  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4488 
4489  /* put variable into array of variables in GUB that are considered for the lifting,
4490  * i.e., not capacity exceeding
4491  */
4492  liftgubvars[nliftgubvars] = liftvar;
4493  nliftgubvars++;
4494 
4495  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4496  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4497  */
4498  if( minweights[*liftrhs] <= capacity - weight )
4499  {
4500  z = *liftrhs;
4501  }
4502  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4503  */
4504  else
4505  {
4506  left = 0;
4507  right = (*liftrhs) + 1;
4508  while( left < right - 1 )
4509  {
4510  middle = (left + right) / 2;
4511  assert(0 <= middle && middle < minweightslen);
4512  if( minweights[middle] <= capacity - weight )
4513  left = middle;
4514  else
4515  right = middle;
4516  }
4517  assert(left == right - 1);
4518  assert(0 <= left && left < minweightslen);
4519  assert(minweights[left] <= capacity - weight);
4520  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4521 
4522  /* now z = left */
4523  z = left;
4524  assert(z <= *liftrhs);
4525  }
4526  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4527  liftcoef = (*liftrhs) - z;
4528  liftcoefs[liftvar] = liftcoef;
4529  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4530 
4531  /* updates activity of current valid inequality */
4532  (*cutact) += liftcoef * solvals[liftvar];
4533 
4534  /* updates sum of all lifting coefficients in GUB */
4535  sumliftcoef += liftcoefs[liftvar];
4536  }
4537  else
4538  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4539  }
4540  assert(nliftgubvars >= 1); /* at least one variable is in R */
4541 
4542  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4543  if( sumliftcoef == 0 )
4544  continue;
4545 
4546  /* updates minweight table: minweight_i+1[w] =
4547  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4548  */
4549  for( w = *liftrhs; w >= 0; w-- )
4550  {
4551  for( k = 0; k < nliftgubvars; k++ )
4552  {
4553  liftcoef = liftcoefs[liftgubvars[k]];
4554  weight = weights[liftgubvars[k]];
4555 
4556  if( w < liftcoef )
4557  {
4558  min = MIN(minweights[w], weight);
4559  minweights[w] = min;
4560  }
4561  else
4562  {
4563  SCIP_Longint tmpval;
4564 
4565  assert(w >= liftcoef);
4566 
4567  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4568  min = MIN(minweights[w], tmpval);
4569  minweights[w] = min;
4570  }
4571  }
4572  }
4573  assert(minweights[0] == 0);
4574  }
4575 
4576  /* frees temporary memory */
4577  SCIPfreeBufferArray(scip, &minweights);
4578  SCIPfreeBufferArray(scip, &finished);
4579  SCIPfreeBufferArray(scip, &unfinished);
4580  SCIPfreeBufferArray(scip, &liftgubvars);
4581  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4582  SCIPfreeBufferArray(scip, &gubconsGNC1);
4583 
4584  return SCIP_OKAY;
4585 }
4586 
4587 /** lifts given minimal cover inequality
4588  * \f[
4589  * \sum_{j \in C} x_j \leq |C| - 1
4590  * \f]
4591  * valid for
4592  * \f[
4593  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4594  * \f]
4595  * to a valid inequality
4596  * \f[
4597  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4598  * \f]
4599  * for
4600  * \f[
4601  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4602  * \f]
4603  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4604  */
4605 static
4607  SCIP* scip, /**< SCIP data structure */
4608  SCIP_VAR** vars, /**< variables in knapsack constraint */
4609  int nvars, /**< number of variables in knapsack constraint */
4610  int ntightened, /**< number of variables with tightened upper bound */
4611  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4612  SCIP_Longint capacity, /**< capacity of knapsack */
4613  SCIP_Real* solvals, /**< solution values of all problem variables */
4614  int* covervars, /**< cover variables */
4615  int* noncovervars, /**< noncover variables */
4616  int ncovervars, /**< number of cover variables */
4617  int nnoncovervars, /**< number of noncover variables */
4618  SCIP_Longint coverweight, /**< weight of cover */
4619  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4620  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4621  )
4622 {
4623  SCIP_Longint* maxweightsums;
4624  SCIP_Longint* intervalends;
4625  SCIP_Longint* rhos;
4626  SCIP_Real* sortkeys;
4627  SCIP_Longint lambda;
4628  int j;
4629  int h;
4630 
4631  assert(scip != NULL);
4632  assert(vars != NULL);
4633  assert(nvars >= 0);
4634  assert(weights != NULL);
4635  assert(capacity >= 0);
4636  assert(solvals != NULL);
4637  assert(covervars != NULL);
4638  assert(noncovervars != NULL);
4639  assert(ncovervars > 0 && ncovervars <= nvars);
4640  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4641  assert(ncovervars + nnoncovervars == nvars - ntightened);
4642  assert(liftcoefs != NULL);
4643  assert(cutact != NULL);
4644 
4645  /* allocates temporary memory */
4646  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4647  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4648  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4649  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4650 
4651  /* initializes data structures */
4652  BMSclearMemoryArray(liftcoefs, nvars);
4653  *cutact = 0.0;
4654 
4655  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4656  * and calculates activity of current valid inequality
4657  */
4658  for( j = 0; j < ncovervars; j++ )
4659  {
4660  assert(liftcoefs[covervars[j]] == 0.0);
4661  liftcoefs[covervars[j]] = 1.0;
4662  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4663  (*cutact) += solvals[covervars[j]];
4664  }
4665  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4666 
4667  /* calculates weight excess of cover C */
4668  lambda = coverweight - capacity;
4669  assert(lambda > 0);
4670 
4671  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4672  maxweightsums[0] = 0;
4673  for( h = 1; h <= ncovervars; h++ )
4674  {
4675  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4676  intervalends[h-1] = maxweightsums[h] - lambda;
4677  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4678  }
4679 
4680  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4681  for( j = 0; j < nnoncovervars; j++ )
4682  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4683  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4684 
4685  /* calculates lifting coefficient for all variables in N\C */
4686  h = 0;
4687  for( j = 0; j < nnoncovervars; j++ )
4688  {
4689  int liftvar;
4690  SCIP_Longint weight;
4691  SCIP_Real liftcoef;
4692 
4693  liftvar = noncovervars[j];
4694  weight = weights[liftvar];
4695 
4696  while( intervalends[h] < weight )
4697  h++;
4698 
4699  if( h == 0 )
4700  liftcoef = h;
4701  else
4702  {
4703  if( weight <= intervalends[h-1] + rhos[h] )
4704  {
4705  SCIP_Real tmp1;
4706  SCIP_Real tmp2;
4707  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4708  tmp2 = (SCIP_Real) rhos[1];
4709  liftcoef = h - ( tmp1 / tmp2 );
4710  }
4711  else
4712  liftcoef = h;
4713  }
4714 
4715  /* sets lifting coefficient */
4716  assert(liftcoefs[liftvar] == 0.0);
4717  liftcoefs[liftvar] = liftcoef;
4718 
4719  /* updates activity of current valid inequality */
4720  (*cutact) += liftcoef * solvals[liftvar];
4721  }
4722 
4723  /* frees temporary memory */
4724  SCIPfreeBufferArray(scip, &rhos);
4725  SCIPfreeBufferArray(scip, &intervalends);
4726  SCIPfreeBufferArray(scip, &maxweightsums);
4727  SCIPfreeBufferArray(scip, &sortkeys);
4728 
4729  return SCIP_OKAY;
4730 }
4731 
4732 
4733 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4734  * given knapsack problem
4735 */
4736 static
4738  SCIP* scip, /**< SCIP data structure */
4739  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4740  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4741  SCIP_VAR** vars, /**< variables in knapsack constraint */
4742  int nvars, /**< number of variables in knapsack constraint */
4743  int ntightened, /**< number of variables with tightened upper bound */
4744  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4745  SCIP_Longint capacity, /**< capacity of knapsack */
4746  SCIP_Real* solvals, /**< solution values of all problem variables */
4747  int* mincovervars, /**< mincover variables */
4748  int* nonmincovervars, /**< nonmincover variables */
4749  int nmincovervars, /**< number of mincover variables */
4750  int nnonmincovervars, /**< number of nonmincover variables */
4751  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4752  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4753  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4754  int* ncuts /**< pointer to add up the number of found cuts */
4755  )
4756 {
4757  int* varsC1;
4758  int* varsC2;
4759  int* varsF;
4760  int* varsR;
4761  int nvarsC1;
4762  int nvarsC2;
4763  int nvarsF;
4764  int nvarsR;
4765  SCIP_Real cutact;
4766  int* liftcoefs;
4767  int liftrhs;
4768 
4769  assert( cutoff != NULL );
4770  *cutoff = FALSE;
4771 
4772  /* allocates temporary memory */
4773  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4774  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4775  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4776  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4777  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4778 
4779  /* 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
4780  * as follows
4781  * C_2 = { j in C : x*_j = 1 } and
4782  * C_1 = C\C_2
4783  */
4784  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4785  assert(nvarsC1 + nvarsC2 == nmincovervars);
4786  assert(nmincovervars > 0);
4787  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4788 
4789  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4790  if( nvarsC1 < 2 && nvarsC2 > 0)
4791  {
4792  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4793  assert(nvarsC1 >= 1);
4794  }
4795  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4796 
4797  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4798  * R = { j in N\C : x*_j = 0 } and
4799  * F = (N\C)\F
4800  */
4801  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4802  assert(nvarsF + nvarsR == nnonmincovervars);
4803  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4804 
4805  /* lift cuts without GUB information */
4806  if( gubset == NULL )
4807  {
4808  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4809  * lifting procedure
4810  */
4811  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4812 
4813  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4814  *
4815  * 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 }
4816  *
4817  * 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
4818  *
4819  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4820  *
4821  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4822  * up-lifting for the variables in R according to the second level lifting sequence
4823  */
4824  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4825  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4826  }
4827  /* lift cuts with GUB information */
4828  else
4829  {
4830  int* gubconsGC1;
4831  int* gubconsGC2;
4832  int* gubconsGFC1;
4833  int* gubconsGR;
4834  int ngubconsGC1;
4835  int ngubconsGC2;
4836  int ngubconsGFC1;
4837  int ngubconsGR;
4838  int ngubconss;
4839  int nconstightened;
4840  int maxgubvarssize;
4841 
4842  assert(nvars == gubset->nvars);
4843 
4844  ngubconsGC1 = 0;
4845  ngubconsGC2 = 0;
4846  ngubconsGFC1 = 0;
4847  ngubconsGR = 0;
4848  ngubconss = gubset->ngubconss;
4849  nconstightened = 0;
4850  maxgubvarssize = 0;
4851 
4852  /* allocates temporary memory */
4853  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4854  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4855  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4856  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4857 
4858  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4859  * the GUBs for the sequential GUB wise lifting procedure
4860  */
4861  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4862  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4863  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4864 
4865  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4866  *
4867  * 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,
4868  * sum_{j in Q_i} x_j <= 1, forall i in I }
4869  *
4870  * 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
4871  *
4872  * 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 },
4873  *
4874  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4875  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4876  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4877  */
4878  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4879  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4880  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4881 
4882  /* frees temporary memory */
4883  SCIPfreeBufferArray(scip, &gubconsGR);
4884  SCIPfreeBufferArray(scip, &gubconsGFC1);
4885  SCIPfreeBufferArray(scip, &gubconsGC2);
4886  SCIPfreeBufferArray(scip, &gubconsGC1);
4887  }
4888 
4889  /* checks, if lifting yielded a violated cut */
4890  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4891  {
4892  SCIP_ROW* row;
4893  char name[SCIP_MAXSTRLEN];
4894  int j;
4895 
4896  /* creates LP row */
4897  assert( cons == NULL || sepa == NULL );
4898  if ( cons != NULL )
4899  {
4900  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4901  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4902  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4903  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4904  }
4905  else if ( sepa != NULL )
4906  {
4907  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4908  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4909  }
4910  else
4911  {
4912  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4913  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4914  }
4915 
4916  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4917  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4918  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4919  for( j = 0; j < nvarsC1; j++ )
4920  {
4921  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4922  }
4923  for( j = 0; j < nvarsC2; j++ )
4924  {
4925  if( liftcoefs[varsC2[j]] > 0 )
4926  {
4927  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4928  }
4929  }
4930  for( j = 0; j < nvarsF; j++ )
4931  {
4932  if( liftcoefs[varsF[j]] > 0 )
4933  {
4934  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4935  }
4936  }
4937  for( j = 0; j < nvarsR; j++ )
4938  {
4939  if( liftcoefs[varsR[j]] > 0 )
4940  {
4941  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4942  }
4943  }
4944  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4945 
4946  /* checks, if cut is violated enough */
4947  if( SCIPisCutEfficacious(scip, sol, row) )
4948  {
4949  if( cons != NULL )
4950  {
4951  SCIP_CALL( SCIPresetConsAge(scip, cons) );
4952  }
4953  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
4954  (*ncuts)++;
4955  }
4956  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4957  }
4958 
4959  /* frees temporary memory */
4960  SCIPfreeBufferArray(scip, &liftcoefs);
4961  SCIPfreeBufferArray(scip, &varsR);
4962  SCIPfreeBufferArray(scip, &varsF);
4963  SCIPfreeBufferArray(scip, &varsC2);
4964  SCIPfreeBufferArray(scip, &varsC1);
4965 
4966  return SCIP_OKAY;
4967 }
4968 
4969 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
4970 static
4972  SCIP* scip, /**< SCIP data structure */
4973  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
4974  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4975  SCIP_VAR** vars, /**< variables in knapsack constraint */
4976  int nvars, /**< number of variables in knapsack constraint */
4977  int ntightened, /**< number of variables with tightened upper bound */
4978  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4979  SCIP_Longint capacity, /**< capacity of knapsack */
4980  SCIP_Real* solvals, /**< solution values of all problem variables */
4981  int* feassetvars, /**< variables in feasible set */
4982  int* nonfeassetvars, /**< variables not in feasible set */
4983  int nfeassetvars, /**< number of variables in feasible set */
4984  int nnonfeassetvars, /**< number of variables not in feasible set */
4985  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4986  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
4987  int* ncuts /**< pointer to add up the number of found cuts */
4988  )
4989 {
4990  int* varsT1;
4991  int* varsT2;
4992  int* varsF;
4993  int* varsR;
4994  int* liftcoefs;
4995  SCIP_Real cutact;
4996  int nvarsT1;
4997  int nvarsT2;
4998  int nvarsF;
4999  int nvarsR;
5000  int liftrhs;
5001  int j;
5002 
5003  assert( cutoff != NULL );
5004  *cutoff = FALSE;
5005 
5006  /* allocates temporary memory */
5007  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5008  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5009  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5010  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5011  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5012 
5013  /* 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
5014  * as follows
5015  * T_2 = { j in T : x*_j = 1 } and
5016  * T_1 = T\T_2
5017  */
5018  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5019  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5020 
5021  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5022  if( nvarsT1 == 0 && nvarsT2 > 0)
5023  {
5024  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5025  assert(nvarsT1 == 1);
5026  }
5027  assert(nvarsT2 == 0 || nvarsT1 > 0);
5028 
5029  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5030  * R = { j in N\T : x*_j = 0 } and
5031  * F = (N\T)\F
5032  */
5033  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5034  assert(nvarsF + nvarsR == nnonfeassetvars);
5035  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5036 
5037  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5038  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5039  * is included in the sorting routine)
5040  */
5041  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5042 
5043  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5044  *
5045  * 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 }
5046  *
5047  * 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
5048  *
5049  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5050  *
5051  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5052  * up-lifting for the variabels in R according to the second level lifting sequence
5053  */
5054  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5055  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5056 
5057  /* checks, if lifting yielded a violated cut */
5058  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5059  {
5060  SCIP_ROW* row;
5061  char name[SCIP_MAXSTRLEN];
5062 
5063  /* creates LP row */
5064  assert( cons == NULL || sepa == NULL );
5065  if( cons != NULL )
5066  {
5067  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5068  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5069  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5070  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5071  }
5072  else if ( sepa != NULL )
5073  {
5074  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5075  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5076  }
5077  else
5078  {
5079  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5080  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5081  }
5082 
5083  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5084  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5085  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5086  for( j = 0; j < nvarsT1; j++ )
5087  {
5088  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5089  }
5090  for( j = 0; j < nvarsT2; j++ )
5091  {
5092  if( liftcoefs[varsT2[j]] > 0 )
5093  {
5094  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5095  }
5096  }
5097  for( j = 0; j < nvarsF; j++ )
5098  {
5099  if( liftcoefs[varsF[j]] > 0 )
5100  {
5101  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5102  }
5103  }
5104  for( j = 0; j < nvarsR; j++ )
5105  {
5106  if( liftcoefs[varsR[j]] > 0 )
5107  {
5108  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5109  }
5110  }
5111  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5112 
5113  /* checks, if cut is violated enough */
5114  if( SCIPisCutEfficacious(scip, sol, row) )
5115  {
5116  if( cons != NULL )
5117  {
5118  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5119  }
5120  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5121  (*ncuts)++;
5122  }
5123  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5124  }
5125 
5126  /* frees temporary memory */
5127  SCIPfreeBufferArray(scip, &liftcoefs);
5128  SCIPfreeBufferArray(scip, &varsR);
5129  SCIPfreeBufferArray(scip, &varsF);
5130  SCIPfreeBufferArray(scip, &varsT2);
5131  SCIPfreeBufferArray(scip, &varsT1);
5132 
5133  return SCIP_OKAY;
5134 }
5135 
5136 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5137 static
5139  SCIP* scip, /**< SCIP data structure */
5140  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5141  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5142  SCIP_VAR** vars, /**< variables in knapsack constraint */
5143  int nvars, /**< number of variables in knapsack constraint */
5144  int ntightened, /**< number of variables with tightened upper bound */
5145  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5146  SCIP_Longint capacity, /**< capacity of knapsack */
5147  SCIP_Real* solvals, /**< solution values of all problem variables */
5148  int* mincovervars, /**< mincover variables */
5149  int* nonmincovervars, /**< nonmincover variables */
5150  int nmincovervars, /**< number of mincover variables */
5151  int nnonmincovervars, /**< number of nonmincover variables */
5152  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5153  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5154  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5155  int* ncuts /**< pointer to add up the number of found cuts */
5156  )
5157 {
5158  SCIP_Real* realliftcoefs;
5159  SCIP_Real cutact;
5160  int liftrhs;
5161 
5162  assert( cutoff != NULL );
5163  *cutoff = FALSE;
5164  cutact = 0.0;
5165 
5166  /* allocates temporary memory */
5167  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5168 
5169  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5170  *
5171  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5172  *
5173  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5174  *
5175  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5176  *
5177  * uses superadditive up-lifting for the variables in N\C.
5178  */
5179  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5180  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5181  liftrhs = nmincovervars - 1;
5182 
5183  /* checks, if lifting yielded a violated cut */
5184  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5185  {
5186  SCIP_ROW* row;
5187  char name[SCIP_MAXSTRLEN];
5188  int j;
5189 
5190  /* creates LP row */
5191  assert( cons == NULL || sepa == NULL );
5192  if ( cons != NULL )
5193  {
5194  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5195  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5196  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5197  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5198  }
5199  else if ( sepa != NULL )
5200  {
5201  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5202  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5203  }
5204  else
5205  {
5206  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5207  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5208  }
5209 
5210  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5211  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5212  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5213  for( j = 0; j < nmincovervars; j++ )
5214  {
5215  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5216  }
5217  for( j = 0; j < nnonmincovervars; j++ )
5218  {
5219  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5220  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5221  {
5222  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5223  }
5224  }
5225  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5226 
5227  /* checks, if cut is violated enough */
5228  if( SCIPisCutEfficacious(scip, sol, row) )
5229  {
5230  if( cons != NULL )
5231  {
5232  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5233  }
5234  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5235  (*ncuts)++;
5236  }
5237  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5238  }
5239 
5240  /* frees temporary memory */
5241  SCIPfreeBufferArray(scip, &realliftcoefs);
5242 
5243  return SCIP_OKAY;
5244 }
5245 
5246 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5247  * 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
5248  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5249  * note that all variables with x*_j = 1 will be removed last
5250  */
5251 static
5253  SCIP* scip, /**< SCIP data structure */
5254  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5255  SCIP_Longint capacity, /**< capacity of knapsack */
5256  SCIP_Real* solvals, /**< solution values of all problem variables */
5257  int* covervars, /**< pointer to store cover variables */
5258  int* noncovervars, /**< pointer to store noncover variables */
5259  int* ncovervars, /**< pointer to store number of cover variables */
5260  int* nnoncovervars, /**< pointer to store number of noncover variables */
5261  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5262  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5263  )
5264 {
5265  SORTKEYPAIR** sortkeypairs;
5266  SORTKEYPAIR** sortkeypairssorted;
5267  SCIP_Longint minweight;
5268  int nsortkeypairs;
5269  int minweightidx;
5270  int j;
5271  int k;
5272 
5273  assert(scip != NULL);
5274  assert(covervars != NULL);
5275  assert(noncovervars != NULL);
5276  assert(ncovervars != NULL);
5277  assert(*ncovervars > 0);
5278  assert(nnoncovervars != NULL);
5279  assert(*nnoncovervars >= 0);
5280  assert(coverweight != NULL);
5281  assert(*coverweight > 0);
5282  assert(*coverweight > capacity);
5283 
5284  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5285  * order */
5286  nsortkeypairs = *ncovervars;
5287  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5288  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5289 
5290  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5291  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5292  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5293  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5294  */
5295  assert(*ncovervars == nsortkeypairs);
5296  if( modtransused )
5297  {
5298  for( j = 0; j < *ncovervars; j++ )
5299  {
5300  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5301  sortkeypairssorted[j] = sortkeypairs[j];
5302 
5303  sortkeypairs[j]->key1 = solvals[covervars[j]];
5304  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5305  }
5306  }
5307  else
5308  {
5309  for( j = 0; j < *ncovervars; j++ )
5310  {
5311  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5312  sortkeypairssorted[j] = sortkeypairs[j];
5313 
5314  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5315  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5316  }
5317  }
5318  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5319 
5320  /* gets j' with a_j' = min{ a_j : j in C } */
5321  minweightidx = 0;
5322  minweight = weights[covervars[minweightidx]];
5323  for( j = 1; j < *ncovervars; j++ )
5324  {
5325  if( weights[covervars[j]] <= minweight )
5326  {
5327  minweightidx = j;
5328  minweight = weights[covervars[minweightidx]];
5329  }
5330  }
5331  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5332  assert(minweight > 0 && minweight <= *coverweight);
5333 
5334  j = 0;
5335  /* removes variables from C until the remaining variables form a minimal cover */
5336  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5337  {
5338  assert(minweightidx >= j);
5339  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5340 
5341  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5342  if( (*coverweight) - weights[covervars[j]] <= capacity )
5343  {
5344  ++j;
5345  continue;
5346  }
5347 
5348  /* adds j to N\C */
5349  noncovervars[*nnoncovervars] = covervars[j];
5350  (*nnoncovervars)++;
5351 
5352  /* removes j from C */
5353  (*coverweight) -= weights[covervars[j]];
5354  for( k = j; k < (*ncovervars) - 1; k++ )
5355  covervars[k] = covervars[k+1];
5356  (*ncovervars)--;
5357 
5358  /* updates j' with a_j' = min{ a_j : j in C } */
5359  if( j == minweightidx )
5360  {
5361  minweightidx = 0;
5362  minweight = weights[covervars[minweightidx]];
5363  for( k = 1; k < *ncovervars; k++ )
5364  {
5365  if( weights[covervars[k]] <= minweight )
5366  {
5367  minweightidx = k;
5368  minweight = weights[covervars[minweightidx]];
5369  }
5370  }
5371  assert(minweight > 0 && minweight <= *coverweight);
5372  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5373  }
5374  else
5375  {
5376  assert(minweightidx > j);
5377  minweightidx--;
5378  }
5379  /* j needs to stay the same */
5380  }
5381  assert((*coverweight) > capacity);
5382  assert((*coverweight) - minweight <= capacity);
5383 
5384  /* frees temporary memory */
5385  for( j = nsortkeypairs-1; j >= 0; j-- )
5386  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5387  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5388  SCIPfreeBufferArray(scip, &sortkeypairs);
5389 
5390  return SCIP_OKAY;
5391 }
5392 
5393 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5394  * they were chosen to be in C_init:
5395  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5396  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5397  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5398  * and all subsequent feasible sets.
5399  */
5400 static
5402  SCIP* scip, /**< SCIP data structure */
5403  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5404  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5405  SCIP_VAR** vars, /**< variables in knapsack constraint */
5406  int nvars, /**< number of variables in knapsack constraint */
5407  int ntightened, /**< number of variables with tightened upper bound */
5408  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5409  SCIP_Longint capacity, /**< capacity of knapsack */
5410  SCIP_Real* solvals, /**< solution values of all problem variables */
5411  int* covervars, /**< pointer to store cover variables */
5412  int* noncovervars, /**< pointer to store noncover variables */
5413  int* ncovervars, /**< pointer to store number of cover variables */
5414  int* nnoncovervars, /**< pointer to store number of noncover variables */
5415  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5416  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5417  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5418  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5419  int* ncuts /**< pointer to add up the number of found cuts */
5420  )
5421 {
5422  SCIP_Real* sortkeys;
5423  int j;
5424  int k;
5425 
5426  assert(scip != NULL);
5427  assert(covervars != NULL);
5428  assert(noncovervars != NULL);
5429  assert(ncovervars != NULL);
5430  assert(*ncovervars > 0);
5431  assert(nnoncovervars != NULL);
5432  assert(*nnoncovervars >= 0);
5433  assert(coverweight != NULL);
5434  assert(*coverweight > 0);
5435  assert(*coverweight > capacity);
5436  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5437  assert(cutoff != NULL);
5438 
5439  *cutoff = FALSE;
5440 
5441  /* allocates temporary memory */
5442  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5443 
5444  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5445  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5446  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5447  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5448  */
5449  if( modtransused )
5450  {
5451  for( j = 0; j < *ncovervars; j++ )
5452  {
5453  sortkeys[j] = solvals[covervars[j]];
5454  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5455  }
5456  }
5457  else
5458  {
5459  for( j = 0; j < *ncovervars; j++ )
5460  {
5461  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5462  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5463  }
5464  }
5465  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5466 
5467  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5468  * in addition to an extended weight inequality this gives cardinality inequalities */
5469  while( *ncovervars >= 2 )
5470  {
5471  /* adds first element of C_init to N\C_init */
5472  noncovervars[*nnoncovervars] = covervars[0];
5473  (*nnoncovervars)++;
5474 
5475  /* removes first element from C_init */
5476  (*coverweight) -= weights[covervars[0]];
5477  for( k = 0; k < (*ncovervars) - 1; k++ )
5478  covervars[k] = covervars[k+1];
5479  (*ncovervars)--;
5480 
5481  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5482  if( (*coverweight) <= capacity )
5483  {
5484  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5485  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5486  }
5487 
5488  /* stop if cover is too large */
5489  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5490  break;
5491  }
5492 
5493  /* frees temporary memory */
5494  SCIPfreeBufferArray(scip, &sortkeys);
5495 
5496  return SCIP_OKAY;
5497 }
5498 
5499 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5501  SCIP* scip, /**< SCIP data structure */
5502  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5503  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5504  SCIP_VAR** vars, /**< variables in knapsack constraint */
5505  int nvars, /**< number of variables in knapsack constraint */
5506  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5507  SCIP_Longint capacity, /**< capacity of knapsack */
5508  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5509  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5510  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5511  int* ncuts /**< pointer to add up the number of found cuts */
5512  )
5513 {
5514  SCIP_Real* solvals;
5515  int* covervars;
5516  int* noncovervars;
5517  SCIP_Bool coverfound;
5518  SCIP_Bool fractional;
5519  SCIP_Bool modtransused;
5520  SCIP_Longint coverweight;
5521  int ncovervars;
5522  int nnoncovervars;
5523  int ntightened;
5524 
5525  assert(scip != NULL);
5526  assert(capacity >= 0);
5527  assert(cutoff != NULL);
5528  assert(ncuts != NULL);
5529 
5530  *cutoff = FALSE;
5531 
5532  if( nvars == 0 )
5533  return SCIP_OKAY;
5534 
5535  assert(vars != NULL);
5536  assert(nvars > 0);
5537  assert(weights != NULL);
5538 
5539  /* increase age of constraint (age is reset to zero, if a cut was found) */
5540  if( cons != NULL )
5541  {
5542  SCIP_CALL( SCIPincConsAge(scip, cons) );
5543  }
5544 
5545  /* allocates temporary memory */
5546  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5547  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5548  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5549 
5550  /* gets solution values of all problem variables */
5551  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5552 
5553 #ifdef SCIP_DEBUG
5554  {
5555  int i;
5556 
5557  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5558  cons == NULL ? "-" : SCIPconsGetName(cons));
5559  for( i = 0; i < nvars; ++i )
5560  {
5561  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5562  }
5563  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5564  }
5565 #endif
5566 
5567  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5568  */
5569  if( usegubs )
5570  {
5571  SCIP_GUBSET* gubset;
5572 
5573  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5574 
5575  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5576  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5577 
5578  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5579  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5580  assert(gubset->ngubconss <= nvars);
5581 
5582  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5583  * MODIFIED transformed separation problem and taking into account the following fixing:
5584  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5585  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5586  * if one exists
5587  */
5588  modtransused = TRUE;
5589  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5590  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5591 
5592  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5593 
5594  /* if x* is not fractional we stop the separation routine */
5595  if( !fractional )
5596  {
5597  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5598 
5599  /* frees memory for GUB set data structure */
5600  GUBsetFree(scip, &gubset);
5601 
5602  goto TERMINATE;
5603  }
5604 
5605  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5606  if( coverfound )
5607  {
5608  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5609  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5610  */
5611  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5612  &nnoncovervars, &coverweight, modtransused) );
5613 
5614  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5615  if( gubset->ngubconss < nvars )
5616  {
5617  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5618  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5619  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5620  }
5621  else
5622  {
5623  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5624  * GUB information
5625  */
5626  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5627  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5628  }
5629  }
5630 
5631  /* frees memory for GUB set data structure */
5632  GUBsetFree(scip, &gubset);
5633  }
5634  else
5635  {
5636  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5637  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5638  */
5639 
5640  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5641  * MODIFIED transformed separation problem and taking into account the following fixing:
5642  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5643  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5644  * if one exists
5645  */
5646  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5647  modtransused = TRUE;
5648  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5649  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5650  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5651 
5652  /* if x* is not fractional we stop the separation routine */
5653  if( !fractional )
5654  goto TERMINATE;
5655 
5656  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5657  if( coverfound )
5658  {
5659  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5660  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5661  */
5662  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5663  &nnoncovervars, &coverweight, modtransused) );
5664 
5665  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5666  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5667  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5668 
5669  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5670  {
5671  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5672  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5673  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5674  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5675  }
5676  }
5677  }
5678 
5679  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5680  if ( ! (*cutoff) )
5681  {
5682  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5683  * transformed separation problem and taking into account the following fixing:
5684  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5685  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5686  * if one exists
5687  */
5688  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5689  modtransused = FALSE;
5690  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5691  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5692  assert(fractional);
5693  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5694 
5695  /* if no cover was found we stop the separation routine */
5696  if( coverfound )
5697  {
5698  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5699  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5700  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5701  */
5702  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5703  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5704  }
5705  }
5706 
5707  TERMINATE:
5708  /* frees temporary memory */
5709  SCIPfreeBufferArray(scip, &noncovervars);
5710  SCIPfreeBufferArray(scip, &covervars);
5711  SCIPfreeBufferArray(scip, &solvals);
5712 
5713  return SCIP_OKAY;
5714 }
5715 
5716 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5718  SCIP* scip, /**< SCIP data structure */
5719  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5720  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5721  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5722  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5723  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5724  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5725  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5726  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5727  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5728  int* ncuts /**< pointer to add up the number of found cuts */
5729  )
5730 {
5731  SCIP_VAR** binvars;
5732  SCIP_VAR** consvars;
5733  SCIP_Real* binvals;
5734  SCIP_Longint* consvals;
5735  SCIP_Longint minact;
5736  SCIP_Longint maxact;
5737  SCIP_Real intscalar;
5738  SCIP_Bool success;
5739  int nbinvars;
5740  int nconsvars;
5741  int i;
5742 
5743  int* tmpindices;
5744  int tmp;
5745  SCIP_CONSHDLR* conshdlr;
5746  SCIP_CONSHDLRDATA* conshdlrdata;
5747  SCIP_Bool noknapsackconshdlr;
5748  SCIP_Bool usegubs;
5749 
5750  assert(nknapvars > 0);
5751  assert(knapvars != NULL);
5752  assert(cutoff != NULL);
5753 
5754  tmpindices = NULL;
5755 
5756  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5757  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5758 
5759  binvars = SCIPgetVars(scip);
5760 
5761  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5762  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5763 
5764  *cutoff = FALSE;
5765 
5766  if( nbinvars == 0 )
5767  return SCIP_OKAY;
5768 
5769  /* set up data structures */
5770  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5771  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5772 
5773  /* get conshdlrdata to use cleared memory */
5774  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5775  if( conshdlr == NULL )
5776  {
5777  noknapsackconshdlr = TRUE;
5778  usegubs = DEFAULT_USEGUBS;
5779 
5780  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5781  BMSclearMemoryArray(binvals, nbinvars);
5782  }
5783  else
5784  {
5785  noknapsackconshdlr = FALSE;
5786  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5787  assert(conshdlrdata != NULL);
5788  usegubs = conshdlrdata->usegubs;
5789 
5790  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5791 
5792  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5793  * change their types to SCIP_VARTYPE_BINARY during presolving
5794  */
5795  if( conshdlrdata->reals1size == 0 )
5796  {
5797  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5798  conshdlrdata->reals1size = 1;
5799  conshdlrdata->reals1[0] = 0.0;
5800  }
5801 
5802  assert(conshdlrdata->reals1size > 0);
5803 
5804  /* next if condition should normally not be true, because it means that presolving has created more binary
5805  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5806  * transform all integers into their binary representation then it maybe happens
5807  */
5808  if( conshdlrdata->reals1size < nbinvars )
5809  {
5810  int oldsize = conshdlrdata->reals1size;
5811 
5812  conshdlrdata->reals1size = nbinvars;
5813  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5814  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5815  }
5816  binvals = conshdlrdata->reals1;
5817 
5818  /* check for cleared array, all entries have to be zero */
5819 #ifndef NDEBUG
5820  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5821  {
5822  assert(binvals[tmp] == 0);
5823  }
5824 #endif
5825  }
5826 
5827  tmp = 0;
5828 
5829  /* relax continuous knapsack constraint:
5830  * 1. make all variables binary:
5831  * if x_j is continuous or integer variable substitute:
5832  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5833  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5834  * 2. convert coefficients of all variables to positive integers:
5835  * - scale all coefficients a_j to a~_j integral
5836  * - substitute x~_j = 1 - x_j if a~_j < 0
5837  */
5838 
5839  /* replace integer and continuous variables with binary variables */
5840  for( i = 0; i < nknapvars; i++ )
5841  {
5842  SCIP_VAR* var;
5843 
5844  var = knapvars[i];
5845 
5846  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5847  {
5848  SCIP_Real solval;
5849  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5850 
5851  solval = SCIPgetSolVal(scip, sol, var);
5852 
5853  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5854  if( SCIPisFeasLT(scip, solval, 0.0 )
5855  || SCIPisFeasGT(scip, solval, 1.0) )
5856  {
5857  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5858  solval, SCIPvarGetName(var));
5859  goto TERMINATE;
5860  }
5861 
5862  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5863  if( !noknapsackconshdlr )
5864  {
5865  assert(tmpindices != NULL);
5866 
5867  tmpindices[tmp] = SCIPvarGetProbindex(var);
5868  ++tmp;
5869  }
5870  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5871  }
5872  else if( valscale * knapvals[i] > 0.0 )
5873  {
5874  SCIP_VAR** zvlb;
5875  SCIP_Real* bvlb;
5876  SCIP_Real* dvlb;
5877  SCIP_Real bestlbsol;
5878  int bestlbtype;
5879  int nvlb;
5880  int j;
5881 
5882  /* a_j > 0: substitution with lb or vlb */
5883  nvlb = SCIPvarGetNVlbs(var);
5884  zvlb = SCIPvarGetVlbVars(var);
5885  bvlb = SCIPvarGetVlbCoefs(var);
5886  dvlb = SCIPvarGetVlbConstants(var);
5887 
5888  /* search for lb or vlb with maximal bound value */
5889  bestlbsol = SCIPvarGetLbGlobal(var);
5890  bestlbtype = -1;
5891  for( j = 0; j < nvlb; j++ )
5892  {
5893  /* use only numerical stable vlb with binary variable z */
5894  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5895  {
5896  SCIP_Real vlbsol;
5897 
5898  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5899  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5900  {
5901  *cutoff = TRUE;
5902  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5904  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5905  goto TERMINATE;
5906  }
5907 
5908  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5909  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5910  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5911  {
5912  bestlbsol = vlbsol;
5913  bestlbtype = j;
5914  }
5915  }
5916  }
5917 
5918  /* if no lb or vlb with binary variable was found, we have to abort */
5919  if( SCIPisInfinity(scip, -bestlbsol) )
5920  goto TERMINATE;
5921 
5922  if( bestlbtype == -1 )
5923  {
5924  rhs -= valscale * knapvals[i] * bestlbsol;
5925  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5926  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5927  }
5928  else
5929  {
5930  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5931  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5932  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5933 
5934  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5935  goto TERMINATE;
5936 
5937  if( !noknapsackconshdlr )
5938  {
5939  assert(tmpindices != NULL);
5940 
5941  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5942  ++tmp;
5943  }
5944  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5945  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5946  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5947  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5948  }
5949  }
5950  else
5951  {
5952  SCIP_VAR** zvub;
5953  SCIP_Real* bvub;
5954  SCIP_Real* dvub;
5955  SCIP_Real bestubsol;
5956  int bestubtype;
5957  int nvub;
5958  int j;
5959 
5960  assert(valscale * knapvals[i] < 0.0);
5961 
5962  /* a_j < 0: substitution with ub or vub */
5963  nvub = SCIPvarGetNVubs(var);
5964  zvub = SCIPvarGetVubVars(var);
5965  bvub = SCIPvarGetVubCoefs(var);
5966  dvub = SCIPvarGetVubConstants(var);
5967 
5968  /* search for ub or vub with minimal bound value */
5969  bestubsol = SCIPvarGetUbGlobal(var);
5970  bestubtype = -1;
5971  for( j = 0; j < nvub; j++ )
5972  {
5973  /* use only numerical stable vub with active binary variable z */
5974  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
5975  {
5976  SCIP_Real vubsol;
5977 
5978  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
5979  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
5980  {
5981  *cutoff = TRUE;
5982  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
5984  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
5985  goto TERMINATE;
5986  }
5987 
5988  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
5989  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
5990  if( SCIPisLE(scip, vubsol, bestubsol) )
5991  {
5992  bestubsol = vubsol;
5993  bestubtype = j;
5994  }
5995  }
5996  }
5997 
5998  /* if no ub or vub with binary variable was found, we have to abort */
5999  if( SCIPisInfinity(scip, bestubsol) )
6000  goto TERMINATE;
6001 
6002  if( bestubtype == -1 )
6003  {
6004  rhs -= valscale * knapvals[i] * bestubsol;
6005  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6006  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6007  }
6008  else
6009  {
6010  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6011  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6012  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6013 
6014  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6015  goto TERMINATE;
6016 
6017  if( !noknapsackconshdlr )
6018  {
6019  assert(tmpindices != NULL);
6020 
6021  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6022  ++tmp;
6023  }
6024  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6025  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6026  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6027  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6028  }
6029  }
6030  }
6031 
6032  /* convert coefficients of all (now binary) variables to positive integers:
6033  * - make all coefficients integral
6034  * - make all coefficients positive (substitute negated variable)
6035  */
6036  nconsvars = 0;
6037 
6038  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6039  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6040  */
6042  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6043  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6044 
6045  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6046  if( !success )
6047  intscalar = 1.0;
6048 
6049  /* make all coefficients integral and positive:
6050  * - scale a~_j = a_j * intscalar
6051  * - substitute x~_j = 1 - x_j if a~_j < 0
6052  */
6053  rhs = rhs * intscalar;
6054 
6055  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6056  minact = 0;
6057  maxact = 0;
6058  for( i = 0; i < nbinvars; i++ )
6059  {
6060  SCIP_VAR* var;
6061  SCIP_Longint val;
6062 
6063  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6064  if( val == 0 )
6065  continue;
6066 
6067  if( val > 0 )
6068  {
6069  var = binvars[i];
6070  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6071  val, SCIPvarGetName(var), binvals[i], rhs);
6072  }
6073  else
6074  {
6075  assert(val < 0);
6076 
6077  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6078  val = -val; /*lint !e2704*/
6079  rhs += val;
6080  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6081  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6082  }
6083 
6084  if( SCIPvarGetLbLocal(var) > 0.5 )
6085  minact += val;
6086  if( SCIPvarGetUbLocal(var) > 0.5 )
6087  maxact += val;
6088  consvals[nconsvars] = val;
6089  consvars[nconsvars] = var;
6090  nconsvars++;
6091  }
6092 
6093  if( nconsvars > 0 )
6094  {
6095  SCIP_Longint capacity;
6096 
6097  assert(consvars != NULL);
6098  assert(consvals != NULL);
6099  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6100 
6101 #ifdef SCIP_DEBUG
6102  {
6103  SCIP_Real act;
6104 
6105  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6106  act = 0.0;
6107  for( i = 0; i < nconsvars; ++i )
6108  {
6109  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6110  SCIPgetSolVal(scip, sol, consvars[i]));
6111  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6112  }
6113  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6114  capacity, rhs, act, minact, maxact);
6115  }
6116 #endif
6117 
6118  if( minact > capacity )
6119  {
6120  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6121  *cutoff = TRUE;
6122  goto TERMINATE;
6123  }
6124 
6125  if( maxact > capacity )
6126  {
6127  /* separate lifted cut from relaxed knapsack constraint */
6128  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6129  }
6130  }
6131 
6132  TERMINATE:
6133  /* free data structures */
6134  if( noknapsackconshdlr)
6135  {
6136  SCIPfreeBufferArray(scip, &binvals);
6137  }
6138  else
6139  {
6140  /* clear binvals */
6141  for( --tmp; tmp >= 0; --tmp)
6142  {
6143  assert(tmpindices != NULL);
6144  binvals[tmpindices[tmp]] = 0;
6145  }
6146  SCIPfreeBufferArray(scip, &tmpindices);
6147  }
6148  SCIPfreeBufferArray(scip, &consvals);
6149  SCIPfreeBufferArray(scip, &consvars);
6150 
6151  return SCIP_OKAY;
6152 }
6153 
6154 /** separates given knapsack constraint */
6155 static
6157  SCIP* scip, /**< SCIP data structure */
6158  SCIP_CONS* cons, /**< knapsack constraint */
6159  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6160  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6161  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6162  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6163  int* ncuts /**< pointer to add up the number of found cuts */
6164  )
6165 {
6166  SCIP_CONSDATA* consdata;
6167  SCIP_Bool violated;
6168 
6169  assert(ncuts != NULL);
6170  assert(cutoff != NULL);
6171  *cutoff = FALSE;
6172 
6173  consdata = SCIPconsGetData(cons);
6174  assert(consdata != NULL);
6175 
6176  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6177 
6178  /* check knapsack constraint itself for feasibility */
6179  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6180 
6181  if( violated )
6182  {
6183  /* add knapsack constraint as LP row to the LP */
6184  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6185  (*ncuts)++;
6186  }
6187  else if( sepacuts )
6188  {
6189  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6190  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6191  }
6192 
6193  return SCIP_OKAY;
6194 }
6195 
6196 /** adds coefficient to constraint data */
6197 static
6199  SCIP* scip, /**< SCIP data structure */
6200  SCIP_CONS* cons, /**< knapsack constraint */
6201  SCIP_VAR* var, /**< variable to add to knapsack */
6202  SCIP_Longint weight /**< weight of variable in knapsack */
6203  )
6204 {
6205  SCIP_CONSDATA* consdata;
6207  consdata = SCIPconsGetData(cons);
6208  assert(consdata != NULL);
6209  assert(SCIPvarIsBinary(var));
6210  assert(weight > 0);
6211 
6212  /* add the new coefficient to the LP row */
6213  if( consdata->row != NULL )
6214  {
6215  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6216  }
6217 
6218  /* check for fixed variable */
6219  if( SCIPvarGetLbGlobal(var) > 0.5 )
6220  {
6221  /* variable is fixed to one: reduce capacity */
6222  consdata->capacity -= weight;
6223  }
6224  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6225  {
6226  SCIP_Bool negated;
6227 
6228  /* get binary representative of variable */
6229  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6230 
6231  /* insert coefficient */
6232  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6233  consdata->vars[consdata->nvars] = var;
6234  consdata->weights[consdata->nvars] = weight;
6235  consdata->nvars++;
6236 
6237  /* capture variable */
6238  SCIP_CALL( SCIPcaptureVar(scip, var) );
6239 
6240  /* install the rounding locks of variable */
6241  SCIP_CALL( lockRounding(scip, cons, var) );
6242 
6243  /* catch events */
6244  if( SCIPconsIsTransformed(cons) )
6245  {
6246  SCIP_CONSHDLRDATA* conshdlrdata;
6247 
6248  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6249  assert(conshdlrdata != NULL);
6250  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6252  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6253  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6254 
6255  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6256  consdata->existmultaggr = TRUE;
6257 
6258  /* mark constraint to be propagated and presolved */
6259  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6260  consdata->presolvedtiming = 0;
6261  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6262  }
6263 
6264  /* update weight sums */
6265  updateWeightSums(consdata, var, weight);
6266 
6267  consdata->sorted = FALSE;
6268  consdata->cliquepartitioned = FALSE;
6269  consdata->negcliquepartitioned = FALSE;
6270  consdata->merged = FALSE;
6271  }
6272 
6273  return SCIP_OKAY;
6274 }
6275 
6276 /** deletes coefficient at given position from constraint data */
6277 static
6279  SCIP* scip, /**< SCIP data structure */
6280  SCIP_CONS* cons, /**< knapsack constraint */
6281  int pos /**< position of coefficient to delete */
6282  )
6283 {
6284  SCIP_CONSDATA* consdata;
6285  SCIP_VAR* var;
6287  consdata = SCIPconsGetData(cons);
6288  assert(consdata != NULL);
6289  assert(0 <= pos && pos < consdata->nvars);
6290 
6291  var = consdata->vars[pos];
6292  assert(var != NULL);
6293  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6294 
6295  /* delete the coefficient from the LP row */
6296  if( consdata->row != NULL )
6297  {
6298  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6299  }
6300 
6301  /* remove the rounding locks of variable */
6302  SCIP_CALL( unlockRounding(scip, cons, var) );
6303 
6304  /* drop events and mark constraint to be propagated and presolved */
6305  if( SCIPconsIsTransformed(cons) )
6306  {
6307  SCIP_CONSHDLRDATA* conshdlrdata;
6308 
6309  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6310  assert(conshdlrdata != NULL);
6312  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6313  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6314 
6315  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6316  consdata->presolvedtiming = 0;
6317  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6318  }
6319 
6320  /* decrease weight sums */
6321  updateWeightSums(consdata, var, -consdata->weights[pos]);
6322 
6323  /* move the last variable to the free slot */
6324  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6325  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6326  if( consdata->eventdata != NULL )
6327  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6328 
6329  /* release variable */
6330  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6331 
6332  /* try to use old clique partitions */
6333  if( consdata->cliquepartitioned )
6334  {
6335  assert(consdata->cliquepartition != NULL);
6336  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6337  * change the clique number */
6338  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6339  {
6340  int oldcliqenum;
6341 
6342  oldcliqenum = consdata->cliquepartition[pos];
6343  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6344 
6345  /* the following if and else cases assure that we have increasing clique numbers */
6346  if( consdata->cliquepartition[pos] > pos )
6347  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6348  else
6349  {
6350  int i;
6351  int cliquenumbefore;
6352 
6353  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6354  * occurs the same as the old one is still in the cliquepartition */
6355  if( oldcliqenum > consdata->cliquepartition[pos] )
6356  {
6357  for( i = 0; i < consdata->nvars; ++i )
6358  if( oldcliqenum == consdata->cliquepartition[i] )
6359  break;
6360  else if( oldcliqenum < consdata->cliquepartition[i] )
6361  {
6362  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6363  break;
6364  }
6365  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6366  * the biggest index, so decrease the number of cliques
6367  */
6368  if( i == consdata->nvars )
6369  --(consdata->ncliques);
6370  }
6371  /* if the old clique number was smaller than the new one we have to check the front for an element with
6372  * clique number minus 1 */
6373  else if( oldcliqenum < consdata->cliquepartition[pos] )
6374  {
6375  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6376  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6377 
6378  if( i < cliquenumbefore )
6379  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6380  }
6381  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6382  else if( pos == consdata->nvars - 1)
6383  {
6384  cliquenumbefore = consdata->cliquepartition[pos];
6385  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6386 
6387  if( i < cliquenumbefore )
6388  --(consdata->ncliques);
6389  }
6390  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6391  }
6392  }
6393  else
6394  --(consdata->ncliques);
6395  }
6396 
6397  if( consdata->negcliquepartitioned )
6398  {
6399  assert(consdata->negcliquepartition != NULL);
6400  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6401  * change the clique number */
6402  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6403  {
6404  int oldcliqenum;
6405 
6406  oldcliqenum = consdata->negcliquepartition[pos];
6407  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6408 
6409  /* the following if and else cases assure that we have increasing clique numbers */
6410  if( consdata->negcliquepartition[pos] > pos )
6411  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6412  else
6413  {
6414  int i;
6415  int cliquenumbefore;
6416 
6417  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6418  * occurs, the same as the old one occurs */
6419  if( oldcliqenum > consdata->negcliquepartition[pos] )
6420  {
6421  for( i = 0; i < consdata->nvars; ++i )
6422  if( oldcliqenum == consdata->negcliquepartition[i] )
6423  break;
6424  else if( oldcliqenum < consdata->negcliquepartition[i] )
6425  {
6426  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6427  break;
6428  }
6429  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6430  * the biggest index, so decrease the number of negated cliques
6431  */
6432  if( i == consdata->nvars )
6433  --(consdata->nnegcliques);
6434  }
6435  /* if the old clique number was smaller than the new one we have to check the front for an element with
6436  * clique number minus 1 */
6437  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6438  {
6439  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6440  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6441 
6442  if( i < cliquenumbefore )
6443  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6444  }
6445  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6446  else if( pos == consdata->nvars - 1)
6447  {
6448  cliquenumbefore = consdata->negcliquepartition[pos];
6449  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6450 
6451  if( i < cliquenumbefore )
6452  --(consdata->nnegcliques);
6453  }
6454  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6455  }
6456  }
6457  else
6458  --(consdata->nnegcliques);
6459  }
6460 
6461  --(consdata->nvars);
6462 
6463  return SCIP_OKAY;
6464 }
6465 
6466 /** removes all items with weight zero from knapsack constraint */
6467 static
6469  SCIP* scip, /**< SCIP data structure */
6470  SCIP_CONS* cons /**< knapsack constraint */
6471  )
6472 {
6473  SCIP_CONSDATA* consdata;
6474  int v;
6475 
6476  consdata = SCIPconsGetData(cons);
6477  assert(consdata != NULL);
6478 
6479  for( v = consdata->nvars-1; v >= 0; --v )
6480  {
6481  if( consdata->weights[v] == 0 )
6482  {
6483  SCIP_CALL( delCoefPos(scip, cons, v) );
6484  }
6485  }
6486 
6487  return SCIP_OKAY;
6488 }
6489 
6490 /* perform deletion of variables in all constraints of the constraint handler */
6491 static
6493  SCIP* scip, /**< SCIP data structure */
6494  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6495  SCIP_CONS** conss, /**< array of constraints */
6496  int nconss /**< number of constraints */
6497  )
6498 {
6499  SCIP_CONSDATA* consdata;
6500  int i;
6501  int v;
6502 
6503  assert(scip != NULL);
6504  assert(conshdlr != NULL);
6505  assert(conss != NULL);
6506  assert(nconss >= 0);
6507  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6508 
6509  /* iterate over all constraints */
6510  for( i = 0; i < nconss; i++ )
6511  {
6512  consdata = SCIPconsGetData(conss[i]);
6513 
6514  /* constraint is marked, that some of its variables were deleted */
6515  if( consdata->varsdeleted )
6516  {
6517  /* iterate over all variables of the constraint and delete them from the constraint */
6518  for( v = consdata->nvars - 1; v >= 0; --v )
6519  {
6520  if( SCIPvarIsDeleted(consdata->vars[v]) )
6521  {
6522  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6523  }
6524  }
6525  consdata->varsdeleted = FALSE;
6526  }
6527  }
6528 
6529  return SCIP_OKAY;
6530 }
6531 
6532 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6533 static
6535  SCIP* scip, /**< SCIP data structure */
6536  SCIP_CONS* cons, /**< knapsack constraint */
6537  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6538  )
6539 {
6540  SCIP_CONSDATA* consdata;
6541  int v;
6542  int prev;
6543 
6544  assert(scip != NULL);
6545  assert(cons != NULL);
6546  assert(cutoff != NULL);
6547 
6548  consdata = SCIPconsGetData(cons);
6549  assert(consdata != NULL);
6550 
6551  *cutoff = FALSE;
6552 
6553  if( consdata->merged )
6554  return SCIP_OKAY;
6555 
6556  if( consdata->nvars <= 1 )
6557  {
6558  consdata->merged = TRUE;
6559  return SCIP_OKAY;
6560  }
6561 
6562  assert(consdata->vars != NULL || consdata->nvars == 0);
6563 
6564  /* sorting array after indices of variables, that's only for faster merging */
6565  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6566  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6567 
6568  /* knapsack-sorting (decreasing weights) now lost */
6569  consdata->sorted = FALSE;
6570 
6571  v = consdata->nvars - 1;
6572  prev = v - 1;
6573  /* loop backwards through the items: deletion only affects rear items */
6574  while( prev >= 0 )
6575  {
6576  SCIP_VAR* var1;
6577  SCIP_VAR* var2;
6578  SCIP_Bool negated1;
6579  SCIP_Bool negated2;
6580 
6581  negated1 = FALSE;
6582  negated2 = FALSE;
6583 
6584  var1 = consdata->vars[v];
6585  assert(SCIPvarIsBinary(var1));
6586  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6588  {
6589  var1 = SCIPvarGetNegatedVar(var1);
6590  negated1 = TRUE;
6591  }
6592  assert(var1 != NULL);
6593 
6594  var2 = consdata->vars[prev];
6595  assert(SCIPvarIsBinary(var2));
6596  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6598  {
6599  var2 = SCIPvarGetNegatedVar(var2);
6600  negated2 = TRUE;
6601  }
6602  assert(var2 != NULL);
6603 
6604  if( var1 == var2 )
6605  {
6606  /* both variables are either active or negated */
6607  if( negated1 == negated2 )
6608  {
6609  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6610  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6611  SCIP_CALL( delCoefPos(scip, cons, v) );
6612  }
6613  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6614  * and delete item of smaller weight
6615  */
6616  else if( consdata->weights[v] == consdata->weights[prev] )
6617  {
6618  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6619  consdata->capacity -= consdata->weights[v];
6620  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6621  SCIP_CALL( delCoefPos(scip, cons, prev) );
6622 
6623  --prev;
6624  }
6625  else if( consdata->weights[v] < consdata->weights[prev] )
6626  {
6627  consdata->capacity -= consdata->weights[v];
6628  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6629  assert(consdata->weights[prev] > 0);
6630  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6631  }
6632  else
6633  {
6634  consdata->capacity -= consdata->weights[prev];
6635  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6636  assert(consdata->weights[v] > 0);
6637  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6638  /* restore order iff necessary */
6639  if( consdata->nvars != v ) /* otherwise the order still stands */
6640  {
6641  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6642  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6643  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6644  --prev;
6645  else /* we need to let v at the same position*/
6646  {
6647  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6648  /* don't decrease v, the same variable may exist up front */
6649  --prev;
6650  continue;
6651  }
6652  }
6653  }
6654  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6655  }
6656  v = prev;
6657  --prev;
6658  }
6659 
6660  consdata->merged = TRUE;
6661 
6662  /* check infeasibility */
6663  if( consdata->onesweightsum > consdata->capacity )
6664  {
6665  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6666  *cutoff = TRUE;
6667  return SCIP_OKAY;
6668  }
6669 
6670  return SCIP_OKAY;
6671 }
6672 
6673 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6674  * fixings (dual reductions)
6675  */
6676 static
6678  SCIP* scip, /**< SCIP data structure */
6679  SCIP_CONS* cons, /**< knapsack constraint */
6680  int* nfixedvars, /**< pointer to count number of fixings */
6681  int* ndelconss, /**< pointer to count number of deleted constraints */
6682  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6683  )
6684 {
6685  SCIP_CONSDATA* consdata;
6686  SCIP_VAR** vars;
6687  SCIP_Real* profits;
6688  int* solitems;
6689  int* nonsolitems;
6690  int* items;
6691  SCIP_Real solval;
6692  SCIP_Bool infeasible;
6693  SCIP_Bool tightened;
6694  SCIP_Bool applicable;
6695  int nsolitems;
6696  int nnonsolitems;
6697  int nvars;
6698  int v;
6699 
6700  assert(!SCIPconsIsModifiable(cons));
6701 
6702  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6703  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6704  * added to the problems have the check flag set to FALSE
6705  */
6706  if( !SCIPconsIsChecked(cons) )
6707  return SCIP_OKAY;
6708 
6709  consdata = SCIPconsGetData(cons);
6710  assert(consdata != NULL);
6711 
6712  nvars = consdata->nvars;
6713  vars = consdata->vars;
6714 
6715  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6716  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6717  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6718  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6719 
6720  applicable = TRUE;
6721 
6722  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6723  * collect object values which are the profits of the knapsack problem
6724  */
6725  for( v = 0; v < nvars; ++v )
6726  {
6727  SCIP_VAR* var;
6728  SCIP_Bool negated;
6729 
6730  var = vars[v];
6731  assert(var != NULL);
6732 
6733  /* the variable should not be (globally) fixed */
6734  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6735 
6738  {
6739  applicable = FALSE;
6740  break;
6741  }
6742 
6743  negated = FALSE;
6744 
6745  /* get the active variable */
6746  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6747  assert(SCIPvarIsActive(var));
6748 
6749  if( negated )
6750  profits[v] = SCIPvarGetObj(var);
6751  else
6752  profits[v] = -SCIPvarGetObj(var);
6753 
6754  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6755  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6756  items[v] = v;
6757  }
6758 
6759  if( applicable )
6760  {
6761  SCIP_Bool success;
6762 
6763  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6764  SCIPdebugPrintCons(scip, cons, NULL);
6765 
6766  /* solve knapsack problem exactly */
6767  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6768  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6769 
6770  if( success )
6771  {
6772  SCIP_VAR* var;
6773 
6774  /* apply solution of the knapsack as dual reductions */
6775  for( v = 0; v < nsolitems; ++v )
6776  {
6777  var = vars[solitems[v]];
6778  assert(var != NULL);
6779 
6780  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6782  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6783  assert(!infeasible);
6784  assert(tightened);
6785  (*nfixedvars)++;
6786  }
6787 
6788  for( v = 0; v < nnonsolitems; ++v )
6789  {
6790  var = vars[nonsolitems[v]];
6791  assert(var != NULL);
6792 
6793  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6795  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6796  assert(!infeasible);
6797  assert(tightened);
6798  (*nfixedvars)++;
6799  }
6800 
6801  SCIP_CALL( SCIPdelCons(scip, cons) );
6802  (*ndelconss)++;
6803  (*deleted) = TRUE;
6804  }
6805  }
6806 
6807  SCIPfreeBufferArray(scip, &nonsolitems);
6808  SCIPfreeBufferArray(scip, &solitems);
6809  SCIPfreeBufferArray(scip, &items);
6810  SCIPfreeBufferArray(scip, &profits);
6811 
6812  return SCIP_OKAY;
6813 }
6814 
6815 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6816  * constraint enters the LP by setting the initial and separated flag to FALSE
6817  */
6818 static
6820  SCIP* scip, /**< SCIP data structure */
6821  SCIP_CONS* cons, /**< knapsack constraint */
6822  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6823  )
6824 {
6825  SCIP_CONSDATA* consdata;
6826  SCIP_VAR** vars;
6827  SCIP_VAR* var;
6828  SCIP_Real offset;
6829  SCIP_Real scale;
6830  SCIP_Real objval;
6831  SCIP_Bool applicable;
6832  SCIP_Bool negated;
6833  int nobjvars;
6834  int nvars;
6835  int v;
6836 
6837  assert(scip != NULL);
6838  assert(cons != NULL);
6839  assert(conshdlrdata != NULL);
6840 
6841  consdata = SCIPconsGetData(cons);
6842  assert(consdata != NULL);
6843 
6844  nvars = consdata->nvars;
6845  nobjvars = SCIPgetNObjVars(scip);
6846 
6847  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6848  * and/or separated flag is set to FALSE
6849  */
6850  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6851  return SCIP_OKAY;
6852 
6853  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6854  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6855  */
6856  if( nobjvars == 0 )
6857  return SCIP_OKAY;
6858 
6859  vars = consdata->vars;
6860  assert(vars != NULL);
6861 
6862  applicable = TRUE;
6863  offset = 0.0;
6864  scale = 1.0;
6865 
6866  for( v = 0; v < nvars && applicable; ++v )
6867  {
6868  negated = FALSE;
6869  var = vars[v];
6870  assert(var != NULL);
6871 
6872  if( SCIPvarIsNegated(var) )
6873  {
6874  negated = TRUE;
6875  var = SCIPvarGetNegatedVar(var);
6876  assert(var != NULL);
6877  }
6878 
6879  objval = SCIPvarGetObj(var);
6880 
6881  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6882  if( SCIPisZero(scip, objval) )
6883  applicable = FALSE;
6884  else
6885  {
6886  SCIP_Real weight;
6887 
6888  weight = (SCIP_Real)consdata->weights[v];
6889 
6890  if( negated )
6891  {
6892  if( v == 0 )
6893  {
6894  /* the first variable defines the scale */
6895  scale = weight / -objval;
6896 
6897  offset += weight;
6898  }
6899  else if( SCIPisEQ(scip, -objval * scale, weight) )
6900  offset += weight;
6901  else
6902  applicable = FALSE;
6903  }
6904  else if( v == 0 )
6905  {
6906  /* the first variable define the scale */
6907  scale = weight / objval;
6908  }
6909  else if( !SCIPisEQ(scip, objval * scale, weight) )
6910  applicable = FALSE;
6911  }
6912  }
6913 
6914  if( applicable )
6915  {
6916  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6917  {
6918  SCIP_Real cutoffbound;
6919 
6920  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6921  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6922  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6923 
6924  cutoffbound = (consdata->capacity - offset) / scale;
6925 
6926  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6927  SCIPconsGetName(cons), cutoffbound);
6928 
6929  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6930  * still excepted
6931  */
6932  cutoffbound += SCIPcutoffbounddelta(scip);
6933 
6934  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6935  SCIPconsGetName(cons), cutoffbound);
6936 
6937  if( cutoffbound < SCIPgetCutoffbound(scip) )
6938  {
6939  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6940 
6941  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6942  }
6943  else
6944  {
6945  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6946  * propagation
6947  */
6948  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6949  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6950  }
6951  }
6952  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6953  {
6954  SCIP_Real lowerbound;
6955 
6956  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6957  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6958  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6959 
6960  lowerbound = (consdata->capacity - offset) / scale;
6961 
6962  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6963  SCIPconsGetName(cons), lowerbound);
6964 
6965  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6966  }
6967  }
6968 
6969  return SCIP_OKAY;
6970 }
6971 
6972 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6973  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
6974 static
6976  SCIP* scip, /**< SCIP data structure */
6977  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
6978  SCIP_VAR** vars, /**< array for sorted variables */
6979  SCIP_Longint* weights, /**< array for sorted weights */
6980  int* cliquestartposs, /**< starting position array for each clique */
6981  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
6982  )
6983 {
6984  SCIP_VAR** origvars;
6985  int norigvars;
6986  SCIP_Longint* origweights;
6987  int* cliquepartition;
6988  int ncliques;
6989 
6990  SCIP_VAR*** varpointers;
6991  SCIP_Longint** weightpointers;
6992  int* cliquecount;
6993 
6994  int nextpos;
6995  int c;
6996  int v;
6997 
6998  assert(scip != NULL);
6999  assert(consdata != NULL);
7000  assert(vars != NULL);
7001  assert(weights != NULL);
7002  assert(cliquestartposs != NULL);
7003 
7004  origweights = consdata->weights;
7005  origvars = consdata->vars;
7006  norigvars = consdata->nvars;
7007 
7008  assert(origvars != NULL || norigvars == 0);
7009  assert(origweights != NULL || norigvars == 0);
7010 
7011  if( norigvars == 0 )
7012  return SCIP_OKAY;
7013 
7014  if( usenegatedclique )
7015  {
7016  assert(consdata->negcliquepartitioned);
7017 
7018  cliquepartition = consdata->negcliquepartition;
7019  ncliques = consdata->nnegcliques;
7020  }
7021  else
7022  {
7023  assert(consdata->cliquepartitioned);
7024 
7025  cliquepartition = consdata->cliquepartition;
7026  ncliques = consdata->ncliques;
7027  }
7028 
7029  assert(cliquepartition != NULL);
7030  assert(ncliques > 0);
7031 
7032  /* we first count all clique items and alloc temporary memory for a bucket sort */
7033  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7034  BMSclearMemoryArray(cliquecount, ncliques);
7035 
7036  /* first we count for each clique the number of elements */
7037  for( v = norigvars - 1; v >= 0; --v )
7038  {
7039  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7040  ++(cliquecount[cliquepartition[v]]);
7041  }
7042 
7043  /*@todo: maybe it is better to put largest cliques up front */
7044 
7045 #ifndef NDEBUG
7046  BMSclearMemoryArray(vars, norigvars);
7047  BMSclearMemoryArray(weights, norigvars);
7048 #endif
7049  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7050  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7051 
7052  nextpos = 0;
7053  /* now we initialize all start pointers for each clique, so they will be ordered */
7054  for( c = 0; c < ncliques; ++c )
7055  {
7056  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7057  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7058  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7059  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7060  * vars[7]
7061  *
7062  */
7063  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7064  cliquestartposs[c] = nextpos;
7065  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7066  assert(cliquecount[c] > 0);
7067  nextpos += cliquecount[c];
7068  assert(nextpos > 0);
7069  }
7070  assert(nextpos == norigvars);
7071  cliquestartposs[c] = nextpos;
7072 
7073  /* now we copy all variable and weights to the right order */
7074  for( v = 0; v < norigvars; ++v )
7075  {
7076  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7077  ++(varpointers[cliquepartition[v]]);
7078  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7079  ++(weightpointers[cliquepartition[v]]);
7080  }
7081 #ifndef NDEBUG
7082  for( v = 0; v < norigvars; ++v )
7083  {
7084  assert(vars[v] != NULL);
7085  assert(weights[v] > 0);
7086  }
7087 #endif
7088 
7089  /* free temporary memory */
7090  SCIPfreeBufferArray(scip, &weightpointers);
7091  SCIPfreeBufferArray(scip, &varpointers);
7092  SCIPfreeBufferArray(scip, &cliquecount);
7093 
7094  return SCIP_OKAY;
7095 }
7096 
7097 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7098 static
7100  SCIP* scip, /**< SCIP data structure */
7101  SCIP_CONS* cons, /**< knapsack constraint */
7102  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7103  * information is not needed; in this case, we apply all fixings
7104  * instead of stopping after the first infeasible one */
7105  )
7106 {
7107  SCIP_CONSDATA* consdata;
7108  int v;
7109 
7110  assert(scip != NULL);
7111  assert(cons != NULL);
7112 
7113  consdata = SCIPconsGetData(cons);
7114  assert(consdata != NULL);
7115  assert(consdata->nvars == 0 || consdata->vars != NULL);
7116 
7117  if( cutoff != NULL )
7118  *cutoff = FALSE;
7119 
7120  SCIPdebugMsg(scip, "apply fixings:\n");
7121  SCIPdebugPrintCons(scip, cons, NULL);
7122 
7123  /* check infeasibility */
7124  if ( consdata->onesweightsum > consdata->capacity )
7125  {
7126  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7127 
7128  if( cutoff != NULL )
7129  *cutoff = TRUE;
7130 
7131  return SCIP_OKAY;
7132  }
7133 
7134  /* all multi-aggregations should be resolved */
7135  consdata->existmultaggr = FALSE;
7136 
7137  v = 0;
7138  while( v < consdata->nvars )
7139  {
7140  SCIP_VAR* var;
7141 
7142  var = consdata->vars[v];
7143  assert(SCIPvarIsBinary(var));
7144 
7145  if( SCIPvarGetLbGlobal(var) > 0.5 )
7146  {
7147  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7148  consdata->capacity -= consdata->weights[v];
7149  SCIP_CALL( delCoefPos(scip, cons, v) );
7150  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7151  }
7152  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7153  {
7154  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7155  SCIP_CALL( delCoefPos(scip, cons, v) );
7156  }
7157  else
7158  {
7159  SCIP_VAR* repvar;
7160  SCIP_VAR* negvar;
7161  SCIP_VAR* workvar;
7162  SCIP_Longint weight;
7163  SCIP_Bool negated;
7164 
7165  weight = consdata->weights[v];
7166 
7167  /* get binary representative of variable */
7168  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7169  assert(repvar != NULL);
7170 
7171  /* check for multi-aggregation */
7172  if( SCIPvarIsNegated(repvar) )
7173  {
7174  workvar = SCIPvarGetNegatedVar(repvar);
7175  assert(workvar != NULL);
7176  negated = TRUE;
7177  }
7178  else
7179  {
7180  workvar = repvar;
7181  negated = FALSE;
7182  }
7183 
7184  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7185  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7186  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7187  *
7188  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7189  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7190  *
7191  * The explanation for the following block:
7192  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7193  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7194  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7195  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7196  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7197  * 2) For all replacement variable we check:
7198  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7199  * capacity -= weight * a_i caused by the negation of y_i.
7200  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7201  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7202  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7203  * weight in this case.
7204  */
7205  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7206  {
7207  SCIP_VAR** aggrvars;
7208  SCIP_Real* aggrscalars;
7209  SCIP_Real aggrconst;
7210  int naggrvars;
7211  int i;
7212 
7213  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7214  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7215  aggrvars = SCIPvarGetMultaggrVars(workvar);
7216  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7217  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7218  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7219 
7220  if( !SCIPisIntegral(scip, weight * aggrconst) )
7221  {
7222  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7223  return SCIP_ERROR;
7224  }
7225 
7226  /* if workvar was negated, we have to flip the weight */
7227  if( negated )
7228  weight *= -1;
7229 
7230  for( i = naggrvars - 1; i >= 0; --i )
7231  {
7232  assert(aggrvars != NULL);
7233  assert(aggrscalars != NULL);
7234 
7235  if( !SCIPvarIsBinary(aggrvars[i]) )
7236  {
7237  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7238  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7239  return SCIP_ERROR;
7240  }
7241  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7242  {
7243  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7244  return SCIP_ERROR;
7245  }
7246  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7247  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7248  {
7249  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7250  assert(negvar != NULL);
7251  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7252  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7253  }
7254  else
7255  {
7256  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7257  }
7258  }
7259  /* delete old coefficient */
7260  SCIP_CALL( delCoefPos(scip, cons, v) );
7261 
7262  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7263  if( negated )
7264  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7265  else
7266  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7267 
7268  if( consdata->capacity < 0 )
7269  {
7270  if( cutoff != NULL )
7271  {
7272  *cutoff = TRUE;
7273  break;
7274  }
7275  }
7276  }
7277  /* check, if the variable should be replaced with the representative */
7278  else if( repvar != var )
7279  {
7280  /* delete old (aggregated) variable */
7281  SCIP_CALL( delCoefPos(scip, cons, v) );
7282 
7283  /* add representative instead */
7284  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7285  }
7286  else
7287  ++v;
7288  }
7289  }
7290  assert(consdata->onesweightsum == 0);
7291 
7292  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7293  SCIPdebugPrintCons(scip, cons, NULL);
7294 
7295  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7296  * clean up the constraint
7297  */
7298  if( cutoff != NULL && !(*cutoff) )
7299  {
7300  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7301  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7302  SCIPdebugPrintCons(scip, cons, NULL);
7303  }
7304 
7305  return SCIP_OKAY;
7306 }
7307 
7308 
7309 /** propagation method for knapsack constraints */
7310 static
7312  SCIP* scip, /**< SCIP data structure */
7313  SCIP_CONS* cons, /**< knapsack constraint */
7314  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7315  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7316  int* nfixedvars, /**< pointer to count number of fixings */
7317  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7318  )
7320  SCIP_CONSDATA* consdata;
7321  SCIP_Bool infeasible;
7322  SCIP_Bool tightened;
7323  SCIP_Longint* secondmaxweights;
7324  SCIP_Longint minweightsum;
7325  SCIP_Longint residualcapacity;
7326 
7327  int nvars;
7328  int i;
7329  int nnegcliques;
7330 
7331  SCIP_VAR** myvars;
7332  SCIP_Longint* myweights;
7333  int* cliquestartposs;
7334  int* cliqueendposs;
7335  SCIP_Longint localminweightsum;
7336  SCIP_Bool foundmax;
7337  int c;
7338 
7339  assert(scip != NULL);
7340  assert(cons != NULL);
7341  assert(cutoff != NULL);
7342  assert(redundant != NULL);
7343  assert(nfixedvars != NULL);
7344 
7345  consdata = SCIPconsGetData(cons);
7346  assert(consdata != NULL);
7347 
7348  *cutoff = FALSE;
7349  *redundant = FALSE;
7350 
7351  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7352 
7353  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7354  if( !SCIPinRepropagation(scip) )
7355  {
7356  SCIP_CALL( SCIPincConsAge(scip, cons) );
7357  }
7358 
7359 #ifndef NDEBUG
7360  /* assert that only active or negated variables are present */
7361  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7362  {
7363  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7364  }
7365 #endif
7366 
7367  usenegatedclique = usenegatedclique && consdata->merged;
7368 
7369  /* init for debugging */
7370  myvars = NULL;
7371  myweights = NULL;
7372  cliquestartposs = NULL;
7373  secondmaxweights = NULL;
7374  minweightsum = 0;
7375  nvars = consdata->nvars;
7376  /* make sure, the items are sorted by non-increasing weight */
7377  sortItems(consdata);
7378 
7379  do
7380  {
7381  localminweightsum = 0;
7382 
7383  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7384  * a negated clique means, that at most one of the clique variables can be zero
7385  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7386  *
7387  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7388  * since replacing i with the element of maximal weight leads to infeasibility
7389  */
7390  if( usenegatedclique && nvars > 0 )
7391  {
7392  SCIP_CONSHDLRDATA* conshdlrdata;
7393  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7394  assert(conshdlrdata != NULL);
7395 
7396  /* compute clique partitions */
7397  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7398  nnegcliques = consdata->nnegcliques;
7399 
7400  /* if we have no real negated cliques we can stop here */
7401  if( nnegcliques == nvars )
7402  {
7403  /* run the standard algorithm that does not involve cliques */
7404  usenegatedclique = FALSE;
7405  break;
7406  }
7407 
7408  /* allocate temporary memory and initialize it */
7409  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7410  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7411  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7412  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7413  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7414  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7415 
7416  /* resort variables to avoid quadratic algorithm later on */
7417  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7418 
7419  /* save the end positions of the cliques because start positions are moved in the following loop */
7420  for( c = 0; c < nnegcliques; ++c )
7421  {
7422  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7423  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7424  }
7425 
7426  c = 0;
7427  foundmax = FALSE;
7428  i = 0;
7429 
7430  while( i < nvars )
7431  {
7432  /* ignore variables of the negated clique which are fixed to one since these are counted in
7433  * consdata->onesweightsum
7434  */
7435 
7436  /* if there are only one variable negated cliques left we can stop */
7437  if( nnegcliques - c == nvars - i )
7438  {
7439  minweightsum += localminweightsum;
7440  localminweightsum = 0;
7441  break;
7442  }
7443 
7444  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7445  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7446  * other clique variables to one
7447  */
7448  if( cliquestartposs[c] == i )
7449  {
7450  assert(myweights[i] > 0);
7451  ++c;
7452  minweightsum += localminweightsum;
7453  localminweightsum = 0;
7454  foundmax = TRUE;
7455 
7456  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7457  foundmax = FALSE;
7458 
7459  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7460  {
7461  ++i;
7462  continue;
7463  }
7464  }
7465 
7466  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7467  {
7468  assert(myweights[i] > 0);
7469 
7470  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7471  {
7472  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7473 
7474  if( !foundmax )
7475  {
7476  foundmax = TRUE;
7477 
7478  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7479  cliquestartposs[c - 1] = i;
7480  ++i;
7481 
7482  continue;
7483  }
7484  /* memorize second max weight for each clique */
7485  if( secondmaxweights[c - 1] == 0 )
7486  secondmaxweights[c - 1] = myweights[i];
7487 
7488  localminweightsum += myweights[i];
7489  }
7490  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7491  else
7492  {
7493  int v;
7494  /* fix all other variables of the negated clique to 1 */
7495  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7496  {
7497  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7498  {
7499  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7500  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7501 
7502  if( infeasible )
7503  {
7504  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7505 
7506  /* analyze the infeasibility if conflict analysis is applicable */
7508  {
7509  /* conflict analysis can only be applied in solving stage */
7510  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7511 
7512  /* initialize the conflict analysis */
7514 
7515  /* add the two variables which are fixed to zero within a negated clique */
7516  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7517  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7518 
7519  /* start the conflict analysis */
7520  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7521  }
7522  *cutoff = TRUE;
7523  break;
7524  }
7525  assert(tightened);
7526  ++(*nfixedvars);
7527  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7528  }
7529  }
7530 
7531  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7532  localminweightsum = 0;
7533  /* we can jump to the end of this clique */
7534  i = cliqueendposs[c - 1];
7535 
7536  if( *cutoff )
7537  break;
7538  }
7539  }
7540  ++i;
7541  }
7542  /* add last clique minweightsum */
7543  minweightsum += localminweightsum;
7544 
7545  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7546  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7547 
7548  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7549  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7550  {
7551  SCIP_Longint maxcliqueweight = -1LL;
7552 
7553  /* loop over cliques */
7554  for( c = 0; c < nnegcliques; ++c )
7555  {
7556  SCIP_VAR* maxvar;
7557  SCIP_Bool maxvarfixed;
7558  int endvarposclique;
7559  int startvarposclique;
7560 
7561  assert(myvars != NULL);
7562  assert(nnegcliques == consdata->nnegcliques);
7563  assert(myweights != NULL);
7564  assert(secondmaxweights != NULL);
7565  assert(cliquestartposs != NULL);
7566 
7567  endvarposclique = cliqueendposs[c];
7568  startvarposclique = cliquestartposs[c];
7569 
7570  maxvar = myvars[startvarposclique];
7571 
7572  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7573  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7574  continue;
7575 
7576  maxcliqueweight = myweights[startvarposclique];
7577  maxvarfixed = FALSE;
7578  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7579  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7580  * exceeds the capacity the maximum weight variable can be fixed to zero.
7581  */
7582  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7583  {
7584 #ifndef NDEBUG
7585  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7586 #endif
7587  assert(maxcliqueweight >= secondmaxweights[c]);
7588  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7589 
7590  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7591  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7592  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7593  assert(consdata->onesweightsum == oldonesweightsum);
7594  assert(!infeasible);
7595  assert(tightened);
7596  (*nfixedvars)++;
7597  maxvarfixed = TRUE;
7598  }
7599  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7600  * fits into the knapsack
7601  */
7602  else if( nnegcliques - c == nvars - startvarposclique )
7603  break;
7604  /* early termination of the remaining loop because no further variable fixings are possible:
7605  *
7606  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7607  * largest was set to 0) does not suffice to infer additional variable fixings because
7608  *
7609  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7610  * - their second largest elements are at least as large as the smallest weight of the knapsack
7611  */
7612  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7613  break;
7614 
7615  /* loop over items with non-maximal weight (omitting the first position) */
7616  for( i = endvarposclique; i > startvarposclique; --i )
7617  {
7618  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7619  * messed up the clique preprocessing in the previous loop to filter those variables out */
7620  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7621 
7622  /* only check variables of negated cliques for which no variable is locally fixed */
7623  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7624  {
7625  assert(maxcliqueweight >= myweights[i]);
7626  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7627 
7628  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7629  *
7630  * the maxvar was already fixed to 0 because it has a huge gain.
7631  *
7632  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7633  * since replacing i with the element of maximal weight leads to infeasibility */
7634  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7635  {
7636 #ifndef NDEBUG
7637  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7638 #endif
7639  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7640  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7641  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7642  assert(!infeasible);
7643  assert(tightened);
7644  ++(*nfixedvars);
7645  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7646 
7647  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7648  * consdata->onesweightsum
7649  */
7650  minweightsum -= myweights[i];
7651  assert(minweightsum >= 0);
7652  }
7653  else
7654  break;
7655  }
7656  }
7657 #ifndef NDEBUG
7658  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7659  for( ; i > startvarposclique; --i )
7660  {
7661  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7662  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7663 
7664  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7665  assert(varisfixed || !exceedscapacity);
7666  }
7667 #endif
7668  }
7669  }
7670  SCIPfreeBufferArray(scip, &secondmaxweights);
7671  SCIPfreeBufferArray(scip, &cliqueendposs);
7672  SCIPfreeBufferArray(scip, &cliquestartposs);
7673  SCIPfreeBufferArray(scip, &myweights);
7674  SCIPfreeBufferArray(scip, &myvars);
7675  }
7676 
7677  assert(consdata->negcliquepartitioned || minweightsum == 0);
7678  }
7679  while( FALSE );
7680 
7681  assert(usenegatedclique || minweightsum == 0);
7682  /* check, if weights of fixed variables already exceed knapsack capacity */
7683  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7684  {
7685  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7686  consdata->onesweightsum, consdata->capacity);
7687 
7688  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7689  *cutoff = TRUE;
7690 
7691  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7693  {
7694  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7695  SCIP_Longint weight;
7696 
7697  weight = 0;
7698 
7700 
7701  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7702  {
7703  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7704  {
7705  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7706  weight += consdata->weights[i];
7707  }
7708  }
7709 
7710  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7711  }
7712 
7713  return SCIP_OKAY;
7714  }
7715 
7716  /* the algorithm below is a special case of propagation involving negated cliques */
7717  if( !usenegatedclique )
7718  {
7719  assert(consdata->sorted);
7720  residualcapacity = consdata->capacity - consdata->onesweightsum;
7721 
7722  /* fix all variables to zero, that don't fit into the knapsack anymore */
7723  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7724  {
7725  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7726  * to zero
7727  */
7728  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7729  {
7730  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7731  {
7732  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7733  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7734  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7735  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7736  assert(!infeasible);
7737  assert(tightened);
7738  (*nfixedvars)++;
7739  }
7740  }
7741  }
7742  }
7743 
7744  /* check if the knapsack is now redundant */
7745  if( !SCIPconsIsModifiable(cons) )
7746  {
7747  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7748 
7749  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7750  for( i = 0; i < nvars; ++i )
7751  {
7752  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7753  {
7754  unfixedweightsum += consdata->weights[i];
7755 
7756  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7757  if( unfixedweightsum > consdata->capacity )
7758  return SCIP_OKAY;
7759  }
7760  }
7761  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7762  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7763  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7764  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7765  *redundant = TRUE;
7766  }
7767 
7768  return SCIP_OKAY;
7769 }
7770 
7771 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7772  * containing all negated variables of this knapsack constraint
7773  */
7774 static
7776  SCIP* scip, /**< SCIP data structure */
7777  SCIP_CONS* cons, /**< knapsack constraint */
7778  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7779  int* naddconss /**< pointer to count number of added constraints */
7780  )
7781 {
7782  SCIP_CONS* newcons;
7783  SCIP_CONSDATA* consdata;
7784 
7785  assert(scip != NULL);
7786  assert(cons != NULL);
7787  assert(ndelconss != NULL);
7788  assert(naddconss != NULL);
7789 
7790  consdata = SCIPconsGetData(cons);
7791  assert(consdata != NULL);
7792  assert(consdata->nvars > 1);
7793 
7794  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7795  if( consdata->nvars == 2 )
7796  {
7797  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7798 
7799  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7803  SCIPconsIsStickingAtNode(cons)) );
7804  }
7805  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7806  * containing all negated variables of the knapsack
7807  */
7808  else
7809  {
7810  SCIP_VAR** consvars;
7811 
7812  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7813 
7814  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7815  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7816 
7817  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7821  SCIPconsIsStickingAtNode(cons)) );
7822 
7823  SCIPfreeBufferArray(scip, &consvars);
7824  }
7825 
7826  SCIP_CALL( SCIPaddCons(scip, newcons) );
7827  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7828  ++(*naddconss);
7829 
7830  SCIP_CALL( SCIPdelCons(scip, cons) );
7831  ++(*ndelconss);
7832 
7833  return SCIP_OKAY;
7834 }
7835 
7836 /** delete redundant variables
7837  *
7838  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7839  *
7840  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7841  * => x4, x5 always fits into the knapsack, so we can delete them
7842  *
7843  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7844  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7845  */
7846 static
7848  SCIP* scip, /**< SCIP data structure */
7849  SCIP_CONS* cons, /**< knapsack constraint */
7850  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7851  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7852  * first which did not fit */
7853  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7854  int* nchgsides, /**< pointer to store the amount of changed sides */
7855  int* naddconss /**< pointer to count number of added constraints */
7856  )
7857 {
7858  SCIP_CONSHDLRDATA* conshdlrdata;
7859  SCIP_CONSDATA* consdata;
7860  SCIP_VAR** vars;
7861  SCIP_Longint* weights;
7862  SCIP_Longint capacity;
7863  SCIP_Longint gcd;
7864  int nvars;
7865  int w;
7866 
7867  assert(scip != NULL);
7868  assert(cons != NULL);
7869  assert(nchgcoefs != NULL);
7870  assert(nchgsides != NULL);
7871  assert(naddconss != NULL);
7872 
7873  consdata = SCIPconsGetData(cons);
7874  assert(consdata != NULL);
7875  assert(0 < frontsum && frontsum < consdata->weightsum);
7876  assert(0 < splitpos && splitpos < consdata->nvars);
7877 
7878  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7879  assert(conshdlrdata != NULL);
7880 
7881  vars = consdata->vars;
7882  weights = consdata->weights;
7883  nvars = consdata->nvars;
7884  capacity = consdata->capacity;
7885 
7886  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7887  * weight must not be sorted by their index
7888  */
7889 #ifndef NDEBUG
7890  for( w = nvars - 1; w > 0; --w )
7891  assert(weights[w] <= weights[w-1]);
7892 #endif
7893 
7894  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7895  if( consdata->nvars - 1 == splitpos )
7896  return SCIP_OKAY;
7897 
7898  assert(frontsum + weights[splitpos] > capacity);
7899 
7900  /* detect redundant variables */
7901  if( consdata->weightsum - weights[splitpos] <= capacity )
7902  {
7903  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7904  * fit
7905  */
7906  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7907 
7908  /* delete items and update capacity */
7909  for( w = nvars - 1; w > splitpos; --w )
7910  {
7911  consdata->capacity -= weights[w];
7912  SCIP_CALL( delCoefPos(scip, cons, w) );
7913  }
7914  assert(w == splitpos);
7915 
7916  ++(*nchgsides);
7917  *nchgcoefs += (nvars - splitpos);
7918 
7919  /* division by greatest common divisor */
7920  gcd = weights[w];
7921  for( ; w >= 0 && gcd > 1; --w )
7922  {
7923  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7924  }
7925 
7926  /* normalize if possible */
7927  if( gcd > 1 )
7928  {
7929  for( w = splitpos; w >= 0; --w )
7930  {
7931  consdataChgWeight(consdata, w, weights[w]/gcd);
7932  }
7933  (*nchgcoefs) += nvars;
7934 
7935  consdata->capacity /= gcd;
7936  ++(*nchgsides);
7937  }
7938 
7939  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7940  * weight must not be sorted by their index
7941  */
7942 #ifndef NDEBUG
7943  for( w = consdata->nvars - 1; w > 0; --w )
7944  assert(weights[w] <= weights[w - 1]);
7945 #endif
7946  }
7947  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7948  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7949  * splitpos and needs to fit into the knapsack
7950  */
7951  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7952  {
7953  int* clqpart;
7954  int nclq;
7955  int len;
7956 
7957  len = nvars - (splitpos + 1);
7958  /* allocate temporary memory */
7959  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7960 
7961  /* calculate clique partition */
7962  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7963 
7964  /* check if we found at least one clique */
7965  if( nclq < len )
7966  {
7967  SCIP_Longint maxactduetoclq;
7968  int cliquenum;
7969 
7970  maxactduetoclq = 0;
7971  cliquenum = 0;
7972 
7973  /* calculate maximum activity due to cliques */
7974  for( w = 0; w < len; ++w )
7975  {
7976  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7977  if( clqpart[w] == cliquenum )
7978  {
7979  maxactduetoclq += weights[w + splitpos + 1];
7980  ++cliquenum;
7981  }
7982  }
7983 
7984  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
7985  * so delete them and create for all clique the corresponding clique constraints and update the capacity
7986  */
7987  if( frontsum + maxactduetoclq <= capacity )
7988  {
7989  SCIP_VAR** clqvars;
7990  int nclqvars;
7991  int c;
7992 
7993  assert(maxactduetoclq < weights[splitpos]);
7994 
7995  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
7996 
7997  /* allocate temporary memory */
7998  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
7999 
8000  for( c = 0; c < nclq; ++c )
8001  {
8002  nclqvars = 0;
8003  for( w = 0; w < len; ++w )
8004  {
8005  if( clqpart[w] == c )
8006  {
8007  clqvars[nclqvars] = vars[w + splitpos + 1];
8008  ++nclqvars;
8009  }
8010  }
8011 
8012  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8013  if( nclqvars > 1 )
8014  {
8015  SCIP_CONS* cliquecons;
8016  char name[SCIP_MAXSTRLEN];
8017 
8018  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8019  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8023  SCIPconsIsStickingAtNode(cons)) );
8024  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8025  SCIPdebugPrintCons(scip, cliquecons, NULL);
8026  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8027  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8028  ++(*naddconss);
8029  }
8030  }
8031 
8032  /* delete items and update capacity */
8033  for( w = nvars - 1; w > splitpos; --w )
8034  {
8035  SCIP_CALL( delCoefPos(scip, cons, w) );
8036  ++(*nchgcoefs);
8037  }
8038  consdata->capacity -= maxactduetoclq;
8039  assert(frontsum <= consdata->capacity);
8040  ++(*nchgsides);
8041 
8042  assert(w == splitpos);
8043 
8044  /* renew weights pointer */
8045  weights = consdata->weights;
8046 
8047  /* division by greatest common divisor */
8048  gcd = weights[w];
8049  for( ; w >= 0 && gcd > 1; --w )
8050  {
8051  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8052  }
8053 
8054  /* normalize if possible */
8055  if( gcd > 1 )
8056  {
8057  for( w = splitpos; w >= 0; --w )
8058  {
8059  consdataChgWeight(consdata, w, weights[w]/gcd);
8060  }
8061  (*nchgcoefs) += nvars;
8062 
8063  consdata->capacity /= gcd;
8064  ++(*nchgsides);
8065  }
8066 
8067  /* free temporary memory */
8068  SCIPfreeBufferArray(scip, &clqvars);
8069 
8070  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8071  * weight must not be sorted by their index
8072  */
8073 #ifndef NDEBUG
8074  for( w = consdata->nvars - 1; w > 0; --w )
8075  assert(weights[w] <= weights[w - 1]);
8076 #endif
8077  }
8078  }
8079 
8080  /* free temporary memory */
8081  SCIPfreeBufferArray(scip, &clqpart);
8082  }
8083 
8084  return SCIP_OKAY;
8085 }
8086 
8087 /* detect redundant variables which always fits into the knapsack
8088  *
8089  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8090  *
8091  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8092  * => x4, x5 always fits into the knapsack, so we can delete them
8093  *
8094  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8095  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8096  */
8097 static
8099  SCIP* scip, /**< SCIP data structure */
8100  SCIP_CONS* cons, /**< knapsack constraint */
8101  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8102  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8103  int* nchgsides, /**< pointer to store the amount of changed sides */
8104  int* naddconss /**< pointer to count number of added constraints */
8105  )
8107  SCIP_CONSHDLRDATA* conshdlrdata;
8108  SCIP_CONSDATA* consdata;
8109  SCIP_VAR** vars;
8110  SCIP_Longint* weights;
8111  SCIP_Longint capacity;
8112  SCIP_Longint sum;
8113  int noldchgcoefs;
8114  int nvars;
8115  int v;
8116  int w;
8117 
8118  assert(scip != NULL);
8119  assert(cons != NULL);
8120  assert(ndelconss != NULL);
8121  assert(nchgcoefs != NULL);
8122  assert(nchgsides != NULL);
8123  assert(naddconss != NULL);
8124 
8125  consdata = SCIPconsGetData(cons);
8126  assert(consdata != NULL);
8127  assert(consdata->nvars >= 2);
8128  assert(consdata->weightsum > consdata->capacity);
8129 
8130  noldchgcoefs = *nchgcoefs;
8131  vars = consdata->vars;
8132  weights = consdata->weights;
8133  nvars = consdata->nvars;
8134  capacity = consdata->capacity;
8135  sum = 0;
8136 
8137  /* search for maximal fitting items */
8138  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8139  sum += weights[v];
8140 
8141  assert(v < nvars);
8142 
8143  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8144  if( v == nvars - 1 )
8145  {
8146  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8147  assert(SCIPconsIsDeleted(cons));
8148 
8149  return SCIP_OKAY;
8150  }
8151 
8152  if( v < nvars - 1 )
8153  {
8154  /* try to delete variables */
8155  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8156  assert(consdata->nvars > 1);
8157 
8158  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8159  if( v == consdata->nvars - 1 )
8160  {
8161  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8162  assert(SCIPconsIsDeleted(cons));
8163  }
8164 
8165  return SCIP_OKAY;
8166  }
8167 
8168  /* if we already found some redundant variables, stop here */
8169  if( *nchgcoefs > noldchgcoefs )
8170  return SCIP_OKAY;
8171 
8172  assert(vars == consdata->vars);
8173  assert(weights == consdata->weights);
8174  assert(nvars == consdata->nvars);
8175  assert(capacity == consdata->capacity);
8176 
8177  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8178  assert(conshdlrdata != NULL);
8179  /* calculate clique partition */
8180  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8181 
8182  /* check for real existing cliques */
8183  if( consdata->cliquepartition[v] < v )
8184  {
8185  SCIP_Longint sumfront;
8186  SCIP_Longint maxactduetoclqfront;
8187  int* clqpart;
8188  int cliquenum;
8189 
8190  sumfront = 0;
8191  maxactduetoclqfront = 0;
8192 
8193  clqpart = consdata->cliquepartition;
8194  cliquenum = 0;
8195 
8196  /* calculate maximal activity due to cliques */
8197  for( w = 0; w < nvars; ++w )
8198  {
8199  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8200  if( clqpart[w] == cliquenum )
8201  {
8202  if( maxactduetoclqfront + weights[w] <= capacity )
8203  {
8204  maxactduetoclqfront += weights[w];
8205  ++cliquenum;
8206  }
8207  else
8208  break;
8209  }
8210  sumfront += weights[w];
8211  }
8212  assert(w >= v);
8213 
8214  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8215  * information
8216  */
8217  if( conshdlrdata->disaggregation && w == nvars )
8218  {
8219  SCIP_VAR** clqvars;
8220  int nclqvars;
8221  int c;
8222  int ncliques;
8223 
8224  assert(maxactduetoclqfront <= capacity);
8225 
8226  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8227 
8228  ncliques = consdata->ncliques;
8229 
8230  /* allocate temporary memory */
8231  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8232 
8233  for( c = 0; c < ncliques; ++c )
8234  {
8235  nclqvars = 0;
8236  for( w = 0; w < nvars; ++w )
8237  {
8238  if( clqpart[w] == c )
8239  {
8240  clqvars[nclqvars] = vars[w];
8241  ++nclqvars;
8242  }
8243  }
8244 
8245  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8246  if( nclqvars > 1 )
8247  {
8248  SCIP_CONS* cliquecons;
8249  char name[SCIP_MAXSTRLEN];
8250 
8251  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8252  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8256  SCIPconsIsStickingAtNode(cons)) );
8257  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8258  SCIPdebugPrintCons(scip, cliquecons, NULL);
8259  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8260  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8261  ++(*naddconss);
8262  }
8263  }
8264 
8265  /* delete old constraint */
8266  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8267  ++(*ndelconss);
8268 
8269  SCIPfreeBufferArray(scip, &clqvars);
8270 
8271  return SCIP_OKAY;
8272  }
8273 
8274  if( w > v && w < nvars - 1 )
8275  {
8276  /* try to delete variables */
8277  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8278  }
8279  }
8280 
8281  return SCIP_OKAY;
8282 }
8283 
8284 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8285 static
8286 void normalizeWeights(
8287  SCIP_CONS* cons, /**< knapsack constraint */
8288  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8289  int* nchgsides /**< pointer to count number of side changes */
8290  )
8291 {
8292  SCIP_CONSDATA* consdata;
8293  SCIP_Longint gcd;
8294  int i;
8295 
8296  assert(nchgcoefs != NULL);
8297  assert(nchgsides != NULL);
8298  assert(!SCIPconsIsModifiable(cons));
8299 
8300  consdata = SCIPconsGetData(cons);
8301  assert(consdata != NULL);
8302  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8303  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8304  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8305  assert(consdata->nvars >= 1);
8306 
8307  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8308  sortItems(consdata);
8309 
8310  gcd = consdata->weights[consdata->nvars-1];
8311  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8312  {
8313  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8314  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8315 
8316  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8317  }
8318 
8319  if( gcd >= 2 )
8320  {
8321  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8322 
8323  for( i = 0; i < consdata->nvars; ++i )
8324  {
8325  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8326  }
8327  consdata->capacity /= gcd;
8328  (*nchgcoefs) += consdata->nvars;
8329  (*nchgsides)++;
8330 
8331  /* weight should still be sorted, because the reduction preserves this */
8332 #ifndef NDEBUG
8333  for( i = consdata->nvars - 1; i > 0; --i )
8334  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8335 #endif
8336  consdata->sorted = TRUE;
8337  }
8338 }
8339 
8340 /** dual weights tightening for knapsack constraints
8341  *
8342  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8343  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8344  * constraint
8345  *
8346  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8347  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8348  *
8349  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8350  *
8351  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8352  *
8353  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8354  *
8355  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8356  *
8357  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8358  */
8359 static
8361  SCIP* scip, /**< SCIP data structure */
8362  SCIP_CONS* cons, /**< knapsack constraint */
8363  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8364  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8365  int* nchgsides, /**< pointer to store the amount of changed sides */
8366  int* naddconss /**< pointer to count number of added constraints */
8367  )
8369  SCIP_CONSDATA* consdata;
8370  SCIP_Longint* weights;
8371  SCIP_Longint dualcapacity;
8372  SCIP_Longint reductionsum;
8373  SCIP_Longint capacity;
8374  SCIP_Longint exceedsum;
8375  int oldnchgcoefs;
8376  int nvars;
8377  int vbig;
8378  int v;
8379  int w;
8380 #ifndef NDEBUG
8381  int oldnchgsides;
8382 #endif
8383 
8384  assert(scip != NULL);
8385  assert(cons != NULL);
8386  assert(ndelconss != NULL);
8387  assert(nchgcoefs != NULL);
8388  assert(nchgsides != NULL);
8389  assert(naddconss != NULL);
8390 
8391 #ifndef NDEBUG
8392  oldnchgsides = *nchgsides;
8393 #endif
8394 
8395  consdata = SCIPconsGetData(cons);
8396  assert(consdata != NULL);
8397  assert(consdata->weightsum > consdata->capacity);
8398  assert(consdata->nvars >= 2);
8399  assert(consdata->sorted);
8400 
8401  /* constraint should be merged */
8402  assert(consdata->merged);
8403 
8404  nvars = consdata->nvars;
8405  weights = consdata->weights;
8406  capacity = consdata->capacity;
8407 
8408  oldnchgcoefs = *nchgcoefs;
8409 
8410  /* case 1. */
8411  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8412  {
8413  SCIP_CONS* newcons;
8414 
8415  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8416  *
8417  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8418  */
8419  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8420 
8421  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8425  SCIPconsIsStickingAtNode(cons)) );
8426 
8427  SCIP_CALL( SCIPaddCons(scip, newcons) );
8428  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8429  ++(*naddconss);
8430 
8431  SCIP_CALL( SCIPdelCons(scip, cons) );
8432  ++(*ndelconss);
8433 
8434  return SCIP_OKAY;
8435  }
8436 
8437  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8438  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8439  {
8440  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8441  assert(SCIPconsIsDeleted(cons));
8442 
8443  return SCIP_OKAY;
8444  }
8445 
8446  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8447  /* @todo might be changed/removed when improving the coeffcients tightening */
8448  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8449  return SCIP_OKAY;
8450 
8451  /* case 2. */
8452 
8453  v = 0;
8454 
8455  /* @todo generalize the following algorithm for several parts of the knapsack
8456  *
8457  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8458  * variables each combination is a minimal cover, some examples
8459  *
8460  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8461  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8462  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8463  *
8464  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8465  *
8466  */
8467 
8468  /* determine big weights that fit only by itself */
8469  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8470  ++v;
8471 
8472  vbig = v;
8473  assert(vbig < nvars - 1);
8474  exceedsum = 0;
8475 
8476  /* determine the amount needed to exceed the capacity */
8477  while( v < nvars && exceedsum <= capacity )
8478  {
8479  exceedsum += weights[v];
8480  ++v;
8481  }
8482 
8483  /* if we exceeded the capacity we might reduce the weights */
8484  if( exceedsum > capacity )
8485  {
8486  assert(vbig > 0 || v < nvars);
8487 
8488  /* all small weights were needed to exceed the capacity */
8489  if( v == nvars )
8490  {
8491  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8492  assert(newweight > 0);
8493 
8494  /* reduce big weights */
8495  for( v = 0; v < vbig; ++v )
8496  {
8497  if( weights[v] > newweight )
8498  {
8499  consdataChgWeight(consdata, v, newweight);
8500  ++(*nchgcoefs);
8501  }
8502  }
8503 
8504  /* reduce small weights */
8505  for( ; v < nvars; ++v )
8506  {
8507  if( weights[v] > 1 )
8508  {
8509  consdataChgWeight(consdata, v, 1LL);
8510  ++(*nchgcoefs);
8511  }
8512  }
8513 
8514  consdata->capacity = newweight;
8515 
8516  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8517  * weight must not be sorted by their index
8518  */
8519 #ifndef NDEBUG
8520  for( v = nvars - 1; v > 0; --v )
8521  assert(weights[v] <= weights[v-1]);
8522 #endif
8523 
8524  return SCIP_OKAY;
8525  }
8526  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8527  * small weights
8528  */
8529  else
8530  {
8531  SCIP_Longint exceedsumback = 0;
8532  int nexceed = v - vbig;
8533 
8534  assert(nexceed > 1);
8535 
8536  /* determine weightsum of the same amount as before but of the smallest weight */
8537  for( w = nvars - 1; w >= nvars - nexceed; --w )
8538  exceedsumback += weights[w];
8539 
8540  assert(w >= 0);
8541 
8542  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8543  * combinations of all small weights
8544  */
8545  if( exceedsumback > capacity )
8546  {
8547  SCIP_Longint newweight = nexceed - 1;
8548 
8549  /* taking out the smallest element needs to fit */
8550  assert(exceedsumback - weights[nvars - 1] <= capacity);
8551 
8552  /* reduce big weights */
8553  for( v = 0; v < vbig; ++v )
8554  {
8555  if( weights[v] > newweight )
8556  {
8557  consdataChgWeight(consdata, v, newweight);
8558  ++(*nchgcoefs);
8559  }
8560  }
8561 
8562  /* reduce small weights */
8563  for( ; v < nvars; ++v )
8564  {
8565  if( weights[v] > 1 )
8566  {
8567  consdataChgWeight(consdata, v, 1LL);
8568  ++(*nchgcoefs);
8569  }
8570  }
8571 
8572  consdata->capacity = newweight;
8573 
8574  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8575  * weight must not be sorted by their index
8576  */
8577 #ifndef NDEBUG
8578  for( v = nvars - 1; v > 0; --v )
8579  assert(weights[v] <= weights[v-1]);
8580 #endif
8581  return SCIP_OKAY;
8582  }
8583  }
8584  }
8585  else
8586  {
8587  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8588  * not happen here
8589  */
8590  assert(vbig > 0 && vbig < nvars);
8591 
8592  /* either choose a big coefficients or all other variables
8593  *
8594  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8595  *
8596  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8597  * constraint to
8598  *
8599  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8600  */
8601 
8602  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8603  {
8604  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8605 #ifndef NDEBUG
8606  SCIP_Longint resweightsum = consdata->weightsum;
8607 
8608  for( v = 0; v < vbig; ++v )
8609  resweightsum -= weights[v];
8610 
8611  assert(exceedsum == resweightsum);
8612 #endif
8613  assert(newweight > 0);
8614 
8615  /* reduce big weights */
8616  for( v = 0; v < vbig; ++v )
8617  {
8618  if( weights[v] > newweight )
8619  {
8620  consdataChgWeight(consdata, v, newweight);
8621  ++(*nchgcoefs);
8622  }
8623  }
8624 
8625  /* reduce small weights */
8626  for( ; v < nvars; ++v )
8627  {
8628  if( weights[v] > 1 )
8629  {
8630  consdataChgWeight(consdata, v, 1LL);
8631  ++(*nchgcoefs);
8632  }
8633  }
8634 
8635  consdata->capacity = newweight;
8636 
8637  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8638  * weight must not be sorted by their index
8639  */
8640 #ifndef NDEBUG
8641  for( v = nvars - 1; v > 0; --v )
8642  assert(weights[v] <= weights[v-1]);
8643 #endif
8644  return SCIP_OKAY;
8645  }
8646  }
8647 
8648  /* case 3. */
8649 
8650  dualcapacity = consdata->weightsum - capacity;
8651  reductionsum = 0;
8652  v = 0;
8653 
8654  /* reduce big weights
8655  *
8656  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8657  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8658  * <=> x0 + x1 + x2 + x3 <= 3
8659  */
8660  while( weights[v] > dualcapacity )
8661  {
8662  reductionsum += (weights[v] - dualcapacity);
8663  consdataChgWeight(consdata, v, dualcapacity);
8664  ++v;
8665  assert(v < nvars);
8666  }
8667  (*nchgcoefs) += v;
8668 
8669  /* skip weights equal to the dualcapacity, because we cannot change them */
8670  while( v < nvars && weights[v] == dualcapacity )
8671  ++v;
8672 
8673  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8674  * after a possible removal of the last, redundant item
8675  *
8676  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8677  */
8678  if( v >= nvars - 1 )
8679  {
8680  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8681  if( v == nvars - 1 )
8682  {
8683  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8684  }
8685  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8686  assert(SCIPconsIsDeleted(cons));
8687 
8688  return SCIP_OKAY;
8689  }
8690  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8691  {
8692  /* @todo generalize the following algorithm for more than two variables */
8693 
8694  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8695  {
8696  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8697  * coefficients) of all or two variables of the rest
8698  *
8699  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8700  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8701  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8702  *
8703  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8704  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8705  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8706  *
8707  */
8708  if( v > 0 && weights[nvars - 2] > 1 )
8709  {
8710  int ncoefchg = 0;
8711 
8712  /* reduce all bigger weights */
8713  for( w = 0; w < v; ++w )
8714  {
8715  if( weights[w] > 2 )
8716  {
8717  consdataChgWeight(consdata, w, 2LL);
8718  ++ncoefchg;
8719  }
8720  else
8721  {
8722  assert(weights[0] == 2);
8723  assert(weights[v - 1] == 2);
8724  break;
8725  }
8726  }
8727 
8728  /* reduce all smaller weights */
8729  for( w = v; w < nvars; ++w )
8730  {
8731  if( weights[w] > 1 )
8732  {
8733  consdataChgWeight(consdata, w, 1LL);
8734  ++ncoefchg;
8735  }
8736  }
8737  assert(ncoefchg > 0);
8738 
8739  (*nchgcoefs) += ncoefchg;
8740 
8741  /* correct the capacity */
8742  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8743  assert(consdata->capacity > 0);
8744  assert(weights[0] <= consdata->capacity);
8745  assert(consdata->weightsum > consdata->capacity);
8746  /* reset the reductionsum */
8747  reductionsum = 0;
8748  }
8749  else if( v == 0 )
8750  {
8751  assert(weights[nvars - 2] == 1);
8752  }
8753  }
8754  else
8755  {
8756  SCIP_Longint minweight = weights[nvars - 1];
8757  SCIP_Longint newweight = dualcapacity - minweight;
8758  SCIP_Longint restsumweights = 0;
8759  SCIP_Longint sumcoef;
8760  SCIP_Bool sumcoefcase = FALSE;
8761  int startv = v;
8762  int end;
8763  int k;
8764 
8765  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8766 
8767  /* reduce big weights of pairs that exceed the dualcapacity
8768  *
8769  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8770  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8771  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8772  */
8773  while( weights[v] > newweight )
8774  {
8775  reductionsum += (weights[v] - newweight);
8776  consdataChgWeight(consdata, v, newweight);
8777  ++v;
8778  assert(v < nvars);
8779  }
8780  (*nchgcoefs) += (v - startv);
8781 
8782  /* skip equal weights */
8783  while( weights[v] == newweight )
8784  ++v;
8785 
8786  if( v > 0 )
8787  {
8788  for( w = v; w < nvars; ++w )
8789  restsumweights += weights[w];
8790  }
8791  else
8792  restsumweights = consdata->weightsum;
8793 
8794  if( restsumweights < dualcapacity )
8795  {
8796  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8797  *
8798  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8799  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8800  */
8801  if( startv == v )
8802  {
8803  /* remove redundant variables */
8804  for( w = nvars - 1; w >= v; --w )
8805  {
8806  SCIP_CALL( delCoefPos(scip, cons, v) );
8807  ++(*nchgcoefs);
8808  }
8809 
8810 #ifndef NDEBUG
8811  /* each coefficients should exceed the dualcapacity by itself */
8812  for( ; w >= 0; --w )
8813  assert(weights[w] == dualcapacity);
8814 #endif
8815  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8816  * upgrade this constraint
8817  */
8818  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8819  assert(SCIPconsIsDeleted(cons));
8820 
8821  return SCIP_OKAY;
8822  }
8823 
8824  /* special case where we have three different coefficient types
8825  *
8826  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8827  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8828  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8829  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8830  */
8831  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8832  {
8833  SCIP_Longint newcap;
8834 
8835  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8836  for( w = nvars - 1; w >= v; --w )
8837  {
8838  if( weights[w] > 1 )
8839  {
8840  consdataChgWeight(consdata, w, 1LL);
8841  ++(*nchgcoefs);
8842  }
8843  }
8844 
8845  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8846  * dualcapacity
8847  */
8848  newweight = (SCIP_Longint)nvars - v;
8849  assert(newweight > 1);
8850  for( ; w >= startv; --w )
8851  {
8852  if( weights[w] > newweight )
8853  {
8854  consdataChgWeight(consdata, w, newweight);
8855  ++(*nchgcoefs);
8856  }
8857  else
8858  assert(weights[w] == newweight);
8859  }
8860 
8861  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8862  ++newweight;
8863  assert(newweight > 2);
8864  for( ; w >= 0; --w )
8865  {
8866  if( weights[w] > newweight )
8867  {
8868  consdataChgWeight(consdata, w, newweight);
8869  ++(*nchgcoefs);
8870  }
8871  else
8872  assert(weights[w] == newweight);
8873  }
8874 
8875  /* update the capacity */
8876  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8877  if( consdata->capacity > newcap )
8878  {
8879  consdata->capacity = newcap;
8880  ++(*nchgsides);
8881  }
8882  else
8883  assert(consdata->capacity == newcap);
8884  }
8885  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8886 
8887  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8888  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8889 
8890  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8891  * weight must not be sorted by their index
8892  */
8893 #ifndef NDEBUG
8894  for( w = nvars - 1; w > 0; --w )
8895  assert(weights[w] <= weights[w - 1]);
8896 #endif
8897  return SCIP_OKAY;
8898  }
8899 
8900  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8901  end = nvars - 2;
8902  while( end >= 0 && weights[end] == weights[end + 1] )
8903  {
8904  assert(end >= v);
8905  --end;
8906  }
8907 
8908  if( v >= end )
8909  goto TERMINATE;
8910 
8911  end = nvars - 2;
8912 
8913  /* can we stop early, another special reduction case might exist */
8914  if( 2 * weights[end] > dualcapacity )
8915  {
8916  restsumweights = 0;
8917 
8918  /* determine capacity of the small items */
8919  for( w = end + 1; w < nvars; ++w )
8920  restsumweights += weights[w];
8921 
8922  if( restsumweights * 2 <= dualcapacity )
8923  {
8924  /* check for further posssible reductions in the middle */
8925  while( v < end && restsumweights + weights[v] >= dualcapacity )
8926  ++v;
8927 
8928  if( v >= end )
8929  goto TERMINATE;
8930 
8931  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8932  if( (dualcapacity & 1) == 0 )
8933  {
8934  newweight = dualcapacity / 2;
8935 
8936  /* set all middle coefficients */
8937  for( ; v <= end; ++v )
8938  {
8939  if( weights[v] > newweight )
8940  {
8941  reductionsum += (weights[v] - newweight);
8942  consdataChgWeight(consdata, v, newweight);
8943  ++(*nchgcoefs);
8944  }
8945  }
8946  }
8947  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8948  * other coefficients by 2
8949  */
8950  else
8951  {
8952  /* correct the reductionsum */
8953  reductionsum *= 2;
8954 
8955  /* multiply big coefficients by 2 */
8956  for( w = 0; w < v; ++w )
8957  {
8958  consdataChgWeight(consdata, w, weights[w] * 2);
8959  }
8960 
8961  newweight = dualcapacity;
8962  /* set all middle coefficients */
8963  for( ; v <= end; ++v )
8964  {
8965  reductionsum += (2 * weights[v] - newweight);
8966  consdataChgWeight(consdata, v, newweight);
8967  }
8968 
8969  /* multiply small coefficients by 2 */
8970  for( w = end + 1; w < nvars; ++w )
8971  {
8972  consdataChgWeight(consdata, w, weights[w] * 2);
8973  }
8974  (*nchgcoefs) += nvars;
8975 
8976  dualcapacity *= 2;
8977  consdata->capacity *= 2;
8978  ++(*nchgsides);
8979  }
8980  }
8981 
8982  goto TERMINATE;
8983  }
8984 
8985  /* further reductions using the next possible coefficient sum
8986  *
8987  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
8988  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
8989  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
8990  */
8991  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
8992  for( k = 0; k < 4; ++k )
8993  {
8994  /* determine next minimal coefficient sum */
8995  switch( k )
8996  {
8997  case 0:
8998  sumcoef = weights[nvars - 1] + weights[nvars - 2];
8999  break;
9000  case 1:
9001  assert(nvars >= 3);
9002  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9003  break;
9004  case 2:
9005  assert(nvars >= 4);
9006  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9007  {
9008  sumcoefcase = TRUE;
9009  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9010  }
9011  else
9012  {
9013  sumcoefcase = FALSE;
9014  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9015  }
9016  break;
9017  case 3:
9018  assert(nvars >= 5);
9019  if( sumcoefcase )
9020  {
9021  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9022  }
9023  else
9024  {
9025  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9026  }
9027  break;
9028  default:
9029  return SCIP_ERROR;
9030  }
9031 
9032  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9033  minweight = weights[end];
9034  while( minweight <= sumcoef )
9035  {
9036  newweight = dualcapacity - minweight;
9037  startv = v;
9038  assert(v < nvars);
9039 
9040  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9041  /* shrink big coefficients */
9042  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9043  {
9044  reductionsum += (weights[v] - newweight);
9045  consdataChgWeight(consdata, v, newweight);
9046  ++v;
9047  assert(v < nvars);
9048  }
9049  (*nchgcoefs) += (v - startv);
9050 
9051  /* skip unchangable weights */
9052  while( weights[v] + minweight == dualcapacity )
9053  {
9054  assert(v < nvars);
9055  ++v;
9056  }
9057 
9058  --end;
9059  /* skip same end weights */
9060  while( end >= 0 && weights[end] == weights[end + 1] )
9061  --end;
9062 
9063  if( v >= end )
9064  goto TERMINATE;
9065 
9066  minweight = weights[end];
9067  }
9068 
9069  if( v >= end )
9070  goto TERMINATE;
9071 
9072  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9073  if( sumcoef < minweight )
9074  {
9075  minweight = sumcoef;
9076  newweight = dualcapacity - minweight;
9077  startv = v;
9078  assert(v < nvars);
9079 
9080  /* shrink big coefficients */
9081  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9082  {
9083  reductionsum += (weights[v] - newweight);
9084  consdataChgWeight(consdata, v, newweight);
9085  ++v;
9086  assert(v < nvars);
9087  }
9088  (*nchgcoefs) += (v - startv);
9089 
9090  /* skip unchangable weights */
9091  while( weights[v] + minweight == dualcapacity )
9092  {
9093  assert(v < nvars);
9094  ++v;
9095  }
9096  }
9097 
9098  if( v >= end )
9099  goto TERMINATE;
9100 
9101  /* can we stop early, another special reduction case might exist */
9102  if( 2 * weights[end] > dualcapacity )
9103  {
9104  restsumweights = 0;
9105 
9106  /* determine capacity of the small items */
9107  for( w = end + 1; w < nvars; ++w )
9108  restsumweights += weights[w];
9109 
9110  if( restsumweights * 2 <= dualcapacity )
9111  {
9112  /* check for further posssible reductions in the middle */
9113  while( v < end && restsumweights + weights[v] >= dualcapacity )
9114  ++v;
9115 
9116  if( v >= end )
9117  goto TERMINATE;
9118 
9119  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9120  if( (dualcapacity & 1) == 0 )
9121  {
9122  newweight = dualcapacity / 2;
9123 
9124  /* set all middle coefficients */
9125  for( ; v <= end; ++v )
9126  {
9127  if( weights[v] > newweight )
9128  {
9129  reductionsum += (weights[v] - newweight);
9130  consdataChgWeight(consdata, v, newweight);
9131  ++(*nchgcoefs);
9132  }
9133  }
9134  }
9135  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9136  * other coefficients by 2
9137  */
9138  else
9139  {
9140  /* correct the reductionsum */
9141  reductionsum *= 2;
9142 
9143  /* multiply big coefficients by 2 */
9144  for( w = 0; w < v; ++w )
9145  {
9146  consdataChgWeight(consdata, w, weights[w] * 2);
9147  }
9148 
9149  newweight = dualcapacity;
9150  /* set all middle coefficients */
9151  for( ; v <= end; ++v )
9152  {
9153  reductionsum += (2 * weights[v] - newweight);
9154  consdataChgWeight(consdata, v, newweight);
9155  }
9156 
9157  /* multiply small coefficients by 2 */
9158  for( w = end + 1; w < nvars; ++w )
9159  {
9160  consdataChgWeight(consdata, w, weights[w] * 2);
9161  }
9162  (*nchgcoefs) += nvars;
9163 
9164  dualcapacity *= 2;
9165  consdata->capacity *= 2;
9166  ++(*nchgsides);
9167  }
9168  }
9169 
9170  goto TERMINATE;
9171  }
9172 
9173  /* cannot tighten any further */
9174  if( 2 * sumcoef > dualcapacity )
9175  goto TERMINATE;
9176  }
9177  }
9178  }
9179 
9180  TERMINATE:
9181  /* correct capacity */
9182  if( reductionsum > 0 )
9183  {
9184  assert(v > 0);
9185 
9186  consdata->capacity -= reductionsum;
9187  ++(*nchgsides);
9188 
9189  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9190  }
9191  assert(weights[0] <= consdata->capacity);
9192 
9193  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9194  * weight must not be sorted by their index
9195  */
9196 #ifndef NDEBUG
9197  for( w = nvars - 1; w > 0; --w )
9198  assert(weights[w] <= weights[w - 1]);
9199 #endif
9200 
9201  if( oldnchgcoefs < *nchgcoefs )
9202  {
9203  assert(!SCIPconsIsDeleted(cons));
9204 
9205  /* it might be that we can divide the weights by their greatest common divisor */
9206  normalizeWeights(cons, nchgcoefs, nchgsides);
9207  }
9208  else
9209  {
9210  assert(oldnchgcoefs == *nchgcoefs);
9211  assert(oldnchgsides == *nchgsides);
9212  }
9213 
9214  return SCIP_OKAY;
9215 }
9216 
9217 
9218 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9219 static
9221  SCIP* scip, /**< SCIP data structure */
9222  SCIP_CONS* cons, /**< knapsack constraint */
9223  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9224  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9225  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9226  )
9227 {
9228  SCIP_VAR** vars;
9229  SCIP_CONSDATA* consdata;
9230  SCIP_Longint* weights;
9231  SCIP_Longint capacity;
9232  SCIP_Bool infeasible;
9233  SCIP_Bool fixed;
9234  int nvars;
9235  int v;
9236 
9237  assert(scip != NULL);
9238  assert(cons != NULL);
9239  assert(nfixedvars != NULL);
9240  assert(ndelconss != NULL);
9241  assert(nchgcoefs != NULL);
9242 
9243  consdata = SCIPconsGetData(cons);
9244  assert(consdata != NULL);
9245 
9246  nvars = consdata->nvars;
9247 
9248  /* no variables left, then delete constraint */
9249  if( nvars == 0 )
9250  {
9251  assert(consdata->capacity >= 0);
9252 
9253  SCIP_CALL( SCIPdelCons(scip, cons) );
9254  ++(*ndelconss);
9255 
9256  return SCIP_OKAY;
9257  }
9258 
9259  /* sort items */
9260  sortItems(consdata);
9261 
9262  vars = consdata->vars;
9263  weights = consdata->weights;
9264  capacity = consdata->capacity;
9265  v = 0;
9266 
9267  /* check for weights bigger than the capacity */
9268  while( v < nvars && weights[v] > capacity )
9269  {
9270  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9271  assert(!infeasible);
9272 
9273  if( fixed )
9274  ++(*nfixedvars);
9275 
9276  ++v;
9277  }
9278 
9279  /* if we fixed at least one variable we need to delete them from the constraint */
9280  if( v > 0 )
9281  {
9282  if( v == nvars )
9283  {
9284  SCIP_CALL( SCIPdelCons(scip, cons) );
9285  ++(*ndelconss);
9286 
9287  return SCIP_OKAY;
9288  }
9289 
9290  /* delete all position from back to front */
9291  for( --v; v >= 0; --v )
9292  {
9293  SCIP_CALL( delCoefPos(scip, cons, v) );
9294  ++(*nchgcoefs);
9295  }
9296 
9297  /* sort items again because of deletion */
9298  sortItems(consdata);
9299  assert(vars == consdata->vars);
9300  assert(weights == consdata->weights);
9301  }
9302  assert(consdata->sorted);
9303  assert(weights[0] <= capacity);
9304 
9305  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9306  {
9307  SCIP_CALL( SCIPdelCons(scip, cons) );
9308  ++(*ndelconss);
9309  }
9310 
9311  return SCIP_OKAY;
9312 }
9313 
9314 
9315 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9316  *
9317  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9318  *
9319  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9320  *
9321  * the above constraint can be changed to
9322  *
9323  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9324  *
9325  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9326  *
9327  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9328  *
9329  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9330  * constraint further, e.g.
9331  *
9332  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9333  * => 2x1 + x2 + x3 + x4 <= 2
9334  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9335  */
9336 static
9338  SCIP* scip, /**< SCIP data structure */
9339  SCIP_CONS* cons, /**< knapsack constraint */
9340  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9341  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9342  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9343  int* nchgsides, /**< pointer to store the amount of changed sides */
9344  int* naddconss, /**< pointer to count number of added constraints */
9345  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9346  )
9347 {
9348  SCIP_VAR** vars;
9349  SCIP_CONSDATA* consdata;
9350  SCIP_Longint* weights;
9351  SCIP_Longint restweight;
9352  SCIP_Longint newweight;
9353  SCIP_Longint weight;
9354  SCIP_Longint oldgcd;
9355  SCIP_Longint rest;
9356  SCIP_Longint gcd;
9357  int oldnchgcoefs;
9358  int oldnchgsides;
9359  int candpos;
9360  int candpos2;
9361  int offsetv;
9362  int nvars;
9363  int v;
9364 
9365  assert(scip != NULL);
9366  assert(cons != NULL);
9367  assert(nfixedvars != NULL);
9368  assert(ndelconss != NULL);
9369  assert(nchgcoefs != NULL);
9370  assert(nchgsides != NULL);
9371  assert(naddconss != NULL);
9372  assert(cutoff != NULL);
9373  assert(!SCIPconsIsModifiable(cons));
9374 
9375  consdata = SCIPconsGetData(cons);
9376  assert( consdata != NULL );
9377 
9378  *cutoff = FALSE;
9379 
9380  /* remove double enties and also combinations of active and negated variables */
9381  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9382  assert(consdata->merged);
9383  if( *cutoff )
9384  return SCIP_OKAY;
9385 
9386  assert(consdata->capacity >= 0);
9387 
9388  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9389  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9390 
9391  if( SCIPconsIsDeleted(cons) )
9392  return SCIP_OKAY;
9393 
9394  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9395  {
9396  /* 1. dual weights tightening */
9397  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9398 
9399  if( SCIPconsIsDeleted(cons) )
9400  return SCIP_OKAY;
9401  /* 2. delete redundant variables */
9402  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9403 
9404  if( SCIPconsIsDeleted(cons) )
9405  return SCIP_OKAY;
9406  }
9407 
9408  weights = consdata->weights;
9409  nvars = consdata->nvars;
9410 
9411 #ifndef NDEBUG
9412  /* constraint might not be sorted, but the weights are already sorted */
9413  for( v = nvars - 1; v > 0; --v )
9414  assert(weights[v] <= weights[v-1]);
9415 #endif
9416 
9417  /* determine greatest common divisor */
9418  gcd = weights[nvars - 1];
9419  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9420  {
9421  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9422  }
9423 
9424  /* divide the constraint by their greatest common divisor */
9425  if( gcd >= 2 )
9426  {
9427  for( v = nvars - 1; v >= 0; --v )
9428  {
9429  consdataChgWeight(consdata, v, weights[v]/gcd);
9430  }
9431  (*nchgcoefs) += nvars;
9432 
9433  consdata->capacity /= gcd;
9434  (*nchgsides)++;
9435  }
9436  assert(consdata->nvars == nvars);
9437 
9438  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9439  * must not be sorted by their index
9440  */
9441 #ifndef NDEBUG
9442  for( v = nvars - 1; v > 0; --v )
9443  assert(weights[v] <= weights[v-1]);
9444 #endif
9445 
9446  /* 3. start gcd procedure for all variables */
9447  do
9448  {
9449  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9450  SCIPdebug( oldnchgsides = *nchgsides; )
9451 
9452  vars = consdata->vars;
9453  weights = consdata->weights;
9454  nvars = consdata->nvars;
9455 
9456  /* stop if we have two coefficients which are one in absolute value */
9457  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9458  return SCIP_OKAY;
9459 
9460  v = 0;
9461  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9462  * gcd
9463  */
9464  while( weights[v] == consdata->capacity )
9465  {
9466  ++v;
9467  assert(v < nvars);
9468  }
9469 
9470  /* all but one variable are as big as the capacity, this is handled elsewhere */
9471  if( v == nvars - 1 )
9472  return SCIP_OKAY;
9473 
9474  offsetv = v;
9475 
9476  gcd = -1;
9477  candpos = -1;
9478  candpos2 = -1;
9479 
9480  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9481  * change the coefficient
9482  */
9483  for( v = nvars - 1; v >= offsetv; --v )
9484  {
9485  weight = weights[v];
9486  assert(weight >= 1);
9487 
9488  oldgcd = gcd;
9489 
9490  if( gcd == -1 )
9491  {
9492  gcd = weights[v];
9493  assert(gcd >= 1);
9494  }
9495  else
9496  {
9497  /* calculate greatest common divisor for all variables */
9498  gcd = SCIPcalcGreComDiv(gcd, weight);
9499  }
9500 
9501  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9502  * can terminate
9503  */
9504  if( gcd == 1 )
9505  {
9506  /* found candidate */
9507  if( candpos == -1 )
9508  {
9509  gcd = oldgcd;
9510  candpos = v;
9511 
9512  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9513  if( v == nvars - 2 )
9514  candpos2 = v + 1;
9515  }
9516  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9517  else
9518  {
9519  if( candpos == v + 1 && candpos2 == v + 2 )
9520  {
9521  assert(candpos2 == nvars - 1);
9522 
9523  /* take new candidates */
9524  candpos = candpos2;
9525 
9526  /* recalculate gcd from scratch */
9527  gcd = weights[v+1];
9528  assert(gcd >= 1);
9529 
9530  /* calculate greatest common divisor for variables */
9531  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9532  if( gcd == 1 )
9533  return SCIP_OKAY;
9534  }
9535  else
9536  /* cannot determine a possible coefficient for reduction */
9537  return SCIP_OKAY;
9538  }
9539  }
9540  }
9541  assert(gcd >= 2);
9542 
9543  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9544  * further
9545  */
9546  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9547 
9548  /* determine the remainder of the capacity and the gcd */
9549  rest = consdata->capacity % gcd;
9550  assert(rest >= 0);
9551  assert(rest < gcd);
9552 
9553  if( candpos == -1 )
9554  {
9555  /* we assume that the constraint was normalized */
9556  assert(rest > 0);
9557 
9558  /* replace old with new capacity */
9559  consdata->capacity -= rest;
9560  ++(*nchgsides);
9561 
9562  /* replace old big coefficients with new capacity */
9563  for( v = 0; v < offsetv; ++v )
9564  {
9565  consdataChgWeight(consdata, v, consdata->capacity);
9566  }
9567 
9568  *nchgcoefs += offsetv;
9569  goto CONTINUE;
9570  }
9571 
9572  /* determine the remainder of the coefficient candidate and the gcd */
9573  restweight = weights[candpos] % gcd;
9574  assert(restweight >= 1);
9575  assert(restweight < gcd);
9576 
9577  /* calculate new coefficient */
9578  if( restweight > rest )
9579  newweight = weights[candpos] - restweight + gcd;
9580  else
9581  newweight = weights[candpos] - restweight;
9582 
9583  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9584 
9585  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);
9586 
9587  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9588  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9589  */
9590  if( newweight == 0 && offsetv > 0 )
9591  return SCIP_OKAY;
9592 
9593  if( rest > 0 )
9594  {
9595  /* replace old with new capacity */
9596  consdata->capacity -= rest;
9597  ++(*nchgsides);
9598 
9599  /* replace old big coefficients with new capacity */
9600  for( v = 0; v < offsetv; ++v )
9601  {
9602  consdataChgWeight(consdata, v, consdata->capacity);
9603  }
9604 
9605  *nchgcoefs += offsetv;
9606  }
9607 
9608  if( newweight == 0 )
9609  {
9610  /* delete redundant coefficient */
9611  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9612  assert(consdata->nvars == nvars - 1);
9613  --nvars;
9614  }
9615  else
9616  {
9617  /* replace old with new coefficient */
9618  consdataChgWeight(consdata, candpos, newweight);
9619  }
9620  ++(*nchgcoefs);
9621 
9622  assert(consdata->vars == vars);
9623  assert(consdata->nvars == nvars);
9624  assert(consdata->weights == weights);
9625 
9626  CONTINUE:
9627  /* now constraint can be normalized, dividing it by the gcd */
9628  for( v = nvars - 1; v >= 0; --v )
9629  {
9630  consdataChgWeight(consdata, v, weights[v]/gcd);
9631  }
9632  (*nchgcoefs) += nvars;
9633 
9634  consdata->capacity /= gcd;
9635  ++(*nchgsides);
9636 
9637  SCIPdebugPrintCons(scip, cons, NULL);
9638 
9639  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));
9640  }
9641  while( nvars >= 2 );
9642 
9643  return SCIP_OKAY;
9644 }
9645 
9646 
9647 /** inserts an element into the list of binary zero implications */
9648 static
9650  SCIP* scip, /**< SCIP data structure */
9651  int** liftcands, /**< array of the lifting candidates */
9652  int* nliftcands, /**< number of lifting candidates */
9653  int** firstidxs, /**< array of first zeroitems indices */
9654  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9655  int** zeroitems, /**< pointer to zero items array */
9656  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9657  int* zeroitemssize, /**< pointer to size of zero items array */
9658  int* nzeroitems, /**< pointer to length of zero items array */
9659  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9660  SCIP_Bool value, /**< value v of variable y in implication */
9661  int knapsackidx, /**< index of variable x in knapsack */
9662  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9663  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9664  )
9665 {
9666  int nzeros;
9667 
9668  assert(liftcands != NULL);
9669  assert(liftcands[value] != NULL);
9670  assert(nliftcands != NULL);
9671  assert(firstidxs != NULL);
9672  assert(firstidxs[value] != NULL);
9673  assert(zeroweightsums != NULL);
9674  assert(zeroweightsums[value] != NULL);
9675  assert(zeroitems != NULL);
9676  assert(nextidxs != NULL);
9677  assert(zeroitemssize != NULL);
9678  assert(nzeroitems != NULL);
9679  assert(*nzeroitems <= *zeroitemssize);
9680  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9681  assert(memlimitreached != NULL);
9682 
9683  nzeros = *nzeroitems;
9684 
9685  /* allocate enough memory */
9686  if( nzeros == *zeroitemssize )
9687  {
9688  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9689  * this can be too huge - abort on memory limit
9690  */
9691  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9692  {
9693  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9694  *zeroitemssize);
9695  *memlimitreached = TRUE;
9696  return SCIP_OKAY;
9697  }
9698  *zeroitemssize *= 2;
9699  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9700  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9701  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9702  }
9703  assert(nzeros < *zeroitemssize);
9704 
9705  if( *memlimitreached )
9706  *memlimitreached = FALSE;
9707 
9708  /* insert element */
9709  (*zeroitems)[nzeros] = knapsackidx;
9710  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9711  if( firstidxs[value][probindex] == 0 )
9712  {
9713  liftcands[value][nliftcands[value]] = probindex;
9714  ++nliftcands[value];
9715  }
9716  firstidxs[value][probindex] = nzeros;
9717  ++(*nzeroitems);
9718  zeroweightsums[value][probindex] += knapsackweight;
9719 
9720  return SCIP_OKAY;
9721 }
9722 
9723 #define MAX_CLIQUELENGTH 50
9724 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9725  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9726  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9727  * if cliqueweightsum(xi == v) < capacity:
9728  * - fixing variable xi to v would make the knapsack constraint redundant
9729  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9730  * redundancy effect:
9731  * wi' := capacity - cliqueweightsum(xi == v)
9732  * this rule can also be applied to binary variables not in the knapsack!
9733  */
9734 static
9736  SCIP* scip, /**< SCIP data structure */
9737  SCIP_CONS* cons, /**< knapsack constraint */
9738  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9739  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9740  )
9741 {
9742  SCIP_CONSDATA* consdata;
9743  SCIP_VAR** binvars;
9744  int nbinvars;
9745  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9746  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9747  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9748  int* zeroitems; /* item number in knapsack that is implied to zero */
9749  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9750  int zeroitemssize;
9751  int nzeroitems;
9752  SCIP_Bool* zeroiteminserted[2];
9753  SCIP_Bool memlimitreached;
9754  int nliftcands[2];
9755  SCIP_Bool* cliqueused;
9756  SCIP_Bool* itemremoved;
9757  SCIP_Longint maxcliqueweightsum;
9758  SCIP_VAR** addvars;
9759  SCIP_Longint* addweights;
9760  SCIP_Longint addweightsum;
9761  int nvars;
9762  int cliquenum;
9763  int naddvars;
9764  int val;
9765  int i;
9766 
9767  int* tmpindices;
9768  SCIP_Bool* tmpboolindices;
9769  int* tmpindices2;
9770  SCIP_Bool* tmpboolindices2;
9771  int* tmpindices3;
9772  SCIP_Bool* tmpboolindices3;
9773  int tmp;
9774  int tmp2;
9775  int tmp3;
9776  SCIP_CONSHDLR* conshdlr;
9777  SCIP_CONSHDLRDATA* conshdlrdata;
9778 
9779  assert(nchgcoefs != NULL);
9780  assert(!SCIPconsIsModifiable(cons));
9781 
9782  consdata = SCIPconsGetData(cons);
9783  assert(consdata != NULL);
9784  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9785  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9786  assert(consdata->nvars > 0);
9787  assert(consdata->merged);
9788 
9789  nvars = consdata->nvars;
9790 
9791  /* check if the knapsack has too many items/cliques for applying this costly method */
9792  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9793  return SCIP_OKAY;
9794 
9795  /* sort items, s.t. the heaviest one is in the first position */
9796  sortItems(consdata);
9797 
9798  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9799  return SCIP_OKAY;
9800 
9801  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9802  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9803  assert(nbinvars > 0);
9804  binvars = SCIPgetVars(scip);
9805 
9806  /* get conshdlrdata to use cleared memory */
9807  conshdlr = SCIPconsGetHdlr(cons);
9808  assert(conshdlr != NULL);
9809  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9810  assert(conshdlrdata != NULL);
9811 
9812  /* allocate temporary memory for the list of implied to zero variables */
9813  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9814  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9815  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9816 
9817  assert(conshdlrdata->ints1size > 0);
9818  assert(conshdlrdata->ints2size > 0);
9819  assert(conshdlrdata->longints1size > 0);
9820  assert(conshdlrdata->longints2size > 0);
9821 
9822  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9823  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9824  * transform all integers into their binary representation then it maybe happens
9825  */
9826  if( conshdlrdata->ints1size < nbinvars )
9827  {
9828  int oldsize = conshdlrdata->ints1size;
9829 
9830  conshdlrdata->ints1size = nbinvars;
9831  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9832  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9833  }
9834  if( conshdlrdata->ints2size < nbinvars )
9835  {
9836  int oldsize = conshdlrdata->ints2size;
9837 
9838  conshdlrdata->ints2size = nbinvars;
9839  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9840  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9841  }
9842  if( conshdlrdata->longints1size < nbinvars )
9843  {
9844  int oldsize = conshdlrdata->longints1size;
9845 
9846  conshdlrdata->longints1size = nbinvars;
9847  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9848  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9849  }
9850  if( conshdlrdata->longints2size < nbinvars )
9851  {
9852  int oldsize = conshdlrdata->longints2size;
9853 
9854  conshdlrdata->longints2size = nbinvars;
9855  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9856  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9857  }
9858 
9859  firstidxs[0] = conshdlrdata->ints1;
9860  firstidxs[1] = conshdlrdata->ints2;
9861  zeroweightsums[0] = conshdlrdata->longints1;
9862  zeroweightsums[1] = conshdlrdata->longints2;
9863 
9864  /* check for cleared arrays, all entries are zero */
9865 #ifndef NDEBUG
9866  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9867  {
9868  assert(firstidxs[0][tmp] == 0);
9869  assert(firstidxs[1][tmp] == 0);
9870  assert(zeroweightsums[0][tmp] == 0);
9871  assert(zeroweightsums[1][tmp] == 0);
9872  }
9873 #endif
9874 
9875  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9876  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9877 
9878  zeroitems[0] = -1; /* dummy element */
9879  nextidxs[0] = -1;
9880  nzeroitems = 1;
9881  nliftcands[0] = 0;
9882  nliftcands[1] = 0;
9883 
9884  assert(conshdlrdata->bools1size > 0);
9885  assert(conshdlrdata->bools2size > 0);
9886 
9887  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9888  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9889  * transform all integers into their binary representation then it maybe happens
9890  */
9891  if( conshdlrdata->bools1size < nbinvars )
9892  {
9893  int oldsize = conshdlrdata->bools1size;
9894 
9895  conshdlrdata->bools1size = nbinvars;
9896  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9897  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9898  }
9899  if( conshdlrdata->bools2size < nbinvars )
9900  {
9901  int oldsize = conshdlrdata->bools2size;
9902 
9903  conshdlrdata->bools2size = nbinvars;
9904  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9905  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9906  }
9907 
9908  zeroiteminserted[0] = conshdlrdata->bools1;
9909  zeroiteminserted[1] = conshdlrdata->bools2;
9910 
9911  /* check for cleared arrays, all entries are zero */
9912 #ifndef NDEBUG
9913  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9914  {
9915  assert(zeroiteminserted[0][tmp] == 0);
9916  assert(zeroiteminserted[1][tmp] == 0);
9917  }
9918 #endif
9919 
9920  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9921  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9922  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9923  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9924  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9925  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9926 
9927  tmp2 = 0;
9928  tmp3 = 0;
9929 
9930  memlimitreached = FALSE;
9931  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9932  {
9933  SCIP_CLIQUE** cliques;
9934  SCIP_VAR* var;
9935  SCIP_Longint weight;
9936  SCIP_Bool value;
9937  int varprobindex;
9938  int ncliques;
9939  int j;
9940 
9941  tmp = 0;
9942 
9943  /* get corresponding active problem variable */
9944  var = consdata->vars[i];
9945  weight = consdata->weights[i];
9946  value = TRUE;
9947  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9948  varprobindex = SCIPvarGetProbindex(var);
9949  assert(0 <= varprobindex && varprobindex < nbinvars);
9950 
9951  /* update the zeroweightsum */
9952  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9953  tmpboolindices3[tmp3] = !value;
9954  tmpindices3[tmp3] = varprobindex;
9955  ++tmp3;
9956 
9957  /* initialize the arrays of inserted zero items */
9958  /* first add the implications (~x == 1 -> x == 0) */
9959  {
9960  SCIP_Bool implvalue;
9961  int probindex;
9962 
9963  probindex = SCIPvarGetProbindex(var);
9964  assert(0 <= probindex && probindex < nbinvars);
9965 
9966  implvalue = !value;
9967 
9968  /* insert the item into the list of the implied variable/value */
9969  assert( !zeroiteminserted[implvalue][probindex] );
9970 
9971  if( firstidxs[implvalue][probindex] == 0 )
9972  {
9973  tmpboolindices2[tmp2] = implvalue;
9974  tmpindices2[tmp2] = probindex;
9975  ++tmp2;
9976  }
9977  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
9978  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
9979  &memlimitreached) );
9980  zeroiteminserted[implvalue][probindex] = TRUE;
9981  tmpboolindices[tmp] = implvalue;
9982  tmpindices[tmp] = probindex;
9983  ++tmp;
9984  }
9985 
9986  /* get the cliques where the knapsack item is member of with value 1 */
9987  ncliques = SCIPvarGetNCliques(var, value);
9988  cliques = SCIPvarGetCliques(var, value);
9989  for( j = 0; j < ncliques && !memlimitreached; ++j )
9990  {
9991  SCIP_VAR** cliquevars;
9992  SCIP_Bool* cliquevalues;
9993  int ncliquevars;
9994  int k;
9995 
9996  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
9997 
9998  /* discard big cliques */
9999  if( ncliquevars > MAX_CLIQUELENGTH )
10000  continue;
10001 
10002  cliquevars = SCIPcliqueGetVars(cliques[j]);
10003  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10004 
10005  for( k = ncliquevars - 1; k >= 0; --k )
10006  {
10007  SCIP_Bool implvalue;
10008  int probindex;
10009 
10010  if( var == cliquevars[k] )
10011  continue;
10012 
10013  probindex = SCIPvarGetProbindex(cliquevars[k]);
10014  if( probindex == -1 )
10015  continue;
10016 
10017  assert(0 <= probindex && probindex < nbinvars);
10018  implvalue = cliquevalues[k];
10019 
10020  /* insert the item into the list of the clique variable/value */
10021  if( !zeroiteminserted[implvalue][probindex] )
10022  {
10023  if( firstidxs[implvalue][probindex] == 0 )
10024  {
10025  tmpboolindices2[tmp2] = implvalue;
10026  tmpindices2[tmp2] = probindex;
10027  ++tmp2;
10028  }
10029 
10030  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10031  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10032  &memlimitreached) );
10033  zeroiteminserted[implvalue][probindex] = TRUE;
10034  tmpboolindices[tmp] = implvalue;
10035  tmpindices[tmp] = probindex;
10036  ++tmp;
10037 
10038  if( memlimitreached )
10039  break;
10040  }
10041  }
10042  }
10043  /* clear zeroiteminserted */
10044  for( --tmp; tmp >= 0; --tmp)
10045  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10046  }
10047  SCIPfreeBufferArray(scip, &tmpboolindices);
10048 
10049  /* calculate the clique partition and the maximal sum of weights using the clique information */
10050  assert(consdata->sorted);
10051  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10052 
10053  assert(conshdlrdata->bools3size > 0);
10054 
10055  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10056  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10057  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10058  */
10059  if( conshdlrdata->bools3size < consdata->nvars )
10060  {
10061  int oldsize = conshdlrdata->bools3size;
10062 
10063  conshdlrdata->bools3size = consdata->nvars;;
10064  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10065  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10066  }
10067 
10068  cliqueused = conshdlrdata->bools3;
10069 
10070  /* check for cleared array, all entries are zero */
10071 #ifndef NDEBUG
10072  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10073  assert(cliqueused[tmp] == 0);
10074 #endif
10075 
10076  maxcliqueweightsum = 0;
10077  tmp = 0;
10078 
10079  /* calculates maximal weight of cliques */
10080  for( i = 0; i < consdata->nvars; ++i )
10081  {
10082  cliquenum = consdata->cliquepartition[i];
10083  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10084 
10085  if( !cliqueused[cliquenum] )
10086  {
10087  maxcliqueweightsum += consdata->weights[i];
10088  cliqueused[cliquenum] = TRUE;
10089  tmpindices[tmp] = cliquenum;
10090  ++tmp;
10091  }
10092  }
10093  /* clear cliqueused */
10094  for( --tmp; tmp >= 0; --tmp)
10095  cliqueused[tmp] = FALSE;
10096 
10097  assert(conshdlrdata->bools4size > 0);
10098 
10099  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10100  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10101  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10102  */
10103  if( conshdlrdata->bools4size < consdata->nvars )
10104  {
10105  int oldsize = conshdlrdata->bools4size;
10106 
10107  conshdlrdata->bools4size = consdata->nvars;
10108  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10109  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10110  }
10111 
10112  itemremoved = conshdlrdata->bools4;
10113 
10114  /* check for cleared array, all entries are zero */
10115 #ifndef NDEBUG
10116  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10117  assert(itemremoved[tmp] == 0);
10118 #endif
10119 
10120  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10121  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10122  * included in subsequent cliqueweightsum calculations)
10123  */
10124  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10125  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10126  naddvars = 0;
10127  addweightsum = 0;
10128  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10129  {
10130  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10131  {
10132  SCIP_Longint cliqueweightsum;
10133  int probindex;
10134  int idx;
10135  int j;
10136 
10137  tmp = 0;
10138 
10139  probindex = liftcands[val][i];
10140  assert(0 <= probindex && probindex < nbinvars);
10141 
10142  /* ignore empty zero lists and variables that cannot be lifted anyways */
10143  if( firstidxs[val][probindex] == 0
10144  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10145  continue;
10146 
10147  /* mark the items that are implied to zero by setting the current variable to the current value */
10148  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10149  {
10150  assert(0 < idx && idx < nzeroitems);
10151  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10152  itemremoved[zeroitems[idx]] = TRUE;
10153  }
10154 
10155  /* calculate the residual cliqueweight sum */
10156  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10157  for( j = 0; j < consdata->nvars; ++j )
10158  {
10159  cliquenum = consdata->cliquepartition[j];
10160  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10161  if( !itemremoved[j] )
10162  {
10163  if( !cliqueused[cliquenum] )
10164  {
10165  cliqueweightsum += consdata->weights[j];
10166  cliqueused[cliquenum] = TRUE;
10167  tmpindices[tmp] = cliquenum;
10168  ++tmp;
10169  }
10170 
10171  if( cliqueweightsum >= consdata->capacity )
10172  break;
10173  }
10174  }
10175 
10176  /* check if the weight of the variable/value can be increased */
10177  if( cliqueweightsum < consdata->capacity )
10178  {
10179  SCIP_VAR* var;
10180  SCIP_Longint weight;
10181 
10182  /* insert the variable (with value TRUE) in the list of additional items */
10183  assert(naddvars < 2*nbinvars);
10184  var = binvars[probindex];
10185  if( val == FALSE )
10186  {
10187  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10188  }
10189  weight = consdata->capacity - cliqueweightsum;
10190  addvars[naddvars] = var;
10191  addweights[naddvars] = weight;
10192  addweightsum += weight;
10193  naddvars++;
10194 
10195  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10196  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10197  }
10198 
10199  /* clear itemremoved */
10200  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10201  {
10202  assert(0 < idx && idx < nzeroitems);
10203  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10204  itemremoved[zeroitems[idx]] = FALSE;
10205  }
10206  /* clear cliqueused */
10207  for( --tmp; tmp >= 0; --tmp)
10208  cliqueused[tmpindices[tmp]] = FALSE;
10209  }
10210  }
10211 
10212  /* clear part of zeroweightsums */
10213  for( --tmp3; tmp3 >= 0; --tmp3)
10214  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10215 
10216  /* clear rest of zeroweightsums and firstidxs */
10217  for( --tmp2; tmp2 >= 0; --tmp2)
10218  {
10219  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10220  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10221  }
10222 
10223  /* add all additional item weights */
10224  for( i = 0; i < naddvars; ++i )
10225  {
10226  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10227  }
10228  *nchgcoefs += naddvars;
10229 
10230  if( naddvars > 0 )
10231  {
10232  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10233  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10234  }
10235 
10236  /* free temporary memory */
10237  SCIPfreeBufferArray(scip, &addweights);
10238  SCIPfreeBufferArray(scip, &addvars);
10239  SCIPfreeBufferArray(scip, &tmpindices);
10240  SCIPfreeBufferArray(scip, &tmpindices2);
10241  SCIPfreeBufferArray(scip, &tmpindices3);
10242  SCIPfreeBufferArray(scip, &tmpboolindices2);
10243  SCIPfreeBufferArray(scip, &tmpboolindices3);
10244  SCIPfreeBufferArray(scip, &nextidxs);
10245  SCIPfreeBufferArray(scip, &zeroitems);
10246  SCIPfreeBufferArray(scip, &liftcands[1]);
10247  SCIPfreeBufferArray(scip, &liftcands[0]);
10248 
10249  return SCIP_OKAY;
10250 }
10251 
10252 /** tightens item weights and capacity in presolving:
10253  * given a knapsack sum(wi*xi) <= capacity
10254  * (1) let weightsum := sum(wi)
10255  * if weightsum - wi < capacity:
10256  * - not using item i would make the knapsack constraint redundant
10257  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10258  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10259  * - change coefficients:
10260  * wi' := weightsum - capacity
10261  * capacity' := capacity - (wi - wi')
10262  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10263  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10264  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10265  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10266  * can be multiple times the same weight, this can be improved
10267  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10268  * weight, to capacity - lastmininmalweightsum, e.g. :
10269  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10270  * -> minimal weightsums: 5, 5, 10, 10
10271  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10272  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10273  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10274  * (3) let W(C) be the maximal weight of clique C,
10275  * cliqueweightsum := sum(W(C))
10276  * if cliqueweightsum - W(C) < capacity:
10277  * - not using any item of C would make the knapsack constraint redundant
10278  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10279  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10280  * - change coefficients:
10281  * delta := capacity - (cliqueweightsum - W(C))
10282  * wi' := max(wi - delta, 0)
10283  * capacity' := capacity - delta
10284  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10285  * introduce infeasible solutions.
10286  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10287  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10288  * if cliqueweightsum(xi == v) < capacity:
10289  * - fixing variable xi to v would make the knapsack constraint redundant
10290  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10291  * redundancy effect:
10292  * wi' := capacity - cliqueweightsum(xi == v)
10293  * This rule can also be applied to binary variables not in the knapsack!
10294  * (5) if min{w} + wi > capacity:
10295  * - using item i would force to fix other items to zero
10296  * - wi can be increased to the capacity
10297  */
10298 static
10300  SCIP* scip, /**< SCIP data structure */
10301  SCIP_CONS* cons, /**< knapsack constraint */
10302  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10303  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10304  int* nchgsides, /**< pointer to count number of side changes */
10305  int* naddconss, /**< pointer to count number of added constraints */
10306  int* ndelconss, /**< pointer to count number of deleted constraints */
10307  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10308  )
10309 {
10310  SCIP_CONSHDLRDATA* conshdlrdata;
10311  SCIP_CONSDATA* consdata;
10312  SCIP_Longint* weights;
10313  SCIP_Longint sumcoef;
10314  SCIP_Longint capacity;
10315  SCIP_Longint newweight;
10316  SCIP_Longint maxweight;
10317  SCIP_Longint minweight;
10318  SCIP_Bool sumcoefcase = FALSE;
10319  int startpos;
10320  int backpos;
10321  int nvars;
10322  int pos;
10323  int k;
10324  int i;
10325 
10326  assert(nchgcoefs != NULL);
10327  assert(nchgsides != NULL);
10328  assert(!SCIPconsIsModifiable(cons));
10329 
10330  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10331  assert(conshdlrdata != NULL);
10332 
10333  consdata = SCIPconsGetData(cons);
10334  assert(consdata != NULL);
10335  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10336  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10337  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10338  assert(consdata->nvars > 0);
10339 
10340  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10341  if( *cutoff )
10342  return SCIP_OKAY;
10343 
10344  /* apply rule (1) */
10345  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10346  {
10347  do
10348  {
10349  assert(consdata->merged);
10350 
10351  /* sort items, s.t. the heaviest one is in the first position */
10352  sortItems(consdata);
10353 
10354  for( i = 0; i < consdata->nvars; ++i )
10355  {
10356  SCIP_Longint weight;
10357 
10358  weight = consdata->weights[i];
10359  if( consdata->weightsum - weight < consdata->capacity )
10360  {
10361  newweight = consdata->weightsum - consdata->capacity;
10362  consdataChgWeight(consdata, i, newweight);
10363  consdata->capacity -= (weight - newweight);
10364  (*nchgcoefs)++;
10365  (*nchgsides)++;
10366  assert(!consdata->sorted);
10367  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",
10368  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10369  consdata->capacity + (weight-newweight), consdata->capacity);
10370  }
10371  else
10372  break;
10373  }
10374  }
10375  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10376  }
10377 
10378  /* check for redundancy */
10379  if( consdata->weightsum <= consdata->capacity )
10380  return SCIP_OKAY;
10381 
10382  pos = 0;
10383  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10384  ++pos;
10385 
10386  sumcoef = 0;
10387  weights = consdata->weights;
10388  nvars = consdata->nvars;
10389  capacity = consdata->capacity;
10390 
10391  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10392  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10393  {
10394  /* further reductions using the next possible coefficient sum
10395  *
10396  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10397  */
10398  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10399  for( k = 0; k < 4; ++k )
10400  {
10401  newweight = capacity - sumcoef;
10402 
10403  /* determine next minimal coefficient sum */
10404  switch( k )
10405  {
10406  case 0:
10407  sumcoef = weights[nvars - 1];
10408  backpos = nvars - 1;
10409  break;
10410  case 1:
10411  sumcoef = weights[nvars - 2];
10412  backpos = nvars - 2;
10413  break;
10414  case 2:
10415  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10416  {
10417  sumcoefcase = TRUE;
10418  sumcoef = weights[nvars - 3];
10419  backpos = nvars - 3;
10420  }
10421  else
10422  {
10423  sumcoefcase = FALSE;
10424  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10425  backpos = nvars - 2;
10426  }
10427  break;
10428  default:
10429  assert(k == 3);
10430  if( sumcoefcase )
10431  {
10432  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10433  {
10434  sumcoef = weights[nvars - 4];
10435  backpos = nvars - 4;
10436  }
10437  else
10438  {
10439  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10440  backpos = nvars - 2;
10441  }
10442  }
10443  else
10444  {
10445  sumcoef = weights[nvars - 3];
10446  backpos = nvars - 3;
10447  }
10448  break;
10449  }
10450 
10451  if( backpos <= pos )
10452  break;
10453 
10454  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10455  maxweight = weights[pos];
10456  startpos = pos;
10457  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10458  {
10459  assert(newweight > weights[pos]);
10460 
10461  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10462  SCIPconsGetName(cons), maxweight, newweight);
10463 
10464  consdataChgWeight(consdata, pos, newweight);
10465 
10466  ++pos;
10467  assert(pos < nvars);
10468 
10469  maxweight = weights[pos];
10470 
10471  if( backpos <= pos )
10472  break;
10473  }
10474  (*nchgcoefs) += (pos - startpos);
10475 
10476  /* skip unchangable weights */
10477  while( pos < nvars && weights[pos] + sumcoef == capacity )
10478  ++pos;
10479 
10480  /* check special case were there is only one weight left to tighten
10481  *
10482  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10483  *
10484  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10485  *
10486  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10487  */
10488  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10489  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10490  {
10491  newweight = capacity - sumcoef;
10492  assert(newweight > weights[pos]);
10493 
10494  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10495  SCIPconsGetName(cons), maxweight, newweight);
10496 
10497  consdataChgWeight(consdata, pos, newweight);
10498 
10499  break;
10500  }
10501 
10502  if( backpos <= pos )
10503  break;
10504  }
10505  }
10506 
10507  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10508  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10509  {
10510  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10511  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10512  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10513  {
10514  SCIP_VAR** clqvars;
10515  SCIP_CONS* cliquecons;
10516  char name[SCIP_MAXSTRLEN];
10517  int* clqpart;
10518  int nclqvars;
10519  int nclq;
10520  int len;
10521  int c;
10522  int w;
10523 
10524  assert(!SCIPconsIsDeleted(cons));
10525 
10526  if( pos == consdata->nvars )
10527  {
10528  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10529 
10530  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10534  SCIPconsIsStickingAtNode(cons)) );
10535 
10536  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10537  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10538  ++(*naddconss);
10539 
10540  /* delete old constraint */
10541  SCIP_CALL( SCIPdelCons(scip, cons) );
10542  ++(*ndelconss);
10543 
10544  return SCIP_OKAY;
10545  }
10546 
10547  len = consdata->nvars - pos;
10548 
10549  /* allocate temporary memory */
10550  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10551 
10552  /* calculate clique partition */
10553  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10554  assert(nclq <= len);
10555 
10556 #ifndef NDEBUG
10557  /* clique numbers must be at least as high as the index */
10558  for( w = 0; w < nclq; ++w )
10559  assert(clqpart[w] <= w);
10560 #endif
10561 
10562  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10563 
10564  /* allocate temporary memory */
10565  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10566 
10567  /* copy corresponding variables with big coefficients */
10568  for( w = pos - 1; w >= 0; --w )
10569  clqvars[w] = consdata->vars[w];
10570 
10571  /* create for each clique a set-packing constraint */
10572  for( c = 0; c < nclq; ++c )
10573  {
10574  nclqvars = pos;
10575 
10576  for( w = c; w < len; ++w )
10577  {
10578  if( clqpart[w] == c )
10579  {
10580  assert(nclqvars < pos + len - nclq + 1);
10581  clqvars[nclqvars] = consdata->vars[w + pos];
10582  ++nclqvars;
10583  }
10584  }
10585 
10586  assert(nclqvars > 1);
10587 
10588  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10589  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10593  SCIPconsIsStickingAtNode(cons)) );
10594  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10595  SCIPdebugPrintCons(scip, cliquecons, NULL);
10596  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10597  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10598  ++(*naddconss);
10599  }
10600 
10601  /* delete old constraint */
10602  SCIP_CALL( SCIPdelCons(scip, cons) );
10603  ++(*ndelconss);
10604 
10605  SCIPfreeBufferArray(scip, &clqvars);
10606  SCIPfreeBufferArray(scip, &clqpart);
10607 
10608  return SCIP_OKAY;
10609  }
10610  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10611  {
10612  SCIP_Longint* maxcliqueweights;
10613  SCIP_Longint* newweightvals;
10614  int* newweightidxs;
10615  SCIP_Longint cliqueweightsum;
10616 
10617  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10618  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10619  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10620 
10621  /* repeat as long as changes have been applied */
10622  do
10623  {
10624  int ncliques;
10625  int cliquenum;
10626  SCIP_Bool zeroweights;
10627 
10628  assert(consdata->merged);
10629 
10630  /* sort items, s.t. the heaviest one is in the first position */
10631  sortItems(consdata);
10632 
10633  /* calculate a clique partition */
10634  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10635 
10636  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10637  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10638  break;
10639 
10640  /* calculate the maximal weight of the cliques and store the clique type */
10641  cliqueweightsum = 0;
10642  ncliques = 0;
10643 
10644  for( i = 0; i < consdata->nvars; ++i )
10645  {
10646  SCIP_Longint weight;
10647 
10648  cliquenum = consdata->cliquepartition[i];
10649  assert(0 <= cliquenum && cliquenum <= ncliques);
10650 
10651  weight = consdata->weights[i];
10652  assert(weight > 0);
10653 
10654  if( cliquenum == ncliques )
10655  {
10656  maxcliqueweights[ncliques] = weight;
10657  cliqueweightsum += weight;
10658  ++ncliques;
10659  }
10660 
10661  assert(maxcliqueweights[cliquenum] >= weight);
10662  }
10663 
10664  /* apply rule on every clique */
10665  zeroweights = FALSE;
10666  for( i = 0; i < ncliques; ++i )
10667  {
10668  SCIP_Longint delta;
10669 
10670  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10671  if( delta > 0 )
10672  {
10673  SCIP_Longint newcapacity;
10674 #ifndef NDEBUG
10675  SCIP_Longint newmincliqueweight;
10676 #endif
10677  SCIP_Longint newminweightsuminclique;
10678  SCIP_Bool forceclique;
10679  int nnewweights;
10680  int j;
10681 
10682  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",
10683  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10684  newcapacity = consdata->capacity - delta;
10685  forceclique = FALSE;
10686  nnewweights = 0;
10687 #ifndef NDEBUG
10688  newmincliqueweight = newcapacity + 1;
10689  for( j = 0; j < i; ++j )
10690  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10691 #endif
10692  for( j = i; j < consdata->nvars; ++j )
10693  {
10694  if( consdata->cliquepartition[j] == i )
10695  {
10696  newweight = consdata->weights[j] - delta;
10697  newweight = MAX(newweight, 0);
10698 
10699  /* cache the new weight */
10700  assert(nnewweights < consdata->nvars);
10701  newweightvals[nnewweights] = newweight;
10702  newweightidxs[nnewweights] = j;
10703  nnewweights++;
10704 
10705 #ifndef NDEBUG
10706  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10707  newmincliqueweight = newweight;
10708 #endif
10709  }
10710  }
10711 
10712  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10713  if( nnewweights > 1 )
10714  {
10715 #ifndef NDEBUG
10716  j = newweightidxs[nnewweights - 2];
10717  assert(0 <= j && j < consdata->nvars);
10718  assert(consdata->cliquepartition[j] == i);
10719  j = newweightidxs[nnewweights - 1];
10720  assert(0 <= j && j < consdata->nvars);
10721  assert(consdata->cliquepartition[j] == i);
10722 #endif
10723 
10724  newminweightsuminclique = newweightvals[nnewweights - 2];
10725  newminweightsuminclique += newweightvals[nnewweights - 1];
10726 
10727  /* check if these new two minimal weights both fit into the knapsack;
10728  * if this is true, we have to add a clique constraint in order to enforce the clique
10729  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10730  * reduction might be infeasible, i.e., allows additional solutions)
10731  */
10732  if( newminweightsuminclique <= newcapacity )
10733  forceclique = TRUE;
10734  }
10735 
10736  /* check if we really want to apply the change */
10737  if( conshdlrdata->disaggregation || !forceclique )
10738  {
10739  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10740  consdata->capacity, newcapacity, forceclique);
10741  consdata->capacity = newcapacity;
10742  (*nchgsides)++;
10743 
10744  for( k = 0; k < nnewweights; ++k )
10745  {
10746  j = newweightidxs[k];
10747  assert(0 <= j && j < consdata->nvars);
10748  assert(consdata->cliquepartition[j] == i);
10749 
10750  /* apply the weight change */
10751  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10752  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10753  consdataChgWeight(consdata, j, newweightvals[k]);
10754  (*nchgcoefs)++;
10755  assert(!consdata->sorted);
10756  zeroweights = zeroweights || (newweightvals[k] == 0);
10757  }
10758  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10759  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10760  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10761  * knapsack constraint
10762  */
10763  if( forceclique )
10764  {
10765  SCIP_CONS* cliquecons;
10766  char name[SCIP_MAXSTRLEN];
10767  SCIP_VAR** cliquevars;
10768 
10769  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10770  for( k = 0; k < nnewweights; ++k )
10771  cliquevars[k] = consdata->vars[newweightidxs[k]];
10772 
10773  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10774  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10778  SCIPconsIsStickingAtNode(cons)) );
10779  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10780  SCIPdebugPrintCons(scip, cliquecons, NULL);
10781  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10782  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10783  SCIPfreeBufferArray(scip, &cliquevars);
10784  (*naddconss)++;
10785  }
10786  }
10787  }
10788  }
10789  if( zeroweights )
10790  {
10791  SCIP_CALL( removeZeroWeights(scip, cons) );
10792  }
10793  }
10794  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10795 
10796  /* free temporary memory */
10797  SCIPfreeBufferArray(scip, &newweightidxs);
10798  SCIPfreeBufferArray(scip, &newweightvals);
10799  SCIPfreeBufferArray(scip, &maxcliqueweights);
10800 
10801  /* check for redundancy */
10802  if( consdata->weightsum <= consdata->capacity )
10803  return SCIP_OKAY;
10804  }
10805  }
10806 
10807  /* apply rule (3) */
10808  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10809  {
10810  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10811  }
10812 
10813  /* check for redundancy */
10814  if( consdata->weightsum <= consdata->capacity )
10815  return SCIP_OKAY;
10816 
10817  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10818  {
10819  /* apply rule (4) (all but smallest weight) */
10820  assert(consdata->merged);
10821  sortItems(consdata);
10822  minweight = consdata->weights[consdata->nvars-1];
10823  for( i = 0; i < consdata->nvars-1; ++i )
10824  {
10825  SCIP_Longint weight;
10826 
10827  weight = consdata->weights[i];
10828  assert(weight >= minweight);
10829  if( minweight + weight > consdata->capacity )
10830  {
10831  if( weight < consdata->capacity )
10832  {
10833  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10834  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10835  assert(consdata->sorted);
10836  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10837  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10838  consdata->sorted = TRUE;
10839  (*nchgcoefs)++;
10840  }
10841  }
10842  else
10843  break;
10844  }
10845 
10846  /* apply rule (5) (smallest weight) */
10847  if( consdata->nvars >= 2 )
10848  {
10849  SCIP_Longint weight;
10850 
10851  minweight = consdata->weights[consdata->nvars-2];
10852  weight = consdata->weights[consdata->nvars-1];
10853  assert(minweight >= weight);
10854  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10855  {
10856  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10857  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10858  assert(consdata->sorted);
10859  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10860  assert(minweight >= consdata->weights[consdata->nvars-1]);
10861  consdata->sorted = TRUE;
10862  (*nchgcoefs)++;
10863  }
10864  }
10865  }
10866 
10867  return SCIP_OKAY;
10868 }
10869 
10870 
10871 #ifdef SCIP_DEBUG
10872 static
10873 void printClique(
10874  SCIP_VAR** cliquevars,
10875  int ncliquevars
10876  )
10877 {
10878  int b;
10879  SCIPdebugMessage("adding new Clique: ");
10880  for( b = 0; b < ncliquevars; ++b )
10881  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10882  SCIPdebugPrintf("\n");
10883 }
10884 #endif
10885 
10886 /** adds negated cliques of the knapsack constraint to the global clique table */
10887 static
10889  SCIP*const scip, /**< SCIP data structure */
10890  SCIP_CONS*const cons, /**< knapsack constraint */
10891  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10892  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10893  )
10894 {
10895  SCIP_CONSDATA* consdata;
10896  SCIP_CONSHDLRDATA* conshdlrdata;
10897  SCIP_VAR** poscliquevars;
10898  SCIP_VAR** cliquevars;
10899  SCIP_Longint* maxweights;
10900  SCIP_Longint* gainweights;
10901  int* gaincliquepartition;
10902  SCIP_Bool* cliqueused;
10903  SCIP_Longint minactduetonegcliques;
10904  SCIP_Longint freecapacity;
10905  SCIP_Longint lastweight;
10906  SCIP_Longint beforelastweight;
10907  int nposcliquevars;
10908  int ncliquevars;
10909  int nvars;
10910  int nnegcliques;
10911  int lastcliqueused;
10912  int thisnbdchgs;
10913  int v;
10914  int w;
10915 
10916  assert(scip != NULL);
10917  assert(cons != NULL);
10918  assert(cutoff != NULL);
10919  assert(nbdchgs != NULL);
10920 
10921  *cutoff = FALSE;
10922 
10923  consdata = SCIPconsGetData(cons);
10924  assert(consdata != NULL);
10925 
10926  nvars = consdata->nvars;
10927 
10928  /* check whether the cliques have already been added */
10929  if( consdata->cliquesadded || nvars == 0 )
10930  return SCIP_OKAY;
10931 
10932  /* make sure, the items are merged */
10933  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10934  if( *cutoff )
10935  return SCIP_OKAY;
10936 
10937  /* make sure, items are sorted by non-increasing weight */
10938  sortItems(consdata);
10939 
10940  assert(consdata->merged);
10941 
10942  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10943  assert(conshdlrdata != NULL);
10944 
10945  /* calculate a clique partition */
10946  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10947  nnegcliques = consdata->nnegcliques;
10948 
10949  /* if we have no negated cliques, stop */
10950  if( nnegcliques == nvars )
10951  return SCIP_OKAY;
10952 
10953  /* get temporary memory */
10954  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10955  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10956  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
10957  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10958  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10959  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
10960 
10961  nnegcliques = 0;
10962  minactduetonegcliques = 0;
10963 
10964  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10965  for( v = 0; v < nvars; ++v )
10966  {
10967  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10968  assert(consdata->weights[v] > 0);
10969 
10970  if( consdata->negcliquepartition[v] == nnegcliques )
10971  {
10972  nnegcliques++;
10973  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
10974  }
10975  else
10976  minactduetonegcliques += consdata->weights[v];
10977  }
10978 
10979  nposcliquevars = 0;
10980 
10981  /* add cliques, using negated cliques information */
10982  if( minactduetonegcliques > 0 )
10983  {
10984  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
10985  freecapacity = consdata->capacity - minactduetonegcliques;
10986 
10987  SCIPdebugPrintCons(scip, cons, NULL);
10988  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",
10989  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
10990 
10991  /* calculate possible gain by switching chosen items in negated cliques */
10992  for( v = 0; v < nvars; ++v )
10993  {
10994  if( !cliqueused[consdata->negcliquepartition[v]] )
10995  {
10996  cliqueused[consdata->negcliquepartition[v]] = TRUE;
10997  for( w = v + 1; w < nvars; ++w )
10998  {
10999  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11000  * weight[w] (which are both in a negated clique) */
11001  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11002  && consdata->weights[v] > consdata->weights[w] )
11003  {
11004  poscliquevars[nposcliquevars] = consdata->vars[w];
11005  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11006  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11007  ++nposcliquevars;
11008  }
11009  }
11010  }
11011  }
11012 
11013  /* try to create negated cliques */
11014  if( nposcliquevars > 0 )
11015  {
11016  /* sort possible gain per substitution of the clique members */
11017  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11018 
11019  for( v = 0; v < nposcliquevars; ++v )
11020  {
11021  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11022  ncliquevars = 1;
11023  lastweight = gainweights[v];
11024  beforelastweight = -1;
11025  lastcliqueused = gaincliquepartition[v];
11026  /* clear cliqueused to get an unused array */
11027  BMSclearMemoryArray(cliqueused, nnegcliques);
11028  cliqueused[gaincliquepartition[v]] = TRUE;
11029 
11030  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11031  * in the same negated clique and by taking two of them would exceed the free capacity */
11032  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11033  {
11034  beforelastweight = lastweight;
11035  lastweight = gainweights[w];
11036  lastcliqueused = gaincliquepartition[w];
11037  cliqueused[gaincliquepartition[w]] = TRUE;
11038  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11039  ++ncliquevars;
11040  }
11041 
11042  if( ncliquevars > 1 )
11043  {
11044  SCIPdebug( printClique(cliquevars, ncliquevars) );
11045  assert(beforelastweight > 0);
11046  /* add the clique to the clique table */
11047  /* this really happens, e.g., on enigma.mps from the short test set */
11048  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11049  if( *cutoff )
11050  goto TERMINATE;
11051  *nbdchgs += thisnbdchgs;
11052 
11053  /* reset last used clique to get slightly different cliques */
11054  cliqueused[lastcliqueused] = FALSE;
11055 
11056  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11057  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11058  {
11059  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11060  SCIPdebug( printClique(cliquevars, ncliquevars) );
11061  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11062  if( *cutoff )
11063  goto TERMINATE;
11064  *nbdchgs += thisnbdchgs;
11065  }
11066  }
11067  }
11068  }
11069  }
11070 
11071  TERMINATE:
11072  /* free temporary memory */
11073  SCIPfreeBufferArray(scip, &cliqueused);
11074  SCIPfreeBufferArray(scip, &maxweights);
11075  SCIPfreeBufferArray(scip, &gaincliquepartition);
11076  SCIPfreeBufferArray(scip, &gainweights);
11077  SCIPfreeBufferArray(scip, &cliquevars);
11078  SCIPfreeBufferArray(scip, &poscliquevars);
11079 
11080  return SCIP_OKAY;
11081 }
11082 
11083 /** greedy clique detection by considering weights and capacity
11084  *
11085  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11086  * 1) neighboring items which exceed the capacity together => one clique
11087  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11088  */
11089 static
11091  SCIP*const scip, /**< SCIP data structure */
11092  SCIP_VAR** items, /**< array of variable items */
11093  SCIP_Longint* weights, /**< weights of the items */
11094  int nitems, /**< the number of items */
11095  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11096  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11097  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11098  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11099  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11100  )
11101 {
11102  SCIP_Longint lastweight;
11103  int ncliquevars;
11104  int i;
11105  int thisnbdchgs;
11106 
11107  if( nitems <= 1 )
11108  return SCIP_OKAY;
11109 
11110  /* sort possible gain per substitution of the clique members */
11111  if( ! sorteditems )
11112  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11113 
11114  ncliquevars = 1;
11115  lastweight = weights[0];
11116 
11117  /* taking these two weights together violates the knapsack => include into clique */
11118  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11119  {
11120  lastweight = weights[i];
11121  ++ncliquevars;
11122  }
11123 
11124  if( ncliquevars > 1 )
11125  {
11126  SCIP_Longint compareweight;
11127  SCIP_VAR** cliquevars;
11128  int compareweightidx;
11129  int minclqsize;
11130  int nnzadded;
11131 
11132  /* add the clique to the clique table */
11133  SCIPdebug( printClique(items, ncliquevars) );
11134  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11135 
11136  if( *cutoff )
11137  return SCIP_OKAY;
11138 
11139  *nbdchgs += thisnbdchgs;
11140  nnzadded = ncliquevars;
11141 
11142  /* 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)*/
11143  if( ncliquevars == nitems )
11144  return SCIP_OKAY;
11145 
11146  /* copy items in order into buffer array and deduce more cliques */
11147  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11148 
11149  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11150  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11151  compareweightidx = ncliquevars - 2;
11152  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11153 
11154  /* determine minimum clique size for the following loop */
11155  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11156  minclqsize = MAX(minclqsize, 2);
11157 
11158  /* loop over the remaining variables and the larger items of the first clique until we
11159  * find another clique or reach the size limit */
11160  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11161  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11162  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11163  )
11164  {
11165  compareweight = weights[compareweightidx];
11166  assert(compareweight > 0);
11167 
11168  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11169  if( compareweight + weights[i] > capacity )
11170  {
11171  assert(compareweightidx == ncliquevars -2);
11172  cliquevars[ncliquevars - 1] = items[i];
11173  SCIPdebug( printClique(cliquevars, ncliquevars) );
11174  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11175 
11176  nnzadded += ncliquevars;
11177 
11178  /* stop when there is a cutoff */
11179  if( ! (*cutoff) )
11180  *nbdchgs += thisnbdchgs;
11181 
11182  /* go to next smaller item */
11183  ++i;
11184  }
11185  else
11186  {
11187  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11188  compareweightidx--;
11189  ncliquevars --;
11190  }
11191  }
11192 
11193  SCIPfreeBufferArray(scip, &cliquevars);
11194  }
11195 
11196  return SCIP_OKAY;
11197 }
11198 
11199 /** adds cliques of the knapsack constraint to the global clique table */
11200 static
11202  SCIP*const scip, /**< SCIP data structure */
11203  SCIP_CONS*const cons, /**< knapsack constraint */
11204  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11205  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11206  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11207  )
11208 {
11209  SCIP_CONSDATA* consdata;
11210  SCIP_CONSHDLRDATA* conshdlrdata;
11211  int i;
11212  SCIP_Longint minactduetonegcliques;
11213  SCIP_Longint freecapacity;
11214  int nnegcliques;
11215  int cliquenum;
11216  SCIP_VAR** poscliquevars;
11217  SCIP_Longint* gainweights;
11218  int nposcliquevars;
11219  SCIP_Longint* secondmaxweights;
11220  int nvars;
11221 
11222  assert(scip != NULL);
11223  assert(cons != NULL);
11224  assert(cutoff != NULL);
11225  assert(nbdchgs != NULL);
11226 
11227  *cutoff = FALSE;
11228 
11229  consdata = SCIPconsGetData(cons);
11230  assert(consdata != NULL);
11231 
11232  nvars = consdata->nvars;
11233 
11234  /* check whether the cliques have already been added */
11235  if( consdata->cliquesadded || nvars == 0 )
11236  return SCIP_OKAY;
11237 
11238  /* make sure, the items are merged */
11239  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11240  if( *cutoff )
11241  return SCIP_OKAY;
11242 
11243  /* make sure, the items are sorted by non-increasing weight */
11244  sortItems(consdata);
11245 
11246  assert(consdata->merged);
11247 
11248  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11249  assert(conshdlrdata != NULL);
11250 
11251  /* calculate a clique partition */
11252  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11253  nnegcliques = consdata->nnegcliques;
11254  assert(nnegcliques <= nvars);
11255 
11256  /* get temporary memory */
11257  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11258  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11259  BMSclearMemoryArray(gainweights, nvars);
11260  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11261  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11262 
11263  minactduetonegcliques = 0;
11264 
11265  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11266  if( nnegcliques < nvars )
11267  {
11268  nnegcliques = 0;
11269 
11270  for( i = 0; i < nvars; ++i )
11271  {
11272  SCIP_Longint weight;
11273 
11274  cliquenum = consdata->negcliquepartition[i];
11275  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11276 
11277  weight = consdata->weights[i];
11278  assert(weight > 0);
11279 
11280  if( cliquenum == nnegcliques )
11281  nnegcliques++;
11282  else
11283  {
11284  minactduetonegcliques += weight;
11285  if( secondmaxweights[cliquenum] == 0 )
11286  secondmaxweights[cliquenum] = weight;
11287  }
11288  }
11289  }
11290 
11291  /* add cliques, using negated cliques information */
11292  if( minactduetonegcliques > 0 )
11293  {
11294  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11295  freecapacity = consdata->capacity - minactduetonegcliques;
11296 
11297  SCIPdebugPrintCons(scip, cons, NULL);
11298  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",
11299  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11300 
11301  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11302  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11303 
11304  if( *cutoff )
11305  goto TERMINATE;
11306 
11307  nposcliquevars = 0;
11308 
11309  for( i = nvars - 1; i >= 0; --i )
11310  {
11311  /* if we would take the biggest weight instead of the second biggest */
11312  cliquenum = consdata->negcliquepartition[i];
11313  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11314  {
11315  poscliquevars[nposcliquevars] = consdata->vars[i];
11316  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11317  ++nposcliquevars;
11318  }
11319  }
11320 
11321  /* use the gain weights and free capacity to derive greedily cliques */
11322  if( nposcliquevars > 1 )
11323  {
11324  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11325 
11326  if( *cutoff )
11327  goto TERMINATE;
11328  }
11329  }
11330 
11331  /* build cliques by using the items with the maximal weights */
11332  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11333 
11334  TERMINATE:
11335  /* free temporary memory and mark the constraint */
11336  SCIPfreeBufferArray(scip, &secondmaxweights);
11337  SCIPfreeBufferArray(scip, &gainweights);
11338  SCIPfreeBufferArray(scip, &poscliquevars);
11339  consdata->cliquesadded = TRUE;
11340 
11341  return SCIP_OKAY;
11342 }
11343 
11344 
11345 /** gets the key of the given element */
11346 static
11347 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11348 { /*lint --e{715}*/
11349  /* the key is the element itself */
11350  return elem;
11351 }
11352 
11353 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11354  * same coefficients
11355  */
11356 static
11357 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11358 {
11359 #ifndef NDEBUG
11360  SCIP* scip;
11361 #endif
11362  SCIP_CONSDATA* consdata1;
11363  SCIP_CONSDATA* consdata2;
11364  int i;
11366  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11367  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11368  assert(consdata1->sorted);
11369  assert(consdata2->sorted);
11370 #ifndef NDEBUG
11371  scip = (SCIP*)userptr;
11372  assert(scip != NULL);
11373 #endif
11374 
11375  /* checks trivial case */
11376  if( consdata1->nvars != consdata2->nvars )
11377  return FALSE;
11378 
11379  for( i = consdata1->nvars - 1; i >= 0; --i )
11380  {
11381  /* tests if variables are equal */
11382  if( consdata1->vars[i] != consdata2->vars[i] )
11383  {
11384  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11385  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11386  return FALSE;
11387  }
11388  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11389 
11390  /* tests if weights are equal too */
11391  if( consdata1->weights[i] != consdata2->weights[i] )
11392  return FALSE;
11393  }
11394 
11395  return TRUE;
11396 }
11397 
11398 /** returns the hash value of the key */
11399 static
11400 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11401 {
11402 #ifndef NDEBUG
11403  SCIP* scip;
11404 #endif
11405  SCIP_CONSDATA* consdata;
11406  uint64_t firstweight;
11407  int minidx;
11408  int mididx;
11409  int maxidx;
11410 
11411  consdata = SCIPconsGetData((SCIP_CONS*)key);
11412  assert(consdata != NULL);
11413  assert(consdata->nvars > 0);
11414 
11415 #ifndef NDEBUG
11416  scip = (SCIP*)userptr;
11417  assert(scip != NULL);
11418 #endif
11419 
11420  /* sorts the constraints */
11421  sortItems(consdata);
11422 
11423  minidx = SCIPvarGetIndex(consdata->vars[0]);
11424  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11425  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11426  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11427 
11428  /* hash value depends on vectors of variable indices */
11429  firstweight = (uint64_t)consdata->weights[0];
11430  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11431 }
11432 
11433 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11434  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11435  */
11436 static
11438  SCIP* scip, /**< SCIP data structure */
11439  BMS_BLKMEM* blkmem, /**< block memory */
11440  SCIP_CONS** conss, /**< constraint set */
11441  int nconss, /**< number of constraints in constraint set */
11442  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11443  int* ndelconss /**< pointer to count number of deleted constraints */
11444  )
11446  SCIP_HASHTABLE* hashtable;
11447  int hashtablesize;
11448  int c;
11449 
11450  assert(scip != NULL);
11451  assert(blkmem != NULL);
11452  assert(conss != NULL);
11453  assert(ndelconss != NULL);
11454 
11455  /* create a hash table for the constraint set */
11456  hashtablesize = nconss;
11457  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11458  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11459  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11460 
11461  /* check all constraints in the given set for redundancy */
11462  for( c = nconss - 1; c >= 0; --c )
11463  {
11464  SCIP_CONS* cons0;
11465  SCIP_CONS* cons1;
11466  SCIP_CONSDATA* consdata0;
11467 
11468  cons0 = conss[c];
11469 
11470  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11471  continue;
11472 
11473  consdata0 = SCIPconsGetData(cons0);
11474  assert(consdata0 != NULL);
11475  if( consdata0->nvars == 0 )
11476  {
11477  if( consdata0->capacity < 0 )
11478  {
11479  *cutoff = TRUE;
11480  goto TERMINATE;
11481  }
11482  else
11483  {
11484  SCIP_CALL( SCIPdelCons(scip, cons0) );
11485  ++(*ndelconss);
11486  continue;
11487  }
11488  }
11489 
11490  /* get constraint from current hash table with same variables and same weights as cons0 */
11491  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11492 
11493  if( cons1 != NULL )
11494  {
11495  SCIP_CONS* consstay;
11496  SCIP_CONS* consdel;
11497  SCIP_CONSDATA* consdata1;
11498 
11499  assert(SCIPconsIsActive(cons1));
11500  assert(!SCIPconsIsModifiable(cons1));
11501 
11502  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11503  * delete old constraints afterwards
11504  */
11505  consdata1 = SCIPconsGetData(cons1);
11506 
11507  assert(consdata1 != NULL);
11508  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11509 
11510  assert(consdata0->sorted && consdata1->sorted);
11511  assert(consdata0->vars[0] == consdata1->vars[0]);
11512  assert(consdata0->weights[0] == consdata1->weights[0]);
11513 
11514  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11515  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11516 
11517  /* check which constraint has to stay; */
11518  if( consdata0->capacity < consdata1->capacity )
11519  {
11520  consstay = cons0;
11521  consdel = cons1;
11522 
11523  /* exchange consdel with consstay in hashtable */
11524  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11525  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11526  }
11527  else
11528  {
11529  consstay = cons1;
11530  consdel = cons0;
11531  }
11532 
11533  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11534  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11535 
11536  /* delete consdel */
11537  SCIP_CALL( SCIPdelCons(scip, consdel) );
11538  ++(*ndelconss);
11539 
11540  assert(SCIPconsIsActive(consstay));
11541  }
11542  else
11543  {
11544  /* no such constraint in current hash table: insert cons0 into hash table */
11545  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11546  }
11547  }
11548 
11549  TERMINATE:
11550  /* free hash table */
11551  SCIPhashtableFree(&hashtable);
11552 
11553  return SCIP_OKAY;
11554 }
11555 
11556 
11557 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11558  * and removes or changes constraint accordingly
11559  */
11560 static
11562  SCIP* scip, /**< SCIP data structure */
11563  SCIP_CONS** conss, /**< constraint set */
11564  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11565  int chkind, /**< index of constraint to check against all prior indices upto startind */
11566  int* ndelconss /**< pointer to count number of deleted constraints */
11567  )
11568 {
11569  SCIP_CONS* cons0;
11570  SCIP_CONSDATA* consdata0;
11571  int c;
11572 
11573  assert(scip != NULL);
11574  assert(conss != NULL);
11575  assert(firstchange <= chkind);
11576  assert(ndelconss != NULL);
11577 
11578  /* get the constraint to be checked against all prior constraints */
11579  cons0 = conss[chkind];
11580  assert(cons0 != NULL);
11581  assert(SCIPconsIsActive(cons0));
11582  assert(!SCIPconsIsModifiable(cons0));
11583 
11584  consdata0 = SCIPconsGetData(cons0);
11585  assert(consdata0 != NULL);
11586  assert(consdata0->nvars >= 1);
11587  assert(consdata0->merged);
11588 
11589  /* sort the constraint */
11590  sortItems(consdata0);
11591 
11592  /* see #2970 */
11593  if( consdata0->capacity == 0 )
11594  return SCIP_OKAY;
11595 
11596  /* check constraint against all prior constraints */
11597  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11598  {
11599  SCIP_CONS* cons1;
11600  SCIP_CONSDATA* consdata1;
11601  SCIP_Bool iscons0incons1contained;
11602  SCIP_Bool iscons1incons0contained;
11603  SCIP_Real quotient;
11604  int v;
11605  int v0;
11606  int v1;
11607 
11608  cons1 = conss[c];
11609  assert(cons1 != NULL);
11610  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11611  continue;
11612 
11613  consdata1 = SCIPconsGetData(cons1);
11614  assert(consdata1 != NULL);
11615 
11616  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11617  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11618  continue;
11619 
11620  assert(consdata1->nvars >= 1);
11621  assert(consdata1->merged);
11622 
11623  /* sort the constraint */
11624  sortItems(consdata1);
11625 
11626  /* see #2970 */
11627  if( consdata1->capacity == 0 )
11628  continue;
11629 
11630  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11631 
11632  if( consdata0->nvars > consdata1->nvars )
11633  {
11634  iscons0incons1contained = FALSE;
11635  iscons1incons0contained = TRUE;
11636  v = consdata1->nvars - 1;
11637  }
11638  else if( consdata0->nvars < consdata1->nvars )
11639  {
11640  iscons0incons1contained = TRUE;
11641  iscons1incons0contained = FALSE;
11642  v = consdata0->nvars - 1;
11643  }
11644  else
11645  {
11646  iscons0incons1contained = TRUE;
11647  iscons1incons0contained = TRUE;
11648  v = consdata0->nvars - 1;
11649  }
11650 
11651  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11652 
11653  /* check consdata0 against consdata1:
11654  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11655  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11656  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11657  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11658  */
11659  v0 = consdata0->nvars - 1;
11660  v1 = consdata1->nvars - 1;
11661 
11662  while( v >= 0 )
11663  {
11664  assert(iscons0incons1contained || iscons1incons0contained);
11665 
11666  /* now there are more variables in cons1 left */
11667  if( v1 > v0 )
11668  {
11669  iscons1incons0contained = FALSE;
11670  if( !iscons0incons1contained )
11671  break;
11672  }
11673  /* now there are more variables in cons0 left */
11674  else if( v1 < v0 )
11675  {
11676  iscons0incons1contained = FALSE;
11677  if( !iscons1incons0contained )
11678  break;
11679  }
11680 
11681  assert(v == v0 || v == v1);
11682  assert(v0 >= 0);
11683  assert(v1 >= 0);
11684 
11685  /* both variables are the same */
11686  if( consdata0->vars[v0] == consdata1->vars[v1] )
11687  {
11688  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11689  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11690  {
11691  iscons1incons0contained = FALSE;
11692  if( !iscons0incons1contained )
11693  break;
11694  }
11695  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11696  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11697  {
11698  iscons0incons1contained = FALSE;
11699  if( !iscons1incons0contained )
11700  break;
11701  }
11702  --v0;
11703  --v1;
11704  --v;
11705  }
11706  else
11707  {
11708  /* both constraints have a variables which is not part of the other constraint, so stop */
11709  if( iscons0incons1contained && iscons1incons0contained )
11710  {
11711  iscons0incons1contained = FALSE;
11712  iscons1incons0contained = FALSE;
11713  break;
11714  }
11715  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11716  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11717  /* continue to the next variable */
11718  if( iscons0incons1contained )
11719  --v1;
11720  else
11721  --v0;
11722  }
11723  }
11724  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11725  * other
11726  */
11727  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11728 
11729  if( iscons1incons0contained )
11730  {
11731  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11732  SCIPdebugPrintCons(scip, cons1, NULL);
11733 
11734  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11735  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11736 
11737  SCIP_CALL( SCIPdelCons(scip, cons1) );
11738  ++(*ndelconss);
11739  }
11740  else if( iscons0incons1contained )
11741  {
11742  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11743  SCIPdebugPrintCons(scip, cons0, NULL);
11744 
11745  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11746  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11747 
11748  SCIP_CALL( SCIPdelCons(scip, cons0) );
11749  ++(*ndelconss);
11750  break;
11751  }
11752  }
11753 
11754  return SCIP_OKAY;
11755 }
11756 
11757 /** helper function to enforce constraints */
11758 static
11760  SCIP* scip, /**< SCIP data structure */
11761  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11762  SCIP_CONS** conss, /**< constraints to process */
11763  int nconss, /**< number of constraints */
11764  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11765  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11766  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11767  )
11768 {
11769  SCIP_CONSHDLRDATA* conshdlrdata;
11770  SCIP_Bool violated;
11771  SCIP_Bool cutoff = FALSE;
11772  int maxncuts;
11773  int ncuts = 0;
11774  int i;
11775 
11776  *result = SCIP_FEASIBLE;
11777 
11778  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11779  sol == NULL ? "LP" : "relaxation");
11780 
11781  /* get maximal number of cuts per round */
11782  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11783  assert(conshdlrdata != NULL);
11784  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11785 
11786  /* search for violated useful knapsack constraints */
11787  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11788  {
11789  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11790  if( violated )
11791  {
11792  /* add knapsack constraint as LP row to the relaxation */
11793  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11794  ncuts++;
11795  }
11796  }
11797 
11798  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11799  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11800  {
11801  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11802  if( violated )
11803  {
11804  /* add knapsack constraint as LP row to the relaxation */
11805  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11806  ncuts++;
11807  }
11808  }
11809 
11810  /* adjust the result code */
11811  if ( cutoff )
11812  *result = SCIP_CUTOFF;
11813  else if ( ncuts > 0 )
11814  *result = SCIP_SEPARATED;
11815 
11816  return SCIP_OKAY;
11817 }
11818 
11819 /*
11820  * Linear constraint upgrading
11821  */
11822 
11823 /** creates and captures a knapsack constraint out of a linear inequality */
11824 static
11826  SCIP* scip, /**< SCIP data structure */
11827  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11828  const char* name, /**< name of constraint */
11829  int nvars, /**< number of variables in the constraint */
11830  SCIP_VAR** vars, /**< array with variables of constraint entries */
11831  SCIP_Real* vals, /**< array with inequality coefficients */
11832  SCIP_Real lhs, /**< left hand side of inequality */
11833  SCIP_Real rhs, /**< right hand side of inequality */
11834  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11835  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11836  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11837  * Usually set to TRUE. */
11838  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11839  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11840  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11841  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11842  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11843  * Usually set to TRUE. */
11844  SCIP_Bool local, /**< is constraint only valid locally?
11845  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11846  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11847  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11848  * adds coefficients to this constraint. */
11849  SCIP_Bool dynamic, /**< is constraint subject to aging?
11850  * Usually set to FALSE. Set to TRUE for own cuts which
11851  * are separated as constraints. */
11852  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11853  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11854  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11855  * if it may be moved to a more global node?
11856  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11857  )
11858 {
11859  SCIP_VAR** transvars;
11860  SCIP_Longint* weights;
11861  SCIP_Longint capacity;
11862  SCIP_Longint weight;
11863  int mult;
11864  int v;
11865 
11866  assert(nvars == 0 || vars != NULL);
11867  assert(nvars == 0 || vals != NULL);
11868  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11869 
11870  /* get temporary memory */
11871  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11872  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11873 
11874  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11875  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11876  */
11877  if( SCIPisInfinity(scip, rhs) )
11878  {
11879  mult = -1;
11880  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11881  }
11882  else
11883  {
11884  mult = +1;
11885  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11886  }
11887 
11888  /* negate positive or negative variables */
11889  for( v = 0; v < nvars; ++v )
11890  {
11891  assert(SCIPisFeasIntegral(scip, vals[v]));
11892  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11893  if( weight > 0 )
11894  {
11895  transvars[v] = vars[v];
11896  weights[v] = weight;
11897  }
11898  else
11899  {
11900  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11901  weights[v] = -weight; /*lint !e2704*/
11902  capacity -= weight;
11903  }
11904  assert(transvars[v] != NULL);
11905  }
11906 
11907  /* create the constraint */
11908  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11909  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11910 
11911  /* free temporary memory */
11912  SCIPfreeBufferArray(scip, &weights);
11913  SCIPfreeBufferArray(scip, &transvars);
11914 
11915  return SCIP_OKAY;
11916 }
11917 
11918 /** tries to upgrade a linear constraint into a knapsack constraint */
11919 static
11920 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11921 { /*lint --e{715}*/
11922  SCIP_Bool upgrade;
11923 
11924  assert(upgdcons != NULL);
11925 
11926  /* check, if linear constraint can be upgraded to a knapsack constraint
11927  * - all variables must be binary
11928  * - all coefficients must be integral
11929  * - exactly one of the sides must be infinite
11930  */
11931  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11932  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11933  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11934 
11935  if( upgrade )
11936  {
11937  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11938 
11939  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11940  assert(!SCIPconsIsModifiable(cons));
11941  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11946  }
11947 
11948  return SCIP_OKAY;
11949 }
11950 
11951 
11952 /*
11953  * Callback methods of constraint handler
11954  */
11955 
11956 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11957 /**! [SnippetConsCopyKnapsack] */
11958 static
11959 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11960 { /*lint --e{715}*/
11961  assert(scip != NULL);
11962  assert(conshdlr != NULL);
11963  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11964 
11965  /* call inclusion method of constraint handler */
11968  *valid = TRUE;
11969 
11970  return SCIP_OKAY;
11971 }
11972 /**! [SnippetConsCopyKnapsack] */
11973 
11974 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11975 /**! [SnippetConsFreeKnapsack] */
11976 static
11977 SCIP_DECL_CONSFREE(consFreeKnapsack)
11978 { /*lint --e{715}*/
11979  SCIP_CONSHDLRDATA* conshdlrdata;
11980 
11981  /* free constraint handler data */
11982  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11983  assert(conshdlrdata != NULL);
11984 
11985  SCIPfreeBlockMemory(scip, &conshdlrdata);
11986 
11987  SCIPconshdlrSetData(conshdlr, NULL);
11988 
11989  return SCIP_OKAY;
11990 }
11991 /**! [SnippetConsFreeKnapsack] */
11992 
11993 
11994 /** initialization method of constraint handler (called after problem was transformed) */
11995 static
11996 SCIP_DECL_CONSINIT(consInitKnapsack)
11997 { /*lint --e{715}*/
11998  SCIP_CONSHDLRDATA* conshdlrdata;
11999  int nvars;
12000 
12001  assert( scip != NULL );
12002  assert( conshdlr != NULL );
12003 
12004  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12005  assert(conshdlrdata != NULL);
12006 
12007  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12008  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12009 
12010  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12011  conshdlrdata->reals1size = nvars;
12012 
12013  return SCIP_OKAY;
12014 }
12015 
12016 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12017 static
12018 SCIP_DECL_CONSEXIT(consExitKnapsack)
12019 { /*lint --e{715}*/
12020  SCIP_CONSHDLRDATA* conshdlrdata;
12021 
12022  assert( scip != NULL );
12023  assert( conshdlr != NULL );
12024 
12025  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12026  assert(conshdlrdata != NULL);
12027 
12028  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12029  conshdlrdata->reals1size = 0;
12030 
12031  return SCIP_OKAY;
12032 }
12033 
12034 
12035 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12036 static
12037 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12038 { /*lint --e{715}*/
12039  SCIP_CONSHDLRDATA* conshdlrdata;
12040  int nvars;
12041 
12042  assert(scip != NULL);
12043  assert(conshdlr != NULL);
12044  assert(nconss == 0 || conss != NULL);
12046  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12047  assert(conshdlrdata != NULL);
12048 
12049  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12050  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12051 
12052  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12053  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12054  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12055  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12056  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12057  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12058  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12059  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12060 
12061  conshdlrdata->ints1size = nvars;
12062  conshdlrdata->ints2size = nvars;
12063  conshdlrdata->longints1size = nvars;
12064  conshdlrdata->longints2size = nvars;
12065  conshdlrdata->bools1size = nvars;
12066  conshdlrdata->bools2size = nvars;
12067  conshdlrdata->bools3size = nvars;
12068  conshdlrdata->bools4size = nvars;
12069 
12070 #ifdef WITH_CARDINALITY_UPGRADE
12071  conshdlrdata->upgradedcard = FALSE;
12072 #endif
12073 
12074  return SCIP_OKAY;
12075 }
12076 
12077 
12078 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12079 static
12080 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12081 { /*lint --e{715}*/
12082  SCIP_CONSHDLRDATA* conshdlrdata;
12083  int c;
12084 
12085  assert(scip != NULL);
12086  assert(conshdlr != NULL);
12087 
12088  for( c = 0; c < nconss; ++c )
12089  {
12090  if( !SCIPconsIsDeleted(conss[c]) )
12091  {
12092  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12093  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12094  }
12095  }
12096 
12097  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12098  assert(conshdlrdata != NULL);
12099 
12100  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12101  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12102  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12103  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12104  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12105  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12106  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12107  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12108 
12109  conshdlrdata->ints1size = 0;
12110  conshdlrdata->ints2size = 0;
12111  conshdlrdata->longints1size = 0;
12112  conshdlrdata->longints2size = 0;
12113  conshdlrdata->bools1size = 0;
12114  conshdlrdata->bools2size = 0;
12115  conshdlrdata->bools3size = 0;
12116  conshdlrdata->bools4size = 0;
12117 
12118  return SCIP_OKAY;
12119 }
12120 
12121 
12122 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12123 static
12124 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12125 { /*lint --e{715}*/
12126  SCIP_CONSDATA* consdata;
12127  int c;
12128 
12129  assert( scip != NULL );
12130 
12131  /* release the rows of all constraints */
12132  for( c = 0; c < nconss; ++c )
12133  {
12134  consdata = SCIPconsGetData(conss[c]);
12135  assert(consdata != NULL);
12136 
12137  if( consdata->row != NULL )
12138  {
12139  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12140  }
12141  }
12142 
12143  return SCIP_OKAY;
12144 }
12145 
12146 /** frees specific constraint data */
12147 static
12148 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12149 { /*lint --e{715}*/
12150  SCIP_CONSHDLRDATA* conshdlrdata;
12151 
12152  assert(conshdlr != NULL);
12153  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12154 
12155  /* get event handler */
12156  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12157  assert(conshdlrdata != NULL);
12158  assert(conshdlrdata->eventhdlr != NULL);
12159 
12160  /* free knapsack constraint */
12161  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12162 
12163  return SCIP_OKAY;
12164 }
12165 
12166 /** transforms constraint data into data belonging to the transformed problem */
12167 /**! [SnippetConsTransKnapsack]*/
12168 static
12169 SCIP_DECL_CONSTRANS(consTransKnapsack)
12170 { /*lint --e{715}*/
12171  SCIP_CONSHDLRDATA* conshdlrdata;
12172  SCIP_CONSDATA* sourcedata;
12173  SCIP_CONSDATA* targetdata;
12174 
12175  assert(conshdlr != NULL);
12176  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12178  assert(sourcecons != NULL);
12179  assert(targetcons != NULL);
12180 
12181  sourcedata = SCIPconsGetData(sourcecons);
12182  assert(sourcedata != NULL);
12183  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12184 
12185  /* get event handler */
12186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12187  assert(conshdlrdata != NULL);
12188  assert(conshdlrdata->eventhdlr != NULL);
12189 
12190  /* create target constraint data */
12191  SCIP_CALL( consdataCreate(scip, &targetdata,
12192  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12193 
12194  /* create target constraint */
12195  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12196  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12197  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12198  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12199  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12200 
12201  /* catch events for variables */
12202  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12203 
12204  return SCIP_OKAY;
12205 }
12206 /**! [SnippetConsTransKnapsack]*/
12207 
12208 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12209 static
12210 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12211 { /*lint --e{715}*/
12212  int i;
12213 
12214  *infeasible = FALSE;
12215 
12216  for( i = 0; i < nconss && !(*infeasible); i++ )
12217  {
12218  assert(SCIPconsIsInitial(conss[i]));
12219  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12220  }
12221 
12222  return SCIP_OKAY;
12223 }
12224 
12225 /** separation method of constraint handler for LP solutions */
12226 static
12227 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12228 { /*lint --e{715}*/
12229  SCIP_CONSHDLRDATA* conshdlrdata;
12230  SCIP_Bool sepacardinality;
12231  SCIP_Bool cutoff;
12232 
12233  SCIP_Real loclowerbound;
12234  SCIP_Real glblowerbound;
12235  SCIP_Real cutoffbound;
12236  SCIP_Real maxbound;
12237 
12238  int depth;
12239  int nrounds;
12240  int sepafreq;
12241  int sepacardfreq;
12242  int ncuts;
12243  int maxsepacuts;
12244  int i;
12245 
12246  *result = SCIP_DIDNOTRUN;
12247 
12248  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12249  assert(conshdlrdata != NULL);
12250 
12251  depth = SCIPgetDepth(scip);
12252  nrounds = SCIPgetNSepaRounds(scip);
12253 
12254  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12255  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12256 
12257  /* only call the separator a given number of times at each node */
12258  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12259  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12260  return SCIP_OKAY;
12261 
12262  /* check, if we should additionally separate knapsack cuts */
12263  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12264  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12265  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12266  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12267 
12268  /* check dual bound to see if we want to produce knapsack cuts at this node */
12269  loclowerbound = SCIPgetLocalLowerbound(scip);
12270  glblowerbound = SCIPgetLowerbound(scip);
12271  cutoffbound = SCIPgetCutoffbound(scip);
12272  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12273  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12274  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12275 
12276  /* get the maximal number of cuts allowed in a separation round */
12277  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12278 
12279  *result = SCIP_DIDNOTFIND;
12280  ncuts = 0;
12281  cutoff = FALSE;
12282 
12283  /* separate useful constraints */
12284  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12285  {
12286  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12287  }
12288 
12289  /* adjust return value */
12290  if ( cutoff )
12291  *result = SCIP_CUTOFF;
12292  else if ( ncuts > 0 )
12293  *result = SCIP_SEPARATED;
12294 
12295  return SCIP_OKAY;
12296 }
12297 
12298 
12299 /** separation method of constraint handler for arbitrary primal solutions */
12300 static
12301 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12302 { /*lint --e{715}*/
12303  SCIP_CONSHDLRDATA* conshdlrdata;
12304  SCIP_Bool sepacardinality;
12305  SCIP_Bool cutoff;
12306 
12307  int depth;
12308  int nrounds;
12309  int sepafreq;
12310  int sepacardfreq;
12311  int ncuts;
12312  int maxsepacuts;
12313  int i;
12314 
12315  *result = SCIP_DIDNOTRUN;
12316 
12317  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12318  assert(conshdlrdata != NULL);
12319 
12320  depth = SCIPgetDepth(scip);
12321  nrounds = SCIPgetNSepaRounds(scip);
12322 
12323  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12324  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12325 
12326  /* only call the separator a given number of times at each node */
12327  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12328  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12329  return SCIP_OKAY;
12330 
12331  /* check, if we should additionally separate knapsack cuts */
12332  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12333  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12334  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12335  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12336 
12337  /* get the maximal number of cuts allowed in a separation round */
12338  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12339 
12340  *result = SCIP_DIDNOTFIND;
12341  ncuts = 0;
12342  cutoff = FALSE;
12343 
12344  /* separate useful constraints */
12345  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12346  {
12347  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12348  }
12349 
12350  /* adjust return value */
12351  if ( cutoff )
12352  *result = SCIP_CUTOFF;
12353  else if( ncuts > 0 )
12354  *result = SCIP_SEPARATED;
12355 
12356  return SCIP_OKAY;
12357 }
12358 
12359 /** constraint enforcing method of constraint handler for LP solutions */
12360 static
12361 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12362 { /*lint --e{715}*/
12363  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12364 
12365  return SCIP_OKAY;
12366 }
12367 
12368 /** constraint enforcing method of constraint handler for relaxation solutions */
12369 static
12370 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12371 { /*lint --e{715}*/
12372  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12373 
12374  return SCIP_OKAY;
12375 }
12376 
12377 /** constraint enforcing method of constraint handler for pseudo solutions */
12378 static
12379 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12380 { /*lint --e{715}*/
12381  SCIP_Bool violated;
12382  int i;
12383 
12384  for( i = 0; i < nconss; i++ )
12385  {
12386  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12387  if( violated )
12388  {
12389  *result = SCIP_INFEASIBLE;
12390  return SCIP_OKAY;
12391  }
12392  }
12393  *result = SCIP_FEASIBLE;
12394 
12395  return SCIP_OKAY;
12396 }
12397 
12398 /** feasibility check method of constraint handler for integral solutions */
12399 static
12400 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12401 { /*lint --e{715}*/
12402  SCIP_Bool violated;
12403  int i;
12404 
12405  *result = SCIP_FEASIBLE;
12406 
12407  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12408  {
12409  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12410  if( violated )
12411  *result = SCIP_INFEASIBLE;
12412  }
12413 
12414  return SCIP_OKAY;
12415 }
12416 
12417 /** domain propagation method of constraint handler */
12418 static
12419 SCIP_DECL_CONSPROP(consPropKnapsack)
12420 { /*lint --e{715}*/
12421  SCIP_CONSHDLRDATA* conshdlrdata;
12422  SCIP_Bool cutoff;
12423  SCIP_Bool redundant;
12424  SCIP_Bool inpresolve;
12425  int nfixedvars;
12426  int i;
12428  cutoff = FALSE;
12429  nfixedvars = 0;
12430 
12431  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12432  assert(conshdlrdata != NULL);
12433 
12434  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12435  assert(!inpresolve || SCIPinProbing(scip));
12436 
12437  /* process useful constraints */
12438  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12439  {
12440  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12441  * otherwise the multi-aggregation should be resolved
12442  */
12443  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12444  continue;
12445 #ifndef NDEBUG
12446  else
12447  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12448 #endif
12449 
12450  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12451 
12452  /* unmark the constraint to be propagated */
12453  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12454  }
12455 
12456  /* adjust result code */
12457  if( cutoff )
12458  *result = SCIP_CUTOFF;
12459  else if( nfixedvars > 0 )
12460  *result = SCIP_REDUCEDDOM;
12461  else
12462  *result = SCIP_DIDNOTFIND;
12463 
12464  return SCIP_OKAY; /*lint !e438*/
12465 }
12466 
12467 /** presolving method of constraint handler */
12468 static
12469 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12470 { /*lint --e{574,715}*/
12471  SCIP_CONSHDLRDATA* conshdlrdata;
12472  SCIP_CONSDATA* consdata;
12473  SCIP_CONS* cons;
12474  SCIP_Bool cutoff;
12475  SCIP_Bool redundant;
12476  SCIP_Bool success;
12477  int oldnfixedvars;
12478  int oldnchgbds;
12479  int oldndelconss;
12480  int oldnaddconss;
12481  int oldnchgcoefs;
12482  int oldnchgsides;
12483  int firstchange;
12484  int c;
12485  SCIP_Bool newchanges;
12486 
12487  /* remember old preprocessing counters */
12488  cutoff = FALSE;
12489  oldnfixedvars = *nfixedvars;
12490  oldnchgbds = *nchgbds;
12491  oldndelconss = *ndelconss;
12492  oldnaddconss = *naddconss;
12493  oldnchgcoefs = *nchgcoefs;
12494  oldnchgsides = *nchgsides;
12495  firstchange = INT_MAX;
12496 
12497  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12498 
12499  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12500  assert(conshdlrdata != NULL);
12501 
12502  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12503  {
12504  int thisnfixedvars;
12505  int thisnchgbds;
12506 
12507  cons = conss[c];
12508  consdata = SCIPconsGetData(cons);
12509  assert(consdata != NULL);
12510 
12511  /* update data structures */
12512  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12513  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12514  {
12515  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12516  if( cutoff )
12517  break;
12518  }
12519 
12520  /* force presolving the constraint in the initial round */
12521  if( nrounds == 0 )
12522  consdata->presolvedtiming = 0;
12523  else if( consdata->presolvedtiming >= presoltiming )
12524  continue;
12525 
12526  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12527  SCIPdebugPrintCons(scip, cons, NULL);
12528  consdata->presolvedtiming = presoltiming;
12529 
12530  thisnfixedvars = *nfixedvars;
12531  thisnchgbds = *nchgbds;
12532 
12533  /* merge constraint, so propagation works better */
12534  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12535  if( cutoff )
12536  break;
12537 
12538  /* add cliques in the knapsack to the clique table */
12539  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12540  {
12541  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12542  if( cutoff )
12543  break;
12544  }
12545 
12546  /* propagate constraint */
12547  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12548  {
12549  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12550 
12551  if( cutoff )
12552  break;
12553  if( redundant )
12554  {
12555  (*ndelconss)++;
12556  continue;
12557  }
12558  }
12559 
12560  /* remove again all fixed variables, if further fixings were found */
12561  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12562  {
12563  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12564  if( cutoff )
12565  break;
12566 
12567  thisnfixedvars = *nfixedvars;
12568  }
12569 
12570  if( !SCIPconsIsModifiable(cons) )
12571  {
12572  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12573  if( consdata->weightsum <= consdata->capacity )
12574  {
12575  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12576  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12577  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12578  continue;
12579  }
12580 
12581  /* divide weights by their greatest common divisor */
12582  normalizeWeights(cons, nchgcoefs, nchgsides);
12583 
12584  /* try to simplify inequalities */
12585  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12586  {
12587  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12588  if( cutoff )
12589  break;
12590 
12591  if( SCIPconsIsDeleted(cons) )
12592  continue;
12593 
12594  /* remove again all fixed variables, if further fixings were found */
12595  if( *nfixedvars > thisnfixedvars )
12596  {
12597  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12598  if( cutoff )
12599  break;
12600  }
12601  }
12602 
12603  /* tighten capacity and weights */
12604  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12605  if( cutoff )
12606  break;
12607 
12608  if( SCIPconsIsActive(cons) )
12609  {
12610  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12611  {
12612  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12613  * dual reduction
12614  */
12615  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12616  if( redundant )
12617  continue;
12618  }
12619 
12620  /* check if knapsack constraint is parallel to objective function */
12621  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12622  }
12623  }
12624  /* remember the first changed constraint to begin the next aggregation round with */
12625  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12626  firstchange = c;
12627  }
12628 
12629  /* preprocess pairs of knapsack constraints */
12630  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12631  {
12632  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12633  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12634  }
12635 
12636  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12637  success = TRUE;
12638  else
12639  success = FALSE;
12640 
12641  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12642  {
12643  SCIP_Longint npaircomparisons;
12644 
12645  npaircomparisons = 0;
12646  oldndelconss = *ndelconss;
12647  oldnchgsides = *nchgsides;
12648  oldnchgcoefs = *nchgcoefs;
12649 
12650  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12651  {
12652  cons = conss[c];
12653  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12654  continue;
12655 
12656  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12657 
12658  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12659 
12660  if( npaircomparisons > NMINCOMPARISONS )
12661  {
12662  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12663  success = TRUE;
12664  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12665  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12666  break;
12667  oldndelconss = *ndelconss;
12668  oldnchgsides = *nchgsides;
12669  oldnchgcoefs = *nchgcoefs;
12670  npaircomparisons = 0;
12671  }
12672  }
12673  }
12674 #ifdef WITH_CARDINALITY_UPGRADE
12675  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12676  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12677  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12678  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12679  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12680  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12681  * as well, we better keep this code disabled. */
12682  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12683  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12684  {
12685  SCIP_HASHMAP* varhash;
12686  SCIP_VAR** cardvars;
12687  SCIP_Real* cardweights;
12688  int noldupgdconss;
12689  int nscipvars;
12690  int makeupgrade;
12691 
12692  noldupgdconss = *nupgdconss;
12693  nscipvars = SCIPgetNVars(scip);
12694  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12695  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12696 
12697  /* set up hash map */
12698  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12699 
12700  /* We loop through all cardinality constraints twice:
12701  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12702  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12703  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12704  * - Second, upgrade knapsack constraints to cardinality constraints. */
12705  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12706  {
12707  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12708  {
12709  SCIP_CONS* cardcons;
12710  SCIP_VAR** vars;
12711  SCIP_Longint* weights;
12712  int nvars;
12713  int v;
12714 
12715  cons = conss[c];
12716  assert( cons != NULL );
12717  consdata = SCIPconsGetData(cons);
12718  assert( consdata != NULL );
12719 
12720  nvars = consdata->nvars;
12721  vars = consdata->vars;
12722  weights = consdata->weights;
12723 
12724  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12725  * - all variables must be binary (always true)
12726  * - all coefficients must be 1.0
12727  * - the right hand side must be smaller than nvars
12728  */
12729  if ( consdata->capacity >= nvars )
12730  continue;
12731 
12732  /* the weights are sorted: check first and last weight */
12733  assert( consdata->sorted );
12734  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12735  continue;
12736 
12737  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12738  for (v = 0; v < nvars; ++v)
12739  {
12740  SCIP_BOUNDTYPE* impltypes;
12741  SCIP_Real* implbounds;
12742  SCIP_VAR** implvars;
12743  SCIP_VAR* var;
12744  int nimpls;
12745  int j;
12746 
12747  var = consdata->vars[v];
12748  assert( var != NULL );
12749  assert( SCIPvarIsBinary(var) );
12750 
12751  /* ignore non-active variables */
12752  if ( ! SCIPvarIsActive(var) )
12753  break;
12754 
12755  /* be sure that implication variable has zero objective */
12756  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12757  break;
12758 
12759  nimpls = SCIPvarGetNImpls(var, FALSE);
12760  implvars = SCIPvarGetImplVars(var, FALSE);
12761  implbounds = SCIPvarGetImplBounds(var, FALSE);
12762  impltypes = SCIPvarGetImplTypes(var, FALSE);
12763 
12764  for (j = 0; j < nimpls; ++j)
12765  {
12766  /* be sure that continuous variable is fixed to 0 */
12767  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12768  continue;
12769 
12770  /* cannot currently deal with nonzero fixings */
12771  if ( ! SCIPisZero(scip, implbounds[j]) )
12772  continue;
12773 
12774  /* number of down locks should be one */
12775  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12776  continue;
12777 
12778  cardvars[v] = implvars[j];
12779  cardweights[v] = (SCIP_Real) v;
12780 
12781  break;
12782  }
12783 
12784  /* found no variable upper bound candidate -> exit */
12785  if ( j >= nimpls )
12786  break;
12787  }
12788 
12789  /* did not find fitting variable upper bound for some variable -> exit */
12790  if ( v < nvars )
12791  break;
12792 
12793  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12794  * in which the binary variable is involved in */
12795  if ( makeupgrade == 0 )
12796  {
12797  for (v = 0; v < nvars; ++v)
12798  {
12799  if ( SCIPhashmapExists(varhash, vars[v]) )
12800  {
12801  int image;
12802 
12803  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12804  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12805  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12806  }
12807  else
12808  {
12809  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12810  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12811  assert( SCIPhashmapExists(varhash, vars[v]) );
12812  }
12813  }
12814  }
12815  else
12816  {
12817  SCIP_CONS* origcons;
12818 
12819  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12820  * knapsack constraint coincides with the number of variable up locks */
12821  for (v = 0; v < nvars; ++v)
12822  {
12823  assert( SCIPhashmapExists(varhash, vars[v]) );
12824  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12825  break;
12826  }
12827  if ( v < nvars )
12828  break;
12829 
12830  /* store that we have upgraded */
12831  conshdlrdata->upgradedcard = TRUE;
12832 
12833  /* at this point we found suitable variable upper bounds */
12834  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12835 
12836  /* create cardinality constraint */
12837  assert( ! SCIPconsIsModifiable(cons) );
12838  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12842 #ifdef SCIP_DEBUG
12843  SCIPprintCons(scip, cons, NULL);
12844  SCIPinfoMessage(scip, NULL, "\n");
12845  SCIPprintCons(scip, cardcons, NULL);
12846  SCIPinfoMessage(scip, NULL, "\n");
12847 #endif
12848  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12849  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12850  ++(*nupgdconss);
12851 
12852  /* delete oknapsack constraint */
12853  SCIP_CALL( SCIPdelCons(scip, cons) );
12854  ++(*ndelconss);
12855 
12856  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12857  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12858  * although the cardinality constraint is satisfied. */
12859  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12860  assert( origcons != NULL );
12861  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12862 
12863  for (v = 0; v < nvars; ++v)
12864  {
12865  int image;
12866 
12867  assert ( SCIPhashmapExists(varhash, vars[v]) );
12868  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12869  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12870  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12871  }
12872  }
12873  }
12874  }
12875  SCIPhashmapFree(&varhash);
12876  SCIPfreeBufferArray(scip, &cardweights);
12877  SCIPfreeBufferArray(scip, &cardvars);
12878 
12879  if ( *nupgdconss > noldupgdconss )
12880  success = TRUE;
12881  }
12882 #endif
12883 
12884  if( cutoff )
12885  *result = SCIP_CUTOFF;
12886  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12887  *result = SCIP_SUCCESS;
12888  else
12889  *result = SCIP_DIDNOTFIND;
12890 
12891  return SCIP_OKAY;
12892 }
12893 
12894 /** propagation conflict resolving method of constraint handler */
12895 static
12896 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12897 { /*lint --e{715}*/
12898  SCIP_CONSDATA* consdata;
12899  SCIP_Longint capsum;
12900  int i;
12901 
12902  assert(result != NULL);
12903 
12904  consdata = SCIPconsGetData(cons);
12905  assert(consdata != NULL);
12906 
12907  /* check if we fixed a binary variable to one (due to negated clique) */
12908  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12909  {
12910  for( i = 0; i < consdata->nvars; ++i )
12911  {
12912  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12913  {
12914  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12915  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12916  break;
12917  }
12918  }
12919  assert(i < consdata->nvars);
12920  }
12921  else
12922  {
12923  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12924  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12925  * knapsack constraint, see one above call of SCIPinferBinvarCons
12926  */
12927  if( inferinfo < 0 )
12928  capsum = 0;
12929  else
12930  {
12931  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12932  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12933  */
12934  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12935  capsum = consdata->weights[inferinfo];
12936  else
12937  {
12938  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12939  {}
12940  assert(i < consdata->nvars);
12941  capsum = consdata->weights[i];
12942  }
12943  }
12944 
12945  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12946  * the capacity
12947  */
12948  if( capsum <= consdata->capacity )
12949  {
12950  for( i = 0; i < consdata->nvars; i++ )
12951  {
12952  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12953  {
12954  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12955  capsum += consdata->weights[i];
12956  if( capsum > consdata->capacity )
12957  break;
12958  }
12959  }
12960  }
12961  }
12962 
12963  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12964  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12965  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12966  * used to fix variables to zero.
12967  *
12968  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12969  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12970  * one.
12971  */
12972  *result = SCIP_SUCCESS;
12973 
12974  return SCIP_OKAY;
12975 }
12976 
12977 /** variable rounding lock method of constraint handler */
12978 /**! [SnippetConsLockKnapsack] */
12979 static
12980 SCIP_DECL_CONSLOCK(consLockKnapsack)
12981 { /*lint --e{715}*/
12982  SCIP_CONSDATA* consdata;
12983  int i;
12984 
12985  consdata = SCIPconsGetData(cons);
12986  assert(consdata != NULL);
12987 
12988  for( i = 0; i < consdata->nvars; i++)
12989  {
12990  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
12991  }
12992 
12993  return SCIP_OKAY;
12994 }
12995 /**! [SnippetConsLockKnapsack] */
12996 
12997 
12998 /** variable deletion method of constraint handler */
12999 static
13000 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13001 {
13002  assert(scip != NULL);
13003  assert(conshdlr != NULL);
13004  assert(conss != NULL || nconss == 0);
13005 
13006  if( nconss > 0 )
13007  {
13008  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13009  }
13010 
13011  return SCIP_OKAY;
13012 }
13013 
13014 /** constraint display method of constraint handler */
13015 static
13016 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13017 { /*lint --e{715}*/
13018  SCIP_CONSDATA* consdata;
13019  int i;
13020 
13021  assert( scip != NULL );
13022  assert( conshdlr != NULL );
13023  assert( cons != NULL );
13025  consdata = SCIPconsGetData(cons);
13026  assert(consdata != NULL);
13027 
13028  for( i = 0; i < consdata->nvars; ++i )
13029  {
13030  if( i > 0 )
13031  SCIPinfoMessage(scip, file, " ");
13032  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13033  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13034  }
13035  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13036 
13037  return SCIP_OKAY;
13038 }
13039 
13040 /** constraint copying method of constraint handler */
13041 static
13042 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13043 { /*lint --e{715}*/
13044  SCIP_VAR** sourcevars;
13045  SCIP_Longint* weights;
13046  SCIP_Real* coefs;
13047  const char* consname;
13048  int nvars;
13049  int v;
13051  /* get variables and coefficients of the source constraint */
13052  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13053  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13054  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13055 
13056  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13057  for( v = 0; v < nvars; ++v )
13058  coefs[v] = (SCIP_Real) weights[v];
13059 
13060  if( name != NULL )
13061  consname = name;
13062  else
13063  consname = SCIPconsGetName(sourcecons);
13064 
13065  /* copy the logic using the linear constraint copy method */
13066  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13067  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13068  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13069  assert(cons != NULL);
13070 
13071  SCIPfreeBufferArray(scip, &coefs);
13072 
13073  return SCIP_OKAY;
13074 }
13075 
13076 /** constraint parsing method of constraint handler */
13077 static
13078 SCIP_DECL_CONSPARSE(consParseKnapsack)
13079 { /*lint --e{715}*/
13080  SCIP_VAR* var;
13081  SCIP_Longint weight;
13082  SCIP_VAR** vars;
13083  SCIP_Longint* weights;
13084  SCIP_Longint capacity;
13085  char* endptr;
13086  int nread;
13087  int nvars;
13088  int varssize;
13089 
13090  assert(scip != NULL);
13091  assert(success != NULL);
13092  assert(str != NULL);
13093  assert(name != NULL);
13094  assert(cons != NULL);
13095 
13096  *success = TRUE;
13097 
13098  nvars = 0;
13099  varssize = 5;
13100  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13101  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13102 
13103  while( *str != '\0' )
13104  {
13105  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13106  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13107  break;
13108 
13109  str += nread;
13110 
13111  /* skip whitespace */
13112  while( isspace((int)*str) )
13113  ++str;
13114 
13115  /* parse variable name */
13116  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13117  if( var == NULL )
13118  {
13119  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13120  *success = FALSE;
13121  break;
13122  }
13123 
13124  str = endptr;
13125 
13126  /* store weight and variable */
13127  if( varssize <= nvars )
13128  {
13129  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13130  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13131  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13132  }
13133 
13134  vars[nvars] = var;
13135  weights[nvars] = weight;
13136  ++nvars;
13137 
13138  /* skip whitespace */
13139  while( isspace((int)*str) )
13140  ++str;
13141  }
13142 
13143  if( *success )
13144  {
13145  if( strncmp(str, "<= ", 3) != 0 )
13146  {
13147  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13148  *success = FALSE;
13149  }
13150  else
13151  {
13152  str += 3;
13153  }
13154  }
13155 
13156  if( *success )
13157  {
13158  /* coverity[secure_coding] */
13159  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13160  {
13161  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13162  *success = FALSE;
13163  }
13164  else
13165  {
13166  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13167  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13168  }
13169  }
13170 
13171  SCIPfreeBufferArray(scip, &vars);
13172  SCIPfreeBufferArray(scip, &weights);
13173 
13174  return SCIP_OKAY;
13175 }
13176 
13177 /** constraint method of constraint handler which returns the variables (if possible) */
13178 static
13179 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13180 { /*lint --e{715}*/
13181  SCIP_CONSDATA* consdata;
13182 
13183  consdata = SCIPconsGetData(cons);
13184  assert(consdata != NULL);
13185 
13186  if( varssize < consdata->nvars )
13187  (*success) = FALSE;
13188  else
13189  {
13190  assert(vars != NULL);
13191 
13192  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13193  (*success) = TRUE;
13194  }
13195 
13196  return SCIP_OKAY;
13197 }
13198 
13199 /** constraint method of constraint handler which returns the number of variables (if possible) */
13200 static
13201 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13202 { /*lint --e{715}*/
13203  SCIP_CONSDATA* consdata;
13204 
13205  consdata = SCIPconsGetData(cons);
13206  assert(consdata != NULL);
13207 
13208  (*nvars) = consdata->nvars;
13209  (*success) = TRUE;
13210 
13211  return SCIP_OKAY;
13212 }
13213 
13214 /*
13215  * Event handler
13216  */
13217 
13218 /** execution method of bound change event handler */
13219 static
13220 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13221 { /*lint --e{715}*/
13222  SCIP_CONSDATA* consdata;
13223 
13224  assert(eventdata != NULL);
13225  assert(eventdata->cons != NULL);
13226 
13227  consdata = SCIPconsGetData(eventdata->cons);
13228  assert(consdata != NULL);
13229 
13230  switch( SCIPeventGetType(event) )
13231  {
13233  consdata->onesweightsum += eventdata->weight;
13234  consdata->presolvedtiming = 0;
13235  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13236  break;
13238  consdata->onesweightsum -= eventdata->weight;
13239  break;
13241  consdata->presolvedtiming = 0;
13242  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13243  break;
13244  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13245  if( !consdata->existmultaggr )
13246  {
13247  SCIP_VAR* var;
13248  var = SCIPeventGetVar(event);
13249  assert(var != NULL);
13250 
13251  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13253  {
13254  consdata->existmultaggr = TRUE;
13255  consdata->merged = FALSE;
13256  }
13257  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13259  consdata->merged = FALSE;
13260  }
13261  /*lint -fallthrough*/
13262  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13263  consdata->presolvedtiming = 0;
13264  break;
13266  consdata->varsdeleted = TRUE;
13267  break;
13268  default:
13269  SCIPerrorMessage("invalid event type %lx\n", SCIPeventGetType(event));
13270  return SCIP_INVALIDDATA;
13271  }
13272 
13273  return SCIP_OKAY;
13274 }
13275 
13276 
13277 /*
13278  * constraint specific interface methods
13279  */
13280 
13281 /** creates the handler for knapsack constraints and includes it in SCIP */
13283  SCIP* scip /**< SCIP data structure */
13284  )
13285 {
13286  SCIP_EVENTHDLRDATA* eventhdlrdata;
13287  SCIP_CONSHDLRDATA* conshdlrdata;
13288  SCIP_CONSHDLR* conshdlr;
13289 
13290  /* create knapsack constraint handler data */
13291  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13292 
13293  /* include event handler for bound change events */
13294  eventhdlrdata = NULL;
13295  conshdlrdata->eventhdlr = NULL;
13296  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13297  eventExecKnapsack, eventhdlrdata) );
13298 
13299  /* get event handler for bound change events */
13300  if( conshdlrdata->eventhdlr == NULL )
13301  {
13302  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13303  return SCIP_PLUGINNOTFOUND;
13304  }
13305 
13306  /* include constraint handler */
13309  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13310  conshdlrdata) );
13311 
13312  assert(conshdlr != NULL);
13313 
13314  /* set non-fundamental callbacks via specific setter functions */
13315  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13316  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13317  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13318  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13319  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13320  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13321  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13322  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13323  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13324  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13325  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13326  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13327  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13328  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13329  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13330  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13332  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13333  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13335  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13336  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13337 
13338  if( SCIPfindConshdlr(scip,"linear") != NULL )
13339  {
13340  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13342  }
13343 
13344  /* add knapsack constraint handler parameters */
13345  SCIP_CALL( SCIPaddIntParam(scip,
13346  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13347  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13348  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13350  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13351  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13352  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13354  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13355  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13356  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13357  SCIP_CALL( SCIPaddIntParam(scip,
13358  "constraints/" CONSHDLR_NAME "/maxrounds",
13359  "maximal number of separation rounds per node (-1: unlimited)",
13360  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13361  SCIP_CALL( SCIPaddIntParam(scip,
13362  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13363  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13364  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13365  SCIP_CALL( SCIPaddIntParam(scip,
13366  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13367  "maximal number of cuts separated per separation round",
13368  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13369  SCIP_CALL( SCIPaddIntParam(scip,
13370  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13371  "maximal number of cuts separated per separation round in the root node",
13372  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13374  "constraints/" CONSHDLR_NAME "/disaggregation",
13375  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13376  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13378  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13379  "should presolving try to simplify knapsacks",
13380  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13382  "constraints/" CONSHDLR_NAME "/negatedclique",
13383  "should negated clique information be used in solving process",
13384  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13386  "constraints/" CONSHDLR_NAME "/presolpairwise",
13387  "should pairwise constraint comparison be performed in presolving?",
13388  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13390  "constraints/" CONSHDLR_NAME "/presolusehashing",
13391  "should hash table be used for detecting redundant constraints in advance",
13392  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13394  "constraints/" CONSHDLR_NAME "/dualpresolving",
13395  "should dual presolving steps be performed?",
13396  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13398  "constraints/" CONSHDLR_NAME "/usegubs",
13399  "should GUB information be used for separation?",
13400  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13402  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13403  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13404  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13406  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13407  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13408  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13410  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13411  "should clique partition information be updated when old partition seems outdated?",
13412  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13414  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13415  "factor on the growth of global cliques to decide when to update a previous "
13416  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13417  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13418 #ifdef WITH_CARDINALITY_UPGRADE
13420  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13421  "if TRUE then try to update knapsack constraints to cardinality constraints",
13422  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13423 #endif
13424  return SCIP_OKAY;
13425 }
13426 
13427 /** creates and captures a knapsack constraint
13428  *
13429  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13430  */
13431 /**! [SnippetConsCreationKnapsack] */
13433  SCIP* scip, /**< SCIP data structure */
13434  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13435  const char* name, /**< name of constraint */
13436  int nvars, /**< number of items in the knapsack */
13437  SCIP_VAR** vars, /**< array with item variables */
13438  SCIP_Longint* weights, /**< array with item weights */
13439  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13440  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13441  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13442  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13443  * Usually set to TRUE. */
13444  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13445  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13446  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13447  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13448  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13449  * Usually set to TRUE. */
13450  SCIP_Bool local, /**< is constraint only valid locally?
13451  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13452  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13453  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13454  * adds coefficients to this constraint. */
13455  SCIP_Bool dynamic, /**< is constraint subject to aging?
13456  * Usually set to FALSE. Set to TRUE for own cuts which
13457  * are separated as constraints. */
13458  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13459  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13460  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13461  * if it may be moved to a more global node?
13462  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13463  )
13464 {
13465  SCIP_CONSHDLRDATA* conshdlrdata;
13466  SCIP_CONSHDLR* conshdlr;
13467  SCIP_CONSDATA* consdata;
13468 
13469  /* find the knapsack constraint handler */
13470  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13471  if( conshdlr == NULL )
13472  {
13473  SCIPerrorMessage("knapsack constraint handler not found\n");
13474  return SCIP_PLUGINNOTFOUND;
13475  }
13476 
13477  /* get event handler */
13478  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13479  assert(conshdlrdata != NULL);
13480  assert(conshdlrdata->eventhdlr != NULL);
13481 
13482  /* create constraint data */
13483  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13484 
13485  /* create constraint */
13486  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13487  local, modifiable, dynamic, removable, stickingatnode) );
13488 
13489  /* catch events for variables */
13490  if( SCIPisTransformed(scip) )
13491  {
13492  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13493  }
13494 
13495  return SCIP_OKAY;
13496 }
13497 /**! [SnippetConsCreationKnapsack] */
13498 
13499 /** creates and captures a knapsack constraint
13500  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13501  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13502  *
13503  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13504  *
13505  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13506  */
13508  SCIP* scip, /**< SCIP data structure */
13509  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13510  const char* name, /**< name of constraint */
13511  int nvars, /**< number of items in the knapsack */
13512  SCIP_VAR** vars, /**< array with item variables */
13513  SCIP_Longint* weights, /**< array with item weights */
13514  SCIP_Longint capacity /**< capacity of knapsack */
13515  )
13516 {
13517  assert(scip != NULL);
13518 
13519  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13520  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13521 
13522  return SCIP_OKAY;
13523 }
13524 
13525 /** adds new item to knapsack constraint */
13527  SCIP* scip, /**< SCIP data structure */
13528  SCIP_CONS* cons, /**< constraint data */
13529  SCIP_VAR* var, /**< item variable */
13530  SCIP_Longint weight /**< item weight */
13531  )
13532 {
13533  assert(var != NULL);
13534  assert(scip != NULL);
13535 
13536  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13537  {
13538  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13539  return SCIP_INVALIDDATA;
13540  }
13541 
13542  SCIP_CALL( addCoef(scip, cons, var, weight) );
13543 
13544  return SCIP_OKAY;
13545 }
13546 
13547 /** gets the capacity of the knapsack constraint */
13549  SCIP* scip, /**< SCIP data structure */
13550  SCIP_CONS* cons /**< constraint data */
13551  )
13552 {
13553  SCIP_CONSDATA* consdata;
13554 
13555  assert(scip != NULL);
13557  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13558  {
13559  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13560  SCIPABORT();
13561  return 0; /*lint !e527*/
13562  }
13563 
13564  consdata = SCIPconsGetData(cons);
13565  assert(consdata != NULL);
13566 
13567  return consdata->capacity;
13568 }
13569 
13570 /** changes capacity of the knapsack constraint
13571  *
13572  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13573  */
13575  SCIP* scip, /**< SCIP data structure */
13576  SCIP_CONS* cons, /**< constraint data */
13577  SCIP_Longint capacity /**< new capacity of knapsack */
13578  )
13579 {
13580  SCIP_CONSDATA* consdata;
13581 
13582  assert(scip != NULL);
13583 
13584  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13585  {
13586  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13587  return SCIP_INVALIDDATA;
13588  }
13589 
13590  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13591  {
13592  SCIPerrorMessage("method can only be called during problem creation stage\n");
13593  return SCIP_INVALIDDATA;
13594  }
13595 
13596  consdata = SCIPconsGetData(cons);
13597  assert(consdata != NULL);
13598 
13599  consdata->capacity = capacity;
13600 
13601  return SCIP_OKAY;
13602 }
13603 
13604 /** gets the number of items in the knapsack constraint */
13606  SCIP* scip, /**< SCIP data structure */
13607  SCIP_CONS* cons /**< constraint data */
13608  )
13609 {
13610  SCIP_CONSDATA* consdata;
13611 
13612  assert(scip != NULL);
13614  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13615  {
13616  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13617  SCIPABORT();
13618  return -1; /*lint !e527*/
13619  }
13620 
13621  consdata = SCIPconsGetData(cons);
13622  assert(consdata != NULL);
13623 
13624  return consdata->nvars;
13625 }
13626 
13627 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13629  SCIP* scip, /**< SCIP data structure */
13630  SCIP_CONS* cons /**< constraint data */
13631  )
13632 {
13633  SCIP_CONSDATA* consdata;
13634 
13635  assert(scip != NULL);
13637  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13638  {
13639  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13640  SCIPABORT();
13641  return NULL; /*lint !e527*/
13642  }
13643 
13644  consdata = SCIPconsGetData(cons);
13645  assert(consdata != NULL);
13646 
13647  return consdata->vars;
13648 }
13649 
13650 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13652  SCIP* scip, /**< SCIP data structure */
13653  SCIP_CONS* cons /**< constraint data */
13654  )
13655 {
13656  SCIP_CONSDATA* consdata;
13657 
13658  assert(scip != NULL);
13660  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13661  {
13662  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13663  SCIPABORT();
13664  return NULL; /*lint !e527*/
13665  }
13666 
13667  consdata = SCIPconsGetData(cons);
13668  assert(consdata != NULL);
13669 
13670  return consdata->weights;
13671 }
13672 
13673 /** gets the dual solution of the knapsack constraint in the current LP */
13675  SCIP* scip, /**< SCIP data structure */
13676  SCIP_CONS* cons /**< constraint data */
13677  )
13678 {
13679  SCIP_CONSDATA* consdata;
13680 
13681  assert(scip != NULL);
13683  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13684  {
13685  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13686  SCIPABORT();
13687  return SCIP_INVALID; /*lint !e527*/
13688  }
13689 
13690  consdata = SCIPconsGetData(cons);
13691  assert(consdata != NULL);
13692 
13693  if( consdata->row != NULL )
13694  return SCIProwGetDualsol(consdata->row);
13695  else
13696  return 0.0;
13697 }
13698 
13699 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13701  SCIP* scip, /**< SCIP data structure */
13702  SCIP_CONS* cons /**< constraint data */
13703  )
13704 {
13705  SCIP_CONSDATA* consdata;
13706 
13707  assert(scip != NULL);
13709  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13710  {
13711  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13712  SCIPABORT();
13713  return SCIP_INVALID; /*lint !e527*/
13714  }
13715 
13716  consdata = SCIPconsGetData(cons);
13717  assert(consdata != NULL);
13718 
13719  if( consdata->row != NULL )
13720  return SCIProwGetDualfarkas(consdata->row);
13721  else
13722  return 0.0;
13723 }
13724 
13725 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13726  * the user must not modify the row!
13727  */
13729  SCIP* scip, /**< SCIP data structure */
13730  SCIP_CONS* cons /**< constraint data */
13731  )
13732 {
13733  SCIP_CONSDATA* consdata;
13734 
13735  assert(scip != NULL);
13737  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13738  {
13739  SCIPerrorMessage("constraint is not a knapsack\n");
13740  SCIPABORT();
13741  return NULL; /*lint !e527*/
13742  }
13743 
13744  consdata = SCIPconsGetData(cons);
13745  assert(consdata != NULL);
13746 
13747  return consdata->row;
13748 }
13749 
13750 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13752  SCIP* scip, /**< SCIP data structure */
13753  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13754  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13755  )
13756 {
13757  SCIP_CONSHDLR* conshdlr;
13758  SCIP_CONS** conss;
13759  int nconss;
13760  int i;
13761 
13762  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13763  if( conshdlr == NULL )
13764  return SCIP_OKAY;
13765 
13766  assert(infeasible != NULL);
13767  *infeasible = FALSE;
13768 
13769  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13770  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13771 
13772  for( i = 0; i < nconss; ++i )
13773  {
13774  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13775 
13776  if( *infeasible )
13777  break;
13778  }
13779 
13780  return SCIP_OKAY;
13781 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define KNAPSACKRELAX_MAXSCALE
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int * gubconssidx
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7230
#define DEFAULT_DETECTCUTOFFBOUND
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4197
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4602
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2166
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17159
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_Real SCIPepsilon(SCIP *scip)
GUBVarstatus
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:687
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3351
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2487
SCIP_EXPORT SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17172
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17176
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
#define CONSHDLR_DESC
Definition: cons_knapsack.c:70
public methods for SCIP parameter handling
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:85
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:63
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1989
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip_prob.c:2892
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:221
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:453
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5177
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:934
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8316
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3250
public methods for memory management
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:308
static SCIP_DECL_CONSINIT(consInitKnapsack)
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:113
#define DEFAULT_CLQPARTUPDATEFAC
public methods for implications, variable bounds, and cliques
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8276
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1951
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:166
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4256
GUBCONSSTATUS * gubconsstatus
#define SCIP_MAXSTRLEN
Definition: def.h:279
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1477
public methods for conflict handler plugins and conflict analysis
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip_var.c:1557
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:72
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5697
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2548
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1594
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1211
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1353
SCIP_EXPORT void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5294
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
SCIP_EXPORT SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:844
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2152
#define LINCONSUPGD_PRIORITY
Definition: cons_knapsack.c:95
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9022
#define DEFAULT_CLIQUEEXTRACTFACTOR
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
SCIP_GUBCONS ** gubconss
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:146
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:419
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_EXPORT void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip_cons.c:747
GUBConsstatus
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3132
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define CONSHDLR_SEPAFREQ
Definition: cons_knapsack.c:74
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
SCIP_EXPORT SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17197
SCIP_EXPORT SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17962
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1986
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8138
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:216
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1368
#define FALSE
Definition: def.h:73
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define MAX_CLIQUELENGTH
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17515
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:79
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1428
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:76
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3468
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:524
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8246
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip_prob.c:3579
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:277
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17340
public methods for problem variables
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:521
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3690
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_EXPORT SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17991
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2617
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:87
#define SCIPdebugMessage
Definition: pub_message.h:87
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17136
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1233
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:119
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
#define SCIP_LONGINT_MAX
Definition: def.h:149
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:381
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:136
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1258
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
public methods for SCIP variables
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:501
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:84
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
#define DEFAULT_PRESOLUSEHASHING
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4347
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
SCIP_EXPORT void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17871
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:559
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1461
SCIP_EXPORT void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
public methods for numerical tolerances
SCIP_EXPORT SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17459
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_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2837
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
public methods for querying solving statistics
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17387
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define DEFAULT_SEPACARDFREQ
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:69
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3221
public methods for the branch-and-bound tree
static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1524
static SCIP_DECL_CONSPARSE(consParseKnapsack)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
#define DEFAULT_MAXROUNDS
#define DEFAULT_DISAGGREGATION
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3363
SCIP_VAR * w
Definition: circlepacking.c:58
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define CONSHDLR_SEPAPRIORITY
Definition: cons_knapsack.c:71
public methods for managing constraints
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10912
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:405
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17017
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1337
SCIP_EXPORT void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
enum GUBVarstatus GUBVARSTATUS
SCIP_EXPORT SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17208
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_EXPORT SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12049
#define SCIPdebugPrintf
Definition: pub_message.h:90
SCIP_EXPORT void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
SCIP_EXPORT SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17483
SCIP_EXPORT int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17945
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
public methods for event handler plugins and event handlers
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2214
#define DEFAULT_PRESOLPAIRWISE
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:596
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1941
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:109
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIPInterval sqrt(const SCIPInterval &x)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define DEFAULT_DUALPRESOLVING
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4559
SCIP_EXPORT SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17923
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
SCIP_EXPORT void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:76
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7549
#define NULL
Definition: lpi_spx1.cpp:155
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:187
#define DEFAULT_NEGATEDCLIQUE
SCIP_EXPORT void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
public methods for problem copies
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip_copy.c:646
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:477
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8107
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
#define SCIP_CALL(x)
Definition: def.h:370
SCIP_EXPORT int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17901
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:68
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:632
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1021
SCIP_VAR * h
Definition: circlepacking.c:59
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
GUBVARSTATUS * gubvarsstatus
SCIP_EXPORT const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:697
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
Definition: grphload.c:88
#define KNAPSACKRELAX_MAXDNOM
#define DEFAULT_MAXSEPACUTSROOT
static SCIP_DECL_CONSFREE(consFreeKnapsack)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7449
static SCIP_DECL_CONSEXIT(consExitKnapsack)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
public methods for constraint handler plugins and constraints
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5076
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1749
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8346
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible)
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17189
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:220
public data structures and miscellaneous methods
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4432
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2286
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:638
SCIP_EXPORT void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define SCIP_Bool
Definition: def.h:70
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
SCIP_EXPORT SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17471
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1208
#define MINGAINPERNMINCOMPARISONS
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3014
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
SCIP_EXPORT void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
static SCIP_DECL_CONSPROP(consPropKnapsack)
SCIP_EXPORT SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11989
#define MAXABSVBCOEF
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:80
#define DEFAULT_MAXSEPACUTS
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17677
#define DEFAULT_MAXCARDBOUNDDIST
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4187
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
#define MAX(x, y)
Definition: tclique_def.h:83
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3363
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1308
public methods for LP management
#define DEFAULT_USEGUBS
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8386
#define KNAPSACKRELAX_MAXDELTA
public methods for cuts and aggregation rows
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:98
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:88
#define CONSHDLR_NAME
Definition: cons_knapsack.c:69
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4616
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:88
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8256
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:81
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8250
int SCIPgetNSepaRounds(SCIP *scip)
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_EXPORT SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17238
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:70
Constraint handler for linear constraints in their most general form, .
#define IDX(j, d)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_EXPORT SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18030
int * gubvarsidx
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8336
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17723
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define SCIP_MAXTREEDEPTH
Definition: def.h:306
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:95
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:130
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1979
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
public methods for the LP relaxation, rows and columns
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2125
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3193
SCIP_EXPORT void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17733
methods for sorting joint arrays of various types
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1390
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
public methods for branching rule plugins and branching
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_VAR ** b
Definition: circlepacking.c:56
static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:221
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
public methods for managing events
general public methods
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:121
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
static SCIP_DECL_CONSLOCK(consLockKnapsack)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
public methods for solutions
SCIP_EXPORT void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8266
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17667
public methods for the probing mode
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
constraint handler for cardinality constraints
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17881
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1641
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
SCIP_EXPORT int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17435
#define DEFAULT_DETECTLOWERBOUND
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4539
public methods for message output
#define HASHSIZE_KNAPSACKCONS
enum GUBConsstatus GUBCONSSTATUS
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17891
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:97
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6895
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10604
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:74
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8077
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1245
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8206
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:163
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8097
#define GUBCONSGROWVALUE
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
#define EVENTTYPE_KNAPSACK
Definition: cons_knapsack.c:89
#define SCIP_INVALID
Definition: def.h:183
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:75
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:82
SCIP_EXPORT SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17977
#define SCIP_Longint
Definition: def.h:148
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8356
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4167
SCIP_EXPORT SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:11249
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1044
SCIP_EXPORT int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17360
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2764
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
SCIP_EXPORT SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:12081
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1721
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3341
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
public methods for separators
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8590
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9114
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
#define USESUPADDLIFT
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:429
SCIP_EXPORT int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18019
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1690
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:266
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:9458
#define SCIPABORT()
Definition: def.h:342
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
public methods for global and local (sub)problems
#define MAXCOVERSIZEITERLEWI
SCIP_EXPORT SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17933
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:106
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8296
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17913
#define DEFAULT_UPDATECLIQUEPARTITIONS
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:73
SCIP_EXPORT SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17447
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:62
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:609
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17859
SCIP_EXPORT int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17350
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1399
#define DEFAULT_SIMPLIFYINEQUALITIES
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8326
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4846
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
methods for selecting (weighted) k-medians
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11713
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1283
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3297
memory allocation routines