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-2019 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 scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_knapsack.c
17  * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
18  * @author Tobias Achterberg
19  * @author Xin Liu
20  * @author Kati Wolter
21  * @author Michael Winkler
22  * @author Tobias Fischer
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #include "blockmemshell/memory.h"
28 #include "scip/cons_knapsack.h"
29 #include "scip/cons_linear.h"
30 #include "scip/cons_logicor.h"
31 #include "scip/cons_setppc.h"
32 #include "scip/pub_cons.h"
33 #include "scip/pub_event.h"
34 #include "scip/pub_implics.h"
35 #include "scip/pub_lp.h"
36 #include "scip/pub_message.h"
37 #include "scip/pub_misc.h"
38 #include "scip/pub_misc_select.h"
39 #include "scip/pub_misc_sort.h"
40 #include "scip/pub_sepa.h"
41 #include "scip/pub_var.h"
42 #include "scip/scip_branch.h"
43 #include "scip/scip_conflict.h"
44 #include "scip/scip_cons.h"
45 #include "scip/scip_copy.h"
46 #include "scip/scip_cut.h"
47 #include "scip/scip_event.h"
48 #include "scip/scip_general.h"
49 #include "scip/scip_lp.h"
50 #include "scip/scip_mem.h"
51 #include "scip/scip_message.h"
52 #include "scip/scip_numerics.h"
53 #include "scip/scip_param.h"
54 #include "scip/scip_prob.h"
55 #include "scip/scip_probing.h"
56 #include "scip/scip_sol.h"
57 #include "scip/scip_solvingstats.h"
58 #include "scip/scip_tree.h"
59 #include "scip/scip_var.h"
60 #include <ctype.h>
61 #include <string.h>
62 
63 #ifdef WITH_CARDINALITY_UPGRADE
64 #include "scip/cons_cardinality.h"
65 #endif
66 
67 /* constraint handler properties */
68 #define CONSHDLR_NAME "knapsack"
69 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
70 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
71 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
72 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
73 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
74 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
75 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
76  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
77 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
78 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
79 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
80 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
81 
82 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
83 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
84 
85 #define EVENTHDLR_NAME "knapsack"
86 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
87 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
88  | SCIP_EVENTTYPE_UBTIGHTENED \
89  | SCIP_EVENTTYPE_VARFIXED \
90  | SCIP_EVENTTYPE_VARDELETED \
91  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
92 
93 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
94 
95 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
96 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
97 
98 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
99 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
100 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
102 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
103 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
104 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
105 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
106 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
107 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
108  * to best node's dual bound for separating knapsack cuts */
109 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
110 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
111 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
113 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
114 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
116 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
117 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
119 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
120 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
121 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
122  * comparison round */
123 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
124 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
125  * function defining an upper bound and prevent these constraints from
126  * entering the LP */
127 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
128  * function defining a lower bound and prevent these constraints from
129  * entering the LP */
130 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
131 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
133 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
134 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
135 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
136 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
137  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
138 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
139 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
140 #ifdef WITH_CARDINALITY_UPGRADE
141 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
142 #endif
144 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
145 
146 /*
147  * Data structures
148  */
149 
150 /** constraint handler data */
151 struct SCIP_ConshdlrData
152 {
153  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
154  * you have to clear it at the end, exists only in presolving stage */
155  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
156  * you have to clear it at the end, exists only in presolving stage */
157  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
158  * you have to clear it at the end, exists only in presolving stage */
159  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
160  * you have to clear it at the end, exists only in presolving stage */
161  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
162  * you have to clear it at the end, exists only in presolving stage */
163  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
164  * you have to clear it at the end, exists only in presolving stage */
165  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
166  * you have to clear it at the end, exists only in presolving stage */
167  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
168  * you have to clear it at the end, exists only in presolving stage */
169  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
170  * you have to clear it at the end */
171  int ints1size; /**< size of ints1 array */
172  int ints2size; /**< size of ints2 array */
173  int longints1size; /**< size of longints1 array */
174  int longints2size; /**< size of longints2 array */
175  int bools1size; /**< size of bools1 array */
176  int bools2size; /**< size of bools2 array */
177  int bools3size; /**< size of bools3 array */
178  int bools4size; /**< size of bools4 array */
179  int reals1size; /**< size of reals1 array */
180  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
181  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
182  * to best node's dual bound for separating knapsack cuts */
183  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
184  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
185  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
186  int maxsepacuts; /**< maximal number of cuts separated per separation round */
187  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
188  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
189  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
190  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
191  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
192  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
193  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
194  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
195  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
196  * function defining an upper bound and prevent these constraints from
197  * entering the LP */
198  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
199  * function defining a lower bound and prevent these constraints from
200  * entering the LP */
201  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
202  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
203  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
204  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
205 #ifdef WITH_CARDINALITY_UPGRADE
206  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
207  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
208 #endif
209 };
210 
211 
212 /** constraint data for knapsack constraints */
213 struct SCIP_ConsData
214 {
215  SCIP_VAR** vars; /**< variables in knapsack constraint */
216  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
217  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
218  int* cliquepartition; /**< clique indices of the clique partition */
219  int* negcliquepartition; /**< clique indices of the negated clique partition */
220  SCIP_ROW* row; /**< corresponding LP row */
221  int nvars; /**< number of variables in knapsack constraint */
222  int varssize; /**< size of vars, weights, and eventdata arrays */
223  int ncliques; /**< number of cliques in the clique partition */
224  int nnegcliques; /**< number of cliques in the negated clique partition */
225  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
226  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
227  SCIP_Longint capacity; /**< capacity of knapsack */
228  SCIP_Longint weightsum; /**< sum of all weights */
229  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
230  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
231  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
232  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
233  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
234  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
235  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
236  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
237  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
238 };
239 
240 /** event data for bound changes events */
241 struct SCIP_EventData
242 {
243  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
244  SCIP_Longint weight; /**< weight of variable */
245  int filterpos; /**< position of event in variable's event filter */
246 };
247 
248 
249 /** data structure to combine two sorting key values */
250 struct sortkeypair
251 {
252  SCIP_Real key1; /**< first sort key value */
253  SCIP_Real key2; /**< second sort key value */
254 };
255 typedef struct sortkeypair SORTKEYPAIR;
256 
257 /** status of GUB constraint */
258 enum GUBVarstatus
259 {
260  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
261  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
262  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
263  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
264  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
265  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
266 };
267 typedef enum GUBVarstatus GUBVARSTATUS;
269 /** status of variable in GUB constraint */
271 {
272  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
273  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
274  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
275  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
276  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
277  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
278 };
279 typedef enum GUBConsstatus GUBCONSSTATUS;
281 /** data structure of GUB constraints */
283 {
284  int* gubvars; /**< indices of GUB variables in knapsack constraint */
285  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
286  int ngubvars; /**< number of GUB variables */
287  int gubvarssize; /**< size of gubvars array */
288 };
289 typedef struct SCIP_GUBCons SCIP_GUBCONS;
291 /** data structure of a set of GUB constraints */
293 {
294  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
295  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
296  int ngubconss; /**< number of GUB constraints */
297  int nvars; /**< number of variables in knapsack constraint */
298  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
299  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
300 };
301 typedef struct SCIP_GUBSet SCIP_GUBSET;
303 /*
304  * Local methods
305  */
307 /** comparison method for two sorting key pairs */
308 static
309 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
310 {
311  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
312  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
313 
314  if( sortkeypair1->key1 < sortkeypair2->key1 )
315  return -1;
316  else if( sortkeypair1->key1 > sortkeypair2->key1 )
317  return +1;
318  else if( sortkeypair1->key2 < sortkeypair2->key2 )
319  return -1;
320  else if( sortkeypair1->key2 > sortkeypair2->key2 )
321  return +1;
322  else
323  return 0;
324 }
325 
326 /** creates event data */
327 static
329  SCIP* scip, /**< SCIP data structure */
330  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
331  SCIP_CONS* cons, /**< constraint */
332  SCIP_Longint weight /**< weight of variable */
333  )
334 {
335  assert(eventdata != NULL);
337  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
338  (*eventdata)->cons = cons;
339  (*eventdata)->weight = weight;
340 
341  return SCIP_OKAY;
342 }
343 
344 /** frees event data */
345 static
347  SCIP* scip, /**< SCIP data structure */
348  SCIP_EVENTDATA** eventdata /**< pointer to event data */
349  )
350 {
351  assert(eventdata != NULL);
352 
353  SCIPfreeBlockMemory(scip, eventdata);
355  return SCIP_OKAY;
356 }
357 
358 /** sorts items in knapsack with nonincreasing weights */
359 static
360 void sortItems(
361  SCIP_CONSDATA* consdata /**< constraint data */
362  )
363 {
364  assert(consdata != NULL);
365  assert(consdata->nvars == 0 || consdata->vars != NULL);
366  assert(consdata->nvars == 0 || consdata->weights != NULL);
367  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
368  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
369 
370  if( !consdata->sorted )
371  {
372  int pos;
373  int lastcliquenum;
374  int v;
375 
376  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
377  * sorted by first array in non-increasing order via sort template */
379  consdata->weights,
380  (void**)consdata->vars,
381  (void**)consdata->eventdata,
382  consdata->cliquepartition,
383  consdata->negcliquepartition,
384  consdata->nvars);
385 
386  v = consdata->nvars - 1;
387  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
388  while( v >= 0 )
389  {
390  int w = v - 1;
391 
392  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
393  --w;
394 
395  if( v - w > 1 )
396  {
397  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
399  (void**)(&(consdata->vars[w+1])),
400  (void**)(&(consdata->eventdata[w+1])),
401  &(consdata->cliquepartition[w+1]),
402  &(consdata->negcliquepartition[w+1]),
403  SCIPvarComp,
404  v - w);
405  }
406  v = w;
407  }
408 
409  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
410  if( consdata->cliquepartitioned )
411  {
412  lastcliquenum = 0;
413 
414  for( pos = 0; pos < consdata->nvars; ++pos )
415  {
416  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
417  * partition is invalid */
418  if( consdata->cliquepartition[pos] > lastcliquenum )
419  {
420  consdata->cliquepartitioned = FALSE;
421  break;
422  }
423  else if( consdata->cliquepartition[pos] == lastcliquenum )
424  ++lastcliquenum;
425  }
426  }
427  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
428  if( consdata->negcliquepartitioned )
429  {
430  lastcliquenum = 0;
431 
432  for( pos = 0; pos < consdata->nvars; ++pos )
433  {
434  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
435  * partition is invalid */
436  if( consdata->negcliquepartition[pos] > lastcliquenum )
437  {
438  consdata->negcliquepartitioned = FALSE;
439  break;
440  }
441  else if( consdata->negcliquepartition[pos] == lastcliquenum )
442  ++lastcliquenum;
443  }
444  }
445 
446  consdata->sorted = TRUE;
447  }
448 #ifndef NDEBUG
449  {
450  /* check if the weight array is sorted in a non-increasing way */
451  int i;
452  for( i = 0; i < consdata->nvars-1; ++i )
453  assert(consdata->weights[i] >= consdata->weights[i+1]);
454  }
455 #endif
456 }
457 
458 /** calculates a partition of the variables into cliques */
459 static
461  SCIP* scip, /**< SCIP data structure */
462  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
463  SCIP_CONSDATA* consdata, /**< constraint data */
464  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
465  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
466  )
467 {
468  SCIP_Bool ispartitionoutdated;
469  SCIP_Bool isnegpartitionoutdated;
470  assert(consdata != NULL);
471  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
472 
473  /* rerun eventually if number of global cliques increased considerably since last partition */
474  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
475  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
476 
477  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
478  {
479  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
480  consdata->cliquepartitioned = TRUE;
481  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
482  }
483 
484  /* rerun eventually if number of global cliques increased considerably since last negated partition */
485  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
486  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
487 
488  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
489  {
490  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
491  consdata->negcliquepartitioned = TRUE;
492  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
493  }
494  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
495  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
496 
497  return SCIP_OKAY;
498 }
499 
500 /** installs rounding locks for the given variable in the given knapsack constraint */
501 static
503  SCIP* scip, /**< SCIP data structure */
504  SCIP_CONS* cons, /**< knapsack constraint */
505  SCIP_VAR* var /**< variable of constraint entry */
506  )
507 {
508  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
509 
510  return SCIP_OKAY;
511 }
512 
513 /** removes rounding locks for the given variable in the given knapsack constraint */
514 static
516  SCIP* scip, /**< SCIP data structure */
517  SCIP_CONS* cons, /**< knapsack constraint */
518  SCIP_VAR* var /**< variable of constraint entry */
519  )
520 {
521  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
522 
523  return SCIP_OKAY;
524 }
525 
526 /** catches bound change events for variables in knapsack */
527 static
529  SCIP* scip, /**< SCIP data structure */
530  SCIP_CONS* cons, /**< constraint */
531  SCIP_CONSDATA* consdata, /**< constraint data */
532  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
533  )
534 {
535  int i;
537  assert(cons != NULL);
538  assert(consdata != NULL);
539  assert(consdata->nvars == 0 || consdata->vars != NULL);
540  assert(consdata->nvars == 0 || consdata->weights != NULL);
541  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
542 
543  for( i = 0; i < consdata->nvars; i++)
544  {
545  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
546  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
547  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
548  }
549 
550  return SCIP_OKAY;
551 }
552 
553 /** drops bound change events for variables in knapsack */
554 static
556  SCIP* scip, /**< SCIP data structure */
557  SCIP_CONSDATA* consdata, /**< constraint data */
558  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
559  )
560 {
561  int i;
562 
563  assert(consdata != NULL);
564  assert(consdata->nvars == 0 || consdata->vars != NULL);
565  assert(consdata->nvars == 0 || consdata->weights != NULL);
566  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
567 
568  for( i = 0; i < consdata->nvars; i++)
569  {
570  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
571  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
572  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
573  }
574 
575  return SCIP_OKAY;
576 }
577 
578 /** ensures, that vars and vals arrays can store at least num entries */
579 static
581  SCIP* scip, /**< SCIP data structure */
582  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
583  int num, /**< minimum number of entries to store */
584  SCIP_Bool transformed /**< is constraint from transformed problem? */
585  )
586 {
587  assert(consdata != NULL);
588  assert(consdata->nvars <= consdata->varssize);
589 
590  if( num > consdata->varssize )
591  {
592  int newsize;
593 
594  newsize = SCIPcalcMemGrowSize(scip, num);
595  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
596  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
597  if( transformed )
598  {
599  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
600  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
601  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
602  }
603  else
604  {
605  assert(consdata->eventdata == NULL);
606  assert(consdata->cliquepartition == NULL);
607  assert(consdata->negcliquepartition == NULL);
608  }
609  consdata->varssize = newsize;
610  }
611  assert(num <= consdata->varssize);
612 
613  return SCIP_OKAY;
614 }
615 
616 /** updates all weight sums for fixed and unfixed variables */
617 static
618 void updateWeightSums(
619  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
620  SCIP_VAR* var, /**< variable for this weight */
621  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
622  )
623 {
624  assert(consdata != NULL);
625  assert(var != NULL);
627  consdata->weightsum += weightdelta;
628 
629  if( SCIPvarGetLbLocal(var) > 0.5 )
630  consdata->onesweightsum += weightdelta;
631 
632  assert(consdata->weightsum >= 0);
633  assert(consdata->onesweightsum >= 0);
634 }
635 
636 /** creates knapsack constraint data */
637 static
639  SCIP* scip, /**< SCIP data structure */
640  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
641  int nvars, /**< number of variables in knapsack */
642  SCIP_VAR** vars, /**< variables of knapsack */
643  SCIP_Longint* weights, /**< weights of knapsack items */
644  SCIP_Longint capacity /**< capacity of knapsack */
645  )
646 {
647  int v;
648  SCIP_Longint constant;
649 
650  assert(consdata != NULL);
651 
652  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
653 
654  constant = 0L;
655  (*consdata)->vars = NULL;
656  (*consdata)->weights = NULL;
657  (*consdata)->nvars = 0;
658  if( nvars > 0 )
659  {
660  SCIP_VAR** varsbuffer;
661  SCIP_Longint* weightsbuffer;
662  int k;
663 
664  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
665  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
666 
667  k = 0;
668  for( v = 0; v < nvars; ++v )
669  {
670  assert(vars[v] != NULL);
671  assert(SCIPvarIsBinary(vars[v]));
672 
673  /* all weight have to be non negative */
674  assert( weights[v] >= 0 );
675 
676  if( weights[v] > 0 )
677  {
678  /* treat fixed variables as constants if problem compression is enabled */
679  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
680  {
681  /* only if the variable is fixed to 1, we add its weight to the constant */
682  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
683  constant += weights[v];
684  }
685  else
686  {
687  varsbuffer[k] = vars[v];
688  weightsbuffer[k] = weights[v];
689  ++k;
690  }
691  }
692  }
693  assert(k >= 0);
694 
695  (*consdata)->nvars = k;
696 
697  /* copy the active variables and weights into the constraint data structure */
698  if( k > 0 )
699  {
700  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
701  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
702  }
703 
704  /* free buffer storage */
705  SCIPfreeBufferArray(scip, &weightsbuffer);
706  SCIPfreeBufferArray(scip, &varsbuffer);
707  }
708 
709  /* capacity has to be greater or equal to zero */
710  assert(capacity >= 0);
711  assert(constant >= 0);
712 
713  (*consdata)->varssize = (*consdata)->nvars;
714  (*consdata)->capacity = capacity - constant;
715  (*consdata)->eventdata = NULL;
716  (*consdata)->cliquepartition = NULL;
717  (*consdata)->negcliquepartition = NULL;
718  (*consdata)->row = NULL;
719  (*consdata)->weightsum = 0;
720  (*consdata)->onesweightsum = 0;
721  (*consdata)->ncliques = 0;
722  (*consdata)->nnegcliques = 0;
723  (*consdata)->presolvedtiming = 0;
724  (*consdata)->sorted = FALSE;
725  (*consdata)->cliquepartitioned = FALSE;
726  (*consdata)->negcliquepartitioned = FALSE;
727  (*consdata)->ncliqueslastpart = -1;
728  (*consdata)->ncliqueslastnegpart = -1;
729  (*consdata)->merged = FALSE;
730  (*consdata)->cliquesadded = FALSE;
731  (*consdata)->varsdeleted = FALSE;
732  (*consdata)->existmultaggr = FALSE;
733 
734  /* get transformed variables, if we are in the transformed problem */
735  if( SCIPisTransformed(scip) )
736  {
737  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
738 
739  for( v = 0; v < (*consdata)->nvars; v++ )
740  {
741  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
742  assert(var != NULL);
743  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
744  }
745 
746  /* allocate memory for additional data structures */
747  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
748  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
749  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
750  }
751 
752  /* calculate sum of weights and capture variables */
753  for( v = 0; v < (*consdata)->nvars; ++v )
754  {
755  /* calculate sum of weights */
756  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
757 
758  /* capture variables */
759  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
760  }
761  return SCIP_OKAY;
762 }
763 
764 /** frees knapsack constraint data */
765 static
767  SCIP* scip, /**< SCIP data structure */
768  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
769  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
770  )
771 {
772  assert(consdata != NULL);
773  assert(*consdata != NULL);
775  if( (*consdata)->row != NULL )
776  {
777  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
778  }
779  if( (*consdata)->eventdata != NULL )
780  {
781  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
782  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
783  }
784  if( (*consdata)->negcliquepartition != NULL )
785  {
786  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
787  }
788  if( (*consdata)->cliquepartition != NULL )
789  {
790  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
791  }
792  if( (*consdata)->vars != NULL )
793  {
794  int v;
795 
796  /* release variables */
797  for( v = 0; v < (*consdata)->nvars; v++ )
798  {
799  assert((*consdata)->vars[v] != NULL);
800  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
801  }
802 
803  assert( (*consdata)->weights != NULL );
804  assert( (*consdata)->varssize > 0 );
805  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
806  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
807  }
808 
809  SCIPfreeBlockMemory(scip, consdata);
810 
811  return SCIP_OKAY;
812 }
813 
814 /** changes a single weight in knapsack constraint data */
815 static
816 void consdataChgWeight(
817  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
818  int item, /**< item number */
819  SCIP_Longint newweight /**< new weight of item */
820  )
821 {
822  SCIP_Longint oldweight;
823  SCIP_Longint weightdiff;
825  assert(consdata != NULL);
826  assert(0 <= item && item < consdata->nvars);
827 
828  oldweight = consdata->weights[item];
829  weightdiff = newweight - oldweight;
830  consdata->weights[item] = newweight;
831 
832  /* update weight sums for all and fixed variables */
833  updateWeightSums(consdata, consdata->vars[item], weightdiff);
834 
835  if( consdata->eventdata != NULL )
836  {
837  assert(consdata->eventdata[item] != NULL);
838  assert(consdata->eventdata[item]->weight == oldweight);
839  consdata->eventdata[item]->weight = newweight;
840  }
841 
842  consdata->presolvedtiming = 0;
843  consdata->sorted = FALSE;
844 
845  /* recalculate cliques extraction after a weight was increased */
846  if( oldweight < newweight )
847  {
848  consdata->cliquesadded = FALSE;
849  }
850 }
851 
852 /** creates LP row corresponding to knapsack constraint */
853 static
855  SCIP* scip, /**< SCIP data structure */
856  SCIP_CONS* cons /**< knapsack constraint */
857  )
858 {
859  SCIP_CONSDATA* consdata;
860  int i;
861 
862  consdata = SCIPconsGetData(cons);
863  assert(consdata != NULL);
864  assert(consdata->row == NULL);
865 
866  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, SCIPconsGetHdlr(cons), SCIPconsGetName(cons),
867  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
869 
870  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
871  for( i = 0; i < consdata->nvars; ++i )
872  {
873  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
874  }
875  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
876 
877  return SCIP_OKAY;
878 }
879 
880 /** adds linear relaxation of knapsack constraint to the LP */
881 static
883  SCIP* scip, /**< SCIP data structure */
884  SCIP_CONS* cons, /**< knapsack constraint */
885  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
886  )
887 {
888  SCIP_CONSDATA* consdata;
889 
890  assert( cutoff != NULL );
891  *cutoff = FALSE;
892 
893  consdata = SCIPconsGetData(cons);
894  assert(consdata != NULL);
895 
896  if( consdata->row == NULL )
897  {
898  SCIP_CALL( createRelaxation(scip, cons) );
899  }
900  assert(consdata->row != NULL);
901 
902  /* insert LP row as cut */
903  if( !SCIProwIsInLP(consdata->row) )
904  {
905  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
906  SCIPconsGetName(cons), consdata->capacity);
907  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
908  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
909  }
910 
911  return SCIP_OKAY;
912 }
913 
914 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
915 static
917  SCIP* scip, /**< SCIP data structure */
918  SCIP_CONS* cons, /**< constraint to check */
919  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
920  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
921  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
922  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
923  )
924 {
925  SCIP_CONSDATA* consdata;
926 
927  assert(violated != NULL);
928 
929  consdata = SCIPconsGetData(cons);
930  assert(consdata != NULL);
931 
932  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
933  SCIPconsGetName(cons), (void*)sol, checklprows);
934 
935  *violated = FALSE;
936 
937  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
938  {
939  SCIP_Real sum;
940  SCIP_Longint integralsum;
941  SCIP_Bool ishuge;
942  SCIP_Real absviol;
943  SCIP_Real relviol;
944  int v;
945 
946  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
947  * enforcement
948  */
949  if( sol == NULL )
950  {
951  SCIP_CALL( SCIPincConsAge(scip, cons) );
952  }
953 
954  sum = 0.0;
955  integralsum = 0;
956  /* we perform a more exact comparison if the capacity does not exceed the huge value */
957  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
958  {
959  ishuge = TRUE;
960 
961  /* sum over all weight times the corresponding solution value */
962  for( v = consdata->nvars - 1; v >= 0; --v )
963  {
964  assert(SCIPvarIsBinary(consdata->vars[v]));
965  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
966  }
967  }
968  else
969  {
970  ishuge = FALSE;
971 
972  /* sum over all weight for which the variable has a solution value of 1 in feastol */
973  for( v = consdata->nvars - 1; v >= 0; --v )
974  {
975  assert(SCIPvarIsBinary(consdata->vars[v]));
976 
977  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
978  integralsum += consdata->weights[v];
979  }
980  }
981 
982  /* calculate constraint violation and update it in solution */
983  absviol = ishuge ? sum : (SCIP_Real)integralsum;
984  absviol -= consdata->capacity;
985  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
986  if( sol != NULL )
987  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
988 
989  if( SCIPisFeasPositive(scip, absviol) )
990  {
991  *violated = TRUE;
992 
993  /* only reset constraint age if we are in enforcement */
994  if( sol == NULL )
995  {
996  SCIP_CALL( SCIPresetConsAge(scip, cons) );
997  }
998 
999  if( printreason )
1000  {
1001  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1002 
1003  SCIPinfoMessage(scip, NULL, ";\n");
1004  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1005  }
1006  }
1007  }
1008 
1009  return SCIP_OKAY;
1010 }
1011 
1012 /* IDX computes the integer index for the optimal solution array */
1013 #define IDX(j,d) ((j)*(intcap)+(d))
1014 
1015 /** solves knapsack problem in maximization form exactly using dynamic programming;
1016  * if needed, one can provide arrays to store all selected items and all not selected items
1017  *
1018  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1019  *
1020  * @note the algorithm will first compute a greedy solution and terminate
1021  * if the greedy solution is proven to be optimal.
1022  * The dynamic programming algorithm runs with a time and space complexity
1023  * of O(nitems * capacity).
1024  *
1025  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1026  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1027  * to be checked whether they are faster and whether they can reconstruct the solution.
1028  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1029  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1030  * This could be implemented, however, it would be technically a bit cumbersome,
1031  * since one needs the greedy solution and the LP-value for this.
1032  * This is currently only available after the redundant items have already been sorted out.
1033  */
1035  SCIP* scip, /**< SCIP data structure */
1036  int nitems, /**< number of available items */
1037  SCIP_Longint* weights, /**< item weights */
1038  SCIP_Real* profits, /**< item profits */
1039  SCIP_Longint capacity, /**< capacity of knapsack */
1040  int* items, /**< item numbers */
1041  int* solitems, /**< array to store items in solution, or NULL */
1042  int* nonsolitems, /**< array to store items not in solution, or NULL */
1043  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1044  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1045  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1046  SCIP_Bool* success /**< pointer to store if an error occured during solving
1047  * (normally a memory problem) */
1048  )
1049 {
1050  SCIP_RETCODE retcode;
1051  SCIP_Real* tempsort;
1052  SCIP_Real* optvalues;
1053  int intcap;
1054  int d;
1055  int j;
1056  int greedymedianpos;
1057  SCIP_Longint weightsum;
1058  int* myitems;
1059  SCIP_Longint* myweights;
1060  SCIP_Real* realweights;
1061  int* allcurrminweight;
1062  SCIP_Real* myprofits;
1063  int nmyitems;
1064  SCIP_Longint gcd;
1065  SCIP_Longint minweight;
1066  SCIP_Longint maxweight;
1067  int currminweight;
1068  SCIP_Longint greedysolweight;
1069  SCIP_Real greedysolvalue;
1070  SCIP_Real greedyupperbound;
1071  SCIP_Bool eqweights;
1072  SCIP_Bool intprofits;
1073 
1074  assert(weights != NULL);
1075  assert(profits != NULL);
1076  assert(capacity >= 0);
1077  assert(items != NULL);
1078  assert(nitems >= 0);
1079  assert(success != NULL);
1080 
1081  *success = TRUE;
1082 
1083 #ifndef NDEBUG
1084  for( j = nitems - 1; j >= 0; --j )
1085  assert(weights[j] >= 0);
1086 #endif
1087 
1088  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1089 
1090  /* initializing solution value */
1091  if( solval != NULL )
1092  *solval = 0.0;
1093 
1094  /* init solution information */
1095  if( solitems != NULL )
1096  {
1097  assert(items != NULL);
1098  assert(nsolitems != NULL);
1099  assert(nonsolitems != NULL);
1100  assert(nnonsolitems != NULL);
1101 
1102  *nnonsolitems = 0;
1103  *nsolitems = 0;
1104  }
1105 
1106  /* allocate temporary memory */
1107  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1108  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1109  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1110  nmyitems = 0;
1111  weightsum = 0;
1112  minweight = SCIP_LONGINT_MAX;
1113  maxweight = 0;
1114 
1115  /* remove unnecessary items */
1116  for( j = 0; j < nitems; ++j )
1117  {
1118  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1119 
1120  /* item does not fit */
1121  if( weights[j] > capacity )
1122  {
1123  if( solitems != NULL )
1124  nonsolitems[(*nnonsolitems)++] = items[j];
1125  }
1126  /* item is not profitable */
1127  else if( profits[j] <= 0.0 )
1128  {
1129  if( solitems != NULL )
1130  nonsolitems[(*nnonsolitems)++] = items[j];
1131  }
1132  /* item always fits */
1133  else if( weights[j] == 0 )
1134  {
1135  if( solitems != NULL )
1136  solitems[(*nsolitems)++] = items[j];
1137 
1138  if( solval != NULL )
1139  *solval += profits[j];
1140  }
1141  /* all important items */
1142  else
1143  {
1144  myweights[nmyitems] = weights[j];
1145  myprofits[nmyitems] = profits[j];
1146  myitems[nmyitems] = items[j];
1147 
1148  /* remember smallest item */
1149  if( myweights[nmyitems] < minweight )
1150  minweight = myweights[nmyitems];
1151 
1152  /* remember bigest item */
1153  if( myweights[nmyitems] > maxweight )
1154  maxweight = myweights[nmyitems];
1155 
1156  weightsum += myweights[nmyitems];
1157  ++nmyitems;
1158  }
1159  }
1160 
1161  intprofits = TRUE;
1162  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1163  for( j = 0; j < nmyitems && intprofits; ++j )
1164  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1165 
1166 
1167  /* if no item is left then goto end */
1168  if( nmyitems == 0 )
1169  {
1170  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1171 
1172  goto TERMINATE;
1173  }
1174 
1175  /* if all items fit, we also do not need to do the expensive stuff later on */
1176  if( weightsum > 0 && weightsum <= capacity )
1177  {
1178  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1179 
1180  for( j = nmyitems - 1; j >= 0; --j )
1181  {
1182  if( solitems != NULL )
1183  solitems[(*nsolitems)++] = myitems[j];
1184 
1185  if( solval != NULL )
1186  *solval += myprofits[j];
1187  }
1188 
1189  goto TERMINATE;
1190  }
1191 
1192  assert(0 < minweight && minweight <= capacity );
1193  assert(0 < maxweight && maxweight <= capacity);
1194 
1195  /* make weights relatively prime */
1196  eqweights = TRUE;
1197  if( maxweight > 1 )
1198  {
1199  /* determine greatest common divisor */
1200  gcd = myweights[nmyitems - 1];
1201  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1202  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1203 
1204  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1205 
1206  /* divide by greatest common divisor */
1207  if( gcd > 1 )
1208  {
1209  for( j = nmyitems - 1; j >= 0; --j )
1210  {
1211  myweights[j] /= gcd;
1212  eqweights = eqweights && (myweights[j] == 1);
1213  }
1214  capacity /= gcd;
1215  minweight /= gcd;
1216  }
1217  else
1218  eqweights = FALSE;
1219  }
1220  assert(minweight <= capacity);
1221 
1222  /* if only one item fits, then take the best */
1223  if( minweight > capacity / 2 )
1224  {
1225  int p;
1226 
1227  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1228 
1229  p = nmyitems - 1;
1230 
1231  /* find best item */
1232  for( j = nmyitems - 2; j >= 0; --j )
1233  {
1234  if( myprofits[j] > myprofits[p] )
1235  p = j;
1236  }
1237 
1238  /* update solution information */
1239  if( solitems != NULL )
1240  {
1241  solitems[(*nsolitems)++] = myitems[p];
1242  for( j = nmyitems - 1; j >= 0; --j )
1243  {
1244  if( j != p )
1245  nonsolitems[(*nnonsolitems)++] = myitems[j];
1246  }
1247  }
1248  /* update solution value */
1249  if( solval != NULL )
1250  *solval += myprofits[p];
1251 
1252  goto TERMINATE;
1253  }
1254 
1255  /* if all items have the same weight, then take the best */
1256  if( eqweights )
1257  {
1258  SCIP_Real addval = 0.0;
1259 
1260  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1261 
1262  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1263 
1264  /* update solution information */
1265  if( solitems != NULL || solval != NULL )
1266  {
1267  SCIP_Longint i;
1268 
1269  /* if all items would fit we had handled this case before */
1270  assert((SCIP_Longint) nmyitems > capacity);
1271 
1272  /* take the first best items into the solution */
1273  for( i = capacity - 1; i >= 0; --i )
1274  {
1275  if( solitems != NULL )
1276  solitems[(*nsolitems)++] = myitems[i];
1277  addval += myprofits[i];
1278  }
1279 
1280  if( solitems != NULL )
1281  {
1282  /* the rest are not in the solution */
1283  for( i = nmyitems - 1; i >= capacity; --i )
1284  nonsolitems[(*nnonsolitems)++] = myitems[i];
1285  }
1286  }
1287  /* update solution value */
1288  if( solval != NULL )
1289  {
1290  assert(addval > 0.0);
1291  *solval += addval;
1292  }
1293 
1294  goto TERMINATE;
1295  }
1296 
1297  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1298 
1299  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1300  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1301  */
1302  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1303  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1304 
1305  for( j = 0; j < nmyitems; ++j )
1306  {
1307  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1308  realweights[j] = (SCIP_Real)myweights[j];
1309  }
1310 
1311  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1312  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1313 
1314  SCIPfreeBufferArray(scip, &realweights);
1315  SCIPfreeBufferArray(scip, &tempsort);
1316 
1317  /* initialize values for greedy solution information */
1318  greedysolweight = 0;
1319  greedysolvalue = 0.0;
1320 
1321  /* determine greedy solution */
1322  for( j = 0; j < greedymedianpos; ++j )
1323  {
1324  assert(myweights[j] <= capacity);
1325 
1326  /* update greedy solution weight and value */
1327  greedysolweight += myweights[j];
1328  greedysolvalue += myprofits[j];
1329  }
1330 
1331  assert(0 < greedysolweight && greedysolweight <= capacity);
1332  assert(greedysolvalue > 0.0);
1333 
1334  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1335  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1336  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1337  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1338  if( intprofits )
1339  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1340  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1341  {
1342  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1343 
1344  /* update solution information */
1345  if( solitems != NULL )
1346  {
1347  int l;
1348 
1349  /* collect items */
1350  for( l = 0; l < j; ++l )
1351  solitems[(*nsolitems)++] = myitems[l];
1352  for ( ; l < nmyitems; ++l )
1353  nonsolitems[(*nnonsolitems)++] = myitems[l];
1354  }
1355  /* update solution value */
1356  if( solval != NULL )
1357  {
1358  assert(greedysolvalue > 0.0);
1359  *solval += greedysolvalue;
1360  }
1361 
1362  goto TERMINATE;
1363  }
1364 
1365  /* in the following table we do not need the first minweight columns */
1366  capacity -= (minweight - 1);
1367 
1368  /* we can only handle integers */
1369  if( capacity >= INT_MAX )
1370  {
1371  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1372 
1373  *success = FALSE;
1374  goto TERMINATE;
1375  }
1376  assert(capacity < INT_MAX);
1377 
1378  intcap = (int)capacity;
1379  assert(intcap >= 0);
1380  assert(nmyitems > 0);
1381  assert(sizeof(size_t) >= sizeof(int)); /* no following conversion should be messed up */
1382 
1383  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1384  * computing the size for the allocation
1385  */
1386  if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1387  {
1388  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1389 
1390  *success = FALSE;
1391  goto TERMINATE;
1392  }
1393 
1394  /* allocate temporary memory and check for memory exceedance */
1395  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1396  if( retcode == SCIP_NOMEMORY )
1397  {
1398  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1399 
1400  *success = FALSE;
1401  goto TERMINATE;
1402  }
1403  else
1404  {
1405  SCIP_CALL( retcode );
1406  }
1407 
1408  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1409 
1410  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1411  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1412  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1413  * 'nmyitem' values
1414  */
1415  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1416  assert(myweights[0] - minweight < INT_MAX);
1417  currminweight = (int) (myweights[0] - minweight);
1418  allcurrminweight[0] = currminweight;
1419 
1420  /* fills first row of dynamic programming table with optimal values */
1421  for( d = currminweight; d < intcap; ++d )
1422  optvalues[d] = myprofits[0];
1423 
1424  /* fills dynamic programming table with optimal values */
1425  for( j = 1; j < nmyitems; ++j )
1426  {
1427  int intweight;
1428 
1429  /* compute important part of weight, which will be represented in the table */
1430  intweight = (int)(myweights[j] - minweight);
1431  assert(0 <= intweight && intweight < intcap);
1432 
1433  /* copy all nonzeros from row above */
1434  for( d = currminweight; d < intweight && d < intcap; ++d )
1435  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1436 
1437  /* update corresponding row */
1438  for( d = intweight; d < intcap; ++d )
1439  {
1440  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1441  if( d < currminweight )
1442  optvalues[IDX(j,d)] = myprofits[j];
1443  else
1444  {
1445  SCIP_Real sumprofit;
1446 
1447  if( d - myweights[j] < currminweight )
1448  sumprofit = myprofits[j];
1449  else
1450  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1451 
1452  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1453  }
1454  }
1455 
1456  /* update currminweight */
1457  if( intweight < currminweight )
1458  currminweight = intweight;
1459 
1460  allcurrminweight[j] = currminweight;
1461  }
1462 
1463  /* update optimal solution by following the table */
1464  if( solitems != NULL )
1465  {
1466  d = intcap - 1;
1467 
1468  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1469 
1470  /* insert all items in (non-) solution vector */
1471  for( j = nmyitems - 1; j > 0; --j )
1472  {
1473  /* if the following condition holds this means all remaining items does not fit anymore */
1474  if( d < allcurrminweight[j] )
1475  {
1476  /* we cannot have exceeded our capacity */
1477  assert((SCIP_Longint) d >= -minweight);
1478  break;
1479  }
1480 
1481  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1482  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1483  {
1484  solitems[(*nsolitems)++] = myitems[j];
1485 
1486  /* check that we do not have an underflow */
1487  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1488  d = (int)(d - myweights[j]);
1489  }
1490  /* collect non-solution items */
1491  else
1492  nonsolitems[(*nnonsolitems)++] = myitems[j];
1493  }
1494 
1495  /* insert remaining items */
1496  if( d >= allcurrminweight[j] )
1497  {
1498  assert(j == 0);
1499  solitems[(*nsolitems)++] = myitems[j];
1500  }
1501  else
1502  {
1503  assert(j >= 0);
1504  assert(d < allcurrminweight[j]);
1505 
1506  for( ; j >= 0; --j )
1507  nonsolitems[(*nnonsolitems)++] = myitems[j];
1508  }
1509 
1510  assert(*nsolitems + *nnonsolitems == nitems);
1511  }
1512 
1513  /* update solution value */
1514  if( solval != NULL )
1515  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1516  SCIPfreeBufferArray(scip, &allcurrminweight);
1517 
1518  /* free all temporary memory */
1519  SCIPfreeBufferArray(scip, &optvalues);
1520 
1521  TERMINATE:
1522  SCIPfreeBufferArray(scip, &myitems);
1523  SCIPfreeBufferArray(scip, &myprofits);
1524  SCIPfreeBufferArray(scip, &myweights);
1525 
1526  return SCIP_OKAY;
1527 }
1528 
1529 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1530  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1531  * selected items
1532  */
1534  SCIP* scip, /**< SCIP data structure */
1535  int nitems, /**< number of available items */
1536  SCIP_Longint* weights, /**< item weights */
1537  SCIP_Real* profits, /**< item profits */
1538  SCIP_Longint capacity, /**< capacity of knapsack */
1539  int* items, /**< item numbers */
1540  int* solitems, /**< array to store items in solution, or NULL */
1541  int* nonsolitems, /**< array to store items not in solution, or NULL */
1542  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1543  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1544  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1545  )
1546 {
1547  SCIP_Real* tempsort;
1548  SCIP_Longint solitemsweight;
1549  SCIP_Real* realweights;
1550  int j;
1551  int criticalindex;
1552 
1553  assert(weights != NULL);
1554  assert(profits != NULL);
1555  assert(capacity >= 0);
1556  assert(items != NULL);
1557  assert(nitems >= 0);
1558 
1559  if( solitems != NULL )
1560  {
1561  *nsolitems = 0;
1562  *nnonsolitems = 0;
1563  }
1564  if( solval != NULL )
1565  *solval = 0.0;
1566 
1567  /* initialize data for median search */
1568  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1569  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1570  for( j = nitems - 1; j >= 0; --j )
1571  {
1572  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1573  realweights[j] = (SCIP_Real)weights[j];
1574  }
1575 
1576  /* partially sort indices such that all elements that are larger than the break item appear first */
1577  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1578 
1579  /* selects items as long as they fit into the knapsack */
1580  solitemsweight = 0;
1581  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1582  {
1583  if( solitems != NULL )
1584  solitems[(*nsolitems)++] = items[j];
1585 
1586  if( solval != NULL )
1587  (*solval) += profits[j];
1588  solitemsweight += weights[j];
1589  }
1590  if ( solitems != NULL )
1591  {
1592  for( ; j < nitems; j++ )
1593  nonsolitems[(*nnonsolitems)++] = items[j];
1594  }
1595 
1596  SCIPfreeBufferArray(scip, &realweights);
1597  SCIPfreeBufferArray(scip, &tempsort);
1598 
1599  return SCIP_OKAY;
1600 }
1601 
1602 #ifdef SCIP_DEBUG
1603 /** prints all nontrivial GUB constraints and their LP solution values */
1604 static
1605 void GUBsetPrint(
1606  SCIP* scip, /**< SCIP data structure */
1607  SCIP_GUBSET* gubset, /**< GUB set data structure */
1608  SCIP_VAR** vars, /**< variables in knapsack constraint */
1609  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1610  )
1611 {
1612  int nnontrivialgubconss;
1613  int c;
1614 
1615  nnontrivialgubconss = 0;
1616 
1617  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1618 
1619  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1620  for( c = 0; c < gubset->ngubconss; c++ )
1621  {
1622  SCIP_Real gubsolval;
1623 
1624  assert(gubset->gubconss[c]->ngubvars >= 0);
1625 
1626  /* nontrivial GUB */
1627  if( gubset->gubconss[c]->ngubvars > 1 )
1628  {
1629  int v;
1630 
1631  gubsolval = 0.0;
1632  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1633 
1634  /* print GUB var */
1635  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1636  {
1637  int currentvar;
1638 
1639  currentvar = gubset->gubconss[c]->gubvars[v];
1640  if( solvals != NULL )
1641  {
1642  gubsolval += solvals[currentvar];
1643  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1644  }
1645  else
1646  {
1647  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1648  }
1649  }
1650 
1651  /* check whether LP solution satisfies the GUB constraint */
1652  if( solvals != NULL )
1653  {
1654  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1655  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1656  }
1657  else
1658  {
1659  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1660  }
1661  nnontrivialgubconss++;
1662  }
1663  }
1664 
1665  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1666 }
1667 #endif
1668 
1669 /** creates an empty GUB constraint */
1670 static
1672  SCIP* scip, /**< SCIP data structure */
1673  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1674  )
1675 {
1676  assert(scip != NULL);
1677  assert(gubcons != NULL);
1678 
1679  /* allocate memory for GUB constraint data structures */
1680  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1681  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1682  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1683  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1684 
1685  (*gubcons)->ngubvars = 0;
1686 
1687  return SCIP_OKAY;
1688 }
1689 
1690 /** frees GUB constraint */
1691 static
1693  SCIP* scip, /**< SCIP data structure */
1694  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1695  )
1696 {
1697  assert(scip != NULL);
1698  assert(gubcons != NULL);
1699  assert((*gubcons)->gubvars != NULL);
1700  assert((*gubcons)->gubvarsstatus != NULL);
1701 
1702  /* free allocated memory */
1703  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1704  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1705  SCIPfreeBuffer(scip, gubcons);
1706 
1707  return SCIP_OKAY;
1708 }
1709 
1710 /** adds variable to given GUB constraint */
1711 static
1713  SCIP* scip, /**< SCIP data structure */
1714  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1715  int var /**< index of given variable in knapsack constraint */
1716  )
1717 {
1718  assert(scip != NULL);
1719  assert(gubcons != NULL);
1720  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1721  assert(gubcons->gubvars != NULL);
1722  assert(gubcons->gubvarsstatus != NULL);
1723  assert(var >= 0);
1724 
1725  /* add variable to GUB constraint */
1726  gubcons->gubvars[gubcons->ngubvars] = var;
1727  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1728  gubcons->ngubvars++;
1729 
1730  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1731  if( gubcons->ngubvars == gubcons->gubvarssize )
1732  {
1733  int newlen;
1734 
1735  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1736  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1737  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1738 
1739  gubcons->gubvarssize = newlen;
1740  }
1741 
1742  return SCIP_OKAY;
1743 }
1744 
1745 /** deletes variable from its current GUB constraint */
1746 static
1748  SCIP* scip, /**< SCIP data structure */
1749  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1750  int var, /**< index of given variable in knapsack constraint */
1751  int gubvarsidx /**< index of the variable in its current GUB constraint */
1752  )
1753 {
1754  assert(scip != NULL);
1755  assert(gubcons != NULL);
1756  assert(var >= 0);
1757  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1758  assert(gubcons->ngubvars >= gubvarsidx+1);
1759  assert(gubcons->gubvars[gubvarsidx] == var);
1760 
1761  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1762  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1763  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1764  gubcons->ngubvars--;
1765 
1766  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1767  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1768  {
1769  int newlen;
1770 
1771  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1772 
1773  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1774  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1775 
1776  gubcons->gubvarssize = newlen;
1777  }
1778 
1779  return SCIP_OKAY;
1780 }
1781 
1782 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1783 static
1785  SCIP* scip, /**< SCIP data structure */
1786  SCIP_GUBSET* gubset, /**< GUB set data structure */
1787  SCIP_VAR** vars, /**< variables in knapsack constraint */
1788  int var, /**< index of given variable in knapsack constraint */
1789  int oldgubcons, /**< index of old GUB constraint of given variable */
1790  int newgubcons /**< index of new GUB constraint of given variable */
1791  )
1793  int oldgubvaridx;
1794  int replacevar;
1795  int j;
1796 
1797  assert(scip != NULL);
1798  assert(gubset != NULL);
1799  assert(var >= 0);
1800  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1801  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1802  assert(oldgubcons != newgubcons);
1803  assert(gubset->gubconssidx[var] == oldgubcons);
1804  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1805  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1806 
1807  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1808 
1809  oldgubvaridx = gubset->gubvarsidx[var];
1810 
1811  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1812  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1813 
1814  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1815  * replacement variable is given by old position of the deleted variable
1816  */
1817  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1818  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1819  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1820 
1821  /* add variable to the end of new GUB constraint */
1822  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1823  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1824 
1825  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1826  gubset->gubconssidx[var] = newgubcons;
1827  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1828 
1829  /* delete old GUB constraint if it became empty */
1830  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1831  {
1832  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1833 #ifdef SCIP_DEBUG
1834  GUBsetPrint(scip, gubset, vars, NULL);
1835 #endif
1836 
1837  /* free old GUB constraint */
1838  SCIP_CALL( GUBconsFree(scip, &gubset->gubconss[oldgubcons]) );
1839 
1840  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1841  if( oldgubcons != gubset->ngubconss-1 )
1842  {
1843  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1844  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1845 
1846  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1847  * replacement GUB is given by old position of the deleted GUB
1848  */
1849  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1850  {
1851  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1852  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1853  }
1854  }
1855 
1856  /* update number of GUB constraints */
1857  gubset->ngubconss--;
1858 
1859  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1860  * (because it was at the end of the GUB constraint array)
1861  */
1862  assert(gubset->gubconssidx[var] == newgubcons
1863  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1864  }
1865 #ifndef NDEBUG
1866  else
1867  assert(gubset->gubconssidx[var] == newgubcons);
1868 #endif
1869 
1870  return SCIP_OKAY;
1871 }
1872 
1873 /** swaps two variables in the same GUB constraint */
1874 static
1875 void GUBsetSwapVars(
1876  SCIP* scip, /**< SCIP data structure */
1877  SCIP_GUBSET* gubset, /**< GUB set data structure */
1878  int var1, /**< first variable to be swapped */
1879  int var2 /**< second variable to be swapped */
1880  )
1881 {
1882  int gubcons;
1883  int var1idx;
1884  GUBVARSTATUS var1status;
1885  int var2idx;
1886  GUBVARSTATUS var2status;
1887 
1888  assert(scip != NULL);
1889  assert(gubset != NULL);
1890 
1891  gubcons = gubset->gubconssidx[var1];
1892  assert(gubcons == gubset->gubconssidx[var2]);
1893 
1894  /* nothing to be done if both variables are the same */
1895  if( var1 == var2 )
1896  return;
1897 
1898  /* swap index and status of variables in GUB constraint */
1899  var1idx = gubset->gubvarsidx[var1];
1900  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1901  var2idx = gubset->gubvarsidx[var2];
1902  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1903 
1904  gubset->gubvarsidx[var1] = var2idx;
1905  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1906  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1907 
1908  gubset->gubvarsidx[var2] = var1idx;
1909  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1910  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1911 }
1912 
1913 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1914 static
1916  SCIP* scip, /**< SCIP data structure */
1917  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1918  int nvars, /**< number of variables in the knapsack constraint */
1919  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1920  SCIP_Longint capacity /**< capacity of knapsack */
1921  )
1922 {
1923  int i;
1924 
1925  assert(scip != NULL);
1926  assert(gubset != NULL);
1927  assert(nvars > 0);
1928  assert(weights != NULL);
1929  assert(capacity >= 0);
1930 
1931  /* allocate memory for GUB set data structures */
1932  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1933  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1934  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1935  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1936  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1937  (*gubset)->ngubconss = nvars;
1938  (*gubset)->nvars = nvars;
1939 
1940  /* initialize the set of GUB constraints */
1941  for( i = 0; i < nvars; i++ )
1942  {
1943  /* assign each variable to a new (trivial) GUB constraint */
1944  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1945  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1946 
1947  /* set status of GUB constraint to initial */
1948  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1949 
1950  (*gubset)->gubconssidx[i] = i;
1951  (*gubset)->gubvarsidx[i] = 0;
1952  assert((*gubset)->gubconss[i]->ngubvars == 1);
1953 
1954  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1955  if( weights[i] > capacity )
1956  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1957  }
1958 
1959  return SCIP_OKAY;
1960 }
1961 
1962 /** frees GUB set data structure */
1963 static
1965  SCIP* scip, /**< SCIP data structure */
1966  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1967  )
1968 {
1969  int i;
1970 
1971  assert(scip != NULL);
1972  assert(gubset != NULL);
1973  assert((*gubset)->gubconss != NULL);
1974  assert((*gubset)->gubconsstatus != NULL);
1975  assert((*gubset)->gubconssidx != NULL);
1976  assert((*gubset)->gubvarsidx != NULL);
1977 
1978  /* free all GUB constraints */
1979  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1980  {
1981  assert((*gubset)->gubconss[i] != NULL);
1982  SCIP_CALL( GUBconsFree(scip, &(*gubset)->gubconss[i]) );
1983  }
1984 
1985  /* free allocated memory */
1986  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1987  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1988  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1989  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
1990  SCIPfreeBuffer(scip, gubset);
1991 
1992  return SCIP_OKAY;
1993 }
1994 
1995 #ifndef NDEBUG
1996 /** checks whether GUB set data structure is consistent */
1997 static
1999  SCIP* scip, /**< SCIP data structure */
2000  SCIP_GUBSET* gubset, /**< GUB set data structure */
2001  SCIP_VAR** vars /**< variables in the knapsack constraint */
2002  )
2003 {
2004  int i;
2005  int gubconsidx;
2006  int gubvaridx;
2007  SCIP_VAR* var1;
2008  SCIP_VAR* var2;
2009  SCIP_Bool var1negated;
2010  SCIP_Bool var2negated;
2011 
2012  assert(scip != NULL);
2013  assert(gubset != NULL);
2014 
2015  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2016 
2017  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2018  for( i = 0; i < gubset->nvars; i++ )
2019  {
2020  gubconsidx = gubset->gubconssidx[i];
2021  gubvaridx = gubset->gubvarsidx[i];
2022 
2023  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2024  {
2025  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2026  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2027  }
2028  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2029  }
2030 
2031  /* checks for each GUB whether all pairs of its variables have a common clique */
2032  for( i = 0; i < gubset->ngubconss; i++ )
2033  {
2034  int j;
2035 
2036  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2037  {
2038  int k;
2039 
2040  /* get corresponding active problem variable */
2041  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2042  var1negated = FALSE;
2043  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2044 
2045  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2046  {
2047  /* get corresponding active problem variable */
2048  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2049  var2negated = FALSE;
2050  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2051 
2052  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2053  {
2054  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2055  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2056  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2057  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2058  SCIPvarGetName(var1), k,
2059  SCIPvarGetName(var2));
2060  }
2061 
2062  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2063  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2064  }
2065  }
2066  }
2067  SCIPdebugMsg(scip, " --> successful\n");
2068 
2069  return SCIP_OKAY;
2070 }
2071 #endif
2072 
2073 /** calculates a partition of the given set of binary variables into cliques;
2074  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2075  * were assigned to the same clique;
2076  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2077  * the preceding variables was assigned to clique i-1;
2078  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2079  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2080  */
2081 
2082 static
2084  SCIP*const scip, /**< SCIP data structure */
2085  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2086  int const nvars, /**< number of variables in the clique */
2087  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2088  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2089  SCIP_Real* solvals /**< solution values of all given binary variables */
2090  )
2092  SCIP_VAR** tmpvars;
2093  SCIP_VAR** cliquevars;
2094  SCIP_Bool* cliquevalues;
2095  SCIP_Bool* tmpvalues;
2096  int* varseq;
2097  int* sortkeys;
2098  int ncliquevars;
2099  int maxncliquevarscomp;
2100  int nignorevars;
2101  int nvarsused;
2102  int i;
2103 
2104  assert(scip != NULL);
2105  assert(nvars == 0 || vars != NULL);
2106  assert(nvars == 0 || cliquepartition != NULL);
2107  assert(ncliques != NULL);
2108 
2109  if( nvars == 0 )
2110  {
2111  *ncliques = 0;
2112  return SCIP_OKAY;
2113  }
2114 
2115  /* allocate temporary memory for storing the variables of the current clique */
2116  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2117  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2118  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2119  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2120  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2121  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2122 
2123  /* initialize the cliquepartition array with -1 */
2124  /* initialize the tmpvalues array */
2125  for( i = nvars - 1; i >= 0; --i )
2126  {
2127  tmpvalues[i] = TRUE;
2128  cliquepartition[i] = -1;
2129  }
2130 
2131  /* get corresponding active problem variables */
2132  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2133 
2134  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2135  * by nondecreasing number of cliques the variables are in
2136  */
2137  nignorevars = 0;
2138  nvarsused = 0;
2139  for( i = 0; i < nvars; i++ )
2140  {
2141  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2142  {
2143  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2144  varseq[nvars-1-nignorevars] = i;
2145  nignorevars++;
2146  }
2147  else
2148  {
2149  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2150  varseq[nvarsused] = i;
2151  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2152  nvarsused++;
2153  }
2154  }
2155  assert(nvarsused + nignorevars == nvars);
2156 
2157  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2158  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2159 
2160  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2161 
2162  /* calculate the clique partition */
2163  *ncliques = 0;
2164  for( i = 0; i < nvars; ++i )
2165  {
2166  if( cliquepartition[varseq[i]] == -1 )
2167  {
2168  int j;
2169 
2170  /* variable starts a new clique */
2171  cliquepartition[varseq[i]] = *ncliques;
2172  cliquevars[0] = tmpvars[varseq[i]];
2173  cliquevalues[0] = tmpvalues[varseq[i]];
2174  ncliquevars = 1;
2175 
2176  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2177  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2178  */
2179  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2180  {
2181  /* greedily fill up the clique */
2182  for( j = i + 1; j < nvarsused; ++j )
2183  {
2184  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2185  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2186  {
2187  int k;
2188 
2189  /* check if every variable in the actual clique is in clique with the new variable */
2190  for( k = ncliquevars - 1; k >= 0; --k )
2191  {
2192  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2193  cliquevalues[k], TRUE) )
2194  break;
2195  }
2196 
2197  if( k == -1 )
2198  {
2199  /* put the variable into the same clique */
2200  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2201  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2202  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2203  ++ncliquevars;
2204  }
2205  }
2206  }
2207  }
2208 
2209  /* this clique is finished */
2210  ++(*ncliques);
2211  }
2212  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2213 
2214  /* break if we reached the maximal number of comparisons */
2215  if( i * nvars > maxncliquevarscomp )
2216  break;
2217  }
2218  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2219  for( ; i < nvars; ++i )
2220  {
2221  if( cliquepartition[varseq[i]] == -1 )
2222  {
2223  cliquepartition[varseq[i]] = *ncliques;
2224  ++(*ncliques);
2225  }
2226  }
2227 
2228  /* free temporary memory */
2229  SCIPfreeBufferArray(scip, &sortkeys);
2230  SCIPfreeBufferArray(scip, &varseq);
2231  SCIPfreeBufferArray(scip, &tmpvars);
2232  SCIPfreeBufferArray(scip, &tmpvalues);
2233  SCIPfreeBufferArray(scip, &cliquevalues);
2234  SCIPfreeBufferArray(scip, &cliquevars);
2235 
2236  return SCIP_OKAY;
2237 }
2238 
2239 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2240 static
2242  SCIP* scip, /**< SCIP data structure */
2243  SCIP_GUBSET* gubset, /**< GUB set data structure */
2244  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2245  SCIP_Real* solvals /**< solution values of all knapsack variables */
2246  )
2247 {
2248  int* cliquepartition;
2249  int* gubfirstvar;
2250  int ncliques;
2251  int currentgubconsidx;
2252  int newgubconsidx;
2253  int cliqueidx;
2254  int nvars;
2255  int i;
2256 
2257  assert(scip != NULL);
2258  assert(gubset != NULL);
2259  assert(vars != NULL);
2260 
2261  nvars = gubset->nvars;
2262  assert(nvars >= 0);
2263 
2264  /* allocate temporary memory for clique partition */
2265  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2266 
2267  /* compute sophisticated clique partition */
2268  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2269 
2270  /* allocate temporary memory for GUB set data structure */
2271  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2272 
2273  /* translate GUB partition into GUB set data structure */
2274  for( i = 0; i < ncliques; i++ )
2275  {
2276  /* initialize first variable for every GUB */
2277  gubfirstvar[i] = -1;
2278  }
2279  /* move every knapsack variable into GUB defined by clique partition */
2280  for( i = 0; i < nvars; i++ )
2281  {
2282  assert(cliquepartition[i] >= 0);
2283 
2284  cliqueidx = cliquepartition[i];
2285  currentgubconsidx = gubset->gubconssidx[i];
2286  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2287 
2288  /* variable is first element in GUB constraint defined by clique partition */
2289  if( gubfirstvar[cliqueidx] == -1 )
2290  {
2291  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2292  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2293  */
2294  assert(gubset->gubvarsidx[i] == 0);
2295  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2296 
2297  /* remember the first variable found for the current GUB */
2298  gubfirstvar[cliqueidx] = i;
2299  }
2300  /* variable is additional element of GUB constraint defined by clique partition */
2301  else
2302  {
2303  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2304 
2305  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2306  * first variable of this GUB constraint
2307  */
2308  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2309  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2310  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2311 
2312  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2313  }
2314  }
2315 
2316 #ifdef SCIP_DEBUG
2317  /* prints GUB set data structure */
2318  GUBsetPrint(scip, gubset, vars, solvals);
2319 #endif
2320 
2321 #ifndef NDEBUG
2322  /* checks consistency of GUB set data structure */
2323  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2324 #endif
2325 
2326  /* free temporary memory */
2327  SCIPfreeBufferArray(scip, &gubfirstvar);
2328  SCIPfreeBufferArray(scip, &cliquepartition);
2329 
2330  return SCIP_OKAY;
2331 }
2332 
2333 /** 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$
2334  * 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
2335  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2336  */
2337 static
2339  SCIP* scip, /**< SCIP data structure */
2340  SCIP_VAR** vars, /**< variables in knapsack constraint */
2341  int nvars, /**< number of variables in knapsack constraint */
2342  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2343  SCIP_Longint capacity, /**< capacity of knapsack */
2344  SCIP_Real* solvals, /**< solution values of all problem variables */
2345  int* covervars, /**< pointer to store cover variables */
2346  int* noncovervars, /**< pointer to store noncover variables */
2347  int* ncovervars, /**< pointer to store number of cover variables */
2348  int* nnoncovervars, /**< pointer to store number of noncover variables */
2349  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2350  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2351  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2352  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2353  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2354  )
2355 {
2356  SCIP_Longint* transweights;
2357  SCIP_Real* transprofits;
2358  SCIP_Longint transcapacity;
2359  SCIP_Longint fixedonesweight;
2360  SCIP_Longint itemsweight;
2361  SCIP_Bool infeasible;
2362  int* fixedones;
2363  int* fixedzeros;
2364  int* items;
2365  int nfixedones;
2366  int nfixedzeros;
2367  int nitems;
2368  int j;
2369 
2370  assert(scip != NULL);
2371  assert(vars != NULL);
2372  assert(nvars > 0);
2373  assert(weights != NULL);
2374  assert(capacity >= 0);
2375  assert(solvals != NULL);
2376  assert(covervars != NULL);
2377  assert(noncovervars != NULL);
2378  assert(ncovervars != NULL);
2379  assert(nnoncovervars != NULL);
2380  assert(coverweight != NULL);
2381  assert(found != NULL);
2382  assert(ntightened != NULL);
2383  assert(fractional != NULL);
2384 
2385  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2386 
2387  /* allocates temporary memory */
2388  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2389  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2390  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2391  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2392  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2393 
2394  *found = FALSE;
2395  *ncovervars = 0;
2396  *nnoncovervars = 0;
2397  *coverweight = 0;
2398  *fractional = TRUE;
2399 
2400  /* gets the following sets
2401  * N_1 = {j in N : x*_j = 1} (fixedones),
2402  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2403  * N\(N_0 & N_1) (items),
2404  * where x*_j is the solution value of variable x_j
2405  */
2406  nfixedones = 0;
2407  nfixedzeros = 0;
2408  nitems = 0;
2409  fixedonesweight = 0;
2410  itemsweight = 0;
2411  *ntightened = 0;
2412  for( j = 0; j < nvars; j++ )
2413  {
2414  assert(SCIPvarIsBinary(vars[j]));
2415 
2416  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2417  if( weights[j] > capacity )
2418  {
2419  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2420  assert(!infeasible);
2421  (*ntightened)++;
2422  continue;
2423  }
2424 
2425  /* variable x_j has solution value one */
2426  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2427  {
2428  fixedones[nfixedones] = j;
2429  nfixedones++;
2430  fixedonesweight += weights[j];
2431  }
2432  /* variable x_j has solution value zero */
2433  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2434  {
2435  fixedzeros[nfixedzeros] = j;
2436  nfixedzeros++;
2437  }
2438  /* variable x_j has fractional solution value */
2439  else
2440  {
2441  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2442  items[nitems] = j;
2443  nitems++;
2444  itemsweight += weights[j];
2445  }
2446  }
2447  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2448 
2449  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2450  * the separation routine
2451  */
2452  assert(nitems >= 0);
2453  if( nitems == 0 )
2454  {
2455  *fractional = FALSE;
2456  goto TERMINATE;
2457  }
2458  assert(*fractional);
2459 
2460  /* transforms the traditional separation problem (under consideration of the following fixing:
2461  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2462  *
2463  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2464  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2465  * z_j in {0,1}, j in N\(N_0 & N_1)
2466  *
2467  * to a knapsack problem in maximization form by complementing the variables
2468  *
2469  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2470  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2471  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2472  * z_j in {0,1}, j in N\(N_0 & N_1)
2473  */
2474 
2475  /* gets weight and profit of variables in transformed knapsack problem */
2476  for( j = 0; j < nitems; j++ )
2477  {
2478  transweights[j] = weights[items[j]];
2479  transprofits[j] = 1.0 - solvals[items[j]];
2480  }
2481  /* gets capacity of transformed knapsack problem */
2482  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2483 
2484  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2485  * (when variables fixed to zero are not used)
2486  */
2487  if( transcapacity < 0 )
2488  {
2489  assert(!(*found));
2490  goto TERMINATE;
2491  }
2492 
2493  if( modtransused )
2494  {
2495  /* transforms the modified separation problem (under consideration of the following fixing:
2496  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2497  *
2498  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2499  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2500  * z_j in {0,1}, j in N\(N_0 & N_1)
2501  *
2502  * to a knapsack problem in maximization form by complementing the variables
2503  *
2504  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2505  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2506  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2507  * z_j in {0,1}, j in N\(N_0 & N_1)
2508  */
2509 
2510  /* gets weight and profit of variables in modified transformed knapsack problem */
2511  for( j = 0; j < nitems; j++ )
2512  {
2513  transprofits[j] *= weights[items[j]];
2514  assert(SCIPisFeasPositive(scip, transprofits[j]));
2515  }
2516  }
2517 
2518  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2519  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2520  * let z* be the solution, then
2521  * j in C, if z*_j = 0 and
2522  * i in N\C, if z*_j = 1.
2523  */
2524  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2525  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2526  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2527 
2528  /* constructs cover C (sum_{j in C} a_j > a_0) */
2529  for( j = 0; j < *ncovervars; j++ )
2530  {
2531  (*coverweight) += weights[covervars[j]];
2532  }
2533 
2534  /* adds all variables from N_1 to C */
2535  for( j = 0; j < nfixedones; j++ )
2536  {
2537  covervars[*ncovervars] = fixedones[j];
2538  (*ncovervars)++;
2539  (*coverweight) += weights[fixedones[j]];
2540  }
2541 
2542  /* adds all variables from N_0 to N\C */
2543  for( j = 0; j < nfixedzeros; j++ )
2544  {
2545  noncovervars[*nnoncovervars] = fixedzeros[j];
2546  (*nnoncovervars)++;
2547  }
2548  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2549  assert((*coverweight) > capacity);
2550  *found = TRUE;
2551 
2552  TERMINATE:
2553  /* frees temporary memory */
2554  SCIPfreeBufferArray(scip, &items);
2555  SCIPfreeBufferArray(scip, &fixedzeros);
2556  SCIPfreeBufferArray(scip, &fixedones);
2557  SCIPfreeBufferArray(scip, &transprofits);
2558  SCIPfreeBufferArray(scip, &transweights);
2559 
2560  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2561 
2562  return SCIP_OKAY;
2563 }
2564 
2565 #ifndef NDEBUG
2566 /** checks if minweightidx is set correctly
2567  */
2568 static
2570  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2571  SCIP_Longint capacity, /**< capacity of knapsack */
2572  int* covervars, /**< pointer to store cover variables */
2573  int ncovervars, /**< pointer to store number of cover variables */
2574  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2575  int minweightidx, /**< index of variable in cover variables with minimum weight */
2576  int j /**< current index in cover variables */
2577  )
2578 {
2579  SCIP_Longint minweight;
2580  int i;
2581 
2582  assert(weights != NULL);
2583  assert(covervars != NULL);
2584  assert(ncovervars > 0);
2585 
2586  minweight = weights[covervars[minweightidx]];
2587 
2588  /* checks if all cover variables before index j have weight greater than minweight */
2589  for( i = 0; i < j; i++ )
2590  {
2591  assert(weights[covervars[i]] > minweight);
2592  if( weights[covervars[i]] <= minweight )
2593  return FALSE;
2594  }
2595 
2596  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2597  for( i = 0; i < j; i++ )
2598  {
2599  assert(coverweight - weights[covervars[i]] <= capacity);
2600  if( coverweight - weights[covervars[i]] > capacity )
2601  return FALSE;
2602  }
2603  return TRUE;
2604 }
2605 #endif
2606 
2607 
2608 /** 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$,
2609  * 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$
2610  */
2611 static
2613  SCIP* scip, /**< SCIP data structure */
2614  SCIP_Real* solvals, /**< solution values of all problem variables */
2615  int* covervars, /**< cover variables */
2616  int ncovervars, /**< number of cover variables */
2617  int* varsC1, /**< pointer to store variables in C1 */
2618  int* varsC2, /**< pointer to store variables in C2 */
2619  int* nvarsC1, /**< pointer to store number of variables in C1 */
2620  int* nvarsC2 /**< pointer to store number of variables in C2 */
2621  )
2622 {
2623  int j;
2624 
2625  assert(scip != NULL);
2626  assert(ncovervars >= 0);
2627  assert(solvals != NULL);
2628  assert(covervars != NULL);
2629  assert(varsC1 != NULL);
2630  assert(varsC2 != NULL);
2631  assert(nvarsC1 != NULL);
2632  assert(nvarsC2 != NULL);
2633 
2634  *nvarsC1 = 0;
2635  *nvarsC2 = 0;
2636  for( j = 0; j < ncovervars; j++ )
2637  {
2638  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2639 
2640  /* variable has solution value one */
2641  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2642  {
2643  varsC2[*nvarsC2] = covervars[j];
2644  (*nvarsC2)++;
2645  }
2646  /* variable has solution value less than one */
2647  else
2648  {
2649  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2650  varsC1[*nvarsC1] = covervars[j];
2651  (*nvarsC1)++;
2652  }
2653  }
2654  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2655 }
2656 
2657 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2658  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2659  */
2660 static
2662  SCIP* scip, /**< SCIP data structure */
2663  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2664  int* varsC1, /**< pointer to store variables in C1 */
2665  int* varsC2, /**< pointer to store variables in C2 */
2666  int* nvarsC1, /**< pointer to store number of variables in C1 */
2667  int* nvarsC2 /**< pointer to store number of variables in C2 */
2668  )
2670  SCIP_Real* sortkeysC2;
2671  int j;
2672 
2673  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2674  assert(*nvarsC2 > 0);
2675 
2676  /* allocates temporary memory */
2677  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2678 
2679  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2680  for( j = 0; j < *nvarsC2; j++ )
2681  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2682  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2683 
2684  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2685  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2686  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2687  {
2688  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2689  (*nvarsC1)++;
2690  (*nvarsC2)--;
2691  }
2692 
2693  /* frees temporary memory */
2694  SCIPfreeBufferArray(scip, &sortkeysC2);
2695 
2696  return SCIP_OKAY;
2697 }
2698 
2699 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2700 static
2702  SCIP* scip, /**< SCIP data structure */
2703  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2704  int* varsC1, /**< pointer to store variables in C1 */
2705  int* varsC2, /**< pointer to store variables in C2 */
2706  int* nvarsC1, /**< pointer to store number of variables in C1 */
2707  int* nvarsC2 /**< pointer to store number of variables in C2 */
2708  )
2710  SCIP_Real* sortkeysC2;
2711  int j;
2712 
2713  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2714  assert(*nvarsC2 > 0);
2715 
2716  /* allocates temporary memory */
2717  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2718 
2719  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2720  for( j = 0; j < *nvarsC2; j++ )
2721  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2722  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2723 
2724  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2725  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2726  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2727  (*nvarsC1)++;
2728  (*nvarsC2)--;
2729 
2730  /* frees temporary memory */
2731  SCIPfreeBufferArray(scip, &sortkeysC2);
2732 
2733  return SCIP_OKAY;
2734 }
2735 
2736 
2737 /** 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$
2738  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2739  * \f$F = (N \setminus C) \setminus F\f$
2740  */
2741 static
2743  SCIP* scip, /**< SCIP data structure */
2744  SCIP_Real* solvals, /**< solution values of all problem variables */
2745  int* noncovervars, /**< noncover variables */
2746  int nnoncovervars, /**< number of noncover variables */
2747  int* varsF, /**< pointer to store variables in F */
2748  int* varsR, /**< pointer to store variables in R */
2749  int* nvarsF, /**< pointer to store number of variables in F */
2750  int* nvarsR /**< pointer to store number of variables in R */
2751  )
2752 {
2753  int j;
2754 
2755  assert(scip != NULL);
2756  assert(nnoncovervars >= 0);
2757  assert(solvals != NULL);
2758  assert(noncovervars != NULL);
2759  assert(varsF != NULL);
2760  assert(varsR != NULL);
2761  assert(nvarsF != NULL);
2762  assert(nvarsR != NULL);
2763 
2764  *nvarsF = 0;
2765  *nvarsR = 0;
2766 
2767  for( j = 0; j < nnoncovervars; j++ )
2768  {
2769  /* variable has solution value zero */
2770  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2771  {
2772  varsR[*nvarsR] = noncovervars[j];
2773  (*nvarsR)++;
2774  }
2775  /* variable has solution value greater than zero */
2776  else
2777  {
2778  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2779  varsF[*nvarsF] = noncovervars[j];
2780  (*nvarsF)++;
2781  }
2782  }
2783  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2784 }
2785 
2786 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2787  * lifting procedure
2788  */
2789 static
2791  SCIP* scip, /**< SCIP data structure */
2792  SCIP_Real* solvals, /**< solution values of all problem variables */
2793  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2794  int* varsF, /**< pointer to store variables in F */
2795  int* varsC2, /**< pointer to store variables in C2 */
2796  int* varsR, /**< pointer to store variables in R */
2797  int nvarsF, /**< number of variables in F */
2798  int nvarsC2, /**< number of variables in C2 */
2799  int nvarsR /**< number of variables in R */
2800  )
2801 {
2802  SORTKEYPAIR** sortkeypairsF;
2803  SORTKEYPAIR* sortkeypairsFstore;
2804  SCIP_Real* sortkeysC2;
2805  SCIP_Real* sortkeysR;
2806  int j;
2807 
2808  assert(scip != NULL);
2809  assert(solvals != NULL);
2810  assert(weights != NULL);
2811  assert(varsF != NULL);
2812  assert(varsC2 != NULL);
2813  assert(varsR != NULL);
2814  assert(nvarsF >= 0);
2815  assert(nvarsC2 >= 0);
2816  assert(nvarsR >= 0);
2817 
2818  /* allocates temporary memory */
2819  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2820  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2821  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2822  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2823 
2824  /* gets sorting key for variables in F corresponding to the following lifting sequence
2825  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2826  * x*_1 >= x*_2 >= ... >= x*_|F|
2827  * in case of equality uses
2828  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2829  */
2830  for( j = 0; j < nvarsF; j++ )
2831  {
2832  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2833  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2834  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2835  }
2836 
2837  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2838  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2839  */
2840  for( j = 0; j < nvarsC2; j++ )
2841  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2842 
2843  /* gets sorting key for variables in R corresponding to the following lifting sequence
2844  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2845  */
2846  for( j = 0; j < nvarsR; j++ )
2847  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2848 
2849  /* sorts F, C2 and R */
2850  if( nvarsF > 0 )
2851  {
2852  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2853  }
2854  if( nvarsC2 > 0 )
2855  {
2856  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2857  }
2858  if( nvarsR > 0)
2859  {
2860  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2861  }
2862 
2863  /* frees temporary memory */
2864  SCIPfreeBufferArray(scip, &sortkeysR);
2865  SCIPfreeBufferArray(scip, &sortkeysC2);
2866  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2867  SCIPfreeBufferArray(scip, &sortkeypairsF);
2868 
2869  return SCIP_OKAY;
2870 }
2871 
2872 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2873  * for the sequential GUB wise lifting procedure
2874  */
2875 static
2877  SCIP* scip, /**< SCIP data structure */
2878  SCIP_GUBSET* gubset, /**< GUB set data structure */
2879  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2880  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2881  int* varsC1, /**< variables in C1 */
2882  int* varsC2, /**< variables in C2 */
2883  int* varsF, /**< variables in F */
2884  int* varsR, /**< variables in R */
2885  int nvarsC1, /**< number of variables in C1 */
2886  int nvarsC2, /**< number of variables in C2 */
2887  int nvarsF, /**< number of variables in F */
2888  int nvarsR, /**< number of variables in R */
2889  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2890  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2891  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2892  int* gubconsGR, /**< pointer to store GUBs in GR */
2893  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2894  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2895  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2896  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2897  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2898  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2899  )
2900 {
2901 #if 0 /* not required */
2902  SORTKEYPAIR** sortkeypairsF;
2903 #endif
2904  SORTKEYPAIR** sortkeypairsGFC1;
2905  SORTKEYPAIR* sortkeypairsGFC1store;
2906  SCIP_Real* sortkeysC1;
2907  SCIP_Real* sortkeysC2;
2908  SCIP_Real* sortkeysR;
2909  int* nC1varsingubcons;
2910  int var;
2911  int gubconsidx;
2912  int varidx;
2913  int ngubconss;
2914  int ngubconsGOC1;
2915  int targetvar;
2916  int nvarsprocessed;
2917  int i;
2918  int j;
2919 
2920 #if GUBSPLITGNC1GUBS
2921  SCIP_Bool gubconswithF;
2922  int origngubconss;
2923  origngubconss = gubset->ngubconss;
2924 #endif
2925 
2926  assert(scip != NULL);
2927  assert(gubset != NULL);
2928  assert(solvals != NULL);
2929  assert(weights != NULL);
2930  assert(varsC1 != NULL);
2931  assert(varsC2 != NULL);
2932  assert(varsF != NULL);
2933  assert(varsR != NULL);
2934  assert(nvarsC1 > 0);
2935  assert(nvarsC2 >= 0);
2936  assert(nvarsF >= 0);
2937  assert(nvarsR >= 0);
2938  assert(gubconsGC1 != NULL);
2939  assert(gubconsGC2 != NULL);
2940  assert(gubconsGFC1 != NULL);
2941  assert(gubconsGR != NULL);
2942  assert(ngubconsGC1 != NULL);
2943  assert(ngubconsGC2 != NULL);
2944  assert(ngubconsGFC1 != NULL);
2945  assert(ngubconsGR != NULL);
2946  assert(maxgubvarssize != NULL);
2947 
2948  ngubconss = gubset->ngubconss;
2949  nvarsprocessed = 0;
2950  ngubconsGOC1 = 0;
2951 
2952  /* GUBs are categorized into different types according to the variables in volved
2953  * - GOC1: involves variables in C1 only -- no C2, R, F
2954  * - GNC1: involves variables in C1 and F (and R) -- no C2
2955  * - GF: involves variables in F (and R) only -- no C1, C2
2956  * - GC2: involves variables in C2 only -- no C1, R, F
2957  * - GR: involves variables in R only -- no C1, C2, F
2958  * which requires splitting GUBs in case they include variable in F and R.
2959  *
2960  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2961  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2962  * - second ordering level is
2963  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2964  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2965  * GR: non-increasing max{ a_k : k in GR_j}
2966  *
2967  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2968  * - GC1: GUBs of category GOC1 and GNC1
2969  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2970  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2971  */
2972 
2973  /* allocates temporary memory */
2974  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2975 #if 0 /* not required */
2976  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2977 #endif
2978  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2979  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2980 
2981  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2982  * - F: non-increasing x*_j and non-increasing a_j in case of equality
2983  * - C2: non-increasing a_j
2984  * - R: non-increasing a_j
2985  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2986  */
2987 
2988  /* gets sorting key for variables in C1 corresponding to the following ordering
2989  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
2990  */
2991  for( j = 0; j < nvarsC1; j++ )
2992  {
2993  /* gets sortkeys */
2994  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
2995 
2996  /* update status of variable in its gub constraint */
2997  gubconsidx = gubset->gubconssidx[varsC1[j]];
2998  varidx = gubset->gubvarsidx[varsC1[j]];
2999  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3000  }
3001 
3002  /* gets sorting key for variables in F corresponding to the following ordering
3003  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3004  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3005  * and updates status of each variable in F in GUB set data structure
3006  */
3007  for( j = 0; j < nvarsF; j++ )
3008  {
3009 #if 0 /* not required */
3010  /* gets sortkeys */
3011  SCIP_CALL( SCIPallocBuffer(scip, &sortkeypairsF[j]) );
3012  sortkeypairsF[j]->key1 = solvals[varsF[j]];
3013  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
3014 #endif
3015 
3016  /* update status of variable in its gub constraint */
3017  gubconsidx = gubset->gubconssidx[varsF[j]];
3018  varidx = gubset->gubvarsidx[varsF[j]];
3019  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3020  }
3021 
3022  /* gets sorting key for variables in C2 corresponding to the following ordering
3023  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3024  * and updates status of each variable in F in GUB set data structure
3025  */
3026  for( j = 0; j < nvarsC2; j++ )
3027  {
3028  /* gets sortkeys */
3029  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3030 
3031  /* update status of variable in its gub constraint */
3032  gubconsidx = gubset->gubconssidx[varsC2[j]];
3033  varidx = gubset->gubvarsidx[varsC2[j]];
3034  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3035  }
3036 
3037  /* gets sorting key for variables in R corresponding to the following ordering
3038  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3039  * and updates status of each variable in F in GUB set data structure
3040  */
3041  for( j = 0; j < nvarsR; j++ )
3042  {
3043  /* gets sortkeys */
3044  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3045 
3046  /* update status of variable in its gub constraint */
3047  gubconsidx = gubset->gubconssidx[varsR[j]];
3048  varidx = gubset->gubvarsidx[varsR[j]];
3049  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3050  }
3051 
3052  /* sorts C1, F, C2 and R */
3053  if( nvarsC1 > 0 )
3054  {
3055  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3056  }
3057 #if 0 /* not required */
3058  if( nvarsF > 0 )
3059  {
3060  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
3061  }
3062 #endif
3063  if( nvarsC2 > 0 )
3064  {
3065  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3066  }
3067  if( nvarsR > 0)
3068  {
3069  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3070  }
3071 
3072  /* frees temporary memory */
3073  SCIPfreeBufferArray(scip, &sortkeysR);
3074  SCIPfreeBufferArray(scip, &sortkeysC2);
3075 #if 0 /* not required */
3076  for( j = nvarsF-1; j >= 0; j-- )
3077  SCIPfreeBuffer(scip, &sortkeypairsF[j]);
3078  SCIPfreeBufferArray(scip, &sortkeypairsF);
3079 #endif
3080  SCIPfreeBufferArray(scip, &sortkeysC1);
3081 
3082  /* allocate and initialize temporary memory for sorting GUB constraints */
3083  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3084  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3085  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3086  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3087  for( i = 0; i < ngubconss; i++)
3088  {
3089  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3090  sortkeypairsGFC1[i]->key1 = 0.0;
3091  sortkeypairsGFC1[i]->key2 = 0.0;
3092  }
3093  *ngubconsGC1 = 0;
3094  *ngubconsGC2 = 0;
3095  *ngubconsGFC1 = 0;
3096  *ngubconsGR = 0;
3097  *ngubconscapexceed = 0;
3098  *maxgubvarssize = 0;
3099 
3100 #ifndef NDEBUG
3101  for( i = 0; i < gubset->ngubconss; i++ )
3102  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3103 #endif
3104 
3105  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3106  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3107  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3108  * non-increasing number of variables in F, and
3109  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3110  */
3111  for( i = 0; i < nvarsC1; i++ )
3112  {
3113  int nvarsC1capexceed;
3114 
3115  nvarsC1capexceed = 0;
3116 
3117  var = varsC1[i];
3118  gubconsidx = gubset->gubconssidx[var];
3119  varidx = gubset->gubvarsidx[var];
3120 
3121  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3122  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3123 
3124  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3125  * note that variables in C1 are already sorted by non-decreasing weigth
3126  */
3127  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3128  GUBsetSwapVars(scip, gubset, var, targetvar);
3129  nC1varsingubcons[gubconsidx]++;
3130 
3131  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3132  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3133  {
3134  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3135  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3136  continue;
3137  }
3138 
3139  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3140  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3141  */
3142 #if GUBSPLITGNC1GUBS
3143  gubconswithF = FALSE;
3144 #endif
3145  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3146  {
3147  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3148 
3149  /* C1-variable: update number of C1/capacity exceeding variables */
3150  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3151  {
3152  nvarsC1capexceed++;
3153  nvarsprocessed++;
3154  }
3155  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3156  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3157  {
3158 #if GUBSPLITGNC1GUBS
3159  gubconswithF = TRUE;
3160 #endif
3161  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3162 
3163  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3164  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3165  }
3166  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3167  {
3168  nvarsC1capexceed++;
3169  }
3170  else
3171  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3172  }
3173 
3174  /* update set of GC1 GUBs */
3175  gubconsGC1[*ngubconsGC1] = gubconsidx;
3176  (*ngubconsGC1)++;
3177 
3178  /* update maximum size of all GUB constraints */
3179  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3180  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3181 
3182  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3183  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3184  {
3185  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3186  ngubconsGOC1++;
3187  }
3188  else
3189  {
3190 #if GUBSPLITGNC1GUBS
3191  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3192  if( !gubconswithF )
3193  {
3194  GUBVARSTATUS movevarstatus;
3195 
3196  assert(gubset->ngubconss < gubset->nvars);
3197 
3198  /* create a new GUB for GR part of splitting */
3199  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3200  gubset->ngubconss++;
3201  ngubconss = gubset->ngubconss;
3202 
3203  /* fill GR with R variables in current GUB */
3204  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3205  {
3206  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3207  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3208  {
3209  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3210  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3211  gubconsidx, ngubconss-1) );
3212  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3213  movevarstatus;
3214  }
3215  }
3216 
3217  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3218  ngubconsGOC1++;
3219 
3220  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3221  gubconsGR[*ngubconsGR] = ngubconss-1;
3222  (*ngubconsGR)++;
3223  }
3224  /* variables in C1, F, and maybe R: GNC1 GUB */
3225  else
3226  {
3227  assert(gubconswithF);
3228 
3229  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3230  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3231  (*ngubconsGFC1)++;
3232  }
3233 #else
3234  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3235  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3236  (*ngubconsGFC1)++;
3237 #endif
3238  }
3239  }
3240 
3241  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3242  * are already sorted correctly
3243  */
3244  for( i = 0; i < nvarsC2; i++ )
3245  {
3246  var = varsC2[i];
3247  gubconsidx = gubset->gubconssidx[var];
3248  varidx = gubset->gubvarsidx[var];
3249 
3250  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3251  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3252  assert(varidx == 0);
3253  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3254  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3255 
3256  /* set status of GC2 GUB */
3257  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3258 
3259  /* update group of GC2 GUBs */
3260  gubconsGC2[*ngubconsGC2] = gubconsidx;
3261  (*ngubconsGC2)++;
3262 
3263  /* update maximum size of all GUB constraints */
3264  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3265  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3266 
3267  nvarsprocessed++;
3268  }
3269 
3270  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3271  * non-increasing number of variables in F, and
3272  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3273  */
3274  for( i = 0; i < nvarsF; i++ )
3275  {
3276  var = varsF[i];
3277  gubconsidx = gubset->gubconssidx[var];
3278  varidx = gubset->gubvarsidx[var];
3279 
3280  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3281  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3282 
3283  nvarsprocessed++;
3284 
3285  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3286  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3287  {
3288  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3289  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3290  continue;
3291  }
3292 
3293  /* set status of GF GUB */
3294  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3295 
3296  /* update sorting key of corresponding GFC1 GUB */
3297  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3298  {
3299  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3300  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3301 
3302  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3303  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3304  {
3305  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3306 
3307  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3308  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3309  }
3310  }
3311 
3312  /* update set of GFC1 GUBs */
3313  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3314  (*ngubconsGFC1)++;
3315 
3316  /* update maximum size of all GUB constraints */
3317  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3318  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3319  }
3320 
3321  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3322  * correctly
3323  */
3324  for( i = 0; i < nvarsR; i++ )
3325  {
3326  var = varsR[i];
3327  gubconsidx = gubset->gubconssidx[var];
3328  varidx = gubset->gubvarsidx[var];
3329 
3330  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3331  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3332 
3333  nvarsprocessed++;
3334 
3335  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3336  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3337  {
3338  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3339  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3340  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3341  continue;
3342  }
3343 
3344  /* set status of GR GUB */
3345  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3346 
3347  /* update set of GR GUBs */
3348  gubconsGR[*ngubconsGR] = gubconsidx;
3349  (*ngubconsGR)++;
3350 
3351  /* update maximum size of all GUB constraints */
3352  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3353  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3354  }
3355  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3356 
3357  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3358  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3359  assert(*ngubconscapexceed >= 0);
3360 #ifndef NDEBUG
3361  {
3362  int check;
3363 
3364  check = 0;
3365 
3366  /* remaining not handled GUBs should only contain capacity exceeding variables */
3367  for( i = 0; i < ngubconss; i++ )
3368  {
3369  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3370  check++;
3371  }
3372  assert(check == *ngubconscapexceed);
3373  }
3374 #endif
3375 
3376  /* sort GFCI GUBs according to computed sorting keys */
3377  if( (*ngubconsGFC1) > 0 )
3378  {
3379  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3380  }
3381 
3382  /* free temporary memory */
3383 #if GUBSPLITGNC1GUBS
3384  ngubconss = origngubconss;
3385 #endif
3386  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3387  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3388  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3389 
3390  return SCIP_OKAY;
3391 }
3392 
3393 /** enlarges minweight table to at least the given length */
3394 static
3396  SCIP* scip, /**< SCIP data structure */
3397  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3398  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3399  int* minweightssize, /**< pointer to current size of minweights table */
3400  int newlen /**< new length of minweights table */
3401  )
3402 {
3403  int j;
3404 
3405  assert(minweightsptr != NULL);
3406  assert(*minweightsptr != NULL);
3407  assert(minweightslen != NULL);
3408  assert(*minweightslen >= 0);
3409  assert(minweightssize != NULL);
3410  assert(*minweightssize >= 0);
3411 
3412  if( newlen > *minweightssize )
3413  {
3414  int newsize;
3415 
3416  /* reallocate table memory */
3417  newsize = SCIPcalcMemGrowSize(scip, newlen);
3418  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3419  *minweightssize = newsize;
3420  }
3421  assert(newlen <= *minweightssize);
3422 
3423  /* initialize new elements */
3424  for( j = *minweightslen; j < newlen; ++j )
3425  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3426  *minweightslen = newlen;
3427 
3428  return SCIP_OKAY;
3429 }
3430 
3431 /** lifts given inequality
3432  * sum_{j in M_1} x_j <= alpha_0
3433  * valid for
3434  * 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 }
3435  * to a valid inequality
3436  * 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
3437  * <= alpha_0 + sum_{j in M_2} alpha_j
3438  * for
3439  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3440  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3441  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3442  * extended weight inequalities.
3443  */
3444 static
3446  SCIP* scip, /**< SCIP data structure */
3447  SCIP_VAR** vars, /**< variables in knapsack constraint */
3448  int nvars, /**< number of variables in knapsack constraint */
3449  int ntightened, /**< number of variables with tightened upper bound */
3450  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3451  SCIP_Longint capacity, /**< capacity of knapsack */
3452  SCIP_Real* solvals, /**< solution values of all problem variables */
3453  int* varsM1, /**< variables in M_1 */
3454  int* varsM2, /**< variables in M_2 */
3455  int* varsF, /**< variables in F */
3456  int* varsR, /**< variables in R */
3457  int nvarsM1, /**< number of variables in M_1 */
3458  int nvarsM2, /**< number of variables in M_2 */
3459  int nvarsF, /**< number of variables in F */
3460  int nvarsR, /**< number of variables in R */
3461  int alpha0, /**< rights hand side of given valid inequality */
3462  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3463  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3464  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3465  )
3466 {
3467  SCIP_Longint* minweights;
3468  SCIP_Real* sortkeys;
3469  SCIP_Longint fixedonesweight;
3470  int minweightssize;
3471  int minweightslen;
3472  int j;
3473  int w;
3474 
3475  assert(scip != NULL);
3476  assert(vars != NULL);
3477  assert(nvars >= 0);
3478  assert(weights != NULL);
3479  assert(capacity >= 0);
3480  assert(solvals != NULL);
3481  assert(varsM1 != NULL);
3482  assert(varsM2 != NULL);
3483  assert(varsF != NULL);
3484  assert(varsR != NULL);
3485  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3486  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3487  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3488  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3489  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3490  assert(alpha0 >= 0);
3491  assert(liftcoefs != NULL);
3492  assert(cutact != NULL);
3493  assert(liftrhs != NULL);
3494 
3495  /* allocates temporary memory */
3496  minweightssize = nvarsM1 + 1;
3497  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3498  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3499 
3500  /* initializes data structures */
3501  BMSclearMemoryArray(liftcoefs, nvars);
3502  *cutact = 0.0;
3503 
3504  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3505  * and calculates activity of the current valid inequality
3506  */
3507  for( j = 0; j < nvarsM1; j++ )
3508  {
3509  assert(liftcoefs[varsM1[j]] == 0);
3510  liftcoefs[varsM1[j]] = 1;
3511  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3512  (*cutact) += solvals[varsM1[j]];
3513  }
3514 
3515  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3516 
3517  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3518  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3519  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3520  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3521  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3522  */
3523  minweights[0] = 0;
3524  for( w = 1; w <= nvarsM1; w++ )
3525  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3526  minweightslen = nvarsM1 + 1;
3527 
3528  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3529  fixedonesweight = 0;
3530  for( j = 0; j < nvarsM2; j++ )
3531  fixedonesweight += weights[varsM2[j]];
3532  assert(fixedonesweight >= 0);
3533 
3534  /* initializes right hand side of lifted valid inequality */
3535  *liftrhs = alpha0;
3536 
3537  /* sequentially up-lifts all variables in F: */
3538  for( j = 0; j < nvarsF; j++ )
3539  {
3540  SCIP_Longint weight;
3541  int liftvar;
3542  int liftcoef;
3543  int z;
3544 
3545  liftvar = varsF[j];
3546  weight = weights[liftvar];
3547  assert(liftvar >= 0 && liftvar < nvars);
3548  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3549  assert(weight > 0);
3550 
3551  /* knapsack problem is infeasible:
3552  * sets z = 0
3553  */
3554  if( capacity - fixedonesweight - weight < 0 )
3555  {
3556  z = 0;
3557  }
3558  /* knapsack problem is feasible:
3559  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3560  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3561  */
3562  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3563  {
3564  z = *liftrhs;
3565  }
3566  /* knapsack problem is feasible:
3567  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3568  */
3569  else
3570  {
3571  int left;
3572  int right;
3573  int middle;
3574 
3575  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3576  left = 0;
3577  right = (*liftrhs) + 1;
3578  while( left < right - 1 )
3579  {
3580  middle = (left + right) / 2;
3581  assert(0 <= middle && middle < minweightslen);
3582  if( minweights[middle] <= capacity - fixedonesweight - weight )
3583  left = middle;
3584  else
3585  right = middle;
3586  }
3587  assert(left == right - 1);
3588  assert(0 <= left && left < minweightslen);
3589  assert(minweights[left] <= capacity - fixedonesweight - weight );
3590  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3591 
3592  /* now z = left */
3593  z = left;
3594  assert(z <= *liftrhs);
3595  }
3596 
3597  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3598  liftcoef = (*liftrhs) - z;
3599  liftcoefs[liftvar] = liftcoef;
3600  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3601 
3602  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3603  if( liftcoef == 0 )
3604  continue;
3605 
3606  /* updates activity of current valid inequality */
3607  (*cutact) += liftcoef * solvals[liftvar];
3608 
3609  /* enlarges current minweight table:
3610  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3611  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3612  * and sets minweights_i[w] = infinity for
3613  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3614  */
3615  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3616 
3617  /* updates minweight table: minweight_i+1[w] =
3618  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3619  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3620  */
3621  for( w = minweightslen - 1; w >= 0; w-- )
3622  {
3623  SCIP_Longint min;
3624  if( w < liftcoef )
3625  {
3626  min = MIN(minweights[w], weight);
3627  minweights[w] = min;
3628  }
3629  else
3630  {
3631  assert(w >= liftcoef);
3632  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3633  minweights[w] = min;
3634  }
3635  }
3636  }
3637  assert(minweights[0] == 0);
3638 
3639  /* sequentially down-lifts all variables in M_2: */
3640  for( j = 0; j < nvarsM2; j++ )
3641  {
3642  SCIP_Longint weight;
3643  int liftvar;
3644  int liftcoef;
3645  int left;
3646  int right;
3647  int middle;
3648  int z;
3649 
3650  liftvar = varsM2[j];
3651  weight = weights[liftvar];
3652  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3653  assert(liftvar >= 0 && liftvar < nvars);
3654  assert(weight > 0);
3655 
3656  /* uses binary search to find
3657  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3658  */
3659  left = 0;
3660  right = minweightslen;
3661  while( left < right - 1 )
3662  {
3663  middle = (left + right) / 2;
3664  assert(0 <= middle && middle < minweightslen);
3665  if( minweights[middle] <= capacity - fixedonesweight + weight )
3666  left = middle;
3667  else
3668  right = middle;
3669  }
3670  assert(left == right - 1);
3671  assert(0 <= left && left < minweightslen);
3672  assert(minweights[left] <= capacity - fixedonesweight + weight );
3673  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3674 
3675  /* now z = left */
3676  z = left;
3677  assert(z >= *liftrhs);
3678 
3679  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3680  liftcoef = z - (*liftrhs);
3681  liftcoefs[liftvar] = liftcoef;
3682  assert(liftcoef >= 0);
3683 
3684  /* updates sum of weights of variables fixed to one */
3685  fixedonesweight -= weight;
3686 
3687  /* updates right-hand side of current valid inequality */
3688  (*liftrhs) += liftcoef;
3689  assert(*liftrhs >= alpha0);
3690 
3691  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3692  if( liftcoef == 0 )
3693  continue;
3694 
3695  /* updates activity of current valid inequality */
3696  (*cutact) += liftcoef * solvals[liftvar];
3697 
3698  /* enlarges current minweight table:
3699  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3700  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3701  * and sets minweights_i[w] = infinity for
3702  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3703  */
3704  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3705 
3706  /* updates minweight table: minweight_i+1[w] =
3707  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3708  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3709  */
3710  for( w = minweightslen - 1; w >= 0; w-- )
3711  {
3712  SCIP_Longint min;
3713  if( w < liftcoef )
3714  {
3715  min = MIN(minweights[w], weight);
3716  minweights[w] = min;
3717  }
3718  else
3719  {
3720  assert(w >= liftcoef);
3721  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3722  minweights[w] = min;
3723  }
3724  }
3725  }
3726  assert(fixedonesweight == 0);
3727  assert(*liftrhs >= alpha0);
3728 
3729  /* sequentially up-lifts all variables in R: */
3730  for( j = 0; j < nvarsR; j++ )
3731  {
3732  SCIP_Longint weight;
3733  int liftvar;
3734  int liftcoef;
3735  int z;
3736 
3737  liftvar = varsR[j];
3738  weight = weights[liftvar];
3739  assert(liftvar >= 0 && liftvar < nvars);
3740  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3741  assert(weight > 0);
3742  assert(capacity - weight >= 0);
3743  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3744 
3745  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3746  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3747  */
3748  if( minweights[*liftrhs] <= capacity - weight )
3749  {
3750  z = *liftrhs;
3751  }
3752  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3753  */
3754  else
3755  {
3756  int left;
3757  int right;
3758  int middle;
3759 
3760  left = 0;
3761  right = (*liftrhs) + 1;
3762  while( left < right - 1)
3763  {
3764  middle = (left + right) / 2;
3765  assert(0 <= middle && middle < minweightslen);
3766  if( minweights[middle] <= capacity - weight )
3767  left = middle;
3768  else
3769  right = middle;
3770  }
3771  assert(left == right - 1);
3772  assert(0 <= left && left < minweightslen);
3773  assert(minweights[left] <= capacity - weight );
3774  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3775 
3776  /* now z = left */
3777  z = left;
3778  assert(z <= *liftrhs);
3779  }
3780 
3781  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3782  liftcoef = (*liftrhs) - z;
3783  liftcoefs[liftvar] = liftcoef;
3784  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3785 
3786  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3787  if( liftcoef == 0 )
3788  continue;
3789 
3790  /* updates activity of current valid inequality */
3791  (*cutact) += liftcoef * solvals[liftvar];
3792 
3793  /* updates minweight table: minweight_i+1[w] =
3794  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3795  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3796  */
3797  for( w = *liftrhs; w >= 0; w-- )
3798  {
3799  SCIP_Longint min;
3800  if( w < liftcoef )
3801  {
3802  min = MIN(minweights[w], weight);
3803  minweights[w] = min;
3804  }
3805  else
3806  {
3807  assert(w >= liftcoef);
3808  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3809  minweights[w] = min;
3810  }
3811  }
3812  }
3813 
3814  /* frees temporary memory */
3815  SCIPfreeBufferArray(scip, &sortkeys);
3816  SCIPfreeBufferArray(scip, &minweights);
3817 
3818  return SCIP_OKAY;
3819 }
3820 
3821 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3822 static
3824  SCIP_Longint val1, /**< first value to add */
3825  SCIP_Longint val2 /**< second value to add */
3826  )
3827 {
3828  assert(val1 >= 0);
3829  assert(val2 >= 0);
3830 
3831  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3832  return SCIP_LONGINT_MAX;
3833  else
3834  {
3835  assert(val1 <= SCIP_LONGINT_MAX - val2);
3836  return (val1 + val2);
3837  }
3838 }
3839 
3840 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3841 static
3843  SCIP_Longint* minweights, /**< minweight table to compute */
3844  SCIP_Longint* finished, /**< given finished table */
3845  SCIP_Longint* unfinished, /**< given unfinished table */
3846  int minweightslen /**< length of minweight, finished, and unfinished tables */
3847  )
3848 {
3849  int w1;
3850  int w2;
3851 
3852  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3853  * note that finished and unfished arrays sorted by non-decreasing weight
3854  */
3855 
3856  /* initialize minweight with w2 = 0 */
3857  w2 = 0;
3858  assert(unfinished[w2] == 0);
3859  for( w1 = 0; w1 < minweightslen; w1++ )
3860  minweights[w1] = finished[w1];
3861 
3862  /* consider w2 = 1, ..., minweightslen-1 */
3863  for( w2 = 1; w2 < minweightslen; w2++ )
3864  {
3865  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3866  break;
3867 
3868  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3869  {
3870  SCIP_Longint temp;
3871 
3872  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3873  if( temp <= minweights[w1+w2] )
3874  minweights[w1+w2] = temp;
3875  }
3876  }
3877 }
3878 
3879 /** lifts given inequality
3880  * sum_{j in C_1} x_j <= alpha_0
3881  * valid for
3882  * 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;
3883  * sum_{j in Q_i} x_j <= 1, forall i in I }
3884  * to a valid inequality
3885  * 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
3886  * <= alpha_0 + sum_{j in C_2} alpha_j
3887  * for
3888  * 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 };
3889  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3890  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3891  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3892  */
3893 static
3895  SCIP* scip, /**< SCIP data structure */
3896  SCIP_GUBSET* gubset, /**< GUB set data structure */
3897  SCIP_VAR** vars, /**< variables in knapsack constraint */
3898  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3899  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3900  SCIP_Longint capacity, /**< capacity of knapsack */
3901  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3902  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3903  int* gubconsGC2, /**< GUBs in GC2 */
3904  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3905  int* gubconsGR, /**< GUBs in GR */
3906  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3907  int ngubconsGC2, /**< number of GUBs in GC2 */
3908  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3909  int ngubconsGR, /**< number of GUBs in GR */
3910  int alpha0, /**< rights hand side of given valid inequality */
3911  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3912  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3913  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3914  int maxgubvarssize /**< maximal size of GUB constraints */
3915  )
3916 {
3917  SCIP_Longint* minweights;
3918  SCIP_Longint* finished;
3919  SCIP_Longint* unfinished;
3920  int* gubconsGOC1;
3921  int* gubconsGNC1;
3922  int* liftgubvars;
3923  SCIP_Longint fixedonesweight;
3924  SCIP_Longint weight;
3925  SCIP_Longint weightdiff1;
3926  SCIP_Longint weightdiff2;
3927  SCIP_Longint min;
3928  int minweightssize;
3929  int minweightslen;
3930  int nvars;
3931  int varidx;
3932  int liftgubconsidx;
3933  int liftvar;
3934  int sumliftcoef;
3935  int liftcoef;
3936  int ngubconsGOC1;
3937  int ngubconsGNC1;
3938  int left;
3939  int right;
3940  int middle;
3941  int nliftgubvars;
3942  int tmplen;
3943  int tmpsize;
3944  int j;
3945  int k;
3946  int w;
3947  int z;
3948 #ifndef NDEBUG
3949  int ngubconss;
3950  int nliftgubC1;
3951 
3952  assert(gubset != NULL);
3953  ngubconss = gubset->ngubconss;
3954 #else
3955  assert(gubset != NULL);
3956 #endif
3957 
3958  nvars = gubset->nvars;
3959 
3960  assert(scip != NULL);
3961  assert(vars != NULL);
3962  assert(nvars >= 0);
3963  assert(weights != NULL);
3964  assert(capacity >= 0);
3965  assert(solvals != NULL);
3966  assert(gubconsGC1 != NULL);
3967  assert(gubconsGC2 != NULL);
3968  assert(gubconsGFC1 != NULL);
3969  assert(gubconsGR != NULL);
3970  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3971  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3972  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3973  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3974  assert(alpha0 >= 0);
3975  assert(liftcoefs != NULL);
3976  assert(cutact != NULL);
3977  assert(liftrhs != NULL);
3978 
3979  minweightssize = ngubconsGC1+1;
3980 
3981  /* allocates temporary memory */
3982  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3983  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3984  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3985  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3986  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3987  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3988 
3989  /* initializes data structures */
3990  BMSclearMemoryArray(liftcoefs, nvars);
3991  *cutact = 0.0;
3992 
3993  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
3994  * valid inequality
3995  */
3996  ngubconsGOC1 = 0;
3997  ngubconsGNC1 = 0;
3998  for( j = 0; j < ngubconsGC1; j++ )
3999  {
4000  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4001  {
4002  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4003  ngubconsGOC1++;
4004  }
4005  else
4006  {
4007  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4008  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4009  ngubconsGNC1++;
4010  }
4011  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4012  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4013  {
4014  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4015  assert(varidx >= 0 && varidx < nvars);
4016  assert(liftcoefs[varidx] == 0);
4017 
4018  liftcoefs[varidx] = 1;
4019  (*cutact) += solvals[varidx];
4020  }
4021  assert(k >= 1);
4022  }
4023  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4024  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4025 
4026  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4027  * - finished_i[w] =
4028  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4029  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4030  * sum_{j in Q_k} x_j <= 1
4031  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4032  * - unfinished_i[w] =
4033  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4034  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4035  * sum_{j in Q_k} x_j <= 1
4036  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4037  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4038  */
4039 
4040  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4041  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4042  * 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
4043  * comes from the first variable in the GUB
4044  */
4045  assert(ngubconsGOC1 <= ngubconsGC1);
4046  finished[0] = 0;
4047  for( w = 1; w <= ngubconsGOC1; w++ )
4048  {
4049  liftgubconsidx = gubconsGOC1[w-1];
4050 
4051  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4052  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4053 
4054  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4055 
4056  assert(varidx >= 0 && varidx < nvars);
4057  assert(liftcoefs[varidx] == 1);
4058 
4059  min = weights[varidx];
4060  finished[w] = finished[w-1] + min;
4061 
4062 #ifndef NDEBUG
4063  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4064  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4065  {
4066  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4067  assert(varidx >= 0 && varidx < nvars);
4068  assert(liftcoefs[varidx] == 1);
4069  assert(weights[varidx] >= min);
4070  }
4071 #endif
4072  }
4073  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4074  finished[w] = SCIP_LONGINT_MAX;
4075 
4076  /* initialize unfinished table; note that variables in GNC1 GUBs
4077  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4078  * 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
4079  * comes from the first variable in the GUB
4080  */
4081  assert(ngubconsGNC1 <= ngubconsGC1);
4082  unfinished[0] = 0;
4083  for( w = 1; w <= ngubconsGNC1; w++ )
4084  {
4085  liftgubconsidx = gubconsGNC1[w-1];
4086 
4087  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4088  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4089 
4090  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4091 
4092  assert(varidx >= 0 && varidx < nvars);
4093  assert(liftcoefs[varidx] == 1);
4094 
4095  min = weights[varidx];
4096  unfinished[w] = unfinished[w-1] + min;
4097 
4098 #ifndef NDEBUG
4099  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4100  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4101  {
4102  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4103  assert(varidx >= 0 && varidx < nvars);
4104  assert(liftcoefs[varidx] == 1);
4105  assert(weights[varidx] >= min );
4106  }
4107 #endif
4108  }
4109  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4110  unfinished[w] = SCIP_LONGINT_MAX;
4111 
4112  /* initialize minweights table; note that variables in GC1 GUBs
4113  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4114  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4115  * consuming) because is it has to be build using weights from C1 only.
4116  */
4117  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4118  minweights[0] = 0;
4119  for( w = 1; w <= ngubconsGC1; w++ )
4120  {
4121  liftgubconsidx = gubconsGC1[w-1];
4122 
4123  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4124  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4125  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4126 
4127  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4128 
4129  assert(varidx >= 0 && varidx < nvars);
4130  assert(liftcoefs[varidx] == 1);
4131 
4132  min = weights[varidx];
4133  minweights[w] = minweights[w-1] + min;
4134 
4135 #ifndef NDEBUG
4136  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4137  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4138  {
4139  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4140  assert(varidx >= 0 && varidx < nvars);
4141  assert(liftcoefs[varidx] == 1);
4142  assert(weights[varidx] >= min);
4143  }
4144 #endif
4145  }
4146  minweightslen = ngubconsGC1 + 1;
4147 
4148  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4149  fixedonesweight = 0;
4150  for( j = 0; j < ngubconsGC2; j++ )
4151  {
4152  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4153 
4154  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4155  assert(varidx >= 0 && varidx < nvars);
4156  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4157 
4158  fixedonesweight += weights[varidx];
4159  }
4160  assert(fixedonesweight >= 0);
4161 
4162  /* initializes right hand side of lifted valid inequality */
4163  *liftrhs = alpha0;
4164 
4165  /* sequentially up-lifts all variables in GFC1 GUBs */
4166  for( j = 0; j < ngubconsGFC1; j++ )
4167  {
4168  liftgubconsidx = gubconsGFC1[j];
4169  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4170 
4171  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4172  * compute minweight table via updated unfinished table and aleady upto date finished table;
4173  */
4174  k = 0;
4175  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4176  {
4177  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4178  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4179  assert(ngubconsGNC1 > 0);
4180 
4181  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4182  * are considered for the lifting, i.e., not capacity exceeding
4183  */
4184  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4185  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4186  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4187  assert(k >= 1);
4188 
4189  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4190  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4191  */
4192  weight = weights[liftgubvars[0]];
4193 
4194  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4195  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4196  for( w = ngubconsGNC1-1; w >= 1; w-- )
4197  {
4198  weightdiff1 = weightdiff2;
4199  weightdiff2 = unfinished[w] - weight;
4200 
4201  if( unfinished[w] < weightdiff1 )
4202  unfinished[w] = weightdiff1;
4203  else
4204  break;
4205  }
4206  ngubconsGNC1--;
4207 
4208  /* computes minweights table by combining unfished and fished tables */
4209  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4210  assert(minweights[0] == 0);
4211  }
4212  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4213  * are therefore not in the unfinished table
4214  */
4215  else
4216  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4217 
4218 #ifndef NDEBUG
4219  nliftgubC1 = k;
4220 #endif
4221  nliftgubvars = k;
4222  sumliftcoef = 0;
4223 
4224  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4225  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4226  {
4227  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4228  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4229  {
4230  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4231  weight = weights[liftvar];
4232  assert(weight > 0);
4233  assert(liftvar >= 0 && liftvar < nvars);
4234  assert(capacity - weight >= 0);
4235 
4236  /* put variable into array of variables in GUB that are considered for the lifting,
4237  * i.e., not capacity exceeding
4238  */
4239  liftgubvars[nliftgubvars] = liftvar;
4240  nliftgubvars++;
4241 
4242  /* knapsack problem is infeasible:
4243  * sets z = 0
4244  */
4245  if( capacity - fixedonesweight - weight < 0 )
4246  {
4247  z = 0;
4248  }
4249  /* knapsack problem is feasible:
4250  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4251  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4252  */
4253  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4254  {
4255  z = *liftrhs;
4256  }
4257  /* knapsack problem is feasible:
4258  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4259  */
4260  else
4261  {
4262  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4263  left = 0;
4264  right = (*liftrhs) + 1;
4265  while( left < right - 1 )
4266  {
4267  middle = (left + right) / 2;
4268  assert(0 <= middle && middle < minweightslen);
4269  if( minweights[middle] <= capacity - fixedonesweight - weight )
4270  left = middle;
4271  else
4272  right = middle;
4273  }
4274  assert(left == right - 1);
4275  assert(0 <= left && left < minweightslen);
4276  assert(minweights[left] <= capacity - fixedonesweight - weight);
4277  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4278 
4279  /* now z = left */
4280  z = left;
4281  assert(z <= *liftrhs);
4282  }
4283 
4284  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4285  liftcoef = (*liftrhs) - z;
4286  liftcoefs[liftvar] = liftcoef;
4287  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4288 
4289  /* updates activity of current valid inequality */
4290  (*cutact) += liftcoef * solvals[liftvar];
4291 
4292  /* updates sum of all lifting coefficients in GUB */
4293  sumliftcoef += liftcoefs[liftvar];
4294  }
4295  else
4296  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4297  }
4298  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4299  assert(nliftgubvars > nliftgubC1);
4300 
4301  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4302  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4303  * not needed for GF GUBs
4304  */
4305  if( sumliftcoef == 0 )
4306  {
4307  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4308  {
4309  weight = weights[liftgubvars[0]];
4310  /* update finished table and minweights table by applying special case of
4311  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4312  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4313  */
4314  for( w = minweightslen-1; w >= 1; w-- )
4315  {
4316  SCIP_Longint tmpval;
4317 
4318  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4319  finished[w] = MIN(finished[w], tmpval);
4320 
4321  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4322  minweights[w] = MIN(minweights[w], tmpval);
4323  }
4324  }
4325  else
4326  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4327 
4328  continue;
4329  }
4330 
4331  /* enlarges current minweights tables(finished, unfinished, minweights):
4332  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4333  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4334  * and sets minweights_i[w] = infinity for
4335  * 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
4336  */
4337  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4338  tmpsize = minweightssize;
4339  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4340  tmplen = minweightslen;
4341  tmpsize = minweightssize;
4342  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4343  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4344 
4345  /* update finished table and minweight table;
4346  * note that instead of computing minweight table from updated finished and updated unfinished table again
4347  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4348  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4349  * not needed because only finished table changed at this point and the change was "adding" one weight)
4350  *
4351  * update formular for minweight table is: minweight_i+1[w] =
4352  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4353  * formular for finished table has the same pattern.
4354  */
4355  for( w = minweightslen-1; w >= 0; w-- )
4356  {
4357  SCIP_Longint minminweight;
4358  SCIP_Longint minfinished;
4359 
4360  for( k = 0; k < nliftgubvars; k++ )
4361  {
4362  liftcoef = liftcoefs[liftgubvars[k]];
4363  weight = weights[liftgubvars[k]];
4364 
4365  if( w < liftcoef )
4366  {
4367  minfinished = MIN(finished[w], weight);
4368  minminweight = MIN(minweights[w], weight);
4369 
4370  finished[w] = minfinished;
4371  minweights[w] = minminweight;
4372  }
4373  else
4374  {
4375  SCIP_Longint tmpval;
4376 
4377  assert(w >= liftcoef);
4378 
4379  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4380  minfinished = MIN(finished[w], tmpval);
4381 
4382  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4383  minminweight = MIN(minweights[w], tmpval);
4384 
4385  finished[w] = minfinished;
4386  minweights[w] = minminweight;
4387  }
4388  }
4389  }
4390  assert(minweights[0] == 0);
4391  }
4392  assert(ngubconsGNC1 == 0);
4393 
4394  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4395  * therefore, only work with minweight table from here on
4396  */
4397 
4398  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4399  for( j = 0; j < ngubconsGC2; j++ )
4400  {
4401  liftgubconsidx = gubconsGC2[j];
4402 
4403  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4404  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4405  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4406  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4407 
4408  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4409  weight = weights[liftvar];
4410 
4411  assert(liftvar >= 0 && liftvar < nvars);
4412  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4413  assert(weight > 0);
4414 
4415  /* uses binary search to find
4416  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4417  */
4418  left = 0;
4419  right = minweightslen;
4420  while( left < right - 1 )
4421  {
4422  middle = (left + right) / 2;
4423  assert(0 <= middle && middle < minweightslen);
4424  if( minweights[middle] <= capacity - fixedonesweight + weight )
4425  left = middle;
4426  else
4427  right = middle;
4428  }
4429  assert(left == right - 1);
4430  assert(0 <= left && left < minweightslen);
4431  assert(minweights[left] <= capacity - fixedonesweight + weight);
4432  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4433 
4434  /* now z = left */
4435  z = left;
4436  assert(z >= *liftrhs);
4437 
4438  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4439  liftcoef = z - (*liftrhs);
4440  liftcoefs[liftvar] = liftcoef;
4441  assert(liftcoef >= 0);
4442 
4443  /* updates sum of weights of variables fixed to one */
4444  fixedonesweight -= weight;
4445 
4446  /* updates right-hand side of current valid inequality */
4447  (*liftrhs) += liftcoef;
4448  assert(*liftrhs >= alpha0);
4449 
4450  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4451  if( liftcoef == 0 )
4452  continue;
4453 
4454  /* updates activity of current valid inequality */
4455  (*cutact) += liftcoef * solvals[liftvar];
4456 
4457  /* enlarges current minweight table:
4458  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4459  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4460  * and sets minweights_i[w] = infinity for
4461  * 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
4462  */
4463  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4464 
4465  /* updates minweight table: minweight_i+1[w] =
4466  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4467  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4468  */
4469  for( w = minweightslen - 1; w >= 0; w-- )
4470  {
4471  if( w < liftcoef )
4472  {
4473  min = MIN(minweights[w], weight);
4474  minweights[w] = min;
4475  }
4476  else
4477  {
4478  SCIP_Longint tmpval;
4479 
4480  assert(w >= liftcoef);
4481 
4482  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4483  min = MIN(minweights[w], tmpval);
4484  minweights[w] = min;
4485  }
4486  }
4487  }
4488  assert(fixedonesweight == 0);
4489  assert(*liftrhs >= alpha0);
4490 
4491  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4492  for( j = 0; j < ngubconsGR; j++ )
4493  {
4494  liftgubconsidx = gubconsGR[j];
4495 
4496  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4497  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4498 
4499  sumliftcoef = 0;
4500  nliftgubvars = 0;
4501  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4502  {
4503  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4504  {
4505  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4506  weight = weights[liftvar];
4507  assert(weight > 0);
4508  assert(liftvar >= 0 && liftvar < nvars);
4509  assert(capacity - weight >= 0);
4510  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4511 
4512  /* put variable into array of variables in GUB that are considered for the lifting,
4513  * i.e., not capacity exceeding
4514  */
4515  liftgubvars[nliftgubvars] = liftvar;
4516  nliftgubvars++;
4517 
4518  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4519  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4520  */
4521  if( minweights[*liftrhs] <= capacity - weight )
4522  {
4523  z = *liftrhs;
4524  }
4525  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4526  */
4527  else
4528  {
4529  left = 0;
4530  right = (*liftrhs) + 1;
4531  while( left < right - 1 )
4532  {
4533  middle = (left + right) / 2;
4534  assert(0 <= middle && middle < minweightslen);
4535  if( minweights[middle] <= capacity - weight )
4536  left = middle;
4537  else
4538  right = middle;
4539  }
4540  assert(left == right - 1);
4541  assert(0 <= left && left < minweightslen);
4542  assert(minweights[left] <= capacity - weight);
4543  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4544 
4545  /* now z = left */
4546  z = left;
4547  assert(z <= *liftrhs);
4548  }
4549  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4550  liftcoef = (*liftrhs) - z;
4551  liftcoefs[liftvar] = liftcoef;
4552  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4553 
4554  /* updates activity of current valid inequality */
4555  (*cutact) += liftcoef * solvals[liftvar];
4556 
4557  /* updates sum of all lifting coefficients in GUB */
4558  sumliftcoef += liftcoefs[liftvar];
4559  }
4560  else
4561  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4562  }
4563  assert(nliftgubvars >= 1); /* at least one variable is in R */
4564 
4565  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4566  if( sumliftcoef == 0 )
4567  continue;
4568 
4569  /* updates minweight table: minweight_i+1[w] =
4570  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4571  */
4572  for( w = *liftrhs; w >= 0; w-- )
4573  {
4574  for( k = 0; k < nliftgubvars; k++ )
4575  {
4576  liftcoef = liftcoefs[liftgubvars[k]];
4577  weight = weights[liftgubvars[k]];
4578 
4579  if( w < liftcoef )
4580  {
4581  min = MIN(minweights[w], weight);
4582  minweights[w] = min;
4583  }
4584  else
4585  {
4586  SCIP_Longint tmpval;
4587 
4588  assert(w >= liftcoef);
4589 
4590  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4591  min = MIN(minweights[w], tmpval);
4592  minweights[w] = min;
4593  }
4594  }
4595  }
4596  assert(minweights[0] == 0);
4597  }
4598 
4599  /* frees temporary memory */
4600  SCIPfreeBufferArray(scip, &minweights);
4601  SCIPfreeBufferArray(scip, &finished);
4602  SCIPfreeBufferArray(scip, &unfinished);
4603  SCIPfreeBufferArray(scip, &liftgubvars);
4604  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4605  SCIPfreeBufferArray(scip, &gubconsGNC1);
4606 
4607  return SCIP_OKAY;
4608 }
4609 
4610 /** lifts given minimal cover inequality
4611  * \f[
4612  * \sum_{j \in C} x_j \leq |C| - 1
4613  * \f]
4614  * valid for
4615  * \f[
4616  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4617  * \f]
4618  * to a valid inequality
4619  * \f[
4620  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4621  * \f]
4622  * for
4623  * \f[
4624  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4625  * \f]
4626  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4627  */
4628 static
4630  SCIP* scip, /**< SCIP data structure */
4631  SCIP_VAR** vars, /**< variables in knapsack constraint */
4632  int nvars, /**< number of variables in knapsack constraint */
4633  int ntightened, /**< number of variables with tightened upper bound */
4634  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4635  SCIP_Longint capacity, /**< capacity of knapsack */
4636  SCIP_Real* solvals, /**< solution values of all problem variables */
4637  int* covervars, /**< cover variables */
4638  int* noncovervars, /**< noncover variables */
4639  int ncovervars, /**< number of cover variables */
4640  int nnoncovervars, /**< number of noncover variables */
4641  SCIP_Longint coverweight, /**< weight of cover */
4642  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4643  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4644  )
4645 {
4646  SCIP_Longint* maxweightsums;
4647  SCIP_Longint* intervalends;
4648  SCIP_Longint* rhos;
4649  SCIP_Real* sortkeys;
4650  SCIP_Longint lambda;
4651  int j;
4652  int h;
4653 
4654  assert(scip != NULL);
4655  assert(vars != NULL);
4656  assert(nvars >= 0);
4657  assert(weights != NULL);
4658  assert(capacity >= 0);
4659  assert(solvals != NULL);
4660  assert(covervars != NULL);
4661  assert(noncovervars != NULL);
4662  assert(ncovervars > 0 && ncovervars <= nvars);
4663  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4664  assert(ncovervars + nnoncovervars == nvars - ntightened);
4665  assert(liftcoefs != NULL);
4666  assert(cutact != NULL);
4667 
4668  /* allocates temporary memory */
4669  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4670  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4671  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4672  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4673 
4674  /* initializes data structures */
4675  BMSclearMemoryArray(liftcoefs, nvars);
4676  *cutact = 0.0;
4677 
4678  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4679  * and calculates activity of current valid inequality
4680  */
4681  for( j = 0; j < ncovervars; j++ )
4682  {
4683  assert(liftcoefs[covervars[j]] == 0.0);
4684  liftcoefs[covervars[j]] = 1.0;
4685  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4686  (*cutact) += solvals[covervars[j]];
4687  }
4688  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4689 
4690  /* calculates weight excess of cover C */
4691  lambda = coverweight - capacity;
4692  assert(lambda > 0);
4693 
4694  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4695  maxweightsums[0] = 0;
4696  for( h = 1; h <= ncovervars; h++ )
4697  {
4698  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4699  intervalends[h-1] = maxweightsums[h] - lambda;
4700  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4701  }
4702 
4703  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4704  for( j = 0; j < nnoncovervars; j++ )
4705  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4706  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4707 
4708  /* calculates lifting coefficient for all variables in N\C */
4709  h = 0;
4710  for( j = 0; j < nnoncovervars; j++ )
4711  {
4712  int liftvar;
4713  SCIP_Longint weight;
4714  SCIP_Real liftcoef;
4715 
4716  liftvar = noncovervars[j];
4717  weight = weights[liftvar];
4718 
4719  while( intervalends[h] < weight )
4720  h++;
4721 
4722  if( h == 0 )
4723  liftcoef = h;
4724  else
4725  {
4726  if( weight <= intervalends[h-1] + rhos[h] )
4727  {
4728  SCIP_Real tmp1;
4729  SCIP_Real tmp2;
4730  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4731  tmp2 = (SCIP_Real) rhos[1];
4732  liftcoef = h - ( tmp1 / tmp2 );
4733  }
4734  else
4735  liftcoef = h;
4736  }
4737 
4738  /* sets lifting coefficient */
4739  assert(liftcoefs[liftvar] == 0.0);
4740  liftcoefs[liftvar] = liftcoef;
4741 
4742  /* updates activity of current valid inequality */
4743  (*cutact) += liftcoef * solvals[liftvar];
4744  }
4745 
4746  /* frees temporary memory */
4747  SCIPfreeBufferArray(scip, &rhos);
4748  SCIPfreeBufferArray(scip, &intervalends);
4749  SCIPfreeBufferArray(scip, &maxweightsums);
4750  SCIPfreeBufferArray(scip, &sortkeys);
4751 
4752  return SCIP_OKAY;
4753 }
4754 
4755 
4756 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4757  * given knapsack problem
4758 */
4759 static
4761  SCIP* scip, /**< SCIP data structure */
4762  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4763  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4764  SCIP_VAR** vars, /**< variables in knapsack constraint */
4765  int nvars, /**< number of variables in knapsack constraint */
4766  int ntightened, /**< number of variables with tightened upper bound */
4767  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4768  SCIP_Longint capacity, /**< capacity of knapsack */
4769  SCIP_Real* solvals, /**< solution values of all problem variables */
4770  int* mincovervars, /**< mincover variables */
4771  int* nonmincovervars, /**< nonmincover variables */
4772  int nmincovervars, /**< number of mincover variables */
4773  int nnonmincovervars, /**< number of nonmincover variables */
4774  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4775  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4776  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4777  int* ncuts /**< pointer to add up the number of found cuts */
4778  )
4779 {
4780  int* varsC1;
4781  int* varsC2;
4782  int* varsF;
4783  int* varsR;
4784  int nvarsC1;
4785  int nvarsC2;
4786  int nvarsF;
4787  int nvarsR;
4788  SCIP_Real cutact;
4789  int* liftcoefs;
4790  int liftrhs;
4791 
4792  assert( cutoff != NULL );
4793  *cutoff = FALSE;
4794 
4795  /* allocates temporary memory */
4796  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4797  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4798  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4799  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4800  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4801 
4802  /* 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
4803  * as follows
4804  * C_2 = { j in C : x*_j = 1 } and
4805  * C_1 = C\C_2
4806  */
4807  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4808  assert(nvarsC1 + nvarsC2 == nmincovervars);
4809  assert(nmincovervars > 0);
4810  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4811 
4812  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4813  if( nvarsC1 < 2 && nvarsC2 > 0)
4814  {
4815  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4816  assert(nvarsC1 >= 1);
4817  }
4818  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4819 
4820  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4821  * R = { j in N\C : x*_j = 0 } and
4822  * F = (N\C)\F
4823  */
4824  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4825  assert(nvarsF + nvarsR == nnonmincovervars);
4826  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4827 
4828  /* lift cuts without GUB information */
4829  if( gubset == NULL )
4830  {
4831  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4832  * lifting procedure
4833  */
4834  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4835 
4836  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4837  *
4838  * 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 }
4839  *
4840  * 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
4841  *
4842  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4843  *
4844  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4845  * up-lifting for the variables in R according to the second level lifting sequence
4846  */
4847  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4848  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4849  }
4850  /* lift cuts with GUB information */
4851  else
4852  {
4853  int* gubconsGC1;
4854  int* gubconsGC2;
4855  int* gubconsGFC1;
4856  int* gubconsGR;
4857  int ngubconsGC1;
4858  int ngubconsGC2;
4859  int ngubconsGFC1;
4860  int ngubconsGR;
4861  int ngubconss;
4862  int nconstightened;
4863  int maxgubvarssize;
4864 
4865  assert(nvars == gubset->nvars);
4866 
4867  ngubconsGC1 = 0;
4868  ngubconsGC2 = 0;
4869  ngubconsGFC1 = 0;
4870  ngubconsGR = 0;
4871  ngubconss = gubset->ngubconss;
4872  nconstightened = 0;
4873  maxgubvarssize = 0;
4874 
4875  /* allocates temporary memory */
4876  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4877  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4878  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4879  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4880 
4881  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4882  * the GUBs for the sequential GUB wise lifting procedure
4883  */
4884  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4885  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4886  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4887 
4888  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4889  *
4890  * 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,
4891  * sum_{j in Q_i} x_j <= 1, forall i in I }
4892  *
4893  * 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
4894  *
4895  * 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 },
4896  *
4897  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4898  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4899  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4900  */
4901  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4902  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4903  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4904 
4905  /* frees temporary memory */
4906  SCIPfreeBufferArray(scip, &gubconsGR);
4907  SCIPfreeBufferArray(scip, &gubconsGFC1);
4908  SCIPfreeBufferArray(scip, &gubconsGC2);
4909  SCIPfreeBufferArray(scip, &gubconsGC1);
4910  }
4911 
4912  /* checks, if lifting yielded a violated cut */
4913  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4914  {
4915  SCIP_ROW* row;
4916  char name[SCIP_MAXSTRLEN];
4917  int j;
4918 
4919  /* creates LP row */
4920  assert( cons == NULL || sepa == NULL );
4921  if ( cons != NULL )
4922  {
4924  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4925  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4926  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4927  }
4928  else if ( sepa != NULL )
4929  {
4930  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4931  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4932  }
4933  else
4934  {
4935  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
4936  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4937  }
4938 
4939  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4940  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4941  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4942  for( j = 0; j < nvarsC1; j++ )
4943  {
4944  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4945  }
4946  for( j = 0; j < nvarsC2; j++ )
4947  {
4948  if( liftcoefs[varsC2[j]] > 0 )
4949  {
4950  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4951  }
4952  }
4953  for( j = 0; j < nvarsF; j++ )
4954  {
4955  if( liftcoefs[varsF[j]] > 0 )
4956  {
4957  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4958  }
4959  }
4960  for( j = 0; j < nvarsR; j++ )
4961  {
4962  if( liftcoefs[varsR[j]] > 0 )
4963  {
4964  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4965  }
4966  }
4967  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4968 
4969  /* checks, if cut is violated enough */
4970  if( SCIPisCutEfficacious(scip, sol, row) )
4971  {
4972  if( cons != NULL )
4973  {
4974  SCIP_CALL( SCIPresetConsAge(scip, cons) );
4975  }
4976  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
4977  (*ncuts)++;
4978  }
4979  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4980  }
4981 
4982  /* frees temporary memory */
4983  SCIPfreeBufferArray(scip, &liftcoefs);
4984  SCIPfreeBufferArray(scip, &varsR);
4985  SCIPfreeBufferArray(scip, &varsF);
4986  SCIPfreeBufferArray(scip, &varsC2);
4987  SCIPfreeBufferArray(scip, &varsC1);
4988 
4989  return SCIP_OKAY;
4990 }
4991 
4992 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
4993 static
4995  SCIP* scip, /**< SCIP data structure */
4996  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
4997  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4998  SCIP_VAR** vars, /**< variables in knapsack constraint */
4999  int nvars, /**< number of variables in knapsack constraint */
5000  int ntightened, /**< number of variables with tightened upper bound */
5001  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5002  SCIP_Longint capacity, /**< capacity of knapsack */
5003  SCIP_Real* solvals, /**< solution values of all problem variables */
5004  int* feassetvars, /**< variables in feasible set */
5005  int* nonfeassetvars, /**< variables not in feasible set */
5006  int nfeassetvars, /**< number of variables in feasible set */
5007  int nnonfeassetvars, /**< number of variables not in feasible set */
5008  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5009  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5010  int* ncuts /**< pointer to add up the number of found cuts */
5011  )
5012 {
5013  int* varsT1;
5014  int* varsT2;
5015  int* varsF;
5016  int* varsR;
5017  int* liftcoefs;
5018  SCIP_Real cutact;
5019  int nvarsT1;
5020  int nvarsT2;
5021  int nvarsF;
5022  int nvarsR;
5023  int liftrhs;
5024  int j;
5025 
5026  assert( cutoff != NULL );
5027  *cutoff = FALSE;
5028 
5029  /* allocates temporary memory */
5030  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5031  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5032  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5033  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5034  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5035 
5036  /* 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
5037  * as follows
5038  * T_2 = { j in T : x*_j = 1 } and
5039  * T_1 = T\T_2
5040  */
5041  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5042  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5043 
5044  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5045  if( nvarsT1 == 0 && nvarsT2 > 0)
5046  {
5047  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5048  assert(nvarsT1 == 1);
5049  }
5050  assert(nvarsT2 == 0 || nvarsT1 > 0);
5051 
5052  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5053  * R = { j in N\T : x*_j = 0 } and
5054  * F = (N\T)\F
5055  */
5056  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5057  assert(nvarsF + nvarsR == nnonfeassetvars);
5058  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5059 
5060  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5061  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5062  * is included in the sorting routine)
5063  */
5064  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5065 
5066  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5067  *
5068  * 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 }
5069  *
5070  * 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
5071  *
5072  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5073  *
5074  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5075  * up-lifting for the variabels in R according to the second level lifting sequence
5076  */
5077  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5078  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5079 
5080  /* checks, if lifting yielded a violated cut */
5081  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5082  {
5083  SCIP_ROW* row;
5084  char name[SCIP_MAXSTRLEN];
5085 
5086  /* creates LP row */
5087  assert( cons == NULL || sepa == NULL );
5088  if( cons != NULL )
5089  {
5091  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5092  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5093  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5094  }
5095  else if ( sepa != NULL )
5096  {
5097  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5098  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5099  }
5100  else
5101  {
5102  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
5103  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5104  }
5105 
5106  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5107  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5108  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5109  for( j = 0; j < nvarsT1; j++ )
5110  {
5111  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5112  }
5113  for( j = 0; j < nvarsT2; j++ )
5114  {
5115  if( liftcoefs[varsT2[j]] > 0 )
5116  {
5117  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5118  }
5119  }
5120  for( j = 0; j < nvarsF; j++ )
5121  {
5122  if( liftcoefs[varsF[j]] > 0 )
5123  {
5124  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5125  }
5126  }
5127  for( j = 0; j < nvarsR; j++ )
5128  {
5129  if( liftcoefs[varsR[j]] > 0 )
5130  {
5131  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5132  }
5133  }
5134  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5135 
5136  /* checks, if cut is violated enough */
5137  if( SCIPisCutEfficacious(scip, sol, row) )
5138  {
5139  if( cons != NULL )
5140  {
5141  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5142  }
5143  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5144  (*ncuts)++;
5145  }
5146  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5147  }
5148 
5149  /* frees temporary memory */
5150  SCIPfreeBufferArray(scip, &liftcoefs);
5151  SCIPfreeBufferArray(scip, &varsR);
5152  SCIPfreeBufferArray(scip, &varsF);
5153  SCIPfreeBufferArray(scip, &varsT2);
5154  SCIPfreeBufferArray(scip, &varsT1);
5155 
5156  return SCIP_OKAY;
5157 }
5158 
5159 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5160 static
5162  SCIP* scip, /**< SCIP data structure */
5163  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5164  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5165  SCIP_VAR** vars, /**< variables in knapsack constraint */
5166  int nvars, /**< number of variables in knapsack constraint */
5167  int ntightened, /**< number of variables with tightened upper bound */
5168  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5169  SCIP_Longint capacity, /**< capacity of knapsack */
5170  SCIP_Real* solvals, /**< solution values of all problem variables */
5171  int* mincovervars, /**< mincover variables */
5172  int* nonmincovervars, /**< nonmincover variables */
5173  int nmincovervars, /**< number of mincover variables */
5174  int nnonmincovervars, /**< number of nonmincover variables */
5175  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5176  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5177  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5178  int* ncuts /**< pointer to add up the number of found cuts */
5179  )
5180 {
5181  SCIP_Real* realliftcoefs;
5182  SCIP_Real cutact;
5183  int liftrhs;
5184 
5185  assert( cutoff != NULL );
5186  *cutoff = FALSE;
5187  cutact = 0.0;
5188 
5189  /* allocates temporary memory */
5190  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5191 
5192  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5193  *
5194  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5195  *
5196  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5197  *
5198  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5199  *
5200  * uses superadditive up-lifting for the variables in N\C.
5201  */
5202  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5203  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5204  liftrhs = nmincovervars - 1;
5205 
5206  /* checks, if lifting yielded a violated cut */
5207  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5208  {
5209  SCIP_ROW* row;
5210  char name[SCIP_MAXSTRLEN];
5211  int j;
5212 
5213  /* creates LP row */
5214  assert( cons == NULL || sepa == NULL );
5215  if ( cons != NULL )
5216  {
5218  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5219  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5220  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5221  }
5222  else if ( sepa != NULL )
5223  {
5224  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5225  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5226  }
5227  else
5228  {
5229  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%" SCIP_LONGINT_FORMAT "", *ncuts);
5230  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5231  }
5232 
5233  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5234  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5235  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5236  for( j = 0; j < nmincovervars; j++ )
5237  {
5238  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5239  }
5240  for( j = 0; j < nnonmincovervars; j++ )
5241  {
5242  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5243  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5244  {
5245  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5246  }
5247  }
5248  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5249 
5250  /* checks, if cut is violated enough */
5251  if( SCIPisCutEfficacious(scip, sol, row) )
5252  {
5253  if( cons != NULL )
5254  {
5255  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5256  }
5257  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5258  (*ncuts)++;
5259  }
5260  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5261  }
5262 
5263  /* frees temporary memory */
5264  SCIPfreeBufferArray(scip, &realliftcoefs);
5265 
5266  return SCIP_OKAY;
5267 }
5268 
5269 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5270  * 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
5271  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5272  * note that all variables with x*_j = 1 will be removed last
5273  */
5274 static
5276  SCIP* scip, /**< SCIP data structure */
5277  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5278  SCIP_Longint capacity, /**< capacity of knapsack */
5279  SCIP_Real* solvals, /**< solution values of all problem variables */
5280  int* covervars, /**< pointer to store cover variables */
5281  int* noncovervars, /**< pointer to store noncover variables */
5282  int* ncovervars, /**< pointer to store number of cover variables */
5283  int* nnoncovervars, /**< pointer to store number of noncover variables */
5284  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5285  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5286  )
5287 {
5288  SORTKEYPAIR** sortkeypairs;
5289  SORTKEYPAIR** sortkeypairssorted;
5290  SCIP_Longint minweight;
5291  int nsortkeypairs;
5292  int minweightidx;
5293  int j;
5294  int k;
5295 
5296  assert(scip != NULL);
5297  assert(covervars != NULL);
5298  assert(noncovervars != NULL);
5299  assert(ncovervars != NULL);
5300  assert(*ncovervars > 0);
5301  assert(nnoncovervars != NULL);
5302  assert(*nnoncovervars >= 0);
5303  assert(coverweight != NULL);
5304  assert(*coverweight > 0);
5305  assert(*coverweight > capacity);
5306 
5307  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5308  * order */
5309  nsortkeypairs = *ncovervars;
5310  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5311  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5312 
5313  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5314  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5315  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5316  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5317  */
5318  assert(*ncovervars == nsortkeypairs);
5319  if( modtransused )
5320  {
5321  for( j = 0; j < *ncovervars; j++ )
5322  {
5323  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5324  sortkeypairssorted[j] = sortkeypairs[j];
5325 
5326  sortkeypairs[j]->key1 = solvals[covervars[j]];
5327  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5328  }
5329  }
5330  else
5331  {
5332  for( j = 0; j < *ncovervars; j++ )
5333  {
5334  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5335  sortkeypairssorted[j] = sortkeypairs[j];
5336 
5337  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5338  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5339  }
5340  }
5341  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5342 
5343  /* gets j' with a_j' = min{ a_j : j in C } */
5344  minweightidx = 0;
5345  minweight = weights[covervars[minweightidx]];
5346  for( j = 1; j < *ncovervars; j++ )
5347  {
5348  if( weights[covervars[j]] <= minweight )
5349  {
5350  minweightidx = j;
5351  minweight = weights[covervars[minweightidx]];
5352  }
5353  }
5354  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5355  assert(minweight > 0 && minweight <= *coverweight);
5356 
5357  j = 0;
5358  /* removes variables from C until the remaining variables form a minimal cover */
5359  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5360  {
5361  assert(minweightidx >= j);
5362  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5363 
5364  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5365  if( (*coverweight) - weights[covervars[j]] <= capacity )
5366  {
5367  ++j;
5368  continue;
5369  }
5370 
5371  /* adds j to N\C */
5372  noncovervars[*nnoncovervars] = covervars[j];
5373  (*nnoncovervars)++;
5374 
5375  /* removes j from C */
5376  (*coverweight) -= weights[covervars[j]];
5377  for( k = j; k < (*ncovervars) - 1; k++ )
5378  covervars[k] = covervars[k+1];
5379  (*ncovervars)--;
5380 
5381  /* updates j' with a_j' = min{ a_j : j in C } */
5382  if( j == minweightidx )
5383  {
5384  minweightidx = 0;
5385  minweight = weights[covervars[minweightidx]];
5386  for( k = 1; k < *ncovervars; k++ )
5387  {
5388  if( weights[covervars[k]] <= minweight )
5389  {
5390  minweightidx = k;
5391  minweight = weights[covervars[minweightidx]];
5392  }
5393  }
5394  assert(minweight > 0 && minweight <= *coverweight);
5395  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5396  }
5397  else
5398  {
5399  assert(minweightidx > j);
5400  minweightidx--;
5401  }
5402  /* j needs to stay the same */
5403  }
5404  assert((*coverweight) > capacity);
5405  assert((*coverweight) - minweight <= capacity);
5406 
5407  /* frees temporary memory */
5408  for( j = nsortkeypairs-1; j >= 0; j-- )
5409  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5410  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5411  SCIPfreeBufferArray(scip, &sortkeypairs);
5412 
5413  return SCIP_OKAY;
5414 }
5415 
5416 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5417  * they were chosen to be in C_init:
5418  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5419  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5420  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5421  * and all subsequent feasible sets.
5422  */
5423 static
5425  SCIP* scip, /**< SCIP data structure */
5426  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5427  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5428  SCIP_VAR** vars, /**< variables in knapsack constraint */
5429  int nvars, /**< number of variables in knapsack constraint */
5430  int ntightened, /**< number of variables with tightened upper bound */
5431  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5432  SCIP_Longint capacity, /**< capacity of knapsack */
5433  SCIP_Real* solvals, /**< solution values of all problem variables */
5434  int* covervars, /**< pointer to store cover variables */
5435  int* noncovervars, /**< pointer to store noncover variables */
5436  int* ncovervars, /**< pointer to store number of cover variables */
5437  int* nnoncovervars, /**< pointer to store number of noncover variables */
5438  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5439  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5440  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5441  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5442  int* ncuts /**< pointer to add up the number of found cuts */
5443  )
5444 {
5445  SCIP_Real* sortkeys;
5446  int j;
5447  int k;
5448 
5449  assert(scip != NULL);
5450  assert(covervars != NULL);
5451  assert(noncovervars != NULL);
5452  assert(ncovervars != NULL);
5453  assert(*ncovervars > 0);
5454  assert(nnoncovervars != NULL);
5455  assert(*nnoncovervars >= 0);
5456  assert(coverweight != NULL);
5457  assert(*coverweight > 0);
5458  assert(*coverweight > capacity);
5459  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5460  assert(cutoff != NULL);
5461 
5462  *cutoff = FALSE;
5463 
5464  /* allocates temporary memory */
5465  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5466 
5467  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5468  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5469  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5470  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5471  */
5472  if( modtransused )
5473  {
5474  for( j = 0; j < *ncovervars; j++ )
5475  {
5476  sortkeys[j] = solvals[covervars[j]];
5477  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5478  }
5479  }
5480  else
5481  {
5482  for( j = 0; j < *ncovervars; j++ )
5483  {
5484  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5485  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5486  }
5487  }
5488  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5489 
5490  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5491  * in addition to an extended weight inequality this gives cardinality inequalities */
5492  while( *ncovervars >= 2 )
5493  {
5494  /* adds first element of C_init to N\C_init */
5495  noncovervars[*nnoncovervars] = covervars[0];
5496  (*nnoncovervars)++;
5497 
5498  /* removes first element from C_init */
5499  (*coverweight) -= weights[covervars[0]];
5500  for( k = 0; k < (*ncovervars) - 1; k++ )
5501  covervars[k] = covervars[k+1];
5502  (*ncovervars)--;
5503 
5504  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5505  if( (*coverweight) <= capacity )
5506  {
5507  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5508  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5509  }
5510 
5511  /* stop if cover is too large */
5512  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5513  break;
5514  }
5515 
5516  /* frees temporary memory */
5517  SCIPfreeBufferArray(scip, &sortkeys);
5518 
5519  return SCIP_OKAY;
5520 }
5521 
5522 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5524  SCIP* scip, /**< SCIP data structure */
5525  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5526  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5527  SCIP_VAR** vars, /**< variables in knapsack constraint */
5528  int nvars, /**< number of variables in knapsack constraint */
5529  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5530  SCIP_Longint capacity, /**< capacity of knapsack */
5531  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5532  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5533  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5534  int* ncuts /**< pointer to add up the number of found cuts */
5535  )
5536 {
5537  SCIP_Real* solvals;
5538  int* covervars;
5539  int* noncovervars;
5540  SCIP_Bool coverfound;
5541  SCIP_Bool fractional;
5542  SCIP_Bool modtransused;
5543  SCIP_Longint coverweight;
5544  int ncovervars;
5545  int nnoncovervars;
5546  int ntightened;
5547 
5548  assert(scip != NULL);
5549  assert(capacity >= 0);
5550  assert(cutoff != NULL);
5551  assert(ncuts != NULL);
5552 
5553  *cutoff = FALSE;
5554 
5555  if( nvars == 0 )
5556  return SCIP_OKAY;
5557 
5558  assert(vars != NULL);
5559  assert(nvars > 0);
5560  assert(weights != NULL);
5561 
5562  /* increase age of constraint (age is reset to zero, if a cut was found) */
5563  if( cons != NULL )
5564  {
5565  SCIP_CALL( SCIPincConsAge(scip, cons) );
5566  }
5567 
5568  /* allocates temporary memory */
5569  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5570  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5571  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5572 
5573  /* gets solution values of all problem variables */
5574  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5575 
5576 #ifdef SCIP_DEBUG
5577  {
5578  int i;
5579 
5580  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5581  cons == NULL ? "-" : SCIPconsGetName(cons));
5582  for( i = 0; i < nvars; ++i )
5583  {
5584  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5585  }
5586  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5587  }
5588 #endif
5589 
5590  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5591  */
5592  if( usegubs )
5593  {
5594  SCIP_GUBSET* gubset;
5595 
5596  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5597 
5598  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5599  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5600 
5601  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5602  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5603  assert(gubset->ngubconss <= nvars);
5604 
5605  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5606  * MODIFIED transformed separation problem and taking into account the following fixing:
5607  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5608  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5609  * if one exists
5610  */
5611  modtransused = TRUE;
5612  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5613  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5614 
5615  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5616 
5617  /* if x* is not fractional we stop the separation routine */
5618  if( !fractional )
5619  {
5620  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5621 
5622  /* frees memory for GUB set data structure */
5623  SCIP_CALL( GUBsetFree(scip, &gubset) );
5624 
5625  goto TERMINATE;
5626  }
5627 
5628  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5629  if( coverfound )
5630  {
5631  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5632  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5633  */
5634  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5635  &nnoncovervars, &coverweight, modtransused) );
5636 
5637  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5638  if( gubset->ngubconss < nvars )
5639  {
5640  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5641  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5642  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5643  }
5644  else
5645  {
5646  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5647  * GUB information
5648  */
5649  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5650  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5651  }
5652  }
5653 
5654  /* frees memory for GUB set data structure */
5655  SCIP_CALL( GUBsetFree(scip, &gubset) );
5656  }
5657  else
5658  {
5659  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5660  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5661  */
5662 
5663  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5664  * MODIFIED transformed separation problem and taking into account the following fixing:
5665  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5666  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5667  * if one exists
5668  */
5669  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5670  modtransused = TRUE;
5671  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5672  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5673  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5674 
5675  /* if x* is not fractional we stop the separation routine */
5676  if( !fractional )
5677  goto TERMINATE;
5678 
5679  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5680  if( coverfound )
5681  {
5682  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5683  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5684  */
5685  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5686  &nnoncovervars, &coverweight, modtransused) );
5687 
5688  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5689  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5690  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5691 
5692  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5693  {
5694  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5695  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5696  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5697  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5698  }
5699  }
5700  }
5701 
5702  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5703  if ( ! (*cutoff) )
5704  {
5705  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5706  * transformed separation problem and taking into account the following fixing:
5707  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5708  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5709  * if one exists
5710  */
5711  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5712  modtransused = FALSE;
5713  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5714  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5715  assert(fractional);
5716  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5717 
5718  /* if no cover was found we stop the separation routine */
5719  if( coverfound )
5720  {
5721  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5722  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5723  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5724  */
5725  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5726  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5727  }
5728  }
5729 
5730  TERMINATE:
5731  /* frees temporary memory */
5732  SCIPfreeBufferArray(scip, &noncovervars);
5733  SCIPfreeBufferArray(scip, &covervars);
5734  SCIPfreeBufferArray(scip, &solvals);
5735 
5736  return SCIP_OKAY;
5737 }
5738 
5739 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5741  SCIP* scip, /**< SCIP data structure */
5742  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5743  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5744  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5745  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5746  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5747  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5748  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5749  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5750  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5751  int* ncuts /**< pointer to add up the number of found cuts */
5752  )
5753 {
5754  SCIP_VAR** binvars;
5755  SCIP_VAR** consvars;
5756  SCIP_Real* binvals;
5757  SCIP_Longint* consvals;
5758  SCIP_Longint minact;
5759  SCIP_Longint maxact;
5760  SCIP_Real intscalar;
5761  SCIP_Bool success;
5762  int nbinvars;
5763  int nconsvars;
5764  int i;
5765 
5766  int* tmpindices;
5767  int tmp;
5768  SCIP_CONSHDLR* conshdlr;
5769  SCIP_CONSHDLRDATA* conshdlrdata;
5770  SCIP_Bool noknapsackconshdlr;
5771  SCIP_Bool usegubs;
5772 
5773  assert(nknapvars > 0);
5774  assert(knapvars != NULL);
5775  assert(cutoff != NULL);
5776 
5777  tmpindices = NULL;
5778 
5779  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5780  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5781 
5782  binvars = SCIPgetVars(scip);
5783 
5784  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5785  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5786 
5787  *cutoff = FALSE;
5788 
5789  if( nbinvars == 0 )
5790  return SCIP_OKAY;
5791 
5792  /* set up data structures */
5793  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5794  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5795 
5796  /* get conshdlrdata to use cleared memory */
5797  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5798  if( conshdlr == NULL )
5799  {
5800  noknapsackconshdlr = TRUE;
5801  usegubs = DEFAULT_USEGUBS;
5802 
5803  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5804  BMSclearMemoryArray(binvals, nbinvars);
5805  }
5806  else
5807  {
5808  noknapsackconshdlr = FALSE;
5809  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5810  assert(conshdlrdata != NULL);
5811  usegubs = conshdlrdata->usegubs;
5812 
5813  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5814 
5815  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5816  * change their types to SCIP_VARTYPE_BINARY during presolving
5817  */
5818  if( conshdlrdata->reals1size == 0 )
5819  {
5820  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5821  conshdlrdata->reals1size = 1;
5822  conshdlrdata->reals1[0] = 0.0;
5823  }
5824 
5825  assert(conshdlrdata->reals1size > 0);
5826 
5827  /* next if condition should normally not be true, because it means that presolving has created more binary
5828  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5829  * transform all integers into their binary representation then it maybe happens
5830  */
5831  if( conshdlrdata->reals1size < nbinvars )
5832  {
5833  int oldsize = conshdlrdata->reals1size;
5834 
5835  conshdlrdata->reals1size = nbinvars;
5836  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5837  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5838  }
5839  binvals = conshdlrdata->reals1;
5840 
5841  /* check for cleared array, all entries have to be zero */
5842 #ifndef NDEBUG
5843  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5844  {
5845  assert(binvals[tmp] == 0);
5846  }
5847 #endif
5848  }
5849 
5850  tmp = 0;
5851 
5852  /* relax continuous knapsack constraint:
5853  * 1. make all variables binary:
5854  * if x_j is continuous or integer variable substitute:
5855  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5856  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5857  * 2. convert coefficients of all variables to positive integers:
5858  * - scale all coefficients a_j to a~_j integral
5859  * - substitute x~_j = 1 - x_j if a~_j < 0
5860  */
5861 
5862  /* replace integer and continuous variables with binary variables */
5863  for( i = 0; i < nknapvars; i++ )
5864  {
5865  SCIP_VAR* var;
5866 
5867  var = knapvars[i];
5868 
5869  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5870  {
5871  SCIP_Real solval;
5872  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5873 
5874  solval = SCIPgetSolVal(scip, sol, var);
5875 
5876  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5877  if( SCIPisFeasLT(scip, solval, 0.0 )
5878  || SCIPisFeasGT(scip, solval, 1.0) )
5879  {
5880  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5881  solval, SCIPvarGetName(var));
5882  goto TERMINATE;
5883  }
5884 
5885  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5886  if( !noknapsackconshdlr )
5887  {
5888  assert(tmpindices != NULL);
5889 
5890  tmpindices[tmp] = SCIPvarGetProbindex(var);
5891  ++tmp;
5892  }
5893  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5894  }
5895  else if( valscale * knapvals[i] > 0.0 )
5896  {
5897  SCIP_VAR** zvlb;
5898  SCIP_Real* bvlb;
5899  SCIP_Real* dvlb;
5900  SCIP_Real bestlbsol;
5901  int bestlbtype;
5902  int nvlb;
5903  int j;
5904 
5905  /* a_j > 0: substitution with lb or vlb */
5906  nvlb = SCIPvarGetNVlbs(var);
5907  zvlb = SCIPvarGetVlbVars(var);
5908  bvlb = SCIPvarGetVlbCoefs(var);
5909  dvlb = SCIPvarGetVlbConstants(var);
5910 
5911  /* search for lb or vlb with maximal bound value */
5912  bestlbsol = SCIPvarGetLbGlobal(var);
5913  bestlbtype = -1;
5914  for( j = 0; j < nvlb; j++ )
5915  {
5916  /* use only numerical stable vlb with binary variable z */
5917  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5918  {
5919  SCIP_Real vlbsol;
5920 
5921  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5922  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5923  {
5924  *cutoff = TRUE;
5925  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5927  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5928  goto TERMINATE;
5929  }
5930 
5931  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5932  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5933  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5934  {
5935  bestlbsol = vlbsol;
5936  bestlbtype = j;
5937  }
5938  }
5939  }
5940 
5941  /* if no lb or vlb with binary variable was found, we have to abort */
5942  if( SCIPisInfinity(scip, -bestlbsol) )
5943  goto TERMINATE;
5944 
5945  if( bestlbtype == -1 )
5946  {
5947  rhs -= valscale * knapvals[i] * bestlbsol;
5948  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5949  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5950  }
5951  else
5952  {
5953  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5954  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5955  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5956 
5957  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5958  goto TERMINATE;
5959 
5960  if( !noknapsackconshdlr )
5961  {
5962  assert(tmpindices != NULL);
5963 
5964  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5965  ++tmp;
5966  }
5967  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5968  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5969  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5970  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5971  }
5972  }
5973  else
5974  {
5975  SCIP_VAR** zvub;
5976  SCIP_Real* bvub;
5977  SCIP_Real* dvub;
5978  SCIP_Real bestubsol;
5979  int bestubtype;
5980  int nvub;
5981  int j;
5982 
5983  assert(valscale * knapvals[i] < 0.0);
5984 
5985  /* a_j < 0: substitution with ub or vub */
5986  nvub = SCIPvarGetNVubs(var);
5987  zvub = SCIPvarGetVubVars(var);
5988  bvub = SCIPvarGetVubCoefs(var);
5989  dvub = SCIPvarGetVubConstants(var);
5990 
5991  /* search for ub or vub with minimal bound value */
5992  bestubsol = SCIPvarGetUbGlobal(var);
5993  bestubtype = -1;
5994  for( j = 0; j < nvub; j++ )
5995  {
5996  /* use only numerical stable vub with active binary variable z */
5997  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
5998  {
5999  SCIP_Real vubsol;
6000 
6001  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6002  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6003  {
6004  *cutoff = TRUE;
6005  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6007  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6008  goto TERMINATE;
6009  }
6010 
6011  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6012  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6013  if( SCIPisLE(scip, vubsol, bestubsol) )
6014  {
6015  bestubsol = vubsol;
6016  bestubtype = j;
6017  }
6018  }
6019  }
6020 
6021  /* if no ub or vub with binary variable was found, we have to abort */
6022  if( SCIPisInfinity(scip, bestubsol) )
6023  goto TERMINATE;
6024 
6025  if( bestubtype == -1 )
6026  {
6027  rhs -= valscale * knapvals[i] * bestubsol;
6028  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6029  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6030  }
6031  else
6032  {
6033  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6034  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6035  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6036 
6037  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6038  goto TERMINATE;
6039 
6040  if( !noknapsackconshdlr )
6041  {
6042  assert(tmpindices != NULL);
6043 
6044  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6045  ++tmp;
6046  }
6047  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6048  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6049  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6050  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6051  }
6052  }
6053  }
6054 
6055  /* convert coefficients of all (now binary) variables to positive integers:
6056  * - make all coefficients integral
6057  * - make all coefficients positive (substitute negated variable)
6058  */
6059  nconsvars = 0;
6060 
6061  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6062  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6063  */
6065  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6066  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6067 
6068  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6069  if( !success )
6070  intscalar = 1.0;
6071 
6072  /* make all coefficients integral and positive:
6073  * - scale a~_j = a_j * intscalar
6074  * - substitute x~_j = 1 - x_j if a~_j < 0
6075  */
6076  rhs = rhs*intscalar;
6077 
6078  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6079  minact = 0;
6080  maxact = 0;
6081  for( i = 0; i < nbinvars; i++ )
6082  {
6083  SCIP_VAR* var;
6084  SCIP_Longint val;
6085 
6086  val = (SCIP_Longint)SCIPfloor(scip, binvals[i]*intscalar);
6087  if( val == 0 )
6088  continue;
6089 
6090  if( val > 0 )
6091  {
6092  var = binvars[i];
6093  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6094  val, SCIPvarGetName(var), binvals[i], rhs);
6095  }
6096  else
6097  {
6098  assert(val < 0);
6099 
6100  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6101  val = -val;
6102  rhs += val;
6103  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6104  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6105  }
6106 
6107  if( SCIPvarGetLbLocal(var) > 0.5 )
6108  minact += val;
6109  if( SCIPvarGetUbLocal(var) > 0.5 )
6110  maxact += val;
6111  consvals[nconsvars] = val;
6112  consvars[nconsvars] = var;
6113  nconsvars++;
6114  }
6115 
6116  if( nconsvars > 0 )
6117  {
6118  SCIP_Longint capacity;
6119 
6120  assert(consvars != NULL);
6121  assert(consvals != NULL);
6122  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6123 
6124 #ifdef SCIP_DEBUG
6125  {
6126  SCIP_Real act;
6127 
6128  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6129  act = 0.0;
6130  for( i = 0; i < nconsvars; ++i )
6131  {
6132  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6133  SCIPgetSolVal(scip, sol, consvars[i]));
6134  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6135  }
6136  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6137  capacity, rhs, act, minact, maxact);
6138  }
6139 #endif
6140 
6141  if( minact > capacity )
6142  {
6143  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6144  *cutoff = TRUE;
6145  goto TERMINATE;
6146  }
6147 
6148  if( maxact > capacity )
6149  {
6150  /* separate lifted cut from relaxed knapsack constraint */
6151  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6152  }
6153  }
6154 
6155  TERMINATE:
6156  /* free data structures */
6157  if( noknapsackconshdlr)
6158  {
6159  SCIPfreeBufferArray(scip, &binvals);
6160  }
6161  else
6162  {
6163  /* clear binvals */
6164  for( --tmp; tmp >= 0; --tmp)
6165  {
6166  assert(tmpindices != NULL);
6167  binvals[tmpindices[tmp]] = 0;
6168  }
6169  SCIPfreeBufferArray(scip, &tmpindices);
6170  }
6171  SCIPfreeBufferArray(scip, &consvals);
6172  SCIPfreeBufferArray(scip, &consvars);
6173 
6174  return SCIP_OKAY;
6175 }
6176 
6177 /** separates given knapsack constraint */
6178 static
6180  SCIP* scip, /**< SCIP data structure */
6181  SCIP_CONS* cons, /**< knapsack constraint */
6182  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6183  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6184  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6185  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6186  int* ncuts /**< pointer to add up the number of found cuts */
6187  )
6188 {
6189  SCIP_CONSDATA* consdata;
6190  SCIP_Bool violated;
6191 
6192  assert(ncuts != NULL);
6193  assert(cutoff != NULL);
6194  *cutoff = FALSE;
6195 
6196  consdata = SCIPconsGetData(cons);
6197  assert(consdata != NULL);
6198 
6199  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6200 
6201  /* check knapsack constraint itself for feasibility */
6202  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6203 
6204  if( violated )
6205  {
6206  /* add knapsack constraint as LP row to the LP */
6207  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6208  (*ncuts)++;
6209  }
6210  else if( sepacuts )
6211  {
6212  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6213  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6214  }
6215 
6216  return SCIP_OKAY;
6217 }
6218 
6219 /** adds coefficient to constraint data */
6220 static
6222  SCIP* scip, /**< SCIP data structure */
6223  SCIP_CONS* cons, /**< knapsack constraint */
6224  SCIP_VAR* var, /**< variable to add to knapsack */
6225  SCIP_Longint weight /**< weight of variable in knapsack */
6226  )
6227 {
6228  SCIP_CONSDATA* consdata;
6230  consdata = SCIPconsGetData(cons);
6231  assert(consdata != NULL);
6232  assert(SCIPvarIsBinary(var));
6233  assert(weight > 0);
6234 
6235  /* add the new coefficient to the LP row */
6236  if( consdata->row != NULL )
6237  {
6238  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6239  }
6240 
6241  /* check for fixed variable */
6242  if( SCIPvarGetLbGlobal(var) > 0.5 )
6243  {
6244  /* variable is fixed to one: reduce capacity */
6245  consdata->capacity -= weight;
6246  }
6247  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6248  {
6249  SCIP_Bool negated;
6250 
6251  /* get binary representative of variable */
6252  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6253 
6254  /* insert coefficient */
6255  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6256  consdata->vars[consdata->nvars] = var;
6257  consdata->weights[consdata->nvars] = weight;
6258  consdata->nvars++;
6259 
6260  /* capture variable */
6261  SCIP_CALL( SCIPcaptureVar(scip, var) );
6262 
6263  /* install the rounding locks of variable */
6264  SCIP_CALL( lockRounding(scip, cons, var) );
6265 
6266  /* catch events */
6267  if( SCIPconsIsTransformed(cons) )
6268  {
6269  SCIP_CONSHDLRDATA* conshdlrdata;
6270 
6271  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6272  assert(conshdlrdata != NULL);
6273  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6275  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6276  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6277 
6278  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6279  consdata->existmultaggr = TRUE;
6280 
6281  /* mark constraint to be propagated and presolved */
6282  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6283  consdata->presolvedtiming = 0;
6284  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6285  }
6286 
6287  /* update weight sums */
6288  updateWeightSums(consdata, var, weight);
6289 
6290  consdata->sorted = FALSE;
6291  consdata->cliquepartitioned = FALSE;
6292  consdata->negcliquepartitioned = FALSE;
6293  consdata->merged = FALSE;
6294  }
6295 
6296  return SCIP_OKAY;
6297 }
6298 
6299 /** deletes coefficient at given position from constraint data */
6300 static
6302  SCIP* scip, /**< SCIP data structure */
6303  SCIP_CONS* cons, /**< knapsack constraint */
6304  int pos /**< position of coefficient to delete */
6305  )
6306 {
6307  SCIP_CONSDATA* consdata;
6308  SCIP_VAR* var;
6310  consdata = SCIPconsGetData(cons);
6311  assert(consdata != NULL);
6312  assert(0 <= pos && pos < consdata->nvars);
6313 
6314  var = consdata->vars[pos];
6315  assert(var != NULL);
6316  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6317 
6318  /* delete the coefficient from the LP row */
6319  if( consdata->row != NULL )
6320  {
6321  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6322  }
6323 
6324  /* remove the rounding locks of variable */
6325  SCIP_CALL( unlockRounding(scip, cons, var) );
6326 
6327  /* drop events and mark constraint to be propagated and presolved */
6328  if( SCIPconsIsTransformed(cons) )
6329  {
6330  SCIP_CONSHDLRDATA* conshdlrdata;
6331 
6332  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6333  assert(conshdlrdata != NULL);
6335  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6336  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6337 
6338  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6339  consdata->presolvedtiming = 0;
6340  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6341  }
6342 
6343  /* decrease weight sums */
6344  updateWeightSums(consdata, var, -consdata->weights[pos]);
6345 
6346  /* move the last variable to the free slot */
6347  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6348  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6349  if( consdata->eventdata != NULL )
6350  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6351 
6352  /* release variable */
6353  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6354 
6355  /* try to use old clique partitions */
6356  if( consdata->cliquepartitioned )
6357  {
6358  assert(consdata->cliquepartition != NULL);
6359  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6360  * change the clique number */
6361  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6362  {
6363  int oldcliqenum;
6364 
6365  oldcliqenum = consdata->cliquepartition[pos];
6366  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6367 
6368  /* the following if and else cases assure that we have increasing clique numbers */
6369  if( consdata->cliquepartition[pos] > pos )
6370  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6371  else
6372  {
6373  int i;
6374  int cliquenumbefore;
6375 
6376  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6377  * occurs the same as the old one is still in the cliquepartition */
6378  if( oldcliqenum > consdata->cliquepartition[pos] )
6379  {
6380  for( i = 0; i < consdata->nvars; ++i )
6381  if( oldcliqenum == consdata->cliquepartition[i] )
6382  break;
6383  else if( oldcliqenum < consdata->cliquepartition[i] )
6384  {
6385  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6386  break;
6387  }
6388  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6389  * the biggest index, so decrease the number of cliques
6390  */
6391  if( i == consdata->nvars )
6392  --(consdata->ncliques);
6393  }
6394  /* if the old clique number was smaller than the new one we have to check the front for an element with
6395  * clique number minus 1 */
6396  else if( oldcliqenum < consdata->cliquepartition[pos] )
6397  {
6398  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6399  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6400 
6401  if( i < cliquenumbefore )
6402  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6403  }
6404  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6405  else if( pos == consdata->nvars - 1)
6406  {
6407  cliquenumbefore = consdata->cliquepartition[pos];
6408  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6409 
6410  if( i < cliquenumbefore )
6411  --(consdata->ncliques);
6412  }
6413  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6414  }
6415  }
6416  else
6417  --(consdata->ncliques);
6418  }
6419 
6420  if( consdata->negcliquepartitioned )
6421  {
6422  assert(consdata->negcliquepartition != NULL);
6423  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6424  * change the clique number */
6425  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6426  {
6427  int oldcliqenum;
6428 
6429  oldcliqenum = consdata->negcliquepartition[pos];
6430  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6431 
6432  /* the following if and else cases assure that we have increasing clique numbers */
6433  if( consdata->negcliquepartition[pos] > pos )
6434  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6435  else
6436  {
6437  int i;
6438  int cliquenumbefore;
6439 
6440  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6441  * occurs, the same as the old one occurs */
6442  if( oldcliqenum > consdata->negcliquepartition[pos] )
6443  {
6444  for( i = 0; i < consdata->nvars; ++i )
6445  if( oldcliqenum == consdata->negcliquepartition[i] )
6446  break;
6447  else if( oldcliqenum < consdata->negcliquepartition[i] )
6448  {
6449  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6450  break;
6451  }
6452  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6453  * the biggest index, so decrease the number of negated cliques
6454  */
6455  if( i == consdata->nvars )
6456  --(consdata->nnegcliques);
6457  }
6458  /* if the old clique number was smaller than the new one we have to check the front for an element with
6459  * clique number minus 1 */
6460  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6461  {
6462  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6463  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6464 
6465  if( i < cliquenumbefore )
6466  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6467  }
6468  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6469  else if( pos == consdata->nvars - 1)
6470  {
6471  cliquenumbefore = consdata->negcliquepartition[pos];
6472  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6473 
6474  if( i < cliquenumbefore )
6475  --(consdata->nnegcliques);
6476  }
6477  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6478  }
6479  }
6480  else
6481  --(consdata->nnegcliques);
6482  }
6483 
6484  --(consdata->nvars);
6485 
6486  return SCIP_OKAY;
6487 }
6488 
6489 /** removes all items with weight zero from knapsack constraint */
6490 static
6492  SCIP* scip, /**< SCIP data structure */
6493  SCIP_CONS* cons /**< knapsack constraint */
6494  )
6495 {
6496  SCIP_CONSDATA* consdata;
6497  int v;
6498 
6499  consdata = SCIPconsGetData(cons);
6500  assert(consdata != NULL);
6501 
6502  for( v = consdata->nvars-1; v >= 0; --v )
6503  {
6504  if( consdata->weights[v] == 0 )
6505  {
6506  SCIP_CALL( delCoefPos(scip, cons, v) );
6507  }
6508  }
6509 
6510  return SCIP_OKAY;
6511 }
6512 
6513 /* perform deletion of variables in all constraints of the constraint handler */
6514 static
6516  SCIP* scip, /**< SCIP data structure */
6517  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6518  SCIP_CONS** conss, /**< array of constraints */
6519  int nconss /**< number of constraints */
6520  )
6521 {
6522  SCIP_CONSDATA* consdata;
6523  int i;
6524  int v;
6525 
6526  assert(scip != NULL);
6527  assert(conshdlr != NULL);
6528  assert(conss != NULL);
6529  assert(nconss >= 0);
6530  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6531 
6532  /* iterate over all constraints */
6533  for( i = 0; i < nconss; i++ )
6534  {
6535  consdata = SCIPconsGetData(conss[i]);
6536 
6537  /* constraint is marked, that some of its variables were deleted */
6538  if( consdata->varsdeleted )
6539  {
6540  /* iterate over all variables of the constraint and delete them from the constraint */
6541  for( v = consdata->nvars - 1; v >= 0; --v )
6542  {
6543  if( SCIPvarIsDeleted(consdata->vars[v]) )
6544  {
6545  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6546  }
6547  }
6548  consdata->varsdeleted = FALSE;
6549  }
6550  }
6551 
6552  return SCIP_OKAY;
6553 }
6554 
6555 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6556 static
6558  SCIP* scip, /**< SCIP data structure */
6559  SCIP_CONS* cons, /**< knapsack constraint */
6560  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6561  )
6562 {
6563  SCIP_CONSDATA* consdata;
6564  int v;
6565  int prev;
6566 
6567  assert(scip != NULL);
6568  assert(cons != NULL);
6569  assert(cutoff != NULL);
6570 
6571  consdata = SCIPconsGetData(cons);
6572  assert(consdata != NULL);
6573 
6574  *cutoff = FALSE;
6575 
6576  if( consdata->merged )
6577  return SCIP_OKAY;
6578 
6579  if( consdata->nvars <= 1 )
6580  {
6581  consdata->merged = TRUE;
6582  return SCIP_OKAY;
6583  }
6584 
6585  assert(consdata->vars != NULL || consdata->nvars == 0);
6586 
6587  /* sorting array after indices of variables, that's only for faster merging */
6588  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6589  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6590 
6591  /* knapsack-sorting (decreasing weights) now lost */
6592  consdata->sorted = FALSE;
6593 
6594  v = consdata->nvars - 1;
6595  prev = v - 1;
6596  /* loop backwards through the items: deletion only affects rear items */
6597  while( prev >= 0 )
6598  {
6599  SCIP_VAR* var1;
6600  SCIP_VAR* var2;
6601  SCIP_Bool negated1;
6602  SCIP_Bool negated2;
6603 
6604  negated1 = FALSE;
6605  negated2 = FALSE;
6606 
6607  var1 = consdata->vars[v];
6608  assert(SCIPvarIsBinary(var1));
6609  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6611  {
6612  var1 = SCIPvarGetNegatedVar(var1);
6613  negated1 = TRUE;
6614  }
6615  assert(var1 != NULL);
6616 
6617  var2 = consdata->vars[prev];
6618  assert(SCIPvarIsBinary(var2));
6619  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6621  {
6622  var2 = SCIPvarGetNegatedVar(var2);
6623  negated2 = TRUE;
6624  }
6625  assert(var2 != NULL);
6626 
6627  if( var1 == var2 )
6628  {
6629  /* both variables are either active or negated */
6630  if( negated1 == negated2 )
6631  {
6632  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6633  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6634  SCIP_CALL( delCoefPos(scip, cons, v) );
6635  }
6636  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6637  * and delete item of smaller weight
6638  */
6639  else if( consdata->weights[v] == consdata->weights[prev] )
6640  {
6641  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6642  consdata->capacity -= consdata->weights[v];
6643  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6644  SCIP_CALL( delCoefPos(scip, cons, prev) );
6645 
6646  --prev;
6647  }
6648  else if( consdata->weights[v] < consdata->weights[prev] )
6649  {
6650  consdata->capacity -= consdata->weights[v];
6651  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6652  assert(consdata->weights[prev] > 0);
6653  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6654  }
6655  else
6656  {
6657  consdata->capacity -= consdata->weights[prev];
6658  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6659  assert(consdata->weights[v] > 0);
6660  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6661  /* restore order iff necessary */
6662  if( consdata->nvars != v ) /* otherwise the order still stands */
6663  {
6664  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6665  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6666  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6667  --prev;
6668  else /* we need to let v at the same position*/
6669  {
6670  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6671  /* don't decrease v, the same variable may exist up front */
6672  --prev;
6673  continue;
6674  }
6675  }
6676  }
6677  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6678  }
6679  v = prev;
6680  --prev;
6681  }
6682 
6683  consdata->merged = TRUE;
6684 
6685  /* check infeasibility */
6686  if( consdata->onesweightsum > consdata->capacity )
6687  {
6688  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6689  *cutoff = TRUE;
6690  return SCIP_OKAY;
6691  }
6692 
6693  return SCIP_OKAY;
6694 }
6695 
6696 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6697  * fixings (dual reductions)
6698  */
6699 static
6701  SCIP* scip, /**< SCIP data structure */
6702  SCIP_CONS* cons, /**< knapsack constraint */
6703  int* nfixedvars, /**< pointer to count number of fixings */
6704  int* ndelconss, /**< pointer to count number of deleted constraints */
6705  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6706  )
6707 {
6708  SCIP_CONSDATA* consdata;
6709  SCIP_VAR** vars;
6710  SCIP_Real* profits;
6711  int* solitems;
6712  int* nonsolitems;
6713  int* items;
6714  SCIP_Real solval;
6715  SCIP_Bool infeasible;
6716  SCIP_Bool tightened;
6717  SCIP_Bool applicable;
6718  int nsolitems;
6719  int nnonsolitems;
6720  int nvars;
6721  int v;
6722 
6723  assert(!SCIPconsIsModifiable(cons));
6724 
6725  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6726  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6727  * added to the problems have the check flag set to FALSE
6728  */
6729  if( !SCIPconsIsChecked(cons) )
6730  return SCIP_OKAY;
6731 
6732  consdata = SCIPconsGetData(cons);
6733  assert(consdata != NULL);
6734 
6735  nvars = consdata->nvars;
6736  vars = consdata->vars;
6737 
6738  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6739  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6740  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6741  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6742 
6743  applicable = TRUE;
6744 
6745  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6746  * collect object values which are the profits of the knapsack problem
6747  */
6748  for( v = 0; v < nvars; ++v )
6749  {
6750  SCIP_VAR* var;
6751  SCIP_Bool negated;
6752 
6753  var = vars[v];
6754  assert(var != NULL);
6755 
6756  /* the variable should not be (globally) fixed */
6757  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6758 
6761  {
6762  applicable = FALSE;
6763  break;
6764  }
6765 
6766  negated = FALSE;
6767 
6768  /* get the active variable */
6769  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6770  assert(SCIPvarIsActive(var));
6771 
6772  if( negated )
6773  profits[v] = SCIPvarGetObj(var);
6774  else
6775  profits[v] = -SCIPvarGetObj(var);
6776 
6777  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6778  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6779  items[v] = v;
6780  }
6781 
6782  if( applicable )
6783  {
6784  SCIP_Bool success;
6785 
6786  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6787  SCIPdebugPrintCons(scip, cons, NULL);
6788 
6789  /* solve knapsack problem exactly */
6790  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6791  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6792 
6793  if( success )
6794  {
6795  SCIP_VAR* var;
6796 
6797  /* apply solution of the knapsack as dual reductions */
6798  for( v = 0; v < nsolitems; ++v )
6799  {
6800  var = vars[solitems[v]];
6801  assert(var != NULL);
6802 
6803  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6805  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6806  assert(!infeasible);
6807  assert(tightened);
6808  (*nfixedvars)++;
6809  }
6810 
6811  for( v = 0; v < nnonsolitems; ++v )
6812  {
6813  var = vars[nonsolitems[v]];
6814  assert(var != NULL);
6815 
6816  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6818  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6819  assert(!infeasible);
6820  assert(tightened);
6821  (*nfixedvars)++;
6822  }
6823 
6824  SCIP_CALL( SCIPdelCons(scip, cons) );
6825  (*ndelconss)++;
6826  (*deleted) = TRUE;
6827  }
6828  }
6829 
6830  SCIPfreeBufferArray(scip, &nonsolitems);
6831  SCIPfreeBufferArray(scip, &solitems);
6832  SCIPfreeBufferArray(scip, &items);
6833  SCIPfreeBufferArray(scip, &profits);
6834 
6835  return SCIP_OKAY;
6836 }
6837 
6838 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6839  * constraint enters the LP by setting the initial and separated flag to FALSE
6840  */
6841 static
6843  SCIP* scip, /**< SCIP data structure */
6844  SCIP_CONS* cons, /**< knapsack constraint */
6845  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6846  )
6847 {
6848  SCIP_CONSDATA* consdata;
6849  SCIP_VAR** vars;
6850  SCIP_VAR* var;
6851  SCIP_Real offset;
6852  SCIP_Real scale;
6853  SCIP_Real objval;
6854  SCIP_Bool applicable;
6855  SCIP_Bool negated;
6856  int nobjvars;
6857  int nvars;
6858  int v;
6859 
6860  assert(scip != NULL);
6861  assert(cons != NULL);
6862  assert(conshdlrdata != NULL);
6863 
6864  consdata = SCIPconsGetData(cons);
6865  assert(consdata != NULL);
6866 
6867  nvars = consdata->nvars;
6868  nobjvars = SCIPgetNObjVars(scip);
6869 
6870  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6871  * and/or separated flag is set to FALSE
6872  */
6873  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6874  return SCIP_OKAY;
6875 
6876  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6877  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6878  */
6879  if( nobjvars == 0 )
6880  return SCIP_OKAY;
6881 
6882  vars = consdata->vars;
6883  assert(vars != NULL);
6884 
6885  applicable = TRUE;
6886  offset = 0.0;
6887  scale = 1.0;
6888 
6889  for( v = 0; v < nvars && applicable; ++v )
6890  {
6891  negated = FALSE;
6892  var = vars[v];
6893  assert(var != NULL);
6894 
6895  if( SCIPvarIsNegated(var) )
6896  {
6897  negated = TRUE;
6898  var = SCIPvarGetNegatedVar(var);
6899  assert(var != NULL);
6900  }
6901 
6902  objval = SCIPvarGetObj(var);
6903 
6904  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6905  if( SCIPisZero(scip, objval) )
6906  applicable = FALSE;
6907  else
6908  {
6909  SCIP_Real weight;
6910 
6911  weight = (SCIP_Real)consdata->weights[v];
6912 
6913  if( negated )
6914  {
6915  if( v == 0 )
6916  {
6917  /* the first variable defines the scale */
6918  scale = weight / -objval;
6919 
6920  offset += weight;
6921  }
6922  else if( SCIPisEQ(scip, -objval * scale, weight) )
6923  offset += weight;
6924  else
6925  applicable = FALSE;
6926  }
6927  else if( v == 0 )
6928  {
6929  /* the first variable define the scale */
6930  scale = weight / objval;
6931  }
6932  else if( !SCIPisEQ(scip, objval * scale, weight) )
6933  applicable = FALSE;
6934  }
6935  }
6936 
6937  if( applicable )
6938  {
6939  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6940  {
6941  SCIP_Real cutoffbound;
6942 
6943  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6944  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6945  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6946 
6947  cutoffbound = (consdata->capacity - offset) / scale;
6948 
6949  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6950  * still excepted
6951  */
6952  cutoffbound += SCIPcutoffbounddelta(scip);
6953 
6954  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6955  SCIPconsGetName(cons), cutoffbound);
6956 
6957  if( cutoffbound < SCIPgetCutoffbound(scip) )
6958  {
6959  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6960 
6961  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6962  }
6963  else
6964  {
6965  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6966  * propagation
6967  */
6968  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6969  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6970  }
6971  }
6972  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6973  {
6974  SCIP_Real lowerbound;
6975 
6976  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6977  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6978  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6979 
6980  lowerbound = (consdata->capacity - offset) / scale;
6981 
6982  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6983  SCIPconsGetName(cons), lowerbound);
6984 
6985  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6986  }
6987  }
6988 
6989  return SCIP_OKAY;
6990 }
6991 
6992 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6993  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
6994 static
6996  SCIP* scip, /**< SCIP data structure */
6997  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
6998  SCIP_VAR** vars, /**< array for sorted variables */
6999  SCIP_Longint* weights, /**< array for sorted weights */
7000  int* cliquestartposs, /**< starting position array for each clique */
7001  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7002  )
7003 {
7004  SCIP_VAR** origvars;
7005  int norigvars;
7006  SCIP_Longint* origweights;
7007  int* cliquepartition;
7008  int ncliques;
7009 
7010  SCIP_VAR*** varpointers;
7011  SCIP_Longint** weightpointers;
7012  int* cliquecount;
7013 
7014  int nextpos;
7015  int c;
7016  int v;
7017 
7018  assert(scip != NULL);
7019  assert(consdata != NULL);
7020  assert(vars != NULL);
7021  assert(weights != NULL);
7022  assert(cliquestartposs != NULL);
7023 
7024  origweights = consdata->weights;
7025  origvars = consdata->vars;
7026  norigvars = consdata->nvars;
7027 
7028  assert(origvars != NULL || norigvars == 0);
7029  assert(origweights != NULL || norigvars == 0);
7030 
7031  if( norigvars == 0 )
7032  return SCIP_OKAY;
7033 
7034  if( usenegatedclique )
7035  {
7036  assert(consdata->negcliquepartitioned);
7037 
7038  cliquepartition = consdata->negcliquepartition;
7039  ncliques = consdata->nnegcliques;
7040  }
7041  else
7042  {
7043  assert(consdata->cliquepartitioned);
7044 
7045  cliquepartition = consdata->cliquepartition;
7046  ncliques = consdata->ncliques;
7047  }
7048 
7049  assert(cliquepartition != NULL);
7050  assert(ncliques > 0);
7051 
7052  /* we first count all clique items and alloc temporary memory for a bucket sort */
7053  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7054  BMSclearMemoryArray(cliquecount, ncliques);
7055 
7056  /* first we count for each clique the number of elements */
7057  for( v = norigvars - 1; v >= 0; --v )
7058  {
7059  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7060  ++(cliquecount[cliquepartition[v]]);
7061  }
7062 
7063  /*@todo: maybe it is better to put largest cliques up front */
7064 
7065 #ifndef NDEBUG
7066  BMSclearMemoryArray(vars, norigvars);
7067  BMSclearMemoryArray(weights, norigvars);
7068 #endif
7069  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7070  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7071 
7072  nextpos = 0;
7073  /* now we initialize all start pointers for each clique, so they will be ordered */
7074  for( c = 0; c < ncliques; ++c )
7075  {
7076  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7077  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7078  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7079  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7080  * vars[7]
7081  *
7082  */
7083  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7084  cliquestartposs[c] = nextpos;
7085  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7086  assert(cliquecount[c] > 0);
7087  nextpos += cliquecount[c];
7088  assert(nextpos > 0);
7089  }
7090  assert(nextpos == norigvars);
7091  cliquestartposs[c] = nextpos;
7092 
7093  /* now we copy all variable and weights to the right order */
7094  for( v = 0; v < norigvars; ++v )
7095  {
7096  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7097  ++(varpointers[cliquepartition[v]]);
7098  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7099  ++(weightpointers[cliquepartition[v]]);
7100  }
7101 #ifndef NDEBUG
7102  for( v = 0; v < norigvars; ++v )
7103  {
7104  assert(vars[v] != NULL);
7105  assert(weights[v] > 0);
7106  }
7107 #endif
7108 
7109  /* free temporary memory */
7110  SCIPfreeBufferArray(scip, &weightpointers);
7111  SCIPfreeBufferArray(scip, &varpointers);
7112  SCIPfreeBufferArray(scip, &cliquecount);
7113 
7114  return SCIP_OKAY;
7115 }
7116 
7117 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7118 static
7120  SCIP* scip, /**< SCIP data structure */
7121  SCIP_CONS* cons, /**< knapsack constraint */
7122  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7123  * information is not needed; in this case, we apply all fixings
7124  * instead of stopping after the first infeasible one */
7125  )
7126 {
7127  SCIP_CONSDATA* consdata;
7128  int v;
7129 
7130  assert(scip != NULL);
7131  assert(cons != NULL);
7132 
7133  consdata = SCIPconsGetData(cons);
7134  assert(consdata != NULL);
7135  assert(consdata->nvars == 0 || consdata->vars != NULL);
7136 
7137  if( cutoff != NULL )
7138  *cutoff = FALSE;
7139 
7140  SCIPdebugMsg(scip, "apply fixings:\n");
7141  SCIPdebugPrintCons(scip, cons, NULL);
7142 
7143  /* check infeasibility */
7144  if ( consdata->onesweightsum > consdata->capacity )
7145  {
7146  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7147 
7148  if( cutoff != NULL )
7149  *cutoff = TRUE;
7150 
7151  return SCIP_OKAY;
7152  }
7153 
7154  /* all multi-aggregations should be resolved */
7155  consdata->existmultaggr = FALSE;
7156 
7157  v = 0;
7158  while( v < consdata->nvars )
7159  {
7160  SCIP_VAR* var;
7161 
7162  var = consdata->vars[v];
7163  assert(SCIPvarIsBinary(var));
7164 
7165  if( SCIPvarGetLbGlobal(var) > 0.5 )
7166  {
7167  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7168  consdata->capacity -= consdata->weights[v];
7169  SCIP_CALL( delCoefPos(scip, cons, v) );
7170  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7171  }
7172  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7173  {
7174  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7175  SCIP_CALL( delCoefPos(scip, cons, v) );
7176  }
7177  else
7178  {
7179  SCIP_VAR* repvar;
7180  SCIP_VAR* negvar;
7181  SCIP_VAR* workvar;
7182  SCIP_Longint weight;
7183  SCIP_Bool negated;
7184 
7185  weight = consdata->weights[v];
7186 
7187  /* get binary representative of variable */
7188  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7189  assert(repvar != NULL);
7190 
7191  /* check for multi-aggregation */
7192  if( SCIPvarIsNegated(repvar) )
7193  {
7194  workvar = SCIPvarGetNegatedVar(repvar);
7195  assert(workvar != NULL);
7196  negated = TRUE;
7197  }
7198  else
7199  {
7200  workvar = repvar;
7201  negated = FALSE;
7202  }
7203 
7204  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7205  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7206  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7207  *
7208  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7209  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7210  *
7211  * The explanation for the following block:
7212  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7213  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7214  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7215  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7216  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7217  * 2) For all replacement variable we check:
7218  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7219  * capacity -= weight * a_i caused by the negation of y_i.
7220  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7221  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7222  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7223  * weight in this case.
7224  */
7225  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7226  {
7227  SCIP_VAR** aggrvars;
7228  SCIP_Real* aggrscalars;
7229  SCIP_Real aggrconst;
7230  int naggrvars;
7231  int i;
7232 
7233  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7234  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7235  aggrvars = SCIPvarGetMultaggrVars(workvar);
7236  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7237  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7238  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7239 
7240  if( !SCIPisIntegral(scip, weight * aggrconst) )
7241  {
7242  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7243  return SCIP_ERROR;
7244  }
7245 
7246  /* if workvar was negated, we have to flip the weight */
7247  if( negated )
7248  weight *= -1;
7249 
7250  for( i = naggrvars - 1; i >= 0; --i )
7251  {
7252  assert(aggrvars != NULL);
7253  assert(aggrscalars != NULL);
7254 
7255  if( !SCIPvarIsBinary(aggrvars[i]) )
7256  {
7257  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary variable <%s>\n", aggrvars[i]);
7258  return SCIP_ERROR;
7259  }
7260  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7261  {
7262  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7263  return SCIP_ERROR;
7264  }
7265  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7266  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7267  {
7268  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7269  assert(negvar != NULL);
7270  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7271  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7272  }
7273  else
7274  {
7275  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7276  }
7277  }
7278  /* delete old coefficient */
7279  SCIP_CALL( delCoefPos(scip, cons, v) );
7280 
7281  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7282  if( negated )
7283  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7284  else
7285  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7286 
7287  if( consdata->capacity < 0 )
7288  {
7289  if( cutoff != NULL )
7290  {
7291  *cutoff = TRUE;
7292  break;
7293  }
7294  }
7295  }
7296  /* check, if the variable should be replaced with the representative */
7297  else if( repvar != var )
7298  {
7299  /* delete old (aggregated) variable */
7300  SCIP_CALL( delCoefPos(scip, cons, v) );
7301 
7302  /* add representative instead */
7303  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7304  }
7305  else
7306  ++v;
7307  }
7308  }
7309  assert(consdata->onesweightsum == 0);
7310 
7311  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7312  SCIPdebugPrintCons(scip, cons, NULL);
7313 
7314  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7315  * clean up the constraint
7316  */
7317  if( cutoff != NULL && !(*cutoff) )
7318  {
7319  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7320  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7321  SCIPdebugPrintCons(scip, cons, NULL);
7322  }
7323 
7324  return SCIP_OKAY;
7325 }
7326 
7327 
7328 /** propagation method for knapsack constraints */
7329 static
7331  SCIP* scip, /**< SCIP data structure */
7332  SCIP_CONS* cons, /**< knapsack constraint */
7333  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7334  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7335  int* nfixedvars, /**< pointer to count number of fixings */
7336  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7337  )
7339  SCIP_CONSDATA* consdata;
7340  SCIP_Bool infeasible;
7341  SCIP_Bool tightened;
7342  SCIP_Longint* secondmaxweights;
7343  SCIP_Longint minweightsum;
7344  SCIP_Longint residualcapacity;
7345 
7346  int nvars;
7347  int i;
7348  int nnegcliques;
7349 
7350  SCIP_VAR** myvars;
7351  SCIP_Longint* myweights;
7352  int* cliquestartposs;
7353  int* cliqueendposs;
7354  SCIP_Longint localminweightsum;
7355  SCIP_Bool foundmax;
7356  int c;
7357 
7358  assert(scip != NULL);
7359  assert(cons != NULL);
7360  assert(cutoff != NULL);
7361  assert(redundant != NULL);
7362  assert(nfixedvars != NULL);
7363 
7364  consdata = SCIPconsGetData(cons);
7365  assert(consdata != NULL);
7366 
7367  *cutoff = FALSE;
7368  *redundant = FALSE;
7369 
7370  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7371 
7372  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7373  if( !SCIPinRepropagation(scip) )
7374  {
7375  SCIP_CALL( SCIPincConsAge(scip, cons) );
7376  }
7377 
7378 #ifndef NDEBUG
7379  /* assert that only active or negated variables are present */
7380  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7381  {
7382  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7383  }
7384 #endif
7385 
7386  usenegatedclique = usenegatedclique && consdata->merged;
7387 
7388  /* init for debugging */
7389  myvars = NULL;
7390  myweights = NULL;
7391  cliquestartposs = NULL;
7392  secondmaxweights = NULL;
7393  minweightsum = 0;
7394  nvars = consdata->nvars;
7395  /* make sure, the items are sorted by non-increasing weight */
7396  sortItems(consdata);
7397 
7398  do
7399  {
7400  localminweightsum = 0;
7401 
7402  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7403  * a negated clique means, that at most one of the clique variables can be zero
7404  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7405  *
7406  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7407  * since replacing i with the element of maximal weight leads to infeasibility
7408  */
7409  if( usenegatedclique && nvars > 0 )
7410  {
7411  SCIP_CONSHDLRDATA* conshdlrdata;
7412  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7413  assert(conshdlrdata != NULL);
7414 
7415  /* compute clique partitions */
7416  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7417  nnegcliques = consdata->nnegcliques;
7418 
7419  /* if we have no real negated cliques we can stop here */
7420  if( nnegcliques == nvars )
7421  {
7422  /* run the standard algorithm that does not involve cliques */
7423  usenegatedclique = FALSE;
7424  break;
7425  }
7426 
7427  /* allocate temporary memory and initialize it */
7428  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7429  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7430  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7431  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7432  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7433  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7434 
7435  /* resort variables to avoid quadratic algorithm later on */
7436  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7437 
7438  /* save the end positions of the cliques because start positions are moved in the following loop */
7439  for( c = 0; c < nnegcliques; ++c )
7440  {
7441  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7442  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7443  }
7444 
7445  c = 0;
7446  foundmax = FALSE;
7447  i = 0;
7448 
7449  while( i < nvars )
7450  {
7451  /* ignore variables of the negated clique which are fixed to one since these are counted in
7452  * consdata->onesweightsum
7453  */
7454 
7455  /* if there are only one variable negated cliques left we can stop */
7456  if( nnegcliques - c == nvars - i )
7457  {
7458  minweightsum += localminweightsum;
7459  localminweightsum = 0;
7460  break;
7461  }
7462 
7463  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7464  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7465  * other clique variables to one
7466  */
7467  if( cliquestartposs[c] == i )
7468  {
7469  assert(myweights[i] > 0);
7470  ++c;
7471  minweightsum += localminweightsum;
7472  localminweightsum = 0;
7473  foundmax = TRUE;
7474 
7475  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7476  foundmax = FALSE;
7477 
7478  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7479  {
7480  ++i;
7481  continue;
7482  }
7483  }
7484 
7485  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7486  {
7487  assert(myweights[i] > 0);
7488 
7489  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7490  {
7491  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7492 
7493  if( !foundmax )
7494  {
7495  foundmax = TRUE;
7496 
7497  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7498  cliquestartposs[c - 1] = i;
7499  ++i;
7500 
7501  continue;
7502  }
7503  /* memorize second max weight for each clique */
7504  if( secondmaxweights[c - 1] == 0 )
7505  secondmaxweights[c - 1] = myweights[i];
7506 
7507  localminweightsum += myweights[i];
7508  }
7509  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7510  else
7511  {
7512  int v;
7513  /* fix all other variables of the negated clique to 1 */
7514  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7515  {
7516  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7517  {
7518  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7519  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7520 
7521  if( infeasible )
7522  {
7523  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7524 
7525  /* analyze the infeasibility if conflict analysis is applicable */
7527  {
7528  /* conflict analysis can only be applied in solving stage */
7529  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7530 
7531  /* initialize the conflict analysis */
7533 
7534  /* add the two variables which are fixed to zero within a negated clique */
7535  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7536  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7537 
7538  /* start the conflict analysis */
7539  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7540  }
7541  *cutoff = TRUE;
7542  break;
7543  }
7544  assert(tightened);
7545  ++(*nfixedvars);
7546  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7547  }
7548  }
7549  if( *cutoff )
7550  break;
7551 
7552  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7553  localminweightsum = 0;
7554  /* we can jump to the end of this clique */
7555  i = cliqueendposs[c - 1];
7556  }
7557  }
7558  ++i;
7559  }
7560  /* add last clique minweightsum */
7561  minweightsum += localminweightsum;
7562 
7563  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7564  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7565 
7566  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7567  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7568  {
7569  SCIP_Longint maxcliqueweight = -1LL;
7570 
7571  /* loop over cliques */
7572  for( c = 0; c < nnegcliques; ++c )
7573  {
7574  SCIP_VAR* maxvar;
7575  SCIP_Bool maxvarfixed;
7576  int endvarposclique;
7577  int startvarposclique;
7578 
7579  assert(myvars != NULL);
7580  assert(nnegcliques == consdata->nnegcliques);
7581  assert(myweights != NULL);
7582  assert(secondmaxweights != NULL);
7583  assert(cliquestartposs != NULL);
7584 
7585  endvarposclique = cliqueendposs[c];
7586  startvarposclique = cliquestartposs[c];
7587 
7588  maxvar = myvars[startvarposclique];
7589 
7590  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7591  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7592  continue;
7593 
7594  maxcliqueweight = myweights[startvarposclique];
7595  maxvarfixed = FALSE;
7596  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7597  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7598  * exceeds the capacity the maximum weight variable can be fixed to zero.
7599  */
7600  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7601  {
7602 #ifndef NDEBUG
7603  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7604 #endif
7605  assert(maxcliqueweight >= secondmaxweights[c]);
7606  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7607 
7608  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7609  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7610  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7611  assert(consdata->onesweightsum == oldonesweightsum);
7612  assert(!infeasible);
7613  assert(tightened);
7614  (*nfixedvars)++;
7615  maxvarfixed = TRUE;
7616  }
7617  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7618  * fits into the knapsack
7619  */
7620  else if( nnegcliques - c == nvars - startvarposclique )
7621  break;
7622  /* early termination of the remaining loop because no further variable fixings are possible:
7623  *
7624  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7625  * largest was set to 0) does not suffice to infer additional variable fixings because
7626  *
7627  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7628  * - their second largest elements are at least as large as the smallest weight of the knapsack
7629  */
7630  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7631  break;
7632 
7633  /* loop over items with non-maximal weight (omitting the first position) */
7634  for( i = endvarposclique; i > startvarposclique; --i )
7635  {
7636  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7637  * messed up the clique preprocessing in the previous loop to filter those variables out */
7638  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7639 
7640  /* only check variables of negated cliques for which no variable is locally fixed */
7641  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7642  {
7643  assert(maxcliqueweight >= myweights[i]);
7644  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7645 
7646  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7647  *
7648  * the maxvar was already fixed to 0 because it has a huge gain.
7649  *
7650  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7651  * since replacing i with the element of maximal weight leads to infeasibility */
7652  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7653  {
7654 #ifndef NDEBUG
7655  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7656 #endif
7657  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7658  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7659  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7660  assert(!infeasible);
7661  assert(tightened);
7662  ++(*nfixedvars);
7663  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7664 
7665  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7666  * consdata->onesweightsum
7667  */
7668  minweightsum -= myweights[i];
7669  assert(minweightsum >= 0);
7670  }
7671  else
7672  break;
7673  }
7674  }
7675 #ifndef NDEBUG
7676  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7677  for( ; i > startvarposclique; --i )
7678  {
7679  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7680  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7681 
7682  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7683  assert(varisfixed || !exceedscapacity);
7684  }
7685 #endif
7686  }
7687  }
7688  SCIPfreeBufferArray(scip, &secondmaxweights);
7689  SCIPfreeBufferArray(scip, &cliqueendposs);
7690  SCIPfreeBufferArray(scip, &cliquestartposs);
7691  SCIPfreeBufferArray(scip, &myweights);
7692  SCIPfreeBufferArray(scip, &myvars);
7693  }
7694 
7695  assert(consdata->negcliquepartitioned || minweightsum == 0);
7696  }
7697  while( FALSE );
7698 
7699  assert(usenegatedclique || minweightsum == 0);
7700  /* check, if weights of fixed variables already exceed knapsack capacity */
7701  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7702  {
7703  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7704  consdata->onesweightsum, consdata->capacity);
7705 
7706  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7707  *cutoff = TRUE;
7708 
7709  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7711  {
7712  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7713  SCIP_Longint weight;
7714 
7715  weight = 0;
7716 
7718 
7719  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7720  {
7721  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7722  {
7723  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7724  weight += consdata->weights[i];
7725  }
7726  }
7727 
7728  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7729  }
7730 
7731  return SCIP_OKAY;
7732  }
7733 
7734  /* the algorithm below is a special case of propagation involving negated cliques */
7735  if( !usenegatedclique )
7736  {
7737  assert(consdata->sorted);
7738  residualcapacity = consdata->capacity - consdata->onesweightsum;
7739 
7740  /* fix all variables to zero, that don't fit into the knapsack anymore */
7741  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7742  {
7743  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7744  * to zero
7745  */
7746  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7747  {
7748  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7749  {
7750  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7751  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7752  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7753  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7754  assert(!infeasible);
7755  assert(tightened);
7756  (*nfixedvars)++;
7757  }
7758  }
7759  }
7760  }
7761 
7762  /* check if the knapsack is now redundant */
7763  if( !SCIPconsIsModifiable(cons) )
7764  {
7765  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7766 
7767  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7768  for( i = 0; i < nvars; ++i )
7769  {
7770  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7771  {
7772  unfixedweightsum += consdata->weights[i];
7773 
7774  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7775  if( unfixedweightsum > consdata->capacity )
7776  return SCIP_OKAY;
7777  }
7778  }
7779  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7780  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7781  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7782  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7783  *redundant = TRUE;
7784  }
7785 
7786  return SCIP_OKAY;
7787 }
7788 
7789 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7790  * containing all negated variables of this knapsack constraint
7791  */
7792 static
7794  SCIP* scip, /**< SCIP data structure */
7795  SCIP_CONS* cons, /**< knapsack constraint */
7796  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7797  int* naddconss /**< pointer to count number of added constraints */
7798  )
7799 {
7800  SCIP_CONS* newcons;
7801  SCIP_CONSDATA* consdata;
7802 
7803  assert(scip != NULL);
7804  assert(cons != NULL);
7805  assert(ndelconss != NULL);
7806  assert(naddconss != NULL);
7807 
7808  consdata = SCIPconsGetData(cons);
7809  assert(consdata != NULL);
7810  assert(consdata->nvars > 1);
7811 
7812  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7813  if( consdata->nvars == 2 )
7814  {
7815  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7816 
7817  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7821  SCIPconsIsStickingAtNode(cons)) );
7822  }
7823  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7824  * containing all negated variables of the knapsack
7825  */
7826  else
7827  {
7828  SCIP_VAR** consvars;
7829 
7830  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7831 
7832  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7833  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7834 
7835  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7839  SCIPconsIsStickingAtNode(cons)) );
7840 
7841  SCIPfreeBufferArray(scip, &consvars);
7842  }
7843 
7844  SCIP_CALL( SCIPaddCons(scip, newcons) );
7845  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7846  ++(*naddconss);
7847 
7848  SCIP_CALL( SCIPdelCons(scip, cons) );
7849  ++(*ndelconss);
7850 
7851  return SCIP_OKAY;
7852 }
7853 
7854 /** delete redundant variables
7855  *
7856  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7857  *
7858  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7859  * => x4, x5 always fits into the knapsack, so we can delete them
7860  *
7861  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7862  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7863  */
7864 static
7866  SCIP* scip, /**< SCIP data structure */
7867  SCIP_CONS* cons, /**< knapsack constraint */
7868  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7869  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7870  * first which did not fit */
7871  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7872  int* nchgsides, /**< pointer to store the amount of changed sides */
7873  int* naddconss /**< pointer to count number of added constraints */
7874  )
7875 {
7876  SCIP_CONSHDLRDATA* conshdlrdata;
7877  SCIP_CONSDATA* consdata;
7878  SCIP_VAR** vars;
7879  SCIP_Longint* weights;
7880  SCIP_Longint capacity;
7881  SCIP_Longint gcd;
7882  int nvars;
7883  int w;
7884 
7885  assert(scip != NULL);
7886  assert(cons != NULL);
7887  assert(nchgcoefs != NULL);
7888  assert(nchgsides != NULL);
7889  assert(naddconss != NULL);
7890 
7891  consdata = SCIPconsGetData(cons);
7892  assert(consdata != NULL);
7893  assert(0 < frontsum && frontsum < consdata->weightsum);
7894  assert(0 < splitpos && splitpos < consdata->nvars);
7895 
7896  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7897  assert(conshdlrdata != NULL);
7898 
7899  vars = consdata->vars;
7900  weights = consdata->weights;
7901  nvars = consdata->nvars;
7902  capacity = consdata->capacity;
7903 
7904  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7905  * weight must not be sorted by their index
7906  */
7907 #ifndef NDEBUG
7908  for( w = nvars - 1; w > 0; --w )
7909  assert(weights[w] <= weights[w-1]);
7910 #endif
7911 
7912  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7913  if( consdata->nvars - 1 == splitpos )
7914  return SCIP_OKAY;
7915 
7916  assert(frontsum + weights[splitpos] > capacity);
7917 
7918  /* detect redundant variables */
7919  if( consdata->weightsum - weights[splitpos] <= capacity )
7920  {
7921  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7922  * fit
7923  */
7924  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7925 
7926  /* delete items and update capacity */
7927  for( w = nvars - 1; w > splitpos; --w )
7928  {
7929  consdata->capacity -= weights[w];
7930  SCIP_CALL( delCoefPos(scip, cons, w) );
7931  }
7932  assert(w == splitpos);
7933 
7934  ++(*nchgsides);
7935  *nchgcoefs += (nvars - splitpos);
7936 
7937  /* division by greatest common divisor */
7938  gcd = weights[w];
7939  for( ; w >= 0 && gcd > 1; --w )
7940  {
7941  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7942  }
7943 
7944  /* normalize if possible */
7945  if( gcd > 1 )
7946  {
7947  for( w = splitpos; w >= 0; --w )
7948  {
7949  consdataChgWeight(consdata, w, weights[w]/gcd);
7950  }
7951  (*nchgcoefs) += nvars;
7952 
7953  consdata->capacity /= gcd;
7954  ++(*nchgsides);
7955  }
7956 
7957  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7958  * weight must not be sorted by their index
7959  */
7960 #ifndef NDEBUG
7961  for( w = consdata->nvars - 1; w > 0; --w )
7962  assert(weights[w] <= weights[w - 1]);
7963 #endif
7964  }
7965  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7966  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7967  * splitpos and needs to fit into the knapsack
7968  */
7969  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7970  {
7971  int* clqpart;
7972  int nclq;
7973  int len;
7974 
7975  len = nvars - (splitpos + 1);
7976  /* allocate temporary memory */
7977  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7978 
7979  /* calculate clique partition */
7980  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7981 
7982  /* check if we found at least one clique */
7983  if( nclq < len )
7984  {
7985  SCIP_Longint maxactduetoclq;
7986  int cliquenum;
7987 
7988  maxactduetoclq = 0;
7989  cliquenum = 0;
7990 
7991  /* calculate maximum activity due to cliques */
7992  for( w = 0; w < len; ++w )
7993  {
7994  assert(clqpart[w] >= 0 && clqpart[w] <= w);
7995  if( clqpart[w] == cliquenum )
7996  {
7997  maxactduetoclq += weights[w + splitpos + 1];
7998  ++cliquenum;
7999  }
8000  }
8001 
8002  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8003  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8004  */
8005  if( frontsum + maxactduetoclq <= capacity )
8006  {
8007  SCIP_VAR** clqvars;
8008  int nclqvars;
8009  int c;
8010 
8011  assert(maxactduetoclq < weights[splitpos]);
8012 
8013  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8014 
8015  /* allocate temporary memory */
8016  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8017 
8018  for( c = 0; c < nclq; ++c )
8019  {
8020  nclqvars = 0;
8021  for( w = 0; w < len; ++w )
8022  {
8023  if( clqpart[w] == c )
8024  {
8025  clqvars[nclqvars] = vars[w + splitpos + 1];
8026  ++nclqvars;
8027  }
8028  }
8029 
8030  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8031  if( nclqvars > 1 )
8032  {
8033  SCIP_CONS* cliquecons;
8034  char name[SCIP_MAXSTRLEN];
8035 
8036  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8037  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8041  SCIPconsIsStickingAtNode(cons)) );
8042  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8043  SCIPdebugPrintCons(scip, cliquecons, NULL);
8044  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8045  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8046  ++(*naddconss);
8047  }
8048  }
8049 
8050  /* delete items and update capacity */
8051  for( w = nvars - 1; w > splitpos; --w )
8052  {
8053  SCIP_CALL( delCoefPos(scip, cons, w) );
8054  ++(*nchgcoefs);
8055  }
8056  consdata->capacity -= maxactduetoclq;
8057  assert(frontsum <= consdata->capacity);
8058  ++(*nchgsides);
8059 
8060  assert(w == splitpos);
8061 
8062  /* renew weights pointer */
8063  weights = consdata->weights;
8064 
8065  /* division by greatest common divisor */
8066  gcd = weights[w];
8067  for( ; w >= 0 && gcd > 1; --w )
8068  {
8069  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8070  }
8071 
8072  /* normalize if possible */
8073  if( gcd > 1 )
8074  {
8075  for( w = splitpos; w >= 0; --w )
8076  {
8077  consdataChgWeight(consdata, w, weights[w]/gcd);
8078  }
8079  (*nchgcoefs) += nvars;
8080 
8081  consdata->capacity /= gcd;
8082  ++(*nchgsides);
8083  }
8084 
8085  /* free temporary memory */
8086  SCIPfreeBufferArray(scip, &clqvars);
8087 
8088  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8089  * weight must not be sorted by their index
8090  */
8091 #ifndef NDEBUG
8092  for( w = consdata->nvars - 1; w > 0; --w )
8093  assert(weights[w] <= weights[w - 1]);
8094 #endif
8095  }
8096  }
8097 
8098  /* free temporary memory */
8099  SCIPfreeBufferArray(scip, &clqpart);
8100  }
8101 
8102  return SCIP_OKAY;
8103 }
8104 
8105 /* detect redundant variables which always fits into the knapsack
8106  *
8107  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8108  *
8109  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8110  * => x4, x5 always fits into the knapsack, so we can delete them
8111  *
8112  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8113  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8114  */
8115 static
8117  SCIP* scip, /**< SCIP data structure */
8118  SCIP_CONS* cons, /**< knapsack constraint */
8119  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8120  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8121  int* nchgsides, /**< pointer to store the amount of changed sides */
8122  int* naddconss /**< pointer to count number of added constraints */
8123  )
8125  SCIP_CONSHDLRDATA* conshdlrdata;
8126  SCIP_CONSDATA* consdata;
8127  SCIP_VAR** vars;
8128  SCIP_Longint* weights;
8129  SCIP_Longint capacity;
8130  SCIP_Longint sum;
8131  int noldchgcoefs;
8132  int nvars;
8133  int v;
8134  int w;
8135 
8136  assert(scip != NULL);
8137  assert(cons != NULL);
8138  assert(ndelconss != NULL);
8139  assert(nchgcoefs != NULL);
8140  assert(nchgsides != NULL);
8141  assert(naddconss != NULL);
8142 
8143  consdata = SCIPconsGetData(cons);
8144  assert(consdata != NULL);
8145  assert(consdata->nvars >= 2);
8146  assert(consdata->weightsum > consdata->capacity);
8147 
8148  noldchgcoefs = *nchgcoefs;
8149  vars = consdata->vars;
8150  weights = consdata->weights;
8151  nvars = consdata->nvars;
8152  capacity = consdata->capacity;
8153  sum = 0;
8154 
8155  /* search for maximal fitting items */
8156  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8157  sum += weights[v];
8158 
8159  assert(v < nvars);
8160 
8161  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8162  if( v == nvars - 1 )
8163  {
8164  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8165  assert(SCIPconsIsDeleted(cons));
8166 
8167  return SCIP_OKAY;
8168  }
8169 
8170  if( v < nvars - 1 )
8171  {
8172  /* try to delete variables */
8173  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8174  assert(consdata->nvars > 1);
8175 
8176  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8177  if( v == consdata->nvars - 1 )
8178  {
8179  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8180  assert(SCIPconsIsDeleted(cons));
8181  }
8182 
8183  return SCIP_OKAY;
8184  }
8185 
8186  /* if we already found some redundant variables, stop here */
8187  if( *nchgcoefs > noldchgcoefs )
8188  return SCIP_OKAY;
8189 
8190  assert(vars == consdata->vars);
8191  assert(weights == consdata->weights);
8192  assert(nvars == consdata->nvars);
8193  assert(capacity == consdata->capacity);
8194 
8195  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8196  assert(conshdlrdata != NULL);
8197  /* calculate clique partition */
8198  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8199 
8200  /* check for real existing cliques */
8201  if( consdata->cliquepartition[v] < v )
8202  {
8203  SCIP_Longint sumfront;
8204  SCIP_Longint maxactduetoclqfront;
8205  int* clqpart;
8206  int cliquenum;
8207 
8208  sumfront = 0;
8209  maxactduetoclqfront = 0;
8210 
8211  clqpart = consdata->cliquepartition;
8212  cliquenum = 0;
8213 
8214  /* calculate maximal activity due to cliques */
8215  for( w = 0; w < nvars; ++w )
8216  {
8217  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8218  if( clqpart[w] == cliquenum )
8219  {
8220  if( maxactduetoclqfront + weights[w] <= capacity )
8221  {
8222  maxactduetoclqfront += weights[w];
8223  ++cliquenum;
8224  }
8225  else
8226  break;
8227  }
8228  sumfront += weights[w];
8229  }
8230  assert(w >= v);
8231 
8232  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8233  * information
8234  */
8235  if( conshdlrdata->disaggregation && w == nvars )
8236  {
8237  SCIP_VAR** clqvars;
8238  int nclqvars;
8239  int c;
8240  int ncliques;
8241 
8242  assert(maxactduetoclqfront <= capacity);
8243 
8244  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8245 
8246  ncliques = consdata->ncliques;
8247 
8248  /* allocate temporary memory */
8249  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8250 
8251  for( c = 0; c < ncliques; ++c )
8252  {
8253  nclqvars = 0;
8254  for( w = 0; w < nvars; ++w )
8255  {
8256  if( clqpart[w] == c )
8257  {
8258  clqvars[nclqvars] = vars[w];
8259  ++nclqvars;
8260  }
8261  }
8262 
8263  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8264  if( nclqvars > 1 )
8265  {
8266  SCIP_CONS* cliquecons;
8267  char name[SCIP_MAXSTRLEN];
8268 
8269  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8270  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8274  SCIPconsIsStickingAtNode(cons)) );
8275  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8276  SCIPdebugPrintCons(scip, cliquecons, NULL);
8277  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8278  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8279  ++(*naddconss);
8280  }
8281  }
8282 
8283  /* delete old constraint */
8284  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8285  ++(*ndelconss);
8286 
8287  SCIPfreeBufferArray(scip, &clqvars);
8288 
8289  return SCIP_OKAY;
8290  }
8291 
8292  if( w > v && w < nvars - 1 )
8293  {
8294  /* try to delete variables */
8295  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8296  }
8297  }
8298 
8299  return SCIP_OKAY;
8300 }
8301 
8302 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8303 static
8304 void normalizeWeights(
8305  SCIP_CONS* cons, /**< knapsack constraint */
8306  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8307  int* nchgsides /**< pointer to count number of side changes */
8308  )
8309 {
8310  SCIP_CONSDATA* consdata;
8311  SCIP_Longint gcd;
8312  int i;
8313 
8314  assert(nchgcoefs != NULL);
8315  assert(nchgsides != NULL);
8316  assert(!SCIPconsIsModifiable(cons));
8317 
8318  consdata = SCIPconsGetData(cons);
8319  assert(consdata != NULL);
8320  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8321  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8322  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8323  assert(consdata->nvars >= 1);
8324 
8325  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8326  sortItems(consdata);
8327 
8328  gcd = consdata->weights[consdata->nvars-1];
8329  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8330  {
8331  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8332  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8333 
8334  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8335  }
8336 
8337  if( gcd >= 2 )
8338  {
8339  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8340 
8341  for( i = 0; i < consdata->nvars; ++i )
8342  {
8343  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8344  }
8345  consdata->capacity /= gcd;
8346  (*nchgcoefs) += consdata->nvars;
8347  (*nchgsides)++;
8348 
8349  /* weight should still be sorted, because the reduction preserves this */
8350 #ifndef NDEBUG
8351  for( i = consdata->nvars - 1; i > 0; --i )
8352  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8353 #endif
8354  consdata->sorted = TRUE;
8355  }
8356 }
8357 
8358 /** dual weights tightening for knapsack constraints
8359  *
8360  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8361  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8362  * constraint
8363  *
8364  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8365  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8366  *
8367  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8368  *
8369  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8370  *
8371  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8372  *
8373  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8374  *
8375  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8376  */
8377 static
8379  SCIP* scip, /**< SCIP data structure */
8380  SCIP_CONS* cons, /**< knapsack constraint */
8381  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8382  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8383  int* nchgsides, /**< pointer to store the amount of changed sides */
8384  int* naddconss /**< pointer to count number of added constraints */
8385  )
8387  SCIP_CONSDATA* consdata;
8388  SCIP_Longint* weights;
8389  SCIP_Longint dualcapacity;
8390  SCIP_Longint reductionsum;
8391  SCIP_Longint capacity;
8392  SCIP_Longint exceedsum;
8393  int oldnchgcoefs;
8394  int nvars;
8395  int vbig;
8396  int v;
8397  int w;
8398 #ifndef NDEBUG
8399  int oldnchgsides;
8400 #endif
8401 
8402  assert(scip != NULL);
8403  assert(cons != NULL);
8404  assert(ndelconss != NULL);
8405  assert(nchgcoefs != NULL);
8406  assert(nchgsides != NULL);
8407  assert(naddconss != NULL);
8408 
8409 #ifndef NDEBUG
8410  oldnchgsides = *nchgsides;
8411 #endif
8412 
8413  consdata = SCIPconsGetData(cons);
8414  assert(consdata != NULL);
8415  assert(consdata->weightsum > consdata->capacity);
8416  assert(consdata->nvars >= 2);
8417  assert(consdata->sorted);
8418 
8419  /* constraint should be merged */
8420  assert(consdata->merged);
8421 
8422  nvars = consdata->nvars;
8423  weights = consdata->weights;
8424  capacity = consdata->capacity;
8425 
8426  oldnchgcoefs = *nchgcoefs;
8427 
8428  /* case 1. */
8429  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8430  {
8431  SCIP_CONS* newcons;
8432 
8433  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8434  *
8435  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8436  */
8437  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8438 
8439  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8443  SCIPconsIsStickingAtNode(cons)) );
8444 
8445  SCIP_CALL( SCIPaddCons(scip, newcons) );
8446  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8447  ++(*naddconss);
8448 
8449  SCIP_CALL( SCIPdelCons(scip, cons) );
8450  ++(*ndelconss);
8451 
8452  return SCIP_OKAY;
8453  }
8454 
8455  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8456  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8457  {
8458  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8459  assert(SCIPconsIsDeleted(cons));
8460 
8461  return SCIP_OKAY;
8462  }
8463 
8464  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8465  /* @todo might be changed/removed when improving the coeffcients tightening */
8466  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8467  return SCIP_OKAY;
8468 
8469  /* case 2. */
8470 
8471  v = 0;
8472 
8473  /* @todo generalize the following algorithm for several parts of the knapsack
8474  *
8475  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8476  * variables each combination is a minimal cover, some examples
8477  *
8478  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8479  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8480  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8481  *
8482  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8483  *
8484  */
8485 
8486  /* determine big weights that fit only by itself */
8487  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8488  ++v;
8489 
8490  vbig = v;
8491  assert(vbig < nvars - 1);
8492  exceedsum = 0;
8493 
8494  /* determine the amount needed to exceed the capacity */
8495  while( v < nvars && exceedsum <= capacity )
8496  {
8497  exceedsum += weights[v];
8498  ++v;
8499  }
8500 
8501  /* if we exceeded the capacity we might reduce the weights */
8502  if( exceedsum > capacity )
8503  {
8504  assert(vbig > 0 || v < nvars);
8505 
8506  /* all small weights were needed to exceed the capacity */
8507  if( v == nvars )
8508  {
8509  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8510  assert(newweight > 0);
8511 
8512  /* reduce big weights */
8513  for( v = 0; v < vbig; ++v )
8514  {
8515  if( weights[v] > newweight )
8516  {
8517  consdataChgWeight(consdata, v, newweight);
8518  ++(*nchgcoefs);
8519  }
8520  }
8521 
8522  /* reduce small weights */
8523  for( ; v < nvars; ++v )
8524  {
8525  if( weights[v] > 1 )
8526  {
8527  consdataChgWeight(consdata, v, 1LL);
8528  ++(*nchgcoefs);
8529  }
8530  }
8531 
8532  consdata->capacity = newweight;
8533 
8534  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8535  * weight must not be sorted by their index
8536  */
8537 #ifndef NDEBUG
8538  for( v = nvars - 1; v > 0; --v )
8539  assert(weights[v] <= weights[v-1]);
8540 #endif
8541 
8542  return SCIP_OKAY;
8543  }
8544  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8545  * small weights
8546  */
8547  else
8548  {
8549  SCIP_Longint exceedsumback = 0;
8550  int nexceed = v - vbig;
8551 
8552  assert(nexceed > 1);
8553 
8554  /* determine weightsum of the same amount as before but of the smallest weight */
8555  for( w = nvars - 1; w >= nvars - nexceed; --w )
8556  exceedsumback += weights[w];
8557 
8558  assert(w >= 0);
8559 
8560  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8561  * combinations of all small weights
8562  */
8563  if( exceedsumback > capacity )
8564  {
8565  SCIP_Longint newweight = nexceed - 1;
8566 
8567  /* taking out the smallest element needs to fit */
8568  assert(exceedsumback - weights[nvars - 1] <= capacity);
8569 
8570  /* reduce big weights */
8571  for( v = 0; v < vbig; ++v )
8572  {
8573  if( weights[v] > newweight )
8574  {
8575  consdataChgWeight(consdata, v, newweight);
8576  ++(*nchgcoefs);
8577  }
8578  }
8579 
8580  /* reduce small weights */
8581  for( ; v < nvars; ++v )
8582  {
8583  if( weights[v] > 1 )
8584  {
8585  consdataChgWeight(consdata, v, 1LL);
8586  ++(*nchgcoefs);
8587  }
8588  }
8589 
8590  consdata->capacity = newweight;
8591 
8592  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8593  * weight must not be sorted by their index
8594  */
8595 #ifndef NDEBUG
8596  for( v = nvars - 1; v > 0; --v )
8597  assert(weights[v] <= weights[v-1]);
8598 #endif
8599  return SCIP_OKAY;
8600  }
8601  }
8602  }
8603  else
8604  {
8605  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8606  * not happen here
8607  */
8608  assert(vbig > 0 && vbig < nvars);
8609 
8610  /* either choose a big coefficients or all other variables
8611  *
8612  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8613  *
8614  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8615  * constraint to
8616  *
8617  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8618  */
8619 
8620  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8621  {
8622  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8623 #ifndef NDEBUG
8624  SCIP_Longint resweightsum = consdata->weightsum;
8625 
8626  for( v = 0; v < vbig; ++v )
8627  resweightsum -= weights[v];
8628 
8629  assert(exceedsum == resweightsum);
8630 #endif
8631  assert(newweight > 0);
8632 
8633  /* reduce big weights */
8634  for( v = 0; v < vbig; ++v )
8635  {
8636  if( weights[v] > newweight )
8637  {
8638  consdataChgWeight(consdata, v, newweight);
8639  ++(*nchgcoefs);
8640  }
8641  }
8642 
8643  /* reduce small weights */
8644  for( ; v < nvars; ++v )
8645  {
8646  if( weights[v] > 1 )
8647  {
8648  consdataChgWeight(consdata, v, 1LL);
8649  ++(*nchgcoefs);
8650  }
8651  }
8652 
8653  consdata->capacity = newweight;
8654 
8655  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8656  * weight must not be sorted by their index
8657  */
8658 #ifndef NDEBUG
8659  for( v = nvars - 1; v > 0; --v )
8660  assert(weights[v] <= weights[v-1]);
8661 #endif
8662  return SCIP_OKAY;
8663  }
8664  }
8665 
8666  /* case 3. */
8667 
8668  dualcapacity = consdata->weightsum - capacity;
8669  reductionsum = 0;
8670  v = 0;
8671 
8672  /* reduce big weights
8673  *
8674  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8675  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8676  * <=> x0 + x1 + x2 + x3 <= 3
8677  */
8678  while( weights[v] > dualcapacity )
8679  {
8680  reductionsum += (weights[v] - dualcapacity);
8681  consdataChgWeight(consdata, v, dualcapacity);
8682  ++v;
8683  assert(v < nvars);
8684  }
8685  (*nchgcoefs) += v;
8686 
8687  /* skip weights equal to the dualcapacity, because we cannot change them */
8688  while( v < nvars && weights[v] == dualcapacity )
8689  ++v;
8690 
8691  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8692  * after a possible removal of the last, redundant item
8693  *
8694  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8695  */
8696  if( v >= nvars - 1 )
8697  {
8698  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8699  if( v == nvars - 1 )
8700  {
8701  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8702  }
8703  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8704  assert(SCIPconsIsDeleted(cons));
8705 
8706  return SCIP_OKAY;
8707  }
8708  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8709  {
8710  /* @todo generalize the following algorithm for more than two variables */
8711 
8712  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8713  {
8714  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8715  * coefficients) of all or two variables of the rest
8716  *
8717  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8718  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8719  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8720  *
8721  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8722  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8723  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8724  *
8725  */
8726  if( v > 0 && weights[nvars - 2] > 1 )
8727  {
8728  int ncoefchg = 0;
8729 
8730  /* reduce all bigger weights */
8731  for( w = 0; w < v; ++w )
8732  {
8733  if( weights[w] > 2 )
8734  {
8735  consdataChgWeight(consdata, w, 2LL);
8736  ++ncoefchg;
8737  }
8738  else
8739  {
8740  assert(weights[0] == 2);
8741  assert(weights[v - 1] == 2);
8742  break;
8743  }
8744  }
8745 
8746  /* reduce all smaller weights */
8747  for( w = v; w < nvars; ++w )
8748  {
8749  if( weights[w] > 1 )
8750  {
8751  consdataChgWeight(consdata, w, 1LL);
8752  ++ncoefchg;
8753  }
8754  }
8755  assert(ncoefchg > 0);
8756 
8757  (*nchgcoefs) += ncoefchg;
8758 
8759  /* correct the capacity */
8760  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8761  assert(consdata->capacity > 0);
8762  assert(weights[0] <= consdata->capacity);
8763  assert(consdata->weightsum > consdata->capacity);
8764  /* reset the reductionsum */
8765  reductionsum = 0;
8766  }
8767  else if( v == 0 )
8768  {
8769  assert(weights[nvars - 2] == 1);
8770  }
8771  }
8772  else
8773  {
8774  SCIP_Longint minweight = weights[nvars - 1];
8775  SCIP_Longint newweight = dualcapacity - minweight;
8776  SCIP_Longint restsumweights = 0;
8777  SCIP_Longint sumcoef;
8778  SCIP_Bool sumcoefcase = FALSE;
8779  int startv = v;
8780  int end;
8781  int k;
8782 
8783  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8784 
8785  /* reduce big weights of pairs that exceed the dualcapacity
8786  *
8787  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8788  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8789  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8790  */
8791  while( weights[v] > newweight )
8792  {
8793  reductionsum += (weights[v] - newweight);
8794  consdataChgWeight(consdata, v, newweight);
8795  ++v;
8796  assert(v < nvars);
8797  }
8798  (*nchgcoefs) += (v - startv);
8799 
8800  /* skip equal weights */
8801  while( weights[v] == newweight )
8802  ++v;
8803 
8804  if( v > 0 )
8805  {
8806  for( w = v; w < nvars; ++w )
8807  restsumweights += weights[w];
8808  }
8809  else
8810  restsumweights = consdata->weightsum;
8811 
8812  if( restsumweights < dualcapacity )
8813  {
8814  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8815  *
8816  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8817  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8818  */
8819  if( startv == v )
8820  {
8821  /* remove redundant variables */
8822  for( w = nvars - 1; w >= v; --w )
8823  {
8824  SCIP_CALL( delCoefPos(scip, cons, v) );
8825  ++(*nchgcoefs);
8826  }
8827 
8828 #ifndef NDEBUG
8829  /* each coefficients should exceed the dualcapacity by itself */
8830  for( ; w >= 0; --w )
8831  assert(weights[w] == dualcapacity);
8832 #endif
8833  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8834  * upgrade this constraint
8835  */
8836  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8837  assert(SCIPconsIsDeleted(cons));
8838 
8839  return SCIP_OKAY;
8840  }
8841 
8842  /* special case where we have three different coefficient types
8843  *
8844  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8845  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8846  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8847  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8848  */
8849  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8850  {
8851  SCIP_Longint newcap;
8852 
8853  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8854  for( w = nvars - 1; w >= v; --w )
8855  {
8856  if( weights[w] > 1 )
8857  {
8858  consdataChgWeight(consdata, w, 1LL);
8859  ++(*nchgcoefs);
8860  }
8861  }
8862 
8863  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8864  * dualcapacity
8865  */
8866  newweight = (SCIP_Longint)nvars - v;
8867  assert(newweight > 1);
8868  for( ; w >= startv; --w )
8869  {
8870  if( weights[w] > newweight )
8871  {
8872  consdataChgWeight(consdata, w, newweight);
8873  ++(*nchgcoefs);
8874  }
8875  else
8876  assert(weights[w] == newweight);
8877  }
8878 
8879  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8880  ++newweight;
8881  assert(newweight > 2);
8882  for( ; w >= 0; --w )
8883  {
8884  if( weights[w] > newweight )
8885  {
8886  consdataChgWeight(consdata, w, newweight);
8887  ++(*nchgcoefs);
8888  }
8889  else
8890  assert(weights[w] == newweight);
8891  }
8892 
8893  /* update the capacity */
8894  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8895  if( consdata->capacity > newcap )
8896  {
8897  consdata->capacity = newcap;
8898  ++(*nchgsides);
8899  }
8900  else
8901  assert(consdata->capacity == newcap);
8902  }
8903  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8904 
8905  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8906  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8907 
8908  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8909  * weight must not be sorted by their index
8910  */
8911 #ifndef NDEBUG
8912  for( w = nvars - 1; w > 0; --w )
8913  assert(weights[w] <= weights[w - 1]);
8914 #endif
8915  return SCIP_OKAY;
8916  }
8917 
8918  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8919  end = nvars - 2;
8920  while( end >= 0 && weights[end] == weights[end + 1] )
8921  {
8922  assert(end >= v);
8923  --end;
8924  }
8925 
8926  if( v >= end )
8927  goto TERMINATE;
8928 
8929  end = nvars - 2;
8930 
8931  /* can we stop early, another special reduction case might exist */
8932  if( 2 * weights[end] > dualcapacity )
8933  {
8934  restsumweights = 0;
8935 
8936  /* determine capacity of the small items */
8937  for( w = end + 1; w < nvars; ++w )
8938  restsumweights += weights[w];
8939 
8940  if( restsumweights * 2 <= dualcapacity )
8941  {
8942  /* check for further posssible reductions in the middle */
8943  while( v < end && restsumweights + weights[v] >= dualcapacity )
8944  ++v;
8945 
8946  if( v >= end )
8947  goto TERMINATE;
8948 
8949  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8950  if( (dualcapacity & 1) == 0 )
8951  {
8952  newweight = dualcapacity / 2;
8953 
8954  /* set all middle coefficients */
8955  for( ; v <= end; ++v )
8956  {
8957  if( weights[v] > newweight )
8958  {
8959  reductionsum += (weights[v] - newweight);
8960  consdataChgWeight(consdata, v, newweight);
8961  ++(*nchgcoefs);
8962  }
8963  }
8964  }
8965  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8966  * other coefficients by 2
8967  */
8968  else
8969  {
8970  /* correct the reductionsum */
8971  reductionsum *= 2;
8972 
8973  /* multiply big coefficients by 2 */
8974  for( w = 0; w < v; ++w )
8975  {
8976  consdataChgWeight(consdata, w, weights[w] * 2);
8977  }
8978 
8979  newweight = dualcapacity;
8980  /* set all middle coefficients */
8981  for( ; v <= end; ++v )
8982  {
8983  reductionsum += (2 * weights[v] - newweight);
8984  consdataChgWeight(consdata, v, newweight);
8985  }
8986 
8987  /* multiply small coefficients by 2 */
8988  for( w = end + 1; w < nvars; ++w )
8989  {
8990  consdataChgWeight(consdata, w, weights[w] * 2);
8991  }
8992  (*nchgcoefs) += nvars;
8993 
8994  dualcapacity *= 2;
8995  consdata->capacity *= 2;
8996  ++(*nchgsides);
8997  }
8998  }
8999 
9000  goto TERMINATE;
9001  }
9002 
9003  /* further reductions using the next possible coefficient sum
9004  *
9005  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9006  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9007  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9008  */
9009  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9010  for( k = 0; k < 4; ++k )
9011  {
9012  /* determine next minimal coefficient sum */
9013  switch( k )
9014  {
9015  case 0:
9016  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9017  break;
9018  case 1:
9019  assert(nvars >= 3);
9020  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9021  break;
9022  case 2:
9023  assert(nvars >= 4);
9024  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9025  {
9026  sumcoefcase = TRUE;
9027  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9028  }
9029  else
9030  {
9031  sumcoefcase = FALSE;
9032  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9033  }
9034  break;
9035  case 3:
9036  assert(nvars >= 5);
9037  if( sumcoefcase )
9038  {
9039  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9040  }
9041  else
9042  {
9043  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9044  }
9045  break;
9046  default:
9047  return SCIP_ERROR;
9048  }
9049 
9050  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9051  minweight = weights[end];
9052  while( minweight <= sumcoef )
9053  {
9054  newweight = dualcapacity - minweight;
9055  startv = v;
9056  assert(v < nvars);
9057 
9058  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9059  /* shrink big coefficients */
9060  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9061  {
9062  reductionsum += (weights[v] - newweight);
9063  consdataChgWeight(consdata, v, newweight);
9064  ++v;
9065  assert(v < nvars);
9066  }
9067  (*nchgcoefs) += (v - startv);
9068 
9069  /* skip unchangable weights */
9070  while( weights[v] + minweight == dualcapacity )
9071  {
9072  assert(v < nvars);
9073  ++v;
9074  }
9075 
9076  --end;
9077  /* skip same end weights */
9078  while( end >= 0 && weights[end] == weights[end + 1] )
9079  --end;
9080 
9081  if( v >= end )
9082  goto TERMINATE;
9083 
9084  minweight = weights[end];
9085  }
9086 
9087  if( v >= end )
9088  goto TERMINATE;
9089 
9090  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9091  if( sumcoef < minweight )
9092  {
9093  minweight = sumcoef;
9094  newweight = dualcapacity - minweight;
9095  startv = v;
9096  assert(v < nvars);
9097 
9098  /* shrink big coefficients */
9099  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9100  {
9101  reductionsum += (weights[v] - newweight);
9102  consdataChgWeight(consdata, v, newweight);
9103  ++v;
9104  assert(v < nvars);
9105  }
9106  (*nchgcoefs) += (v - startv);
9107 
9108  /* skip unchangable weights */
9109  while( weights[v] + minweight == dualcapacity )
9110  {
9111  assert(v < nvars);
9112  ++v;
9113  }
9114  }
9115 
9116  if( v >= end )
9117  goto TERMINATE;
9118 
9119  /* can we stop early, another special reduction case might exist */
9120  if( 2 * weights[end] > dualcapacity )
9121  {
9122  restsumweights = 0;
9123 
9124  /* determine capacity of the small items */
9125  for( w = end + 1; w < nvars; ++w )
9126  restsumweights += weights[w];
9127 
9128  if( restsumweights * 2 <= dualcapacity )
9129  {
9130  /* check for further posssible reductions in the middle */
9131  while( v < end && restsumweights + weights[v] >= dualcapacity )
9132  ++v;
9133 
9134  if( v >= end )
9135  goto TERMINATE;
9136 
9137  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9138  if( (dualcapacity & 1) == 0 )
9139  {
9140  newweight = dualcapacity / 2;
9141 
9142  /* set all middle coefficients */
9143  for( ; v <= end; ++v )
9144  {
9145  if( weights[v] > newweight )
9146  {
9147  reductionsum += (weights[v] - newweight);
9148  consdataChgWeight(consdata, v, newweight);
9149  ++(*nchgcoefs);
9150  }
9151  }
9152  }
9153  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9154  * other coefficients by 2
9155  */
9156  else
9157  {
9158  /* correct the reductionsum */
9159  reductionsum *= 2;
9160 
9161  /* multiply big coefficients by 2 */
9162  for( w = 0; w < v; ++w )
9163  {
9164  consdataChgWeight(consdata, w, weights[w] * 2);
9165  }
9166 
9167  newweight = dualcapacity;
9168  /* set all middle coefficients */
9169  for( ; v <= end; ++v )
9170  {
9171  reductionsum += (2 * weights[v] - newweight);
9172  consdataChgWeight(consdata, v, newweight);
9173  }
9174 
9175  /* multiply small coefficients by 2 */
9176  for( w = end + 1; w < nvars; ++w )
9177  {
9178  consdataChgWeight(consdata, w, weights[w] * 2);
9179  }
9180  (*nchgcoefs) += nvars;
9181 
9182  dualcapacity *= 2;
9183  consdata->capacity *= 2;
9184  ++(*nchgsides);
9185  }
9186  }
9187 
9188  goto TERMINATE;
9189  }
9190 
9191  /* cannot tighten any further */
9192  if( 2 * sumcoef > dualcapacity )
9193  goto TERMINATE;
9194  }
9195  }
9196  }
9197 
9198  TERMINATE:
9199  /* correct capacity */
9200  if( reductionsum > 0 )
9201  {
9202  assert(v > 0);
9203 
9204  consdata->capacity -= reductionsum;
9205  ++(*nchgsides);
9206 
9207  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9208  }
9209  assert(weights[0] <= consdata->capacity);
9210 
9211  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9212  * weight must not be sorted by their index
9213  */
9214 #ifndef NDEBUG
9215  for( w = nvars - 1; w > 0; --w )
9216  assert(weights[w] <= weights[w - 1]);
9217 #endif
9218 
9219  if( oldnchgcoefs < *nchgcoefs )
9220  {
9221  assert(!SCIPconsIsDeleted(cons));
9222 
9223  /* it might be that we can divide the weights by their greatest common divisor */
9224  normalizeWeights(cons, nchgcoefs, nchgsides);
9225  }
9226  else
9227  {
9228  assert(oldnchgcoefs == *nchgcoefs);
9229  assert(oldnchgsides == *nchgsides);
9230  }
9231 
9232  return SCIP_OKAY;
9233 }
9234 
9235 
9236 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9237 static
9239  SCIP* scip, /**< SCIP data structure */
9240  SCIP_CONS* cons, /**< knapsack constraint */
9241  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9242  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9243  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9244  )
9245 {
9246  SCIP_VAR** vars;
9247  SCIP_CONSDATA* consdata;
9248  SCIP_Longint* weights;
9249  SCIP_Longint capacity;
9250  SCIP_Bool infeasible;
9251  SCIP_Bool fixed;
9252  int nvars;
9253  int v;
9254 
9255  assert(scip != NULL);
9256  assert(cons != NULL);
9257  assert(nfixedvars != NULL);
9258  assert(ndelconss != NULL);
9259  assert(nchgcoefs != NULL);
9260 
9261  consdata = SCIPconsGetData(cons);
9262  assert(consdata != NULL);
9263 
9264  nvars = consdata->nvars;
9265 
9266  /* no variables left, then delete constraint */
9267  if( nvars == 0 )
9268  {
9269  assert(consdata->capacity >= 0);
9270 
9271  SCIP_CALL( SCIPdelCons(scip, cons) );
9272  ++(*ndelconss);
9273 
9274  return SCIP_OKAY;
9275  }
9276 
9277  /* sort items */
9278  sortItems(consdata);
9279 
9280  vars = consdata->vars;
9281  weights = consdata->weights;
9282  capacity = consdata->capacity;
9283  v = 0;
9284 
9285  /* check for weights bigger than the capacity */
9286  while( v < nvars && weights[v] > capacity )
9287  {
9288  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9289  assert(!infeasible);
9290 
9291  if( fixed )
9292  ++(*nfixedvars);
9293 
9294  ++v;
9295  }
9296 
9297  /* if we fixed at least one variable we need to delete them from the constraint */
9298  if( v > 0 )
9299  {
9300  if( v == nvars )
9301  {
9302  SCIP_CALL( SCIPdelCons(scip, cons) );
9303  ++(*ndelconss);
9304 
9305  return SCIP_OKAY;
9306  }
9307 
9308  /* delete all position from back to front */
9309  for( --v; v >= 0; --v )
9310  {
9311  SCIP_CALL( delCoefPos(scip, cons, v) );
9312  ++(*nchgcoefs);
9313  }
9314 
9315  /* sort items again because of deletion */
9316  sortItems(consdata);
9317  assert(vars == consdata->vars);
9318  assert(weights == consdata->weights);
9319  }
9320  assert(consdata->sorted);
9321  assert(weights[0] <= capacity);
9322 
9323  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9324  {
9325  SCIP_CALL( SCIPdelCons(scip, cons) );
9326  ++(*ndelconss);
9327  }
9328 
9329  return SCIP_OKAY;
9330 }
9331 
9332 
9333 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9334  *
9335  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9336  *
9337  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9338  *
9339  * the above constraint can be changed to
9340  *
9341  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9342  *
9343  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9344  *
9345  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9346  *
9347  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9348  * constraint further, e.g.
9349  *
9350  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9351  * => 2x1 + x2 + x3 + x4 <= 2
9352  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9353  */
9354 static
9356  SCIP* scip, /**< SCIP data structure */
9357  SCIP_CONS* cons, /**< knapsack constraint */
9358  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9359  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9360  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9361  int* nchgsides, /**< pointer to store the amount of changed sides */
9362  int* naddconss, /**< pointer to count number of added constraints */
9363  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9364  )
9365 {
9366  SCIP_VAR** vars;
9367  SCIP_CONSDATA* consdata;
9368  SCIP_Longint* weights;
9369  SCIP_Longint restweight;
9370  SCIP_Longint newweight;
9371  SCIP_Longint weight;
9372  SCIP_Longint oldgcd;
9373  SCIP_Longint rest;
9374  SCIP_Longint gcd;
9375  int oldnchgcoefs;
9376  int oldnchgsides;
9377  int candpos;
9378  int candpos2;
9379  int offsetv;
9380  int nvars;
9381  int v;
9382 
9383  assert(scip != NULL);
9384  assert(cons != NULL);
9385  assert(nfixedvars != NULL);
9386  assert(ndelconss != NULL);
9387  assert(nchgcoefs != NULL);
9388  assert(nchgsides != NULL);
9389  assert(naddconss != NULL);
9390  assert(cutoff != NULL);
9391  assert(!SCIPconsIsModifiable(cons));
9392 
9393  consdata = SCIPconsGetData(cons);
9394  assert( consdata != NULL );
9395 
9396  *cutoff = FALSE;
9397 
9398  /* remove double enties and also combinations of active and negated variables */
9399  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9400  assert(consdata->merged);
9401  if( *cutoff )
9402  return SCIP_OKAY;
9403 
9404  assert(consdata->capacity >= 0);
9405 
9406  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9407  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9408 
9409  if( SCIPconsIsDeleted(cons) )
9410  return SCIP_OKAY;
9411 
9412  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9413  {
9414  /* 1. dual weights tightening */
9415  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9416 
9417  if( SCIPconsIsDeleted(cons) )
9418  return SCIP_OKAY;
9419  /* 2. delete redundant variables */
9420  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9421 
9422  if( SCIPconsIsDeleted(cons) )
9423  return SCIP_OKAY;
9424  }
9425 
9426  weights = consdata->weights;
9427  nvars = consdata->nvars;
9428 
9429 #ifndef NDEBUG
9430  /* constraint might not be sorted, but the weights are already sorted */
9431  for( v = nvars - 1; v > 0; --v )
9432  assert(weights[v] <= weights[v-1]);
9433 #endif
9434 
9435  /* determine greatest common divisor */
9436  gcd = weights[nvars - 1];
9437  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9438  {
9439  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9440  }
9441 
9442  /* divide the constraint by their greatest common divisor */
9443  if( gcd >= 2 )
9444  {
9445  for( v = nvars - 1; v >= 0; --v )
9446  {
9447  consdataChgWeight(consdata, v, weights[v]/gcd);
9448  }
9449  (*nchgcoefs) += nvars;
9450 
9451  consdata->capacity /= gcd;
9452  (*nchgsides)++;
9453  }
9454  assert(consdata->nvars == nvars);
9455 
9456  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9457  * must not be sorted by their index
9458  */
9459 #ifndef NDEBUG
9460  for( v = nvars - 1; v > 0; --v )
9461  assert(weights[v] <= weights[v-1]);
9462 #endif
9463 
9464  /* 3. start gcd procedure for all variables */
9465  do
9466  {
9467  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9468  SCIPdebug( oldnchgsides = *nchgsides; )
9469 
9470  vars = consdata->vars;
9471  weights = consdata->weights;
9472  nvars = consdata->nvars;
9473 
9474  /* stop if we have two coefficients which are one in absolute value */
9475  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9476  return SCIP_OKAY;
9477 
9478  v = 0;
9479  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9480  * gcd
9481  */
9482  while( weights[v] == consdata->capacity )
9483  {
9484  ++v;
9485  assert(v < nvars);
9486  }
9487 
9488  /* all but one variable are as big as the capacity, this is handled elsewhere */
9489  if( v == nvars - 1 )
9490  return SCIP_OKAY;
9491 
9492  offsetv = v;
9493 
9494  gcd = -1;
9495  candpos = -1;
9496  candpos2 = -1;
9497 
9498  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9499  * change the coefficient
9500  */
9501  for( v = nvars - 1; v >= offsetv; --v )
9502  {
9503  weight = weights[v];
9504  assert(weight >= 1);
9505 
9506  oldgcd = gcd;
9507 
9508  if( gcd == -1 )
9509  {
9510  gcd = weights[v];
9511  assert(gcd >= 1);
9512  }
9513  else
9514  {
9515  /* calculate greatest common divisor for all variables */
9516  gcd = SCIPcalcGreComDiv(gcd, weight);
9517  }
9518 
9519  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9520  * can terminate
9521  */
9522  if( gcd == 1 )
9523  {
9524  /* found candidate */
9525  if( candpos == -1 )
9526  {
9527  gcd = oldgcd;
9528  candpos = v;
9529 
9530  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9531  if( v == nvars - 2 )
9532  candpos2 = v + 1;
9533  }
9534  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9535  else
9536  {
9537  if( candpos == v + 1 && candpos2 == v + 2 )
9538  {
9539  assert(candpos2 == nvars - 1);
9540 
9541  /* take new candidates */
9542  candpos = candpos2;
9543 
9544  /* recalculate gcd from scratch */
9545  gcd = weights[v+1];
9546  assert(gcd >= 1);
9547 
9548  /* calculate greatest common divisor for variables */
9549  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9550  if( gcd == 1 )
9551  return SCIP_OKAY;
9552  }
9553  else
9554  /* cannot determine a possible coefficient for reduction */
9555  return SCIP_OKAY;
9556  }
9557  }
9558  }
9559  assert(gcd >= 2);
9560 
9561  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9562  * further
9563  */
9564  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9565 
9566  /* determine the remainder of the capacity and the gcd */
9567  rest = consdata->capacity % gcd;
9568  assert(rest >= 0);
9569  assert(rest < gcd);
9570 
9571  if( candpos == -1 )
9572  {
9573  /* we assume that the constraint was normalized */
9574  assert(rest > 0);
9575 
9576  /* replace old with new capacity */
9577  consdata->capacity -= rest;
9578  ++(*nchgsides);
9579 
9580  /* replace old big coefficients with new capacity */
9581  for( v = 0; v < offsetv; ++v )
9582  {
9583  consdataChgWeight(consdata, v, consdata->capacity);
9584  }
9585 
9586  *nchgcoefs += offsetv;
9587  goto CONTINUE;
9588  }
9589 
9590  /* determine the remainder of the coefficient candidate and the gcd */
9591  restweight = weights[candpos] % gcd;
9592  assert(restweight >= 1);
9593  assert(restweight < gcd);
9594 
9595  /* calculate new coefficient */
9596  if( restweight > rest )
9597  newweight = weights[candpos] - restweight + gcd;
9598  else
9599  newweight = weights[candpos] - restweight;
9600 
9601  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9602 
9603  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);
9604 
9605  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9606  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9607  */
9608  if( newweight == 0 && offsetv > 0 )
9609  return SCIP_OKAY;
9610 
9611  if( rest > 0 )
9612  {
9613  /* replace old with new capacity */
9614  consdata->capacity -= rest;
9615  ++(*nchgsides);
9616 
9617  /* replace old big coefficients with new capacity */
9618  for( v = 0; v < offsetv; ++v )
9619  {
9620  consdataChgWeight(consdata, v, consdata->capacity);
9621  }
9622 
9623  *nchgcoefs += offsetv;
9624  }
9625 
9626  if( newweight == 0 )
9627  {
9628  /* delete redundant coefficient */
9629  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9630  assert(consdata->nvars == nvars - 1);
9631  --nvars;
9632  }
9633  else
9634  {
9635  /* replace old with new coefficient */
9636  consdataChgWeight(consdata, candpos, newweight);
9637  }
9638  ++(*nchgcoefs);
9639 
9640  assert(consdata->vars == vars);
9641  assert(consdata->nvars == nvars);
9642  assert(consdata->weights == weights);
9643 
9644  CONTINUE:
9645  /* now constraint can be normalized, dividing it by the gcd */
9646  for( v = nvars - 1; v >= 0; --v )
9647  {
9648  consdataChgWeight(consdata, v, weights[v]/gcd);
9649  }
9650  (*nchgcoefs) += nvars;
9651 
9652  consdata->capacity /= gcd;
9653  ++(*nchgsides);
9654 
9655  SCIPdebugPrintCons(scip, cons, NULL);
9656 
9657  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));
9658  }
9659  while( nvars >= 2 );
9660 
9661  return SCIP_OKAY;
9662 }
9663 
9664 
9665 /** inserts an element into the list of binary zero implications */
9666 static
9668  SCIP* scip, /**< SCIP data structure */
9669  int** liftcands, /**< array of the lifting candidates */
9670  int* nliftcands, /**< number of lifting candidates */
9671  int** firstidxs, /**< array of first zeroitems indices */
9672  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9673  int** zeroitems, /**< pointer to zero items array */
9674  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9675  int* zeroitemssize, /**< pointer to size of zero items array */
9676  int* nzeroitems, /**< pointer to length of zero items array */
9677  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9678  SCIP_Bool value, /**< value v of variable y in implication */
9679  int knapsackidx, /**< index of variable x in knapsack */
9680  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9681  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9682  )
9683 {
9684  int nzeros;
9685 
9686  assert(liftcands != NULL);
9687  assert(liftcands[value] != NULL);
9688  assert(nliftcands != NULL);
9689  assert(firstidxs != NULL);
9690  assert(firstidxs[value] != NULL);
9691  assert(zeroweightsums != NULL);
9692  assert(zeroweightsums[value] != NULL);
9693  assert(zeroitems != NULL);
9694  assert(nextidxs != NULL);
9695  assert(zeroitemssize != NULL);
9696  assert(nzeroitems != NULL);
9697  assert(*nzeroitems <= *zeroitemssize);
9698  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9699  assert(memlimitreached != NULL);
9700 
9701  nzeros = *nzeroitems;
9702 
9703  /* allocate enough memory */
9704  if( nzeros == *zeroitemssize )
9705  {
9706  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9707  * this can be too huge - abort on memory limit
9708  */
9709  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9710  {
9711  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9712  *zeroitemssize);
9713  *memlimitreached = TRUE;
9714  return SCIP_OKAY;
9715  }
9716  *zeroitemssize *= 2;
9717  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9718  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9719  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9720  }
9721  assert(nzeros < *zeroitemssize);
9722 
9723  if( *memlimitreached )
9724  *memlimitreached = FALSE;
9725 
9726  /* insert element */
9727  (*zeroitems)[nzeros] = knapsackidx;
9728  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9729  if( firstidxs[value][probindex] == 0 )
9730  {
9731  liftcands[value][nliftcands[value]] = probindex;
9732  ++nliftcands[value];
9733  }
9734  firstidxs[value][probindex] = nzeros;
9735  ++(*nzeroitems);
9736  zeroweightsums[value][probindex] += knapsackweight;
9737 
9738  return SCIP_OKAY;
9739 }
9740 
9741 #define MAX_CLIQUELENGTH 50
9742 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9743  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9744  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9745  * if cliqueweightsum(xi == v) < capacity:
9746  * - fixing variable xi to v would make the knapsack constraint redundant
9747  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9748  * redundancy effect:
9749  * wi' := capacity - cliqueweightsum(xi == v)
9750  * this rule can also be applied to binary variables not in the knapsack!
9751  */
9752 static
9754  SCIP* scip, /**< SCIP data structure */
9755  SCIP_CONS* cons, /**< knapsack constraint */
9756  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9757  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9758  )
9759 {
9760  SCIP_CONSDATA* consdata;
9761  SCIP_VAR** binvars;
9762  int nbinvars;
9763  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9764  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9765  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9766  int* zeroitems; /* item number in knapsack that is implied to zero */
9767  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9768  int zeroitemssize;
9769  int nzeroitems;
9770  SCIP_Bool* zeroiteminserted[2];
9771  SCIP_Bool memlimitreached;
9772  int nliftcands[2];
9773  SCIP_Bool* cliqueused;
9774  SCIP_Bool* itemremoved;
9775  SCIP_Longint maxcliqueweightsum;
9776  SCIP_VAR** addvars;
9777  SCIP_Longint* addweights;
9778  SCIP_Longint addweightsum;
9779  int nvars;
9780  int cliquenum;
9781  int naddvars;
9782  int val;
9783  int i;
9784 
9785  int* tmpindices;
9786  SCIP_Bool* tmpboolindices;
9787  int* tmpindices2;
9788  SCIP_Bool* tmpboolindices2;
9789  int* tmpindices3;
9790  SCIP_Bool* tmpboolindices3;
9791  int tmp;
9792  int tmp2;
9793  int tmp3;
9794  SCIP_CONSHDLR* conshdlr;
9795  SCIP_CONSHDLRDATA* conshdlrdata;
9796 
9797  assert(nchgcoefs != NULL);
9798  assert(!SCIPconsIsModifiable(cons));
9799 
9800  consdata = SCIPconsGetData(cons);
9801  assert(consdata != NULL);
9802  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9803  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9804  assert(consdata->nvars > 0);
9805  assert(consdata->merged);
9806 
9807  nvars = consdata->nvars;
9808 
9809  /* check if the knapsack has too many items/cliques for applying this costly method */
9810  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9811  return SCIP_OKAY;
9812 
9813  /* sort items, s.t. the heaviest one is in the first position */
9814  sortItems(consdata);
9815 
9816  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9817  return SCIP_OKAY;
9818 
9819  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9820  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9821  assert(nbinvars > 0);
9822  binvars = SCIPgetVars(scip);
9823 
9824  /* get conshdlrdata to use cleared memory */
9825  conshdlr = SCIPconsGetHdlr(cons);
9826  assert(conshdlr != NULL);
9827  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9828  assert(conshdlrdata != NULL);
9829 
9830  /* allocate temporary memory for the list of implied to zero variables */
9831  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9832  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9833  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9834 
9835  assert(conshdlrdata->ints1size > 0);
9836  assert(conshdlrdata->ints2size > 0);
9837  assert(conshdlrdata->longints1size > 0);
9838  assert(conshdlrdata->longints2size > 0);
9839 
9840  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9841  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9842  * transform all integers into their binary representation then it maybe happens
9843  */
9844  if( conshdlrdata->ints1size < nbinvars )
9845  {
9846  int oldsize = conshdlrdata->ints1size;
9847 
9848  conshdlrdata->ints1size = nbinvars;
9849  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9850  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9851  }
9852  if( conshdlrdata->ints2size < nbinvars )
9853  {
9854  int oldsize = conshdlrdata->ints2size;
9855 
9856  conshdlrdata->ints2size = nbinvars;
9857  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9858  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9859  }
9860  if( conshdlrdata->longints1size < nbinvars )
9861  {
9862  int oldsize = conshdlrdata->longints1size;
9863 
9864  conshdlrdata->longints1size = nbinvars;
9865  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9866  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9867  }
9868  if( conshdlrdata->longints2size < nbinvars )
9869  {
9870  int oldsize = conshdlrdata->longints2size;
9871 
9872  conshdlrdata->longints2size = nbinvars;
9873  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9874  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9875  }
9876 
9877  firstidxs[0] = conshdlrdata->ints1;
9878  firstidxs[1] = conshdlrdata->ints2;
9879  zeroweightsums[0] = conshdlrdata->longints1;
9880  zeroweightsums[1] = conshdlrdata->longints2;
9881 
9882  /* check for cleared arrays, all entries are zero */
9883 #ifndef NDEBUG
9884  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9885  {
9886  assert(firstidxs[0][tmp] == 0);
9887  assert(firstidxs[1][tmp] == 0);
9888  assert(zeroweightsums[0][tmp] == 0);
9889  assert(zeroweightsums[1][tmp] == 0);
9890  }
9891 #endif
9892 
9893  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9894  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9895 
9896  zeroitems[0] = -1; /* dummy element */
9897  nextidxs[0] = -1;
9898  nzeroitems = 1;
9899  nliftcands[0] = 0;
9900  nliftcands[1] = 0;
9901 
9902  assert(conshdlrdata->bools1size > 0);
9903  assert(conshdlrdata->bools2size > 0);
9904 
9905  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9906  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9907  * transform all integers into their binary representation then it maybe happens
9908  */
9909  if( conshdlrdata->bools1size < nbinvars )
9910  {
9911  int oldsize = conshdlrdata->bools1size;
9912 
9913  conshdlrdata->bools1size = nbinvars;
9914  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9915  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9916  }
9917  if( conshdlrdata->bools2size < nbinvars )
9918  {
9919  int oldsize = conshdlrdata->bools2size;
9920 
9921  conshdlrdata->bools2size = nbinvars;
9922  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9923  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9924  }
9925 
9926  zeroiteminserted[0] = conshdlrdata->bools1;
9927  zeroiteminserted[1] = conshdlrdata->bools2;
9928 
9929  /* check for cleared arrays, all entries are zero */
9930 #ifndef NDEBUG
9931  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9932  {
9933  assert(zeroiteminserted[0][tmp] == 0);
9934  assert(zeroiteminserted[1][tmp] == 0);
9935  }
9936 #endif
9937 
9938  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9939  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9940  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9941  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9942  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9943  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9944 
9945  tmp2 = 0;
9946  tmp3 = 0;
9947 
9948  memlimitreached = FALSE;
9949  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9950  {
9951  SCIP_CLIQUE** cliques;
9952  SCIP_VAR* var;
9953  SCIP_Longint weight;
9954  SCIP_Bool value;
9955  int varprobindex;
9956  int ncliques;
9957  int j;
9958 
9959  tmp = 0;
9960 
9961  /* get corresponding active problem variable */
9962  var = consdata->vars[i];
9963  weight = consdata->weights[i];
9964  value = TRUE;
9965  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9966  varprobindex = SCIPvarGetProbindex(var);
9967  assert(0 <= varprobindex && varprobindex < nbinvars);
9968 
9969  /* update the zeroweightsum */
9970  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9971  tmpboolindices3[tmp3] = !value;
9972  tmpindices3[tmp3] = varprobindex;
9973  ++tmp3;
9974 
9975  /* initialize the arrays of inserted zero items */
9976  /* first add the implications (~x == 1 -> x == 0) */
9977  {
9978  SCIP_Bool implvalue;
9979  int probindex;
9980 
9981  probindex = SCIPvarGetProbindex(var);
9982  assert(0 <= probindex && probindex < nbinvars);
9983 
9984  implvalue = !value;
9985 
9986  /* insert the item into the list of the implied variable/value */
9987  assert( !zeroiteminserted[implvalue][probindex] );
9988 
9989  if( firstidxs[implvalue][probindex] == 0 )
9990  {
9991  tmpboolindices2[tmp2] = implvalue;
9992  tmpindices2[tmp2] = probindex;
9993  ++tmp2;
9994  }
9995  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
9996  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
9997  &memlimitreached) );
9998  zeroiteminserted[implvalue][probindex] = TRUE;
9999  tmpboolindices[tmp] = implvalue;
10000  tmpindices[tmp] = probindex;
10001  ++tmp;
10002  }
10003 
10004  /* get the cliques where the knapsack item is member of with value 1 */
10005  ncliques = SCIPvarGetNCliques(var, value);
10006  cliques = SCIPvarGetCliques(var, value);
10007  for( j = 0; j < ncliques && !memlimitreached; ++j )
10008  {
10009  SCIP_VAR** cliquevars;
10010  SCIP_Bool* cliquevalues;
10011  int ncliquevars;
10012  int k;
10013 
10014  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10015 
10016  /* discard big cliques */
10017  if( ncliquevars > MAX_CLIQUELENGTH )
10018  continue;
10019 
10020  cliquevars = SCIPcliqueGetVars(cliques[j]);
10021  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10022 
10023  for( k = ncliquevars - 1; k >= 0; --k )
10024  {
10025  SCIP_Bool implvalue;
10026  int probindex;
10027 
10028  if( var == cliquevars[k] )
10029  continue;
10030 
10031  probindex = SCIPvarGetProbindex(cliquevars[k]);
10032  if( probindex == -1 )
10033  continue;
10034 
10035  assert(0 <= probindex && probindex < nbinvars);
10036  implvalue = cliquevalues[k];
10037 
10038  /* insert the item into the list of the clique variable/value */
10039  if( !zeroiteminserted[implvalue][probindex] )
10040  {
10041  if( firstidxs[implvalue][probindex] == 0 )
10042  {
10043  tmpboolindices2[tmp2] = implvalue;
10044  tmpindices2[tmp2] = probindex;
10045  ++tmp2;
10046  }
10047 
10048  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10049  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10050  &memlimitreached) );
10051  zeroiteminserted[implvalue][probindex] = TRUE;
10052  tmpboolindices[tmp] = implvalue;
10053  tmpindices[tmp] = probindex;
10054  ++tmp;
10055 
10056  if( memlimitreached )
10057  break;
10058  }
10059  }
10060  }
10061  /* clear zeroiteminserted */
10062  for( --tmp; tmp >= 0; --tmp)
10063  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10064  }
10065  SCIPfreeBufferArray(scip, &tmpboolindices);
10066 
10067  /* calculate the clique partition and the maximal sum of weights using the clique information */
10068  assert(consdata->sorted);
10069  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10070 
10071  assert(conshdlrdata->bools3size > 0);
10072 
10073  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10074  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10075  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10076  */
10077  if( conshdlrdata->bools3size < consdata->nvars )
10078  {
10079  int oldsize = conshdlrdata->bools3size;
10080 
10081  conshdlrdata->bools3size = consdata->nvars;;
10082  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10083  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10084  }
10085 
10086  cliqueused = conshdlrdata->bools3;
10087 
10088  /* check for cleared array, all entries are zero */
10089 #ifndef NDEBUG
10090  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10091  assert(cliqueused[tmp] == 0);
10092 #endif
10093 
10094  maxcliqueweightsum = 0;
10095  tmp = 0;
10096 
10097  /* calculates maximal weight of cliques */
10098  for( i = 0; i < consdata->nvars; ++i )
10099  {
10100  cliquenum = consdata->cliquepartition[i];
10101  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10102 
10103  if( !cliqueused[cliquenum] )
10104  {
10105  maxcliqueweightsum += consdata->weights[i];
10106  cliqueused[cliquenum] = TRUE;
10107  tmpindices[tmp] = cliquenum;
10108  ++tmp;
10109  }
10110  }
10111  /* clear cliqueused */
10112  for( --tmp; tmp >= 0; --tmp)
10113  cliqueused[tmp] = FALSE;
10114 
10115  assert(conshdlrdata->bools4size > 0);
10116 
10117  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10118  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10119  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10120  */
10121  if( conshdlrdata->bools4size < consdata->nvars )
10122  {
10123  int oldsize = conshdlrdata->bools4size;
10124 
10125  conshdlrdata->bools4size = consdata->nvars;
10126  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10127  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10128  }
10129 
10130  itemremoved = conshdlrdata->bools4;
10131 
10132  /* check for cleared array, all entries are zero */
10133 #ifndef NDEBUG
10134  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10135  assert(itemremoved[tmp] == 0);
10136 #endif
10137 
10138  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10139  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10140  * included in subsequent cliqueweightsum calculations)
10141  */
10142  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10143  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10144  naddvars = 0;
10145  addweightsum = 0;
10146  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10147  {
10148  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10149  {
10150  SCIP_Longint cliqueweightsum;
10151  int probindex;
10152  int idx;
10153  int j;
10154 
10155  tmp = 0;
10156 
10157  probindex = liftcands[val][i];
10158  assert(0 <= probindex && probindex < nbinvars);
10159 
10160  /* ignore empty zero lists and variables that cannot be lifted anyways */
10161  if( firstidxs[val][probindex] == 0
10162  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10163  continue;
10164 
10165  /* mark the items that are implied to zero by setting the current variable to the current value */
10166  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10167  {
10168  assert(0 < idx && idx < nzeroitems);
10169  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10170  itemremoved[zeroitems[idx]] = TRUE;
10171  }
10172 
10173  /* calculate the residual cliqueweight sum */
10174  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10175  for( j = 0; j < consdata->nvars; ++j )
10176  {
10177  cliquenum = consdata->cliquepartition[j];
10178  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10179  if( !itemremoved[j] )
10180  {
10181  if( !cliqueused[cliquenum] )
10182  {
10183  cliqueweightsum += consdata->weights[j];
10184  cliqueused[cliquenum] = TRUE;
10185  tmpindices[tmp] = cliquenum;
10186  ++tmp;
10187  }
10188 
10189  if( cliqueweightsum >= consdata->capacity )
10190  break;
10191  }
10192  }
10193 
10194  /* check if the weight of the variable/value can be increased */
10195  if( cliqueweightsum < consdata->capacity )
10196  {
10197  SCIP_VAR* var;
10198  SCIP_Longint weight;
10199 
10200  /* insert the variable (with value TRUE) in the list of additional items */
10201  assert(naddvars < 2*nbinvars);
10202  var = binvars[probindex];
10203  if( val == FALSE )
10204  {
10205  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10206  }
10207  weight = consdata->capacity - cliqueweightsum;
10208  addvars[naddvars] = var;
10209  addweights[naddvars] = weight;
10210  addweightsum += weight;
10211  naddvars++;
10212 
10213  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10214  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10215  }
10216 
10217  /* clear itemremoved */
10218  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10219  {
10220  assert(0 < idx && idx < nzeroitems);
10221  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10222  itemremoved[zeroitems[idx]] = FALSE;
10223  }
10224  /* clear cliqueused */
10225  for( --tmp; tmp >= 0; --tmp)
10226  cliqueused[tmpindices[tmp]] = FALSE;
10227  }
10228  }
10229 
10230  /* clear part of zeroweightsums */
10231  for( --tmp3; tmp3 >= 0; --tmp3)
10232  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10233 
10234  /* clear rest of zeroweightsums and firstidxs */
10235  for( --tmp2; tmp2 >= 0; --tmp2)
10236  {
10237  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10238  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10239  }
10240 
10241  /* add all additional item weights */
10242  for( i = 0; i < naddvars; ++i )
10243  {
10244  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10245  }
10246  *nchgcoefs += naddvars;
10247 
10248  if( naddvars > 0 )
10249  {
10250  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10251  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10252  }
10253 
10254  /* free temporary memory */
10255  SCIPfreeBufferArray(scip, &addweights);
10256  SCIPfreeBufferArray(scip, &addvars);
10257  SCIPfreeBufferArray(scip, &tmpindices);
10258  SCIPfreeBufferArray(scip, &tmpindices2);
10259  SCIPfreeBufferArray(scip, &tmpindices3);
10260  SCIPfreeBufferArray(scip, &tmpboolindices2);
10261  SCIPfreeBufferArray(scip, &tmpboolindices3);
10262  SCIPfreeBufferArray(scip, &nextidxs);
10263  SCIPfreeBufferArray(scip, &zeroitems);
10264  SCIPfreeBufferArray(scip, &liftcands[1]);
10265  SCIPfreeBufferArray(scip, &liftcands[0]);
10266 
10267  return SCIP_OKAY;
10268 }
10269 
10270 /** tightens item weights and capacity in presolving:
10271  * given a knapsack sum(wi*xi) <= capacity
10272  * (1) let weightsum := sum(wi)
10273  * if weightsum - wi < capacity:
10274  * - not using item i would make the knapsack constraint redundant
10275  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10276  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10277  * - change coefficients:
10278  * wi' := weightsum - capacity
10279  * capacity' := capacity - (wi - wi')
10280  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10281  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10282  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10283  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10284  * can be multiple times the same weight, this can be improved
10285  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10286  * weight, to capacity - lastmininmalweightsum, e.g. :
10287  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10288  * -> minimal weightsums: 5, 5, 10, 10
10289  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10290  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10291  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10292  * (3) let W(C) be the maximal weight of clique C,
10293  * cliqueweightsum := sum(W(C))
10294  * if cliqueweightsum - W(C) < capacity:
10295  * - not using any item of C would make the knapsack constraint redundant
10296  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10297  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10298  * - change coefficients:
10299  * delta := capacity - (cliqueweightsum - W(C))
10300  * wi' := max(wi - delta, 0)
10301  * capacity' := capacity - delta
10302  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10303  * introduce infeasible solutions.
10304  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10305  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10306  * if cliqueweightsum(xi == v) < capacity:
10307  * - fixing variable xi to v would make the knapsack constraint redundant
10308  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10309  * redundancy effect:
10310  * wi' := capacity - cliqueweightsum(xi == v)
10311  * This rule can also be applied to binary variables not in the knapsack!
10312  * (5) if min{w} + wi > capacity:
10313  * - using item i would force to fix other items to zero
10314  * - wi can be increased to the capacity
10315  */
10316 static
10318  SCIP* scip, /**< SCIP data structure */
10319  SCIP_CONS* cons, /**< knapsack constraint */
10320  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10321  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10322  int* nchgsides, /**< pointer to count number of side changes */
10323  int* naddconss, /**< pointer to count number of added constraints */
10324  int* ndelconss, /**< pointer to count number of deleted constraints */
10325  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10326  )
10327 {
10328  SCIP_CONSHDLRDATA* conshdlrdata;
10329  SCIP_CONSDATA* consdata;
10330  SCIP_Longint* weights;
10331  SCIP_Longint sumcoef;
10332  SCIP_Longint capacity;
10333  SCIP_Longint newweight;
10334  SCIP_Longint maxweight;
10335  SCIP_Longint minweight;
10336  SCIP_Bool sumcoefcase = FALSE;
10337  int startpos;
10338  int backpos;
10339  int nvars;
10340  int pos;
10341  int k;
10342  int i;
10343 
10344  assert(nchgcoefs != NULL);
10345  assert(nchgsides != NULL);
10346  assert(!SCIPconsIsModifiable(cons));
10347 
10348  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10349  assert(conshdlrdata != NULL);
10350 
10351  consdata = SCIPconsGetData(cons);
10352  assert(consdata != NULL);
10353  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10354  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10355  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10356  assert(consdata->nvars > 0);
10357 
10358  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10359  if( *cutoff )
10360  return SCIP_OKAY;
10361 
10362  /* apply rule (1) */
10363  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10364  {
10365  do
10366  {
10367  assert(consdata->merged);
10368 
10369  /* sort items, s.t. the heaviest one is in the first position */
10370  sortItems(consdata);
10371 
10372  for( i = 0; i < consdata->nvars; ++i )
10373  {
10374  SCIP_Longint weight;
10375 
10376  weight = consdata->weights[i];
10377  if( consdata->weightsum - weight < consdata->capacity )
10378  {
10379  newweight = consdata->weightsum - consdata->capacity;
10380  consdataChgWeight(consdata, i, newweight);
10381  consdata->capacity -= (weight - newweight);
10382  (*nchgcoefs)++;
10383  (*nchgsides)++;
10384  assert(!consdata->sorted);
10385  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",
10386  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10387  consdata->capacity + (weight-newweight), consdata->capacity);
10388  }
10389  else
10390  break;
10391  }
10392  }
10393  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10394  }
10395 
10396  /* check for redundancy */
10397  if( consdata->weightsum <= consdata->capacity )
10398  return SCIP_OKAY;
10399 
10400  pos = 0;
10401  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10402  ++pos;
10403 
10404  sumcoef = 0;
10405  weights = consdata->weights;
10406  nvars = consdata->nvars;
10407  capacity = consdata->capacity;
10408 
10409  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10410  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10411  {
10412  /* further reductions using the next possible coefficient sum
10413  *
10414  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10415  */
10416  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10417  for( k = 0; k < 4; ++k )
10418  {
10419  newweight = capacity - sumcoef;
10420 
10421  /* determine next minimal coefficient sum */
10422  switch( k )
10423  {
10424  case 0:
10425  sumcoef = weights[nvars - 1];
10426  backpos = nvars - 1;
10427  break;
10428  case 1:
10429  sumcoef = weights[nvars - 2];
10430  backpos = nvars - 2;
10431  break;
10432  case 2:
10433  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10434  {
10435  sumcoefcase = TRUE;
10436  sumcoef = weights[nvars - 3];
10437  backpos = nvars - 3;
10438  }
10439  else
10440  {
10441  sumcoefcase = FALSE;
10442  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10443  backpos = nvars - 2;
10444  }
10445  break;
10446  default:
10447  assert(k == 3);
10448  if( sumcoefcase )
10449  {
10450  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10451  {
10452  sumcoef = weights[nvars - 4];
10453  backpos = nvars - 4;
10454  }
10455  else
10456  {
10457  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10458  backpos = nvars - 2;
10459  }
10460  }
10461  else
10462  {
10463  sumcoef = weights[nvars - 3];
10464  backpos = nvars - 3;
10465  }
10466  break;
10467  }
10468 
10469  if( backpos <= pos )
10470  break;
10471 
10472  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10473  maxweight = weights[pos];
10474  startpos = pos;
10475  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10476  {
10477  assert(newweight > weights[pos]);
10478 
10479  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10480  SCIPconsGetName(cons), maxweight, newweight);
10481 
10482  consdataChgWeight(consdata, pos, newweight);
10483 
10484  ++pos;
10485  assert(pos < nvars);
10486 
10487  maxweight = weights[pos];
10488 
10489  if( backpos <= pos )
10490  break;
10491  }
10492  (*nchgcoefs) += (pos - startpos);
10493 
10494  /* skip unchangable weights */
10495  while( pos < nvars && weights[pos] + sumcoef == capacity )
10496  ++pos;
10497 
10498  /* check special case were there is only one weight left to tighten
10499  *
10500  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10501  *
10502  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10503  *
10504  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10505  */
10506  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10507  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10508  {
10509  newweight = capacity - sumcoef;
10510  assert(newweight > weights[pos]);
10511 
10512  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10513  SCIPconsGetName(cons), maxweight, newweight);
10514 
10515  consdataChgWeight(consdata, pos, newweight);
10516 
10517  break;
10518  }
10519 
10520  if( backpos <= pos )
10521  break;
10522  }
10523  }
10524 
10525  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10526  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10527  {
10528  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10529  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10530  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10531  {
10532  SCIP_VAR** clqvars;
10533  SCIP_CONS* cliquecons;
10534  char name[SCIP_MAXSTRLEN];
10535  int* clqpart;
10536  int nclqvars;
10537  int nclq;
10538  int len;
10539  int c;
10540  int w;
10541 
10542  assert(!SCIPconsIsDeleted(cons));
10543 
10544  if( pos == consdata->nvars )
10545  {
10546  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10547 
10548  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10552  SCIPconsIsStickingAtNode(cons)) );
10553 
10554  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10555  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10556  ++(*naddconss);
10557 
10558  /* delete old constraint */
10559  SCIP_CALL( SCIPdelCons(scip, cons) );
10560  ++(*ndelconss);
10561 
10562  return SCIP_OKAY;
10563  }
10564 
10565  len = consdata->nvars - pos;
10566 
10567  /* allocate temporary memory */
10568  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10569 
10570  /* calculate clique partition */
10571  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10572  assert(nclq <= len);
10573 
10574 #ifndef NDEBUG
10575  /* clique numbers must be at least as high as the index */
10576  for( w = 0; w < nclq; ++w )
10577  assert(clqpart[w] <= w);
10578 #endif
10579 
10580  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10581 
10582  /* allocate temporary memory */
10583  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10584 
10585  /* copy corresponding variables with big coefficients */
10586  for( w = pos - 1; w >= 0; --w )
10587  clqvars[w] = consdata->vars[w];
10588 
10589  /* create for each clique a set-packing constraint */
10590  for( c = 0; c < nclq; ++c )
10591  {
10592  nclqvars = pos;
10593 
10594  for( w = c; w < len; ++w )
10595  {
10596  if( clqpart[w] == c )
10597  {
10598  assert(nclqvars < pos + len - nclq + 1);
10599  clqvars[nclqvars] = consdata->vars[w + pos];
10600  ++nclqvars;
10601  }
10602  }
10603 
10604  assert(nclqvars > 1);
10605 
10606  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10607  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10611  SCIPconsIsStickingAtNode(cons)) );
10612  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10613  SCIPdebugPrintCons(scip, cliquecons, NULL);
10614  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10615  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10616  ++(*naddconss);
10617  }
10618 
10619  /* delete old constraint */
10620  SCIP_CALL( SCIPdelCons(scip, cons) );
10621  ++(*ndelconss);
10622 
10623  SCIPfreeBufferArray(scip, &clqvars);
10624  SCIPfreeBufferArray(scip, &clqpart);
10625 
10626  return SCIP_OKAY;
10627  }
10628  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10629  {
10630  SCIP_Longint* maxcliqueweights;
10631  SCIP_Longint* newweightvals;
10632  int* newweightidxs;
10633  SCIP_Longint cliqueweightsum;
10634 
10635  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10636  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10637  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10638 
10639  /* repeat as long as changes have been applied */
10640  do
10641  {
10642  int ncliques;
10643  int cliquenum;
10644  SCIP_Bool zeroweights;
10645 
10646  assert(consdata->merged);
10647 
10648  /* sort items, s.t. the heaviest one is in the first position */
10649  sortItems(consdata);
10650 
10651  /* calculate a clique partition */
10652  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10653 
10654  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10655  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10656  break;
10657 
10658  /* calculate the maximal weight of the cliques and store the clique type */
10659  cliqueweightsum = 0;
10660  ncliques = 0;
10661 
10662  for( i = 0; i < consdata->nvars; ++i )
10663  {
10664  SCIP_Longint weight;
10665 
10666  cliquenum = consdata->cliquepartition[i];
10667  assert(0 <= cliquenum && cliquenum <= ncliques);
10668 
10669  weight = consdata->weights[i];
10670  assert(weight > 0);
10671 
10672  if( cliquenum == ncliques )
10673  {
10674  maxcliqueweights[ncliques] = weight;
10675  cliqueweightsum += weight;
10676  ++ncliques;
10677  }
10678 
10679  assert(maxcliqueweights[cliquenum] >= weight);
10680  }
10681 
10682  /* apply rule on every clique */
10683  zeroweights = FALSE;
10684  for( i = 0; i < ncliques; ++i )
10685  {
10686  SCIP_Longint delta;
10687 
10688  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10689  if( delta > 0 )
10690  {
10691  SCIP_Longint newcapacity;
10692 #ifndef NDEBUG
10693  SCIP_Longint newmincliqueweight;
10694 #endif
10695  SCIP_Longint newminweightsuminclique;
10696  SCIP_Bool forceclique;
10697  int nnewweights;
10698  int j;
10699 
10700  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",
10701  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10702  newcapacity = consdata->capacity - delta;
10703  forceclique = FALSE;
10704  nnewweights = 0;
10705 #ifndef NDEBUG
10706  newmincliqueweight = newcapacity + 1;
10707  for( j = 0; j < i; ++j )
10708  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10709 #endif
10710  for( j = i; j < consdata->nvars; ++j )
10711  {
10712  if( consdata->cliquepartition[j] == i )
10713  {
10714  newweight = consdata->weights[j] - delta;
10715  newweight = MAX(newweight, 0);
10716 
10717  /* cache the new weight */
10718  assert(nnewweights < consdata->nvars);
10719  newweightvals[nnewweights] = newweight;
10720  newweightidxs[nnewweights] = j;
10721  nnewweights++;
10722 
10723 #ifndef NDEBUG
10724  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10725  newmincliqueweight = newweight;
10726 #endif
10727  }
10728  }
10729 
10730  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10731  if( nnewweights > 1 )
10732  {
10733 #ifndef NDEBUG
10734  j = newweightidxs[nnewweights - 2];
10735  assert(0 <= j && j < consdata->nvars);
10736  assert(consdata->cliquepartition[j] == i);
10737  j = newweightidxs[nnewweights - 1];
10738  assert(0 <= j && j < consdata->nvars);
10739  assert(consdata->cliquepartition[j] == i);
10740 #endif
10741 
10742  newminweightsuminclique = newweightvals[nnewweights - 2];
10743  newminweightsuminclique += newweightvals[nnewweights - 1];
10744 
10745  /* check if these new two minimal weights both fit into the knapsack;
10746  * if this is true, we have to add a clique constraint in order to enforce the clique
10747  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10748  * reduction might be infeasible, i.e., allows additional solutions)
10749  */
10750  if( newminweightsuminclique <= newcapacity )
10751  forceclique = TRUE;
10752  }
10753 
10754  /* check if we really want to apply the change */
10755  if( conshdlrdata->disaggregation || !forceclique )
10756  {
10757  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10758  consdata->capacity, newcapacity, forceclique);
10759  consdata->capacity = newcapacity;
10760  (*nchgsides)++;
10761 
10762  for( k = 0; k < nnewweights; ++k )
10763  {
10764  j = newweightidxs[k];
10765  assert(0 <= j && j < consdata->nvars);
10766  assert(consdata->cliquepartition[j] == i);
10767 
10768  /* apply the weight change */
10769  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10770  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10771  consdataChgWeight(consdata, j, newweightvals[k]);
10772  (*nchgcoefs)++;
10773  assert(!consdata->sorted);
10774  zeroweights = zeroweights || (newweightvals[k] == 0);
10775  }
10776  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10777  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10778  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10779  * knapsack constraint
10780  */
10781  if( forceclique )
10782  {
10783  SCIP_CONS* cliquecons;
10784  char name[SCIP_MAXSTRLEN];
10785  SCIP_VAR** cliquevars;
10786 
10787  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10788  for( k = 0; k < nnewweights; ++k )
10789  cliquevars[k] = consdata->vars[newweightidxs[k]];
10790 
10791  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10792  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10796  SCIPconsIsStickingAtNode(cons)) );
10797  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10798  SCIPdebugPrintCons(scip, cliquecons, NULL);
10799  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10800  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10801  SCIPfreeBufferArray(scip, &cliquevars);
10802  (*naddconss)++;
10803  }
10804  }
10805  }
10806  }
10807  if( zeroweights )
10808  {
10809  SCIP_CALL( removeZeroWeights(scip, cons) );
10810  }
10811  }
10812  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10813 
10814  /* free temporary memory */
10815  SCIPfreeBufferArray(scip, &newweightidxs);
10816  SCIPfreeBufferArray(scip, &newweightvals);
10817  SCIPfreeBufferArray(scip, &maxcliqueweights);
10818 
10819  /* check for redundancy */
10820  if( consdata->weightsum <= consdata->capacity )
10821  return SCIP_OKAY;
10822  }
10823  }
10824 
10825  /* apply rule (3) */
10826  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10827  {
10828  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10829  }
10830 
10831  /* check for redundancy */
10832  if( consdata->weightsum <= consdata->capacity )
10833  return SCIP_OKAY;
10834 
10835  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10836  {
10837  /* apply rule (4) (all but smallest weight) */
10838  assert(consdata->merged);
10839  sortItems(consdata);
10840  minweight = consdata->weights[consdata->nvars-1];
10841  for( i = 0; i < consdata->nvars-1; ++i )
10842  {
10843  SCIP_Longint weight;
10844 
10845  weight = consdata->weights[i];
10846  assert(weight >= minweight);
10847  if( minweight + weight > consdata->capacity )
10848  {
10849  if( weight < consdata->capacity )
10850  {
10851  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10852  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10853  assert(consdata->sorted);
10854  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10855  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10856  consdata->sorted = TRUE;
10857  (*nchgcoefs)++;
10858  }
10859  }
10860  else
10861  break;
10862  }
10863 
10864  /* apply rule (5) (smallest weight) */
10865  if( consdata->nvars >= 2 )
10866  {
10867  SCIP_Longint weight;
10868 
10869  minweight = consdata->weights[consdata->nvars-2];
10870  weight = consdata->weights[consdata->nvars-1];
10871  assert(minweight >= weight);
10872  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10873  {
10874  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10875  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10876  assert(consdata->sorted);
10877  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10878  assert(minweight >= consdata->weights[consdata->nvars-1]);
10879  consdata->sorted = TRUE;
10880  (*nchgcoefs)++;
10881  }
10882  }
10883  }
10884 
10885  return SCIP_OKAY;
10886 }
10887 
10888 
10889 #ifdef SCIP_DEBUG
10890 static
10891 void printClique(
10892  SCIP_VAR** cliquevars,
10893  int ncliquevars
10894  )
10895 {
10896  int b;
10897  SCIPdebugMessage("adding new Clique: ");
10898  for( b = 0; b < ncliquevars; ++b )
10899  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10900  SCIPdebugPrintf("\n");
10901 }
10902 #endif
10903 
10904 /** adds negated cliques of the knapsack constraint to the global clique table */
10905 static
10907  SCIP*const scip, /**< SCIP data structure */
10908  SCIP_CONS*const cons, /**< knapsack constraint */
10909  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10910  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10911  )
10912 {
10913  SCIP_CONSDATA* consdata;
10914  SCIP_CONSHDLRDATA* conshdlrdata;
10915  SCIP_VAR** poscliquevars;
10916  SCIP_VAR** cliquevars;
10917  SCIP_Longint* maxweights;
10918  SCIP_Longint* gainweights;
10919  int* gaincliquepartition;
10920  SCIP_Bool* cliqueused;
10921  SCIP_Longint minactduetonegcliques;
10922  SCIP_Longint freecapacity;
10923  SCIP_Longint lastweight;
10924  SCIP_Longint beforelastweight;
10925  int nposcliquevars;
10926  int ncliquevars;
10927  int nvars;
10928  int nnegcliques;
10929  int lastcliqueused;
10930  int thisnbdchgs;
10931  int v;
10932  int w;
10933 
10934  assert(scip != NULL);
10935  assert(cons != NULL);
10936  assert(cutoff != NULL);
10937  assert(nbdchgs != NULL);
10938 
10939  *cutoff = FALSE;
10940 
10941  consdata = SCIPconsGetData(cons);
10942  assert(consdata != NULL);
10943 
10944  nvars = consdata->nvars;
10945 
10946  /* check whether the cliques have already been added */
10947  if( consdata->cliquesadded || nvars == 0 )
10948  return SCIP_OKAY;
10949 
10950  /* make sure, the items are merged */
10951  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10952  if( *cutoff )
10953  return SCIP_OKAY;
10954 
10955  /* make sure, items are sorted by non-increasing weight */
10956  sortItems(consdata);
10957 
10958  assert(consdata->merged);
10959 
10960  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10961  assert(conshdlrdata != NULL);
10962 
10963  /* calculate a clique partition */
10964  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10965  nnegcliques = consdata->nnegcliques;
10966 
10967  /* if we have no negated cliques, stop */
10968  if( nnegcliques == nvars )
10969  return SCIP_OKAY;
10970 
10971  /* get temporary memory */
10972  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10973  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10974  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
10975  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10976  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10977  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
10978 
10979  nnegcliques = 0;
10980  minactduetonegcliques = 0;
10981 
10982  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10983  for( v = 0; v < nvars; ++v )
10984  {
10985  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10986  assert(consdata->weights[v] > 0);
10987 
10988  if( consdata->negcliquepartition[v] == nnegcliques )
10989  {
10990  nnegcliques++;
10991  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
10992  }
10993  else
10994  minactduetonegcliques += consdata->weights[v];
10995  }
10996 
10997  nposcliquevars = 0;
10998 
10999  /* add cliques, using negated cliques information */
11000  if( minactduetonegcliques > 0 )
11001  {
11002  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11003  freecapacity = consdata->capacity - minactduetonegcliques;
11004 
11005  SCIPdebugPrintCons(scip, cons, NULL);
11006  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",
11007  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11008 
11009  /* calculate possible gain by switching chosen items in negated cliques */
11010  for( v = 0; v < nvars; ++v )
11011  {
11012  if( !cliqueused[consdata->negcliquepartition[v]] )
11013  {
11014  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11015  for( w = v + 1; w < nvars; ++w )
11016  {
11017  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11018  * weight[w] (which are both in a negated clique) */
11019  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11020  && consdata->weights[v] > consdata->weights[w] )
11021  {
11022  poscliquevars[nposcliquevars] = consdata->vars[w];
11023  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11024  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11025  ++nposcliquevars;
11026  }
11027  }
11028  }
11029  }
11030 
11031  /* try to create negated cliques */
11032  if( nposcliquevars > 0 )
11033  {
11034  /* sort possible gain per substitution of the clique members */
11035  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11036 
11037  for( v = 0; v < nposcliquevars; ++v )
11038  {
11039  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11040  ncliquevars = 1;
11041  lastweight = gainweights[v];
11042  beforelastweight = -1;
11043  lastcliqueused = gaincliquepartition[v];
11044  /* clear cliqueused to get an unused array */
11045  BMSclearMemoryArray(cliqueused, nnegcliques);
11046  cliqueused[gaincliquepartition[v]] = TRUE;
11047 
11048  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11049  * in the same negated clique and by taking two of them would exceed the free capacity */
11050  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11051  {
11052  beforelastweight = lastweight;
11053  lastweight = gainweights[w];
11054  lastcliqueused = gaincliquepartition[w];
11055  cliqueused[gaincliquepartition[w]] = TRUE;
11056  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11057  ++ncliquevars;
11058  }
11059 
11060  if( ncliquevars > 1 )
11061  {
11062  SCIPdebug( printClique(cliquevars, ncliquevars) );
11063  assert(beforelastweight > 0);
11064  /* add the clique to the clique table */
11065  /* this really happens, e.g., on enigma.mps from the short test set */
11066  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11067  if( *cutoff )
11068  goto TERMINATE;
11069  *nbdchgs += thisnbdchgs;
11070 
11071  /* reset last used clique to get slightly different cliques */
11072  cliqueused[lastcliqueused] = FALSE;
11073 
11074  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11075  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11076  {
11077  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11078  SCIPdebug( printClique(cliquevars, ncliquevars) );
11079  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11080  if( *cutoff )
11081  goto TERMINATE;
11082  *nbdchgs += thisnbdchgs;
11083  }
11084  }
11085  }
11086  }
11087  }
11088 
11089  TERMINATE:
11090  /* free temporary memory */
11091  SCIPfreeBufferArray(scip, &cliqueused);
11092  SCIPfreeBufferArray(scip, &maxweights);
11093  SCIPfreeBufferArray(scip, &gaincliquepartition);
11094  SCIPfreeBufferArray(scip, &gainweights);
11095  SCIPfreeBufferArray(scip, &cliquevars);
11096  SCIPfreeBufferArray(scip, &poscliquevars);
11097 
11098  return SCIP_OKAY;
11099 }
11100 
11101 /** greedy clique detection by considering weights and capacity
11102  *
11103  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11104  * 1) neighboring items which exceed the capacity together => one clique
11105  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11106  */
11107 static
11109  SCIP*const scip, /**< SCIP data structure */
11110  SCIP_VAR** items, /**< array of variable items */
11111  SCIP_Longint* weights, /**< weights of the items */
11112  int nitems, /**< the number of items */
11113  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11114  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11115  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11116  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11117  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11118  )
11119 {
11120  SCIP_Longint lastweight;
11121  int ncliquevars;
11122  int i;
11123  int thisnbdchgs;
11124 
11125  if( nitems <= 1 )
11126  return SCIP_OKAY;
11127 
11128  /* sort possible gain per substitution of the clique members */
11129  if( ! sorteditems )
11130  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11131 
11132  ncliquevars = 1;
11133  lastweight = weights[0];
11134 
11135  /* taking these two weights together violates the knapsack => include into clique */
11136  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11137  {
11138  lastweight = weights[i];
11139  ++ncliquevars;
11140  }
11141 
11142  if( ncliquevars > 1 )
11143  {
11144  SCIP_Longint compareweight;
11145  SCIP_VAR** cliquevars;
11146  int compareweightidx;
11147  int minclqsize;
11148  int nnzadded;
11149 
11150  /* add the clique to the clique table */
11151  SCIPdebug( printClique(items, ncliquevars) );
11152  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11153 
11154  if( *cutoff )
11155  return SCIP_OKAY;
11156 
11157  *nbdchgs += thisnbdchgs;
11158  nnzadded = ncliquevars;
11159 
11160  /* 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)*/
11161  if( ncliquevars == nitems )
11162  return SCIP_OKAY;
11163 
11164  /* copy items in order into buffer array and deduce more cliques */
11165  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11166 
11167  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11168  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11169  compareweightidx = ncliquevars - 2;
11170  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11171 
11172  /* determine minimum clique size for the following loop */
11173  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11174  minclqsize = MAX(minclqsize, 2);
11175 
11176  /* loop over the remaining variables and the larger items of the first clique until we
11177  * find another clique or reach the size limit */
11178  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11179  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11180  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11181  )
11182  {
11183  compareweight = weights[compareweightidx];
11184  assert(compareweight > 0);
11185 
11186  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11187  if( compareweight + weights[i] > capacity )
11188  {
11189  assert(compareweightidx == ncliquevars -2);
11190  cliquevars[ncliquevars - 1] = items[i];
11191  SCIPdebug( printClique(cliquevars, ncliquevars) );
11192  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11193 
11194  nnzadded += ncliquevars;
11195 
11196  /* stop when there is a cutoff */
11197  if( ! (*cutoff) )
11198  *nbdchgs += thisnbdchgs;
11199 
11200  /* go to next smaller item */
11201  ++i;
11202  }
11203  else
11204  {
11205  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11206  compareweightidx--;
11207  ncliquevars --;
11208  }
11209  }
11210 
11211  SCIPfreeBufferArray(scip, &cliquevars);
11212  }
11213 
11214  return SCIP_OKAY;
11215 }
11216 
11217 /** adds cliques of the knapsack constraint to the global clique table */
11218 static
11220  SCIP*const scip, /**< SCIP data structure */
11221  SCIP_CONS*const cons, /**< knapsack constraint */
11222  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11223  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11224  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11225  )
11226 {
11227  SCIP_CONSDATA* consdata;
11228  SCIP_CONSHDLRDATA* conshdlrdata;
11229  int i;
11230  SCIP_Longint minactduetonegcliques;
11231  SCIP_Longint freecapacity;
11232  int nnegcliques;
11233  int cliquenum;
11234  SCIP_VAR** poscliquevars;
11235  SCIP_Longint* gainweights;
11236  int nposcliquevars;
11237  SCIP_Longint* secondmaxweights;
11238  int nvars;
11239 
11240  assert(scip != NULL);
11241  assert(cons != NULL);
11242  assert(cutoff != NULL);
11243  assert(nbdchgs != NULL);
11244 
11245  *cutoff = FALSE;
11246 
11247  consdata = SCIPconsGetData(cons);
11248  assert(consdata != NULL);
11249 
11250  nvars = consdata->nvars;
11251 
11252  /* check whether the cliques have already been added */
11253  if( consdata->cliquesadded || nvars == 0 )
11254  return SCIP_OKAY;
11255 
11256  /* make sure, the items are merged */
11257  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11258  if( *cutoff )
11259  return SCIP_OKAY;
11260 
11261  /* make sure, the items are sorted by non-increasing weight */
11262  sortItems(consdata);
11263 
11264  assert(consdata->merged);
11265 
11266  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11267  assert(conshdlrdata != NULL);
11268 
11269  /* calculate a clique partition */
11270  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11271  nnegcliques = consdata->nnegcliques;
11272  assert(nnegcliques <= nvars);
11273 
11274  /* get temporary memory */
11275  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11276  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11277  BMSclearMemoryArray(gainweights, nvars);
11278  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11279  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11280 
11281  minactduetonegcliques = 0;
11282 
11283  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11284  if( nnegcliques < nvars )
11285  {
11286  nnegcliques = 0;
11287 
11288  for( i = 0; i < nvars; ++i )
11289  {
11290  SCIP_Longint weight;
11291 
11292  cliquenum = consdata->negcliquepartition[i];
11293  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11294 
11295  weight = consdata->weights[i];
11296  assert(weight > 0);
11297 
11298  if( cliquenum == nnegcliques )
11299  nnegcliques++;
11300  else
11301  {
11302  minactduetonegcliques += weight;
11303  if( secondmaxweights[cliquenum] == 0 )
11304  secondmaxweights[cliquenum] = weight;
11305  }
11306  }
11307  }
11308 
11309  /* add cliques, using negated cliques information */
11310  if( minactduetonegcliques > 0 )
11311  {
11312  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11313  freecapacity = consdata->capacity - minactduetonegcliques;
11314 
11315  SCIPdebugPrintCons(scip, cons, NULL);
11316  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",
11317  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11318 
11319  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11320  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11321 
11322  if( *cutoff )
11323  goto TERMINATE;
11324 
11325  nposcliquevars = 0;
11326 
11327  for( i = nvars - 1; i >= 0; --i )
11328  {
11329  /* if we would take the biggest weight instead of the second biggest */
11330  cliquenum = consdata->negcliquepartition[i];
11331  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11332  {
11333  poscliquevars[nposcliquevars] = consdata->vars[i];
11334  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11335  ++nposcliquevars;
11336  }
11337  }
11338 
11339  /* use the gain weights and free capacity to derive greedily cliques */
11340  if( nposcliquevars > 1 )
11341  {
11342  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11343 
11344  if( *cutoff )
11345  goto TERMINATE;
11346  }
11347  }
11348 
11349  /* build cliques by using the items with the maximal weights */
11350  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11351 
11352  TERMINATE:
11353  /* free temporary memory and mark the constraint */
11354  SCIPfreeBufferArray(scip, &secondmaxweights);
11355  SCIPfreeBufferArray(scip, &gainweights);
11356  SCIPfreeBufferArray(scip, &poscliquevars);
11357  consdata->cliquesadded = TRUE;
11358 
11359  return SCIP_OKAY;
11360 }
11361 
11362 
11363 /** gets the key of the given element */
11364 static
11365 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11366 { /*lint --e{715}*/
11367  /* the key is the element itself */
11368  return elem;
11369 }
11370 
11371 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11372  * same coefficients
11373  */
11374 static
11375 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11376 {
11377 #ifndef NDEBUG
11378  SCIP* scip;
11379 #endif
11380  SCIP_CONSDATA* consdata1;
11381  SCIP_CONSDATA* consdata2;
11382  int i;
11384  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11385  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11386  assert(consdata1->sorted);
11387  assert(consdata2->sorted);
11388 #ifndef NDEBUG
11389  scip = (SCIP*)userptr;
11390  assert(scip != NULL);
11391 #endif
11392 
11393  /* checks trivial case */
11394  if( consdata1->nvars != consdata2->nvars )
11395  return FALSE;
11396 
11397  for( i = consdata1->nvars - 1; i >= 0; --i )
11398  {
11399  /* tests if variables are equal */
11400  if( consdata1->vars[i] != consdata2->vars[i] )
11401  {
11402  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11403  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11404  return FALSE;
11405  }
11406  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11407 
11408  /* tests if weights are equal too */
11409  if( consdata1->weights[i] != consdata2->weights[i] )
11410  return FALSE;
11411  }
11412 
11413  return TRUE;
11414 }
11415 
11416 /** returns the hash value of the key */
11417 static
11418 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11419 {
11420 #ifndef NDEBUG
11421  SCIP* scip;
11422 #endif
11423  SCIP_CONSDATA* consdata;
11424  int minidx;
11425  int mididx;
11426  int maxidx;
11427 
11428  consdata = SCIPconsGetData((SCIP_CONS*)key);
11429  assert(consdata != NULL);
11430  assert(consdata->nvars > 0);
11431 
11432 #ifndef NDEBUG
11433  scip = (SCIP*)userptr;
11434  assert(scip != NULL);
11435 #endif
11436 
11437  /* sorts the constraints */
11438  sortItems(consdata);
11439 
11440  minidx = SCIPvarGetIndex(consdata->vars[0]);
11441  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11442  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11443  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11444 
11445  /* hash value depends on vectors of variable indices */
11446  return SCIPhashTwo(SCIPcombineFourInt(consdata->nvars, minidx, mididx, maxidx),
11447  consdata->weights[0]);
11448 }
11449 
11450 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11451  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11452  */
11453 static
11455  SCIP* scip, /**< SCIP data structure */
11456  BMS_BLKMEM* blkmem, /**< block memory */
11457  SCIP_CONS** conss, /**< constraint set */
11458  int nconss, /**< number of constraints in constraint set */
11459  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11460  int* ndelconss /**< pointer to count number of deleted constraints */
11461  )
11463  SCIP_HASHTABLE* hashtable;
11464  int hashtablesize;
11465  int c;
11466 
11467  assert(scip != NULL);
11468  assert(blkmem != NULL);
11469  assert(conss != NULL);
11470  assert(ndelconss != NULL);
11471 
11472  /* create a hash table for the constraint set */
11473  hashtablesize = nconss;
11474  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11475  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11476  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11477 
11478  /* check all constraints in the given set for redundancy */
11479  for( c = nconss - 1; c >= 0; --c )
11480  {
11481  SCIP_CONS* cons0;
11482  SCIP_CONS* cons1;
11483  SCIP_CONSDATA* consdata0;
11484 
11485  cons0 = conss[c];
11486 
11487  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11488  continue;
11489 
11490  consdata0 = SCIPconsGetData(cons0);
11491  assert(consdata0 != NULL);
11492  if( consdata0->nvars == 0 )
11493  {
11494  if( consdata0->capacity < 0 )
11495  {
11496  *cutoff = TRUE;
11497  goto TERMINATE;
11498  }
11499  else
11500  {
11501  SCIP_CALL( SCIPdelCons(scip, cons0) );
11502  ++(*ndelconss);
11503  continue;
11504  }
11505  }
11506 
11507  /* get constraint from current hash table with same variables and same weights as cons0 */
11508  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11509 
11510  if( cons1 != NULL )
11511  {
11512  SCIP_CONS* consstay;
11513  SCIP_CONS* consdel;
11514  SCIP_CONSDATA* consdata1;
11515 
11516  assert(SCIPconsIsActive(cons1));
11517  assert(!SCIPconsIsModifiable(cons1));
11518 
11519  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11520  * delete old constraints afterwards
11521  */
11522  consdata1 = SCIPconsGetData(cons1);
11523 
11524  assert(consdata1 != NULL);
11525  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11526 
11527  assert(consdata0->sorted && consdata1->sorted);
11528  assert(consdata0->vars[0] == consdata1->vars[0]);
11529  assert(consdata0->weights[0] == consdata1->weights[0]);
11530 
11531  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11532  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11533 
11534  /* check which constraint has to stay; */
11535  if( consdata0->capacity < consdata1->capacity )
11536  {
11537  consstay = cons0;
11538  consdel = cons1;
11539 
11540  /* exchange consdel with consstay in hashtable */
11541  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11542  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11543  }
11544  else
11545  {
11546  consstay = cons1;
11547  consdel = cons0;
11548  }
11549 
11550  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11551  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11552 
11553  /* delete consdel */
11554  SCIP_CALL( SCIPdelCons(scip, consdel) );
11555  ++(*ndelconss);
11556 
11557  assert(SCIPconsIsActive(consstay));
11558  }
11559  else
11560  {
11561  /* no such constraint in current hash table: insert cons0 into hash table */
11562  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11563  }
11564  }
11565 
11566  TERMINATE:
11567  /* free hash table */
11568  SCIPhashtableFree(&hashtable);
11569 
11570  return SCIP_OKAY;
11571 }
11572 
11573 
11574 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11575  * and removes or changes constraint accordingly
11576  */
11577 static
11579  SCIP* scip, /**< SCIP data structure */
11580  SCIP_CONS** conss, /**< constraint set */
11581  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11582  int chkind, /**< index of constraint to check against all prior indices upto startind */
11583  int* ndelconss /**< pointer to count number of deleted constraints */
11584  )
11585 {
11586  SCIP_CONS* cons0;
11587  SCIP_CONSDATA* consdata0;
11588  int c;
11589 
11590  assert(scip != NULL);
11591  assert(conss != NULL);
11592  assert(firstchange <= chkind);
11593  assert(ndelconss != NULL);
11594 
11595  /* get the constraint to be checked against all prior constraints */
11596  cons0 = conss[chkind];
11597  assert(cons0 != NULL);
11598  assert(SCIPconsIsActive(cons0));
11599  assert(!SCIPconsIsModifiable(cons0));
11600 
11601  consdata0 = SCIPconsGetData(cons0);
11602  assert(consdata0 != NULL);
11603  assert(consdata0->nvars >= 1);
11604  assert(consdata0->merged);
11605 
11606  /* sort the constraint */
11607  sortItems(consdata0);
11608 
11609  /* check constraint against all prior constraints */
11610  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11611  {
11612  SCIP_CONS* cons1;
11613  SCIP_CONSDATA* consdata1;
11614  SCIP_Bool iscons0incons1contained;
11615  SCIP_Bool iscons1incons0contained;
11616  SCIP_Real quotient;
11617  int v;
11618  int v0;
11619  int v1;
11620 
11621  cons1 = conss[c];
11622  assert(cons1 != NULL);
11623  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11624  continue;
11625 
11626  consdata1 = SCIPconsGetData(cons1);
11627  assert(consdata1 != NULL);
11628 
11629  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11630  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11631  continue;
11632 
11633  assert(consdata1->nvars >= 1);
11634  assert(consdata1->merged);
11635 
11636  /* sort the constraint */
11637  sortItems(consdata1);
11638 
11639  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11640 
11641  if( consdata0->nvars > consdata1->nvars )
11642  {
11643  iscons0incons1contained = FALSE;
11644  iscons1incons0contained = TRUE;
11645  v = consdata1->nvars - 1;
11646  }
11647  else if( consdata0->nvars < consdata1->nvars )
11648  {
11649  iscons0incons1contained = TRUE;
11650  iscons1incons0contained = FALSE;
11651  v = consdata0->nvars - 1;
11652  }
11653  else
11654  {
11655  iscons0incons1contained = TRUE;
11656  iscons1incons0contained = TRUE;
11657  v = consdata0->nvars - 1;
11658  }
11659 
11660  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11661 
11662  /* check consdata0 against consdata1:
11663  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11664  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11665  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11666  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11667  */
11668  v0 = consdata0->nvars - 1;
11669  v1 = consdata1->nvars - 1;
11670 
11671  while( v >= 0 )
11672  {
11673  assert(iscons0incons1contained || iscons1incons0contained);
11674 
11675  /* now there are more variables in cons1 left */
11676  if( v1 > v0 )
11677  {
11678  iscons1incons0contained = FALSE;
11679  if( !iscons0incons1contained )
11680  break;
11681  }
11682  /* now there are more variables in cons0 left */
11683  else if( v1 < v0 )
11684  {
11685  iscons0incons1contained = FALSE;
11686  if( !iscons1incons0contained )
11687  break;
11688  }
11689 
11690  assert(v == v0 || v == v1);
11691  assert(v0 >= 0);
11692  assert(v1 >= 0);
11693 
11694  /* both variables are the same */
11695  if( consdata0->vars[v0] == consdata1->vars[v1] )
11696  {
11697  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11698  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11699  {
11700  iscons1incons0contained = FALSE;
11701  if( !iscons0incons1contained )
11702  break;
11703  }
11704  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11705  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11706  {
11707  iscons0incons1contained = FALSE;
11708  if( !iscons1incons0contained )
11709  break;
11710  }
11711  --v0;
11712  --v1;
11713  --v;
11714  }
11715  else
11716  {
11717  /* both constraints have a variables which is not part of the other constraint, so stop */
11718  if( iscons0incons1contained && iscons1incons0contained )
11719  {
11720  iscons0incons1contained = FALSE;
11721  iscons1incons0contained = FALSE;
11722  break;
11723  }
11724  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11725  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11726  /* continue to the next variable */
11727  if( iscons0incons1contained )
11728  --v1;
11729  else
11730  --v0;
11731  }
11732  }
11733  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11734  * other
11735  */
11736  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11737 
11738  if( iscons1incons0contained )
11739  {
11740  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11741  SCIPdebugPrintCons(scip, cons1, NULL);
11742 
11743  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11744  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11745 
11746  SCIP_CALL( SCIPdelCons(scip, cons1) );
11747  ++(*ndelconss);
11748  }
11749  else if( iscons0incons1contained )
11750  {
11751  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11752  SCIPdebugPrintCons(scip, cons0, NULL);
11753 
11754  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11755  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11756 
11757  SCIP_CALL( SCIPdelCons(scip, cons0) );
11758  ++(*ndelconss);
11759  break;
11760  }
11761  }
11762 
11763  return SCIP_OKAY;
11764 }
11765 
11766 /** helper function to enforce constraints */
11767 static
11769  SCIP* scip, /**< SCIP data structure */
11770  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11771  SCIP_CONS** conss, /**< constraints to process */
11772  int nconss, /**< number of constraints */
11773  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11774  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11775  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11776  )
11777 {
11778  SCIP_CONSHDLRDATA* conshdlrdata;
11779  SCIP_Bool violated;
11780  SCIP_Bool cutoff = FALSE;
11781  int maxncuts;
11782  int ncuts = 0;
11783  int i;
11784 
11785  *result = SCIP_FEASIBLE;
11786 
11787  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11788  sol == NULL ? "LP" : "relaxation");
11789 
11790  /* get maximal number of cuts per round */
11791  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11792  assert(conshdlrdata != NULL);
11793  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11794 
11795  /* search for violated useful knapsack constraints */
11796  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11797  {
11798  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11799  if( violated )
11800  {
11801  /* add knapsack constraint as LP row to the relaxation */
11802  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11803  ncuts++;
11804  }
11805  }
11806 
11807  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11808  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11809  {
11810  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11811  if( violated )
11812  {
11813  /* add knapsack constraint as LP row to the relaxation */
11814  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11815  ncuts++;
11816  }
11817  }
11818 
11819  /* adjust the result code */
11820  if ( cutoff )
11821  *result = SCIP_CUTOFF;
11822  else if ( ncuts > 0 )
11823  *result = SCIP_SEPARATED;
11824 
11825  return SCIP_OKAY;
11826 }
11827 
11828 /*
11829  * Linear constraint upgrading
11830  */
11831 
11832 /** creates and captures a knapsack constraint out of a linear inequality */
11833 static
11835  SCIP* scip, /**< SCIP data structure */
11836  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11837  const char* name, /**< name of constraint */
11838  int nvars, /**< number of variables in the constraint */
11839  SCIP_VAR** vars, /**< array with variables of constraint entries */
11840  SCIP_Real* vals, /**< array with inequality coefficients */
11841  SCIP_Real lhs, /**< left hand side of inequality */
11842  SCIP_Real rhs, /**< right hand side of inequality */
11843  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11844  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11845  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11846  * Usually set to TRUE. */
11847  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11848  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11849  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11850  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11851  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11852  * Usually set to TRUE. */
11853  SCIP_Bool local, /**< is constraint only valid locally?
11854  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11855  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11856  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11857  * adds coefficients to this constraint. */
11858  SCIP_Bool dynamic, /**< is constraint subject to aging?
11859  * Usually set to FALSE. Set to TRUE for own cuts which
11860  * are separated as constraints. */
11861  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11862  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11863  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11864  * if it may be moved to a more global node?
11865  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11866  )
11867 {
11868  SCIP_VAR** transvars;
11869  SCIP_Longint* weights;
11870  SCIP_Longint capacity;
11871  SCIP_Longint weight;
11872  int mult;
11873  int v;
11874 
11875  assert(nvars == 0 || vars != NULL);
11876  assert(nvars == 0 || vals != NULL);
11877  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11878 
11879  /* get temporary memory */
11880  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11881  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11882 
11883  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11884  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11885  */
11886  if( SCIPisInfinity(scip, rhs) )
11887  {
11888  mult = -1;
11889  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11890  }
11891  else
11892  {
11893  mult = +1;
11894  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11895  }
11896 
11897  /* negate positive or negative variables */
11898  for( v = 0; v < nvars; ++v )
11899  {
11900  assert(SCIPisFeasIntegral(scip, vals[v]));
11901  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11902  if( weight > 0 )
11903  {
11904  transvars[v] = vars[v];
11905  weights[v] = weight;
11906  }
11907  else
11908  {
11909  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11910  weights[v] = -weight;
11911  capacity -= weight;
11912  }
11913  assert(transvars[v] != NULL);
11914  }
11915 
11916  /* create the constraint */
11917  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11918  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11919 
11920  /* free temporary memory */
11921  SCIPfreeBufferArray(scip, &weights);
11922  SCIPfreeBufferArray(scip, &transvars);
11923 
11924  return SCIP_OKAY;
11925 }
11926 
11927 /** tries to upgrade a linear constraint into a knapsack constraint */
11928 static
11929 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11930 { /*lint --e{715}*/
11931  SCIP_Bool upgrade;
11932 
11933  assert(upgdcons != NULL);
11934 
11935  /* check, if linear constraint can be upgraded to a knapsack constraint
11936  * - all variables must be binary
11937  * - all coefficients must be integral
11938  * - exactly one of the sides must be infinite
11939  */
11940  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11941  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11942  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11943 
11944  if( upgrade )
11945  {
11946  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11947 
11948  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11949  assert(!SCIPconsIsModifiable(cons));
11950  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11955  }
11956 
11957  return SCIP_OKAY;
11958 }
11959 
11960 
11961 /*
11962  * Callback methods of constraint handler
11963  */
11964 
11965 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11966 /**! [SnippetConsCopyKnapsack] */
11967 static
11968 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11969 { /*lint --e{715}*/
11970  assert(scip != NULL);
11971  assert(conshdlr != NULL);
11972  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11973 
11974  /* call inclusion method of constraint handler */
11977  *valid = TRUE;
11978 
11979  return SCIP_OKAY;
11980 }
11981 /**! [SnippetConsCopyKnapsack] */
11982 
11983 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11984 /**! [SnippetConsFreeKnapsack] */
11985 static
11986 SCIP_DECL_CONSFREE(consFreeKnapsack)
11987 { /*lint --e{715}*/
11988  SCIP_CONSHDLRDATA* conshdlrdata;
11989 
11990  /* free constraint handler data */
11991  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11992  assert(conshdlrdata != NULL);
11993 
11994  SCIPfreeBlockMemory(scip, &conshdlrdata);
11995 
11996  SCIPconshdlrSetData(conshdlr, NULL);
11997 
11998  return SCIP_OKAY;
11999 }
12000 /**! [SnippetConsFreeKnapsack] */
12001 
12002 
12003 /** initialization method of constraint handler (called after problem was transformed) */
12004 static
12005 SCIP_DECL_CONSINIT(consInitKnapsack)
12006 { /*lint --e{715}*/
12007  SCIP_CONSHDLRDATA* conshdlrdata;
12008  int nvars;
12009 
12010  assert( scip != NULL );
12011  assert( conshdlr != NULL );
12012 
12013  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12014  assert(conshdlrdata != NULL);
12015 
12016  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12017  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12018 
12019  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12020  conshdlrdata->reals1size = nvars;
12021 
12022  return SCIP_OKAY;
12023 }
12024 
12025 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12026 static
12027 SCIP_DECL_CONSEXIT(consExitKnapsack)
12028 { /*lint --e{715}*/
12029  SCIP_CONSHDLRDATA* conshdlrdata;
12030 
12031  assert( scip != NULL );
12032  assert( conshdlr != NULL );
12033 
12034  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12035  assert(conshdlrdata != NULL);
12036 
12037  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12038  conshdlrdata->reals1size = 0;
12039 
12040  return SCIP_OKAY;
12041 }
12042 
12043 
12044 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12045 static
12046 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12047 { /*lint --e{715}*/
12048  SCIP_CONSHDLRDATA* conshdlrdata;
12049  int nvars;
12050 
12051  assert(scip != NULL);
12052  assert(conshdlr != NULL);
12053  assert(nconss == 0 || conss != NULL);
12055  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12056  assert(conshdlrdata != NULL);
12057 
12058  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12059  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12060 
12061  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12062  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12063  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12064  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12065  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12066  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12067  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12068  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12069 
12070  conshdlrdata->ints1size = nvars;
12071  conshdlrdata->ints2size = nvars;
12072  conshdlrdata->longints1size = nvars;
12073  conshdlrdata->longints2size = nvars;
12074  conshdlrdata->bools1size = nvars;
12075  conshdlrdata->bools2size = nvars;
12076  conshdlrdata->bools3size = nvars;
12077  conshdlrdata->bools4size = nvars;
12078 
12079 #ifdef WITH_CARDINALITY_UPGRADE
12080  conshdlrdata->upgradedcard = FALSE;
12081 #endif
12082 
12083  return SCIP_OKAY;
12084 }
12085 
12086 
12087 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12088 static
12089 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12090 { /*lint --e{715}*/
12091  SCIP_CONSHDLRDATA* conshdlrdata;
12092  int c;
12093 
12094  assert(scip != NULL);
12095  assert(conshdlr != NULL);
12096 
12097  for( c = 0; c < nconss; ++c )
12098  {
12099  if( !SCIPconsIsDeleted(conss[c]) )
12100  {
12101  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12102  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12103  }
12104  }
12105 
12106  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12107  assert(conshdlrdata != NULL);
12108 
12109  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12110  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12111  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12112  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12113  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12114  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12115  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12116  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12117 
12118  conshdlrdata->ints1size = 0;
12119  conshdlrdata->ints2size = 0;
12120  conshdlrdata->longints1size = 0;
12121  conshdlrdata->longints2size = 0;
12122  conshdlrdata->bools1size = 0;
12123  conshdlrdata->bools2size = 0;
12124  conshdlrdata->bools3size = 0;
12125  conshdlrdata->bools4size = 0;
12126 
12127  return SCIP_OKAY;
12128 }
12129 
12130 
12131 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12132 static
12133 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12134 { /*lint --e{715}*/
12135  SCIP_CONSDATA* consdata;
12136  int c;
12137 
12138  assert( scip != NULL );
12139 
12140  /* release the rows of all constraints */
12141  for( c = 0; c < nconss; ++c )
12142  {
12143  consdata = SCIPconsGetData(conss[c]);
12144  assert(consdata != NULL);
12145 
12146  if( consdata->row != NULL )
12147  {
12148  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12149  }
12150  }
12151 
12152  return SCIP_OKAY;
12153 }
12154 
12155 /** frees specific constraint data */
12156 static
12157 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12158 { /*lint --e{715}*/
12159  SCIP_CONSHDLRDATA* conshdlrdata;
12160 
12161  assert(conshdlr != NULL);
12162  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12163 
12164  /* get event handler */
12165  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12166  assert(conshdlrdata != NULL);
12167  assert(conshdlrdata->eventhdlr != NULL);
12168 
12169  /* free knapsack constraint */
12170  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12171 
12172  return SCIP_OKAY;
12173 }
12174 
12175 /** transforms constraint data into data belonging to the transformed problem */
12176 /**! [SnippetConsTransKnapsack]*/
12177 static
12178 SCIP_DECL_CONSTRANS(consTransKnapsack)
12179 { /*lint --e{715}*/
12180  SCIP_CONSHDLRDATA* conshdlrdata;
12181  SCIP_CONSDATA* sourcedata;
12182  SCIP_CONSDATA* targetdata;
12183 
12184  assert(conshdlr != NULL);
12185  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12187  assert(sourcecons != NULL);
12188  assert(targetcons != NULL);
12189 
12190  sourcedata = SCIPconsGetData(sourcecons);
12191  assert(sourcedata != NULL);
12192  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12193 
12194  /* get event handler */
12195  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12196  assert(conshdlrdata != NULL);
12197  assert(conshdlrdata->eventhdlr != NULL);
12198 
12199  /* create target constraint data */
12200  SCIP_CALL( consdataCreate(scip, &targetdata,
12201  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12202 
12203  /* create target constraint */
12204  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12205  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12206  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12207  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12208  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12209 
12210  /* catch events for variables */
12211  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12212 
12213  return SCIP_OKAY;
12214 }
12215 /**! [SnippetConsTransKnapsack]*/
12216 
12217 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12218 static
12219 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12220 { /*lint --e{715}*/
12221  int i;
12222 
12223  *infeasible = FALSE;
12224 
12225  for( i = 0; i < nconss && !(*infeasible); i++ )
12226  {
12227  assert(SCIPconsIsInitial(conss[i]));
12228  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12229  }
12230 
12231  return SCIP_OKAY;
12232 }
12233 
12234 /** separation method of constraint handler for LP solutions */
12235 static
12236 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12237 { /*lint --e{715}*/
12238  SCIP_CONSHDLRDATA* conshdlrdata;
12239  SCIP_Bool sepacardinality;
12240  SCIP_Bool cutoff;
12241 
12242  SCIP_Real loclowerbound;
12243  SCIP_Real glblowerbound;
12244  SCIP_Real cutoffbound;
12245  SCIP_Real maxbound;
12246 
12247  int depth;
12248  int nrounds;
12249  int sepafreq;
12250  int sepacardfreq;
12251  int ncuts;
12252  int maxsepacuts;
12253  int i;
12254 
12255  *result = SCIP_DIDNOTRUN;
12256 
12257  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12258  assert(conshdlrdata != NULL);
12259 
12260  depth = SCIPgetDepth(scip);
12261  nrounds = SCIPgetNSepaRounds(scip);
12262 
12263  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12264  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12265 
12266  /* only call the separator a given number of times at each node */
12267  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12268  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12269  return SCIP_OKAY;
12270 
12271  /* check, if we should additionally separate knapsack cuts */
12272  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12273  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12274  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12275  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12276 
12277  /* check dual bound to see if we want to produce knapsack cuts at this node */
12278  loclowerbound = SCIPgetLocalLowerbound(scip);
12279  glblowerbound = SCIPgetLowerbound(scip);
12280  cutoffbound = SCIPgetCutoffbound(scip);
12281  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12282  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12283  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12284 
12285  /* get the maximal number of cuts allowed in a separation round */
12286  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12287 
12288  *result = SCIP_DIDNOTFIND;
12289  ncuts = 0;
12290  cutoff = FALSE;
12291 
12292  /* separate useful constraints */
12293  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12294  {
12295  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12296  }
12297 
12298  /* adjust return value */
12299  if ( cutoff )
12300  *result = SCIP_CUTOFF;
12301  else if ( ncuts > 0 )
12302  *result = SCIP_SEPARATED;
12303 
12304  return SCIP_OKAY;
12305 }
12306 
12307 
12308 /** separation method of constraint handler for arbitrary primal solutions */
12309 static
12310 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12311 { /*lint --e{715}*/
12312  SCIP_CONSHDLRDATA* conshdlrdata;
12313  SCIP_Bool sepacardinality;
12314  SCIP_Bool cutoff;
12315 
12316  int depth;
12317  int nrounds;
12318  int sepafreq;
12319  int sepacardfreq;
12320  int ncuts;
12321  int maxsepacuts;
12322  int i;
12323 
12324  *result = SCIP_DIDNOTRUN;
12325 
12326  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12327  assert(conshdlrdata != NULL);
12328 
12329  depth = SCIPgetDepth(scip);
12330  nrounds = SCIPgetNSepaRounds(scip);
12331 
12332  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12333  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12334 
12335  /* only call the separator a given number of times at each node */
12336  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12337  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12338  return SCIP_OKAY;
12339 
12340  /* check, if we should additionally separate knapsack cuts */
12341  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12342  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12343  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12344  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12345 
12346  /* get the maximal number of cuts allowed in a separation round */
12347  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12348 
12349  *result = SCIP_DIDNOTFIND;
12350  ncuts = 0;
12351  cutoff = FALSE;
12352 
12353  /* separate useful constraints */
12354  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12355  {
12356  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12357  }
12358 
12359  /* adjust return value */
12360  if ( cutoff )
12361  *result = SCIP_CUTOFF;
12362  else if( ncuts > 0 )
12363  *result = SCIP_SEPARATED;
12364 
12365  return SCIP_OKAY;
12366 }
12367 
12368 /** constraint enforcing method of constraint handler for LP solutions */
12369 static
12370 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12371 { /*lint --e{715}*/
12372  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12373 
12374  return SCIP_OKAY;
12375 }
12376 
12377 /** constraint enforcing method of constraint handler for relaxation solutions */
12378 static
12379 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12380 { /*lint --e{715}*/
12381  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12382 
12383  return SCIP_OKAY;
12384 }
12385 
12386 /** constraint enforcing method of constraint handler for pseudo solutions */
12387 static
12388 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12389 { /*lint --e{715}*/
12390  SCIP_Bool violated;
12391  int i;
12392 
12393  for( i = 0; i < nconss; i++ )
12394  {
12395  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12396  if( violated )
12397  {
12398  *result = SCIP_INFEASIBLE;
12399  return SCIP_OKAY;
12400  }
12401  }
12402  *result = SCIP_FEASIBLE;
12403 
12404  return SCIP_OKAY;
12405 }
12406 
12407 /** feasibility check method of constraint handler for integral solutions */
12408 static
12409 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12410 { /*lint --e{715}*/
12411  SCIP_Bool violated;
12412  int i;
12413 
12414  *result = SCIP_FEASIBLE;
12415 
12416  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12417  {
12418  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12419  if( violated )
12420  *result = SCIP_INFEASIBLE;
12421  }
12422 
12423  return SCIP_OKAY;
12424 }
12425 
12426 /** domain propagation method of constraint handler */
12427 static
12428 SCIP_DECL_CONSPROP(consPropKnapsack)
12429 { /*lint --e{715}*/
12430  SCIP_CONSHDLRDATA* conshdlrdata;
12431  SCIP_Bool cutoff;
12432  SCIP_Bool redundant;
12433  SCIP_Bool inpresolve;
12434  int nfixedvars;
12435  int i;
12437  cutoff = FALSE;
12438  nfixedvars = 0;
12439 
12440  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12441  assert(conshdlrdata != NULL);
12442 
12443  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12444  assert(!inpresolve || SCIPinProbing(scip));
12445 
12446  /* process useful constraints */
12447  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12448  {
12449  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12450  * otherwise the multi-aggregation should be resolved
12451  */
12452  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12453  continue;
12454 #ifndef NDEBUG
12455  else
12456  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12457 #endif
12458 
12459  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12460 
12461  /* unmark the constraint to be propagated */
12462  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12463  }
12464 
12465  /* adjust result code */
12466  if( cutoff )
12467  *result = SCIP_CUTOFF;
12468  else if( nfixedvars > 0 )
12469  *result = SCIP_REDUCEDDOM;
12470  else
12471  *result = SCIP_DIDNOTFIND;
12472 
12473  return SCIP_OKAY;
12474 }
12475 
12476 /** presolving method of constraint handler */
12477 static
12478 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12479 { /*lint --e{574,715}*/
12480  SCIP_CONSHDLRDATA* conshdlrdata;
12481  SCIP_CONSDATA* consdata;
12482  SCIP_CONS* cons;
12483  SCIP_Bool cutoff;
12484  SCIP_Bool redundant;
12485  SCIP_Bool success;
12486  int oldnfixedvars;
12487  int oldnchgbds;
12488  int oldndelconss;
12489  int oldnaddconss;
12490  int oldnchgcoefs;
12491  int oldnchgsides;
12492  int firstchange;
12493  int c;
12494  SCIP_Bool newchanges;
12495 
12496  /* remember old preprocessing counters */
12497  cutoff = FALSE;
12498  oldnfixedvars = *nfixedvars;
12499  oldnchgbds = *nchgbds;
12500  oldndelconss = *ndelconss;
12501  oldnaddconss = *naddconss;
12502  oldnchgcoefs = *nchgcoefs;
12503  oldnchgsides = *nchgsides;
12504  firstchange = INT_MAX;
12505 
12506  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12507 
12508  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12509  assert(conshdlrdata != NULL);
12510 
12511  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12512  {
12513  int thisnfixedvars;
12514  int thisnchgbds;
12515 
12516  cons = conss[c];
12517  consdata = SCIPconsGetData(cons);
12518  assert(consdata != NULL);
12519 
12520  /* update data structures */
12521  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12522  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12523  {
12524  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12525  if( cutoff )
12526  break;
12527  }
12528 
12529  /* force presolving the constraint in the initial round */
12530  if( nrounds == 0 )
12531  consdata->presolvedtiming = 0;
12532  else if( consdata->presolvedtiming >= presoltiming )
12533  continue;
12534 
12535  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12536  SCIPdebugPrintCons(scip, cons, NULL);
12537  consdata->presolvedtiming = presoltiming;
12538 
12539  thisnfixedvars = *nfixedvars;
12540  thisnchgbds = *nchgbds;
12541 
12542  /* merge constraint, so propagation works better */
12543  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12544  if( cutoff )
12545  break;
12546 
12547  /* add cliques in the knapsack to the clique table */
12548  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12549  {
12550  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12551  if( cutoff )
12552  break;
12553  }
12554 
12555  /* propagate constraint */
12556  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12557  {
12558  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12559 
12560  if( cutoff )
12561  break;
12562  if( redundant )
12563  {
12564  (*ndelconss)++;
12565  continue;
12566  }
12567  }
12568 
12569  /* remove again all fixed variables, if further fixings were found */
12570  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12571  {
12572  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12573  if( cutoff )
12574  break;
12575 
12576  thisnfixedvars = *nfixedvars;
12577  }
12578 
12579  if( !SCIPconsIsModifiable(cons) )
12580  {
12581  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12582  if( consdata->weightsum <= consdata->capacity )
12583  {
12584  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12585  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12586  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12587  continue;
12588  }
12589 
12590  /* divide weights by their greatest common divisor */
12591  normalizeWeights(cons, nchgcoefs, nchgsides);
12592 
12593  /* try to simplify inequalities */
12594  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12595  {
12596  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12597  if( cutoff )
12598  break;
12599 
12600  if( SCIPconsIsDeleted(cons) )
12601  continue;
12602 
12603  /* remove again all fixed variables, if further fixings were found */
12604  if( *nfixedvars > thisnfixedvars )
12605  {
12606  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12607  if( cutoff )
12608  break;
12609  }
12610  }
12611 
12612  /* tighten capacity and weights */
12613  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12614  if( cutoff )
12615  break;
12616 
12617  if( SCIPconsIsActive(cons) )
12618  {
12619  if( conshdlrdata->dualpresolving && SCIPallowDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12620  {
12621  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12622  * dual reduction
12623  */
12624  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12625  if( redundant )
12626  continue;
12627  }
12628 
12629  /* check if knapsack constraint is parallel to objective function */
12630  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12631  }
12632  }
12633  /* remember the first changed constraint to begin the next aggregation round with */
12634  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12635  firstchange = c;
12636  }
12637 
12638  /* preprocess pairs of knapsack constraints */
12639  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12640  {
12641  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12642  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12643  }
12644 
12645  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12646  success = TRUE;
12647  else
12648  success = FALSE;
12649 
12650  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12651  {
12652  SCIP_Longint npaircomparisons;
12653 
12654  npaircomparisons = 0;
12655  oldndelconss = *ndelconss;
12656  oldnchgsides = *nchgsides;
12657  oldnchgcoefs = *nchgcoefs;
12658 
12659  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12660  {
12661  cons = conss[c];
12662  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12663  continue;
12664 
12665  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12666 
12667  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12668 
12669  if( npaircomparisons > NMINCOMPARISONS )
12670  {
12671  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12672  success = TRUE;
12673  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12674  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12675  break;
12676  oldndelconss = *ndelconss;
12677  oldnchgsides = *nchgsides;
12678  oldnchgcoefs = *nchgcoefs;
12679  npaircomparisons = 0;
12680  }
12681  }
12682  }
12683 #ifdef WITH_CARDINALITY_UPGRADE
12684  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12685  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12686  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12687  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12688  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12689  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12690  * as well, we better keep this code disabled. */
12691  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12692  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12693  {
12694  SCIP_HASHMAP* varhash;
12695  SCIP_VAR** cardvars;
12696  SCIP_Real* cardweights;
12697  int noldupgdconss;
12698  int nscipvars;
12699  int makeupgrade;
12700 
12701  noldupgdconss = *nupgdconss;
12702  nscipvars = SCIPgetNVars(scip);
12703  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12704  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12705 
12706  /* set up hash map */
12707  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12708 
12709  /* We loop through all cardinality constraints twice:
12710  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12711  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12712  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12713  * - Second, upgrade knapsack constraints to cardinality constraints. */
12714  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12715  {
12716  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12717  {
12718  SCIP_CONS* cardcons;
12719  SCIP_VAR** vars;
12720  SCIP_Longint* weights;
12721  int nvars;
12722  int v;
12723 
12724  cons = conss[c];
12725  assert( cons != NULL );
12726  consdata = SCIPconsGetData(cons);
12727  assert( consdata != NULL );
12728 
12729  nvars = consdata->nvars;
12730  vars = consdata->vars;
12731  weights = consdata->weights;
12732 
12733  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12734  * - all variables must be binary (always true)
12735  * - all coefficients must be 1.0
12736  * - the right hand side must be smaller than nvars
12737  */
12738  if ( consdata->capacity >= nvars )
12739  continue;
12740 
12741  /* the weights are sorted: check first and last weight */
12742  assert( consdata->sorted );
12743  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12744  continue;
12745 
12746  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12747  for (v = 0; v < nvars; ++v)
12748  {
12749  SCIP_BOUNDTYPE* impltypes;
12750  SCIP_Real* implbounds;
12751  SCIP_VAR** implvars;
12752  SCIP_VAR* var;
12753  int nimpls;
12754  int j;
12755 
12756  var = consdata->vars[v];
12757  assert( var != NULL );
12758  assert( SCIPvarIsBinary(var) );
12759 
12760  /* ignore non-active variables */
12761  if ( ! SCIPvarIsActive(var) )
12762  break;
12763 
12764  /* be sure that implication variable has zero objective */
12765  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12766  break;
12767 
12768  nimpls = SCIPvarGetNImpls(var, FALSE);
12769  implvars = SCIPvarGetImplVars(var, FALSE);
12770  implbounds = SCIPvarGetImplBounds(var, FALSE);
12771  impltypes = SCIPvarGetImplTypes(var, FALSE);
12772 
12773  for (j = 0; j < nimpls; ++j)
12774  {
12775  /* be sure that continuous variable is fixed to 0 */
12776  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12777  continue;
12778 
12779  /* cannot currently deal with nonzero fixings */
12780  if ( ! SCIPisZero(scip, implbounds[j]) )
12781  continue;
12782 
12783  /* number of down locks should be one */
12784  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12785  continue;
12786 
12787  cardvars[v] = implvars[j];
12788  cardweights[v] = (SCIP_Real) v;
12789 
12790  break;
12791  }
12792 
12793  /* found no variable upper bound candidate -> exit */
12794  if ( j >= nimpls )
12795  break;
12796  }
12797 
12798  /* did not find fitting variable upper bound for some variable -> exit */
12799  if ( v < nvars )
12800  break;
12801 
12802  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12803  * in which the binary variable is involved in */
12804  if ( makeupgrade == 0 )
12805  {
12806  for (v = 0; v < nvars; ++v)
12807  {
12808  if ( SCIPhashmapExists(varhash, vars[v]) )
12809  {
12810  int image;
12811 
12812  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12813  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12814  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12815  }
12816  else
12817  {
12818  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12819  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12820  assert( SCIPhashmapExists(varhash, vars[v]) );
12821  }
12822  }
12823  }
12824  else
12825  {
12826  SCIP_CONS* origcons;
12827 
12828  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12829  * knapsack constraint coincides with the number of variable up locks */
12830  for (v = 0; v < nvars; ++v)
12831  {
12832  assert( SCIPhashmapExists(varhash, vars[v]) );
12833  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12834  break;
12835  }
12836  if ( v < nvars )
12837  break;
12838 
12839  /* store that we have upgraded */
12840  conshdlrdata->upgradedcard = TRUE;
12841 
12842  /* at this point we found suitable variable upper bounds */
12843  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12844 
12845  /* create cardinality constraint */
12846  assert( ! SCIPconsIsModifiable(cons) );
12847  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12851 #ifdef SCIP_DEBUG
12852  SCIPprintCons(scip, cons, NULL);
12853  SCIPinfoMessage(scip, NULL, "\n");
12854  SCIPprintCons(scip, cardcons, NULL);
12855  SCIPinfoMessage(scip, NULL, "\n");
12856 #endif
12857  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12858  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12859  ++(*nupgdconss);
12860 
12861  /* delete oknapsack constraint */
12862  SCIP_CALL( SCIPdelCons(scip, cons) );
12863  ++(*ndelconss);
12864 
12865  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12866  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12867  * although the cardinality constraint is satisfied. */
12868  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12869  assert( origcons != NULL );
12870  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12871 
12872  for (v = 0; v < nvars; ++v)
12873  {
12874  int image;
12875 
12876  assert ( SCIPhashmapExists(varhash, vars[v]) );
12877  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12878  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12879  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12880  }
12881  }
12882  }
12883  }
12884  SCIPhashmapFree(&varhash);
12885  SCIPfreeBufferArray(scip, &cardweights);
12886  SCIPfreeBufferArray(scip, &cardvars);
12887 
12888  if ( *nupgdconss > noldupgdconss )
12889  success = TRUE;
12890  }
12891 #endif
12892 
12893  if( cutoff )
12894  *result = SCIP_CUTOFF;
12895  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12896  *result = SCIP_SUCCESS;
12897  else
12898  *result = SCIP_DIDNOTFIND;
12899 
12900  return SCIP_OKAY;
12901 }
12902 
12903 /** propagation conflict resolving method of constraint handler */
12904 static
12905 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12906 { /*lint --e{715}*/
12907  SCIP_CONSDATA* consdata;
12908  SCIP_Longint capsum;
12909  int i;
12910 
12911  assert(result != NULL);
12912 
12913  consdata = SCIPconsGetData(cons);
12914  assert(consdata != NULL);
12915 
12916  /* check if we fixed a binary variable to one (due to negated clique) */
12917  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12918  {
12919  for( i = 0; i < consdata->nvars; ++i )
12920  {
12921  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12922  {
12923  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12924  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12925  break;
12926  }
12927  }
12928  assert(i < consdata->nvars);
12929  }
12930  else
12931  {
12932  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12933  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12934  * knapsack constraint, see one above call of SCIPinferBinvarCons
12935  */
12936  if( inferinfo < 0 )
12937  capsum = 0;
12938  else
12939  {
12940  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12941  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12942  */
12943  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12944  capsum = consdata->weights[inferinfo];
12945  else
12946  {
12947  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12948  {}
12949  assert(i < consdata->nvars);
12950  capsum = consdata->weights[i];
12951  }
12952  }
12953 
12954  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12955  * the capacity
12956  */
12957  if( capsum <= consdata->capacity )
12958  {
12959  for( i = 0; i < consdata->nvars; i++ )
12960  {
12961  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12962  {
12963  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12964  capsum += consdata->weights[i];
12965  if( capsum > consdata->capacity )
12966  break;
12967  }
12968  }
12969  }
12970  }
12971 
12972  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12973  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12974  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12975  * used to fix variables to zero.
12976  *
12977  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12978  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12979  * one.
12980  */
12981  *result = SCIP_SUCCESS;
12982 
12983  return SCIP_OKAY;
12984 }
12985 
12986 /** variable rounding lock method of constraint handler */
12987 /**! [SnippetConsLockKnapsack] */
12988 static
12989 SCIP_DECL_CONSLOCK(consLockKnapsack)
12990 { /*lint --e{715}*/
12991  SCIP_CONSDATA* consdata;
12992  int i;
12993 
12994  consdata = SCIPconsGetData(cons);
12995  assert(consdata != NULL);
12996 
12997  for( i = 0; i < consdata->nvars; i++)
12998  {
12999  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13000  }
13001 
13002  return SCIP_OKAY;
13003 }
13004 /**! [SnippetConsLockKnapsack] */
13005 
13006 
13007 /** variable deletion method of constraint handler */
13008 static
13009 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13010 {
13011  assert(scip != NULL);
13012  assert(conshdlr != NULL);
13013  assert(conss != NULL || nconss == 0);
13014 
13015  if( nconss > 0 )
13016  {
13017  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13018  }
13019 
13020  return SCIP_OKAY;
13021 }
13022 
13023 /** constraint display method of constraint handler */
13024 static
13025 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13026 { /*lint --e{715}*/
13027  SCIP_CONSDATA* consdata;
13028  int i;
13029 
13030  assert( scip != NULL );
13031  assert( conshdlr != NULL );
13032  assert( cons != NULL );
13034  consdata = SCIPconsGetData(cons);
13035  assert(consdata != NULL);
13036 
13037  for( i = 0; i < consdata->nvars; ++i )
13038  {
13039  if( i > 0 )
13040  SCIPinfoMessage(scip, file, " ");
13041  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13042  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13043  }
13044  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13045 
13046  return SCIP_OKAY;
13047 }
13048 
13049 /** constraint copying method of constraint handler */
13050 static
13051 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13052 { /*lint --e{715}*/
13053  SCIP_VAR** sourcevars;
13054  SCIP_Longint* weights;
13055  SCIP_Real* coefs;
13056  const char* consname;
13057  int nvars;
13058  int v;
13060  /* get variables and coefficients of the source constraint */
13061  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13062  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13063  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13064 
13065  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13066  for( v = 0; v < nvars; ++v )
13067  coefs[v] = (SCIP_Real) weights[v];
13068 
13069  if( name != NULL )
13070  consname = name;
13071  else
13072  consname = SCIPconsGetName(sourcecons);
13073 
13074  /* copy the logic using the linear constraint copy method */
13075  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13076  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13077  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13078  assert(cons != NULL);
13079 
13080  SCIPfreeBufferArray(scip, &coefs);
13081 
13082  return SCIP_OKAY;
13083 }
13084 
13085 /** constraint parsing method of constraint handler */
13086 static
13087 SCIP_DECL_CONSPARSE(consParseKnapsack)
13088 { /*lint --e{715}*/
13089  SCIP_VAR* var;
13090  SCIP_Longint weight;
13091  SCIP_VAR** vars;
13092  SCIP_Longint* weights;
13093  SCIP_Longint capacity;
13094  char* endptr;
13095  int nread;
13096  int nvars;
13097  int varssize;
13098 
13099  assert(scip != NULL);
13100  assert(success != NULL);
13101  assert(str != NULL);
13102  assert(name != NULL);
13103  assert(cons != NULL);
13104 
13105  *success = TRUE;
13106 
13107  nvars = 0;
13108  varssize = 5;
13109  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13110  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13111 
13112  while( *str != '\0' )
13113  {
13114  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13115  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13116  break;
13117 
13118  str += nread;
13119 
13120  /* skip whitespace */
13121  while( isspace((int)*str) )
13122  ++str;
13123 
13124  /* parse variable name */
13125  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13126  if( var == NULL )
13127  {
13128  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13129  *success = FALSE;
13130  break;
13131  }
13132 
13133  str = endptr;
13134 
13135  /* store weight and variable */
13136  if( varssize <= nvars )
13137  {
13138  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13139  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13140  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13141  }
13142 
13143  vars[nvars] = var;
13144  weights[nvars] = weight;
13145  ++nvars;
13146 
13147  /* skip whitespace */
13148  while( isspace((int)*str) )
13149  ++str;
13150  }
13151 
13152  if( *success )
13153  {
13154  if( strncmp(str, "<= ", 3) != 0 )
13155  {
13156  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13157  *success = FALSE;
13158  }
13159  else
13160  {
13161  str += 3;
13162  }
13163  }
13164 
13165  if( *success )
13166  {
13167  /* coverity[secure_coding] */
13168  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13169  {
13170  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13171  *success = FALSE;
13172  }
13173  else
13174  {
13175  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13176  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13177  }
13178  }
13179 
13180  SCIPfreeBufferArray(scip, &vars);
13181  SCIPfreeBufferArray(scip, &weights);
13182 
13183  return SCIP_OKAY;
13184 }
13185 
13186 /** constraint method of constraint handler which returns the variables (if possible) */
13187 static
13188 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13189 { /*lint --e{715}*/
13190  SCIP_CONSDATA* consdata;
13191 
13192  consdata = SCIPconsGetData(cons);
13193  assert(consdata != NULL);
13194 
13195  if( varssize < consdata->nvars )
13196  (*success) = FALSE;
13197  else
13198  {
13199  assert(vars != NULL);
13200 
13201  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13202  (*success) = TRUE;
13203  }
13204 
13205  return SCIP_OKAY;
13206 }
13207 
13208 /** constraint method of constraint handler which returns the number of variables (if possible) */
13209 static
13210 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13211 { /*lint --e{715}*/
13212  SCIP_CONSDATA* consdata;
13213 
13214  consdata = SCIPconsGetData(cons);
13215  assert(consdata != NULL);
13216 
13217  (*nvars) = consdata->nvars;
13218  (*success) = TRUE;
13219 
13220  return SCIP_OKAY;
13221 }
13222 
13223 /*
13224  * Event handler
13225  */
13226 
13227 /** execution method of bound change event handler */
13228 static
13229 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13230 { /*lint --e{715}*/
13231  SCIP_CONSDATA* consdata;
13232 
13233  assert(eventdata != NULL);
13234  assert(eventdata->cons != NULL);
13235 
13236  consdata = SCIPconsGetData(eventdata->cons);
13237  assert(consdata != NULL);
13238 
13239  switch( SCIPeventGetType(event) )
13240  {
13242  consdata->onesweightsum += eventdata->weight;
13243  consdata->presolvedtiming = 0;
13244  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13245  break;
13247  consdata->onesweightsum -= eventdata->weight;
13248  break;
13250  consdata->presolvedtiming = 0;
13251  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13252  break;
13253  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13254  if( !consdata->existmultaggr )
13255  {
13256  SCIP_VAR* var;
13257  var = SCIPeventGetVar(event);
13258  assert(var != NULL);
13259 
13260  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13262  {
13263  consdata->existmultaggr = TRUE;
13264  consdata->merged = FALSE;
13265  }
13266  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13268  consdata->merged = FALSE;
13269  }
13270  /*lint -fallthrough*/
13271  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13272  consdata->presolvedtiming = 0;
13273  break;
13275  consdata->varsdeleted = TRUE;
13276  break;
13277  default:
13278  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
13279  return SCIP_INVALIDDATA;
13280  }
13281 
13282  return SCIP_OKAY;
13283 }
13284 
13285 
13286 /*
13287  * constraint specific interface methods
13288  */
13289 
13290 /** creates the handler for knapsack constraints and includes it in SCIP */
13292  SCIP* scip /**< SCIP data structure */
13293  )
13294 {
13295  SCIP_EVENTHDLRDATA* eventhdlrdata;
13296  SCIP_CONSHDLRDATA* conshdlrdata;
13297  SCIP_CONSHDLR* conshdlr;
13298 
13299  /* create knapsack constraint handler data */
13300  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13301 
13302  /* include event handler for bound change events */
13303  eventhdlrdata = NULL;
13304  conshdlrdata->eventhdlr = NULL;
13305  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13306  eventExecKnapsack, eventhdlrdata) );
13307 
13308  /* get event handler for bound change events */
13309  if( conshdlrdata->eventhdlr == NULL )
13310  {
13311  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13312  return SCIP_PLUGINNOTFOUND;
13313  }
13314 
13315  /* include constraint handler */
13318  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13319  conshdlrdata) );
13320 
13321  assert(conshdlr != NULL);
13322 
13323  /* set non-fundamental callbacks via specific setter functions */
13324  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13325  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13326  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13327  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13328  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13329  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13330  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13331  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13332  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13333  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13334  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13335  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13336  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13337  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13338  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13339  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13341  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13342  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13344  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13345  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13346 
13347  if( SCIPfindConshdlr(scip,"linear") != NULL )
13348  {
13349  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13351  }
13352 
13353  /* add knapsack constraint handler parameters */
13354  SCIP_CALL( SCIPaddIntParam(scip,
13355  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13356  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13357  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13359  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13360  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13361  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13363  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13364  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13365  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13366  SCIP_CALL( SCIPaddIntParam(scip,
13367  "constraints/" CONSHDLR_NAME "/maxrounds",
13368  "maximal number of separation rounds per node (-1: unlimited)",
13369  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13370  SCIP_CALL( SCIPaddIntParam(scip,
13371  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13372  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13373  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13374  SCIP_CALL( SCIPaddIntParam(scip,
13375  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13376  "maximal number of cuts separated per separation round",
13377  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13378  SCIP_CALL( SCIPaddIntParam(scip,
13379  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13380  "maximal number of cuts separated per separation round in the root node",
13381  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13383  "constraints/" CONSHDLR_NAME "/disaggregation",
13384  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13385  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13387  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13388  "should presolving try to simplify knapsacks",
13389  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13391  "constraints/" CONSHDLR_NAME "/negatedclique",
13392  "should negated clique information be used in solving process",
13393  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13395  "constraints/" CONSHDLR_NAME "/presolpairwise",
13396  "should pairwise constraint comparison be performed in presolving?",
13397  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13399  "constraints/" CONSHDLR_NAME "/presolusehashing",
13400  "should hash table be used for detecting redundant constraints in advance",
13401  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13403  "constraints/" CONSHDLR_NAME "/dualpresolving",
13404  "should dual presolving steps be performed?",
13405  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13407  "constraints/" CONSHDLR_NAME "/usegubs",
13408  "should GUB information be used for separation?",
13409  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13411  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13412  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13413  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13415  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13416  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13417  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13419  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13420  "should clique partition information be updated when old partition seems outdated?",
13421  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13423  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13424  "factor on the growth of global cliques to decide when to update a previous "
13425  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13426  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13427 #ifdef WITH_CARDINALITY_UPGRADE
13429  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13430  "if TRUE then try to update knapsack constraints to cardinality constraints",
13431  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13432 #endif
13433  return SCIP_OKAY;
13434 }
13435 
13436 /** creates and captures a knapsack constraint
13437  *
13438  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13439  */
13440 /**! [SnippetConsCreationKnapsack] */
13442  SCIP* scip, /**< SCIP data structure */
13443  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13444  const char* name, /**< name of constraint */
13445  int nvars, /**< number of items in the knapsack */
13446  SCIP_VAR** vars, /**< array with item variables */
13447  SCIP_Longint* weights, /**< array with item weights */
13448  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13449  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13450  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13451  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13452  * Usually set to TRUE. */
13453  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13454  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13455  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13456  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13457  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13458  * Usually set to TRUE. */
13459  SCIP_Bool local, /**< is constraint only valid locally?
13460  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13461  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13462  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13463  * adds coefficients to this constraint. */
13464  SCIP_Bool dynamic, /**< is constraint subject to aging?
13465  * Usually set to FALSE. Set to TRUE for own cuts which
13466  * are separated as constraints. */
13467  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13468  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13469  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13470  * if it may be moved to a more global node?
13471  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13472  )
13473 {
13474  SCIP_CONSHDLRDATA* conshdlrdata;
13475  SCIP_CONSHDLR* conshdlr;
13476  SCIP_CONSDATA* consdata;
13477 
13478  /* find the knapsack constraint handler */
13479  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13480  if( conshdlr == NULL )
13481  {
13482  SCIPerrorMessage("knapsack constraint handler not found\n");
13483  return SCIP_PLUGINNOTFOUND;
13484  }
13485 
13486  /* get event handler */
13487  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13488  assert(conshdlrdata != NULL);
13489  assert(conshdlrdata->eventhdlr != NULL);
13490 
13491  /* create constraint data */
13492  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13493 
13494  /* create constraint */
13495  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13496  local, modifiable, dynamic, removable, stickingatnode) );
13497 
13498  /* catch events for variables */
13499  if( SCIPisTransformed(scip) )
13500  {
13501  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13502  }
13503 
13504  return SCIP_OKAY;
13505 }
13506 /**! [SnippetConsCreationKnapsack] */
13507 
13508 /** creates and captures a knapsack constraint
13509  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13510  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13511  *
13512  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13513  *
13514  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13515  */
13517  SCIP* scip, /**< SCIP data structure */
13518  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13519  const char* name, /**< name of constraint */
13520  int nvars, /**< number of items in the knapsack */
13521  SCIP_VAR** vars, /**< array with item variables */
13522  SCIP_Longint* weights, /**< array with item weights */
13523  SCIP_Longint capacity /**< capacity of knapsack */
13524  )
13525 {
13526  assert(scip != NULL);
13527 
13528  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13529  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13530 
13531  return SCIP_OKAY;
13532 }
13533 
13534 /** adds new item to knapsack constraint */
13536  SCIP* scip, /**< SCIP data structure */
13537  SCIP_CONS* cons, /**< constraint data */
13538  SCIP_VAR* var, /**< item variable */
13539  SCIP_Longint weight /**< item weight */
13540  )
13541 {
13542  assert(var != NULL);
13544  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13545  {
13546  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13547  return SCIP_INVALIDDATA;
13548  }
13549 
13550  SCIP_CALL( addCoef(scip, cons, var, weight) );
13551 
13552  return SCIP_OKAY;
13553 }
13554 
13555 /** gets the capacity of the knapsack constraint */
13557  SCIP* scip, /**< SCIP data structure */
13558  SCIP_CONS* cons /**< constraint data */
13559  )
13560 {
13561  SCIP_CONSDATA* consdata;
13562 
13563  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13564  {
13565  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13566  SCIPABORT();
13567  return 0; /*lint !e527*/
13568  }
13569 
13570  consdata = SCIPconsGetData(cons);
13571  assert(consdata != NULL);
13572 
13573  return consdata->capacity;
13574 }
13575 
13576 /** changes capacity of the knapsack constraint
13577  *
13578  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13579  */
13581  SCIP* scip, /**< SCIP data structure */
13582  SCIP_CONS* cons, /**< constraint data */
13583  SCIP_Longint capacity /**< new capacity of knapsack */
13584  )
13585 {
13586  SCIP_CONSDATA* consdata;
13587 
13589  {
13590  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13591  return SCIP_INVALIDDATA;
13592  }
13593 
13594  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13595  {
13596  SCIPerrorMessage("method can only be called during problem creation stage\n");
13597  return SCIP_INVALIDDATA;
13598  }
13599 
13600  consdata = SCIPconsGetData(cons);
13601  assert(consdata != NULL);
13602 
13603  consdata->capacity = capacity;
13604 
13605  return SCIP_OKAY;
13606 }
13607 
13608 /** gets the number of items in the knapsack constraint */
13610  SCIP* scip, /**< SCIP data structure */
13611  SCIP_CONS* cons /**< constraint data */
13612  )
13613 {
13614  SCIP_CONSDATA* consdata;
13615 
13616  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13617  {
13618  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13619  SCIPABORT();
13620  return -1; /*lint !e527*/
13621  }
13622 
13623  consdata = SCIPconsGetData(cons);
13624  assert(consdata != NULL);
13625 
13626  return consdata->nvars;
13627 }
13628 
13629 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13631  SCIP* scip, /**< SCIP data structure */
13632  SCIP_CONS* cons /**< constraint data */
13633  )
13634 {
13635  SCIP_CONSDATA* consdata;
13636 
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  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13659  {
13660  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13661  SCIPABORT();
13662  return NULL; /*lint !e527*/
13663  }
13664 
13665  consdata = SCIPconsGetData(cons);
13666  assert(consdata != NULL);
13667 
13668  return consdata->weights;
13669 }
13670 
13671 /** gets the dual solution of the knapsack constraint in the current LP */
13673  SCIP* scip, /**< SCIP data structure */
13674  SCIP_CONS* cons /**< constraint data */
13675  )
13676 {
13677  SCIP_CONSDATA* consdata;
13678 
13679  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13680  {
13681  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13682  SCIPABORT();
13683  return SCIP_INVALID; /*lint !e527*/
13684  }
13685 
13686  consdata = SCIPconsGetData(cons);
13687  assert(consdata != NULL);
13688 
13689  if( consdata->row != NULL )
13690  return SCIProwGetDualsol(consdata->row);
13691  else
13692  return 0.0;
13693 }
13694 
13695 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13697  SCIP* scip, /**< SCIP data structure */
13698  SCIP_CONS* cons /**< constraint data */
13699  )
13700 {
13701  SCIP_CONSDATA* consdata;
13702 
13703  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13704  {
13705  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13706  SCIPABORT();
13707  return SCIP_INVALID; /*lint !e527*/
13708  }
13709 
13710  consdata = SCIPconsGetData(cons);
13711  assert(consdata != NULL);
13712 
13713  if( consdata->row != NULL )
13714  return SCIProwGetDualfarkas(consdata->row);
13715  else
13716  return 0.0;
13717 }
13718 
13719 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13720  * the user must not modify the row!
13721  */
13723  SCIP* scip, /**< SCIP data structure */
13724  SCIP_CONS* cons /**< constraint data */
13725  )
13726 {
13727  SCIP_CONSDATA* consdata;
13728 
13729  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13730  {
13731  SCIPerrorMessage("constraint is not a knapsack\n");
13732  SCIPABORT();
13733  return NULL; /*lint !e527*/
13734  }
13735 
13736  consdata = SCIPconsGetData(cons);
13737  assert(consdata != NULL);
13738 
13739  return consdata->row;
13740 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define KNAPSACKRELAX_MAXSCALE
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:116
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int * gubconssidx
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4221
#define DEFAULT_DETECTCUTOFFBOUND
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1798
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:105
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1696
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:640
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:213
static SCIP_RETCODE GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
GUBVarstatus
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17558
#define NULL
Definition: def.h:246
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:10964
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3343
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:99
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5119
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1547
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2130
#define CONSHDLR_DESC
Definition: cons_knapsack.c:69
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for SCIP parameter handling
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3176
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:84
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:411
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8335
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17136
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:663
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1600
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1394
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3174
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1994
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2364
public methods for memory management
static SCIP_DECL_CONSINIT(consInitKnapsack)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:422
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:954
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1570
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:132
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17536
#define DEFAULT_CLQPARTUPDATEFAC
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
public methods for implications, variable bounds, and cliques
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17344
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:893
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
GUBCONSSTATUS * gubconsstatus
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:11796
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define SCIP_MAXSTRLEN
Definition: def.h:267
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3233
public methods for conflict handler plugins and conflict analysis
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:71
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:385
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:103
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1826
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2895
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:210
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17124
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1607
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1385
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip_var.c:1563
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17400
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17707
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
#define LINCONSUPGD_PRIORITY
Definition: cons_knapsack.c:94
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:172
#define DEFAULT_CLIQUEEXTRACTFACTOR
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
SCIP_GUBCONS ** gubconss
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1538
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:523
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1251
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16910
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:138
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:554
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
GUBConsstatus
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define CONSHDLR_SEPAFREQ
Definition: cons_knapsack.c:73
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define FALSE
Definition: def.h:72
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2891
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10561
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:243
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:78
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10253
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:71
#define SCIPdebug(x)
Definition: pub_message.h:74
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:689
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2056
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip_prob.c:3638
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:75
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8355
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17578
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3009
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17037
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:836
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4847
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8385
public methods for problem variables
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5235
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:114
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:86
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:297
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17548
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:138
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5077
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_LONGINT_MAX
Definition: def.h:143
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:142
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:97
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:610
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:417
public methods for SCIP variables
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip_cons.c:824
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8345
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:686
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:16979
#define SCIPdebugMsgPrint
Definition: scip_message.h:89
#define SCIPdebugMsg
Definition: scip_message.h:88
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:155
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1483
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:83
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:870
#define DEFAULT_PRESOLUSEHASHING
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17696
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:279
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2224
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:1011
SCIP_Real SCIPepsilon(SCIP *scip)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
public methods for numerical tolerances
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2113
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
public methods for querying solving statistics
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17160
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17170
#define DEFAULT_SEPACARDFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3240
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4198
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:64
static SCIP_RETCODE GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
public methods for the branch-and-bound tree
static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
static SCIP_DECL_CONSPARSE(consParseKnapsack)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1310
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:6829
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
#define DEFAULT_MAXROUNDS
#define DEFAULT_DISAGGREGATION
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17354
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11704
SCIP_VAR * w
Definition: circlepacking.c:58
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:111
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:70
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:161
public methods for managing constraints
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:647
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:409
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
enum GUBVarstatus GUBVARSTATUS
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4191
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2822
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3527
public methods for event handler plugins and event handlers
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1447
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
#define DEFAULT_PRESOLPAIRWISE
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:128
SCIPInterval sqrt(const SCIPInterval &x)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define DEFAULT_DUALPRESOLVING
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip_prob.c:2950
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:179
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:128
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4374
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1360
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8076
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17610
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8295
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:71
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16730
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:434
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2925
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4211
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2028
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:181
#define DEFAULT_NEGATEDCLIQUE
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
public methods for problem copies
#define SCIP_CALL(x)
Definition: def.h:358
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:493
SCIP_Real SCIPgetLowerbound(SCIP *scip)
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17568
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17148
SCIP_VAR * h
Definition: circlepacking.c:59
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2494
GUBVARSTATUS * gubvarsstatus
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:334
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:296
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17600
Definition: grphload.c:88
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8315
#define KNAPSACKRELAX_MAXDNOM
#define DEFAULT_MAXSEPACUTSROOT
static SCIP_DECL_CONSFREE(consFreeKnapsack)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:294
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:709
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:51
static SCIP_DECL_CONSEXIT(consExitKnapsack)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
public methods for constraint handler plugins and constraints
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9116
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:130
public data structures and miscellaneous methods
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17654
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1018
#define SCIP_Bool
Definition: def.h:69
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:995
#define MINGAINPERNMINCOMPARISONS
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_DECL_CONSPROP(consPropKnapsack)
#define MAXABSVBCOEF
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:79
#define DEFAULT_MAXSEPACUTS
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1336
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
#define DEFAULT_MAXCARDBOUNDDIST
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:715
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17622
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2550
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7164
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11428
#define MIN(x, y)
Definition: def.h:216
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3355
public methods for LP management
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1365
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8205
#define DEFAULT_USEGUBS
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
#define KNAPSACKRELAX_MAXDELTA
Definition: cons_knapsack.c:99
public methods for cuts and aggregation rows
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17192
#define MAX_ZEROITEMS_SIZE
Definition: cons_knapsack.c:97
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:468
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:87
#define CONSHDLR_NAME
Definition: cons_knapsack.c:68
#define SCIPcombineFourInt(a, b, c, d)
Definition: pub_misc.h:503
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8178
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:123
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:80
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:16992
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4289
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:847
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
Constraint handler for linear constraints in their most general form, .
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2272
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2425
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17112
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17668
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define SCIP_MAXTREEDEPTH
Definition: def.h:294
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:152
public methods for the LP relaxation, rows and columns
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2163
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2044
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3749
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
methods for sorting joint arrays of various types
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17639
#define SCIP_LONGINT_FORMAT
Definition: def.h:149
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:578
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
public methods for branching rule plugins and branching
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_VAR ** b
Definition: circlepacking.c:56
static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1474
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
public methods for managing events
general public methods
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:140
#define MAX(x, y)
Definition: def.h:215
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_DECL_CONSLOCK(consLockKnapsack)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
public methods for solutions
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8106
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:458
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1335
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:482
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip_copy.c:687
public methods for the probing mode
constraint handler for cardinality constraints
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1187
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip_var.c:8488
#define DEFAULT_DETECTLOWERBOUND
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:602
public methods for message output
#define HASHSIZE_KNAPSACKCONS
enum GUBConsstatus GUBCONSSTATUS
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7483
#define MAX_USECLIQUES_SIZE
Definition: cons_knapsack.c:96
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1999
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16849
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7383
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1217
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:157
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8325
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:738
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11764
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:916
#define GUBCONSGROWVALUE
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8265
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:88
#define SCIP_INVALID
Definition: def.h:177
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2099
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17590
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:74
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:81
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
#define SCIP_Longint
Definition: def.h:142
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:9123
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17027
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:50
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17410
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:117
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3333
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16872
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
public methods for separators
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:119
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
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:426
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3098
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:530
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:330
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:220
public methods for global and local (sub)problems
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8690
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1410
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:16951
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
#define DEFAULT_UPDATECLIQUEPARTITIONS
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:211
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:5635
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:72
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:57
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1530
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:129
int SCIPgetNSepaRounds(SCIP *scip)
#define DEFAULT_SIMPLIFYINEQUALITIES
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17017
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:16885
methods for selecting (weighted) k-medians
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:134
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:343
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1285
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
memory allocation routines